Refactor EditorPlugins to properly initialize and deinitialize

This commit is contained in:
2022-09-02 09:52:41 +02:00
parent 1d7ba2210a
commit fba60f05a0
4 changed files with 116 additions and 13 deletions
+7 -1
View File
@@ -571,7 +571,13 @@ namespace FlaxEditor
// Deinitialize Editor Plugins
foreach (var plugin in PluginManager.EditorPlugins)
((EditorPlugin)plugin).DeinitializeEditor();
{
if (plugin is EditorPlugin editorPlugin && editorPlugin._isEditorInitialized)
{
editorPlugin._isEditorInitialized = false;
editorPlugin.DeinitializeEditor();
}
}
// Start exit
StateMachine.GoToState<ClosingState>();
+17 -12
View File
@@ -5,15 +5,10 @@ using FlaxEngine;
namespace FlaxEditor
{
/// <summary>
/// Base class for all plugins used in Editor.
/// </summary>
/// <remarks>
/// Plugins should have a public and parameter-less constructor.
/// </remarks>
/// <seealso cref="FlaxEngine.Plugin" />
public abstract class EditorPlugin : Plugin
partial class EditorPlugin
{
internal bool _isEditorInitialized;
/// <summary>
/// Gets the type of the <see cref="GamePlugin"/> that is related to this plugin. Some plugins may be used only in editor while others want to gave a runtime representation. Use this property to link the related game plugin.
/// </summary>
@@ -24,14 +19,12 @@ namespace FlaxEditor
/// </summary>
public Editor Editor { get; private set; }
/// <inheritdoc />
public override void Initialize()
internal void Initialize_Internal()
{
base.Initialize();
Editor = Editor.Instance;
if (Editor.IsInitialized)
{
_isEditorInitialized = true;
InitializeEditor();
}
else
@@ -40,9 +33,21 @@ namespace FlaxEditor
}
}
internal void Deinitialize_Internal()
{
if (_isEditorInitialized)
{
_isEditorInitialized = false;
DeinitializeEditor();
}
}
private void OnEditorInitializationEnd()
{
Editor.InitializationEnd -= OnEditorInitializationEnd;
if (_isEditorInitialized)
return;
_isEditorInitialized = true;
InitializeEditor();
}
@@ -0,0 +1,24 @@
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
#pragma once
#include "Plugin.h"
#if USE_EDITOR
/// <summary>
/// Base class for all plugins used in Editor.
/// </summary>
/// <remarks>
/// Plugins should have a public and parameter-less constructor.
/// </remarks>
/// <seealso cref="FlaxEngine.Plugin" />
API_CLASS(Abstract, Namespace="FlaxEditor") class FLAXENGINE_API EditorPlugin : public Plugin
{
DECLARE_SCRIPTING_TYPE(EditorPlugin);
public:
void Initialize() override;
void Deinitialize() override;
};
#endif
@@ -27,6 +27,45 @@ GamePlugin::GamePlugin(const SpawnParams& params)
{
}
#if USE_EDITOR
#include "EditorPlugin.h"
#include "Engine/Scripting/MException.h"
#include "Engine/Scripting/ManagedCLR/MMethod.h"
EditorPlugin::EditorPlugin(const SpawnParams& params)
: Plugin(params)
{
}
void EditorPlugin::Initialize()
{
Plugin::Initialize();
MObject* exception = nullptr;
TypeInitializer.GetType().ManagedClass->GetMethod("Initialize_Internal")->Invoke(GetOrCreateManagedInstance(), nullptr, &exception);
if (exception)
{
MException ex(exception);
ex.Log(LogType::Error,TEXT("EditorPlugin"));
}
}
void EditorPlugin::Deinitialize()
{
MObject* exception = nullptr;
TypeInitializer.GetType().ManagedClass->GetMethod("Deinitialize_Internal")->Invoke(GetOrCreateManagedInstance(), nullptr, &exception);
if (exception)
{
MException ex(exception);
ex.Log(LogType::Error,TEXT("EditorPlugin"));
}
Plugin::Deinitialize();
}
#endif
Delegate<Plugin*> PluginManager::PluginLoading;
Delegate<Plugin*> PluginManager::PluginLoaded;
Delegate<Plugin*> PluginManager::PluginUnloading;
@@ -42,6 +81,7 @@ namespace PluginManagerImpl
void OnAssemblyLoaded(MAssembly* assembly);
void OnAssemblyUnloading(MAssembly* assembly);
void OnBinaryModuleLoaded(BinaryModule* module);
void OnScriptsReloading();
}
using namespace PluginManagerImpl;
@@ -211,6 +251,32 @@ void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module)
managedModule->Assembly->Unloading.Bind(OnAssemblyUnloading);
}
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;
for (int32 i = EditorPlugins.Count() - 1; i >= 0 && EditorPlugins.Count() > 0; i--)
{
auto plugin = EditorPlugins[i];
{
PluginManagerService::InvokeDeinitialize(plugin);
EditorPlugins.RemoveAtKeepOrder(i);
changed = true;
}
}
for (int32 i = GamePlugins.Count() - 1; i >= 0 && GamePlugins.Count() > 0; i--)
{
auto plugin = GamePlugins[i];
{
PluginManagerService::InvokeDeinitialize(plugin);
GamePlugins.RemoveAtKeepOrder(i);
changed = true;
}
}
if (changed)
PluginManager::PluginsChanged();
}
bool PluginManagerService::Init()
{
// Process already loaded modules
@@ -221,6 +287,7 @@ bool PluginManagerService::Init()
// Register for new binary modules load actions
Scripting::BinaryModuleLoaded.Bind(&OnBinaryModuleLoaded);
Scripting::ScriptsReloading.Bind(&OnScriptsReloading);
return false;
}
@@ -228,6 +295,7 @@ bool PluginManagerService::Init()
void PluginManagerService::Dispose()
{
Scripting::BinaryModuleLoaded.Unbind(&OnBinaryModuleLoaded);
Scripting::ScriptsReloading.Unbind(&OnScriptsReloading);
// Cleanup all plugins
PROFILE_CPU_NAMED("Dispose Plugins");