Skip to content

Commit 756980b

Browse files
committed
Allow registering "gameplay classes"
1 parent bf2f9e2 commit 756980b

File tree

7 files changed

+102
-7
lines changed

7 files changed

+102
-7
lines changed

gdextension/gdextension_interface.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,40 @@ typedef struct {
325325
void *class_userdata; // Per-class user data, later accessible in instance bindings.
326326
} GDExtensionClassCreationInfo2;
327327

328+
typedef struct {
329+
GDExtensionBool is_virtual;
330+
GDExtensionBool is_abstract;
331+
GDExtensionBool is_exposed;
332+
GDExtensionBool is_tool;
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;
361+
328362
typedef void *GDExtensionClassLibraryPtr;
329363

330364
/* Method */
@@ -2408,6 +2442,21 @@ typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass)(GDExtensionCla
24082442
*/
24092443
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass2)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo2 *p_extension_funcs);
24102444

2445+
/**
2446+
* @name classdb_register_extension_class3
2447+
* @since 4.3
2448+
*
2449+
* Registers an extension class in the ClassDB.
2450+
*
2451+
* Provided struct can be safely freed once the function returns.
2452+
*
2453+
* @param p_library A pointer the library received by the GDExtension's entry point function.
2454+
* @param p_class_name A pointer to a StringName with the class name.
2455+
* @param p_parent_class_name A pointer to a StringName with the parent class name.
2456+
* @param p_extension_funcs A pointer to a GDExtensionClassCreationInfo2 struct.
2457+
*/
2458+
typedef void (*GDExtensionInterfaceClassdbRegisterExtensionClass3)(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_parent_class_name, const GDExtensionClassCreationInfo3 *p_extension_funcs);
2459+
24112460
/**
24122461
* @name classdb_register_extension_class_method
24132462
* @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_tool = true);
114114

115115
public:
116116
template <class T>
@@ -120,6 +120,8 @@ class ClassDB {
120120
template <class T>
121121
static void register_internal_class();
122122
template <class T>
123+
static void register_gameplay_class();
124+
template <class T>
123125
static void register_engine_class();
124126

125127
template <class N, class M, typename... VarArgs>
@@ -167,7 +169,7 @@ class ClassDB {
167169
}
168170

169171
template <class T, bool is_abstract>
170-
void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
172+
void ClassDB::_register_class(bool p_virtual, bool p_exposed, bool p_tool) {
171173
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
172174

173175
// Register this class within our plugin
@@ -184,10 +186,11 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
184186
class_register_order.push_back(cl.name);
185187

186188
// Register this class with Godot
187-
GDExtensionClassCreationInfo2 class_info = {
189+
GDExtensionClassCreationInfo3 class_info = {
188190
p_virtual, // GDExtensionBool is_virtual;
189191
is_abstract, // GDExtensionBool is_abstract;
190192
p_exposed, // GDExtensionBool is_exposed;
193+
p_tool, // GDExtensionBool is_tool;
191194
T::set_bind, // GDExtensionClassSet set_func;
192195
T::get_bind, // GDExtensionClassGet get_func;
193196
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
@@ -209,7 +212,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
209212
(void *)&T::get_class_static(), // void *class_userdata;
210213
};
211214

212-
internal::gdextension_interface_classdb_register_extension_class2(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
215+
internal::gdextension_interface_classdb_register_extension_class3(internal::library, cl.name._native_ptr(), cl.parent_name._native_ptr(), &class_info);
213216

214217
// call bind_methods etc. to register all members of the class
215218
T::initialize_class();
@@ -233,6 +236,11 @@ void ClassDB::register_internal_class() {
233236
ClassDB::_register_class<T, false>(false, false);
234237
}
235238

239+
template <class T>
240+
void ClassDB::register_gameplay_class() {
241+
ClassDB::_register_class<T, false>(false, true, false);
242+
}
243+
236244
template <class T>
237245
void ClassDB::register_engine_class() {
238246
instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
@@ -297,6 +305,7 @@ MethodBind *ClassDB::bind_vararg_method(uint32_t p_flags, StringName p_name, M p
297305
#define GDREGISTER_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
298306
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>();
299307
#define GDREGISTER_INTERNAL_CLASS(m_class) ClassDB::register_internal_class<m_class>();
308+
#define GDREGISTER_GAMEPLAY_CLASS(m_class) ClassDB::register_gameplay_class<m_class>();
300309

301310
} // namespace godot
302311

include/godot_cpp/godot.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_inter
173173
extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object;
174174
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
175175
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag;
176-
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2;
176+
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3;
177177
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
178178
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
179179
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;

src/godot.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeh
179179
GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr;
180180
GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr;
181181
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = nullptr;
182-
GDExtensionInterfaceClassdbRegisterExtensionClass2 gdextension_interface_classdb_register_extension_class2 = nullptr;
182+
GDExtensionInterfaceClassdbRegisterExtensionClass3 gdextension_interface_classdb_register_extension_class3 = nullptr;
183183
GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = nullptr;
184184
GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr;
185185
GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property = nullptr;
@@ -396,7 +396,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
396396
LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject);
397397
LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind);
398398
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag);
399-
LOAD_PROC_ADDRESS(classdb_register_extension_class2, GDExtensionInterfaceClassdbRegisterExtensionClass2);
399+
LOAD_PROC_ADDRESS(classdb_register_extension_class3, GDExtensionInterfaceClassdbRegisterExtensionClass3);
400400
LOAD_PROC_ADDRESS(classdb_register_extension_class_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod);
401401
LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);
402402
LOAD_PROC_ADDRESS(classdb_register_extension_class_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty);

test/src/example.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,3 +523,23 @@ void Example::_input(const Ref<InputEvent> &event) {
523523
emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode());
524524
}
525525
}
526+
527+
void ExampleGameplay::_bind_methods() {
528+
ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleGameplay::set_prop_value);
529+
ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleGameplay::get_prop_value);
530+
ADD_PROPERTY(PropertyInfo(Variant::INT, "prop_value"), "set_prop_value", "get_prop_value");
531+
}
532+
533+
void ExampleGameplay::set_prop_value(int p_prop_value) {
534+
prop_value = p_prop_value;
535+
}
536+
537+
int ExampleGameplay::get_prop_value() const {
538+
return prop_value;
539+
}
540+
541+
ExampleGameplay::ExampleGameplay() {
542+
}
543+
544+
ExampleGameplay::~ExampleGameplay() {
545+
}

test/src/example.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,20 @@ class ExampleAbstract : public Object {
193193
static void _bind_methods() {}
194194
};
195195

196+
class ExampleGameplay : public Node {
197+
GDCLASS(ExampleGameplay, Node);
198+
199+
int prop_value = 12;
200+
201+
protected:
202+
static void _bind_methods();
203+
204+
public:
205+
void set_prop_value(int p_prop_value);
206+
int get_prop_value() const;
207+
208+
ExampleGameplay();
209+
~ExampleGameplay();
210+
};
211+
196212
#endif // EXAMPLE_CLASS_H

test/src/register_types.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
2626
ClassDB::register_class<Example>();
2727
ClassDB::register_class<ExampleVirtual>(true);
2828
ClassDB::register_abstract_class<ExampleAbstract>();
29+
ClassDB::register_gameplay_class<ExampleGameplay>();
2930
}
3031

3132
void uninitialize_example_module(ModuleInitializationLevel p_level) {

0 commit comments

Comments
 (0)