Set instance and instance binding in Wrapped constructor.
parent
b697ba8896
commit
76cbc66785
|
@ -46,13 +46,31 @@ class ClassDB;
|
||||||
|
|
||||||
typedef void GodotObject;
|
typedef void GodotObject;
|
||||||
|
|
||||||
|
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
|
||||||
|
_ALWAYS_INLINE_ void _pre_initialize();
|
||||||
|
|
||||||
// Base for all engine classes, to contain the pointer to the engine instance.
|
// Base for all engine classes, to contain the pointer to the engine instance.
|
||||||
class Wrapped {
|
class Wrapped {
|
||||||
friend class GDExtensionBinding;
|
friend class GDExtensionBinding;
|
||||||
friend class ClassDB;
|
friend class ClassDB;
|
||||||
friend void postinitialize_handler(Wrapped *);
|
friend void postinitialize_handler(Wrapped *);
|
||||||
|
|
||||||
|
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
|
||||||
|
friend _ALWAYS_INLINE_ void _pre_initialize();
|
||||||
|
|
||||||
|
thread_local static const StringName *_constructing_extension_class_name;
|
||||||
|
thread_local static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
_ALWAYS_INLINE_ static void _set_construct_info() {
|
||||||
|
_constructing_extension_class_name = T::_get_extension_class_name();
|
||||||
|
_constructing_class_binding_callbacks = &T::_gde_binding_callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual bool _is_extension_class() const { return false; }
|
||||||
|
static const StringName *_get_extension_class_name(); // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
|
||||||
|
|
||||||
#ifdef HOT_RELOAD_ENABLED
|
#ifdef HOT_RELOAD_ENABLED
|
||||||
struct RecreateInstance {
|
struct RecreateInstance {
|
||||||
GDExtensionClassInstancePtr wrapper;
|
GDExtensionClassInstancePtr wrapper;
|
||||||
|
@ -62,9 +80,6 @@ protected:
|
||||||
inline static RecreateInstance *recreate_instance = nullptr;
|
inline static RecreateInstance *recreate_instance = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
virtual const StringName *_get_extension_class_name() const; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned.
|
|
||||||
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const = 0;
|
|
||||||
|
|
||||||
void _notification(int p_what) {}
|
void _notification(int p_what) {}
|
||||||
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
|
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
|
||||||
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
|
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
|
||||||
|
@ -109,6 +124,11 @@ public:
|
||||||
GodotObject *_owner = nullptr;
|
GodotObject *_owner = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
|
||||||
|
_ALWAYS_INLINE_ void _pre_initialize() {
|
||||||
|
Wrapped::_set_construct_info<T>();
|
||||||
|
}
|
||||||
|
|
||||||
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
|
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,15 +181,14 @@ struct EngineClassRegistration {
|
||||||
private: \
|
private: \
|
||||||
void operator=(const m_class &p_rval) {} \
|
void operator=(const m_class &p_rval) {} \
|
||||||
friend class ::godot::ClassDB; \
|
friend class ::godot::ClassDB; \
|
||||||
|
friend class ::godot::Wrapped; \
|
||||||
\
|
\
|
||||||
protected: \
|
protected: \
|
||||||
virtual const ::godot::StringName *_get_extension_class_name() const override { \
|
virtual bool _is_extension_class() const override { return true; } \
|
||||||
static ::godot::StringName string_name = get_class_static(); \
|
|
||||||
return &string_name; \
|
|
||||||
} \
|
|
||||||
\
|
\
|
||||||
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
|
static const ::godot::StringName *_get_extension_class_name() { \
|
||||||
return &_gde_binding_callbacks; \
|
const ::godot::StringName &string_name = get_class_static(); \
|
||||||
|
return &string_name; \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static void (*_get_bind_methods())() { \
|
static void (*_get_bind_methods())() { \
|
||||||
|
@ -388,12 +407,9 @@ private:
|
||||||
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
|
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
|
||||||
void operator=(const m_class &p_rval) {} \
|
void operator=(const m_class &p_rval) {} \
|
||||||
friend class ::godot::ClassDB; \
|
friend class ::godot::ClassDB; \
|
||||||
|
friend class ::godot::Wrapped; \
|
||||||
\
|
\
|
||||||
protected: \
|
protected: \
|
||||||
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
|
|
||||||
return &_gde_binding_callbacks; \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
|
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
|
||||||
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
|
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
|
||||||
\
|
\
|
||||||
|
|
|
@ -82,6 +82,9 @@ public:
|
||||||
static void free_static(void *p_ptr, bool p_pad_align = false);
|
static void free_static(void *p_ptr, bool p_pad_align = false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T, std::enable_if_t<!std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
|
||||||
|
_ALWAYS_INLINE_ void _pre_initialize() {}
|
||||||
|
|
||||||
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
|
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -94,10 +97,10 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
|
||||||
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
|
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
|
||||||
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
|
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
|
||||||
|
|
||||||
#define memnew(m_class) ::godot::_post_initialize(new ("", "") m_class)
|
#define memnew(m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", "") m_class))
|
||||||
|
|
||||||
#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new ("", m_allocator::alloc) m_class)
|
#define memnew_allocator(m_class, m_allocator) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_allocator::alloc) m_class))
|
||||||
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class)
|
#define memnew_placement(m_placement, m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class))
|
||||||
|
|
||||||
// Generic comparator used in Map, List, etc.
|
// Generic comparator used in Map, List, etc.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
|
|
@ -39,18 +39,16 @@
|
||||||
#include <godot_cpp/core/class_db.hpp>
|
#include <godot_cpp/core/class_db.hpp>
|
||||||
|
|
||||||
namespace godot {
|
namespace godot {
|
||||||
|
thread_local const StringName *Wrapped::_constructing_extension_class_name = nullptr;
|
||||||
|
thread_local const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr;
|
||||||
|
|
||||||
const StringName *Wrapped::_get_extension_class_name() const {
|
const StringName *Wrapped::_get_extension_class_name() {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wrapped::_postinitialize() {
|
void Wrapped::_postinitialize() {
|
||||||
const StringName *extension_class = _get_extension_class_name();
|
// Only send NOTIFICATION_POSTINITIALIZE for extension classes.
|
||||||
if (extension_class) {
|
if (_is_extension_class()) {
|
||||||
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(extension_class), this);
|
|
||||||
}
|
|
||||||
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
|
|
||||||
if (extension_class) {
|
|
||||||
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
|
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,6 +74,19 @@ Wrapped::Wrapped(const StringName p_godot_class) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
_owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
|
_owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
|
||||||
|
|
||||||
|
if (_constructing_extension_class_name) {
|
||||||
|
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(_constructing_extension_class_name), this);
|
||||||
|
_constructing_extension_class_name = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (likely(_constructing_class_binding_callbacks)) {
|
||||||
|
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _constructing_class_binding_callbacks);
|
||||||
|
_constructing_class_binding_callbacks = nullptr;
|
||||||
|
} else {
|
||||||
|
ERR_PRINT("BUG: create a Godot Object without binding callbacks.");
|
||||||
|
CRASH_NOW_MSG("BUG: create a Godot Object without binding callbacks.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Wrapped::Wrapped(GodotObject *p_godot_object) {
|
Wrapped::Wrapped(GodotObject *p_godot_object) {
|
||||||
|
|
|
@ -9,6 +9,9 @@ class TestClass:
|
||||||
func _ready():
|
func _ready():
|
||||||
var example: Example = $Example
|
var example: Example = $Example
|
||||||
|
|
||||||
|
# Timing of set instance binding.
|
||||||
|
assert_equal(example.is_object_binding_set_by_parent_constructor(), true)
|
||||||
|
|
||||||
# Signal.
|
# Signal.
|
||||||
example.emit_custom_signal("Button", 42)
|
example.emit_custom_signal("Button", 42)
|
||||||
assert_equal(custom_signal_emitted, ["Button", 42])
|
assert_equal(custom_signal_emitted, ["Button", 42])
|
||||||
|
|
|
@ -193,6 +193,8 @@ void Example::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("return_extended_ref"), &Example::return_extended_ref);
|
ClassDB::bind_method(D_METHOD("return_extended_ref"), &Example::return_extended_ref);
|
||||||
ClassDB::bind_method(D_METHOD("extended_ref_checks", "ref"), &Example::extended_ref_checks);
|
ClassDB::bind_method(D_METHOD("extended_ref_checks", "ref"), &Example::extended_ref_checks);
|
||||||
|
|
||||||
|
ClassDB::bind_method(D_METHOD("is_object_binding_set_by_parent_constructor"), &Example::is_object_binding_set_by_parent_constructor);
|
||||||
|
|
||||||
ClassDB::bind_method(D_METHOD("test_array"), &Example::test_array);
|
ClassDB::bind_method(D_METHOD("test_array"), &Example::test_array);
|
||||||
ClassDB::bind_method(D_METHOD("test_tarray_arg", "array"), &Example::test_tarray_arg);
|
ClassDB::bind_method(D_METHOD("test_tarray_arg", "array"), &Example::test_tarray_arg);
|
||||||
ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray);
|
ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray);
|
||||||
|
@ -290,7 +292,17 @@ void Example::_bind_methods() {
|
||||||
BIND_ENUM_CONSTANT(OUTSIDE_OF_CLASS);
|
BIND_ENUM_CONSTANT(OUTSIDE_OF_CLASS);
|
||||||
}
|
}
|
||||||
|
|
||||||
Example::Example() {
|
bool Example::has_object_instance_binding() const {
|
||||||
|
return internal::gdextension_interface_object_get_instance_binding(_owner, internal::token, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
Example::Example() :
|
||||||
|
object_instance_binding_set_by_parent_constructor(has_object_instance_binding()) {
|
||||||
|
// Test conversion, to ensure users can use all parent calss functions at this time.
|
||||||
|
// It would crash if instance binding still not be initialized.
|
||||||
|
Variant v = Variant(this);
|
||||||
|
Object *o = (Object *)v;
|
||||||
|
|
||||||
//UtilityFunctions::print("Constructor.");
|
//UtilityFunctions::print("Constructor.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,6 +382,10 @@ void Example::emit_custom_signal(const String &name, int value) {
|
||||||
emit_signal("custom_signal", name, value);
|
emit_signal("custom_signal", name, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Example::is_object_binding_set_by_parent_constructor() const {
|
||||||
|
return object_instance_binding_set_by_parent_constructor;
|
||||||
|
}
|
||||||
|
|
||||||
Array Example::test_array() const {
|
Array Example::test_array() const {
|
||||||
Array arr;
|
Array arr;
|
||||||
|
|
||||||
|
|
|
@ -82,6 +82,9 @@ private:
|
||||||
Vector2 dprop[3];
|
Vector2 dprop[3];
|
||||||
int last_rpc_arg = 0;
|
int last_rpc_arg = 0;
|
||||||
|
|
||||||
|
const bool object_instance_binding_set_by_parent_constructor;
|
||||||
|
bool has_object_instance_binding() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constants.
|
// Constants.
|
||||||
enum Constants {
|
enum Constants {
|
||||||
|
@ -120,6 +123,8 @@ public:
|
||||||
void emit_custom_signal(const String &name, int value);
|
void emit_custom_signal(const String &name, int value);
|
||||||
int def_args(int p_a = 100, int p_b = 200);
|
int def_args(int p_a = 100, int p_b = 200);
|
||||||
|
|
||||||
|
bool is_object_binding_set_by_parent_constructor() const;
|
||||||
|
|
||||||
Array test_array() const;
|
Array test_array() const;
|
||||||
int test_tarray_arg(const TypedArray<int64_t> &p_array);
|
int test_tarray_arg(const TypedArray<int64_t> &p_array);
|
||||||
TypedArray<Vector2> test_tarray() const;
|
TypedArray<Vector2> test_tarray() const;
|
||||||
|
|
Loading…
Reference in New Issue