Browse Source

Merge pull request #816 from bruvzg/get_set_props

Rémi Verschelde 3 years ago
parent
commit
24f97739a1

+ 263 - 62
include/godot_cpp/classes/wrapped.hpp

@@ -33,6 +33,10 @@
 
 #include <godot_cpp/core/memory.hpp>
 
+#include <godot_cpp/core/property_info.hpp>
+
+#include <godot_cpp/templates/list.hpp>
+
 #include <godot_cpp/godot.hpp>
 
 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<PropertyInfo> *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,98 +82,275 @@ 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<char *>(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)                                                                               \
+#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<PropertyInfo> * p_list) {                                                                      \
+		return (void(Wrapped::*)(List<PropertyInfo> * 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 <class T>                                                                                                                                   \
+	static void register_virtuals() {                                                                                                                    \
+		m_inherits::register_virtuals<T>();                                                                                                              \
+	}                                                                                                                                                    \
+                                                                                                                                                         \
+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<m_class>();                                                                                                    \
+		}                                                                                                                                                \
+		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<m_class *>(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<m_class *>(p_instance);                                                                                  \
+				return cls->_set(*reinterpret_cast<const StringName *>(p_name), *reinterpret_cast<const Variant *>(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<m_class *>(p_instance);                                                                                  \
+				return cls->_get(*reinterpret_cast<const StringName *>(p_name), *reinterpret_cast<Variant *>(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<m_class *>(p_instance);                                                                                  \
+				List<PropertyInfo> 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<GDNativePropertyInfo *>(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<m_class *>(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<char *>(cls->plist[i].name));                                                                                         \
+				memfree(const_cast<char *>(cls->plist[i].class_name));                                                                                   \
+				memfree(const_cast<char *>(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<m_class *>(p_instance);                                                                                  \
+				return cls->_property_can_revert(*reinterpret_cast<const StringName *>(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<m_class *>(p_instance);                                                                                  \
+				return cls->_property_get_revert(*reinterpret_cast<const StringName *>(p_name), *reinterpret_cast<Variant *>(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<m_class *>(p_instance);                                                                                  \
+				*reinterpret_cast<String *>(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<m_class *>(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.
+#define GDNATIVE_CLASS(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 <class T>                                                                                             \
-	static void register_virtuals() {                                                                              \
-		m_inherits::register_virtuals<T>();                                                                        \
-	}                                                                                                              \
+	m_class(const char *p_godot_class) : m_inherits(p_godot_class) {}                                              \
+	m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {}                                           \
                                                                                                                    \
-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<m_class>();                                                              \
-		}                                                                                                          \
-		initialized = true;                                                                                        \
+	static void (*_get_bind_methods())() {                                                                         \
+		return nullptr;                                                                                            \
 	}                                                                                                              \
                                                                                                                    \
-	static const char *get_class_static() {                                                                        \
-		return #m_class;                                                                                           \
+	static void (Wrapped::*_get_notification())(int) {                                                             \
+		return nullptr;                                                                                            \
 	}                                                                                                              \
                                                                                                                    \
-	static const char *get_parent_class_static() {                                                                 \
-		return m_inherits::get_class_static();                                                                     \
+	static bool (Wrapped::*_get_set())(const StringName &p_name, const Variant &p_property) {                      \
+		return nullptr;                                                                                            \
 	}                                                                                                              \
                                                                                                                    \
-	static GDNativeObjectPtr create(void *data) {                                                                  \
-		m_class *new_object = memnew(m_class);                                                                     \
-		return new_object->_owner;                                                                                 \
+	static bool (Wrapped::*_get_get())(const StringName &p_name, Variant &r_ret) {                                 \
+		return nullptr;                                                                                            \
 	}                                                                                                              \
                                                                                                                    \
-	static void free(void *data, GDExtensionClassInstancePtr ptr) {                                                \
-		if (ptr) {                                                                                                 \
-			m_class *cls = reinterpret_cast<m_class *>(ptr);                                                       \
-			cls->~m_class();                                                                                       \
-			::godot::Memory::free_static(cls);                                                                     \
-		}                                                                                                          \
+	static void (Wrapped::*_get_get_property_list())(List<PropertyInfo> * p_list) {                                \
+		return nullptr;                                                                                            \
 	}                                                                                                              \
                                                                                                                    \
-	static void *___binding_create_callback(void *p_token, void *p_instance) {                                     \
+	static bool (Wrapped::*_get_property_can_revert())(const StringName &p_name) {                                 \
 		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.
-#define GDNATIVE_CLASS(m_class, m_inherits)                                                                        \
-private:                                                                                                           \
-	void operator=(const m_class &p_rval) {}                                                                       \
                                                                                                                    \
-protected:                                                                                                         \
-	virtual const GDNativeInstanceBindingCallbacks *_get_bindings_callbacks() const override {                     \
-		return &___binding_callbacks;                                                                              \
+	static bool (Wrapped::*_get_property_get_revert())(const StringName &p_name, Variant &) {                      \
+		return nullptr;                                                                                            \
 	}                                                                                                              \
                                                                                                                    \
-	m_class(const char *p_godot_class) : m_inherits(p_godot_class) {}                                              \
-	m_class(GodotObject *p_godot_object) : m_inherits(p_godot_object) {}                                           \
-                                                                                                                   \
-	static void (*_get_bind_methods())() {                                                                         \
+	static String (Wrapped::*_get_to_string())() {                                                                 \
 		return nullptr;                                                                                            \
 	}                                                                                                              \
                                                                                                                    \

+ 8 - 8
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 */

+ 1 - 0
include/godot_cpp/core/defs.hpp

@@ -33,6 +33,7 @@
 
 #include <cstddef>
 #include <cstdint>
+#include <cstring>
 
 #if !defined(GDN_EXPORT)
 #if defined(_WIN32)

+ 3 - 3
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...>(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...>(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...>(p_arg, pi);
 		} else {
-			pi = PropertyInfo();
+			pi = GDNativePropertyInfo();
 		}
 		return pi;
 	}

+ 3 - 38
include/godot_cpp/core/object.hpp

@@ -32,6 +32,9 @@
 #define GODOT_OBJECT_HPP
 
 #include <godot_cpp/core/defs.hpp>
+
+#include <godot_cpp/core/property_info.hpp>
+
 #include <godot_cpp/variant/variant.hpp>
 
 #include <godot_cpp/classes/object.hpp>
@@ -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;

+ 86 - 0
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 <godot_cpp/core/defs.hpp>
+
+#include <godot_cpp/classes/global_constants.hpp>
+
+#include <godot_cpp/variant/variant.hpp>
+
+#include <godot_cpp/godot.hpp>
+
+#include <godot/gdnative_interface.h>
+
+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

+ 10 - 0
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")

+ 2 - 0
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

+ 45 - 0
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<PropertyInfo> *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);

+ 17 - 0
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<PropertyInfo> *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.

+ 1 - 0
test/src/register_types.cpp

@@ -46,6 +46,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
 	}
 
 	ClassDB::register_class<ExampleRef>();
+	ClassDB::register_class<ExampleMin>();
 	ClassDB::register_class<Example>();
 }