From c3d74b690eaea35d9197304f44ad51cfd7372d1e Mon Sep 17 00:00:00 2001 From: Wojtek Figat Date: Mon, 6 Nov 2023 18:13:06 +0100 Subject: [PATCH] Fix editor plugins init regression from #1779 and compact more code --- .../Scripting/Plugins/PluginManager.cpp | 194 +++++++++--------- 1 file changed, 92 insertions(+), 102 deletions(-) diff --git a/Source/Engine/Scripting/Plugins/PluginManager.cpp b/Source/Engine/Scripting/Plugins/PluginManager.cpp index 87965fac9..61d7bc698 100644 --- a/Source/Engine/Scripting/Plugins/PluginManager.cpp +++ b/Source/Engine/Scripting/Plugins/PluginManager.cpp @@ -75,14 +75,16 @@ Action PluginManager::PluginsChanged; namespace PluginManagerImpl { + bool Initialized = false; Array GamePlugins; Array EditorPlugins; - void LoadPlugin(MClass* klass, bool isEditor); void OnAssemblyLoaded(MAssembly* assembly); void OnAssemblyUnloading(MAssembly* assembly); void OnBinaryModuleLoaded(BinaryModule* module); void OnScriptsReloading(); + void InitializePlugins(); + void DeinitializePlugins(); template Array SortPlugins(Array plugins, MClass* pluginLoadOrderAttribute, MField* typeField) @@ -149,7 +151,7 @@ void PluginManagerService::InvokeInitialize(Plugin* plugin) { if (plugin->_initialized) return; - StringAnsiView typeName = plugin->GetType().GetName(); + const StringAnsiView typeName = plugin->GetType().GetName(); PROFILE_CPU(); ZoneName(typeName.Get(), typeName.Length()); @@ -167,7 +169,7 @@ void PluginManagerService::InvokeDeinitialize(Plugin* plugin) { if (!plugin->_initialized) return; - StringAnsiView typeName = plugin->GetType().GetName(); + const StringAnsiView typeName = plugin->GetType().GetName(); PROFILE_CPU(); ZoneName(typeName.Get(), typeName.Length()); @@ -181,26 +183,6 @@ void PluginManagerService::InvokeDeinitialize(Plugin* plugin) PluginManager::PluginUnloaded(plugin); } -void PluginManagerImpl::LoadPlugin(MClass* klass, bool isEditor) -{ - // Create and check if use it - auto plugin = (Plugin*)Scripting::NewObject(klass); - if (!plugin) - return; - - if (!isEditor) - { - GamePlugins.Add((GamePlugin*)plugin); - } -#if USE_EDITOR - else - { - EditorPlugins.Add(plugin); - } -#endif - PluginManager::PluginsChanged(); -} - void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly) { PROFILE_CPU_NAMED("Load Assembly Plugins"); @@ -221,6 +203,7 @@ void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly) #endif // Process all classes to find plugins + bool loadedAnyPlugin = false; auto& classes = assembly->GetClasses(); for (auto i = classes.Begin(); i.IsNotEnd(); ++i) { @@ -230,17 +213,35 @@ void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly) if (mclass->IsGeneric() || mclass->IsStatic() || mclass->IsAbstract()) continue; - if (mclass->IsSubClassOf(gamePluginClass)) - { - LoadPlugin(mclass, false); - } - + if (mclass->IsSubClassOf(gamePluginClass) #if USE_EDITOR - if (mclass->IsSubClassOf(editorPluginClass)) - { - LoadPlugin(mclass, true); - } + || mclass->IsSubClassOf(editorPluginClass) #endif + ) + { + auto plugin = (Plugin*)Scripting::NewObject(mclass); + if (plugin) + { +#if USE_EDITOR + if (mclass->IsSubClassOf(editorPluginClass)) + { + EditorPlugins.Add(plugin); + } + else +#endif + { + GamePlugins.Add((GamePlugin*)plugin); + } + loadedAnyPlugin = true; + } + } + } + + // Send event and initialize newly added plugins (ignore during startup) + if (loadedAnyPlugin && Initialized) + { + InitializePlugins(); + PluginManager::PluginsChanged(); } } @@ -253,8 +254,8 @@ void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly) auto beforeTypeField = pluginLoadOrderAttribute->GetField("DeinitializeBefore"); ASSERT(beforeTypeField); +#if USE_EDITOR auto editorPlugins = SortPlugins(EditorPlugins, pluginLoadOrderAttribute, beforeTypeField); - for (int32 i = editorPlugins.Count() - 1; i >= 0 && editorPlugins.Count() > 0; i--) { auto plugin = editorPlugins[i]; @@ -265,9 +266,9 @@ void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly) changed = true; } } +#endif auto gamePlugins = SortPlugins(GamePlugins, pluginLoadOrderAttribute, beforeTypeField); - for (int32 i = gamePlugins.Count() - 1; i >= 0 && gamePlugins.Count() > 0; i--) { auto plugin = gamePlugins[i]; @@ -309,75 +310,83 @@ void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module) void PluginManagerImpl::OnScriptsReloading() { // When scripting is reloading (eg. for hot-reload in Editor) we have to deinitialize plugins (Scripting service destroys C# objects later on) - bool changed = false; + DeinitializePlugins(); +} + +void PluginManagerImpl::InitializePlugins() +{ + if (EditorPlugins.Count() + GamePlugins.Count() == 0) + return; + PROFILE_CPU_NAMED("InitializePlugins"); + + auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly; + auto pluginLoadOrderAttribute = engineAssembly->GetClass("FlaxEngine.PluginLoadOrderAttribute"); + auto afterTypeField = pluginLoadOrderAttribute->GetField("InitializeAfter"); + ASSERT(afterTypeField); + +#if USE_EDITOR + auto editorPlugins = SortPlugins(EditorPlugins, pluginLoadOrderAttribute, afterTypeField); + for (auto plugin : editorPlugins) + { + PluginManagerService::InvokeInitialize(plugin); + } +#else + // Game plugins are managed via InitializeGamePlugins/DeinitializeGamePlugins by Editor for play mode + auto gamePlugins = SortPlugins(GamePlugins, pluginLoadOrderAttribute, afterTypeField); + for (auto plugin : gamePlugins) + { + PluginManagerService::InvokeInitialize(plugin); + } +#endif +} + +void PluginManagerImpl::DeinitializePlugins() +{ + if (EditorPlugins.Count() + GamePlugins.Count() == 0) + return; + PROFILE_CPU_NAMED("DeinitializePlugins"); auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly; auto pluginLoadOrderAttribute = engineAssembly->GetClass("FlaxEngine.PluginLoadOrderAttribute"); auto beforeTypeField = pluginLoadOrderAttribute->GetField("DeinitializeBefore"); ASSERT(beforeTypeField); +#if USE_EDITOR auto editorPlugins = SortPlugins(EditorPlugins, pluginLoadOrderAttribute, beforeTypeField); - for (int32 i = editorPlugins.Count() - 1; i >= 0 && editorPlugins.Count() > 0; i--) { auto plugin = editorPlugins[i]; - { - PluginManagerService::InvokeDeinitialize(plugin); - EditorPlugins.Remove(plugin); - changed = true; - } + PluginManagerService::InvokeDeinitialize(plugin); + EditorPlugins.Remove(plugin); } +#endif auto gamePlugins = SortPlugins(GamePlugins, pluginLoadOrderAttribute, beforeTypeField); - for (int32 i = gamePlugins.Count() - 1; i >= 0 && gamePlugins.Count() > 0; i--) { auto plugin = gamePlugins[i]; - { - PluginManagerService::InvokeDeinitialize(plugin); - GamePlugins.Remove(plugin); - changed = true; - } + PluginManagerService::InvokeDeinitialize(plugin); + GamePlugins.Remove(plugin); } - if (changed) - PluginManager::PluginsChanged(); + + PluginManager::PluginsChanged(); } bool PluginManagerService::Init() { + Initialized = false; + // Process already loaded modules for (auto module : BinaryModule::GetModules()) { OnBinaryModuleLoaded(module); } - // Initialize plugins - auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly; - auto pluginLoadOrderAttribute = engineAssembly->GetClass("FlaxEngine.PluginLoadOrderAttribute"); - auto afterTypeField = pluginLoadOrderAttribute->GetField("InitializeAfter"); - ASSERT(afterTypeField); - -#if !USE_EDITOR - auto gamePlugins = SortPlugins(GamePlugins, pluginLoadOrderAttribute, afterTypeField); - - // Initialize game plugins - for (auto plugin : gamePlugins) - { - PluginManagerService::InvokeInitialize(plugin); - } -#endif - -#if USE_EDITOR - auto editorPlugins = SortPlugins(EditorPlugins, pluginLoadOrderAttribute, afterTypeField); - - // Initialize editor plugins - for (auto plugin : editorPlugins) - { - PluginManagerService::InvokeInitialize(plugin); - } -#endif + // Invoke plugins initialization for all of them + InitializePlugins(); // Register for new binary modules load actions + Initialized = true; Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded); Scripting::ScriptsReloading.Bind(&OnScriptsReloading); @@ -386,38 +395,13 @@ bool PluginManagerService::Init() void PluginManagerService::Dispose() { + // Unregister from new modules loading + Initialized = false; Scripting::BinaryModuleLoaded.Unbind(&OnBinaryModuleLoaded); Scripting::ScriptsReloading.Unbind(&OnScriptsReloading); // Cleanup all plugins - PROFILE_CPU_NAMED("Dispose Plugins"); - const int32 pluginsCount = EditorPlugins.Count() + GamePlugins.Count(); - if (pluginsCount == 0) - return; - LOG(Info, "Unloading {0} plugins", pluginsCount); - - auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly; - auto pluginLoadOrderAttribute = engineAssembly->GetClass("FlaxEngine.PluginLoadOrderAttribute"); - auto beforeTypeField = pluginLoadOrderAttribute->GetField("DeinitializeBefore"); - ASSERT(beforeTypeField); - - auto editorPlugins = SortPlugins(EditorPlugins, pluginLoadOrderAttribute, beforeTypeField); - for (int32 i = editorPlugins.Count() - 1; i >= 0 && editorPlugins.Count() > 0; i--) - { - auto plugin = editorPlugins[i]; - InvokeDeinitialize(plugin); - EditorPlugins.Remove(plugin); - } - - auto gamePlugins = SortPlugins(GamePlugins, pluginLoadOrderAttribute, beforeTypeField); - for (int32 i = gamePlugins.Count() - 1; i >= 0 && gamePlugins.Count() > 0; i--) - { - auto plugin = gamePlugins[i]; - InvokeDeinitialize(plugin); - GamePlugins.Remove(plugin); - } - - PluginManager::PluginsChanged(); + DeinitializePlugins(); } const Array& PluginManager::GetGamePlugins() @@ -432,11 +416,13 @@ const Array& PluginManager::GetEditorPlugins() Plugin* PluginManager::GetPlugin(const StringView& name) { +#if USE_EDITOR for (Plugin* p : EditorPlugins) { if (p->GetDescription().Name == name) return p; } +#endif for (GamePlugin* gp : GamePlugins) { if (gp->GetDescription().Name == name) @@ -448,11 +434,13 @@ Plugin* PluginManager::GetPlugin(const StringView& name) Plugin* PluginManager::GetPlugin(const MClass* type) { CHECK_RETURN(type, nullptr); +#if USE_EDITOR for (Plugin* p : EditorPlugins) { if (p->GetClass()->IsSubClassOf(type)) return p; } +#endif for (GamePlugin* gp : GamePlugins) { if (gp->GetClass()->IsSubClassOf(type)) @@ -464,11 +452,13 @@ Plugin* PluginManager::GetPlugin(const MClass* type) Plugin* PluginManager::GetPlugin(const ScriptingTypeHandle& type) { CHECK_RETURN(type, nullptr); +#if USE_EDITOR for (Plugin* p : EditorPlugins) { if (p->Is(type)) return p; } +#endif for (GamePlugin* gp : GamePlugins) { if (gp->Is(type))