Browse Source

Merge pull request #107594 from dsnopek/gdextension-shutdown-order-fix

GDExtension: Always run shutdown callback before deinitializing any levels
Thaddeus Crews 2 months ago
parent
commit
6c9463dbd2
2 changed files with 11 additions and 7 deletions
  1. 4 0
      core/extension/gdextension_interface.h
  2. 7 7
      core/extension/gdextension_manager.cpp

+ 4 - 0
core/extension/gdextension_interface.h

@@ -815,8 +815,12 @@ typedef void (*GDExtensionMainLoopShutdownCallback)();
 typedef void (*GDExtensionMainLoopFrameCallback)();
 
 typedef struct {
+	// Will be called after Godot is started and is fully initialized.
 	GDExtensionMainLoopStartupCallback startup_func;
+	// Will be called before Godot is shutdown when it is still fully initialized.
 	GDExtensionMainLoopShutdownCallback shutdown_func;
+	// Will be called for each process frame. This will run after all `_process()` methods on Node, and before `ScriptServer::frame()`.
+	// This is intended to be the equivalent of `ScriptLanguage::frame()` for GDExtension language bindings that don't use the script API.
 	GDExtensionMainLoopFrameCallback frame_func;
 } GDExtensionMainLoopCallbacks;
 

+ 7 - 7
core/extension/gdextension_manager.cpp

@@ -77,13 +77,6 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
 	emit_signal("extension_unloading", p_extension);
 #endif
 
-	if (level >= 0) { // Already initialized up to some level.
-		// Deinitialize down from current level.
-		for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
-			p_extension->deinitialize_library(GDExtension::InitializationLevel(i));
-		}
-	}
-
 	if (!shutdown_callback_called) {
 		// Extension is unloading before the shutdown callback has been called,
 		// which means the engine hasn't shutdown yet but we want to make sure
@@ -93,6 +86,13 @@ GDExtensionManager::LoadStatus GDExtensionManager::_unload_extension_internal(co
 		}
 	}
 
+	if (level >= 0) { // Already initialized up to some level.
+		// Deinitialize down from current level.
+		for (int32_t i = level; i >= GDExtension::INITIALIZATION_LEVEL_CORE; i--) {
+			p_extension->deinitialize_library(GDExtension::InitializationLevel(i));
+		}
+	}
+
 	for (const KeyValue<String, String> &kv : p_extension->class_icon_paths) {
 		gdextension_class_icon_paths.erase(kv.key);
 	}