serialization: scene save/load (Unity-style YAML + UE-style GUID registry)

Engine-layer SceneSerializer (yaml-cpp submodule): entities/components
to versioned YAML, atomic clear-and-rebuild on load with per-entity
fault tolerance, missing-field defaults, unknown-component skip and
UUID dedup. Asset references are {Guid, Path} pairs resolved through
the new AssetManager GUID registry (assets/asset_registry.yaml) with
path fallback; procedural:// pseudo-paths rebuild from parameters.
Editor File menu gets Save/Load Scene modals; app re-resolves stale
entity handles via onSceneLoaded callback.
This commit is contained in:
2026-10-03 14:47:02 +08:00
parent ffe33e9967
commit 007d175314
14 changed files with 867 additions and 1 deletions
+21
View File
@@ -201,6 +201,10 @@ namespace
void OnUpdate(const FrameTime& frameTime) override
{
// 加载过无相机实体的场景(或场景被清空):相机句柄悬空,
// 直接跳过本帧游戏逻辑(渲染仍以编辑器视角进行)
if (!m_Camera.IsAlive()) return;
// 相机(RMB 飞行 / MMB 焦点环绕 / 滚轮推拉;位姿读写实体
// Transform)。编辑器相机走真实轨:暂停(timeScale=0)时仍
// 可飞行观察。编辑器模式移动键需 RMB 按住(UE 语义:飞行时
@@ -268,6 +272,23 @@ namespace
ctx.app = this;
ctx.getEnvIndex = [this] { return m_EnvIndex; };
ctx.setEnvIndex = [this](int index) { m_EnvIndex = index; };
// 场景加载成功 → 沙盒侧悬空句柄重解析(registry 清场重建后
// m_Camera 等成员句柄全部失效,不重解析则下一帧必崩)
ctx.onSceneLoaded = [this] {
Scene& scene = GetScene();
m_Spinners.clear();
m_Gun = {};
m_Ground = {};
m_KeyLight = {};
entt::entity camEnt = entt::null;
scene.Each<CameraComponent>([&](entt::entity e,
CameraComponent& cc) {
if (cc.primary) camEnt = e;
});
m_Camera = scene.GetEntityHandle(camEnt); // 无效 → 空句柄
ENGINE_INFO("SandboxApp: scene state re-resolved (camera {})",
m_Camera.IsAlive() ? "found" : "missing");
};
// 继承原沙盒默认:初始暂停(StatsPanel 的 Pause Simulation 开关恢复)
Time::SetTimeScale(0.0f);
m_Editor->Init(ctx);