Refactor Plugins system to support plugins in C++ scripts
This commit is contained in:
@@ -128,7 +128,9 @@ namespace FlaxEditor
|
||||
// Plugin assets
|
||||
foreach (var plugin in PluginManager.GamePlugins)
|
||||
{
|
||||
plugin.OnCollectAssets(list);
|
||||
var pluginRefs = plugin.GetReferences();
|
||||
if (pluginRefs != null)
|
||||
list.AddRange(pluginRefs);
|
||||
}
|
||||
|
||||
if (list.Count == 0)
|
||||
|
||||
@@ -144,7 +144,7 @@ namespace FlaxEditor.States
|
||||
_duplicateScenes.GatherSceneData();
|
||||
Editor.Internal_SetPlayMode(true);
|
||||
IsPaused = false;
|
||||
PluginManager.InitializeGamePlugins();
|
||||
PluginManager.Internal_InitializeGamePlugins();
|
||||
_duplicateScenes.CreateScenes();
|
||||
SceneDuplicated?.Invoke();
|
||||
RestoreSelection();
|
||||
@@ -180,7 +180,7 @@ namespace FlaxEditor.States
|
||||
// Restore editor scene
|
||||
SceneRestoring?.Invoke();
|
||||
_duplicateScenes.DeletedScenes();
|
||||
PluginManager.DeinitializeGamePlugins();
|
||||
PluginManager.Internal_DeinitializeGamePlugins();
|
||||
Editor.Internal_SetPlayMode(false);
|
||||
_duplicateScenes.RestoreSceneData();
|
||||
SceneRestored?.Invoke();
|
||||
|
||||
@@ -190,9 +190,11 @@ namespace FlaxEditor.Windows
|
||||
private void OnPluginsChanged()
|
||||
{
|
||||
List<PluginEntry> toRemove = null;
|
||||
var gamePlugins = PluginManager.GamePlugins;
|
||||
var editorPlugins = PluginManager.EditorPlugins;
|
||||
foreach (var e in _entries)
|
||||
{
|
||||
if (!PluginManager.EditorPlugins.Contains(e.Key) && !PluginManager.GamePlugins.Contains(e.Key))
|
||||
if (!editorPlugins.Contains(e.Key) && !gamePlugins.Contains(e.Key))
|
||||
{
|
||||
if (toRemove == null)
|
||||
toRemove = new List<PluginEntry>();
|
||||
@@ -204,9 +206,9 @@ namespace FlaxEditor.Windows
|
||||
foreach (var plugin in toRemove)
|
||||
OnPluginRemove(plugin);
|
||||
}
|
||||
foreach (var plugin in PluginManager.GamePlugins)
|
||||
foreach (var plugin in gamePlugins)
|
||||
OnPluginAdd(plugin);
|
||||
foreach (var plugin in PluginManager.EditorPlugins)
|
||||
foreach (var plugin in editorPlugins)
|
||||
OnPluginAdd(plugin);
|
||||
}
|
||||
|
||||
@@ -288,7 +290,7 @@ namespace FlaxEditor.Windows
|
||||
|
||||
foreach (var e in _entries.Keys)
|
||||
{
|
||||
if (e.GetType() == pluginType)
|
||||
if (e.GetType() == pluginType && _entries.ContainsKey(e))
|
||||
return _entries[e];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,30 @@
|
||||
#include "Version.h"
|
||||
#include "Engine/Core/Types/StringBuilder.h"
|
||||
|
||||
Version::Version(int32 major, int32 minor, int32 build, int32 revision)
|
||||
{
|
||||
_major = Math::Max(major, 0);
|
||||
_minor = Math::Max(minor, 0);
|
||||
_build = Math::Max(build, 0);
|
||||
_revision = Math::Max(revision, 0);
|
||||
}
|
||||
|
||||
Version::Version(int32 major, int32 minor, int32 build)
|
||||
{
|
||||
_major = Math::Max(major, 0);
|
||||
_minor = Math::Max(minor, 0);
|
||||
_build = Math::Max(build, 0);
|
||||
_revision = -1;
|
||||
}
|
||||
|
||||
Version::Version(int32 major, int32 minor)
|
||||
{
|
||||
_major = Math::Max(major, 0);
|
||||
_minor = Math::Max(minor, 0);
|
||||
_build = -1;
|
||||
_revision = -1;
|
||||
}
|
||||
|
||||
int32 Version::CompareTo(const Version& value) const
|
||||
{
|
||||
if (_major != value._major)
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
/// <summary>
|
||||
/// Represents the version number made of major, minor, build and revision numbers.
|
||||
/// </summary>
|
||||
struct FLAXENGINE_API Version
|
||||
API_STRUCT(InBuild) struct FLAXENGINE_API Version
|
||||
{
|
||||
private:
|
||||
int32 _major;
|
||||
@@ -25,13 +25,7 @@ public:
|
||||
/// <param name="minor">The minor version number.</param>
|
||||
/// <param name="build">The build number.</param>
|
||||
/// <param name="revision">The revision number.</param>
|
||||
Version(int32 major, int32 minor, int32 build, int32 revision)
|
||||
{
|
||||
_major = Math::Max(major, 0);
|
||||
_minor = Math::Max(minor, 0);
|
||||
_build = Math::Max(build, 0);
|
||||
_revision = Math::Max(revision, 0);
|
||||
}
|
||||
Version(int32 major, int32 minor, int32 build, int32 revision);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Version class using the specified major, minor, and build values.
|
||||
@@ -39,26 +33,14 @@ public:
|
||||
/// <param name="major">The major version number.</param>
|
||||
/// <param name="minor">The minor version number.</param>
|
||||
/// <param name="build">The build number.</param>
|
||||
Version(int32 major, int32 minor, int32 build)
|
||||
{
|
||||
_major = Math::Max(major, 0);
|
||||
_minor = Math::Max(minor, 0);
|
||||
_build = Math::Max(build, 0);
|
||||
_revision = -1;
|
||||
}
|
||||
Version(int32 major, int32 minor, int32 build);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Version class using the specified major and minor values.
|
||||
/// </summary>
|
||||
/// <param name="major">The major version number.</param>
|
||||
/// <param name="minor">The minor version number.</param>
|
||||
Version(int32 major, int32 minor)
|
||||
{
|
||||
_major = Math::Max(major, 0);
|
||||
_minor = Math::Max(minor, 0);
|
||||
_build = -1;
|
||||
_revision = -1;
|
||||
}
|
||||
Version(int32 major, int32 minor);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the Version class.
|
||||
@@ -67,8 +49,8 @@ public:
|
||||
{
|
||||
_major = 0;
|
||||
_minor = 0;
|
||||
_revision = 0;
|
||||
_build = 0;
|
||||
_revision = -1;
|
||||
_build = -1;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "Engine/Platform/MessageBox.h"
|
||||
#include "Engine/Engine/CommandLine.h"
|
||||
#include "Engine/Serialization/JsonSerializer.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#endif
|
||||
|
||||
#if USE_LARGE_WORLDS
|
||||
@@ -950,7 +951,12 @@ bool Level::loadScene(rapidjson_flax::Value& data, int32 engineBuild, Scene** ou
|
||||
LOG(Error, "Cannot load scene without game modules loaded.");
|
||||
#if USE_EDITOR
|
||||
if (!CommandLine::Options.Headless.IsTrue())
|
||||
MessageBox::Show(TEXT("Cannot load scene without game script modules. Please fix the compilation issues. See logs for more info."), TEXT("Missing game modules"), MessageBoxButtons::OK, MessageBoxIcon::Error);
|
||||
{
|
||||
if (ScriptsBuilder::LastCompilationFailed())
|
||||
MessageBox::Show(TEXT("Scripts compilation failed. Cannot load scene without game script modules. Please fix the compilation issues. See logs for more info."), TEXT("Failed to compile scripts"), MessageBoxButtons::OK, MessageBoxIcon::Error);
|
||||
else
|
||||
MessageBox::Show(TEXT("Failed to load scripts. Cannot load scene without game script modules. See logs for more info."), TEXT("Missing game modules"), MessageBoxButtons::OK, MessageBoxIcon::Error);
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -571,6 +571,17 @@ String ScriptingType::ToString() const
|
||||
return String(Fullname.Get(), Fullname.Length());
|
||||
}
|
||||
|
||||
StringAnsiView ScriptingType::GetName() const
|
||||
{
|
||||
int32 lastDotIndex = Fullname.FindLast('.');
|
||||
if (lastDotIndex != -1)
|
||||
{
|
||||
lastDotIndex++;
|
||||
return StringAnsiView(Fullname.Get() + lastDotIndex, Fullname.Length() - lastDotIndex);
|
||||
}
|
||||
return Fullname;
|
||||
}
|
||||
|
||||
ScriptingTypeInitializer::ScriptingTypeInitializer(BinaryModule* module, const StringAnsiView& fullname, int32 size, ScriptingType::InitRuntimeHandler initRuntime, ScriptingType::SpawnHandler spawn, ScriptingTypeInitializer* baseType, ScriptingType::SetupScriptVTableHandler setupScriptVTable, ScriptingType::SetupScriptObjectVTableHandler setupScriptObjectVTable, const ScriptingType::InterfaceImplementation* interfaces)
|
||||
: ScriptingTypeHandle(module, module->Types.Count())
|
||||
{
|
||||
@@ -686,7 +697,7 @@ ManagedBinaryModule::ManagedBinaryModule(MAssembly* assembly)
|
||||
// Bind for C# assembly events
|
||||
assembly->Loading.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnLoading>(this);
|
||||
assembly->Loaded.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnLoaded>(this);
|
||||
assembly->Unloading.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnUnloading>(this);
|
||||
assembly->Unloaded.Bind<ManagedBinaryModule, &ManagedBinaryModule::OnUnloaded>(this);
|
||||
|
||||
if (Assembly->IsLoaded())
|
||||
{
|
||||
@@ -1084,7 +1095,7 @@ void ManagedBinaryModule::InitType(MClass* mclass)
|
||||
#endif
|
||||
}
|
||||
|
||||
void ManagedBinaryModule::OnUnloading(MAssembly* assembly)
|
||||
void ManagedBinaryModule::OnUnloaded(MAssembly* assembly)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
|
||||
|
||||
@@ -309,7 +309,7 @@ private:
|
||||
void OnLoading(MAssembly* assembly);
|
||||
void OnLoaded(MAssembly* assembly);
|
||||
void InitType(MClass* mclass);
|
||||
void OnUnloading(MAssembly* assembly);
|
||||
void OnUnloaded(MAssembly* assembly);
|
||||
|
||||
public:
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "MType.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/DataContainer.h"
|
||||
#include "Engine/Core/Types/Version.h"
|
||||
#include "Engine/Core/Math/BoundingBox.h"
|
||||
#include "Engine/Core/Math/BoundingSphere.h"
|
||||
#include "Engine/Core/Math/Rectangle.h"
|
||||
@@ -1279,4 +1280,18 @@ void* MUtils::VariantToManagedArgPtr(Variant& value, const MType& type, bool& fa
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
MonoObject* MUtils::ToManaged(const Version& value)
|
||||
{
|
||||
auto obj = mono_object_new(mono_domain_get(), Scripting::FindClassNative("System.Version"));
|
||||
Platform::MemoryCopy((byte*)obj + sizeof(MonoObject), &value, sizeof(Version));
|
||||
return obj;
|
||||
}
|
||||
|
||||
Version MUtils::ToNative(MonoObject* value)
|
||||
{
|
||||
if (value)
|
||||
return *(Version*)((byte*)value + sizeof(MonoObject));
|
||||
return Version();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/object.h>
|
||||
#include <ThirdParty/mono-2.0/mono/metadata/appdomain.h>
|
||||
|
||||
struct Version;
|
||||
|
||||
namespace MUtils
|
||||
{
|
||||
extern FLAXENGINE_API StringView ToString(MonoString* str);
|
||||
@@ -500,6 +502,9 @@ namespace MUtils
|
||||
}
|
||||
|
||||
extern void* VariantToManagedArgPtr(Variant& value, const MType& type, bool& failed);
|
||||
extern MonoObject* ToManaged(const Version& value);
|
||||
extern Version ToNative(MonoObject* value);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for all plugins used at runtime in game.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Plugins should have a public and parameter-less constructor.
|
||||
/// </remarks>
|
||||
/// <seealso cref="FlaxEngine.Plugin" />
|
||||
public abstract class GamePlugin : Plugin
|
||||
{
|
||||
#if FLAX_EDITOR
|
||||
/// <summary>
|
||||
/// Event called during game cooking in Editor to collect any assets that this plugin uses. Can be used to inject content for plugins.
|
||||
/// </summary>
|
||||
/// <param name="assets">The result assets list (always valid).</param>
|
||||
public virtual void OnCollectAssets(System.Collections.Generic.List<System.Guid> assets)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
25
Source/Engine/Scripting/Plugins/GamePlugin.h
Normal file
25
Source/Engine/Scripting/Plugins/GamePlugin.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Plugin.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
|
||||
/// <summary>
|
||||
/// Base class for all plugins used at runtime in game.
|
||||
/// </summary>
|
||||
API_CLASS(Abstract) class FLAXENGINE_API GamePlugin : public Plugin
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE(GamePlugin);
|
||||
public:
|
||||
#if USE_EDITOR
|
||||
/// <summary>
|
||||
/// Function called during game cooking in Editor to collect any assets that this plugin uses. Can be used to inject content for plugins.
|
||||
/// </summary>
|
||||
/// <returns>The result assets list.</returns>
|
||||
API_FUNCTION() virtual Array<Guid> GetReferences() const
|
||||
{
|
||||
return Array<Guid>();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
@@ -1,44 +0,0 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for game engine editor plugins.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Plugins should have a public and parameter-less constructor.
|
||||
/// </remarks>
|
||||
public abstract class Plugin
|
||||
{
|
||||
internal bool _initialized;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the description.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Plugin description should be a constant part of the plugin created in constructor and valid before calling <see cref="Initialize"/>.
|
||||
/// </remarks>
|
||||
public virtual PluginDescription Description => new PluginDescription
|
||||
{
|
||||
Name = GetType().Name,
|
||||
Category = "Other",
|
||||
Version = new Version(1, 0),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initialization method called when this plugin is loaded to the memory and can be used.
|
||||
/// </summary>
|
||||
public virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup method called when this plugin is being unloaded or reloaded or engine is closing.
|
||||
/// </summary>
|
||||
public virtual void Deinitialize()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
46
Source/Engine/Scripting/Plugins/Plugin.h
Normal file
46
Source/Engine/Scripting/Plugins/Plugin.h
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PluginDescription.h"
|
||||
#include "Engine/Scripting/ScriptingObject.h"
|
||||
|
||||
/// <summary>
|
||||
/// Base class for game engine editor plugins.
|
||||
/// </summary>
|
||||
API_CLASS(Abstract) class FLAXENGINE_API Plugin : public ScriptingObject
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE(Plugin);
|
||||
private:
|
||||
friend class PluginManagerService;
|
||||
bool _initialized = false;
|
||||
|
||||
protected:
|
||||
/// <remarks>
|
||||
/// Plugin description. Should be a constant part of the plugin created in constructor and valid before calling <see cref="Initialize"/>.
|
||||
/// </remarks>
|
||||
API_FIELD() PluginDescription _description;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the description.
|
||||
/// </summary>
|
||||
API_PROPERTY() const PluginDescription& GetDescription() const
|
||||
{
|
||||
return _description;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialization method called when this plugin is loaded to the memory and can be used.
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cleanup method called when this plugin is being unloaded or reloaded or engine is closing.
|
||||
/// </summary>
|
||||
API_FUNCTION() virtual void Deinitialize()
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// The engine plugin description container.
|
||||
/// </summary>
|
||||
public struct PluginDescription
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the plugin.
|
||||
/// </summary>
|
||||
public string Name;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the plugin.
|
||||
/// </summary>
|
||||
public Version Version;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the author of the plugin.
|
||||
/// </summary>
|
||||
public string Author;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin author website URL.
|
||||
/// </summary>
|
||||
public string AuthorUrl;
|
||||
|
||||
/// <summary>
|
||||
/// The homepage URL for the plugin.
|
||||
/// </summary>
|
||||
public string HomepageUrl;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin repository URL (for open-source plugins).
|
||||
/// </summary>
|
||||
public string RepositoryUrl;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin description.
|
||||
/// </summary>
|
||||
public string Description;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin category.
|
||||
/// </summary>
|
||||
public string Category;
|
||||
|
||||
/// <summary>
|
||||
/// True if plugin is during Beta tests (before release).
|
||||
/// </summary>
|
||||
public bool IsBeta;
|
||||
|
||||
/// <summary>
|
||||
/// True if plugin is during Alpha tests (early version).
|
||||
/// </summary>
|
||||
public bool IsAlpha;
|
||||
}
|
||||
}
|
||||
65
Source/Engine/Scripting/Plugins/PluginDescription.h
Normal file
65
Source/Engine/Scripting/Plugins/PluginDescription.h
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/String.h"
|
||||
#include "Engine/Core/Types/Version.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
|
||||
/// <summary>
|
||||
/// The engine plugin description container.
|
||||
/// </summary>
|
||||
API_STRUCT() struct PluginDescription
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(PluginDescription);
|
||||
public:
|
||||
/// <summary>
|
||||
/// The name of the plugin.
|
||||
/// </summary>
|
||||
API_FIELD() String Name;
|
||||
|
||||
/// <summary>
|
||||
/// The version of the plugin.
|
||||
/// </summary>
|
||||
API_FIELD() Version Version;
|
||||
|
||||
/// <summary>
|
||||
/// The name of the author of the plugin.
|
||||
/// </summary>
|
||||
API_FIELD() String Author;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin author website URL.
|
||||
/// </summary>
|
||||
API_FIELD() String AuthorUrl;
|
||||
|
||||
/// <summary>
|
||||
/// The homepage URL for the plugin.
|
||||
/// </summary>
|
||||
API_FIELD() String HomepageUrl;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin repository URL (for open-source plugins).
|
||||
/// </summary>
|
||||
API_FIELD() String RepositoryUrl;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin description.
|
||||
/// </summary>
|
||||
API_FIELD() String Description;
|
||||
|
||||
/// <summary>
|
||||
/// The plugin category.
|
||||
/// </summary>
|
||||
API_FIELD() String Category;
|
||||
|
||||
/// <summary>
|
||||
/// True if plugin is during Beta tests (before release).
|
||||
/// </summary>
|
||||
API_FIELD() bool IsBeta = false;
|
||||
|
||||
/// <summary>
|
||||
/// True if plugin is during Alpha tests (early version).
|
||||
/// </summary>
|
||||
API_FIELD() bool IsAlpha = false;
|
||||
};
|
||||
@@ -2,22 +2,41 @@
|
||||
|
||||
#include "PluginManager.h"
|
||||
#include "FlaxEngine.Gen.h"
|
||||
#include "GamePlugin.h"
|
||||
#include "Engine/Scripting/Scripting.h"
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Scripting/BinaryModule.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MAssembly.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MMethod.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MClass.h"
|
||||
#include "Engine/Scripting/ManagedCLR/MUtils.h"
|
||||
#include "Engine/Platform/FileSystem.h"
|
||||
#include "Engine/Debug/DebugLog.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Engine/EngineService.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
|
||||
Plugin::Plugin(const SpawnParams& params)
|
||||
: ScriptingObject(params)
|
||||
{
|
||||
_description.Name = String(GetType().GetName());
|
||||
_description.Category = TEXT("Other");
|
||||
_description.Version = Version(1, 0);
|
||||
}
|
||||
|
||||
GamePlugin::GamePlugin(const SpawnParams& params)
|
||||
: Plugin(params)
|
||||
{
|
||||
}
|
||||
|
||||
Delegate<Plugin*> PluginManager::PluginLoading;
|
||||
Delegate<Plugin*> PluginManager::PluginLoaded;
|
||||
Delegate<Plugin*> PluginManager::PluginUnloading;
|
||||
Delegate<Plugin*> PluginManager::PluginUnloaded;
|
||||
Action PluginManager::PluginsChanged;
|
||||
|
||||
namespace PluginManagerImpl
|
||||
{
|
||||
MMethod* Internal_LoadPlugin = nullptr;
|
||||
Array<GamePlugin*> GamePlugins;
|
||||
Array<Plugin*> EditorPlugins;
|
||||
|
||||
void LoadPlugin(MClass* klass, bool isEditor);
|
||||
void OnAssemblyLoaded(MAssembly* assembly);
|
||||
@@ -30,7 +49,6 @@ using namespace PluginManagerImpl;
|
||||
class PluginManagerService : public EngineService
|
||||
{
|
||||
public:
|
||||
|
||||
PluginManagerService()
|
||||
: EngineService(TEXT("Plugin Manager"), 130)
|
||||
{
|
||||
@@ -38,50 +56,79 @@ public:
|
||||
|
||||
bool Init() override;
|
||||
void Dispose() override;
|
||||
|
||||
static void InvokeInitialize(Plugin* plugin);
|
||||
static void InvokeDeinitialize(Plugin* plugin);
|
||||
};
|
||||
|
||||
PluginManagerService PluginManagerServiceInstance;
|
||||
|
||||
void PluginManagerService::InvokeInitialize(Plugin* plugin)
|
||||
{
|
||||
if (plugin->_initialized)
|
||||
return;
|
||||
|
||||
LOG(Info, "Loading plugin {}", plugin->ToString());
|
||||
|
||||
PluginManager::PluginLoading(plugin);
|
||||
|
||||
plugin->Initialize();
|
||||
plugin->_initialized = true;
|
||||
|
||||
PluginManager::PluginLoaded(plugin);
|
||||
}
|
||||
|
||||
void PluginManagerService::InvokeDeinitialize(Plugin* plugin)
|
||||
{
|
||||
if (!plugin->_initialized)
|
||||
return;
|
||||
|
||||
LOG(Info, "Unloading plugin {}", plugin->ToString());
|
||||
|
||||
PluginManager::PluginUnloading(plugin);
|
||||
|
||||
plugin->Deinitialize();
|
||||
plugin->_initialized = false;
|
||||
|
||||
PluginManager::PluginUnloaded(plugin);
|
||||
}
|
||||
|
||||
void PluginManagerImpl::LoadPlugin(MClass* klass, bool isEditor)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
if (Internal_LoadPlugin == nullptr)
|
||||
{
|
||||
Internal_LoadPlugin = PluginManager::GetStaticClass()->GetMethod("Internal_LoadPlugin", 2);
|
||||
ASSERT(Internal_LoadPlugin);
|
||||
}
|
||||
// Create and check if use it
|
||||
auto plugin = (Plugin*)Scripting::NewObject(klass);
|
||||
if (!plugin)
|
||||
return;
|
||||
|
||||
MObject* exception = nullptr;
|
||||
void* params[2];
|
||||
params[0] = MUtils::GetType(klass->GetNative());
|
||||
params[1] = &isEditor;
|
||||
Internal_LoadPlugin->Invoke(nullptr, params, &exception);
|
||||
if (exception)
|
||||
if (!isEditor)
|
||||
{
|
||||
DebugLog::LogException(exception);
|
||||
GamePlugins.Add((GamePlugin*)plugin);
|
||||
#if !USE_EDITOR
|
||||
PluginManagerService::InvokeInitialize(plugin);
|
||||
#endif
|
||||
}
|
||||
#if USE_EDITOR
|
||||
else
|
||||
{
|
||||
EditorPlugins.Add(plugin);
|
||||
PluginManagerService::InvokeInitialize(plugin);
|
||||
}
|
||||
#endif
|
||||
PluginManager::PluginsChanged();
|
||||
}
|
||||
|
||||
void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly)
|
||||
{
|
||||
PROFILE_CPU_NAMED("Load Assembly Plugins");
|
||||
|
||||
// Prepare FlaxEngine
|
||||
auto engineAssembly = ((NativeBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly;
|
||||
if (!engineAssembly->IsLoaded())
|
||||
{
|
||||
LOG(Warning, "Cannot find plugin class types for assembly {0} because FlaxEngine is not loaded.", assembly->ToString());
|
||||
return;
|
||||
}
|
||||
const auto gamePluginClass = engineAssembly->GetClass("FlaxEngine.GamePlugin");
|
||||
const auto gamePluginClass = GamePlugin::GetStaticClass();
|
||||
if (gamePluginClass == nullptr)
|
||||
{
|
||||
LOG(Warning, "Missing GamePlugin class.");
|
||||
return;
|
||||
}
|
||||
#if USE_EDITOR
|
||||
const auto editorPluginClass = engineAssembly->GetClass("FlaxEditor.EditorPlugin");
|
||||
const auto editorPluginClass = ((ManagedBinaryModule*)GetBinaryModuleFlaxEngine())->Assembly->GetClass("FlaxEditor.EditorPlugin");
|
||||
if (editorPluginClass == nullptr)
|
||||
{
|
||||
LOG(Warning, "Missing EditorPlugin class.");
|
||||
@@ -115,19 +162,29 @@ void PluginManagerImpl::OnAssemblyLoaded(MAssembly* assembly)
|
||||
|
||||
void PluginManagerImpl::OnAssemblyUnloading(MAssembly* assembly)
|
||||
{
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Cleanup plugins from this assembly
|
||||
const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose", 1);
|
||||
ASSERT(disposeMethod);
|
||||
MObject* exception = nullptr;
|
||||
void* params[1];
|
||||
params[0] = assembly->GetNative();
|
||||
disposeMethod->Invoke(nullptr, params, &exception);
|
||||
if (exception)
|
||||
bool changed = false;
|
||||
for (int32 i = EditorPlugins.Count() - 1; i >= 0 && EditorPlugins.Count() > 0; i--)
|
||||
{
|
||||
DebugLog::LogException(exception);
|
||||
auto plugin = EditorPlugins[i];
|
||||
if (plugin->GetType().ManagedClass->GetAssembly() == assembly)
|
||||
{
|
||||
PluginManagerService::InvokeDeinitialize(plugin);
|
||||
EditorPlugins.RemoveAtKeepOrder(i);
|
||||
changed = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
for (int32 i = GamePlugins.Count() - 1; i >= 0 && GamePlugins.Count() > 0; i--)
|
||||
{
|
||||
auto plugin = GamePlugins[i];
|
||||
if (plugin->GetType().ManagedClass->GetAssembly() == assembly)
|
||||
{
|
||||
PluginManagerService::InvokeDeinitialize(plugin);
|
||||
GamePlugins.RemoveAtKeepOrder(i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
PluginManager::PluginsChanged();
|
||||
}
|
||||
|
||||
void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module)
|
||||
@@ -138,6 +195,7 @@ void PluginManagerImpl::OnBinaryModuleLoaded(BinaryModule* module)
|
||||
return;
|
||||
|
||||
// Skip non-managed modules
|
||||
// TODO: search native-only modules too
|
||||
auto managedModule = dynamic_cast<ManagedBinaryModule*>(module);
|
||||
if (!managedModule)
|
||||
return;
|
||||
@@ -171,17 +229,86 @@ void PluginManagerService::Dispose()
|
||||
{
|
||||
Scripting::BinaryModuleLoaded.Unbind(&OnBinaryModuleLoaded);
|
||||
|
||||
PROFILE_CPU_NAMED("Dispose Plugins");
|
||||
|
||||
#if !COMPILE_WITHOUT_CSHARP
|
||||
// Cleanup all plugins
|
||||
const auto disposeMethod = PluginManager::GetStaticClass()->GetMethod("Internal_Dispose");
|
||||
ASSERT(disposeMethod);
|
||||
MObject* exception = nullptr;
|
||||
disposeMethod->Invoke(nullptr, nullptr, &exception);
|
||||
if (exception)
|
||||
PROFILE_CPU_NAMED("Dispose Plugins");
|
||||
const int32 pluginsCount = EditorPlugins.Count() + GamePlugins.Count();
|
||||
if (pluginsCount == 0)
|
||||
return;
|
||||
LOG(Info, "Unloading {0} plugins", pluginsCount);
|
||||
for (int32 i = EditorPlugins.Count() - 1; i >= 0 && EditorPlugins.Count() > 0; i--)
|
||||
{
|
||||
DebugLog::LogException(exception);
|
||||
auto plugin = EditorPlugins[i];
|
||||
InvokeDeinitialize(plugin);
|
||||
EditorPlugins.RemoveAtKeepOrder(i);
|
||||
}
|
||||
#endif
|
||||
for (int32 i = GamePlugins.Count() - 1; i >= 0 && GamePlugins.Count() > 0; i--)
|
||||
{
|
||||
auto plugin = GamePlugins[i];
|
||||
InvokeDeinitialize(plugin);
|
||||
GamePlugins.RemoveAtKeepOrder(i);
|
||||
}
|
||||
PluginManager::PluginsChanged();
|
||||
}
|
||||
|
||||
const Array<GamePlugin*>& PluginManager::GetGamePlugins()
|
||||
{
|
||||
return GamePlugins;
|
||||
}
|
||||
|
||||
const Array<Plugin*>& PluginManager::GetEditorPlugins()
|
||||
{
|
||||
return EditorPlugins;
|
||||
}
|
||||
|
||||
Plugin* PluginManager::GetPlugin(const StringView& name)
|
||||
{
|
||||
for (Plugin* p : EditorPlugins)
|
||||
{
|
||||
if (p->GetDescription().Name == name)
|
||||
return p;
|
||||
}
|
||||
for (GamePlugin* gp : GamePlugins)
|
||||
{
|
||||
if (gp->GetDescription().Name == name)
|
||||
return gp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Plugin* PluginManager::GetPlugin(const MClass* type)
|
||||
{
|
||||
CHECK_RETURN(type, nullptr);
|
||||
for (Plugin* p : EditorPlugins)
|
||||
{
|
||||
if (p->GetClass()->IsSubClassOf(type))
|
||||
return p;
|
||||
}
|
||||
for (GamePlugin* gp : GamePlugins)
|
||||
{
|
||||
if (gp->GetClass()->IsSubClassOf(type))
|
||||
return gp;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if USE_EDITOR
|
||||
|
||||
void PluginManager::InitializeGamePlugins()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
for (int32 i = 0; i < GamePlugins.Count(); i++)
|
||||
{
|
||||
PluginManagerService::InvokeInitialize(GamePlugins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void PluginManager::DeinitializeGamePlugins()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
for (int32 i = GamePlugins.Count() - 1; i >= 0; i--)
|
||||
{
|
||||
PluginManagerService::InvokeDeinitialize(GamePlugins[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,282 +1,17 @@
|
||||
// Copyright (c) 2012-2022 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace FlaxEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// Plugin related event delegate type.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin.</param>
|
||||
[HideInEditor]
|
||||
public delegate void PluginDelegate(Plugin plugin);
|
||||
|
||||
public static partial class PluginManager
|
||||
partial class PluginManager
|
||||
{
|
||||
private static readonly List<GamePlugin> _gamePlugins = new List<GamePlugin>();
|
||||
private static readonly List<Plugin> _editorPlugins = new List<Plugin>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the game plugins.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<GamePlugin> GamePlugins => _gamePlugins;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the editor plugins.
|
||||
/// </summary>
|
||||
public static IReadOnlyList<Plugin> EditorPlugins => _editorPlugins;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before loading plugin.
|
||||
/// </summary>
|
||||
public static event PluginDelegate PluginLoading;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when plugin gets loaded and initialized.
|
||||
/// </summary>
|
||||
public static event PluginDelegate PluginLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before unloading plugin.
|
||||
/// </summary>
|
||||
public static event PluginDelegate PluginUnloading;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when plugin gets unloaded. It should not be used anymore.
|
||||
/// </summary>
|
||||
public static event PluginDelegate PluginUnloaded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when plugins collection gets edited (added or removed plugin).
|
||||
/// </summary>
|
||||
public static event Action PluginsChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether can load the specified plugin.
|
||||
/// </summary>
|
||||
/// <param name="pluginDesc">The plugin description.</param>
|
||||
/// <returns>True if load it, otherwise false.</returns>
|
||||
public delegate bool CanLoadPluginDelegate(ref PluginDescription pluginDesc);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether can load the specified plugin.
|
||||
/// </summary>
|
||||
public static CanLoadPluginDelegate CanLoadPlugin = DefaultCanLoadPlugin;
|
||||
|
||||
/// <summary>
|
||||
/// Plugin related event delegate type.
|
||||
/// </summary>
|
||||
/// <param name="plugin">The plugin.</param>
|
||||
public delegate void PluginDelegate(Plugin plugin);
|
||||
|
||||
/// <summary>
|
||||
/// The default implementation for <see cref="CanLoadPlugin"/>.
|
||||
/// </summary>
|
||||
/// <param name="pluginDesc">The plugin description.</param>
|
||||
/// <returns>True if load it, otherwise false.</returns>
|
||||
public static bool DefaultCanLoadPlugin(ref PluginDescription pluginDesc)
|
||||
{
|
||||
return true;
|
||||
//return !pluginDesc.DisabledByDefault;
|
||||
}
|
||||
|
||||
#if FLAX_EDITOR
|
||||
internal static void InitializeGamePlugins()
|
||||
{
|
||||
Profiler.BeginEvent("PluginManager.InitializeGamePlugins");
|
||||
for (var i = 0; i < _gamePlugins.Count; i++)
|
||||
{
|
||||
InvokeInitialize(_gamePlugins[i]);
|
||||
}
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
|
||||
internal static void DeinitializeGamePlugins()
|
||||
{
|
||||
Profiler.BeginEvent("PluginManager.DeinitializeGamePlugins");
|
||||
for (var i = _gamePlugins.Count - 1; i >= 0; i--)
|
||||
{
|
||||
InvokeDeinitialize(_gamePlugins[i]);
|
||||
}
|
||||
Profiler.EndEvent();
|
||||
}
|
||||
#endif
|
||||
|
||||
private static void InvokeInitialize(Plugin plugin)
|
||||
{
|
||||
if (plugin._initialized)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Debug.Write(LogType.Info, "Loading plugin " + plugin);
|
||||
|
||||
PluginLoading?.Invoke(plugin);
|
||||
|
||||
plugin.Initialize();
|
||||
plugin._initialized = true;
|
||||
|
||||
PluginLoaded?.Invoke(plugin);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
Debug.LogErrorFormat("Failed to initialize plugin {0}. {1}", plugin, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InvokeDeinitialize(Plugin plugin)
|
||||
{
|
||||
if (!plugin._initialized)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Debug.Write(LogType.Info, "Unloading plugin " + plugin);
|
||||
|
||||
PluginUnloading?.Invoke(plugin);
|
||||
|
||||
plugin.Deinitialize();
|
||||
plugin._initialized = false;
|
||||
|
||||
PluginUnloaded?.Invoke(plugin);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogException(ex);
|
||||
Debug.LogErrorFormat("Failed to deinitialize plugin {0}. {1}", plugin, ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first plugin of the provided type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The plugin type.</typeparam>
|
||||
/// <returns>The plugin, or null if not loaded.</returns>
|
||||
public static T GetPlugin<T>() where T : class
|
||||
public static T GetPlugin<T>() where T : Plugin
|
||||
{
|
||||
foreach (Plugin p in _editorPlugins)
|
||||
{
|
||||
if (p.GetType() == typeof(T))
|
||||
return (T)Convert.ChangeType(p, typeof(T));
|
||||
}
|
||||
|
||||
foreach (GamePlugin gp in _gamePlugins)
|
||||
{
|
||||
if (gp.GetType() == typeof(T))
|
||||
return (T)Convert.ChangeType(gp, typeof(T));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return the first plugin using the provided name.
|
||||
/// </summary>
|
||||
/// /// <param name="name">The plugin name.</param>
|
||||
/// <returns>The plugin, or null if not loaded.</returns>
|
||||
public static Plugin GetPlugin(string name)
|
||||
{
|
||||
foreach (Plugin p in _editorPlugins)
|
||||
{
|
||||
if (p.Description.Name.Equals(name))
|
||||
return p;
|
||||
}
|
||||
|
||||
foreach (GamePlugin gp in _gamePlugins)
|
||||
{
|
||||
if (gp.Description.Name.Equals(name))
|
||||
return gp;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static void Internal_LoadPlugin(Type type, bool isEditor)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException();
|
||||
|
||||
// Create and check if use it
|
||||
var plugin = (Plugin)Activator.CreateInstance(type);
|
||||
var desc = plugin.Description;
|
||||
if (!CanLoadPlugin(ref desc))
|
||||
{
|
||||
Debug.Write(LogType.Info, "Skip loading plugin " + plugin);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isEditor)
|
||||
{
|
||||
_gamePlugins.Add((GamePlugin)plugin);
|
||||
#if !FLAX_EDITOR
|
||||
InvokeInitialize(plugin);
|
||||
#endif
|
||||
}
|
||||
#if FLAX_EDITOR
|
||||
else
|
||||
{
|
||||
_editorPlugins.Add(plugin);
|
||||
InvokeInitialize(plugin);
|
||||
}
|
||||
#endif
|
||||
PluginsChanged?.Invoke();
|
||||
}
|
||||
|
||||
internal static void Internal_Dispose(Assembly assembly)
|
||||
{
|
||||
bool changed = false;
|
||||
|
||||
for (int i = _editorPlugins.Count - 1; i >= 0 && _editorPlugins.Count > 0; i--)
|
||||
{
|
||||
var plugin = _editorPlugins[i];
|
||||
if (plugin.GetType().Assembly == assembly)
|
||||
{
|
||||
InvokeDeinitialize(plugin);
|
||||
_editorPlugins.RemoveAt(i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = _gamePlugins.Count - 1; i >= 0 && _gamePlugins.Count > 0; i--)
|
||||
{
|
||||
var plugin = _gamePlugins[i];
|
||||
if (plugin.GetType().Assembly == assembly)
|
||||
{
|
||||
InvokeDeinitialize(plugin);
|
||||
_gamePlugins.RemoveAt(i);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
PluginsChanged?.Invoke();
|
||||
}
|
||||
|
||||
internal static void Internal_Dispose()
|
||||
{
|
||||
int pluginsCount = _editorPlugins.Count + _gamePlugins.Count;
|
||||
if (pluginsCount == 0)
|
||||
return;
|
||||
Debug.Write(LogType.Info, string.Format("Unloading {0} plugins", pluginsCount));
|
||||
|
||||
for (int i = _editorPlugins.Count - 1; i >= 0 && _editorPlugins.Count > 0; i--)
|
||||
{
|
||||
var plugin = _editorPlugins[i];
|
||||
InvokeDeinitialize(plugin);
|
||||
_editorPlugins.RemoveAt(i);
|
||||
}
|
||||
|
||||
for (int i = _gamePlugins.Count - 1; i >= 0 && _gamePlugins.Count > 0; i--)
|
||||
{
|
||||
var plugin = _gamePlugins[i];
|
||||
InvokeDeinitialize(plugin);
|
||||
_gamePlugins.RemoveAt(i);
|
||||
}
|
||||
|
||||
PluginsChanged?.Invoke();
|
||||
return (T)GetPlugin(typeof(T));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,13 +2,80 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Scripting/ScriptingType.h"
|
||||
#include "Engine/Core/Collections/Array.h"
|
||||
#include "GamePlugin.h"
|
||||
|
||||
/// <summary>
|
||||
/// Game and Editor plugins management service.
|
||||
/// </summary>
|
||||
API_CLASS(Static) class PluginManager
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(PluginManager);
|
||||
DECLARE_SCRIPTING_TYPE_NO_SPAWN(PluginManager);
|
||||
public:
|
||||
/// <summary>
|
||||
/// Gets the game plugins.
|
||||
/// </summary>
|
||||
API_PROPERTY() static const Array<GamePlugin*>& GetGamePlugins();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the editor plugins.
|
||||
/// </summary>
|
||||
API_PROPERTY() static const Array<Plugin*>& GetEditorPlugins();
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Occurs before loading plugin.
|
||||
/// </summary>
|
||||
API_EVENT() static Delegate<Plugin*> PluginLoading;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when plugin gets loaded and initialized.
|
||||
/// </summary>
|
||||
API_EVENT() static Delegate<Plugin*> PluginLoaded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs before unloading plugin.
|
||||
/// </summary>
|
||||
API_EVENT() static Delegate<Plugin*> PluginUnloading;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when plugin gets unloaded. It should not be used anymore.
|
||||
/// </summary>
|
||||
API_EVENT() static Delegate<Plugin*> PluginUnloaded;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when plugins collection gets edited (added or removed plugin).
|
||||
/// </summary>
|
||||
API_EVENT() static Action PluginsChanged;
|
||||
|
||||
public:
|
||||
/// <summary>
|
||||
/// Return the first plugin using the provided name.
|
||||
/// </summary>
|
||||
// <param name="name">The plugin name.</param>
|
||||
/// <returns>The plugin, or null if not loaded.</returns>
|
||||
API_FUNCTION() static Plugin* GetPlugin(const StringView& name);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first plugin of the provided type.
|
||||
/// </summary>
|
||||
/// <param name="type">Type of the plugin to search for. Includes any plugin base class derived from the type.</param>
|
||||
/// <returns>The plugin or null.</returns>
|
||||
API_FUNCTION() static Plugin* GetPlugin(API_PARAM(Attributes="TypeReference(typeof(Plugin))") const MClass* type);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the first plugin of the provided type.
|
||||
/// </summary>
|
||||
/// <returns>The plugin or null.</returns>
|
||||
template<typename T>
|
||||
FORCE_INLINE static T* GetPlugin()
|
||||
{
|
||||
return (T*)GetPlugin(T::GetStaticClass());
|
||||
}
|
||||
|
||||
private:
|
||||
#if USE_EDITOR
|
||||
// Internal bindings
|
||||
API_FUNCTION(NoProxy) static void InitializeGamePlugins();
|
||||
API_FUNCTION(NoProxy) static void DeinitializeGamePlugins();
|
||||
#endif
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "Engine/Platform/File.h"
|
||||
#include "Engine/Debug/DebugLog.h"
|
||||
#if USE_EDITOR
|
||||
#include "Engine/Level/Level.h"
|
||||
#include "Editor/Scripting/ScriptsBuilder.h"
|
||||
#endif
|
||||
#include "ManagedCLR/MAssembly.h"
|
||||
@@ -20,7 +21,6 @@
|
||||
#include "ManagedCLR/MDomain.h"
|
||||
#include "ManagedCLR/MCore.h"
|
||||
#include "MException.h"
|
||||
#include "Engine/Level/Level.h"
|
||||
#include "Engine/Core/ObjectsRemovalService.h"
|
||||
#include "Engine/Core/Types/TimeSpan.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
@@ -40,7 +40,6 @@ extern void registerFlaxEngineInternalCalls();
|
||||
class ScriptingService : public EngineService
|
||||
{
|
||||
public:
|
||||
|
||||
ScriptingService()
|
||||
: EngineService(TEXT("Scripting"), -20)
|
||||
{
|
||||
@@ -733,6 +732,48 @@ ScriptingTypeHandle Scripting::FindScriptingType(const StringAnsiView& fullname)
|
||||
return ScriptingTypeHandle();
|
||||
}
|
||||
|
||||
ScriptingObject* Scripting::NewObject(const MClass* type)
|
||||
{
|
||||
if (type == nullptr)
|
||||
{
|
||||
LOG(Error, "Invalid type.");
|
||||
return nullptr;
|
||||
}
|
||||
MonoClass* typeClass = type->GetNative();
|
||||
|
||||
#if USE_MONO
|
||||
// Get the assembly with that class
|
||||
auto module = ManagedBinaryModule::FindModule(typeClass);
|
||||
if (module == nullptr)
|
||||
{
|
||||
LOG(Error, "Cannot find scripting assembly for type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Try to find the scripting type for this class
|
||||
int32 typeIndex;
|
||||
if (!module->ClassToTypeIndex.TryGet(typeClass, typeIndex))
|
||||
{
|
||||
LOG(Error, "Cannot spawn objects of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
|
||||
return nullptr;
|
||||
}
|
||||
const ScriptingType& scriptingType = module->Types[typeIndex];
|
||||
|
||||
// Create unmanaged object
|
||||
const ScriptingObjectSpawnParams params(Guid::New(), ScriptingTypeHandle(module, typeIndex));
|
||||
ScriptingObject* obj = scriptingType.Script.Spawn(params);
|
||||
if (obj == nullptr)
|
||||
{
|
||||
LOG(Error, "Failed to spawn object of type \'{0}.{1}\'.", String(mono_class_get_namespace(typeClass)), String(mono_class_get_name(typeClass)));
|
||||
return nullptr;
|
||||
}
|
||||
#else
|
||||
LOG(Error, "Not supported object creation from Managed class.");
|
||||
#endif
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
FLAXENGINE_API ScriptingObject* FindObject(const Guid& id, MClass* type)
|
||||
{
|
||||
return Scripting::FindObject(id, type);
|
||||
|
||||
@@ -109,6 +109,13 @@ public:
|
||||
/// <returns>The scripting type or invalid type if missing.</returns>
|
||||
static ScriptingTypeHandle FindScriptingType(const StringAnsiView& fullname);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the given class object (native construction).
|
||||
/// </summary>
|
||||
/// <param name="type">The Managed type class.</param>
|
||||
/// <returns>The created object or null if failed.</returns>
|
||||
static ScriptingObject* NewObject(const MClass* type);
|
||||
|
||||
public:
|
||||
|
||||
typedef Dictionary<Guid, Guid, HeapAllocation> IdsMappingTable;
|
||||
|
||||
@@ -319,6 +319,7 @@ struct FLAXENGINE_API ScriptingType
|
||||
void SetupScriptObjectVTable(void* object, ScriptingTypeHandle baseTypeHandle, int32 wrapperIndex);
|
||||
void HackObjectVTable(void* object, ScriptingTypeHandle baseTypeHandle, int32 wrapperIndex);
|
||||
String ToString() const;
|
||||
StringAnsiView GetName() const;
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -418,6 +418,9 @@ namespace Flax.Build.Bindings
|
||||
case "CultureInfo":
|
||||
type = "void*";
|
||||
return "MUtils::ToManaged({0})";
|
||||
case "Version":
|
||||
type = "MonoObject*";
|
||||
return "MUtils::ToManaged({0})";
|
||||
default:
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
@@ -590,6 +593,9 @@ namespace Flax.Build.Bindings
|
||||
case "CultureInfo":
|
||||
type = "void*";
|
||||
return "MUtils::ToNative({0})";
|
||||
case "Version":
|
||||
type = "MonoObject*";
|
||||
return "MUtils::ToNative({0})";
|
||||
default:
|
||||
// Object reference property
|
||||
if ((typeInfo.Type == "ScriptingObjectReference" ||
|
||||
|
||||
Reference in New Issue
Block a user