#include "MetaCoreScene/MetaCoreSceneSerializer.h" #include "MetaCoreFoundation/MetaCoreReflection.h" #include #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{}); } template static std::string ReflectedValueToHex(const T& value, const MetaCoreTypeRegistry& registry) { const auto bytes = MetaCoreSerializeToBytes(value, registry); if (!bytes) return {}; constexpr char digits[] = "0123456789abcdef"; std::string result; result.resize(bytes->size()*2U); for(std::size_t i=0;isize();++i){const auto valueByte=std::to_integer((*bytes)[i]);result[i*2U]=digits[valueByte>>4U];result[i*2U+1U]=digits[valueByte&15U];}return result; } template static std::optional ReflectedValueFromHex(const json& value, const MetaCoreTypeRegistry& registry) { if(!value.is_string())return std::nullopt;const std::string hex=value.get();if((hex.size()&1U)!=0U)return std::nullopt; const auto nibble=[](char c)->int{if(c>='0'&&c<='9')return c-'0';if(c>='a'&&c<='f')return c-'a'+10;if(c>='A'&&c<='F')return c-'A'+10;return -1;}; std::vector bytes(hex.size()/2U);for(std::size_t i=0;i((hi<<4)|lo);}T result{};if(!MetaCoreDeserializeFromBytes(std::span(bytes.data(),bytes.size()),result,registry))return std::nullopt;return result; } static json SceneEnvironmentToJson(const MetaCoreSceneEnvironmentSettings& environment) { json environmentJson = json::object(); environmentJson["Source"] = static_cast(environment.Source); environmentJson["IblKtxPath"] = environment.IblKtxPath.generic_string(); environmentJson["SkyboxKtxPath"] = environment.SkyboxKtxPath.generic_string(); environmentJson["SkyboxVisible"] = environment.SkyboxVisible; environmentJson["RotationDegrees"] = environment.RotationDegrees; environmentJson["IndirectLightIntensity"] = environment.IndirectLightIntensity; environmentJson["SkyboxIntensity"] = environment.SkyboxIntensity; environmentJson["EnvironmentProfileGuid"] = GuidToString(environment.EnvironmentProfileGuid); environmentJson["PostProcessProfileGuid"] = GuidToString(environment.PostProcessProfileGuid); return environmentJson; } static MetaCoreSceneEnvironmentSettings JsonToSceneEnvironment(const json& environmentJson) { MetaCoreSceneEnvironmentSettings environment; if (!environmentJson.is_object()) { return environment; } if (environmentJson.contains("Source")) environment.Source = static_cast(environmentJson["Source"].get()); if (environmentJson.contains("IblKtxPath")) environment.IblKtxPath = environmentJson["IblKtxPath"].get(); if (environmentJson.contains("SkyboxKtxPath")) environment.SkyboxKtxPath = environmentJson["SkyboxKtxPath"].get(); if (environmentJson.contains("SkyboxVisible")) environment.SkyboxVisible = environmentJson["SkyboxVisible"].get(); if (environmentJson.contains("RotationDegrees")) environment.RotationDegrees = environmentJson["RotationDegrees"].get(); if (environmentJson.contains("IndirectLightIntensity")) environment.IndirectLightIntensity = environmentJson["IndirectLightIntensity"].get(); if (environmentJson.contains("SkyboxIntensity")) environment.SkyboxIntensity = environmentJson["SkyboxIntensity"].get(); if (environmentJson.contains("EnvironmentProfileGuid")) environment.EnvironmentProfileGuid = StringToGuid(environmentJson["EnvironmentProfileGuid"].get()); if (environmentJson.contains("PostProcessProfileGuid")) environment.PostProcessProfileGuid = StringToGuid(environmentJson["PostProcessProfileGuid"].get()); return environment; } // 辅助方法:将单个 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 == "Type") lightJson["Type"] = static_cast(obj.Light->Type); else if (lightField.Name == "Color") lightJson["Color"] = Vec3ToJson(obj.Light->Color); else if (lightField.Name == "Intensity") lightJson["Intensity"] = obj.Light->Intensity; else if (lightField.Name == "Enabled") lightJson["Enabled"] = obj.Light->Enabled; else if (lightField.Name == "UseColorTemperature") lightJson["UseColorTemperature"] = obj.Light->UseColorTemperature; else if (lightField.Name == "ColorTemperatureKelvin") lightJson["ColorTemperatureKelvin"] = obj.Light->ColorTemperatureKelvin; else if (lightField.Name == "Range") lightJson["Range"] = obj.Light->Range; else if (lightField.Name == "InnerConeDegrees") lightJson["InnerConeDegrees"] = obj.Light->InnerConeDegrees; else if (lightField.Name == "OuterConeDegrees") lightJson["OuterConeDegrees"] = obj.Light->OuterConeDegrees; else if (lightField.Name == "FalloffExponent") lightJson["FalloffExponent"] = obj.Light->FalloffExponent; else if (lightField.Name == "CastShadows") lightJson["CastShadows"] = obj.Light->CastShadows; else if (lightField.Name == "ShadowBias") lightJson["ShadowBias"] = obj.Light->ShadowBias; else if (lightField.Name == "ShadowNormalBias") lightJson["ShadowNormalBias"] = obj.Light->ShadowNormalBias; else if (lightField.Name == "ShadowPriority") lightJson["ShadowPriority"] = obj.Light->ShadowPriority; else if (lightField.Name == "LightingMask") lightJson["LightingMask"] = obj.Light->LightingMask; } objJson["Light"] = lightJson; } } else if (objField.Name == "Rotator" && obj.Rotator.has_value()) { const MetaCoreStructDescriptor* rotatorDesc = registry.FindStruct(); if (rotatorDesc) { json rotatorJson = json::object(); for (const auto& rotatorField : rotatorDesc->Fields) { if (rotatorField.Name == "Enabled") rotatorJson["Enabled"] = obj.Rotator->Enabled; else if (rotatorField.Name == "DegreesPerSecond") rotatorJson["DegreesPerSecond"] = obj.Rotator->DegreesPerSecond; } objJson["Rotator"] = rotatorJson; } } else if (objField.Name == "Animator" && obj.Animator.has_value()) { const MetaCoreStructDescriptor* animatorDesc = registry.FindStruct(); if (animatorDesc) { json animatorJson = json::object(); const auto& animator = obj.Animator.value(); for (const auto& animatorField : animatorDesc->Fields) { if (animatorField.Name == "Enabled") animatorJson["Enabled"] = animator.Enabled; else if (animatorField.Name == "SourceModelAssetGuid") animatorJson["SourceModelAssetGuid"] = GuidToString(animator.SourceModelAssetGuid); else if (animatorField.Name == "SourceModelPath") animatorJson["SourceModelPath"] = animator.SourceModelPath; else if (animatorField.Name == "ClipIndex") animatorJson["ClipIndex"] = animator.ClipIndex; else if (animatorField.Name == "ClipName") animatorJson["ClipName"] = animator.ClipName; else if (animatorField.Name == "PlayOnStart") animatorJson["PlayOnStart"] = animator.PlayOnStart; else if (animatorField.Name == "Loop") animatorJson["Loop"] = animator.Loop; else if (animatorField.Name == "Speed") animatorJson["Speed"] = animator.Speed; } objJson["Animator"] = std::move(animatorJson); } } else if (objField.Name == "Script" && obj.Script.has_value()) { json scriptJson = json::object(); json instancesJson = json::array(); for (const MetaCoreScriptInstanceData& instance : obj.Script->Instances) { json instanceJson = json::object(); instanceJson["InstanceId"] = instance.InstanceId; instanceJson["ScriptTypeId"] = instance.ScriptTypeId; instanceJson["Enabled"] = instance.Enabled; instanceJson["FieldsJson"] = instance.FieldsJson; instancesJson.push_back(std::move(instanceJson)); } scriptJson["Instances"] = std::move(instancesJson); objJson["Script"] = std::move(scriptJson); } else if (objField.Name == "UiRenderer" && obj.UiRenderer.has_value()) { const MetaCoreStructDescriptor* uiDesc = registry.FindStruct(); if (uiDesc) { json uiJson = json::object(); const auto& ui = obj.UiRenderer.value(); for (const auto& uiField : uiDesc->Fields) { if (uiField.Name == "UiDocumentAssetGuid") uiJson["UiDocumentAssetGuid"] = GuidToString(ui.UiDocumentAssetGuid); else if (uiField.Name == "RenderMode") uiJson["RenderMode"] = static_cast(ui.RenderMode); else if (uiField.Name == "Visible") uiJson["Visible"] = ui.Visible; else if (uiField.Name == "InputEnabled") uiJson["InputEnabled"] = ui.InputEnabled; else if (uiField.Name == "FaceCamera") uiJson["FaceCamera"] = ui.FaceCamera; else if (uiField.Name == "Layer") uiJson["Layer"] = ui.Layer; else if (uiField.Name == "PixelsPerUnit") uiJson["PixelsPerUnit"] = ui.PixelsPerUnit; else if (uiField.Name == "WorldSize") uiJson["WorldSize"] = Vec3ToJson(ui.WorldSize); } objJson["UiRenderer"] = std::move(uiJson); } } else if (objField.Name == "Interactable" && obj.Interactable.has_value()) { objJson["Interactable"] = { {"Enabled", obj.Interactable->Enabled}, {"EventMask", obj.Interactable->EventMask}, {"DragThresholdPixels", obj.Interactable->DragThresholdPixels} }; } else if (objField.Name == "Collider" && obj.Collider.has_value()) { const auto& value = *obj.Collider; objJson["Collider"] = {{"Enabled", value.Enabled}, {"Shape", static_cast(value.Shape)}, {"Center", Vec3ToJson(value.Center)}, {"Size", Vec3ToJson(value.Size)}, {"Radius", value.Radius}, {"Height", value.Height}, {"MeshAssetGuid", GuidToString(value.MeshAssetGuid)}, {"MaterialAssetGuid", GuidToString(value.MaterialAssetGuid)}, {"CollisionLayer", value.CollisionLayer}, {"IsTrigger", value.IsTrigger}}; } else if (objField.Name == "RigidBody" && obj.RigidBody.has_value()) { const auto& value = *obj.RigidBody; objJson["RigidBody"] = {{"BodyType", static_cast(value.BodyType)}, {"Mass", value.Mass}, {"LinearDamping", value.LinearDamping}, {"AngularDamping", value.AngularDamping}, {"GravityScale", value.GravityScale}, {"InitialLinearVelocity", Vec3ToJson(value.InitialLinearVelocity)}, {"InitialAngularVelocity", Vec3ToJson(value.InitialAngularVelocity)}, {"AllowSleep", value.AllowSleep}, {"ContinuousCollisionDetection", value.ContinuousCollisionDetection}, {"LockedAxes", value.LockedAxes}}; } else if (objField.Name == "PhysicsConstraint" && obj.PhysicsConstraint.has_value()) { const auto& value = *obj.PhysicsConstraint; objJson["PhysicsConstraint"] = {{"Enabled", value.Enabled}, {"Type", static_cast(value.Type)}, {"TargetObjectId", value.TargetObjectId}, {"Anchor", Vec3ToJson(value.Anchor)}, {"TargetAnchor", Vec3ToJson(value.TargetAnchor)}, {"Axis", Vec3ToJson(value.Axis)}, {"LinearLowerLimit", Vec3ToJson(value.LinearLowerLimit)}, {"LinearUpperLimit", Vec3ToJson(value.LinearUpperLimit)}, {"AngularLowerLimit", Vec3ToJson(value.AngularLowerLimit)}, {"AngularUpperLimit", Vec3ToJson(value.AngularUpperLimit)}, {"MotorEnabled", value.MotorEnabled}, {"MotorTargetVelocity", value.MotorTargetVelocity}, {"MotorMaxImpulse", value.MotorMaxImpulse}, {"BreakForce", value.BreakForce}, {"BreakTorque", value.BreakTorque}, {"EnableConnectedCollision", value.EnableConnectedCollision}}; } else if (objField.Name == "CharacterController" && obj.CharacterController.has_value()) { const auto& value = *obj.CharacterController; objJson["CharacterController"] = {{"Enabled", value.Enabled}, {"Radius", value.Radius}, {"Height", value.Height}, {"SkinWidth", value.SkinWidth}, {"MaxSlopeDegrees", value.MaxSlopeDegrees}, {"StepHeight", value.StepHeight}, {"GravityScale", value.GravityScale}, {"MaxFallSpeed", value.MaxFallSpeed}, {"PushForce", value.PushForce}, {"CollisionLayer", value.CollisionLayer}}; } else if (objField.Name == "ReflectionProbe" && obj.ReflectionProbe) objJson["ReflectionProbe"] = ReflectedValueToHex(*obj.ReflectionProbe, registry); else if (objField.Name == "LodGroup" && obj.LodGroup) objJson["LodGroup"] = ReflectedValueToHex(*obj.LodGroup, registry); else if (objField.Name == "ParticleEmitter" && obj.ParticleEmitter) objJson["ParticleEmitter"] = ReflectedValueToHex(*obj.ParticleEmitter, registry); else if (objField.Name == "LineRenderer" && obj.LineRenderer) objJson["LineRenderer"] = ReflectedValueToHex(*obj.LineRenderer, registry); else if (objField.Name == "TrailRenderer" && obj.TrailRenderer) objJson["TrailRenderer"] = ReflectedValueToHex(*obj.TrailRenderer, registry); else if (objField.Name == "DecalProjector" && obj.DecalProjector) objJson["DecalProjector"] = ReflectedValueToHex(*obj.DecalProjector, registry); else if (objField.Name == "Terrain" && obj.Terrain) objJson["Terrain"] = ReflectedValueToHex(*obj.Terrain, registry); 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; else if (camField.Name == "Enabled") camJson["Enabled"] = obj.Camera->Enabled; else if (camField.Name == "ProjectionMode") camJson["ProjectionMode"] = static_cast(obj.Camera->ProjectionMode); else if (camField.Name == "OrthographicSize") camJson["OrthographicSize"] = obj.Camera->OrthographicSize; else if (camField.Name == "Depth") camJson["Depth"] = obj.Camera->Depth; else if (camField.Name == "CullingMask") camJson["CullingMask"] = obj.Camera->CullingMask; else if (camField.Name == "ClearFlags") camJson["ClearFlags"] = static_cast(obj.Camera->ClearFlags); else if (camField.Name == "BackgroundColor") camJson["BackgroundColor"] = Vec3ToJson(obj.Camera->BackgroundColor); else if (camField.Name == "BackgroundAlpha") camJson["BackgroundAlpha"] = obj.Camera->BackgroundAlpha; else if (camField.Name == "PostProcessProfileGuid") camJson["PostProcessProfileGuid"] = GuidToString(obj.Camera->PostProcessProfileGuid); } 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; } } } 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; const bool legacyNormalizedIntensity = !lightJson.contains("Type"); for (const auto& lightField : lightDesc->Fields) { if (lightField.Name == "Type" && lightJson.contains("Type")) light.Type = static_cast(lightJson["Type"].get()); else 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(); else if (lightField.Name == "Enabled" && lightJson.contains("Enabled")) light.Enabled = lightJson["Enabled"].get(); else if (lightField.Name == "UseColorTemperature" && lightJson.contains("UseColorTemperature")) light.UseColorTemperature = lightJson["UseColorTemperature"].get(); else if (lightField.Name == "ColorTemperatureKelvin" && lightJson.contains("ColorTemperatureKelvin")) light.ColorTemperatureKelvin = lightJson["ColorTemperatureKelvin"].get(); else if (lightField.Name == "Range" && lightJson.contains("Range")) light.Range = lightJson["Range"].get(); else if (lightField.Name == "InnerConeDegrees" && lightJson.contains("InnerConeDegrees")) light.InnerConeDegrees = lightJson["InnerConeDegrees"].get(); else if (lightField.Name == "OuterConeDegrees" && lightJson.contains("OuterConeDegrees")) light.OuterConeDegrees = lightJson["OuterConeDegrees"].get(); else if (lightField.Name == "FalloffExponent" && lightJson.contains("FalloffExponent")) light.FalloffExponent = lightJson["FalloffExponent"].get(); else if (lightField.Name == "CastShadows" && lightJson.contains("CastShadows")) light.CastShadows = lightJson["CastShadows"].get(); else if (lightField.Name == "ShadowBias" && lightJson.contains("ShadowBias")) light.ShadowBias = lightJson["ShadowBias"].get(); else if (lightField.Name == "ShadowNormalBias" && lightJson.contains("ShadowNormalBias")) light.ShadowNormalBias = lightJson["ShadowNormalBias"].get(); else if (lightField.Name == "ShadowPriority" && lightJson.contains("ShadowPriority")) light.ShadowPriority = lightJson["ShadowPriority"].get(); else if (lightField.Name == "LightingMask" && lightJson.contains("LightingMask")) light.LightingMask = lightJson["LightingMask"].get(); } if (legacyNormalizedIntensity) light.Intensity *= 100000.0F; obj.Light = light; } } else if (objField.Name == "Rotator" && objJson.contains("Rotator")) { const auto& rotatorJson = objJson["Rotator"]; const MetaCoreStructDescriptor* rotatorDesc = registry.FindStruct(); if (rotatorDesc) { MetaCoreRotatorComponent rotator; for (const auto& rotatorField : rotatorDesc->Fields) { if (rotatorField.Name == "Enabled" && rotatorJson.contains("Enabled")) rotator.Enabled = rotatorJson["Enabled"].get(); else if (rotatorField.Name == "DegreesPerSecond" && rotatorJson.contains("DegreesPerSecond")) rotator.DegreesPerSecond = rotatorJson["DegreesPerSecond"].get(); } obj.Rotator = rotator; } } else if (objField.Name == "Animator" && objJson.contains("Animator")) { const auto& animatorJson = objJson["Animator"]; const MetaCoreStructDescriptor* animatorDesc = registry.FindStruct(); if (animatorDesc) { MetaCoreAnimatorComponent animator; for (const auto& animatorField : animatorDesc->Fields) { if (animatorField.Name == "Enabled" && animatorJson.contains("Enabled")) animator.Enabled = animatorJson["Enabled"].get(); else if (animatorField.Name == "SourceModelAssetGuid" && animatorJson.contains("SourceModelAssetGuid")) animator.SourceModelAssetGuid = StringToGuid(animatorJson["SourceModelAssetGuid"].get()); else if (animatorField.Name == "SourceModelPath" && animatorJson.contains("SourceModelPath")) animator.SourceModelPath = animatorJson["SourceModelPath"].get(); else if (animatorField.Name == "ClipIndex" && animatorJson.contains("ClipIndex")) animator.ClipIndex = animatorJson["ClipIndex"].get(); else if (animatorField.Name == "ClipName" && animatorJson.contains("ClipName")) animator.ClipName = animatorJson["ClipName"].get(); else if (animatorField.Name == "PlayOnStart" && animatorJson.contains("PlayOnStart")) animator.PlayOnStart = animatorJson["PlayOnStart"].get(); else if (animatorField.Name == "Loop" && animatorJson.contains("Loop")) animator.Loop = animatorJson["Loop"].get(); else if (animatorField.Name == "Speed" && animatorJson.contains("Speed")) animator.Speed = animatorJson["Speed"].get(); } obj.Animator = animator; } } else if (objField.Name == "Script" && objJson.contains("Script")) { const auto& scriptJson = objJson["Script"]; MetaCoreScriptComponent script; if (scriptJson.contains("Instances") && scriptJson["Instances"].is_array()) { for (const auto& instanceJson : scriptJson["Instances"]) { MetaCoreScriptInstanceData instance; if (instanceJson.contains("InstanceId")) { instance.InstanceId = instanceJson["InstanceId"].get(); } if (instanceJson.contains("ScriptTypeId")) { instance.ScriptTypeId = instanceJson["ScriptTypeId"].get(); } if (instanceJson.contains("Enabled")) { instance.Enabled = instanceJson["Enabled"].get(); } if (instanceJson.contains("FieldsJson")) { instance.FieldsJson = instanceJson["FieldsJson"].get(); } if (!instance.ScriptTypeId.empty()) { script.Instances.push_back(std::move(instance)); } } } if (!script.Instances.empty()) { obj.Script = std::move(script); } } else if (objField.Name == "UiRenderer" && objJson.contains("UiRenderer")) { const auto& uiJson = objJson["UiRenderer"]; const MetaCoreStructDescriptor* uiDesc = registry.FindStruct(); if (uiDesc) { MetaCoreUiRendererComponent ui; for (const auto& uiField : uiDesc->Fields) { if (uiField.Name == "UiDocumentAssetGuid" && uiJson.contains("UiDocumentAssetGuid")) ui.UiDocumentAssetGuid = StringToGuid(uiJson["UiDocumentAssetGuid"].get()); else if (uiField.Name == "RenderMode" && uiJson.contains("RenderMode")) ui.RenderMode = static_cast(uiJson["RenderMode"].get()); else if (uiField.Name == "Visible" && uiJson.contains("Visible")) ui.Visible = uiJson["Visible"].get(); else if (uiField.Name == "InputEnabled" && uiJson.contains("InputEnabled")) ui.InputEnabled = uiJson["InputEnabled"].get(); else if (uiField.Name == "FaceCamera" && uiJson.contains("FaceCamera")) ui.FaceCamera = uiJson["FaceCamera"].get(); else if (uiField.Name == "Layer" && uiJson.contains("Layer")) ui.Layer = uiJson["Layer"].get(); else if (uiField.Name == "PixelsPerUnit" && uiJson.contains("PixelsPerUnit")) ui.PixelsPerUnit = uiJson["PixelsPerUnit"].get(); else if (uiField.Name == "WorldSize" && uiJson.contains("WorldSize")) ui.WorldSize = JsonToVec3(uiJson["WorldSize"]); } obj.UiRenderer = ui; } } else if (objField.Name == "Interactable" && objJson.contains("Interactable")) { const auto& value = objJson["Interactable"]; MetaCoreInteractableComponent interactable; if (value.contains("Enabled")) interactable.Enabled = value["Enabled"].get(); if (value.contains("EventMask")) interactable.EventMask = value["EventMask"].get(); if (value.contains("DragThresholdPixels")) interactable.DragThresholdPixels = value["DragThresholdPixels"].get(); obj.Interactable = interactable; } else if (objField.Name == "Collider" && objJson.contains("Collider")) { const auto& value = objJson["Collider"]; MetaCoreColliderComponent component; component.Enabled = value.value("Enabled", true); component.Shape = static_cast(value.value("Shape", 0)); if (value.contains("Center")) component.Center = JsonToVec3(value["Center"]); if (value.contains("Size")) component.Size = JsonToVec3(value["Size"]); component.Radius = value.value("Radius", 0.5F); component.Height = value.value("Height", 2.0F); if (value.contains("MeshAssetGuid")) component.MeshAssetGuid = StringToGuid(value["MeshAssetGuid"].get()); if (value.contains("MaterialAssetGuid")) component.MaterialAssetGuid = StringToGuid(value["MaterialAssetGuid"].get()); component.CollisionLayer = value.value("CollisionLayer", 0U); component.IsTrigger = value.value("IsTrigger", false); obj.Collider = component; } else if (objField.Name == "RigidBody" && objJson.contains("RigidBody")) { const auto& value = objJson["RigidBody"]; MetaCoreRigidBodyComponent component; component.BodyType = static_cast(value.value("BodyType", 0)); component.Mass = value.value("Mass", 1.0F); component.LinearDamping = value.value("LinearDamping", 0.0F); component.AngularDamping = value.value("AngularDamping", 0.05F); component.GravityScale = value.value("GravityScale", 1.0F); if (value.contains("InitialLinearVelocity")) component.InitialLinearVelocity = JsonToVec3(value["InitialLinearVelocity"]); if (value.contains("InitialAngularVelocity")) component.InitialAngularVelocity = JsonToVec3(value["InitialAngularVelocity"]); component.AllowSleep = value.value("AllowSleep", true); component.ContinuousCollisionDetection = value.value("ContinuousCollisionDetection", false); component.LockedAxes = value.value("LockedAxes", 0U); obj.RigidBody = component; } else if (objField.Name == "PhysicsConstraint" && objJson.contains("PhysicsConstraint")) { const auto& value = objJson["PhysicsConstraint"]; MetaCorePhysicsConstraintComponent component; component.Enabled = value.value("Enabled", true); component.Type = static_cast(value.value("Type", 0)); component.TargetObjectId = value.value("TargetObjectId", MetaCoreId{0}); if (value.contains("Anchor")) component.Anchor = JsonToVec3(value["Anchor"]); if (value.contains("TargetAnchor")) component.TargetAnchor = JsonToVec3(value["TargetAnchor"]); if (value.contains("Axis")) component.Axis = JsonToVec3(value["Axis"]); if (value.contains("LinearLowerLimit")) component.LinearLowerLimit = JsonToVec3(value["LinearLowerLimit"]); if (value.contains("LinearUpperLimit")) component.LinearUpperLimit = JsonToVec3(value["LinearUpperLimit"]); if (value.contains("AngularLowerLimit")) component.AngularLowerLimit = JsonToVec3(value["AngularLowerLimit"]); if (value.contains("AngularUpperLimit")) component.AngularUpperLimit = JsonToVec3(value["AngularUpperLimit"]); component.MotorEnabled = value.value("MotorEnabled", false); component.MotorTargetVelocity = value.value("MotorTargetVelocity", 0.0F); component.MotorMaxImpulse = value.value("MotorMaxImpulse", 0.0F); component.BreakForce = value.value("BreakForce", 0.0F); component.BreakTorque = value.value("BreakTorque", 0.0F); component.EnableConnectedCollision = value.value("EnableConnectedCollision", false); obj.PhysicsConstraint = component; } else if (objField.Name == "CharacterController" && objJson.contains("CharacterController")) { const auto& value = objJson["CharacterController"]; MetaCoreCharacterControllerComponent component; component.Enabled = value.value("Enabled", true); component.Radius = value.value("Radius", 0.4F); component.Height = value.value("Height", 1.8F); component.SkinWidth = value.value("SkinWidth", 0.05F); component.MaxSlopeDegrees = value.value("MaxSlopeDegrees", 45.0F); component.StepHeight = value.value("StepHeight", 0.3F); component.GravityScale = value.value("GravityScale", 1.0F); component.MaxFallSpeed = value.value("MaxFallSpeed", 55.0F); component.PushForce = value.value("PushForce", 1.0F); component.CollisionLayer = value.value("CollisionLayer", 0U); obj.CharacterController = component; } else if (objField.Name == "ReflectionProbe" && objJson.contains("ReflectionProbe")) obj.ReflectionProbe = ReflectedValueFromHex(objJson["ReflectionProbe"], registry); else if (objField.Name == "LodGroup" && objJson.contains("LodGroup")) obj.LodGroup = ReflectedValueFromHex(objJson["LodGroup"], registry); else if (objField.Name == "ParticleEmitter" && objJson.contains("ParticleEmitter")) obj.ParticleEmitter = ReflectedValueFromHex(objJson["ParticleEmitter"], registry); else if (objField.Name == "LineRenderer" && objJson.contains("LineRenderer")) obj.LineRenderer = ReflectedValueFromHex(objJson["LineRenderer"], registry); else if (objField.Name == "TrailRenderer" && objJson.contains("TrailRenderer")) obj.TrailRenderer = ReflectedValueFromHex(objJson["TrailRenderer"], registry); else if (objField.Name == "DecalProjector" && objJson.contains("DecalProjector")) obj.DecalProjector = ReflectedValueFromHex(objJson["DecalProjector"], registry); else if (objField.Name == "Terrain" && objJson.contains("Terrain")) obj.Terrain = ReflectedValueFromHex(objJson["Terrain"], registry); 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(); else if (camField.Name == "Enabled" && camJson.contains("Enabled")) cam.Enabled = camJson["Enabled"].get(); else if (camField.Name == "ProjectionMode" && camJson.contains("ProjectionMode")) cam.ProjectionMode = static_cast(camJson["ProjectionMode"].get()); else if (camField.Name == "OrthographicSize" && camJson.contains("OrthographicSize")) cam.OrthographicSize = camJson["OrthographicSize"].get(); else if (camField.Name == "Depth" && camJson.contains("Depth")) cam.Depth = camJson["Depth"].get(); else if (camField.Name == "CullingMask" && camJson.contains("CullingMask")) cam.CullingMask = camJson["CullingMask"].get(); else if (camField.Name == "ClearFlags" && camJson.contains("ClearFlags")) cam.ClearFlags = static_cast(camJson["ClearFlags"].get()); else if (camField.Name == "BackgroundColor" && camJson.contains("BackgroundColor")) cam.BackgroundColor = JsonToVec3(camJson["BackgroundColor"]); else if (camField.Name == "BackgroundAlpha" && camJson.contains("BackgroundAlpha")) cam.BackgroundAlpha = camJson["BackgroundAlpha"].get(); else if (camField.Name == "PostProcessProfileGuid" && camJson.contains("PostProcessProfileGuid")) cam.PostProcessProfileGuid = StringToGuid(camJson["PostProcessProfileGuid"].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; } } } 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 == "Environment") { sceneJson["Environment"] = SceneEnvironmentToJson(sceneDocument.Environment); } 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 == "Environment" && sceneJson.contains("Environment")) { sceneDocument.Environment = JsonToSceneEnvironment(sceneJson["Environment"]); } 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 { MetaCoreMaterialAssetDocument validated = doc; MetaCoreMaterialTemplateRegistry templates; if (!templates.ValidateAndMigrate(validated, nullptr)) return false; json matJson; matJson["AssetGuid"] = GuidToString(doc.AssetGuid); matJson["Name"] = doc.Name; matJson["StableImportKey"] = doc.StableImportKey; matJson["TemplateId"] = validated.TemplateId; matJson["TemplateVersion"] = validated.TemplateVersion; matJson["Parameters"] = json::array(); for(const auto& parameter:validated.Parameters)matJson["Parameters"].push_back({{"Name",parameter.Name},{"Type",static_cast(parameter.Type)},{"FloatValue",parameter.FloatValue},{"BoolValue",parameter.BoolValue},{"VectorValue",Vec3ToJson(parameter.VectorValue)},{"TextureValue",GuidToString(parameter.TextureValue)}}); 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(); if(matJson.contains("TemplateId"))doc.TemplateId=matJson["TemplateId"].get();else doc.TemplateId=doc.ShaderModel==MetaCoreMaterialShaderModel::PbrMetalRough?"metacore.pbr":"metacore.unlit"; if(matJson.contains("TemplateVersion"))doc.TemplateVersion=matJson["TemplateVersion"].get(); if(matJson.contains("Parameters")&&matJson["Parameters"].is_array())for(const auto& value:matJson["Parameters"]){MetaCoreMaterialParameterDocument parameter;parameter.Name=value.value("Name",std::string{});parameter.Type=static_cast(value.value("Type",0));parameter.FloatValue=value.value("FloatValue",0.0F);parameter.BoolValue=value.value("BoolValue",false);if(value.contains("VectorValue"))parameter.VectorValue=JsonToVec3(value["VectorValue"]);if(value.contains("TextureValue"))parameter.TextureValue=StringToGuid(value["TextureValue"].get());doc.Parameters.push_back(std::move(parameter));} MetaCoreMaterialTemplateRegistry templates;if(!templates.ValidateAndMigrate(doc,nullptr))return std::nullopt; 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; j["Action"] = node.Action; j["DataBinding"] = node.DataBinding; j["DataFormat"] = node.DataFormat; 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(); if (j.contains("Action")) node.Action = j["Action"].get(); if (j.contains("DataBinding")) node.DataBinding = j["DataBinding"].get(); if (j.contains("DataFormat")) node.DataFormat = j["DataFormat"].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["BackgroundColor"] = Vec3ToJson(uiDocument.BackgroundColor); uiJson["BackgroundAlpha"] = uiDocument.BackgroundAlpha; 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("BackgroundColor")) doc.BackgroundColor = JsonToVec3(uiJson["BackgroundColor"]); if (uiJson.contains("BackgroundAlpha")) doc.BackgroundAlpha = uiJson["BackgroundAlpha"].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