Skip to content

Commit f900859

Browse files
authored
Merge pull request #1256 from dsnopek/placeholders
Allow registering "runtime classes"
2 parents a6d9393 + fb88457 commit f900859

File tree

7 files changed

+104
-9
lines changed

7 files changed

+104
-9
lines changed

gdextension/gdextension_interface.h

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ typedef struct {
290290
GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
291291
GDExtensionClassGetRID get_rid_func;
292292
void *class_userdata; // Per-class user data, later accessible in instance bindings.
293-
} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo2 instead.
293+
} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
294294

295295
typedef struct {
296296
GDExtensionBool is_virtual;
@@ -323,7 +323,41 @@ typedef struct {
323323
GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
324324
GDExtensionClassGetRID get_rid_func;
325325
void *class_userdata; // Per-class user data, later accessible in instance bindings.
326-
} GDExtensionClassCreationInfo2;
326+
} GDExtensionClassCreationInfo2; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
327+
328+
typedef struct {
329+
GDExtensionBool is_virtual;
330+
GDExtensionBool is_abstract;
331+
GDExtensionBool is_exposed;
332+
GDExtensionBool is_runtime;
333+
GDExtensionClassSet set_func;
334+
GDExtensionClassGet get_func;
335+
GDExtensionClassGetPropertyList get_property_list_func;
336+
GDExtensionClassFreePropertyList free_property_list_func;
337+
GDExtensionClassPropertyCanRevert property_can_revert_func;
338+
GDExtensionClassPropertyGetRevert property_get_revert_func;
339+
GDExtensionClassValidateProperty validate_property_func;
340+
GDExtensionClassNotification2 notification_func;
341+
GDExtensionClassToString to_string_func;
342+
GDExtensionClassReference reference_func;
343+
GDExtensionClassUnreference unreference_func;
344+
GDExtensionClassCreateInstance create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract.
345+
GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
346+
GDExtensionClassRecreateInstance recreate_instance_func;
347+
// Queries a virtual function by name and returns a callback to invoke the requested virtual function.
348+
GDExtensionClassGetVirtual get_virtual_func;
349+
// Paired with `call_virtual_with_data_func`, this is an alternative to `get_virtual_func` for extensions that
350+
// need or benefit from extra data when calling virtual functions.
351+
// Returns user data that will be passed to `call_virtual_with_data_func`.
352+
// Returning `NULL` from this function signals to Godot that the virtual function is not overridden.
353+
// Data returned from this function should be managed by the extension and must be valid until the extension is deinitialized.
354+
// You should supply either `get_virtual_func`, or `get_virtual_call_data_func` with `call_virtual_with_data_func`.
355+
GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
356+
// Used to call virtual functions when `get_virtual_call_data_func` is not null.
357+
GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
358+
GDExtensionClassGetRID get_rid_func;
359+
void *class_userdata; // Per-class user data, later accessible in instance bindings.
360+
} GDExtensionClassCreationInfo3;
327361

328362
typedef void *GDExtensionClassLibraryPtr;
329363

@@ -2514,6 +2548,21 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionCla
25142548
*/
25152549
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
25162550

