editor: explicit runtime path contract

This commit is contained in:
2026-04-28 14:49:41 +08:00
parent 0e506f21ec
commit cd166037bf
38 changed files with 210 additions and 129 deletions

View File

@@ -35,11 +35,48 @@ constexpr const wchar_t* kWindowTitle = L"Main Scene * - Main.xx - XCEngine Edit
constexpr DWORD kBorderlessWindowStyle = WS_POPUP | WS_THICKFRAME;
constexpr int kDefaultSmokeTestDurationSeconds = 12;
bool HasEditorRepoMarkers(const std::filesystem::path& root) {
return std::filesystem::exists(root / "editor" / "AGENTS.md") &&
bool HasEditorWorkspaceMarkers(const std::filesystem::path& root) {
return std::filesystem::exists(root / "CMakeLists.txt") &&
std::filesystem::exists(root / "editor" / "resources") &&
std::filesystem::exists(root / "project");
}
std::filesystem::path NormalizePath(const std::filesystem::path& path) {
std::error_code errorCode = {};
std::filesystem::path normalized =
std::filesystem::weakly_canonical(path, errorCode);
return errorCode
? path.lexically_normal()
: normalized.lexically_normal();
}
App::EditorRuntimePaths BuildEditorRuntimePaths(
const std::filesystem::path& workspaceRoot,
const std::filesystem::path& executableDirectory) {
App::EditorRuntimePaths paths = {};
paths.workspaceRoot = NormalizePath(workspaceRoot);
paths.executableRoot = NormalizePath(executableDirectory);
const std::filesystem::path sourceTreeResourceRoot =
paths.workspaceRoot / "editor" / "resources";
const std::filesystem::path packagedResourceRoot =
paths.executableRoot / "resources";
paths.resourceRoot = std::filesystem::exists(sourceTreeResourceRoot)
? NormalizePath(sourceTreeResourceRoot)
: NormalizePath(packagedResourceRoot);
const std::filesystem::path sourceTreeProjectRoot =
paths.workspaceRoot / "project";
const std::filesystem::path packagedProjectRoot =
paths.executableRoot / "project";
paths.projectRoot = std::filesystem::exists(sourceTreeProjectRoot)
? NormalizePath(sourceTreeProjectRoot)
: NormalizePath(packagedProjectRoot);
paths.captureRoot = NormalizePath(paths.executableRoot / "captures");
return paths;
}
void EnableDpiAwareness() {
const HMODULE user32 = GetModuleHandleW(L"user32.dll");
if (user32 != nullptr) {
@@ -118,7 +155,7 @@ namespace XCEngine::UI::Editor {
bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
m_hInstance = hInstance;
m_resourceService = std::make_unique<Host::Win32EditorResourceService>(m_hInstance);
m_repoRoot = ResolveRepoRootPath(m_resourceService->GetExecutableDirectory());
m_runtimePaths = ResolveRuntimePaths(m_resourceService->GetExecutableDirectory());
EnableDpiAwareness();
const std::filesystem::path logRoot = m_resourceService->GetExecutableDirectory() / "logs";
@@ -126,7 +163,7 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
SetUnhandledExceptionFilter(&Application::HandleUnhandledException);
AppendUIEditorRuntimeTrace("app", "initialize begin");
if (!m_editorContext->Initialize(m_repoRoot)) {
if (!m_editorContext->Initialize(m_runtimePaths)) {
AppendUIEditorRuntimeTrace(
"app",
"shell asset validation failed: " + m_editorContext->GetValidationMessage());
@@ -149,8 +186,7 @@ bool Application::Initialize(HINSTANCE hInstance, int nCmdShow) {
hostConfig.windowUserData = this;
m_windowHostRuntime = std::make_unique<App::EditorWindowHostRuntime>(
hostConfig,
m_repoRoot,
m_editorContext->GetShellAsset().captureRootPath);
m_runtimePaths);
m_renderRuntimeFactory =
std::make_unique<Host::D3D12EditorWindowRenderRuntimeFactory>();
App::EditorWorkspaceShellRuntimeFactory workspaceShellRuntimeFactory = []() {
@@ -270,18 +306,13 @@ void Application::Shutdown() {
ShutdownUIEditorRuntimeTrace();
}
std::filesystem::path Application::ResolveRepoRootPath(
App::EditorRuntimePaths Application::ResolveRuntimePaths(
const std::filesystem::path& executableDirectory) {
std::error_code errorCode = {};
std::filesystem::path current =
std::filesystem::weakly_canonical(executableDirectory, errorCode);
if (errorCode) {
current = executableDirectory.lexically_normal();
}
std::filesystem::path current = NormalizePath(executableDirectory);
while (!current.empty()) {
if (HasEditorRepoMarkers(current)) {
return current.lexically_normal();
if (HasEditorWorkspaceMarkers(current)) {
return BuildEditorRuntimePaths(current, executableDirectory);
}
const std::filesystem::path parent = current.parent_path();
@@ -291,7 +322,7 @@ std::filesystem::path Application::ResolveRepoRootPath(
current = parent;
}
return executableDirectory.lexically_normal();
return BuildEditorRuntimePaths(executableDirectory, executableDirectory);
}
LONG WINAPI Application::HandleUnhandledException(EXCEPTION_POINTERS* exceptionInfo) {