Allow registering "gameplay classes"

David Snopek 2023-09-29 16:30:59 -05:00
parent 3f44e9b404
commit 2e0fb69144
7 changed files with 104 additions and 9 deletions

View File

@ -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. GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
GDExtensionClassGetRID get_rid_func; GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings. void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo2 instead. } GDExtensionClassCreationInfo; // Deprecated. Use GDExtensionClassCreationInfo3 instead.
typedef struct { typedef struct {
GDExtensionBool is_virtual; GDExtensionBool is_virtual;
@ -323,7 +323,41 @@ typedef struct {
GDExtensionClassCallVirtualWithData call_virtual_with_data_func; GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
GDExtensionClassGetRID get_rid_func; GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings. 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_gameplay;
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; typedef void *GDExtensionClassLibraryPtr;
@ -2469,6 +2503,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); 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 * @name classdb_register_extension_class_method
* @since 4.1 * @since 4.1

View File

@ -110,7 +110,7 @@ private:
static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method); static void bind_method_godot(const StringName &p_class_name, MethodBind *p_method);
template <class T, bool is_abstract> 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_gameplay = false);
public: public:
template <class T> template <class T>
@ -119,6 +119,8 @@ public:
static void register_abstract_class(); static void register_abstract_class();
template <class T> template <class T>
static void register_internal_class(); static void register_internal_class();
template <class T>
static void register_gameplay_class();
_FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) { _FORCE_INLINE_ static void _register_engine_class(const StringName &p_name, const GDExtensionInstanceBindingCallbacks *p_callbacks) {
instance_binding_callbacks[p_name] = p_callbacks; instance_binding_callbacks[p_name] = p_callbacks;
@ -169,7 +171,7 @@ public:
} }
template <class T, bool is_abstract> 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_gameplay) {
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS."); 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; instance_binding_callbacks[T::get_class_static()] = &T::_gde_binding_callbacks;
@ -187,10 +189,11 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
class_register_order.push_back(cl.name); class_register_order.push_back(cl.name);
// Register this class with Godot // Register this class with Godot
GDExtensionClassCreationInfo2 class_info = { GDExtensionClassCreationInfo3 class_info = {
p_virtual, // GDExtensionBool is_virtual; p_virtual, // GDExtensionBool is_virtual;
is_abstract, // GDExtensionBool is_abstract; is_abstract, // GDExtensionBool is_abstract;
p_exposed, // GDExtensionBool is_exposed; p_exposed, // GDExtensionBool is_exposed;
p_gameplay, // GDExtensionBool is_gameplay;
T::set_bind, // GDExtensionClassSet set_func; T::set_bind, // GDExtensionClassSet set_func;
T::get_bind, // GDExtensionClassGet get_func; T::get_bind, // GDExtensionClassGet get_func;
T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func; T::has_get_property_list() ? T::get_property_list_bind : nullptr, // GDExtensionClassGetPropertyList get_property_list_func;
@ -212,7 +215,7 @@ void ClassDB::_register_class(bool p_virtual, bool p_exposed) {
(void *)&T::get_class_static(), // void *class_userdata; (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 // call bind_methods etc. to register all members of the class
T::initialize_class(); T::initialize_class();
@ -236,6 +239,11 @@ void ClassDB::register_internal_class() {
ClassDB::_register_class<T, false>(false, false); ClassDB::_register_class<T, false>(false, false);
} }
template <class T>
void ClassDB::register_gameplay_class() {
ClassDB::_register_class<T, false>(false, true, true);
}
template <class N, class M, typename... VarArgs> template <class N, class M, typename... VarArgs>
MethodBind *ClassDB::bind_method(N p_method_name, M p_method, VarArgs... p_args) { 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. Variant args[sizeof...(p_args) + 1] = { p_args..., Variant() }; // +1 makes sure zero sized arrays are also supported.
@ -295,6 +303,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_VIRTUAL_CLASS(m_class) ClassDB::register_class<m_class>(true);
#define GDREGISTER_ABSTRACT_CLASS(m_class) ClassDB::register_abstract_class<m_class>(); #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_INTERNAL_CLASS(m_class) ClassDB::register_internal_class<m_class>();
#define GDREGISTER_GAMEPLAY_CLASS(m_class) ClassDB::register_gameplay_class<m_class>();
} // namespace godot } // namespace godot

View File

@ -175,7 +175,7 @@ extern "C" GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_inter
extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object; extern "C" GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object;
extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind; extern "C" GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind;
extern "C" GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag; 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" GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant;
extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property; extern "C" GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property;

View File

@ -181,7 +181,7 @@ GDExtensionInterfacePlaceHolderScriptInstanceUpdate gdextension_interface_placeh
GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr; GDExtensionInterfaceClassdbConstructObject gdextension_interface_classdb_construct_object = nullptr;
GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr; GDExtensionInterfaceClassdbGetMethodBind gdextension_interface_classdb_get_method_bind = nullptr;
GDExtensionInterfaceClassdbGetClassTag gdextension_interface_classdb_get_class_tag = 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; GDExtensionInterfaceClassdbRegisterExtensionClassMethod gdextension_interface_classdb_register_extension_class_method = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant gdextension_interface_classdb_register_extension_class_integer_constant = nullptr;
GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property = nullptr; GDExtensionInterfaceClassdbRegisterExtensionClassProperty gdextension_interface_classdb_register_extension_class_property = nullptr;
@ -418,7 +418,7 @@ GDExtensionBool GDExtensionBinding::init(GDExtensionInterfaceGetProcAddress p_ge
LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject); LOAD_PROC_ADDRESS(classdb_construct_object, GDExtensionInterfaceClassdbConstructObject);
LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind); LOAD_PROC_ADDRESS(classdb_get_method_bind, GDExtensionInterfaceClassdbGetMethodBind);
LOAD_PROC_ADDRESS(classdb_get_class_tag, GDExtensionInterfaceClassdbGetClassTag); 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_method, GDExtensionInterfaceClassdbRegisterExtensionClassMethod);
LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant); LOAD_PROC_ADDRESS(classdb_register_extension_class_integer_constant, GDExtensionInterfaceClassdbRegisterExtensionClassIntegerConstant);
LOAD_PROC_ADDRESS(classdb_register_extension_class_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty); LOAD_PROC_ADDRESS(classdb_register_extension_class_property, GDExtensionInterfaceClassdbRegisterExtensionClassProperty);

