#include "MetaCoreScene/MetaCoreSceneSerializer.h" #include "MetaCoreFoundation/MetaCoreReflection.h" #include #include #include #include using json = nlohmann::json; namespace MetaCore { // 辅助方法:将 glm::vec3 序列化为 JSON 数组 [x, y, z] static json Vec3ToJson(const glm::vec3& vec) { return { vec.x, vec.y, vec.z }; } // 辅助方法:从 JSON 数组 [x, y, z] 反序列化出 glm::vec3 static glm::vec3 JsonToVec3(const json& j) { if (j.is_array() && j.size() >= 3) { return glm::vec3(j[0].get(), j[1].get(), j[2].get()); } return glm::vec3(0.0f); } // 辅助方法:将 MetaCoreAssetGuid 转换为 String,方便文本化存储 static std::string GuidToString(const MetaCoreAssetGuid& guid) { return guid.IsValid() ? guid.ToString() : ""; } // 辅助方法:从 String 反解析为 MetaCoreAssetGuid static MetaCoreAssetGuid StringToGuid(const std::string& str) { return str.empty() ? MetaCoreAssetGuid{} : MetaCoreAssetGuid::Parse(str).value_or(MetaCoreAssetGuid{}); } static char MetaCoreHexDigit(std::byte value) { constexpr char digits[] = "0123456789abcdef"; return digits[static_cast(value) & 0x0F]; } static std::string BytesToHexString(const std::vector& bytes) { std::string encoded; encoded.reserve(bytes.size() * 2U); for (std::byte byte : bytes) { encoded.push_back(MetaCoreHexDigit(byte >> 4)); encoded.push_back(MetaCoreHexDigit(byte)); } return encoded; } static int HexValue(char character) { if (character >= '0' && character <= '9') return character - '0'; if (character >= 'a' && character <= 'f') return 10 + character - 'a'; if (character >= 'A' && character <= 'F') return 10 + character - 'A'; return -1; } static std::vector HexStringToBytes(const std::string& encoded) { std::vector bytes; if (encoded.size() % 2U != 0U) { return bytes; } bytes.reserve(encoded.size() / 2U); for (std::size_t index = 0; index < encoded.size(); index += 2U) { const int high = HexValue(encoded[index]); const int low = HexValue(encoded[index + 1U]); if (high < 0 || low < 0) { bytes.clear(); return bytes; } bytes.push_back(static_cast((high << 4) | low)); } return bytes; } // 辅助方法:将单个 MetaCoreGameObjectData 转换为 json 格式 static json GameObjectDataToJson(const MetaCoreGameObjectData& obj, const MetaCoreTypeRegistry& registry) { json objJson = json::object(); const MetaCoreStructDescriptor* objDesc = registry.FindStruct(); if (!objDesc) return objJson; for (const auto& objField : objDesc->Fields) { if (objField.Name == "Id") { objJson["Id"] = obj.Id; } else if (objField.Name == "ParentId") { objJson["ParentId"] = obj.ParentId; } else if (objField.Name == "Name") { objJson["Name"] = obj.Name; } else if (objField.Name == "Transform") { const MetaCoreStructDescriptor* transDesc = registry.FindStruct(); if (transDesc) { json transJson = json::object(); for (const auto& transField : transDesc->Fields) { if (transField.Name == "Position") transJson["Position"] = Vec3ToJson(obj.Transform.Position); else if (transField.Name == "RotationEulerDegrees") transJson["RotationEulerDegrees"] = Vec3ToJson(obj.Transform.RotationEulerDegrees); else if (transField.Name == "Scale") transJson["Scale"] = Vec3ToJson(obj.Transform.Scale); } objJson["Transform"] = transJson; } } else if (objField.Name == "MeshRenderer" && obj.MeshRenderer.has_value()) { const MetaCoreStructDescriptor* meshDesc = registry.FindStruct(); if (meshDesc) { json meshJson = json::object(); const auto& mesh = obj.MeshRenderer.value(); for (const auto& meshField : meshDesc->Fields) { if (meshField.Name == "MeshSource") meshJson["MeshSource"] = static_cast(mesh.MeshSource); else if (meshField.Name == "BuiltinMesh") meshJson["BuiltinMesh"] = static_cast(mesh.BuiltinMesh); else if (meshField.Name == "MeshAssetGuid") meshJson["MeshAssetGuid"] = GuidToString(mesh.MeshAssetGuid); else if (meshField.Name == "MaterialAssetGuids") { json matGuids = json::array(); for (const auto& guid : mesh.MaterialAssetGuids) { matGuids.push_back(GuidToString(guid)); } meshJson["MaterialAssetGuids"] = matGuids; } else if (meshField.Name == "SourceModelAssetGuid") meshJson["SourceModelAssetGuid"] = GuidToString(mesh.SourceModelAssetGuid); else if (meshField.Name == "SourceModelPath") meshJson["SourceModelPath"] = mesh.SourceModelPath; else if (meshField.Name == "SourceNodePath") meshJson["SourceNodePath"] = mesh.SourceNodePath; else if (meshField.Name == "BaseColorTextureGuid") meshJson["BaseColorTextureGuid"] = GuidToString(mesh.BaseColorTextureGuid); else if (meshField.Name == "MetallicRoughnessTextureGuid") meshJson["MetallicRoughnessTextureGuid"] = GuidToString(mesh.MetallicRoughnessTextureGuid); else if (meshField.Name == "NormalTextureGuid") meshJson["NormalTextureGuid"] = GuidToString(mesh.NormalTextureGuid); else if (meshField.Name == "EmissiveTextureGuid") meshJson["EmissiveTextureGuid"] = GuidToString(mesh.EmissiveTextureGuid); else if (meshField.Name == "AoTextureGuid") meshJson["AoTextureGuid"] = GuidToString(mesh.AoTextureGuid); else if (meshField.Name == "BaseColorTexturePath") meshJson["BaseColorTexturePath"] = mesh.BaseColorTexturePath; else if (meshField.Name == "MetallicRoughnessTexturePath") meshJson["MetallicRoughnessTexturePath"] = mesh.MetallicRoughnessTexturePath; else if (meshField.Name == "NormalTexturePath") meshJson["NormalTexturePath"] = mesh.NormalTexturePath; else if (meshField.Name == "EmissiveTexturePath") meshJson["EmissiveTexturePath"] = mesh.EmissiveTexturePath; else if (meshField.Name == "AoTexturePath") meshJson["AoTexturePath"] = mesh.AoTexturePath; else if (meshField.Name == "DoubleSided") meshJson["DoubleSided"] = mesh.DoubleSided; else if (meshField.Name == "Metallic") meshJson["Metallic"] = mesh.Metallic; else if (meshField.Name == "Roughness") meshJson["Roughness"] = mesh.Roughness; else if (meshField.Name == "AlphaMode") meshJson["AlphaMode"] = static_cast(mesh.AlphaMode); else if (meshField.Name == "AlphaCutoff") meshJson["AlphaCutoff"] = mesh.AlphaCutoff; else if (meshField.Name == "EmissiveColor") meshJson["EmissiveColor"] = Vec3ToJson(mesh.EmissiveColor); else if (meshField.Name == "BaseColor") meshJson["BaseColor"] = Vec3ToJson(mesh.BaseColor); else if (meshField.Name == "ModelNodeIndex") meshJson["ModelNodeIndex"] = mesh.ModelNodeIndex; else if (meshField.Name == "SubMeshIndex") meshJson["SubMeshIndex"] = mesh.SubMeshIndex; else if (meshField.Name == "Visible") meshJson["Visible"] = mesh.Visible; } objJson["MeshRenderer"] = meshJson; } } else if (objField.Name == "Light" && obj.Light.has_value()) { const MetaCoreStructDescriptor* lightDesc = registry.FindStruct(); if (lightDesc) { json lightJson = json::object(); for (const auto& lightField : lightDesc->Fields) { if (lightField.Name == "Color") lightJson["Color"] = Vec3ToJson(obj.Light->Color); else if (lightField.Name == "Intensity") lightJson["Intensity"] = obj.Light->Intensity; } objJson["Light"] = lightJson; } } else if (objField.Name == "Camera" && obj.Camera.has_value()) { const MetaCoreStructDescriptor* camDesc = registry.FindStruct(); if (camDesc) { json camJson = json::object(); for (const auto& camField : camDesc->Fields) { if (camField.Name == "FieldOfViewDegrees") camJson["FieldOfViewDegrees"] = obj.Camera->FieldOfViewDegrees; else if (camField.Name == "NearClip") camJson["NearClip"] = obj.Camera->NearClip; else if (camField.Name == "FarClip") camJson["FarClip"] = obj.Camera->FarClip; else if (camField.Name == "IsPrimary") camJson["IsPrimary"] = obj.Camera->IsPrimary; } objJson["Camera"] = camJson; } } else if (objField.Name == "PrefabInstance" && obj.PrefabInstance.has_value()) { const MetaCoreStructDescriptor* prefabDesc = registry.FindStruct(); if (prefabDesc) { json prefabJson = json::object(); for (const auto& prefabField : prefabDesc->Fields) { if (prefabField.Name == "PrefabAssetGuid") prefabJson["PrefabAssetGuid"] = GuidToString(obj.PrefabInstance->PrefabAssetGuid); else if (prefabField.Name == "PrefabObjectId") prefabJson["PrefabObjectId"] = obj.PrefabInstance->PrefabObjectId; else if (prefabField.Name == "PrefabInstanceRootId") prefabJson["PrefabInstanceRootId"] = obj.PrefabInstance->PrefabInstanceRootId; } objJson["PrefabInstance"] = prefabJson; } } else if (objField.Name == "SerializedComponents" && !obj.SerializedComponents.empty()) { json componentsJson = json::array(); for (const MetaCoreSerializedComponentData& component : obj.SerializedComponents) { if (component.TypeId.empty() || component.Payload.empty()) { continue; } componentsJson.push_back(json{ {"TypeId", component.TypeId}, {"Payload", BytesToHexString(component.Payload)} }); } if (!componentsJson.empty()) { objJson["Components"] = std::move(componentsJson); } } } return objJson; } // 辅助方法:从 json 格式中恢复单个 MetaCoreGameObjectData static MetaCoreGameObjectData JsonToGameObjectData(const json& objJson, const MetaCoreTypeRegistry& registry) { MetaCoreGameObjectData obj; const MetaCoreStructDescriptor* objDesc = registry.FindStruct(); if (!objDesc) return obj; for (const auto& objField : objDesc->Fields) { if (objField.Name == "Id" && objJson.contains("Id")) { obj.Id = objJson["Id"].get(); } else if (objField.Name == "ParentId" && objJson.contains("ParentId")) { obj.ParentId = objJson["ParentId"].get(); } else if (objField.Name == "Name" && objJson.contains("Name")) { obj.Name = objJson["Name"].get(); } else if (objField.Name == "Transform" && objJson.contains("Transform")) { const auto& transJson = objJson["Transform"]; const MetaCoreStructDescriptor* transDesc = registry.FindStruct(); if (transDesc) { for (const auto& transField : transDesc->Fields) { if (transField.Name == "Position" && transJson.contains("Position")) { obj.Transform.Position = JsonToVec3(transJson["Position"]); } else if (transField.Name == "RotationEulerDegrees" && transJson.contains("RotationEulerDegrees")) { obj.Transform.RotationEulerDegrees = JsonToVec3(transJson["RotationEulerDegrees"]); } else if (transField.Name == "Scale" && transJson.contains("Scale")) { obj.Transform.Scale = JsonToVec3(transJson["Scale"]); } } } } else if (objField.Name == "MeshRenderer" && objJson.contains("MeshRenderer")) { const auto& meshJson = objJson["MeshRenderer"]; const MetaCoreStructDescriptor* meshDesc = registry.FindStruct(); if (meshDesc) { MetaCoreMeshRendererComponent mesh; for (const auto& meshField : meshDesc->Fields) { if (meshField.Name == "MeshSource" && meshJson.contains("MeshSource")) mesh.MeshSource = static_cast(meshJson["MeshSource"].get()); else if (meshField.Name == "BuiltinMesh" && meshJson.contains("BuiltinMesh")) mesh.BuiltinMesh = static_cast(meshJson["BuiltinMesh"].get()); else if (meshField.Name == "MeshAssetGuid" && meshJson.contains("MeshAssetGuid")) mesh.MeshAssetGuid = StringToGuid(meshJson["MeshAssetGuid"].get()); else if (meshField.Name == "MaterialAssetGuids" && meshJson.contains("MaterialAssetGuids") && meshJson["MaterialAssetGuids"].is_array()) { for (const auto& mGuidJson : meshJson["MaterialAssetGuids"]) { mesh.MaterialAssetGuids.push_back(StringToGuid(mGuidJson.get())); } } else if (meshField.Name == "SourceModelAssetGuid" && meshJson.contains("SourceModelAssetGuid")) mesh.SourceModelAssetGuid = StringToGuid(meshJson["SourceModelAssetGuid"].get()); else if (meshField.Name == "SourceModelPath" && meshJson.contains("SourceModelPath")) mesh.SourceModelPath = meshJson["SourceModelPath"].get(); else if (meshField.Name == "SourceNodePath" && meshJson.contains("SourceNodePath")) mesh.SourceNodePath = meshJson["SourceNodePath"].get(); else if (meshField.Name == "BaseColorTextureGuid" && meshJson.contains("BaseColorTextureGuid")) mesh.BaseColorTextureGuid = StringToGuid(meshJson["BaseColorTextureGuid"].get()); else if (meshField.Name == "MetallicRoughnessTextureGuid" && meshJson.contains("MetallicRoughnessTextureGuid")) mesh.MetallicRoughnessTextureGuid = StringToGuid(meshJson["MetallicRoughnessTextureGuid"].get()); else if (meshField.Name == "NormalTextureGuid" && meshJson.contains("NormalTextureGuid")) mesh.NormalTextureGuid = StringToGuid(meshJson["NormalTextureGuid"].get()); else if (meshField.Name == "EmissiveTextureGuid" && meshJson.contains("EmissiveTextureGuid")) mesh.EmissiveTextureGuid = StringToGuid(meshJson["EmissiveTextureGuid"].get()); else if (meshField.Name == "AoTextureGuid" && meshJson.contains("AoTextureGuid")) mesh.AoTextureGuid = StringToGuid(meshJson["AoTextureGuid"].get()); else if (meshField.Name == "BaseColorTexturePath" && meshJson.contains("BaseColorTexturePath")) mesh.BaseColorTexturePath = meshJson["BaseColorTexturePath"].get(); else if (meshField.Name == "MetallicRoughnessTexturePath" && meshJson.contains("MetallicRoughnessTexturePath")) mesh.MetallicRoughnessTexturePath = meshJson["MetallicRoughnessTexturePath"].get(); else if (meshField.Name == "NormalTexturePath" && meshJson.contains("NormalTexturePath")) mesh.NormalTexturePath = meshJson["NormalTexturePath"].get(); else if (meshField.Name == "EmissiveTexturePath" && meshJson.contains("EmissiveTexturePath")) mesh.EmissiveTexturePath = meshJson["EmissiveTexturePath"].get(); else if (meshField.Name == "AoTexturePath" && meshJson.contains("AoTexturePath")) mesh.AoTexturePath = meshJson["AoTexturePath"].get(); else if (meshField.Name == "DoubleSided" && meshJson.contains("DoubleSided")) mesh.DoubleSided = meshJson["DoubleSided"].get(); else if (meshField.Name == "Metallic" && meshJson.contains("Metallic")) mesh.Metallic = meshJson["Metallic"].get(); else if (meshField.Name == "Roughness" && meshJson.contains("Roughness")) mesh.Roughness = meshJson["Roughness"].get(); else if (meshField.Name == "AlphaMode" && meshJson.contains("AlphaMode")) mesh.AlphaMode = static_cast(meshJson["AlphaMode"].get()); else if (meshField.Name == "AlphaCutoff" && meshJson.contains("AlphaCutoff")) mesh.AlphaCutoff = meshJson["AlphaCutoff"].get(); else if (meshField.Name == "EmissiveColor" && meshJson.contains("EmissiveColor")) mesh.EmissiveColor = JsonToVec3(meshJson["EmissiveColor"]); else if (meshField.Name == "BaseColor" && meshJson.contains("BaseColor")) mesh.BaseColor = JsonToVec3(meshJson["BaseColor"]); else if (meshField.Name == "ModelNodeIndex" && meshJson.contains("ModelNodeIndex")) mesh.ModelNodeIndex = meshJson["ModelNodeIndex"].get(); else if (meshField.Name == "SubMeshIndex" && meshJson.contains("SubMeshIndex")) mesh.SubMeshIndex = meshJson["SubMeshIndex"].get(); else if (meshField.Name == "Visible" && meshJson.contains("Visible")) mesh.Visible = meshJson["Visible"].get(); } obj.MeshRenderer = mesh; } } else if (objField.Name == "Light" && objJson.contains("Light")) { const auto& lightJson = objJson["Light"]; const MetaCoreStructDescriptor* lightDesc = registry.FindStruct(); if (lightDesc) { MetaCoreLightComponent light; for (const auto& lightField : lightDesc->Fields) { if (lightField.Name == "Color" && lightJson.contains("Color")) light.Color = JsonToVec3(lightJson["Color"]); else if (lightField.Name == "Intensity" && lightJson.contains("Intensity")) light.Intensity = lightJson["Intensity"].get(); } obj.Light = light; } } else if (objField.Name == "Camera" && objJson.contains("Camera")) { const auto& camJson = objJson["Camera"]; const MetaCoreStructDescriptor* camDesc = registry.FindStruct(); if (camDesc) { MetaCoreCameraComponent cam; for (const auto& camField : camDesc->Fields) { if (camField.Name == "FieldOfViewDegrees" && camJson.contains("FieldOfViewDegrees")) cam.FieldOfViewDegrees = camJson["FieldOfViewDegrees"].get(); else if (camField.Name == "NearClip" && camJson.contains("NearClip")) cam.NearClip = camJson["NearClip"].get(); else if (camField.Name == "FarClip" && camJson.contains("FarClip")) cam.FarClip = camJson["FarClip"].get(); else if (camField.Name == "IsPrimary" && camJson.contains("IsPrimary")) cam.IsPrimary = camJson["IsPrimary"].get(); } obj.Camera = cam; } } else if (objField.Name == "PrefabInstance" && objJson.contains("PrefabInstance")) { const auto& prefabJson = objJson["PrefabInstance"]; const MetaCoreStructDescriptor* prefabDesc = registry.FindStruct(); if (prefabDesc) { MetaCorePrefabInstanceMetadata prefab; for (const auto& prefabField : prefabDesc->Fields) { if (prefabField.Name == "PrefabAssetGuid" && prefabJson.contains("PrefabAssetGuid")) prefab.PrefabAssetGuid = StringToGuid(prefabJson["PrefabAssetGuid"].get()); else if (prefabField.Name == "PrefabObjectId" && prefabJson.contains("PrefabObjectId")) prefab.PrefabObjectId = prefabJson["PrefabObjectId"].get(); else if (prefabField.Name == "PrefabInstanceRootId" && prefabJson.contains("PrefabInstanceRootId")) prefab.PrefabInstanceRootId = prefabJson["PrefabInstanceRootId"].get(); } obj.PrefabInstance = prefab; } } else if (objField.Name == "SerializedComponents" && objJson.contains("Components") && objJson["Components"].is_array()) { for (const auto& componentJson : objJson["Components"]) { if (!componentJson.contains("TypeId") || !componentJson.contains("Payload")) { continue; } MetaCoreSerializedComponentData component{}; component.TypeId = componentJson["TypeId"].get(); component.Payload = HexStringToBytes(componentJson["Payload"].get()); if (!component.TypeId.empty() && !component.Payload.empty()) { obj.SerializedComponents.push_back(std::move(component)); } } } } return obj; } bool MetaCoreSceneSerializer::SaveSceneToJson( const std::filesystem::path& absolutePath, const MetaCoreSceneDocument& sceneDocument, const MetaCoreTypeRegistry& registry ) { try { json sceneJson; // 验证 MetaCoreSceneDocument 反射注册 const MetaCoreStructDescriptor* sceneDesc = registry.FindStruct(); if (!sceneDesc) { std::cerr << "SaveSceneToJson: 未能找到 MetaCoreSceneDocument 反射描述" << std::endl; return false; } for (const auto& field : sceneDesc->Fields) { if (field.Name == "Name") { sceneJson["SceneName"] = sceneDocument.Name; } else if (field.Name == "Selection") { const MetaCoreStructDescriptor* selDesc = registry.FindStruct(); if (selDesc) { json selJson = json::object(); for (const auto& selField : selDesc->Fields) { if (selField.Name == "SelectedObjectIds") selJson["SelectedObjectIds"] = sceneDocument.Selection.SelectedObjectIds; else if (selField.Name == "ActiveObjectId") selJson["ActiveObjectId"] = sceneDocument.Selection.ActiveObjectId; else if (selField.Name == "SelectionAnchorId") selJson["SelectionAnchorId"] = sceneDocument.Selection.SelectionAnchorId; } sceneJson["Selection"] = selJson; } } else if (field.Name == "GameObjects") { json gameObjectsArray = json::array(); for (const auto& obj : sceneDocument.GameObjects) { gameObjectsArray.push_back(GameObjectDataToJson(obj, registry)); } sceneJson["GameObjects"] = gameObjectsArray; } } std::ofstream file(absolutePath); if (!file.is_open()) { std::cerr << "SaveSceneToJson: 无法打开文件写入 " << absolutePath << std::endl; return false; } file << sceneJson.dump(4); return true; } catch (const std::exception& e) { std::cerr << "SaveSceneToJson: 发生异常 - " << e.what() << std::endl; return false; } } std::optional MetaCoreSceneSerializer::LoadSceneFromJson( const std::filesystem::path& absolutePath, const MetaCoreTypeRegistry& registry ) { try { std::ifstream file(absolutePath); if (!file.is_open()) { std::cerr << "LoadSceneFromJson: 无法打开文件进行读取 " << absolutePath << std::endl; return std::nullopt; } json sceneJson; file >> sceneJson; MetaCoreSceneDocument sceneDocument; // 验证 MetaCoreSceneDocument 反射注册 const MetaCoreStructDescriptor* sceneDesc = registry.FindStruct(); if (!sceneDesc) { std::cerr << "LoadSceneFromJson: 未能找到 MetaCoreSceneDocument 反射描述" << std::endl; return std::nullopt; } for (const auto& field : sceneDesc->Fields) { if (field.Name == "Name" && sceneJson.contains("SceneName")) { sceneDocument.Name = sceneJson["SceneName"].get(); } else if (field.Name == "Selection" && sceneJson.contains("Selection")) { const auto& selectionJson = sceneJson["Selection"]; const MetaCoreStructDescriptor* selDesc = registry.FindStruct(); if (selDesc) { for (const auto& selField : selDesc->Fields) { if (selField.Name == "SelectedObjectIds" && selectionJson.contains("SelectedObjectIds")) { sceneDocument.Selection.SelectedObjectIds = selectionJson["SelectedObjectIds"].get>(); } else if (selField.Name == "ActiveObjectId" && selectionJson.contains("ActiveObjectId")) { sceneDocument.Selection.ActiveObjectId = selectionJson["ActiveObjectId"].get(); } else if (selField.Name == "SelectionAnchorId" && selectionJson.contains("SelectionAnchorId")) { sceneDocument.Selection.SelectionAnchorId = selectionJson["SelectionAnchorId"].get(); } } } } else if (field.Name == "GameObjects" && sceneJson.contains("GameObjects") && sceneJson["GameObjects"].is_array()) { for (const auto& objJson : sceneJson["GameObjects"]) { sceneDocument.GameObjects.push_back(JsonToGameObjectData(objJson, registry)); } } } return sceneDocument; } catch (const std::exception& e) { std::cerr << "LoadSceneFromJson: 发生异常 - " << e.what() << std::endl; return std::nullopt; } } // Prefab bool MetaCoreSceneSerializer::SavePrefabToJson( const std::filesystem::path& absolutePath, const MetaCorePrefabDocument& prefabDocument, const MetaCoreTypeRegistry& registry ) { try { json prefabJson; prefabJson["PrefabName"] = prefabDocument.Name; json gameObjectsArray = json::array(); for (const auto& obj : prefabDocument.GameObjects) { gameObjectsArray.push_back(GameObjectDataToJson(obj, registry)); } prefabJson["GameObjects"] = gameObjectsArray; std::ofstream file(absolutePath); if (!file.is_open()) { return false; } file << prefabJson.dump(4); return true; } catch (...) { return false; } } std::optional MetaCoreSceneSerializer::LoadPrefabFromJson( const std::filesystem::path& absolutePath, const MetaCoreTypeRegistry& registry ) { try { std::ifstream file(absolutePath); if (!file.is_open()) { return std::nullopt; } json prefabJson; file >> prefabJson; MetaCorePrefabDocument doc; if (prefabJson.contains("PrefabName")) { doc.Name = prefabJson["PrefabName"].get(); } if (prefabJson.contains("GameObjects") && prefabJson["GameObjects"].is_array()) { for (const auto& objJson : prefabJson["GameObjects"]) { doc.GameObjects.push_back(JsonToGameObjectData(objJson, registry)); } } return doc; } catch (...) { return std::nullopt; } } // Material bool MetaCoreSceneSerializer::SaveMaterialToJson( const std::filesystem::path& absolutePath, const MetaCoreMaterialAssetDocument& doc, const MetaCoreTypeRegistry& registry ) { (void)registry; try { json matJson; matJson["AssetGuid"] = GuidToString(doc.AssetGuid); matJson["Name"] = doc.Name; matJson["StableImportKey"] = doc.StableImportKey; matJson["ShaderModel"] = static_cast(doc.ShaderModel); matJson["BaseColor"] = Vec3ToJson(doc.BaseColor); matJson["BaseColorTexture"] = GuidToString(doc.BaseColorTexture); matJson["NormalTexture"] = GuidToString(doc.NormalTexture); matJson["Metallic"] = doc.Metallic; matJson["Roughness"] = doc.Roughness; matJson["MetallicRoughnessTexture"] = GuidToString(doc.MetallicRoughnessTexture); matJson["AoTexture"] = GuidToString(doc.AoTexture); matJson["EmissiveColor"] = Vec3ToJson(doc.EmissiveColor); matJson["EmissiveTexture"] = GuidToString(doc.EmissiveTexture); matJson["AlphaMode"] = static_cast(doc.AlphaMode); matJson["AlphaCutoff"] = doc.AlphaCutoff; matJson["DoubleSided"] = doc.DoubleSided; std::ofstream file(absolutePath); if (!file.is_open()) { return false; } file << matJson.dump(4); return true; } catch (...) { return false; } } std::optional MetaCoreSceneSerializer::LoadMaterialFromJson( const std::filesystem::path& absolutePath, const MetaCoreTypeRegistry& registry ) { (void)registry; try { std::ifstream file(absolutePath); if (!file.is_open()) { return std::nullopt; } json matJson; file >> matJson; MetaCoreMaterialAssetDocument doc; if (matJson.contains("AssetGuid")) doc.AssetGuid = StringToGuid(matJson["AssetGuid"].get()); if (matJson.contains("Name")) doc.Name = matJson["Name"].get(); if (matJson.contains("StableImportKey")) doc.StableImportKey = matJson["StableImportKey"].get(); if (matJson.contains("ShaderModel")) doc.ShaderModel = static_cast(matJson["ShaderModel"].get()); if (matJson.contains("BaseColor")) doc.BaseColor = JsonToVec3(matJson["BaseColor"]); if (matJson.contains("BaseColorTexture")) doc.BaseColorTexture = StringToGuid(matJson["BaseColorTexture"].get()); if (matJson.contains("NormalTexture")) doc.NormalTexture = StringToGuid(matJson["NormalTexture"].get()); if (matJson.contains("Metallic")) doc.Metallic = matJson["Metallic"].get(); if (matJson.contains("Roughness")) doc.Roughness = matJson["Roughness"].get(); if (matJson.contains("MetallicRoughnessTexture")) doc.MetallicRoughnessTexture = StringToGuid(matJson["MetallicRoughnessTexture"].get()); if (matJson.contains("AoTexture")) doc.AoTexture = StringToGuid(matJson["AoTexture"].get()); if (matJson.contains("EmissiveColor")) doc.EmissiveColor = JsonToVec3(matJson["EmissiveColor"]); if (matJson.contains("EmissiveTexture")) doc.EmissiveTexture = StringToGuid(matJson["EmissiveTexture"].get()); if (matJson.contains("AlphaMode")) doc.AlphaMode = static_cast(matJson["AlphaMode"].get()); if (matJson.contains("AlphaCutoff")) doc.AlphaCutoff = matJson["AlphaCutoff"].get(); if (matJson.contains("DoubleSided")) doc.DoubleSided = matJson["DoubleSided"].get(); return doc; } catch (...) { return std::nullopt; } } // UI 序列化辅助方法 static json RectTransformToJson(const MetaCoreUiRectTransformDocument& trans) { json j = json::object(); j["AnchorMin"] = Vec3ToJson(trans.AnchorMin); j["AnchorMax"] = Vec3ToJson(trans.AnchorMax); j["Pivot"] = Vec3ToJson(trans.Pivot); j["Position"] = Vec3ToJson(trans.Position); j["Size"] = Vec3ToJson(trans.Size); return j; } static MetaCoreUiRectTransformDocument JsonToRectTransform(const json& j) { MetaCoreUiRectTransformDocument trans; if (j.contains("AnchorMin")) trans.AnchorMin = JsonToVec3(j["AnchorMin"]); if (j.contains("AnchorMax")) trans.AnchorMax = JsonToVec3(j["AnchorMax"]); if (j.contains("Pivot")) trans.Pivot = JsonToVec3(j["Pivot"]); if (j.contains("Position")) trans.Position = JsonToVec3(j["Position"]); if (j.contains("Size")) trans.Size = JsonToVec3(j["Size"]); return trans; } static json UiStyleToJson(const MetaCoreUiStyleDocument& style) { json j = json::object(); j["BackgroundColor"] = Vec3ToJson(style.BackgroundColor); j["TextColor"] = Vec3ToJson(style.TextColor); j["TintColor"] = Vec3ToJson(style.TintColor); j["FontSize"] = style.FontSize; j["Padding"] = Vec3ToJson(style.Padding); j["HorizontalAlignment"] = static_cast(style.HorizontalAlignment); j["VerticalAlignment"] = static_cast(style.VerticalAlignment); j["ImageAssetGuid"] = GuidToString(style.ImageAssetGuid); j["PreserveAspect"] = style.PreserveAspect; return j; } static MetaCoreUiStyleDocument JsonToUiStyle(const json& j) { MetaCoreUiStyleDocument style; if (j.contains("BackgroundColor")) style.BackgroundColor = JsonToVec3(j["BackgroundColor"]); if (j.contains("TextColor")) style.TextColor = JsonToVec3(j["TextColor"]); if (j.contains("TintColor")) style.TintColor = JsonToVec3(j["TintColor"]); if (j.contains("FontSize")) style.FontSize = j["FontSize"].get(); if (j.contains("Padding")) style.Padding = JsonToVec3(j["Padding"]); if (j.contains("HorizontalAlignment")) style.HorizontalAlignment = static_cast(j["HorizontalAlignment"].get()); if (j.contains("VerticalAlignment")) style.VerticalAlignment = static_cast(j["VerticalAlignment"].get()); if (j.contains("ImageAssetGuid")) style.ImageAssetGuid = StringToGuid(j["ImageAssetGuid"].get()); if (j.contains("PreserveAspect")) style.PreserveAspect = j["PreserveAspect"].get(); return style; } static json UiNodeToJson(const MetaCoreUiNodeDocument& node) { json j = json::object(); j["Id"] = node.Id; j["Name"] = node.Name; j["Type"] = static_cast(node.Type); j["ParentId"] = node.ParentId; j["Children"] = node.Children; j["Visible"] = node.Visible; j["RectTransform"] = RectTransformToJson(node.RectTransform); j["Style"] = UiStyleToJson(node.Style); j["Text"] = node.Text; j["Interactable"] = node.Interactable; return j; } static MetaCoreUiNodeDocument JsonToUiNode(const json& j) { MetaCoreUiNodeDocument node; if (j.contains("Id")) node.Id = j["Id"].get(); if (j.contains("Name")) node.Name = j["Name"].get(); if (j.contains("Type")) node.Type = static_cast(j["Type"].get()); if (j.contains("ParentId")) node.ParentId = j["ParentId"].get(); if (j.contains("Children")) node.Children = j["Children"].get>(); if (j.contains("Visible")) node.Visible = j["Visible"].get(); if (j.contains("RectTransform")) node.RectTransform = JsonToRectTransform(j["RectTransform"]); if (j.contains("Style")) node.Style = JsonToUiStyle(j["Style"]); if (j.contains("Text")) node.Text = j["Text"].get(); if (j.contains("Interactable")) node.Interactable = j["Interactable"].get(); return node; } bool MetaCoreSceneSerializer::SaveUiToJson( const std::filesystem::path& absolutePath, const MetaCoreUiDocument& uiDocument, const MetaCoreTypeRegistry& registry ) { (void)registry; try { json uiJson; uiJson["Name"] = uiDocument.Name; uiJson["ReferenceWidth"] = uiDocument.ReferenceWidth; uiJson["ReferenceHeight"] = uiDocument.ReferenceHeight; uiJson["RootNodeIds"] = uiDocument.RootNodeIds; json nodesArray = json::array(); for (const auto& node : uiDocument.Nodes) { nodesArray.push_back(UiNodeToJson(node)); } uiJson["Nodes"] = nodesArray; std::ofstream file(absolutePath); if (!file.is_open()) { return false; } file << uiJson.dump(4); return true; } catch (...) { return false; } } std::optional MetaCoreSceneSerializer::LoadUiFromJson( const std::filesystem::path& absolutePath, const MetaCoreTypeRegistry& registry ) { (void)registry; try { std::ifstream file(absolutePath); if (!file.is_open()) { return std::nullopt; } json uiJson; file >> uiJson; MetaCoreUiDocument doc; if (uiJson.contains("Name")) doc.Name = uiJson["Name"].get(); if (uiJson.contains("ReferenceWidth")) doc.ReferenceWidth = uiJson["ReferenceWidth"].get(); if (uiJson.contains("ReferenceHeight")) doc.ReferenceHeight = uiJson["ReferenceHeight"].get(); if (uiJson.contains("RootNodeIds")) doc.RootNodeIds = uiJson["RootNodeIds"].get>(); if (uiJson.contains("Nodes") && uiJson["Nodes"].is_array()) { for (const auto& nodeJson : uiJson["Nodes"]) { doc.Nodes.push_back(JsonToUiNode(nodeJson)); } } return doc; } catch (...) { return std::nullopt; } } } // namespace MetaCore