diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp index f40612ec3e7..ea314b71226 100644 --- a/core/extension/gdextension.cpp +++ b/core/extension/gdextension.cpp @@ -679,6 +679,13 @@ void GDExtension::_get_library_path(GDExtensionClassLibraryPtr p_library, GDExte memnew_placement(r_path, String(library_path)); } +void GDExtension::_register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback) { +#ifdef TOOLS_ENABLED + GDExtension *self = reinterpret_cast(p_library); + self->get_classes_used_callback = p_callback; +#endif +} + HashMap GDExtension::gdextension_interface_functions; void GDExtension::register_interface_function(const StringName &p_function_name, GDExtensionInterfaceFunctionPtr p_function_pointer) { @@ -799,6 +806,7 @@ void GDExtension::initialize_gdextensions() { register_interface_function("classdb_register_extension_class_signal", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_extension_class_signal); register_interface_function("classdb_unregister_extension_class", (GDExtensionInterfaceFunctionPtr)&GDExtension::_unregister_extension_class); register_interface_function("get_library_path", (GDExtensionInterfaceFunctionPtr)&GDExtension::_get_library_path); + register_interface_function("editor_register_get_classes_used_callback", (GDExtensionInterfaceFunctionPtr)&GDExtension::_register_get_classes_used_callback); } void GDExtension::finalize_gdextensions() { @@ -1034,6 +1042,14 @@ void GDExtension::_untrack_instance(void *p_user_data, void *p_instance) { extension->instances.erase(obj->get_instance_id()); } +PackedStringArray GDExtension::get_classes_used() const { + PackedStringArray ret; + if (get_classes_used_callback) { + get_classes_used_callback((GDExtensionTypePtr)&ret); + } + return ret; +} + Vector GDExtensionEditorPlugins::extension_classes; GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_add_plugin = nullptr; GDExtensionEditorPlugins::EditorPluginRegisterFunc GDExtensionEditorPlugins::editor_node_remove_plugin = nullptr; diff --git a/core/extension/gdextension.h b/core/extension/gdextension.h index dba13ae9305..a40f7af4576 100644 --- a/core/extension/gdextension.h +++ b/core/extension/gdextension.h @@ -93,6 +93,7 @@ class GDExtension : public Resource { static void _register_extension_class_signal(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name, GDExtensionConstStringNamePtr p_signal_name, const GDExtensionPropertyInfo *p_argument_info, GDExtensionInt p_argument_count); static void _unregister_extension_class(GDExtensionClassLibraryPtr p_library, GDExtensionConstStringNamePtr p_class_name); static void _get_library_path(GDExtensionClassLibraryPtr p_library, GDExtensionStringPtr r_path); + static void _register_get_classes_used_callback(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback); GDExtensionInitialization initialization; int32_t level_initialized = -1; @@ -101,6 +102,7 @@ class GDExtension : public Resource { bool is_reloading = false; Vector invalid_methods; Vector instance_bindings; + GDExtensionEditorGetClassesUsedCallback get_classes_used_callback = nullptr; static void _track_instance(void *p_user_data, void *p_instance); static void _untrack_instance(void *p_user_data, void *p_instance); @@ -155,6 +157,8 @@ public: void track_instance_binding(Object *p_object); void untrack_instance_binding(Object *p_object); + + PackedStringArray get_classes_used() const; #endif InitializationLevel get_minimum_library_initialization_level() const; diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h index 1bf54199b3b..ecd40c862dd 100644 --- a/core/extension/gdextension_interface.h +++ b/core/extension/gdextension_interface.h @@ -400,6 +400,9 @@ typedef struct { typedef void *GDExtensionClassLibraryPtr; +/* Passed a pointer to a PackedStringArray that should be filled with the classes that may be used by the GDExtension. */ +typedef void (*GDExtensionEditorGetClassesUsedCallback)(GDExtensionTypePtr p_packed_string_array); + /* Method */ typedef enum { @@ -3111,6 +3114,22 @@ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8Chars)(const char * */ typedef void (*GDExtensionsInterfaceEditorHelpLoadXmlFromUtf8CharsAndLen)(const char *p_data, GDExtensionInt p_size); +/** + * @name editor_register_get_classes_used_callback + * @since 4.5 + * + * Registers a callback that Godot can call to get the list of all classes (from ClassDB) that may be used by the calling GDExtension. + * + * This is used by the editor to generate a build profile (in "Tools" > "Engine Compilation Configuration Editor..." > "Detect from project"), + * in order to recompile Godot with only the classes used. + * In the provided callback, the GDExtension should provide the list of classes that _may_ be used statically, thus the time of invocation shouldn't matter. + * If a GDExtension doesn't register a callback, Godot will assume that it could be using any classes. + * + * @param p_library A pointer the library received by the GDExtension's entry point function. + * @param p_callback The callback to retrieve the list of classes used. + */ +typedef void (*GDExtensionInterfaceEditorRegisterGetClassesUsedCallback)(GDExtensionClassLibraryPtr p_library, GDExtensionEditorGetClassesUsedCallback p_callback); + #ifdef __cplusplus } #endif