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:
@@ -172,14 +172,31 @@ namespace Engine
|
||||
|
||||
AssetCache<Model>& Models() { return m_Models; }
|
||||
|
||||
// ---- 资产 GUID 注册表(UE AssetRegistry 模式:中央注册表)----
|
||||
// 磁盘路径资产持久映射 GUID→路径(存 assets/asset_registry.yaml),
|
||||
// 场景文件以 GUID 为主键引用资产——重命名/移动资产不断引用,
|
||||
// Path 仅作人工可读提示与解析兜底。procedural:// 伪路径(参数
|
||||
// 确定性生成,无需稳定身份)不参与
|
||||
// 查询/分配(新路径分配 GUID 并立即持久化,崩溃安全)
|
||||
u64 GetOrCreateGUID(const std::string& path);
|
||||
// GUID → 路径;未登记返回空串
|
||||
std::string ResolveGUID(u64 guid) const;
|
||||
|
||||
// 后续扩展点:TextureHandle / MaterialHandle / ShaderHandle
|
||||
// 各自一个 AssetCache<T> + 便捷方法,模式与 Model 完全一致。
|
||||
|
||||
private:
|
||||
void LoadGUIDRegistry();
|
||||
void SaveGUIDRegistry() const;
|
||||
|
||||
IAssetUploader& m_Uploader;
|
||||
|
||||
AssetCache<Model> m_Models;
|
||||
AssetCache<Cubemap> m_Environments;
|
||||
|
||||
// GUID 注册表(双向);dirty 即时保存,无析构落盘依赖
|
||||
std::unordered_map<u64, std::string> m_GuidToPath;
|
||||
std::unordered_map<std::string, u64> m_PathToGuid;
|
||||
};
|
||||
} // namespace Assets
|
||||
} // namespace Engine
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace Engine::ECS {
|
||||
bool DrawSkybox = true;
|
||||
};
|
||||
Settings& GetSettings() { return m_Settings; }
|
||||
const Settings& GetSettings() const { return m_Settings; } // 序列化只读
|
||||
|
||||
// ---- 实体 ----
|
||||
|
||||
@@ -54,6 +55,15 @@ namespace Engine::ECS {
|
||||
void DestroyEntity(Entity e); // 延迟:帧尾统一销毁
|
||||
void FlushDestroyQueue(); // 每帧末尾由 Application 调用
|
||||
|
||||
// 整场景换血(序列化加载):立即销毁全部实体并清空延迟队列。
|
||||
// 仅用于"校验通过后的原子替换"——调用方持有的 Entity/EntityHandle
|
||||
// 全部悬空,必须自行重解析(GetEntityHandle 可从裸 entity 重建)
|
||||
void Clear();
|
||||
|
||||
// 裸 entity → 句柄表皮(EntityHandle 构造私有 + friend Scene;
|
||||
// 序列化加载后应用层重解析悬空句柄用)。无效 entity 返回空句柄
|
||||
EntityHandle GetEntityHandle(Entity e);
|
||||
|
||||
// 帧循环统一重算脏 transform 的 world 矩阵(UE transform-update
|
||||
// 阶段模式)——由 Application 在 OnUpdate 之后、渲染之前调用,
|
||||
// 用户代码永远不需要手动 Compose
|
||||
@@ -64,6 +74,7 @@ namespace Engine::ECS {
|
||||
Entity FindEntityByUUID(UUID uuid);
|
||||
|
||||
Registry& GetRegistry() { return m_Registry; }
|
||||
const Registry& GetRegistry() const { return m_Registry; } // 序列化等只读遍历
|
||||
|
||||
// ---- 组件便捷接口(转发 entt)----
|
||||
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
//
|
||||
// Created by atdunbg on 2026/10/3.
|
||||
//
|
||||
// SceneSerializer:场景 → YAML 文件的双向转换(Unity 场景 YAML 同构简化)。
|
||||
//
|
||||
// 参照系(定案):Unity 的场景 YAML 结构 + UE AssetRegistry 式中央
|
||||
// GUID 注册表(AssetManager 维护,存 assets/asset_registry.yaml)。
|
||||
// 场景内资产引用双写 {Guid, Path}:GUID 是主键(重命名/移动资产不断
|
||||
// 引用),Path 是人工可读提示 + 注册表缺失时的解析兜底。
|
||||
//
|
||||
// 引擎层身份:本类不感知编辑器(kEnvPaths 表)与渲染器——
|
||||
// environmentPath 以普通字符串经参数进出,消费方(编辑器/游戏运行时)
|
||||
// 自行解释。一套 API 服务两个消费者:编辑器 File 菜单 与
|
||||
// 游戏运行时动态加载,不存在"另一套序列化"。
|
||||
//
|
||||
// 前向兼容(Prefab 路线预留):
|
||||
// - 场景 = 实体节点列表,Prefab 复用同一套实体读写函数
|
||||
// - Version 闸:高版本文件拒载并 WARN,低版本宽容
|
||||
// - 未知组件名跳过(Unity 语义:新版场景在旧版引擎打开可玩)
|
||||
// - UUID 重复 → 重新生成(即 Prefab 实例化的 ID 重映射)
|
||||
//
|
||||
|
||||
#ifndef HELLOVULKAN_SCENESERIALIZER_H
|
||||
#define HELLOVULKAN_SCENESERIALIZER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Engine::ECS { class Scene; }
|
||||
namespace Engine::Assets { class AssetManager; }
|
||||
|
||||
namespace Engine::Serialization {
|
||||
|
||||
// 当前场景文件格式版本(字段/结构变更时递增)
|
||||
inline constexpr int kSceneVersion = 1;
|
||||
|
||||
class SceneSerializer {
|
||||
public:
|
||||
// ---- 保存 ----
|
||||
// scene 序列化到 outPath(YAML)。environmentPath 可空(不写
|
||||
// Environment 字段)。失败(无法写文件)返回 false。
|
||||
static bool Serialize(const ECS::Scene& scene,
|
||||
Assets::AssetManager& assets,
|
||||
const std::string& outPath,
|
||||
const std::string& environmentPath = {});
|
||||
|
||||
// ---- 加载 ----
|
||||
// 原子换血:先解析校验到中间结构,全部成功才 scene.Clear() 重建
|
||||
//(解析失败不动现场)。成功时 outEnvironmentPath 带回场景记录的
|
||||
// 环境路径(空 = 场景未带环境,消费方保持当前环境即可)。
|
||||
// 健壮性:单实体损坏跳过继续、缺字段取默认值、未知组件跳过、
|
||||
// UUID 重复重新生成、YAML 异常优雅报错。
|
||||
// 注意:调用方持有的 Entity/EntityHandle 在成功后全部悬空,
|
||||
// 必须重解析(Scene::GetEntityHandle / 按 UUID 查询)。
|
||||
static bool Deserialize(ECS::Scene& scene,
|
||||
Assets::AssetManager& assets,
|
||||
const std::string& inPath,
|
||||
std::string& outEnvironmentPath);
|
||||
};
|
||||
|
||||
} // namespace Engine::Serialization
|
||||
|
||||
#endif //HELLOVULKAN_SCENESERIALIZER_H
|
||||
Reference in New Issue
Block a user