From 270ad28931e57b7babdd7316c9b3d66b6f6a9e58 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Fri, 19 Aug 2022 10:30:06 +0300 Subject: [PATCH] Add support for `_notification`, `_set`, `_get`, `_get_property_list`, `_property_can_revert`, `_property_get_revert`, and `_to_string` methods. --- include/godot_cpp/classes/wrapped.hpp | 341 ++++++++++++++++++----- include/godot_cpp/core/class_db.hpp | 16 +- include/godot_cpp/core/defs.hpp | 1 + include/godot_cpp/core/method_bind.hpp | 6 +- include/godot_cpp/core/object.hpp | 41 +-- include/godot_cpp/core/property_info.hpp | 86 ++++++ test/demo/main.gd | 10 + test/demo/main.tscn | 2 + test/src/example.cpp | 45 +++ test/src/example.h | 17 ++ test/src/register_types.cpp | 1 + 11 files changed, 447 insertions(+), 119 deletions(-) create mode 100644 include/godot_cpp/core/property_info.hpp diff --git a/include/godot_cpp/classes/wrapped.hpp b/include/godot_cpp/classes/wrapped.hpp index 986edb15..75484d66 100644 --- a/include/godot_cpp/classes/wrapped.hpp +++ b/include/godot_cpp/classes/wrapped.hpp @@ -33,6 +33,10 @@ #include +#include + +#include + #include namespace godot { @@ -48,6 +52,26 @@ protected: virtual const char *_get_extension_class() const; // This is needed to retrieve the class name before the godot object has its _extension and _extension_instance members assigned. virtual const GDNativeInstanceBindingCallbacks *_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; }; + void _get_property_list(List *p_list) const {}; + bool _property_can_revert(const StringName &p_name) const { return false; }; + bool _property_get_revert(const StringName &p_name, Variant &r_property) const { return false; }; + String _to_string() const { return "[" + String(get_class_static()) + ":" + itos(get_instance_id()) + "]"; } + + static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) {} + static GDNativeBool set_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value) { return false; } + static GDNativeBool get_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { return false; } + static const GDNativePropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { return nullptr; } + static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list) {} + static GDNativeBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name) { return false; } + static GDNativeBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { return false; } + static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr r_out) {} + + GDNativePropertyInfo *plist = nullptr; + uint32_t plist_size = 0; + void _postinitialize(); Wrapped(const char *p_godot_class); @@ -58,82 +82,231 @@ public: return "Wrapped"; } + uint64_t get_instance_id() const { + return 0; + } + + static _FORCE_INLINE_ char *_alloc_and_copy_cstr(const char *p_str) { + size_t size = strlen(p_str) + 1; + char *ret = reinterpret_cast(memalloc(size)); + memcpy(ret, p_str, size); + return ret; + } + // Must be public but you should not touch this. GodotObject *_owner = nullptr; }; } // namespace godot -#define GDCLASS(m_class, m_inherits) \ -private: \ - void operator=(const m_class &p_rval) {} \ - friend class ::godot::ClassDB; \ - \ -protected: \ - virtual const char *_get_extension_class() const override { \ - return get_class_static(); \ - } \ - \ - virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const override { \ - return &___binding_callbacks; \ - } \ - \ - static void (*_get_bind_methods())() { \ - return &m_class::_bind_methods; \ - } \ - \ - template \ - static void register_virtuals() { \ - m_inherits::register_virtuals(); \ - } \ - \ -public: \ - static void initialize_class() { \ - static bool initialized = false; \ - if (initialized) { \ - return; \ - } \ - m_inherits::initialize_class(); \ - if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ - _bind_methods(); \ - m_inherits::register_virtuals(); \ - } \ - initialized = true; \ - } \ - \ - static const char *get_class_static() { \ - return #m_class; \ - } \ - \ - static const char *get_parent_class_static() { \ - return m_inherits::get_class_static(); \ - } \ - \ - static GDNativeObjectPtr create(void *data) { \ - m_class *new_object = memnew(m_class); \ - return new_object->_owner; \ - } \ - \ - static void free(void *data, GDExtensionClassInstancePtr ptr) { \ - if (ptr) { \ - m_class *cls = reinterpret_cast(ptr); \ - cls->~m_class(); \ - ::godot::Memory::free_static(cls); \ - } \ - } \ - \ - static void *___binding_create_callback(void *p_token, void *p_instance) { \ - return nullptr; \ - } \ - static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ - } \ - static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ - return true; \ - } \ - static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ - ___binding_create_callback, \ - ___binding_free_callback, \ - ___binding_reference_callback, \ +#define GDCLASS(m_class, m_inherits) \ +private: \ + void operator=(const m_class &p_rval) {} \ + friend class ::godot::ClassDB; \ + \ +protected: \ + virtual const char *_get_extension_class() const override { \ + return get_class_static(); \ + } \ + \ + virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const override { \ + return &___binding_callbacks; \ + } \ + \ + static void (*_get_bind_methods())() { \ + return &m_class::_bind_methods; \ + } \ + \ + static void (Wrapped::*_get_notification())(int) { \ + return (void(Wrapped::*)(int)) & m_class::_notification; \ + } \ + \ + static bool (Wrapped::*_get_set())(const StringName &p_name, const Variant &p_property) { \ + return (bool(Wrapped::*)(const StringName &p_name, const Variant &p_property)) & m_class::_set; \ + } \ + \ + static bool (Wrapped::*_get_get())(const StringName &p_name, Variant &r_ret) { \ + return (bool(Wrapped::*)(const StringName &p_name, Variant &r_ret)) & m_class::_set; \ + } \ + \ + static void (Wrapped::*_get_get_property_list())(List * p_list) { \ + return (void(Wrapped::*)(List * p_list)) & m_class::_get_property_list; \ + } \ + \ + static bool (Wrapped::*_get_property_can_revert())(const StringName &p_name) { \ + return (bool(Wrapped::*)(const StringName &p_name)) & m_class::_property_can_revert; \ + } \ + \ + static bool (Wrapped::*_get_property_get_revert())(const StringName &p_name, Variant &) { \ + return (bool(Wrapped::*)(const StringName &p_name, Variant &)) & m_class::_property_get_revert; \ + } \ + \ + static String (Wrapped::*_get_to_string())() { \ + return (String(Wrapped::*)()) & m_class::_to_string; \ + } \ + \ + template \ + static void register_virtuals() { \ + m_inherits::register_virtuals(); \ + } \ + \ +public: \ + static void initialize_class() { \ + static bool initialized = false; \ + if (initialized) { \ + return; \ + } \ + m_inherits::initialize_class(); \ + if (m_class::_get_bind_methods() != m_inherits::_get_bind_methods()) { \ + _bind_methods(); \ + m_inherits::register_virtuals(); \ + } \ + initialized = true; \ + } \ + \ + static const char *get_class_static() { \ + return #m_class; \ + } \ + \ + static const char *get_parent_class_static() { \ + return m_inherits::get_class_static(); \ + } \ + \ + static GDNativeObjectPtr create(void *data) { \ + m_class *new_object = memnew(m_class); \ + return new_object->_owner; \ + } \ + \ + static void notification_bind(GDExtensionClassInstancePtr p_instance, int32_t p_what) { \ + if (p_instance && m_class::_get_notification()) { \ + if (m_class::_get_notification() != m_inherits::_get_notification()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_notification(p_what); \ + } \ + m_inherits::notification_bind(p_instance, p_what); \ + } \ + } \ + \ + static GDNativeBool set_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, const GDNativeVariantPtr p_value) { \ + if (p_instance && m_class::_get_set()) { \ + if (m_class::_get_set() != m_inherits::_get_set()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_set(*reinterpret_cast(p_name), *reinterpret_cast(p_value)); \ + } \ + return m_inherits::set_bind(p_instance, p_name, p_value); \ + } \ + return false; \ + } \ + \ + static GDNativeBool get_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { \ + if (p_instance && m_class::_get_get()) { \ + if (m_class::_get_get() != m_inherits::_get_get()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_get(*reinterpret_cast(p_name), *reinterpret_cast(r_ret)); \ + } \ + return m_inherits::get_bind(p_instance, p_name, r_ret); \ + } \ + return false; \ + } \ + \ + static const GDNativePropertyInfo *get_property_list_bind(GDExtensionClassInstancePtr p_instance, uint32_t *r_count) { \ + if (p_instance && m_class::_get_get_property_list()) { \ + if (m_class::_get_get_property_list() != m_inherits::_get_get_property_list()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + List list; \ + cls->_get_property_list(&list); \ + ERR_FAIL_COND_V_MSG(cls->plist != nullptr || cls->plist_size != 0, nullptr, "Internal error, property list was not freed by engine!"); \ + cls->plist = reinterpret_cast(memalloc(sizeof(GDNativePropertyInfo) * list.size())); \ + cls->plist_size = 0; \ + for (const PropertyInfo &E : list) { \ + cls->plist[cls->plist_size].type = E.type; \ + cls->plist[cls->plist_size].name = _alloc_and_copy_cstr(E.name); \ + cls->plist[cls->plist_size].hint = E.hint; \ + cls->plist[cls->plist_size].hint_string = _alloc_and_copy_cstr(E.hint_string); \ + cls->plist[cls->plist_size].class_name = _alloc_and_copy_cstr(E.class_name); \ + cls->plist[cls->plist_size].usage = E.usage; \ + cls->plist_size++; \ + } \ + if (r_count) \ + *r_count = cls->plist_size; \ + return cls->plist; \ + } \ + return m_inherits::get_property_list_bind(p_instance, r_count); \ + } \ + return nullptr; \ + } \ + \ + static void free_property_list_bind(GDExtensionClassInstancePtr p_instance, const GDNativePropertyInfo *p_list) { \ + if (p_instance) { \ + m_class *cls = reinterpret_cast(p_instance); \ + ERR_FAIL_COND_MSG(cls->plist == nullptr, "Internal error, property list double free!"); \ + for (size_t i = 0; i < cls->plist_size; i++) { \ + memfree(const_cast(cls->plist[i].name)); \ + memfree(const_cast(cls->plist[i].class_name)); \ + memfree(const_cast(cls->plist[i].hint_string)); \ + } \ + memfree(cls->plist); \ + cls->plist = nullptr; \ + cls->plist_size = 0; \ + } \ + } \ + \ + static GDNativeBool property_can_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name) { \ + if (p_instance && m_class::_get_property_can_revert()) { \ + if (m_class::_get_property_can_revert() != m_inherits::_get_property_can_revert()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_property_can_revert(*reinterpret_cast(p_name)); \ + } \ + return m_inherits::property_can_revert_bind(p_instance, p_name); \ + } \ + return false; \ + } \ + \ + static GDNativeBool property_get_revert_bind(GDExtensionClassInstancePtr p_instance, const GDNativeStringNamePtr p_name, GDNativeVariantPtr r_ret) { \ + if (p_instance && m_class::_get_property_get_revert()) { \ + if (m_class::_get_property_get_revert() != m_inherits::_get_property_get_revert()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + return cls->_property_get_revert(*reinterpret_cast(p_name), *reinterpret_cast(r_ret)); \ + } \ + return m_inherits::property_get_revert_bind(p_instance, p_name, r_ret); \ + } \ + return false; \ + } \ + \ + static void to_string_bind(GDExtensionClassInstancePtr p_instance, GDNativeStringPtr r_out) { \ + if (p_instance && m_class::_get_to_string()) { \ + if (m_class::_get_to_string() != m_inherits::_get_to_string()) { \ + m_class *cls = reinterpret_cast(p_instance); \ + *reinterpret_cast(r_out) = cls->_to_string(); \ + return; \ + } \ + m_inherits::to_string_bind(p_instance, r_out); \ + } \ + } \ + \ + static void free(void *data, GDExtensionClassInstancePtr ptr) { \ + if (ptr) { \ + m_class *cls = reinterpret_cast(ptr); \ + cls->~m_class(); \ + ::godot::Memory::free_static(cls); \ + } \ + } \ + \ + static void *___binding_create_callback(void *p_token, void *p_instance) { \ + return nullptr; \ + } \ + \ + static void ___binding_free_callback(void *p_token, void *p_instance, void *p_binding) { \ + } \ + \ + static GDNativeBool ___binding_reference_callback(void *p_token, void *p_instance, GDNativeBool p_reference) { \ + return true; \ + } \ + \ + static constexpr GDNativeInstanceBindingCallbacks ___binding_callbacks = { \ + ___binding_create_callback, \ + ___binding_free_callback, \ + ___binding_reference_callback, \ }; // Don't use this for your classes, use GDCLASS() instead. @@ -153,6 +326,34 @@ protected: return nullptr; \ } \ \ + static void (Wrapped::*_get_notification())(int) { \ + return nullptr; \ + } \ + \ + static bool (Wrapped::*_get_set())(const StringName &p_name, const Variant &p_property) { \ + return nullptr; \ + } \ + \ + static bool (Wrapped::*_get_get())(const StringName &p_name, Variant &r_ret) { \ + return nullptr; \ + } \ + \ + static void (Wrapped::*_get_get_property_list())(List * p_list) { \ + return nullptr; \ + } \ + \ + static bool (Wrapped::*_get_property_can_revert())(const StringName &p_name) { \ + return nullptr; \ + } \ + \ + static bool (Wrapped::*_get_property_get_revert())(const StringName &p_name, Variant &) { \ + return nullptr; \ + } \ + \ + static String (Wrapped::*_get_to_string())() { \ + return nullptr; \ + } \ + \ public: \ static void initialize_class() {} \ \ diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp index 7a05738d..02e7a795 100644 --- a/include/godot_cpp/core/class_db.hpp +++ b/include/godot_cpp/core/class_db.hpp @@ -158,14 +158,14 @@ void ClassDB::register_class() { // Register this class with Godot GDNativeExtensionClassCreationInfo class_info = { - nullptr, // GDNativeExtensionClassSet set_func; - nullptr, // GDNativeExtensionClassGet get_func; - nullptr, // GDNativeExtensionClassGetPropertyList get_property_list_func; - nullptr, // GDNativeExtensionClassFreePropertyList free_property_list_func; - nullptr, // GDNativeExtensionClassPropertyCanRevert property_can_revert_func; - nullptr, // GDNativeExtensionClassPropertyGetRevert property_get_revert_func; - nullptr, // GDNativeExtensionClassNotification notification_func; - nullptr, // GDNativeExtensionClassToString to_string_func; + T::set_bind, // GDNativeExtensionClassSet set_func; + T::get_bind, // GDNativeExtensionClassGet get_func; + T::get_property_list_bind, // GDNativeExtensionClassGetPropertyList get_property_list_func; + T::free_property_list_bind, // GDNativeExtensionClassFreePropertyList free_property_list_func; + T::property_can_revert_bind, // GDNativeExtensionClassPropertyCanRevert property_can_revert_func; + T::property_get_revert_bind, // GDNativeExtensionClassPropertyGetRevert property_get_revert_func; + T::notification_bind, // GDNativeExtensionClassNotification notification_func; + T::to_string_bind, // GDNativeExtensionClassToString to_string_func; nullptr, // GDNativeExtensionClassReference reference_func; nullptr, // GDNativeExtensionClassUnreference unreference_func; T::create, // GDNativeExtensionClassCreateInstance create_instance_func; /* this one is mandatory */ diff --git a/include/godot_cpp/core/defs.hpp b/include/godot_cpp/core/defs.hpp index b9e37162..9d300f47 100644 --- a/include/godot_cpp/core/defs.hpp +++ b/include/godot_cpp/core/defs.hpp @@ -33,6 +33,7 @@ #include #include +#include #if !defined(GDN_EXPORT) #if defined(_WIN32) diff --git a/include/godot_cpp/core/method_bind.hpp b/include/godot_cpp/core/method_bind.hpp index 52479986..cc332f1c 100644 --- a/include/godot_cpp/core/method_bind.hpp +++ b/include/godot_cpp/core/method_bind.hpp @@ -287,7 +287,7 @@ protected: if (p_arg >= 0 && p_arg < (int)sizeof...(P)) { call_get_argument_type_info(p_arg, pi); } else { - pi = PropertyInfo(); + pi = GDNativePropertyInfo(); } return pi; } @@ -363,7 +363,7 @@ protected: if (p_arg >= 0 && p_arg < (int)sizeof...(P)) { call_get_argument_type_info(p_arg, pi); } else { - pi = PropertyInfo(); + pi = GDNativePropertyInfo(); } return pi; } @@ -603,7 +603,7 @@ protected: if (p_arg >= 0 && p_arg < (int)sizeof...(P)) { call_get_argument_type_info(p_arg, pi); } else { - pi = PropertyInfo(); + pi = GDNativePropertyInfo(); } return pi; } diff --git a/include/godot_cpp/core/object.hpp b/include/godot_cpp/core/object.hpp index df2ef25e..3acf827a 100644 --- a/include/godot_cpp/core/object.hpp +++ b/include/godot_cpp/core/object.hpp @@ -32,6 +32,9 @@ #define GODOT_OBJECT_HPP #include + +#include + #include #include @@ -49,44 +52,6 @@ namespace godot { -struct PropertyInfo { - Variant::Type type = Variant::NIL; - const char *name = nullptr; - const char *class_name = nullptr; - uint32_t hint = 0; - const char *hint_string = nullptr; - uint32_t usage = 7; - - operator GDNativePropertyInfo() const { - GDNativePropertyInfo info; - info.type = type; - info.name = name; - info.hint = hint; - info.hint_string = hint_string; - info.class_name = class_name; - info.usage = usage; - return info; - } - - PropertyInfo() = default; - - PropertyInfo(Variant::Type p_type, const char *p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const char *p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const char *p_class_name = "") : - type(p_type), - name(p_name), - hint(p_hint), - hint_string(p_hint_string), - usage(p_usage) { - if (hint == PROPERTY_HINT_RESOURCE_TYPE) { - class_name = hint_string; - } else { - class_name = p_class_name; - } - } - - PropertyInfo(GDNativeVariantType p_type, const char *p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const char *p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const char *p_class_name = "") : - PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {} -}; - struct MethodInfo { const char *name; PropertyInfo return_val; diff --git a/include/godot_cpp/core/property_info.hpp b/include/godot_cpp/core/property_info.hpp new file mode 100644 index 00000000..4bdf31a7 --- /dev/null +++ b/include/godot_cpp/core/property_info.hpp @@ -0,0 +1,86 @@ +/*************************************************************************/ +/* property_info.hpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_PROPERTY_INFO_HPP +#define GODOT_PROPERTY_INFO_HPP + +#include + +#include + +#include + +#include + +#include + +namespace godot { + +struct PropertyInfo { + Variant::Type type = Variant::NIL; + const char *name = nullptr; + const char *class_name = nullptr; + uint32_t hint = 0; + const char *hint_string = nullptr; + uint32_t usage = 7; + + operator GDNativePropertyInfo() const { + GDNativePropertyInfo info; + info.type = type; + info.name = name; + info.hint = hint; + info.hint_string = hint_string; + info.class_name = class_name; + info.usage = usage; + return info; + } + + PropertyInfo() = default; + + PropertyInfo(Variant::Type p_type, const char *p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const char *p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const char *p_class_name = "") : + type(p_type), + name(p_name), + hint(p_hint), + hint_string(p_hint_string), + usage(p_usage) { + if (hint == PROPERTY_HINT_RESOURCE_TYPE) { + class_name = hint_string; + } else { + class_name = p_class_name; + } + } + + PropertyInfo(GDNativeVariantType p_type, const char *p_name, PropertyHint p_hint = PROPERTY_HINT_NONE, const char *p_hint_string = "", uint32_t p_usage = PROPERTY_USAGE_DEFAULT, const char *p_class_name = "") : + PropertyInfo((Variant::Type)p_type, p_name, p_hint, p_hint_string, p_usage, p_class_name) {} +}; + +} // namespace godot + +#endif // ! GODOT_OBJECT_HPP diff --git a/test/demo/main.gd b/test/demo/main.gd index 48aa6866..537462f3 100644 --- a/test/demo/main.gd +++ b/test/demo/main.gd @@ -7,10 +7,20 @@ func _ready(): prints("") + # To string. + prints("To string") + prints(" Example --> ", $Example.to_string()) + prints(" ExampleMin --> ", $Example/ExampleMin.to_string()) + # Call static methods. prints("Static method calls") prints(" static (109)", Example.test_static(9, 100)); Example.test_static2(); + + # Property list. + prints("Property list") + $Example.property_from_list = Vector3(100, 200, 300) + prints(" property value ", $Example.property_from_list) # Call methods. prints("Instance method calls") diff --git a/test/demo/main.tscn b/test/demo/main.tscn index 2d101f8a..b2a1eaea 100644 --- a/test/demo/main.tscn +++ b/test/demo/main.tscn @@ -7,6 +7,8 @@ script = ExtResource( "1_c326s" ) [node name="Example" type="Example" parent="."] +[node name="ExampleMin" type="ExampleMin" parent="Example"] + [node name="Label" type="Label" parent="Example"] offset_left = 194.0 offset_top = -2.0 diff --git a/test/src/example.cpp b/test/src/example.cpp index 992f29c3..1cdc89a6 100644 --- a/test/src/example.cpp +++ b/test/src/example.cpp @@ -58,6 +58,51 @@ int Example::def_args(int p_a, int p_b) { return p_a + p_b; } +void Example::_notification(int p_what) { + UtilityFunctions::print("Notification: ", String::num(p_what)); +} + +bool Example::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == StringName("property_from_list")) { + property_from_list = p_value; + return true; + } + return false; +} + +bool Example::_get(const StringName &p_name, Variant &r_ret) const { + if (p_name == StringName("property_from_list")) { + r_ret = property_from_list; + return true; + } + return false; +} + +String Example::_to_string() const { + return "[ GDExtension::Example <--> Instance ID:" + itos(get_instance_id()) + " ]"; +} + +void Example::_get_property_list(List *p_list) const { + p_list->push_back(PropertyInfo(Variant::VECTOR3, "property_from_list")); +} + +bool Example::_property_can_revert(const StringName &p_name) const { + if (p_name == StringName("property_from_list") && property_from_list != Vector3(42, 42, 42)) { + return true; + } else { + return false; + } +}; + +bool Example::_property_get_revert(const StringName &p_name, Variant &r_property) const { + if (p_name == StringName("property_from_list")) { + r_property = Vector3(42, 42, 42); + return true; + } else { + return false; + } +}; + void Example::_bind_methods() { // Methods. ClassDB::bind_method(D_METHOD("simple_func"), &Example::simple_func); diff --git a/test/src/example.h b/test/src/example.h index ca87f740..74ef3f86 100644 --- a/test/src/example.h +++ b/test/src/example.h @@ -56,14 +56,31 @@ public: ~ExampleRef(); }; +class ExampleMin : public Control { + GDCLASS(ExampleMin, Control); + +protected: + static void _bind_methods(){}; +}; + class Example : public Control { GDCLASS(Example, Control); protected: static void _bind_methods(); + void _notification(int p_what); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List *p_list) const; + bool _property_can_revert(const StringName &p_name) const; + bool _property_get_revert(const StringName &p_name, Variant &r_property) const; + + String _to_string() const; + private: Vector2 custom_position; + Vector3 property_from_list; public: // Constants. diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp index b05f43d9..97b2c486 100644 --- a/test/src/register_types.cpp +++ b/test/src/register_types.cpp @@ -46,6 +46,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) { } ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); }