2551+
/**
2552+
* @name classdb_register_extension_class3
2553+
* @since 4.3
2554+
*
2555+
* Registers an extension class in the ClassDB.
2556+
*
2557+
* Provided struct can be safely freed once the function returns.
2558+
*
2559+
* @param p_library A pointer the library received by the GDExtension's entry point function.
2560+
* @param p_class_name A pointer to a StringName with the class name.
2561+
* @param p_parent_class_name A pointer to a StringName with the parent class name.
2562+
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct.
2563+
*/
2564+
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
2565+
25172566
/**
25182567
* @name classdb_register_extension_class_method
25192568
* @since 4.1

include/godot_cpp/core/class_db.hpp

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class ClassDB {
110110
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
111111

112112
template <class T, bool is_abstract>
113-
static void _register_class(bool p_virtual = false, bool p_exposed = true);
113+
static void _register_class(bool p_virtual = false, bool p_exposed = true, bool p_runtime = false);
114114

115115
template <class T>
116116
static GDExtensionObjectPtr _create_instance_func(void *data) {
@@ -146,6 +146,8 @@ class ClassDB {
146146
static void register_abstract_class();
147147
template <class T>
148148
static void register_internal_class();
149+
template <class T>
150+
static void register_runtime_class();
149151

150152
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
151153
instance_binding_callbacks[p_name] = p_callbacks;
@@ -199,7 +201,7 @@ class ClassDB {
199201
}
200202

201203
template <class T, bool is_abstract>
202-
void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
204+
void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_runtime) {
203205
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
204206
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
205207

@@ -217,10 +219,11 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
217219
class_register_order.push_back(cl.name);
218220

219221
// Register this class with Godot
220-
GDExtensionClassCreationInfo2 class_info = {
222+
GDExtensionClassCreationInfo3 class_info = {
221223
p_virtual, // GDExtensionBool is_virtual;
222224
is_abstract, // GDExtensionBool is_abstract;
223225
p_exposed, // GDExtensionBool is_exposed;
226+
p_runtime, // GDExtensionBool is_runtime;
224227
T::set_bind, // GDExtensionClassSet set_func;
225228
T::get_bind, // GDExtensionClassGet get_func;
226229
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) {
242245
(void *)&T::get_class_static(), // void *class_userdata;
243246
};
244247

245-
internal::gdextension_interface_classdb_register_extension_class2(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
248+
internal::gdextension_interface_classdb_register_extension_class3(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
246249

247250
// call bind_methods etc. to register all members of the class
248251
T::initialize_class();
@@ -266,6 +269,11 @@ void ClassDB::register_internal_class() {
266269
ClassDB::_register_class<T, false>(false, false);
267270
}
268271

272+
template <class T>
273+
void ClassDB::register_runtime_class() {
274+
ClassDB::_register_class<T, false>(false, true, true);
275+
}
276+
269277
template <class N, class M, typename... VarArgs>
270278
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) {
271279
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
325333
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
326334
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
327335
#define GDREGISTER_INTERNAL_CLASS(m_class) ClassDB::register_internal_class<m_class>();
336+
#define GDREGISTER_RUNTIME_CLASS(m_class) ClassDB::register_runtime_class<m_class>();
328337

329338
} // namespace godot
330339

include/godot_cpp/godot.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_inter
177177
extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object;
178178
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
179179
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
180-
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2;
180+
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3;
181181
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
182182
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method;
183183
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;

src/godot.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@ GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeh
183183
GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr;
184184
GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr;
185185
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr;
186-
GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2 = nullptr;
186+
GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3 = nullptr;
187187
GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = nullptr;
188188
GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod gdextension_interface_classdb_register_extension_class_virtual_method = nullptr;
189189
GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr;
@@ -423,7 +423,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
423423
LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject);
424424
LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind);
425425
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
426-
LOAD_PROC_ADDRESS(classdb_register_extension_class2, GDExtensionInterfaceClassdbRegisterExtensionClass2);
426+
LOAD_PROC_ADDRESS(classdb_register_extension_class3, GDExtensionInterfaceClassdbRegisterExtensionClass3);
427427
LOAD_PROC_ADDRESS(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod);
428428
LOAD_PROC_ADDRESS(classdb_register_extension_class_virtual_method, GDExtensionInterfaceClassdbRegisterExtensionClassVirtualMethod);
429429
LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);

test/src/example.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -637,3 +637,23 @@ String Example::test_virtual_implemented_in_script(const String &p_name, int p_v
637637
}
638638
return "Unimplemented";
639639
}
640+
641+
void ExampleRuntime::_bind_methods() {
642+
ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleRuntime::set_prop_value);
643+
ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleRuntime::get_prop_value);
644+
ADD_PROPERTY(PropertyInfo(Variant::INT, "prop_value"), "set_prop_value", "get_prop_value");
645+
}
646+
647+
void ExampleRuntime::set_prop_value(int p_prop_value) {
648+
prop_value = p_prop_value;
649+
}
650+
651+
int ExampleRuntime::get_prop_value() const {
652+
return prop_value;
653+
}
654+
655+
ExampleRuntime::ExampleRuntime() {
656+
}
657+
658+
ExampleRuntime::~ExampleRuntime() {
659+
}

test/src/example.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,4 +220,20 @@ class ExampleConcrete : public ExampleAbstractBase {
220220
virtual int test_function() override { return 25; }
221221
};
222222

223+
class ExampleRuntime : public Node {
224+
GDCLASS(ExampleRuntime, Node);
225+
226+
int prop_value = 12;
227+
228+
protected:
229+
static void _bind_methods();
230+
231+
public:
232+
void set_prop_value(int p_prop_value);
233+
int get_prop_value() const;
234+
235+
ExampleRuntime();
236+
~ExampleRuntime();
237+
};
238+
223239
#endif // EXAMPLE_CLASS_H

test/src/register_types.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
2727
ClassDB::register_class<ExampleVirtual>(true);
2828
ClassDB::register_abstract_class<ExampleAbstractBase>();
2929
ClassDB::register_class<ExampleConcrete>();
30+
ClassDB::register_runtime_class<ExampleRuntime>();
3031
}
3132

3233
void uninitialize_example_module(ModuleInitializationLevel p_level) {

0 commit comments

Comments
 (0)