View File

@ -626,3 +626,23 @@ void Example::_input(const Ref<InputEvent> &event) {
emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode()); emit_custom_signal(String("_input: ") + key_event->get_key_label(), key_event->get_unicode());
} }
} }
void ExampleGameplay::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_prop_value", "value"), &ExampleGameplay::set_prop_value);
ClassDB::bind_method(D_METHOD("get_prop_value"), &ExampleGameplay::get_prop_value);
ADD_PROPERTY(PropertyInfo(Variant::INT, "prop_value"), "set_prop_value", "get_prop_value");
}
void ExampleGameplay::set_prop_value(int p_prop_value) {
prop_value = p_prop_value;
}
int ExampleGameplay::get_prop_value() const {
return prop_value;
}
ExampleGameplay::ExampleGameplay() {
}
ExampleGameplay::~ExampleGameplay() {
}

View File

@ -205,4 +205,20 @@ protected:
static void _bind_methods() {} static void _bind_methods() {}
}; };
class ExampleGameplay : public Node {
GDCLASS(ExampleGameplay, Node);
int prop_value = 12;
protected:
static void _bind_methods();
public:
void set_prop_value(int p_prop_value);
int get_prop_value() const;
ExampleGameplay();
~ExampleGameplay();
};
#endif // EXAMPLE_CLASS_H #endif // EXAMPLE_CLASS_H

View File

@ -26,6 +26,7 @@ void initialize_example_module(ModuleInitializationLevel p_level) {
ClassDB::register_class<Example>(); ClassDB::register_class<Example>();
ClassDB::register_class<ExampleVirtual>(true); ClassDB::register_class<ExampleVirtual>(true);
ClassDB::register_abstract_class<ExampleAbstract>(); ClassDB::register_abstract_class<ExampleAbstract>();
ClassDB::register_gameplay_class<ExampleGameplay>();
} }
void uninitialize_example_module(ModuleInitializationLevel p_level) { void uninitialize_example_module(ModuleInitializationLevel p_level) {