diff --git a/core/io/resource.h b/core/io/resource.h index 090d2248e2c..af4a70352b6 100644 --- a/core/io/resource.h +++ b/core/io/resource.h @@ -54,6 +54,8 @@ class Resource : public RefCounted { GDCLASS(Resource, RefCounted); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::RESOURCE; + static void register_custom_data_to_otdb() { ClassDB::add_resource_base_extension("res", get_class_static()); } virtual String get_base_extension() const { return "res"; } diff --git a/core/object/object.h b/core/object/object.h index c0e33457973..2a78743d712 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -605,6 +605,8 @@ public: MESH_INSTANCE_3D = 1 << 14, }; + static constexpr AncestralClass static_ancestral_class = (AncestralClass)0; + struct Connection { ::Signal signal; Callable callable; @@ -790,6 +792,8 @@ protected: bool _disconnect(const StringName &p_signal, const Callable &p_callable, bool p_force = false); void _define_ancestry(AncestralClass p_class) { _ancestry |= (uint32_t)p_class; } + // Prefer using derives_from. + bool _has_ancestry(AncestralClass p_class) const { return _ancestry & (uint32_t)p_class; } virtual bool _uses_signal_mutex() const; @@ -821,16 +825,12 @@ public: static T *cast_to(Object *p_object) { // This is like dynamic_cast, but faster. // The reason is that we can assume no virtual and multiple inheritance. - static_assert(std::is_base_of_v, "T must be derived from Object"); - static_assert(std::is_same_v, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS"); - return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast(p_object) : nullptr; + return p_object && p_object->derives_from() ? static_cast(p_object) : nullptr; } template static const T *cast_to(const Object *p_object) { - static_assert(std::is_base_of_v, "T must be derived from Object"); - static_assert(std::is_same_v, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS"); - return p_object && p_object->is_class_ptr(T::get_class_ptr_static()) ? static_cast(p_object) : nullptr; + return p_object && p_object->derives_from() ? static_cast(p_object) : nullptr; } enum { @@ -864,7 +864,8 @@ public: } virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; } - bool has_ancestry(AncestralClass p_class) const { return _ancestry & (uint32_t)p_class; } + template + bool derives_from() const; const StringName &get_class_name() const; @@ -1024,7 +1025,7 @@ public: void clear_internal_resource_paths(); - _ALWAYS_INLINE_ bool is_ref_counted() const { return has_ancestry(AncestralClass::REF_COUNTED); } + _ALWAYS_INLINE_ bool is_ref_counted() const { return _has_ancestry(AncestralClass::REF_COUNTED); } void cancel_free(); @@ -1035,6 +1036,29 @@ public: bool predelete_handler(Object *p_object); void postinitialize_handler(Object *p_object); +template +bool Object::derives_from() const { + static_assert(std::is_base_of_v, "T must be derived from Object."); + static_assert(std::is_same_v, typename T::self_type>, "T must use GDCLASS or GDSOFTCLASS."); + + // If there is an explicitly set ancestral class on the type, we can use that. + if constexpr (T::static_ancestral_class != T::super_type::static_ancestral_class) { + return _has_ancestry(T::static_ancestral_class); + } else { + return is_class_ptr(T::get_class_ptr_static()); + } +} + +template <> +inline bool Object::derives_from() const { + return true; +} + +template <> +inline bool Object::derives_from() const { + return true; +} + class ObjectDB { // This needs to add up to 63, 1 bit is for reference. #define OBJECTDB_VALIDATOR_BITS 39 diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h index 3bd2b06272d..9fca55dd225 100644 --- a/core/object/ref_counted.h +++ b/core/object/ref_counted.h @@ -42,6 +42,8 @@ protected: static void _bind_methods(); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::REF_COUNTED; + _FORCE_INLINE_ bool is_referenced() const { return refcount_init.get() != 1; } bool init_ref(); bool reference(); // returns false if refcount is at zero and didn't get increased diff --git a/core/object/script_language.h b/core/object/script_language.h index 4b995347751..a1bbb58d92a 100644 --- a/core/object/script_language.h +++ b/core/object/script_language.h @@ -140,6 +140,8 @@ protected: } public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::SCRIPT; + virtual void reload_from_file() override; virtual bool can_instantiate() const = 0; diff --git a/scene/2d/node_2d.h b/scene/2d/node_2d.h index dadb163baf0..be18ff82ce9 100644 --- a/scene/2d/node_2d.h +++ b/scene/2d/node_2d.h @@ -55,6 +55,8 @@ protected: static void _bind_methods(); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::NODE_2D; + #ifdef TOOLS_ENABLED virtual Dictionary _edit_get_state() const override; virtual void _edit_set_state(const Dictionary &p_state) override; diff --git a/scene/2d/physics/area_2d.h b/scene/2d/physics/area_2d.h index 982346f3007..b6f6288b661 100644 --- a/scene/2d/physics/area_2d.h +++ b/scene/2d/physics/area_2d.h @@ -37,6 +37,8 @@ class Area2D : public CollisionObject2D { GDCLASS(Area2D, CollisionObject2D); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::AREA_2D; + enum SpaceOverride { SPACE_OVERRIDE_DISABLED, SPACE_OVERRIDE_COMBINE, diff --git a/scene/2d/physics/collision_object_2d.h b/scene/2d/physics/collision_object_2d.h index c63d0ac40a1..a46e9d2daf3 100644 --- a/scene/2d/physics/collision_object_2d.h +++ b/scene/2d/physics/collision_object_2d.h @@ -39,6 +39,8 @@ class CollisionObject2D : public Node2D { GDCLASS(CollisionObject2D, Node2D); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::COLLISION_OBJECT_2D; + enum DisableMode { DISABLE_MODE_REMOVE, DISABLE_MODE_MAKE_STATIC, diff --git a/scene/3d/mesh_instance_3d.h b/scene/3d/mesh_instance_3d.h index 28ca664a778..2e89639693e 100644 --- a/scene/3d/mesh_instance_3d.h +++ b/scene/3d/mesh_instance_3d.h @@ -70,6 +70,8 @@ protected: bool _property_get_revert(const StringName &p_name, Variant &r_property) const; public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::MESH_INSTANCE_3D; + void set_mesh(const Ref &p_mesh); Ref get_mesh() const; diff --git a/scene/3d/node_3d.h b/scene/3d/node_3d.h index cf68d2c831f..2936c8923e7 100644 --- a/scene/3d/node_3d.h +++ b/scene/3d/node_3d.h @@ -54,6 +54,8 @@ class Node3D : public Node { friend class SceneTreeFTITests; public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::NODE_3D; + // Edit mode for the rotation. // THIS MODE ONLY AFFECTS HOW DATA IS EDITED AND SAVED // IT DOES _NOT_ AFFECT THE TRANSFORM LOGIC (see comment in TransformDirty). diff --git a/scene/3d/physics/collision_object_3d.h b/scene/3d/physics/collision_object_3d.h index 8483e770096..e40b949c877 100644 --- a/scene/3d/physics/collision_object_3d.h +++ b/scene/3d/physics/collision_object_3d.h @@ -37,6 +37,8 @@ class CollisionObject3D : public Node3D { GDCLASS(CollisionObject3D, Node3D); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::COLLISION_OBJECT_3D; + enum DisableMode { DISABLE_MODE_REMOVE, DISABLE_MODE_MAKE_STATIC, diff --git a/scene/3d/physics/physics_body_3d.h b/scene/3d/physics/physics_body_3d.h index b9ab0eefd33..5c5608010dd 100644 --- a/scene/3d/physics/physics_body_3d.h +++ b/scene/3d/physics/physics_body_3d.h @@ -49,6 +49,8 @@ protected: Ref _move(const Vector3 &p_motion, bool p_test_only = false, real_t p_margin = 0.001, bool p_recovery_as_collision = false, int p_max_collisions = 1); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::PHYSICS_BODY_3D; + PackedStringArray get_configuration_warnings() const override; bool move_and_collide(const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult &r_result, bool p_test_only = false, bool p_cancel_sliding = true); diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h index 727066a754b..ad25327ce0b 100644 --- a/scene/3d/visual_instance_3d.h +++ b/scene/3d/visual_instance_3d.h @@ -53,6 +53,8 @@ protected: GDVIRTUAL0RC(AABB, _get_aabb) public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::VISUAL_INSTANCE_3D; + enum GetFacesFlags { FACES_SOLID = 1, // solid geometry FACES_ENCLOSING = 2, @@ -86,6 +88,8 @@ class GeometryInstance3D : public VisualInstance3D { GDCLASS(GeometryInstance3D, VisualInstance3D); public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::GEOMETRY_INSTANCE_3D; + enum ShadowCastingSetting { SHADOW_CASTING_SETTING_OFF = RS::SHADOW_CASTING_SETTING_OFF, SHADOW_CASTING_SETTING_ON = RS::SHADOW_CASTING_SETTING_ON, diff --git a/scene/gui/control.h b/scene/gui/control.h index b8b47c9be9d..78846c0ea02 100644 --- a/scene/gui/control.h +++ b/scene/gui/control.h @@ -50,6 +50,8 @@ class Control : public CanvasItem { #endif //TOOLS_ENABLED public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::CONTROL; + enum Anchor { ANCHOR_BEGIN = 0, ANCHOR_END = 1 diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 9de847b81fc..b66c9c555de 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -45,6 +45,8 @@ class CanvasItem : public Node { friend class CanvasLayer; public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::CANVAS_ITEM; + enum TextureFilter { TEXTURE_FILTER_PARENT_NODE, TEXTURE_FILTER_NEAREST, diff --git a/scene/main/node.h b/scene/main/node.h index 8276b4715f5..b9eb0b71320 100644 --- a/scene/main/node.h +++ b/scene/main/node.h @@ -67,6 +67,8 @@ protected: }; public: + static constexpr AncestralClass static_ancestral_class = AncestralClass::NODE; + // N.B. Any enum stored as a bitfield should be specified as UNSIGNED to work around // some compilers trying to store it as signed, and requiring 1 more bit than necessary. enum ProcessMode : unsigned int {