mirror of
https://github.com/godotengine/godot.git
synced 2025-10-19 07:53:26 +00:00
Add GDType
and Object::_gdtype_ptr
for first-class Object
typing.
The type is currently bare-bones, but will be expanded in future PRs.
This commit is contained in:
parent
d705613db3
commit
ac85d24e64
4 changed files with 151 additions and 47 deletions
42
core/object/gdtype.cpp
Normal file
42
core/object/gdtype.cpp
Normal file
|
@ -0,0 +1,42 @@
|
|||
/**************************************************************************/
|
||||
/* gdtype.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "gdtype.h"
|
||||
|
||||
GDType::GDType(const GDType *p_super_type, StringName p_name) :
|
||||
super_type(p_super_type), name(std::move(p_name)) {
|
||||
name_hierarchy.push_back(StringName(name, true));
|
||||
|
||||
if (super_type) {
|
||||
for (const StringName &ancestor_name : super_type->name_hierarchy) {
|
||||
name_hierarchy.push_back(StringName(ancestor_name, true));
|
||||
}
|
||||
}
|
||||
}
|
50
core/object/gdtype.h
Normal file
50
core/object/gdtype.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/**************************************************************************/
|
||||
/* gdtype.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/string/string_name.h"
|
||||
#include "core/templates/vector.h"
|
||||
|
||||
class GDType {
|
||||
const GDType *super_type;
|
||||
|
||||
StringName name;
|
||||
/// Contains all the class names in order:
|
||||
/// `name` is the first element and `Object` is the last.
|
||||
Vector<StringName> name_hierarchy;
|
||||
|
||||
public:
|
||||
GDType(const GDType *p_super_type, StringName p_name);
|
||||
|
||||
const GDType *get_super_type() const { return super_type; }
|
||||
const StringName &get_name() const { return name; }
|
||||
const Vector<StringName> &get_name_hierarchy() const { return name_hierarchy; }
|
||||
};
|
|
@ -258,7 +258,7 @@ bool Object::_predelete() {
|
|||
return false;
|
||||
}
|
||||
|
||||
_class_name_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
|
||||
_gdtype_ptr = nullptr; // Must restore, so constructors/destructors have proper class name access at each stage.
|
||||
notification(NOTIFICATION_PREDELETE_CLEANUP, true);
|
||||
|
||||
// Destruction order starts with the most derived class, and progresses towards the base Object class:
|
||||
|
@ -301,7 +301,7 @@ void Object::cancel_free() {
|
|||
|
||||
void Object::_initialize() {
|
||||
// Cache the class name in the object for quick reference.
|
||||
_class_name_ptr = _get_class_namev();
|
||||
_gdtype_ptr = &_get_typev();
|
||||
_initialize_classv();
|
||||
}
|
||||
|
||||
|
@ -2085,18 +2085,34 @@ uint32_t Object::get_edited_version() const {
|
|||
}
|
||||
#endif
|
||||
|
||||
const GDType &Object::get_gdtype() const {
|
||||
if (unlikely(!_gdtype_ptr)) {
|
||||
// While class is initializing / deinitializing, constructors and destructors
|
||||
// need access to the proper type at the proper stage.
|
||||
return _get_typev();
|
||||
}
|
||||
return *_gdtype_ptr;
|
||||
}
|
||||
|
||||
bool Object::is_class(const String &p_class) const {
|
||||
if (_extension && _extension->is_class(p_class)) {
|
||||
return true;
|
||||
}
|
||||
for (const StringName &name : get_gdtype().get_name_hierarchy()) {
|
||||
if (name == p_class) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const StringName &Object::get_class_name() const {
|
||||
if (_extension) {
|
||||
// Can't put inside the unlikely as constructor can run it.
|
||||
return _extension->class_name;
|
||||
}
|
||||
|
||||
if (unlikely(!_class_name_ptr)) {
|
||||
// While class is initializing / deinitializing, constructors and destructors
|
||||
// need access to the proper class at the proper stage.
|
||||
return *_get_class_namev();
|
||||
}
|
||||
return *_class_name_ptr;
|
||||
return get_gdtype().get_name();
|
||||
}
|
||||
|
||||
StringName Object::get_class_name_for_extension(const GDExtension *p_library) const {
|
||||
|
@ -2105,8 +2121,7 @@ StringName Object::get_class_name_for_extension(const GDExtension *p_library) co
|
|||
// have to return the closest native parent's class name, so that it doesn't try to
|
||||
// use this like the real object.
|
||||
if (unlikely(_extension && _extension->library == p_library && _extension->is_placeholder)) {
|
||||
const StringName *class_name = _get_class_namev();
|
||||
return *class_name;
|
||||
return get_class_name();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2116,13 +2131,13 @@ StringName Object::get_class_name_for_extension(const GDExtension *p_library) co
|
|||
}
|
||||
|
||||
// Extensions only have wrapper classes for classes exposed in ClassDB.
|
||||
const StringName *class_name = _get_class_namev();
|
||||
if (ClassDB::is_class_exposed(*class_name)) {
|
||||
return *class_name;
|
||||
const StringName &class_name = get_class_name();
|
||||
if (ClassDB::is_class_exposed(class_name)) {
|
||||
return class_name;
|
||||
}
|
||||
|
||||
// Find the nearest parent class that's exposed.
|
||||
StringName parent_class = ClassDB::get_parent_class(*class_name);
|
||||
StringName parent_class = ClassDB::get_parent_class(class_name);
|
||||
while (parent_class != StringName()) {
|
||||
if (ClassDB::is_class_exposed(parent_class)) {
|
||||
return parent_class;
|
||||
|
@ -2296,14 +2311,16 @@ void Object::detach_from_objectdb() {
|
|||
}
|
||||
}
|
||||
|
||||
void Object::assign_class_name_static(const Span<char> &p_name, StringName &r_target) {
|
||||
void Object::assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type) {
|
||||
static BinaryMutex _mutex;
|
||||
MutexLock lock(_mutex);
|
||||
if (r_target) {
|
||||
// Already assigned while we were waiting for the mutex.
|
||||
GDType *type = *type_ptr;
|
||||
if (type) {
|
||||
// Assigned while we were waiting.
|
||||
return;
|
||||
}
|
||||
r_target = StringName(p_name.ptr(), true);
|
||||
type = memnew(GDType(super_type, StringName(p_name, true)));
|
||||
*type_ptr = type;
|
||||
}
|
||||
|
||||
Object::~Object() {
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "core/extension/gdextension_interface.h"
|
||||
#include "core/object/gdtype.h"
|
||||
#include "core/object/message_queue.h"
|
||||
#include "core/object/object_id.h"
|
||||
#include "core/os/rw_lock.h"
|
||||
|
@ -494,21 +495,18 @@ private:
|
|||
friend class ::ClassDB; \
|
||||
\
|
||||
public: \
|
||||
virtual const StringName *_get_class_namev() const override { \
|
||||
return &get_class_static(); \
|
||||
virtual const GDType &_get_typev() const override { \
|
||||
return get_gdtype_static(); \
|
||||
} \
|
||||
static const GDType &get_gdtype_static() { \
|
||||
static GDType *_class_static; \
|
||||
if (unlikely(!_class_static)) { \
|
||||
assign_type_static(&_class_static, #m_class, &super_type::get_gdtype_static()); \
|
||||
} \
|
||||
return *_class_static; \
|
||||
} \
|
||||
static const StringName &get_class_static() { \
|
||||
static StringName _class_name_static; \
|
||||
if (unlikely(!_class_name_static)) { \
|
||||
assign_class_name_static(#m_class, _class_name_static); \
|
||||
} \
|
||||
return _class_name_static; \
|
||||
} \
|
||||
virtual bool is_class(const String &p_class) const override { \
|
||||
if (_get_extension() && _get_extension()->is_class(p_class)) { \
|
||||
return true; \
|
||||
} \
|
||||
return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); \
|
||||
return get_gdtype_static().get_name(); \
|
||||
} \
|
||||
\
|
||||
protected: \
|
||||
|
@ -668,7 +666,7 @@ private:
|
|||
Variant script; // Reference does not exist yet, store it in a Variant.
|
||||
HashMap<StringName, Variant> metadata;
|
||||
HashMap<StringName, Variant *> metadata_properties;
|
||||
mutable const StringName *_class_name_ptr = nullptr;
|
||||
mutable const GDType *_gdtype_ptr = nullptr;
|
||||
|
||||
void _add_user_signal(const String &p_name, const Array &p_args = Array());
|
||||
bool _has_user_signal(const StringName &p_name) const;
|
||||
|
@ -774,9 +772,7 @@ protected:
|
|||
Variant _call_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
Variant _call_deferred_bind(const Variant **p_args, int p_argcount, Callable::CallError &r_error);
|
||||
|
||||
virtual const StringName *_get_class_namev() const {
|
||||
return &get_class_static();
|
||||
}
|
||||
virtual const GDType &_get_typev() const { return get_gdtype_static(); }
|
||||
|
||||
TypedArray<StringName> _get_meta_list_bind() const;
|
||||
TypedArray<Dictionary> _get_property_list_bind() const;
|
||||
|
@ -842,26 +838,25 @@ public:
|
|||
};
|
||||
|
||||
/* TYPE API */
|
||||
static void assign_class_name_static(const Span<char> &p_name, StringName &r_target);
|
||||
static void assign_type_static(GDType **type_ptr, const char *p_name, const GDType *super_type);
|
||||
|
||||
static const StringName &get_class_static() {
|
||||
static StringName _class_name_static;
|
||||
if (unlikely(!_class_name_static)) {
|
||||
assign_class_name_static("Object", _class_name_static);
|
||||
static const GDType &get_gdtype_static() {
|
||||
static GDType *_class_static;
|
||||
if (unlikely(!_class_static)) {
|
||||
assign_type_static(&_class_static, "Object", nullptr);
|
||||
}
|
||||
return _class_name_static;
|
||||
return *_class_static;
|
||||
}
|
||||
|
||||
const GDType &get_gdtype() const;
|
||||
|
||||
static const StringName &get_class_static() { return get_gdtype_static().get_name(); }
|
||||
|
||||
_FORCE_INLINE_ String get_class() const { return get_class_name(); }
|
||||
|
||||
virtual String get_save_class() const { return get_class(); } //class stored when saving
|
||||
|
||||
virtual bool is_class(const String &p_class) const {
|
||||
if (_extension && _extension->is_class(p_class)) {
|
||||
return true;
|
||||
}
|
||||
return (p_class == "Object");
|
||||
}
|
||||
bool is_class(const String &p_class) const;
|
||||
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
|
||||
|
||||
template <typename T>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue