feat: expand editor scripting asset and viewport flow
This commit is contained in:
@@ -6,12 +6,18 @@
|
||||
#include "Core/EditorContext.h"
|
||||
#include "Core/EditorEvents.h"
|
||||
#include "Core/EventBus.h"
|
||||
#include "Scripting/EditorScriptAssemblyBuilder.h"
|
||||
#include "UI/BuiltInIcons.h"
|
||||
#include "Platform/Win32Utf8.h"
|
||||
#include "Platform/WindowsProcessDiagnostics.h"
|
||||
#include <XCEngine/Core/Asset/ResourceManager.h>
|
||||
#include <XCEngine/Debug/Logger.h>
|
||||
#include <XCEngine/Scripting/ScriptEngine.h>
|
||||
#ifdef XCENGINE_ENABLE_MONO_SCRIPTING
|
||||
#include <XCEngine/Scripting/Mono/MonoScriptRuntime.h>
|
||||
#endif
|
||||
#include <chrono>
|
||||
#include <filesystem>
|
||||
#include <windows.h>
|
||||
|
||||
namespace XCEngine {
|
||||
@@ -22,6 +28,123 @@ Application& Application::Get() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
void Application::InitializeScriptingRuntime(const std::string& projectPath) {
|
||||
ShutdownScriptingRuntime();
|
||||
|
||||
const std::filesystem::path assemblyDirectoryPath =
|
||||
std::filesystem::path(Platform::Utf8ToWide(projectPath)) / L"Library" / L"ScriptAssemblies";
|
||||
m_scriptRuntimeStatus.assemblyDirectory = Platform::WideToUtf8(assemblyDirectoryPath.wstring());
|
||||
|
||||
#ifdef XCENGINE_ENABLE_MONO_SCRIPTING
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
auto& logger = Debug::Logger::Get();
|
||||
const fs::path assemblyDirectory = assemblyDirectoryPath;
|
||||
m_scriptRuntimeStatus.backendEnabled = true;
|
||||
|
||||
::XCEngine::Scripting::MonoScriptRuntime::Settings settings;
|
||||
settings.assemblyDirectory = assemblyDirectory;
|
||||
settings.corlibDirectory = assemblyDirectory;
|
||||
settings.coreAssemblyPath = assemblyDirectory / L"XCEngine.ScriptCore.dll";
|
||||
settings.appAssemblyPath = assemblyDirectory / L"GameScripts.dll";
|
||||
|
||||
std::error_code ec;
|
||||
const bool hasCoreAssembly = fs::exists(settings.coreAssemblyPath, ec);
|
||||
ec.clear();
|
||||
const bool hasAppAssembly = fs::exists(settings.appAssemblyPath, ec);
|
||||
ec.clear();
|
||||
const bool hasCorlibAssembly = fs::exists(assemblyDirectory / L"mscorlib.dll", ec);
|
||||
m_scriptRuntimeStatus.assembliesFound = hasCoreAssembly && hasAppAssembly && hasCorlibAssembly;
|
||||
|
||||
if (!hasCoreAssembly || !hasAppAssembly || !hasCorlibAssembly) {
|
||||
m_scriptRuntimeStatus.statusMessage =
|
||||
"Script assemblies were not found in " + Platform::WideToUtf8(assemblyDirectory.wstring()) +
|
||||
". Script class discovery is disabled until the managed assemblies are built.";
|
||||
logger.Warning(Debug::LogCategory::Scripting, m_scriptRuntimeStatus.statusMessage.c_str());
|
||||
::XCEngine::Scripting::ScriptEngine::Get().SetRuntime(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto runtime = std::make_unique<::XCEngine::Scripting::MonoScriptRuntime>(settings);
|
||||
if (!runtime->Initialize()) {
|
||||
m_scriptRuntimeStatus.statusMessage =
|
||||
"Failed to initialize editor script runtime: " + runtime->GetLastError();
|
||||
logger.Warning(Debug::LogCategory::Scripting, m_scriptRuntimeStatus.statusMessage.c_str());
|
||||
::XCEngine::Scripting::ScriptEngine::Get().SetRuntime(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
::XCEngine::Scripting::ScriptEngine::Get().SetRuntime(runtime.get());
|
||||
m_scriptRuntimeStatus.runtimeLoaded = true;
|
||||
m_scriptRuntime = std::move(runtime);
|
||||
logger.Info(Debug::LogCategory::Scripting, "Editor script runtime initialized.");
|
||||
#else
|
||||
(void)projectPath;
|
||||
m_scriptRuntimeStatus.backendEnabled = false;
|
||||
m_scriptRuntimeStatus.statusMessage = "This editor build does not include Mono scripting support.";
|
||||
::XCEngine::Scripting::ScriptEngine::Get().SetRuntime(nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Application::ShutdownScriptingRuntime() {
|
||||
::XCEngine::Scripting::ScriptEngine::Get().OnRuntimeStop();
|
||||
::XCEngine::Scripting::ScriptEngine::Get().SetRuntime(nullptr);
|
||||
|
||||
#ifdef XCENGINE_ENABLE_MONO_SCRIPTING
|
||||
m_scriptRuntime.reset();
|
||||
#endif
|
||||
|
||||
m_scriptRuntimeStatus = {};
|
||||
}
|
||||
|
||||
bool Application::ReloadScriptingRuntime() {
|
||||
if (!m_editorContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& projectPath = m_editorContext->GetProjectPath();
|
||||
if (projectPath.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InitializeScriptingRuntime(projectPath);
|
||||
return m_scriptRuntimeStatus.runtimeLoaded;
|
||||
}
|
||||
|
||||
bool Application::RebuildScriptingAssemblies() {
|
||||
if (!m_editorContext) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::string& projectPath = m_editorContext->GetProjectPath();
|
||||
if (projectPath.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef XCENGINE_ENABLE_MONO_SCRIPTING
|
||||
auto& logger = Debug::Logger::Get();
|
||||
logger.Info(Debug::LogCategory::Scripting, "Rebuilding project script assemblies...");
|
||||
|
||||
// Release the currently loaded project assembly before invoking the compiler.
|
||||
// Otherwise GameScripts.dll can remain locked by the active Mono app domain.
|
||||
ShutdownScriptingRuntime();
|
||||
|
||||
const ::XCEngine::Editor::Scripting::EditorScriptAssemblyBuildResult buildResult =
|
||||
::XCEngine::Editor::Scripting::EditorScriptAssemblyBuilder::RebuildProjectAssemblies(projectPath);
|
||||
if (!buildResult.succeeded) {
|
||||
m_scriptRuntimeStatus.statusMessage = buildResult.message;
|
||||
logger.Error(Debug::LogCategory::Scripting, buildResult.message.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
logger.Info(Debug::LogCategory::Scripting, buildResult.message.c_str());
|
||||
return ReloadScriptingRuntime();
|
||||
#else
|
||||
m_scriptRuntimeStatus.statusMessage = "This editor build does not include Mono scripting support.";
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Application::InitializeWindowRenderer(HWND hwnd) {
|
||||
RECT clientRect = {};
|
||||
if (!GetClientRect(hwnd, &clientRect)) {
|
||||
@@ -150,6 +273,7 @@ bool Application::Initialize(HWND hwnd) {
|
||||
|
||||
logger.Info(Debug::LogCategory::General, "Initializing editor context...");
|
||||
InitializeEditorContext(projectRoot);
|
||||
InitializeScriptingRuntime(projectRoot);
|
||||
logger.Info(Debug::LogCategory::General, "Initializing ImGui backend...");
|
||||
InitializeImGui(hwnd);
|
||||
logger.Info(Debug::LogCategory::General, "Attaching editor layer...");
|
||||
@@ -171,6 +295,7 @@ void Application::Shutdown() {
|
||||
UI::ShutdownBuiltInIcons();
|
||||
m_imguiBackend.Shutdown();
|
||||
m_imguiSession.Shutdown();
|
||||
ShutdownScriptingRuntime();
|
||||
ShutdownEditorContext();
|
||||
if (m_resourceManagerInitialized) {
|
||||
::XCEngine::Resources::ResourceManager::Get().Shutdown();
|
||||
@@ -230,6 +355,7 @@ bool Application::SwitchProject(const std::string& projectPath) {
|
||||
logger.Info(Debug::LogCategory::General, infoMessage.c_str());
|
||||
|
||||
::XCEngine::Resources::ResourceManager::Get().SetResourceRoot(projectPath.c_str());
|
||||
InitializeScriptingRuntime(projectPath);
|
||||
|
||||
m_lastWindowTitle.clear();
|
||||
UpdateWindowTitle();
|
||||
|
||||
Reference in New Issue
Block a user