Skip to content

Commit de0b3d0

Browse files
Set instance and instance binding in Wrapped constructor.
1 parent b697ba8 commit de0b3d0

File tree

7 files changed

+92
-28
lines changed

7 files changed

+92
-28
lines changed

include/godot_cpp/classes/wrapped.hpp

Lines changed: 29 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,18 +41,33 @@
4141
#include <godot_cpp/godot.hpp>
4242

4343
namespace godot {
44-
4544
class ClassDB;
4645

4746
typedef void GodotObject;
4847

48+
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
49+
_ALWAYS_INLINE_ void _pre_initialize();
50+
4951
// Base for all engine classes, to contain the pointer to the engine instance.
5052
class Wrapped {
5153
friend class GDExtensionBinding;
5254
friend class ClassDB;
5355
friend void postinitialize_handler(Wrapped *);
5456

57+
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
58+
friend _ALWAYS_INLINE_ void _pre_initialize();
59+
60+
thread_local static const StringName *_constructing_extension_class_name;
61+
thread_local static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;
62+
63+
_ALWAYS_INLINE_ static void _set_construct_info(const StringName *p_extension_class_name, const GDExtensionInstanceBindingCallbacks *p_binding_callbacks) {
64+
_constructing_extension_class_name = p_extension_class_name;
65+
_constructing_class_binding_callbacks = p_binding_callbacks;
66+
}
67+
5568
protected:
69+
virtual bool _is_extension_class() const { return false; }
70+
5671
#ifdef HOT_RELOAD_ENABLED
5772
struct RecreateInstance {
5873
GDExtensionClassInstancePtr wrapper;
@@ -62,9 +77,6 @@ class Wrapped {
6277
inline static RecreateInstance *recreate_instance = nullptr;
6378
#endif
6479

65-
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.
66-
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const = 0;
67-
6880
void _notification(int p_what) {}
6981
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
7082
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
@@ -96,6 +108,8 @@ class Wrapped {
96108
virtual ~Wrapped() {}
97109

98110
public:
111+
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.
112+
99113
static const StringName &get_class_static() {
100114
static const StringName string_name = StringName("Wrapped");
101115
return string_name;
@@ -109,6 +123,11 @@ class Wrapped {
109123
GodotObject *_owner = nullptr;
110124
};
111125

126+
template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
127+
_ALWAYS_INLINE_ void _pre_initialize() {
128+
Wrapped::_set_construct_info(T::_get_extension_class_name(), &T::_gde_binding_callbacks);
129+
}
130+
112131
_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
113132
}
114133

@@ -163,15 +182,7 @@ private:
163182
friend class ::godot::ClassDB; \
164183
\
165184
protected: \
166-
virtual const ::godot::StringName *_get_extension_class_name() const override { \
167-
static ::godot::StringName string_name = get_class_static(); \
168-
return &string_name; \
169-
} \
170-
\
171-
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
172-
return &_gde_binding_callbacks; \
173-
} \
174-
\
185+
virtual bool _is_extension_class() const override { return true; } \
175186
static void (*_get_bind_methods())() { \
176187
return &m_class::_bind_methods; \
177188
} \
@@ -214,6 +225,11 @@ protected:
214225
} \
215226
\
216227
public: \
228+
static const ::godot::StringName *_get_extension_class_name() { \
229+
const ::godot::StringName &string_name = get_class_static(); \
230+
return &string_name; \
231+
} \
232+
\
217233
typedef m_class self_type; \
218234
typedef m_inherits parent_type; \
219235
\
@@ -390,10 +406,6 @@ private:
390406
friend class ::godot::ClassDB; \
391407
\
392408
protected: \
393-
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
394-
return &_gde_binding_callbacks; \
395-
} \
396-
\
397409
m_class(const char *p_godot_class) : m_inherits(p_godot_class) {} \
398410
m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
399411
\

include/godot_cpp/core/memory.hpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ class Memory {
8282
static void free_static(void *p_ptr, bool p_pad_align = false);
8383
};
8484

85+
template <typename T, std::enable_if_t<!std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
86+
_ALWAYS_INLINE_ void _pre_initialize() {}
87+
8588
_ALWAYS_INLINE_ void postinitialize_handler(void *) {}
8689

8790
template <typename T>
@@ -94,10 +97,10 @@ _ALWAYS_INLINE_ T *_post_initialize(T *p_obj) {
9497
#define memrealloc(m_mem, m_size) ::godot::Memory::realloc_static(m_mem, m_size)
9598
#define memfree(m_mem) ::godot::Memory::free_static(m_mem)
9699

97-
#define memnew(m_class) ::godot::_post_initialize(new ("", "") m_class)
100+
#define memnew(m_class) (::godot::_pre_initialize<std::remove_pointer_t<decltype(new ("", "") m_class)>>(), ::godot::_post_initialize(new ("", "") m_class))
98101

99-
#define memnew_allocator(m_class, m_allocator) ::godot::_post_initialize(new ("", m_allocator::alloc) m_class)
100-
#define memnew_placement(m_placement, m_class) ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") m_class)
102+
#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))
103+
#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))
101104

102105
// Generic comparator used in Map, List, etc.
103106
template <typename T>

src/classes/wrapped.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,16 @@
3939
#include <godot_cpp/core/class_db.hpp>
4040

4141
namespace godot {
42+
thread_local const StringName *Wrapped::_constructing_extension_class_name = nullptr;
43+
thread_local const GDExtensionInstanceBindingCallbacks *Wrapped::_constructing_class_binding_callbacks = nullptr;
4244

43-
const StringName *Wrapped::_get_extension_class_name() const {
45+
const StringName *Wrapped::_get_extension_class_name() {
4446
return nullptr;
4547
}
4648

4749
void Wrapped::_postinitialize() {
48-
const StringName *extension_class = _get_extension_class_name();
49-
if (extension_class) {
50-
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(extension_class), this);
51-
}
52-
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
53-
if (extension_class) {
50+
// Only send NOTIFICATION_POSTINITIALIZE for extension classes.
51+
if (_is_extension_class()) {
5452
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
5553
}
5654
}
@@ -76,6 +74,16 @@ Wrapped::Wrapped(const StringName p_godot_class) {
7674
}
7775
#endif
7876
_owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
77+
78+
if (_constructing_extension_class_name) {
79+
godot::internal::gdextension_interface_object_set_instance(_owner, reinterpret_cast<GDExtensionConstStringNamePtr>(_constructing_extension_class_name), this);
80+
_constructing_extension_class_name = nullptr;
81+
}
82+
83+
if (_constructing_class_binding_callbacks) {
84+
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _constructing_class_binding_callbacks);
85+
_constructing_class_binding_callbacks = nullptr;
86+
}
7987
}
8088

8189
Wrapped::Wrapped(GodotObject *p_godot_object) {

test/project/main.gd

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ class TestClass:
99
func _ready():
1010
var example: Example = $Example
1111

12+
# Timing of set instance binding.
13+
assert_equal(example.is_object_binding_set_by_parent_constructor(), true)
14+
1215
# Signal.
1316
example.emit_custom_signal("Button", 42)
1417
assert_equal(custom_signal_emitted, ["Button", 42])

test/src/example.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ void Example::_bind_methods() {
193193
ClassDB::bind_method(D_METHOD("return_extended_ref"), &Example::return_extended_ref);
194194
ClassDB::bind_method(D_METHOD("extended_ref_checks", "ref"), &Example::extended_ref_checks);
195195

196+
ClassDB::bind_method(D_METHOD("is_object_binding_set_by_parent_constructor"), &Example::is_object_binding_set_by_parent_constructor);
197+
196198
ClassDB::bind_method(D_METHOD("test_array"), &Example::test_array);
197199
ClassDB::bind_method(D_METHOD("test_tarray_arg", "array"), &Example::test_tarray_arg);
198200
ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray);
@@ -290,7 +292,17 @@ void Example::_bind_methods() {
290292
BIND_ENUM_CONSTANT(OUTSIDE_OF_CLASS);
291293
}
292294

293-
Example::Example() {
295+
bool Example::has_object_instance_binding() const {
296+
return internal::gdextension_interface_object_get_instance_binding(_owner, internal::token, nullptr);
297+
}
298+
299+
Example::Example() :
300+
object_instance_binding_set_by_parent_constructor(has_object_instance_binding()) {
301+
// Test conversion, to ensure users can use all parent calss functions at this time.
302+
// It would crash if instance binding still not be initialized.
303+
Variant v = Variant(this);
304+
Object *o = (Object *)v;
305+
294306
//UtilityFunctions::print("Constructor.");
295307
}
296308

@@ -370,6 +382,10 @@ void Example::emit_custom_signal(const String &name, int value) {
370382
emit_signal("custom_signal", name, value);
371383
}
372384

385+
bool Example::is_object_binding_set_by_parent_constructor() const {
386+
return object_instance_binding_set_by_parent_constructor;
387+
}
388+
373389
Array Example::test_array() const {
374390
Array arr;
375391

test/src/example.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,9 @@ class Example : public Control {
8282
Vector2 dprop[3];
8383
int last_rpc_arg = 0;
8484

85+
const bool object_instance_binding_set_by_parent_constructor;
86+
bool has_object_instance_binding() const;
87+
8588
public:
8689
// Constants.
8790
enum Constants {
@@ -120,6 +123,8 @@ class Example : public Control {
120123
void emit_custom_signal(const String &name, int value);
121124
int def_args(int p_a = 100, int p_b = 200);
122125

126+
bool is_object_binding_set_by_parent_constructor() const;
127+
123128
Array test_array() const;
124129
int test_tarray_arg(const TypedArray<int64_t> &p_array);
125130
TypedArray<Vector2> test_tarray() const;

test/src/register_types.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include <gdextension_interface.h>
99

10+
#include <godot_cpp/classes/line_edit.hpp>
1011
#include <godot_cpp/core/class_db.hpp>
1112
#include <godot_cpp/core/defs.hpp>
1213
#include <godot_cpp/godot.hpp>
@@ -16,10 +17,26 @@
1617

1718
using namespace godot;
1819

20+
class MyLineEdit : public LineEdit {
21+
GDCLASS(MyLineEdit, LineEdit)
22+
protected:
23+
static void _bind_methods() {}
24+
25+
public:
26+
void _on_text_submitted(const String &p_test) {
27+
UtilityFunctions::print("Submitted: ", p_test);
28+
}
29+
30+
MyLineEdit() {
31+
connect("text_submitted", callable_mp(this, &MyLineEdit::_on_text_submitted));
32+
}
33+
};
34+
1935
void initialize_example_module(ModuleInitializationLevel p_level) {
2036
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
2137
return;
2238
}
39+
GDREGISTER_CLASS(MyLineEdit);
2340

2441
GDREGISTER_CLASS(ExampleRef);
2542
GDREGISTER_CLASS(ExampleMin);

0 commit comments

Comments
 (0)