fix(serialization): load failure on hardened yaml-cpp + flow-style arrays
yaml-cpp master hardens zombie nodes: operator=, size(), Type() and chained operator[] all throw InvalidNode instead of silently passing. Storing per-component nodes via Node::operator= threw for every key that was absent, so all 7 entities were skipped on load (0 loaded). Reads are now level-by-level guarded (copy-init + IsDefined), which only uses the safe surface (as<T>(fallback), begin(), IsDefined). Save side switched from node-tree streaming to a manual Emitter: vector/quat fields emit as single-line flow arrays ([0, 1.2, -6]) and model refs as inline maps, with 9-digit float precision for lossless float32 round-trips. Verified offline against the previously saved scene: 7/7 entities parse with correct component counts; emitter output round-trips.
This commit is contained in:
@@ -1,10 +1,18 @@
|
|||||||
//
|
//
|
||||||
// Created by atdunbg on 2026/10/3.
|
// Created by atdunbg on 2026/10/3.
|
||||||
//
|
//
|
||||||
// SceneSerializer:场景 ↔ YAML。结构见头文件注释与计划 v3。
|
// SceneSerializer:场景 ↔ YAML。结构见头文件注释。
|
||||||
//
|
//
|
||||||
// 原子性:Deserialize 先把整个文件解析进中间结构(逐实体容错),
|
// 写端:手动 Emitter 逐键输出(短集合用 Flow 单行数组/内联 map,
|
||||||
// 全部成功才 scene.Clear() 换血重建——解析失败不动现场。
|
// 浮点 9 位精度保证 float32 无损往返)。
|
||||||
|
// 读端:yaml-cpp 新版对"僵尸节点"(缺失键的返回值)硬化——operator=、
|
||||||
|
// size()、Type()、链式 operator[] 一律抛 InvalidNode,只有 IsDefined/
|
||||||
|
// as<T>(fallback)/begin() 安全。因此读侧铁律:每层节点先
|
||||||
|
// `const Node n = parent["Key"]` 拷贝初始化 + `if (n)` 判空再访问,
|
||||||
|
// 绝不对可能缺失的键做赋值或链式下标。
|
||||||
|
//
|
||||||
|
// 原子性:Deserialize 先解析到中间结构(逐实体容错),全部成功才
|
||||||
|
// scene.Clear() 换血重建——解析失败不动现场。
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <Engine/Serialization/SceneSerializer.h>
|
#include <Engine/Serialization/SceneSerializer.h>
|
||||||
@@ -32,18 +40,33 @@ namespace Engine::Serialization {
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
// ---- 写出辅助:glm → 数组 ----
|
// ---- 写端辅助:Flow 单行数组(Position: [0, 1.2, -6])----
|
||||||
|
|
||||||
std::vector<f32> Vec3Arr(const glm::vec3& v) { return {v.x, v.y, v.z}; }
|
void EmitVec3(YAML::Emitter& e, const glm::vec3& v)
|
||||||
std::vector<f32> Vec4Arr(const glm::vec4& v) { return {v.x, v.y, v.z, v.w}; }
|
{
|
||||||
std::vector<f32> QuatArr(const glm::quat& q) { return {q.w, q.x, q.y, q.z}; }
|
e << YAML::Flow << YAML::BeginSeq << v.x << v.y << v.z
|
||||||
|
<< YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
// ---- 读入辅助:缺字段/类型错 → 默认值(as<T>(fallback) 语义)----
|
void EmitVec4(YAML::Emitter& e, const glm::vec4& v)
|
||||||
|
{
|
||||||
|
e << YAML::Flow << YAML::BeginSeq << v.x << v.y << v.z << v.w
|
||||||
|
<< YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitQuat(YAML::Emitter& e, const glm::quat& q)
|
||||||
|
{
|
||||||
|
e << YAML::Flow << YAML::BeginSeq << q.w << q.x << q.y << q.z
|
||||||
|
<< YAML::EndSeq;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 读端辅助:缺字段/类型错/僵尸节点 → 默认值 ----
|
||||||
|
|
||||||
glm::vec3 ReadVec3(const YAML::Node& n, const glm::vec3& def)
|
glm::vec3 ReadVec3(const YAML::Node& n, const glm::vec3& def)
|
||||||
{
|
{
|
||||||
if (!n || !n.IsSequence() || n.size() < 3) return def;
|
if (!n || !n.IsSequence() || n.size() < 3) return def;
|
||||||
return {n[0].as<f32>(def.x), n[1].as<f32>(def.y), n[2].as<f32>(def.z)};
|
return {n[0].as<f32>(def.x), n[1].as<f32>(def.y),
|
||||||
|
n[2].as<f32>(def.z)};
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec4 ReadVec4(const YAML::Node& n, const glm::vec4& def)
|
glm::vec4 ReadVec4(const YAML::Node& n, const glm::vec4& def)
|
||||||
@@ -144,103 +167,120 @@ namespace Engine::Serialization {
|
|||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 资产引用双写:{Guid, Path}(procedural 只有 Path,Guid=0 不写)
|
|
||||||
void WriteModelRef(YAML::Node& node, Assets::AssetManager& assets,
|
|
||||||
ModelRef ref)
|
|
||||||
{
|
|
||||||
const std::string& path = assets.Models().Path(ref);
|
|
||||||
if (path.empty()) {
|
|
||||||
ENGINE_WARN("SceneSerializer: entity has invalid model ref, "
|
|
||||||
"MeshRenderer skipped");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
YAML::Node m;
|
|
||||||
if (const u64 guid = assets.GetOrCreateGUID(path); guid != 0) {
|
|
||||||
m["Guid"] = guid;
|
|
||||||
}
|
|
||||||
m["Path"] = path;
|
|
||||||
node["Model"] = m;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- 中间结构:解析全部成功才碰 registry ----
|
// ---- 中间结构:解析全部成功才碰 registry ----
|
||||||
|
// comps 持 Components 节点(仅在键存在且为 map 时赋值——
|
||||||
|
// yaml-cpp 新版对僵尸节点做 operator= 会抛异常)
|
||||||
|
|
||||||
struct ParsedEntity
|
struct ParsedEntity
|
||||||
{
|
{
|
||||||
u64 uuid = 0;
|
u64 uuid = 0;
|
||||||
std::string name = "entity";
|
std::string name = "entity";
|
||||||
YAML::Node transform, meshRenderer, animation, camera, light,
|
YAML::Node comps; // 缺省 = Null(无组件)
|
||||||
rigidBody; // 未出现 = undefined
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void SerializeEntity(YAML::Node& out, Assets::AssetManager& assets,
|
// 写端:单实体 → Emitter(调用方已进入 Entities 序列)
|
||||||
const ECS::Registry& reg, entt::entity e)
|
void EmitEntity(YAML::Emitter& out, Assets::AssetManager& assets,
|
||||||
|
const ECS::Registry& reg, entt::entity e)
|
||||||
{
|
{
|
||||||
const auto& id = reg.get<ECS::IdComponent>(e);
|
const auto& id = reg.get<ECS::IdComponent>(e);
|
||||||
|
|
||||||
YAML::Node ent;
|
out << YAML::BeginMap;
|
||||||
ent["Entity"] = id.uuid.Value();
|
out << YAML::Key << "Entity" << YAML::Value << id.uuid.Value();
|
||||||
if (const auto* name = reg.try_get<ECS::NameComponent>(e)) {
|
if (const auto* name = reg.try_get<ECS::NameComponent>(e)) {
|
||||||
ent["Name"] = name->name;
|
out << YAML::Key << "Name" << YAML::Value << name->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
YAML::Node comps;
|
out << YAML::Key << "Components" << YAML::Value << YAML::BeginMap;
|
||||||
|
|
||||||
if (const auto* t = reg.try_get<ECS::TransformComponent>(e)) {
|
if (const auto* t = reg.try_get<ECS::TransformComponent>(e)) {
|
||||||
YAML::Node n;
|
out << YAML::Key << "Transform" << YAML::Value
|
||||||
n["Position"] = Vec3Arr(t->GetPosition());
|
<< YAML::BeginMap;
|
||||||
n["Rotation"] = QuatArr(t->GetRotationQuat()); // (w,x,y,z) 无损
|
out << YAML::Key << "Position" << YAML::Value;
|
||||||
n["Scale"] = Vec3Arr(t->GetScale());
|
EmitVec3(out, t->GetPosition());
|
||||||
comps["Transform"] = n;
|
out << YAML::Key << "Rotation" << YAML::Value;
|
||||||
|
EmitQuat(out, t->GetRotationQuat()); // (w,x,y,z) 无损
|
||||||
|
out << YAML::Key << "Scale" << YAML::Value;
|
||||||
|
EmitVec3(out, t->GetScale());
|
||||||
|
out << YAML::EndMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto* mr = reg.try_get<ECS::MeshRendererComponent>(e)) {
|
if (const auto* mr = reg.try_get<ECS::MeshRendererComponent>(e)) {
|
||||||
YAML::Node n;
|
// ModelRef → {Guid, Path}:Path 反查为空 = 无效引用,跳过
|
||||||
WriteModelRef(n, assets, mr->model);
|
const std::string& path = assets.Models().Path(mr->model);
|
||||||
if (const YAML::Node m = n["Model"]) comps["MeshRenderer"] = n;
|
if (!path.empty()) {
|
||||||
|
out << YAML::Key << "MeshRenderer" << YAML::Value
|
||||||
|
<< YAML::BeginMap;
|
||||||
|
out << YAML::Key << "Model" << YAML::Value << YAML::Flow
|
||||||
|
<< YAML::BeginMap;
|
||||||
|
if (const u64 guid = assets.GetOrCreateGUID(path);
|
||||||
|
guid != 0) {
|
||||||
|
out << YAML::Key << "Guid" << YAML::Value << guid;
|
||||||
|
}
|
||||||
|
out << YAML::Key << "Path" << YAML::Value << path;
|
||||||
|
out << YAML::EndMap; // Model(flow)
|
||||||
|
out << YAML::EndMap; // MeshRenderer
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ENGINE_WARN("SceneSerializer: entity has invalid model "
|
||||||
|
"ref, MeshRenderer skipped");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto* a = reg.try_get<ECS::AnimationComponent>(e)) {
|
if (const auto* a = reg.try_get<ECS::AnimationComponent>(e)) {
|
||||||
YAML::Node n;
|
out << YAML::Key << "Animation" << YAML::Value << YAML::Flow
|
||||||
n["ClipIndex"] = a->clipIndex;
|
<< YAML::BeginMap;
|
||||||
n["Playing"] = a->playing;
|
out << YAML::Key << "ClipIndex" << YAML::Value << a->clipIndex;
|
||||||
n["Loop"] = a->loop;
|
out << YAML::Key << "Playing" << YAML::Value << a->playing;
|
||||||
n["Speed"] = a->speed; // fade*/time 是运行态,不存
|
out << YAML::Key << "Loop" << YAML::Value << a->loop;
|
||||||
comps["Animation"] = n;
|
out << YAML::Key << "Speed" << YAML::Value << a->speed;
|
||||||
|
out << YAML::EndMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto* c = reg.try_get<ECS::CameraComponent>(e)) {
|
if (const auto* c = reg.try_get<ECS::CameraComponent>(e)) {
|
||||||
YAML::Node n;
|
out << YAML::Key << "Camera" << YAML::Value << YAML::Flow
|
||||||
n["Primary"] = c->primary; // 相机不存投影参数(调用方传入)
|
<< YAML::BeginMap;
|
||||||
comps["Camera"] = n;
|
out << YAML::Key << "Primary" << YAML::Value << c->primary;
|
||||||
|
out << YAML::EndMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto* l = reg.try_get<ECS::LightComponent>(e)) {
|
if (const auto* l = reg.try_get<ECS::LightComponent>(e)) {
|
||||||
YAML::Node n;
|
out << YAML::Key << "Light" << YAML::Value << YAML::BeginMap;
|
||||||
n["Type"] = static_cast<u8>(l->type);
|
out << YAML::Key << "Type" << YAML::Value
|
||||||
n["Direction"] = Vec3Arr(l->direction);
|
<< static_cast<int>(l->type);
|
||||||
n["Color"] = Vec4Arr(l->color);
|
out << YAML::Key << "Direction" << YAML::Value;
|
||||||
n["Radius"] = l->radius;
|
EmitVec3(out, l->direction);
|
||||||
n["CastShadow"] = l->castShadow;
|
out << YAML::Key << "Color" << YAML::Value;
|
||||||
comps["Light"] = n;
|
EmitVec4(out, l->color);
|
||||||
|
out << YAML::Key << "Radius" << YAML::Value << l->radius;
|
||||||
|
out << YAML::Key << "CastShadow" << YAML::Value
|
||||||
|
<< l->castShadow;
|
||||||
|
out << YAML::EndMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const auto* rb = reg.try_get<ECS::RigidBodyComponent>(e)) {
|
if (const auto* rb = reg.try_get<ECS::RigidBodyComponent>(e)) {
|
||||||
YAML::Node n;
|
out << YAML::Key << "RigidBody" << YAML::Value
|
||||||
n["Type"] = static_cast<u8>(rb->type);
|
<< YAML::BeginMap;
|
||||||
n["Collider"] = static_cast<u8>(rb->collider);
|
out << YAML::Key << "Type" << YAML::Value
|
||||||
n["BoxHalfExtents"] = Vec3Arr(rb->boxHalfExtents);
|
<< static_cast<int>(rb->type);
|
||||||
n["SphereRadius"] = rb->sphereRadius;
|
out << YAML::Key << "Collider" << YAML::Value
|
||||||
n["Mass"] = rb->mass;
|
<< static_cast<int>(rb->collider);
|
||||||
n["GravityScale"] = rb->gravityScale;
|
out << YAML::Key << "BoxHalfExtents" << YAML::Value;
|
||||||
n["Friction"] = rb->friction;
|
EmitVec3(out, rb->boxHalfExtents);
|
||||||
n["Restitution"] = rb->restitution;
|
out << YAML::Key << "SphereRadius" << YAML::Value
|
||||||
n["IsSensor"] = rb->isSensor;
|
<< rb->sphereRadius;
|
||||||
|
out << YAML::Key << "Mass" << YAML::Value << rb->mass;
|
||||||
|
out << YAML::Key << "GravityScale" << YAML::Value
|
||||||
|
<< rb->gravityScale;
|
||||||
|
out << YAML::Key << "Friction" << YAML::Value << rb->friction;
|
||||||
|
out << YAML::Key << "Restitution" << YAML::Value
|
||||||
|
<< rb->restitution;
|
||||||
|
out << YAML::Key << "IsSensor" << YAML::Value << rb->isSensor;
|
||||||
// bodyId/bodyValid/velocity 由 PhysicsWorld 对账重建,不存
|
// bodyId/bodyValid/velocity 由 PhysicsWorld 对账重建,不存
|
||||||
comps["RigidBody"] = n;
|
out << YAML::EndMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (comps.size() > 0) ent["Components"] = comps;
|
out << YAML::EndMap; // Components
|
||||||
out.push_back(ent);
|
out << YAML::EndMap; // Entity
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -253,35 +293,50 @@ namespace Engine::Serialization {
|
|||||||
const std::string& environmentPath)
|
const std::string& environmentPath)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
YAML::Node root;
|
// float32 无损往返需 9 位有效数字(std::numeric_limits
|
||||||
root["Scene"] = std::filesystem::path(outPath).stem().string();
|
// <float>::max_digits10)
|
||||||
root["Version"] = kSceneVersion;
|
YAML::Emitter out;
|
||||||
|
out.SetFloatPrecision(9);
|
||||||
|
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "Scene" << YAML::Value
|
||||||
|
<< std::filesystem::path(outPath).stem().string();
|
||||||
|
out << YAML::Key << "Version" << YAML::Value << kSceneVersion;
|
||||||
if (!environmentPath.empty()) {
|
if (!environmentPath.empty()) {
|
||||||
root["Environment"] = environmentPath;
|
out << YAML::Key << "Environment" << YAML::Value
|
||||||
|
<< environmentPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& s = scene.GetSettings();
|
const auto& s = scene.GetSettings();
|
||||||
YAML::Node st;
|
out << YAML::Key << "Settings" << YAML::Value << YAML::BeginMap;
|
||||||
st["ClearColor"] = Vec4Arr(s.ClearColor);
|
out << YAML::Key << "ClearColor" << YAML::Value;
|
||||||
st["AmbientColor"] = Vec4Arr(s.AmbientColor);
|
EmitVec4(out, s.ClearColor);
|
||||||
st["DrawSkybox"] = s.DrawSkybox;
|
out << YAML::Key << "AmbientColor" << YAML::Value;
|
||||||
root["Settings"] = st;
|
EmitVec4(out, s.AmbientColor);
|
||||||
|
out << YAML::Key << "DrawSkybox" << YAML::Value << s.DrawSkybox;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
YAML::Node entities(YAML::NodeType::Sequence);
|
out << YAML::Key << "Entities" << YAML::Value << YAML::BeginSeq;
|
||||||
const ECS::Registry& reg = scene.GetRegistry();
|
const ECS::Registry& reg = scene.GetRegistry();
|
||||||
reg.view<ECS::IdComponent>().each(
|
reg.view<ECS::IdComponent>().each(
|
||||||
[&](entt::entity e, const ECS::IdComponent&) {
|
[&](entt::entity e, const ECS::IdComponent&) {
|
||||||
SerializeEntity(entities, assets, reg, e);
|
EmitEntity(out, assets, reg, e);
|
||||||
});
|
});
|
||||||
root["Entities"] = entities;
|
out << YAML::EndSeq;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
|
||||||
std::ofstream out(outPath, std::ios::trunc);
|
if (!out.good()) {
|
||||||
if (!out) {
|
ENGINE_ERROR("SceneSerializer: emit failed: {}", out.GetLastError());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream file(outPath, std::ios::trunc);
|
||||||
|
if (!file) {
|
||||||
ENGINE_ERROR("SceneSerializer: cannot open '{}' for write",
|
ENGINE_ERROR("SceneSerializer: cannot open '{}' for write",
|
||||||
outPath);
|
outPath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
out << root;
|
file << out.c_str();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
catch (const YAML::Exception& e) {
|
catch (const YAML::Exception& e) {
|
||||||
@@ -326,6 +381,7 @@ namespace Engine::Serialization {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 僵尸节点安全:as<T>(fallback) 对缺失键返回 fallback
|
||||||
outEnvironmentPath = root["Environment"].as<std::string>("");
|
outEnvironmentPath = root["Environment"].as<std::string>("");
|
||||||
|
|
||||||
if (const YAML::Node st = root["Settings"]; st && st.IsMap()) {
|
if (const YAML::Node st = root["Settings"]; st && st.IsMap()) {
|
||||||
@@ -339,7 +395,7 @@ namespace Engine::Serialization {
|
|||||||
std::vector<ParsedEntity> parsed;
|
std::vector<ParsedEntity> parsed;
|
||||||
|
|
||||||
const YAML::Node entities = root["Entities"];
|
const YAML::Node entities = root["Entities"];
|
||||||
if (entities.IsSequence()) {
|
if (entities && entities.IsSequence()) {
|
||||||
parsed.reserve(entities.size());
|
parsed.reserve(entities.size());
|
||||||
for (const auto& e : entities) {
|
for (const auto& e : entities) {
|
||||||
try {
|
try {
|
||||||
@@ -348,13 +404,8 @@ namespace Engine::Serialization {
|
|||||||
pe.name = e["Name"].as<std::string>(pe.name);
|
pe.name = e["Name"].as<std::string>(pe.name);
|
||||||
if (const YAML::Node comps = e["Components"];
|
if (const YAML::Node comps = e["Components"];
|
||||||
comps && comps.IsMap()) {
|
comps && comps.IsMap()) {
|
||||||
pe.transform = comps["Transform"];
|
// 仅在 rhs 有效时赋值(僵尸节点 operator= 会抛)
|
||||||
pe.meshRenderer = comps["MeshRenderer"];
|
pe.comps = comps;
|
||||||
pe.animation = comps["Animation"];
|
|
||||||
pe.camera = comps["Camera"];
|
|
||||||
pe.light = comps["Light"];
|
|
||||||
pe.rigidBody = comps["RigidBody"];
|
|
||||||
// 未识别的组件键自然跳过(前向兼容)
|
|
||||||
}
|
}
|
||||||
parsed.push_back(std::move(pe));
|
parsed.push_back(std::move(pe));
|
||||||
}
|
}
|
||||||
@@ -380,32 +431,34 @@ namespace Engine::Serialization {
|
|||||||
}
|
}
|
||||||
handle.GetComponent<ECS::IdComponent>().uuid = UUID{uuid};
|
handle.GetComponent<ECS::IdComponent>().uuid = UUID{uuid};
|
||||||
|
|
||||||
if (pe.transform) {
|
const YAML::Node comps = pe.comps; // 拷贝初始化,缺省 Null
|
||||||
const YAML::Node n = pe.transform;
|
|
||||||
|
if (const YAML::Node n = comps["Transform"]) {
|
||||||
auto& t = handle.GetComponent<ECS::TransformComponent>();
|
auto& t = handle.GetComponent<ECS::TransformComponent>();
|
||||||
t.SetPosition(ReadVec3(n["Position"], t.GetPosition()));
|
t.SetPosition(ReadVec3(n["Position"], t.GetPosition()));
|
||||||
t.SetRotationQuat(ReadQuat(n["Rotation"]));
|
t.SetRotationQuat(ReadQuat(n["Rotation"]));
|
||||||
t.SetScale(ReadVec3(n["Scale"], t.GetScale()));
|
t.SetScale(ReadVec3(n["Scale"], t.GetScale()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pe.meshRenderer) {
|
if (const YAML::Node n = comps["MeshRenderer"]) {
|
||||||
const YAML::Node n = pe.meshRenderer;
|
if (const YAML::Node m = n["Model"]) {
|
||||||
const u64 guid = n["Model"]["Guid"].as<u64>(0);
|
const u64 guid = m["Guid"].as<u64>(0);
|
||||||
const auto path = n["Model"]["Path"].as<std::string>("");
|
const auto path = m["Path"].as<std::string>("");
|
||||||
if (ModelRef ref = ResolveModel(assets, guid, path);
|
if (ModelRef ref = ResolveModel(assets, guid, path);
|
||||||
ref.Valid()) {
|
ref.Valid()) {
|
||||||
handle.AddComponent<ECS::MeshRendererComponent>(
|
handle.AddComponent<ECS::MeshRendererComponent>(
|
||||||
ECS::MeshRendererComponent{ref});
|
ECS::MeshRendererComponent{ref});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ENGINE_WARN("SceneSerializer: model unresolved "
|
ENGINE_WARN("SceneSerializer: model unresolved "
|
||||||
"(guid={}, path='{}'), MeshRenderer skipped",
|
"(guid={}, path='{}'), MeshRenderer "
|
||||||
guid, path);
|
"skipped",
|
||||||
|
guid, path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pe.animation) {
|
if (const YAML::Node n = comps["Animation"]) {
|
||||||
const YAML::Node n = pe.animation;
|
|
||||||
auto& a = handle.AddComponent<ECS::AnimationComponent>();
|
auto& a = handle.AddComponent<ECS::AnimationComponent>();
|
||||||
a.clipIndex = n["ClipIndex"].as<int>(a.clipIndex);
|
a.clipIndex = n["ClipIndex"].as<int>(a.clipIndex);
|
||||||
a.playing = n["Playing"].as<bool>(a.playing);
|
a.playing = n["Playing"].as<bool>(a.playing);
|
||||||
@@ -413,16 +466,15 @@ namespace Engine::Serialization {
|
|||||||
a.speed = n["Speed"].as<f32>(a.speed);
|
a.speed = n["Speed"].as<f32>(a.speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pe.camera) {
|
if (const YAML::Node n = comps["Camera"]) {
|
||||||
const YAML::Node n = pe.camera;
|
|
||||||
auto& c = handle.AddComponent<ECS::CameraComponent>();
|
auto& c = handle.AddComponent<ECS::CameraComponent>();
|
||||||
c.primary = n["Primary"].as<bool>(false);
|
c.primary = n["Primary"].as<bool>(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pe.light) {
|
if (const YAML::Node n = comps["Light"]) {
|
||||||
const YAML::Node n = pe.light;
|
|
||||||
auto& l = handle.AddComponent<ECS::LightComponent>();
|
auto& l = handle.AddComponent<ECS::LightComponent>();
|
||||||
if (const u8 type = n["Type"].as<u8>(0); type <= 1) {
|
if (const int type = n["Type"].as<int>(0); type >= 0 &&
|
||||||
|
type <= 1) {
|
||||||
l.type = static_cast<ECS::LightComponent::Type>(type);
|
l.type = static_cast<ECS::LightComponent::Type>(type);
|
||||||
}
|
}
|
||||||
l.direction = ReadVec3(n["Direction"], l.direction);
|
l.direction = ReadVec3(n["Direction"], l.direction);
|
||||||
@@ -431,14 +483,15 @@ namespace Engine::Serialization {
|
|||||||
l.castShadow = n["CastShadow"].as<bool>(l.castShadow);
|
l.castShadow = n["CastShadow"].as<bool>(l.castShadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pe.rigidBody) {
|
if (const YAML::Node n = comps["RigidBody"]) {
|
||||||
const YAML::Node n = pe.rigidBody;
|
|
||||||
auto& rb = handle.AddComponent<ECS::RigidBodyComponent>();
|
auto& rb = handle.AddComponent<ECS::RigidBodyComponent>();
|
||||||
if (const u8 type = n["Type"].as<u8>(0); type <= 2) {
|
if (const int type = n["Type"].as<int>(0);
|
||||||
rb.type = static_cast<ECS::RigidBodyComponent::BodyType>(
|
type >= 0 && type <= 2) {
|
||||||
type);
|
rb.type =
|
||||||
|
static_cast<ECS::RigidBodyComponent::BodyType>(type);
|
||||||
}
|
}
|
||||||
if (const u8 col = n["Collider"].as<u8>(0); col <= 2) {
|
if (const int col = n["Collider"].as<int>(0);
|
||||||
|
col >= 0 && col <= 2) {
|
||||||
rb.collider =
|
rb.collider =
|
||||||
static_cast<ECS::RigidBodyComponent::ColliderType>(
|
static_cast<ECS::RigidBodyComponent::ColliderType>(
|
||||||
col);
|
col);
|
||||||
|
|||||||
Reference in New Issue
Block a user