Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set instance and instance binding in Wrapped constructor. #1446

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 29 additions & 13 deletions include/godot_cpp/classes/wrapped.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,31 @@ class ClassDB;

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.
class Wrapped {
friend class GDExtensionBinding;
friend class ClassDB;
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:
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
struct RecreateInstance {
GDExtensionClassInstancePtr wrapper;
Expand All @@ -62,9 +80,6 @@ class Wrapped {
inline static RecreateInstance *recreate_instance = nullptr;
#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) {}
bool _set(const StringName &p_name, const Variant &p_property) { return false; }
bool _get(const StringName &p_name, Variant &r_property) const { return false; }
Expand Down Expand Up @@ -109,6 +124,11 @@ class Wrapped {
GodotObject *_owner = nullptr;
};

template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool>>
_ALWAYS_INLINE_ void _pre_initialize() {
dsnopek marked this conversation as resolved.
Show resolved Hide resolved
Wrapped::_set_construct_info<T>();
}

_FORCE_INLINE_ void snarray_add_str(Vector<StringName> &arr) {
}

Expand Down Expand Up @@ -161,15 +181,14 @@ struct EngineClassRegistration {
private: \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
protected: \
virtual const ::godot::StringName *_get_extension_class_name() const override { \
static ::godot::StringName string_name = get_class_static(); \
return &string_name; \
} \
virtual bool _is_extension_class() const override { return true; } \
\
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &_gde_binding_callbacks; \
static const ::godot::StringName *_get_extension_class_name() { \
const ::godot::StringName &string_name = get_class_static(); \
return &string_name; \
} \
\
static void (*_get_bind_methods())() { \
Expand Down Expand Up @@ -388,12 +407,9 @@ private:
inline static ::godot::internal::EngineClassRegistration<m_class> _gde_engine_class_registration_helper; \
void operator=(const m_class &p_rval) {} \
friend class ::godot::ClassDB; \
friend class ::godot::Wrapped; \
\
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(GodotObject *p_godot_object) : m_inherits(p_godot_object) {} \
\
Expand Down
9 changes: 6 additions & 3 deletions include/godot_cpp/core/memory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class Memory {
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 *) {}

template <typename T>
Expand All @@ -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 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_placement(m_placement, m_class) ::godot::_post_initialize(new ("", m_placement, sizeof(m_class), "") 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::_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.
template <typename T>
Expand Down
25 changes: 18 additions & 7 deletions src/classes/wrapped.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,16 @@
#include <godot_cpp/core/class_db.hpp>

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;
}

void Wrapped::_postinitialize() {
const StringName *extension_class = _get_extension_class_name();
if (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) {
// Only send NOTIFICATION_POSTINITIALIZE for extension classes.
if (_is_extension_class()) {
_notificationv(Object::NOTIFICATION_POSTINITIALIZE);
}
}
Expand All @@ -76,6 +74,19 @@ Wrapped::Wrapped(const StringName p_godot_class) {
}
#endif
_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) {
Expand Down
3 changes: 3 additions & 0 deletions test/project/main.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class TestClass:
func _ready():
var example: Example = $Example

# Timing of set instance binding.
assert_equal(example.is_object_binding_set_by_parent_constructor(), true)

# Signal.
example.emit_custom_signal("Button", 42)
assert_equal(custom_signal_emitted, ["Button", 42])
Expand Down
18 changes: 17 additions & 1 deletion test/src/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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("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_tarray_arg", "array"), &Example::test_tarray_arg);
ClassDB::bind_method(D_METHOD("test_tarray"), &Example::test_tarray);
Expand Down Expand Up @@ -290,7 +292,17 @@ void Example::_bind_methods() {
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()) {
dsnopek marked this conversation as resolved.
Show resolved Hide resolved
// 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.");
}

Expand Down Expand Up @@ -370,6 +382,10 @@ void Example::emit_custom_signal(const String &name, int 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 arr;

Expand Down
5 changes: 5 additions & 0 deletions test/src/example.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ class Example : public Control {
Vector2 dprop[3];
int last_rpc_arg = 0;

const bool object_instance_binding_set_by_parent_constructor;
bool has_object_instance_binding() const;

public:
// Constants.
enum Constants {
Expand Down Expand Up @@ -120,6 +123,8 @@ class Example : public Control {
void emit_custom_signal(const String &name, int value);
int def_args(int p_a = 100, int p_b = 200);

bool is_object_binding_set_by_parent_constructor() const;

Array test_array() const;
int test_tarray_arg(const TypedArray<int64_t> &p_array);
TypedArray<Vector2> test_tarray() const;
Expand Down
Loading