summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Snopek <dsnopek@gmail.com>2024-02-21 07:51:52 -0600
committerGitHub <noreply@github.com>2024-02-21 07:51:52 -0600
commitf90085917b16c3daff7b2d195db9bf222119eea1 (patch)
treedc26c7ec5800a5facbeb71e035bb4748c00b1bbc
parenta6d939334166602b85ee4d28c0daa1c87c9fba02 (diff)
parentfb884573ea1a0ec36d1968bf12a667cd17023d38 (diff)
downloadredot-cpp-f90085917b16c3daff7b2d195db9bf222119eea1.tar.gz
Merge pull request #1256 from dsnopek/placeholders
Allow registering "runtime classes"
-rw-r--r--gdextension/gdextension_interface.h53
-rw-r--r--include/godot_cpp/core/class_db.hpp17
-rw-r--r--include/godot_cpp/godot.hpp2
-rw-r--r--src/godot.cpp4
-rw-r--r--test/src/example.cpp20
-rw-r--r--test/src/example.h16
-rw-r--r--test/src/register_types.cpp1
7 files changed, 104 insertions, 9 deletions
diff --git a/gdextension/gdextension_interface.h b/gdextension/gdextension_interface.h
index 765952c..7a8c671 100644
--- a/gdextension/gdextension_interface.h
+++ b/gdextension/gdextension_interface.h
@@ -290,7 +290,7 @@ typedef struct {
GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
-} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo2 instead.
+} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
typedef struct {
GDExtensionBool is_virtual;
@@ -323,7 +323,41 @@ typedef struct {
GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
-} GDExtensionClassCreationInfo2;
+} GDExtensionClassCreationInfo2; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
+
+typedef struct {
+ GDExtensionBool is_virtual;
+ GDExtensionBool is_abstract;
+ GDExtensionBool is_exposed;
+ GDExtensionBool is_runtime;
+ GDExtensionClassSet set_func;
+ GDExtensionClassGet get_func;
+ GDExtensionClassGetPropertyList get_property_list_func;
+ GDExtensionClassFreePropertyList free_property_list_func;
+ GDExtensionClassPropertyCanRevert property_can_revert_func;
+ GDExtensionClassPropertyGetRevert property_get_revert_func;
+ GDExtensionClassValidateProperty validate_property_func;
+ GDExtensionClassNotification2 notification_func;
+ GDExtensionClassToString to_string_func;
+ GDExtensionClassReference reference_func;
+ GDExtensionClassUnreference unreference_func;
+ GDExtensionClassCreateInstance create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract.
+ GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
+ GDExtensionClassRecreateInstance recreate_instance_func;
+ // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
+ GDExtensionClassGetVirtual get_virtual_func;
+ // Paired with `call_virtual_with_data_func`, this is an alternative to `get_virtual_func` for extensions that
+ // need or benefit from extra data when calling virtual functions.
+ // Returns user data that will be passed to `call_virtual_with_data_func`.
+ // Returning `NULL` from this function signals to Godot that the virtual function is not overridden.
+ // Data returned from this function should be managed by the extension and must be valid until the extension is deinitialized.
+ // You should supply either `get_virtual_func`, or `get_virtual_call_data_func` with `call_virtual_with_data_func`.
+ GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
+ // Used to call virtual functions when `get_virtual_call_data_func` is not null.
+ GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
+ GDExtensionClassGetRID get_rid_func;
+ void *class_userdata; // Per-class user data, later accessible in instance bindings.
+} GDExtensionClassCreationInfo3;
typedef void *GDExtensionClassLibraryPtr;
@@ -2515,6 +2549,21 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionCla
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
/**
+ * @name classdb_register_extension_class3
+ * @since 4.3
+ *
+ * Registers an extension class in the ClassDB.
+ *
+ * Provided struct can be safely freed once the function returns.
+ *
+ * @param p_library A pointer the library received by the GDExtension's entry point function.
+ * @param p_class_name A pointer to a StringName with the class name.
+ * @param p_parent_class_name A pointer to a StringName with the parent class name.
+ * @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct.
+ */
+typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
+
+/**
* @name classdb_register_extension_class_method
* @since 4.1
*
diff --git a/include/godot_cpp/core/class_db.hpp b/include/godot_cpp/core/class_db.hpp
index e5bccf3..91748e6 100644
--- a/include/godot_cpp/core/class_db.hpp
+++ b/include/godot_cpp/core/class_db.hpp
@@ -110,7 +110,7 @@ private:
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
template <class T, bool is_abstract>
- static void _register_class(bool p_virtual = false, bool p_exposed = true);
+ static void _register_class(bool p_virtual = false, bool p_exposed = true, bool p_runtime = false);
template <class T>
static GDExtensionObjectPtr _create_instance_func(void *data) {
@@ -146,6 +146,8 @@ public:
static void register_abstract_class();
template <class T>
static void register_internal_class();
+ template <class T>
+ static void register_runtime_class();
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
instance_binding_callbacks[p_name] = p_callbacks;
@@ -199,7 +201,7 @@ public:
}
template <class T, bool is_abstract>
-void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
+void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
@@ -217,10 +219,11 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
class_register_order.push_back(cl.name);
// Register this class with Godot
- GDExtensionClassCreationInfo2 class_info = {
+ GDExtensionClassCreationInfo3 class_info = {
p_virtual, // GDExtensionBool is_virtual;
is_abstract, // GDExtensionBool is_abstract;
p_exposed, // GDExtensionBool is_exposed;
+ p_runtime, // GDExtensionBool is_runtime;
T::set_bind, // GDExtensionClassSet set_func;
T::get_bind, // GDExtensionClassGet get_func;
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
@@ -242,7 +245,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
(void *)&T::get_class_static(), // void *class_userdata;
};
- internal::gdextension_interface_classdb_register_extension_class2(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
+ internal::gdextension_interface_classdb_register_extension_class3(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
// call bind_methods etc. to register all members of the class
T::initialize_class();
@@ -266,6 +269,11 @@ void ClassDB::register_internal_class() {
ClassDB::_register_class<T, false>(false, false);
}
+template <class T>
+void ClassDB::register_runtime_class() {
+ ClassDB::_register_class<T, false>(false, true, true);
+}
+
template <class N, class M, typename... VarArgs>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
@@ -325,6 +333,7 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
#define GDREGISTER_INTERNAL_CLASS(m_class) ClassDB::register_internal_class<m_class>();
+#define GDREGISTER_RUNTIME_CLASS(m_class) ClassDB::register_runtime_class<m_class>();
} // namespace godot
diff --git a/include/godot_cpp/godot.hpp b/include/godot_cpp/godot.hpp
index 1b420d3..c4e5d83 100644
--- a/include/godot_cpp/godot.hpp
+++ b/include/godot_cpp/godot.hpp
@@ -177,7 +177,7 @@ extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_inter
extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object;
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
-extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2;
+extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
diff --git a/src/godot.cpp b/src/godot.cpp
index a80ad90..dd8ace3 100644
--- a/src/godot.cpp
+++ b/src/godot.cpp
@@ -183,7 +183,7 @@ GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeh
GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr;
GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr;
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr;
-GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2 = nullptr;
+GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3 = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr;
@@ -423,7 +423,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject);
LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind);
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
- LOAD_PROC_ADDRESS(classdb_register_extension_class2, GDExtensionInterfaceClassdbRegisterExtensionClass2);
+ LOAD_PROC_ADDRESS(classdb_register_extension_class3, GDExtensionInterfaceClassdbRegisterExtensionClass3);
LOAD_PROC_ADDRESS(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod);
LOAD_PROC_ADDRESS(classdb_register_extension_class_virtual_method, GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod);
LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);
diff --git a/test/src/example.cpp b/test/src/example.cpp
index 53d11f4..136ac94 100644
--- a/test/src/example.cpp
+++ b/test/src/example.cpp
@@ -637,3 +637,23 @@ String Example::test_virtual_implemented_in_script(const String &p_name, int p_v
}
return "Unimplemented";
}
+
+void ExampleRuntime::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleRuntime::set_prop_value);
+ ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleRuntime::get_prop_value);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "prop_value"), "set_prop_value", "get_prop_value");
+}
+
+void ExampleRuntime::set_prop_value(int p_prop_value) {
+ prop_value = p_prop_value;
+}
+
+int ExampleRuntime::get_prop_value() const {
+ return prop_value;
+}
+
+ExampleRuntime::ExampleRuntime() {
+}
+
+ExampleRuntime::~ExampleRuntime() {
+}
diff --git a/test/src/example.h b/test/src/example.h
index 1c57720..7da7b08 100644
--- a/test/src/example.h
+++ b/test/src/example.h
@@ -220,4 +220,20 @@ protected:
virtual int test_function() override { return 25; }
};
+class ExampleRuntime : public Node {
+ GDCLASS(ExampleRuntime, Node);
+
+ int prop_value = 12;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_prop_value(int p_prop_value);
+ int get_prop_value() const;
+
+ ExampleRuntime();
+ ~ExampleRuntime();
+};
+
#endif // EXAMPLE_CLASS_H
diff --git a/test/src/register_types.cpp b/test/src/register_types.cpp
index 58080d2..5c38241 100644
--- a/test/src/register_types.cpp
+++ b/test/src/register_types.cpp
@@ -27,6 +27,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<ExampleVirtual>(true);
ClassDB::register_abstract_class<ExampleAbstractBase>();
ClassDB::register_class<ExampleConcrete>();
+ ClassDB::register_runtime_class<ExampleRuntime>();
}
void uninitialize_example_module(ModuleInitializationLevel p_level) {