Skip to content

Commit

Permalink
Set instance and instance binding in Wrapped constructor.
Browse files Browse the repository at this point in the history
  • Loading branch information
Daylily-Zeleen committed Apr 25, 2024
1 parent ad307e4 commit acd8e4c
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 28 deletions.
50 changes: 33 additions & 17 deletions include/godot_cpp/classes/wrapped.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@
#include <godot_cpp/godot.hpp>

namespace godot {

namespace internal {
_ALWAYS_INLINE_ void _set_construct_info(const StringName *p_extension_class_name, const GDExtensionInstanceBindingCallbacks *p_binding_callbacks);
} //namespace internal
class ClassDB;

typedef void GodotObject;
Expand All @@ -52,7 +54,17 @@ class Wrapped {
friend class ClassDB;
friend void postinitialize_handler(Wrapped *);

friend _ALWAYS_INLINE_ void internal::_set_construct_info(const StringName *p_extension_class_name, const GDExtensionInstanceBindingCallbacks *p_binding_callbacks);

thread_local static const StringName *_constructing_extension_class_name;
thread_local static const GDExtensionInstanceBindingCallbacks *_constructing_class_binding_callbacks;

void _initialize();

protected:
bool has_object_instance_binding() const;
virtual bool _is_extension_class() const { return false; }

#ifdef HOT_RELOAD_ENABLED
struct RecreateInstance {
GDExtensionClassInstancePtr wrapper;
Expand All @@ -62,9 +74,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 @@ -95,6 +104,8 @@ class Wrapped {
virtual ~Wrapped() {}

public:
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.

static StringName &get_class_static() {
static StringName string_name = StringName("Wrapped");
return string_name;
Expand All @@ -108,6 +119,18 @@ class Wrapped {
GodotObject *_owner = nullptr;
};

namespace internal {
_ALWAYS_INLINE_ void _set_construct_info(const StringName *p_extension_class_name, const GDExtensionInstanceBindingCallbacks *p_binding_callbacks) {
Wrapped::_constructing_extension_class_name = p_extension_class_name;
Wrapped::_constructing_class_binding_callbacks = p_binding_callbacks;
}
} //namespace internal

template <typename T, std::enable_if_t<std::is_base_of<::godot::Wrapped, T>::value, bool> = true>
_ALWAYS_INLINE_ void _pre_initialize() {
internal::_set_construct_info(T::_get_extension_class_name(), &T::_gde_binding_callbacks);
}

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

Expand Down Expand Up @@ -162,15 +185,7 @@ private:
friend class ::godot::ClassDB; \
\
protected: \
virtual const ::godot::StringName *_get_extension_class_name() const override { \
static ::godot::StringName string_name = get_class_static(); \
return &string_name; \
} \
\
virtual const GDExtensionInstanceBindingCallbacks *_get_bindings_callbacks() const override { \
return &_gde_binding_callbacks; \
} \
\
virtual bool _is_extension_class() const override { return true; } \
static void (*_get_bind_methods())() { \
return &m_class::_bind_methods; \
} \
Expand Down Expand Up @@ -213,6 +228,11 @@ protected:
} \
\
public: \
static const ::godot::StringName *_get_extension_class_name() { \
static ::godot::StringName string_name = get_class_static(); \
return &string_name; \
} \
\
typedef m_class self_type; \
\
static void initialize_class() { \
Expand Down Expand Up @@ -383,10 +403,6 @@ private:
void operator=(const m_class &p_rval) {} \
\
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
29 changes: 22 additions & 7 deletions src/classes/wrapped.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,32 @@
#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 {
bool Wrapped::has_object_instance_binding() const {
return internal::gdextension_interface_object_get_instance_binding(_owner, internal::token, nullptr);
}

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);
void Wrapped::_initialize() {
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 (_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;
}
godot::internal::gdextension_interface_object_set_instance_binding(_owner, godot::internal::token, this, _get_bindings_callbacks());
if (extension_class) {
}

void Wrapped::_postinitialize() {
// Only send NOTIFICATION_POSTINITIALIZE for extension classes.
if (_is_extension_class()) {
Object *obj = dynamic_cast<Object *>(this);
if (obj) {
obj->notification(Object::NOTIFICATION_POSTINITIALIZE);
Expand Down Expand Up @@ -79,6 +93,7 @@ Wrapped::Wrapped(const StringName p_godot_class) {
}
#endif
_owner = godot::internal::gdextension_interface_classdb_construct_object(reinterpret_cast<GDExtensionConstStringNamePtr>(p_godot_class._native_ptr()));
_initialize();
}

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
9 changes: 8 additions & 1 deletion test/src/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,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 @@ -287,7 +289,8 @@ void Example::_bind_methods() {
BIND_ENUM_CONSTANT(OUTSIDE_OF_CLASS);
}

Example::Example() {
Example::Example() :
object_instance_binding_set_by_parent_constructor(has_object_instance_binding()) {
//UtilityFunctions::print("Constructor.");
}

Expand Down Expand Up @@ -367,6 +370,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
4 changes: 4 additions & 0 deletions test/src/example.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ class Example : public Control {
Vector2 dprop[3];
int last_rpc_arg = 0;

const bool object_instance_binding_set_by_parent_constructor;

public:
// Constants.
enum Constants {
Expand Down Expand Up @@ -120,6 +122,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

0 comments on commit acd8e4c

Please sign in to comment.