[godot] Port PR #2996 fixes and fix GDExtension shutdown crash

Port from 4.2 branch (PR #2996):
- Fix dangling pointer in SpineSkeletonDataResource destructor by using
  ObjectID validation instead of direct EditorFileSystem access
- Register format loaders/savers at CORE level for GDExtension to fix
  loader/saver registration issues (#2899)

Additional fix for GDExtension:
- Fix crash on editor shutdown by properly removing import/inspector
  plugins in NOTIFICATION_PREDELETE before the extension is unloaded
This commit is contained in:
Mario Zechner 2025-12-16 15:18:12 +01:00
parent d5bfea2d68
commit d050ae6682
5 changed files with 52 additions and 11 deletions

View File

@ -197,11 +197,24 @@ Error SpineBinaryResourceImportPlugin::import(const String &source_file, const S
#ifdef SPINE_GODOT_EXTENSION #ifdef SPINE_GODOT_EXTENSION
SpineEditorPlugin::SpineEditorPlugin() { SpineEditorPlugin::SpineEditorPlugin() {
add_import_plugin(memnew(SpineAtlasResourceImportPlugin)); atlas_import_plugin = Ref<EditorImportPlugin>(memnew(SpineAtlasResourceImportPlugin));
add_import_plugin(memnew(SpineJsonResourceImportPlugin)); json_import_plugin = Ref<EditorImportPlugin>(memnew(SpineJsonResourceImportPlugin));
add_import_plugin(memnew(SpineBinaryResourceImportPlugin)); binary_import_plugin = Ref<EditorImportPlugin>(memnew(SpineBinaryResourceImportPlugin));
add_inspector_plugin(memnew(SpineSkeletonDataResourceInspectorPlugin)); skeleton_data_inspector_plugin = Ref<EditorInspectorPlugin>(memnew(SpineSkeletonDataResourceInspectorPlugin));
// add_inspector_plugin(memnew(SpineSpriteInspectorPlugin));
add_import_plugin(atlas_import_plugin);
add_import_plugin(json_import_plugin);
add_import_plugin(binary_import_plugin);
add_inspector_plugin(skeleton_data_inspector_plugin);
}
void SpineEditorPlugin::_notification(int p_what) {
if (p_what == NOTIFICATION_PREDELETE) {
remove_import_plugin(atlas_import_plugin);
remove_import_plugin(json_import_plugin);
remove_import_plugin(binary_import_plugin);
remove_inspector_plugin(skeleton_data_inspector_plugin);
}
} }
#else #else
SpineEditorPlugin::SpineEditorPlugin(EditorNode *node) { SpineEditorPlugin::SpineEditorPlugin(EditorNode *node) {

View File

@ -424,6 +424,13 @@ class SpineEditorPlugin : public EditorPlugin {
static void _bind_methods() { static void _bind_methods() {
} }
#ifdef SPINE_GODOT_EXTENSION
Ref<EditorImportPlugin> atlas_import_plugin;
Ref<EditorImportPlugin> json_import_plugin;
Ref<EditorImportPlugin> binary_import_plugin;
Ref<EditorInspectorPlugin> skeleton_data_inspector_plugin;
#endif
public: public:
#ifdef SPINE_GODOT_EXTENSION #ifdef SPINE_GODOT_EXTENSION
explicit SpineEditorPlugin(); explicit SpineEditorPlugin();
@ -431,6 +438,8 @@ public:
String _get_plugin_name() const override { String _get_plugin_name() const override {
return "SpineEditorPlugin"; return "SpineEditorPlugin";
} }
void _notification(int p_what);
#else #else
explicit SpineEditorPlugin(EditorNode *node); explicit SpineEditorPlugin(EditorNode *node);

View File

@ -194,6 +194,8 @@ SpineSkeletonDataResource::SpineSkeletonDataResource() : default_mix(0), skeleto
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
EditorFileSystem *efs = get_editor_file_system(); EditorFileSystem *efs = get_editor_file_system();
if (efs) { if (efs) {
// Store the ObjectID for safe validation in destructor
editor_file_system_id = efs->get_instance_id();
efs->connect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported)); efs->connect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported));
} }
} }
@ -201,6 +203,8 @@ SpineSkeletonDataResource::SpineSkeletonDataResource() : default_mix(0), skeleto
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
EditorFileSystem *efs = EditorFileSystem::get_singleton(); EditorFileSystem *efs = EditorFileSystem::get_singleton();
if (efs) { if (efs) {
// Store the ObjectID for safe validation in destructor
editor_file_system_id = efs->get_instance_id();
efs->connect("resources_reimported", this, "_on_resources_reimported"); efs->connect("resources_reimported", this, "_on_resources_reimported");
} }
} }
@ -212,14 +216,14 @@ SpineSkeletonDataResource::~SpineSkeletonDataResource() {
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
#if VERSION_MAJOR > 3 #if VERSION_MAJOR > 3
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
EditorFileSystem *efs = get_editor_file_system(); EditorFileSystem *efs = Object::cast_to<EditorFileSystem>(ObjectDB::get_instance(editor_file_system_id));
if (efs && efs->is_connected("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported))) { if (efs && efs->is_connected("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported))) {
efs->disconnect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported)); efs->disconnect("resources_reimported", callable_mp(this, &SpineSkeletonDataResource::_on_resources_reimported));
} }
} }
#else #else
if (Engine::get_singleton()->is_editor_hint()) { if (Engine::get_singleton()->is_editor_hint()) {
EditorFileSystem *efs = EditorFileSystem::get_singleton(); EditorFileSystem *efs = Object::cast_to<EditorFileSystem>(ObjectDB::get_instance(editor_file_system_id));
if (efs && efs->is_connected("resources_reimported", this, "_on_resources_reimported")) { if (efs && efs->is_connected("resources_reimported", this, "_on_resources_reimported")) {
efs->disconnect("resources_reimported", this, "_on_resources_reimported"); efs->disconnect("resources_reimported", this, "_on_resources_reimported");
} }

View File

@ -82,6 +82,10 @@ private:
spine::SkeletonData *skeleton_data; spine::SkeletonData *skeleton_data;
spine::AnimationStateData *animation_state_data; spine::AnimationStateData *animation_state_data;
#ifdef TOOLS_ENABLED
ObjectID editor_file_system_id;
#endif
void update_skeleton_data(); void update_skeleton_data();
#ifdef SPINE_GODOT_EXTENSION #ifdef SPINE_GODOT_EXTENSION

View File

@ -103,6 +103,13 @@ void initialize_spine_godot_module(ModuleInitializationLevel level) {
#endif #endif
return; return;
} }
if (level == MODULE_INITIALIZATION_LEVEL_CORE) {
GDREGISTER_CLASS(SpineAtlasResourceFormatLoader);
GDREGISTER_CLASS(SpineAtlasResourceFormatSaver);
GDREGISTER_CLASS(SpineSkeletonFileResourceFormatLoader);
GDREGISTER_CLASS(SpineSkeletonFileResourceFormatSaver);
return;
}
if (level != MODULE_INITIALIZATION_LEVEL_SCENE) return; if (level != MODULE_INITIALIZATION_LEVEL_SCENE) return;
#else #else
#if VERSION_MAJOR > 3 #if VERSION_MAJOR > 3
@ -125,10 +132,12 @@ void register_spine_godot_types() {
#endif #endif
spine::Bone::setYDown(true); spine::Bone::setYDown(true);
#ifndef SPINE_GODOT_EXTENSION
GDREGISTER_CLASS(SpineAtlasResourceFormatLoader); GDREGISTER_CLASS(SpineAtlasResourceFormatLoader);
GDREGISTER_CLASS(SpineAtlasResourceFormatSaver); GDREGISTER_CLASS(SpineAtlasResourceFormatSaver);
GDREGISTER_CLASS(SpineSkeletonFileResourceFormatLoader); GDREGISTER_CLASS(SpineSkeletonFileResourceFormatLoader);
GDREGISTER_CLASS(SpineSkeletonFileResourceFormatSaver); GDREGISTER_CLASS(SpineSkeletonFileResourceFormatSaver);
#endif
GDREGISTER_CLASS(SpineObjectWrapper); GDREGISTER_CLASS(SpineObjectWrapper);
GDREGISTER_CLASS(SpineAtlasResource); GDREGISTER_CLASS(SpineAtlasResource);
@ -221,9 +230,11 @@ void register_spine_godot_types() {
#ifdef SPINE_GODOT_EXTENSION #ifdef SPINE_GODOT_EXTENSION
void uninitialize_spine_godot_module(ModuleInitializationLevel level) { void uninitialize_spine_godot_module(ModuleInitializationLevel level) {
if (level != MODULE_INITIALIZATION_LEVEL_SCENE) return; if (level == MODULE_INITIALIZATION_LEVEL_SCENE) {
SpineSprite::clear_statics();
SpineSprite::clear_statics(); return;
}
if (level != MODULE_INITIALIZATION_LEVEL_CORE) return;
ResourceLoader::get_singleton()->remove_resource_format_loader(atlas_loader); ResourceLoader::get_singleton()->remove_resource_format_loader(atlas_loader);
ResourceSaver::get_singleton()->remove_resource_format_saver(atlas_saver); ResourceSaver::get_singleton()->remove_resource_format_saver(atlas_saver);
@ -258,7 +269,7 @@ extern "C" GDExtensionBool GDE_EXPORT spine_godot_library_init(GDExtensionInterf
GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization); GDExtensionBinding::InitObject init_obj(p_get_proc_address, p_library, r_initialization);
init_obj.register_initializer(initialize_spine_godot_module); init_obj.register_initializer(initialize_spine_godot_module);
init_obj.register_terminator(uninitialize_spine_godot_module); init_obj.register_terminator(uninitialize_spine_godot_module);
init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_SCENE); init_obj.set_minimum_library_initialization_level(MODULE_INITIALIZATION_LEVEL_CORE);
return init_obj.init(); return init_obj.init();
} }
#endif #endif