18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci 168bf80f4bSopenharmony_ci// This is bit unfortunate construct, clean up once there is one agreed implementation of JSON somewhere 178bf80f4bSopenharmony_ci#include <PropertyTools/property_data.h> 188bf80f4bSopenharmony_ci#define JSON_IMPL // have template specialisation defined once 198bf80f4bSopenharmony_ci#include <algorithm> 208bf80f4bSopenharmony_ci#include <charconv> 218bf80f4bSopenharmony_ci#include <cinttypes> 228bf80f4bSopenharmony_ci 238bf80f4bSopenharmony_ci#include <3d/ecs/components/name_component.h> 248bf80f4bSopenharmony_ci#include <3d/ecs/components/render_handle_component.h> 258bf80f4bSopenharmony_ci#include <base/util/base64_decode.h> 268bf80f4bSopenharmony_ci#include <base/util/base64_encode.h> 278bf80f4bSopenharmony_ci#include <base/util/uid_util.h> 288bf80f4bSopenharmony_ci#include <core/ecs/intf_component_manager.h> 298bf80f4bSopenharmony_ci#include <core/ecs/intf_entity_manager.h> 308bf80f4bSopenharmony_ci#include <core/image/intf_image_loader_manager.h> 318bf80f4bSopenharmony_ci#include <core/intf_engine.h> 328bf80f4bSopenharmony_ci#include <core/property/intf_property_handle.h> 338bf80f4bSopenharmony_ci#include <render/device/intf_gpu_resource_manager.h> 348bf80f4bSopenharmony_ci#include <render/device/intf_shader_manager.h> 358bf80f4bSopenharmony_ci#include <render/util/intf_render_util.h> 368bf80f4bSopenharmony_ci 378bf80f4bSopenharmony_ci#include "asset_loader.h" 388bf80f4bSopenharmony_ci#include "ecs_serializer.h" 398bf80f4bSopenharmony_ci#include "ecs_util.h" 408bf80f4bSopenharmony_ci#include "entity_collection.h" 418bf80f4bSopenharmony_ci#include "json.h" 428bf80f4bSopenharmony_ci#include "json_util.h" 438bf80f4bSopenharmony_ci 448bf80f4bSopenharmony_ciusing namespace BASE_NS; 458bf80f4bSopenharmony_ciusing namespace CORE_NS; 468bf80f4bSopenharmony_ciusing namespace RENDER_NS; 478bf80f4bSopenharmony_ciusing namespace CORE3D_NS; 488bf80f4bSopenharmony_ci 498bf80f4bSopenharmony_ci// #define VERBOSE_LOGGING 508bf80f4bSopenharmony_ciSCENE_BEGIN_NAMESPACE() 518bf80f4bSopenharmony_ci 528bf80f4bSopenharmony_cinamespace { 538bf80f4bSopenharmony_ci 548bf80f4bSopenharmony_ci// Helper function that makes sure that any dynamic arrays referenced in a property path are large enough to contain the 558bf80f4bSopenharmony_ci// referenced indices. 568bf80f4bSopenharmony_civoid EnsureDynamicArraySize(IPropertyHandle* propertyHandle, string_view propertyPath) 578bf80f4bSopenharmony_ci{ 588bf80f4bSopenharmony_ci const auto separatorPosition = propertyPath.find('['); 598bf80f4bSopenharmony_ci if (separatorPosition == BASE_NS::string::npos) { 608bf80f4bSopenharmony_ci return; 618bf80f4bSopenharmony_ci } 628bf80f4bSopenharmony_ci const auto separatorEndPosition = propertyPath.find(']', separatorPosition); 638bf80f4bSopenharmony_ci if (separatorEndPosition == BASE_NS::string::npos) { 648bf80f4bSopenharmony_ci return; 658bf80f4bSopenharmony_ci } 668bf80f4bSopenharmony_ci 678bf80f4bSopenharmony_ci string arrayPath, arrayIndex; 688bf80f4bSopenharmony_ci arrayPath = propertyPath.substr(0, separatorPosition); 698bf80f4bSopenharmony_ci arrayIndex = propertyPath.substr(separatorPosition + 1, separatorEndPosition - separatorPosition - 1); 708bf80f4bSopenharmony_ci 718bf80f4bSopenharmony_ci char* end = nullptr; 728bf80f4bSopenharmony_ci const unsigned long index = std::strtoul(arrayIndex.c_str(), &end, 10); // 10: base 738bf80f4bSopenharmony_ci // Check that conversion stopped at the end of the string. 748bf80f4bSopenharmony_ci if (!end || *end != '\0') { 758bf80f4bSopenharmony_ci return; 768bf80f4bSopenharmony_ci } 778bf80f4bSopenharmony_ci 788bf80f4bSopenharmony_ci PropertyData propertyData; 798bf80f4bSopenharmony_ci PropertyData::PropertyOffset propertyOffset = propertyData.WLock(*propertyHandle, arrayPath); 808bf80f4bSopenharmony_ci if (propertyOffset) { 818bf80f4bSopenharmony_ci auto* containerMethods = propertyOffset.property->metaData.containerMethods; 828bf80f4bSopenharmony_ci if (containerMethods && containerMethods->resize) { 838bf80f4bSopenharmony_ci if (containerMethods->size(propertyOffset.offset) <= index) { 848bf80f4bSopenharmony_ci containerMethods->resize(propertyOffset.offset, index + 1); 858bf80f4bSopenharmony_ci } 868bf80f4bSopenharmony_ci } 878bf80f4bSopenharmony_ci } 888bf80f4bSopenharmony_ci 898bf80f4bSopenharmony_ci const auto restOfThePath = propertyPath.substr(separatorEndPosition); 908bf80f4bSopenharmony_ci EnsureDynamicArraySize(&propertyData, restOfThePath); 918bf80f4bSopenharmony_ci} 928bf80f4bSopenharmony_ci 938bf80f4bSopenharmony_citemplate<typename Type> 948bf80f4bSopenharmony_ciType& GetPropertyValue(uintptr_t ptr) 958bf80f4bSopenharmony_ci{ 968bf80f4bSopenharmony_ci return *reinterpret_cast<Type*>(ptr); 978bf80f4bSopenharmony_ci} 988bf80f4bSopenharmony_ci 998bf80f4bSopenharmony_cistruct IoUtil { 1008bf80f4bSopenharmony_ci struct CompatibilityInfo { 1018bf80f4bSopenharmony_ci uint32_t versionMajor { 0 }; 1028bf80f4bSopenharmony_ci uint32_t versionMinor { 0 }; 1038bf80f4bSopenharmony_ci BASE_NS::string type; 1048bf80f4bSopenharmony_ci }; 1058bf80f4bSopenharmony_ci 1068bf80f4bSopenharmony_ci struct CompatibilityRange { 1078bf80f4bSopenharmony_ci static const uint32_t IGNORE_VERSION = { ~0u }; 1088bf80f4bSopenharmony_ci 1098bf80f4bSopenharmony_ci uint32_t versionMajorMin { IGNORE_VERSION }; 1108bf80f4bSopenharmony_ci uint32_t versionMajorMax { IGNORE_VERSION }; 1118bf80f4bSopenharmony_ci uint32_t versionMinorMin { IGNORE_VERSION }; 1128bf80f4bSopenharmony_ci uint32_t versionMinorMax { IGNORE_VERSION }; 1138bf80f4bSopenharmony_ci BASE_NS::string type {}; 1148bf80f4bSopenharmony_ci }; 1158bf80f4bSopenharmony_ci 1168bf80f4bSopenharmony_ci static bool WriteCompatibilityInfo(json::standalone_value& jsonOut, const CompatibilityInfo& info) 1178bf80f4bSopenharmony_ci { 1188bf80f4bSopenharmony_ci jsonOut["compatibility_info"] = json::standalone_value::object(); 1198bf80f4bSopenharmony_ci jsonOut["compatibility_info"]["version"] = 1208bf80f4bSopenharmony_ci string(to_string(info.versionMajor) + "." + to_string(info.versionMinor)); 1218bf80f4bSopenharmony_ci jsonOut["compatibility_info"]["type"] = string(info.type); 1228bf80f4bSopenharmony_ci return true; 1238bf80f4bSopenharmony_ci } 1248bf80f4bSopenharmony_ci 1258bf80f4bSopenharmony_ci static bool CheckCompatibility(const json::value& json, array_view<CompatibilityRange const> validVersions) 1268bf80f4bSopenharmony_ci { 1278bf80f4bSopenharmony_ci string type; 1288bf80f4bSopenharmony_ci string version; 1298bf80f4bSopenharmony_ci if (const json::value* iter = json.find("compatibility_info"); iter) { 1308bf80f4bSopenharmony_ci string parseError; 1318bf80f4bSopenharmony_ci SafeGetJsonValue(*iter, "type", parseError, type); 1328bf80f4bSopenharmony_ci SafeGetJsonValue(*iter, "version", parseError, version); 1338bf80f4bSopenharmony_ci 1348bf80f4bSopenharmony_ci uint32_t versionMajor { 0 }; 1358bf80f4bSopenharmony_ci uint32_t versionMinor { 0 }; 1368bf80f4bSopenharmony_ci if (const auto delim = version.find('.'); delim != string::npos) { 1378bf80f4bSopenharmony_ci std::from_chars(version.data(), version.data() + delim, versionMajor); 1388bf80f4bSopenharmony_ci const size_t minorStart = delim + 1; 1398bf80f4bSopenharmony_ci std::from_chars(version.data() + minorStart, version.data() + version.size(), versionMinor); 1408bf80f4bSopenharmony_ci } else { 1418bf80f4bSopenharmony_ci std::from_chars(version.data(), version.data() + version.size(), versionMajor); 1428bf80f4bSopenharmony_ci } 1438bf80f4bSopenharmony_ci 1448bf80f4bSopenharmony_ci for (const auto& range : validVersions) { 1458bf80f4bSopenharmony_ci if (type != range.type) { 1468bf80f4bSopenharmony_ci continue; 1478bf80f4bSopenharmony_ci } 1488bf80f4bSopenharmony_ci if ((range.versionMajorMin != CompatibilityRange::IGNORE_VERSION) && 1498bf80f4bSopenharmony_ci (versionMajor < range.versionMajorMin)) { 1508bf80f4bSopenharmony_ci continue; 1518bf80f4bSopenharmony_ci } 1528bf80f4bSopenharmony_ci if ((range.versionMajorMax != CompatibilityRange::IGNORE_VERSION) && 1538bf80f4bSopenharmony_ci (versionMajor > range.versionMajorMax)) { 1548bf80f4bSopenharmony_ci continue; 1558bf80f4bSopenharmony_ci } 1568bf80f4bSopenharmony_ci if ((range.versionMinorMin != CompatibilityRange::IGNORE_VERSION) && 1578bf80f4bSopenharmony_ci (versionMinor < range.versionMinorMin)) { 1588bf80f4bSopenharmony_ci continue; 1598bf80f4bSopenharmony_ci } 1608bf80f4bSopenharmony_ci if ((range.versionMinorMax != CompatibilityRange::IGNORE_VERSION) && 1618bf80f4bSopenharmony_ci (versionMinor > range.versionMinorMax)) { 1628bf80f4bSopenharmony_ci continue; 1638bf80f4bSopenharmony_ci } 1648bf80f4bSopenharmony_ci 1658bf80f4bSopenharmony_ci // A compatible version was found from the list of valid versions. 1668bf80f4bSopenharmony_ci return true; 1678bf80f4bSopenharmony_ci } 1688bf80f4bSopenharmony_ci } 1698bf80f4bSopenharmony_ci 1708bf80f4bSopenharmony_ci // Not a compatible version. 1718bf80f4bSopenharmony_ci return false; 1728bf80f4bSopenharmony_ci } 1738bf80f4bSopenharmony_ci}; 1748bf80f4bSopenharmony_ci} // namespace 1758bf80f4bSopenharmony_ci 1768bf80f4bSopenharmony_ci// 1778bf80f4bSopenharmony_ci// EcsSerializer::SimpleJsonSerializer 1788bf80f4bSopenharmony_ci// 1798bf80f4bSopenharmony_cibool EcsSerializer::SimpleJsonSerializer::ToJson( 1808bf80f4bSopenharmony_ci const IEntityCollection& ec, const Property& property, uintptr_t offset, json::standalone_value& jsonOut) const 1818bf80f4bSopenharmony_ci{ 1828bf80f4bSopenharmony_ci return PropertyToJson(ec, property, offset, jsonOut); 1838bf80f4bSopenharmony_ci} 1848bf80f4bSopenharmony_ci 1858bf80f4bSopenharmony_cibool EcsSerializer::SimpleJsonSerializer::FromJson( 1868bf80f4bSopenharmony_ci const IEntityCollection& ec, const json::value& jsonIn, const Property& property, uintptr_t offset) const 1878bf80f4bSopenharmony_ci{ 1888bf80f4bSopenharmony_ci return PropertyFromJson(ec, jsonIn, property, offset); 1898bf80f4bSopenharmony_ci} 1908bf80f4bSopenharmony_ci 1918bf80f4bSopenharmony_ciEcsSerializer::SimpleJsonSerializer::SimpleJsonSerializer(PropertyToJsonFunc toJson, PropertyFromJsonFunc fromJson) 1928bf80f4bSopenharmony_ci : PropertyToJson(toJson), PropertyFromJson(fromJson) 1938bf80f4bSopenharmony_ci{} 1948bf80f4bSopenharmony_ci 1958bf80f4bSopenharmony_ci// 1968bf80f4bSopenharmony_ci// EcsSerializer 1978bf80f4bSopenharmony_ci// 1988bf80f4bSopenharmony_ciEcsSerializer::EcsSerializer(RENDER_NS::IRenderContext& renderContext) : renderContext_(renderContext) {} 1998bf80f4bSopenharmony_ci 2008bf80f4bSopenharmony_ciEcsSerializer::IPropertySerializer& EcsSerializer::Add(PropertyToJsonFunc toJson, PropertyFromJsonFunc fromJson) 2018bf80f4bSopenharmony_ci{ 2028bf80f4bSopenharmony_ci auto serializer = new SimpleJsonSerializer(toJson, fromJson); 2038bf80f4bSopenharmony_ci auto ptr = unique_ptr<SimpleJsonSerializer> { serializer }; 2048bf80f4bSopenharmony_ci ownedSerializers_.emplace_back(move(ptr)); 2058bf80f4bSopenharmony_ci return *ownedSerializers_.back(); 2068bf80f4bSopenharmony_ci} 2078bf80f4bSopenharmony_ci 2088bf80f4bSopenharmony_cinamespace { 2098bf80f4bSopenharmony_citemplate<class Type> 2108bf80f4bSopenharmony_cibool PropertyToJson( 2118bf80f4bSopenharmony_ci const IEntityCollection& /*ec*/, const Property& /*property*/, uintptr_t offset, json::standalone_value& jsonOut) 2128bf80f4bSopenharmony_ci{ 2138bf80f4bSopenharmony_ci jsonOut = ToJson(GetPropertyValue<Type>(offset)); 2148bf80f4bSopenharmony_ci return true; 2158bf80f4bSopenharmony_ci} 2168bf80f4bSopenharmony_ci 2178bf80f4bSopenharmony_citemplate<class Type> 2188bf80f4bSopenharmony_cibool PropertyFromJson( 2198bf80f4bSopenharmony_ci const IEntityCollection& /*ec*/, const json::value& jsonIn, const Property& /*property*/, uintptr_t offset) 2208bf80f4bSopenharmony_ci{ 2218bf80f4bSopenharmony_ci auto& value = GetPropertyValue<Type>(offset); 2228bf80f4bSopenharmony_ci return FromJson(jsonIn, value); 2238bf80f4bSopenharmony_ci} 2248bf80f4bSopenharmony_ci 2258bf80f4bSopenharmony_cibool RenderHandleReferenceFromJson(const IEcsSerializer& ecsSerializer, IRenderContext& renderContext, 2268bf80f4bSopenharmony_ci const IEntityCollection& ec, const json::value& jsonIn, RenderHandleReference& handleRefOut) 2278bf80f4bSopenharmony_ci{ 2288bf80f4bSopenharmony_ci CORE_UNUSED(ec); 2298bf80f4bSopenharmony_ci 2308bf80f4bSopenharmony_ci if (!jsonIn.is_object()) { 2318bf80f4bSopenharmony_ci return false; 2328bf80f4bSopenharmony_ci } 2338bf80f4bSopenharmony_ci 2348bf80f4bSopenharmony_ci string error; 2358bf80f4bSopenharmony_ci RenderHandleDesc desc; 2368bf80f4bSopenharmony_ci 2378bf80f4bSopenharmony_ci // Casting to enum directly from numeric value is a bit fishy. 2388bf80f4bSopenharmony_ci uint32_t type = 0; 2398bf80f4bSopenharmony_ci if (!SafeGetJsonValue(jsonIn, "type", error, type)) { 2408bf80f4bSopenharmony_ci return false; 2418bf80f4bSopenharmony_ci } 2428bf80f4bSopenharmony_ci desc.type = static_cast<RenderHandleType>(type); 2438bf80f4bSopenharmony_ci 2448bf80f4bSopenharmony_ci if (!SafeGetJsonValue(jsonIn, "name", error, desc.name)) { 2458bf80f4bSopenharmony_ci return false; 2468bf80f4bSopenharmony_ci } 2478bf80f4bSopenharmony_ci 2488bf80f4bSopenharmony_ci SafeGetJsonValue(jsonIn, "additionalName", error, desc.additionalName); 2498bf80f4bSopenharmony_ci 2508bf80f4bSopenharmony_ci auto& renderUtil = renderContext.GetRenderUtil(); 2518bf80f4bSopenharmony_ci handleRefOut = renderUtil.GetRenderHandle(desc); 2528bf80f4bSopenharmony_ci 2538bf80f4bSopenharmony_ci if (!handleRefOut && desc.type == RenderHandleType::GPU_IMAGE && !desc.name.empty()) { 2548bf80f4bSopenharmony_ci // Special handling for images: Load the image if it was not already loaded. 2558bf80f4bSopenharmony_ci // Note: assuming that the name is the image uri. 2568bf80f4bSopenharmony_ci handleRefOut = ecsSerializer.LoadImageResource(desc.name); 2578bf80f4bSopenharmony_ci } 2588bf80f4bSopenharmony_ci 2598bf80f4bSopenharmony_ci return true; 2608bf80f4bSopenharmony_ci} 2618bf80f4bSopenharmony_ci 2628bf80f4bSopenharmony_cibool RenderHandleReferenceToJson(IRenderContext& renderContext, const IEntityCollection& ec, 2638bf80f4bSopenharmony_ci const RenderHandleReference& handleRefIn, json::standalone_value& jsonOut) 2648bf80f4bSopenharmony_ci{ 2658bf80f4bSopenharmony_ci CORE_UNUSED(ec); 2668bf80f4bSopenharmony_ci 2678bf80f4bSopenharmony_ci auto& renderUtil = renderContext.GetRenderUtil(); 2688bf80f4bSopenharmony_ci const auto desc = renderUtil.GetRenderHandleDesc(handleRefIn); 2698bf80f4bSopenharmony_ci 2708bf80f4bSopenharmony_ci jsonOut = json::standalone_value::object {}; 2718bf80f4bSopenharmony_ci jsonOut["type"] = static_cast<unsigned int>(desc.type); 2728bf80f4bSopenharmony_ci jsonOut["name"] = string(desc.name); 2738bf80f4bSopenharmony_ci if (!desc.additionalName.empty()) { 2748bf80f4bSopenharmony_ci jsonOut["additionalName"] = string(desc.additionalName); 2758bf80f4bSopenharmony_ci } 2768bf80f4bSopenharmony_ci 2778bf80f4bSopenharmony_ci return true; 2788bf80f4bSopenharmony_ci} 2798bf80f4bSopenharmony_ci 2808bf80f4bSopenharmony_cibool EntityFromJson(const IEntityCollection& ec, const json::value& jsonIn, Entity& entityOut) 2818bf80f4bSopenharmony_ci{ 2828bf80f4bSopenharmony_ci // Figure out to what entity id a piece of json refers to and handle error cases. 2838bf80f4bSopenharmony_ci Entity entity {}; 2848bf80f4bSopenharmony_ci if (jsonIn.is_unsigned_int()) { 2858bf80f4bSopenharmony_ci const auto entityReference = static_cast<uint32_t>(jsonIn.unsigned_); 2868bf80f4bSopenharmony_ci entity = ec.GetEntity(entityReference); 2878bf80f4bSopenharmony_ci if (entity == Entity {}) { 2888bf80f4bSopenharmony_ci CORE_LOG_W("Component entity not found for index: %u", entityReference); 2898bf80f4bSopenharmony_ci return false; 2908bf80f4bSopenharmony_ci } 2918bf80f4bSopenharmony_ci } else if (jsonIn.is_string()) { 2928bf80f4bSopenharmony_ci string entityReferenceString; 2938bf80f4bSopenharmony_ci if (FromJson(jsonIn, entityReferenceString)) { 2948bf80f4bSopenharmony_ci entity = ec.GetEntity(entityReferenceString); 2958bf80f4bSopenharmony_ci } 2968bf80f4bSopenharmony_ci if (entity == Entity {}) { 2978bf80f4bSopenharmony_ci CORE_LOG_W("Component entity not found for id: '%s'", entityReferenceString.c_str()); 2988bf80f4bSopenharmony_ci return false; 2998bf80f4bSopenharmony_ci } 3008bf80f4bSopenharmony_ci } else if (jsonIn.is_object()) { 3018bf80f4bSopenharmony_ci // Empty object means "null ref". 3028bf80f4bSopenharmony_ci if (jsonIn.empty()) { 3038bf80f4bSopenharmony_ci entityOut = Entity {}; 3048bf80f4bSopenharmony_ci return true; 3058bf80f4bSopenharmony_ci } 3068bf80f4bSopenharmony_ci 3078bf80f4bSopenharmony_ci // Figure out the correct collection (Recursive). 3088bf80f4bSopenharmony_ci const IEntityCollection* collection { nullptr }; 3098bf80f4bSopenharmony_ci const auto* collectionJson = jsonIn.find("collection"); 3108bf80f4bSopenharmony_ci if (collectionJson) { 3118bf80f4bSopenharmony_ci if (collectionJson->is_string()) { 3128bf80f4bSopenharmony_ci string collectionName; 3138bf80f4bSopenharmony_ci if (FromJson(*collectionJson, collectionName)) { 3148bf80f4bSopenharmony_ci if (auto index = ec.GetSubCollectionIndex(collectionName); index >= 0) { 3158bf80f4bSopenharmony_ci collection = ec.GetSubCollection(static_cast<size_t>(index)); 3168bf80f4bSopenharmony_ci } 3178bf80f4bSopenharmony_ci } 3188bf80f4bSopenharmony_ci if (!collection) { 3198bf80f4bSopenharmony_ci CORE_LOG_W("Collection not found: '%s'", collectionName.c_str()); 3208bf80f4bSopenharmony_ci return false; 3218bf80f4bSopenharmony_ci } 3228bf80f4bSopenharmony_ci 3238bf80f4bSopenharmony_ci } else if (collectionJson->is_unsigned_int()) { 3248bf80f4bSopenharmony_ci const auto collectionIndex = collectionJson->unsigned_; 3258bf80f4bSopenharmony_ci if (collectionIndex < ec.GetSubCollectionCount()) { 3268bf80f4bSopenharmony_ci collection = ec.GetSubCollection(collectionIndex); 3278bf80f4bSopenharmony_ci } else { 3288bf80f4bSopenharmony_ci CORE_LOG_W("Collection not found: %" PRIu64, collectionIndex); 3298bf80f4bSopenharmony_ci return false; 3308bf80f4bSopenharmony_ci } 3318bf80f4bSopenharmony_ci 3328bf80f4bSopenharmony_ci } else { 3338bf80f4bSopenharmony_ci CORE_LOG_W("Invalid collection for a component."); 3348bf80f4bSopenharmony_ci return false; 3358bf80f4bSopenharmony_ci } 3368bf80f4bSopenharmony_ci 3378bf80f4bSopenharmony_ci if (collection) { 3388bf80f4bSopenharmony_ci const auto* entityJson = jsonIn.find("entity"); 3398bf80f4bSopenharmony_ci if (entityJson) { 3408bf80f4bSopenharmony_ci return EntityFromJson(*collection, *entityJson, entityOut); 3418bf80f4bSopenharmony_ci } 3428bf80f4bSopenharmony_ci } 3438bf80f4bSopenharmony_ci return false; 3448bf80f4bSopenharmony_ci } 3458bf80f4bSopenharmony_ci 3468bf80f4bSopenharmony_ci } else { 3478bf80f4bSopenharmony_ci CORE_LOG_W("Component entity property must be an index to the entities array, an string id, or an object"); 3488bf80f4bSopenharmony_ci return false; 3498bf80f4bSopenharmony_ci } 3508bf80f4bSopenharmony_ci 3518bf80f4bSopenharmony_ci entityOut = entity; 3528bf80f4bSopenharmony_ci return true; 3538bf80f4bSopenharmony_ci} 3548bf80f4bSopenharmony_ci 3558bf80f4bSopenharmony_cibool EntityToJson(const IEntityCollection& ec, const Entity& entityIn, json::standalone_value& jsonOut) 3568bf80f4bSopenharmony_ci{ 3578bf80f4bSopenharmony_ci // Write entity index/name if part of this collection. 3588bf80f4bSopenharmony_ci const auto entityCount = ec.GetEntityCount(); 3598bf80f4bSopenharmony_ci for (size_t i = 0; i < entityCount; ++i) { 3608bf80f4bSopenharmony_ci if (entityIn == ec.GetEntity(i)) { 3618bf80f4bSopenharmony_ci auto id = ec.GetId(entityIn); 3628bf80f4bSopenharmony_ci if (!id.empty()) { 3638bf80f4bSopenharmony_ci jsonOut = string(id); 3648bf80f4bSopenharmony_ci } else { 3658bf80f4bSopenharmony_ci jsonOut = i; 3668bf80f4bSopenharmony_ci } 3678bf80f4bSopenharmony_ci return true; 3688bf80f4bSopenharmony_ci } 3698bf80f4bSopenharmony_ci } 3708bf80f4bSopenharmony_ci 3718bf80f4bSopenharmony_ci // Otherwise check sub-collections recursively. 3728bf80f4bSopenharmony_ci const auto collectionCount = ec.GetSubCollectionCount(); 3738bf80f4bSopenharmony_ci size_t collectionId = 0; 3748bf80f4bSopenharmony_ci for (size_t i = 0; i < collectionCount; ++i) { 3758bf80f4bSopenharmony_ci auto* collection = ec.GetSubCollection(i); 3768bf80f4bSopenharmony_ci BASE_ASSERT(collection); 3778bf80f4bSopenharmony_ci // NOTE: Skipping over destroyed collections (same needs to be done when writing the actual collections). 3788bf80f4bSopenharmony_ci if (collection->IsMarkedDestroyed() || !collection->IsSerialized()) { 3798bf80f4bSopenharmony_ci continue; 3808bf80f4bSopenharmony_ci } 3818bf80f4bSopenharmony_ci json::standalone_value entityJson; 3828bf80f4bSopenharmony_ci if (EntityToJson(*collection, entityIn, entityJson)) { 3838bf80f4bSopenharmony_ci jsonOut = json::standalone_value::object {}; 3848bf80f4bSopenharmony_ci jsonOut[string_view { "collection" }] = collectionId; 3858bf80f4bSopenharmony_ci jsonOut[string_view { "entity" }] = move(entityJson); 3868bf80f4bSopenharmony_ci return true; 3878bf80f4bSopenharmony_ci } 3888bf80f4bSopenharmony_ci collectionId++; 3898bf80f4bSopenharmony_ci } 3908bf80f4bSopenharmony_ci 3918bf80f4bSopenharmony_ci return false; 3928bf80f4bSopenharmony_ci} 3938bf80f4bSopenharmony_ci 3948bf80f4bSopenharmony_cibool EntityReferenceToJson(IRenderContext& renderContext, const IEntityCollection& ec, const EntityReference& entityIn, 3958bf80f4bSopenharmony_ci json::standalone_value& jsonOut) 3968bf80f4bSopenharmony_ci{ 3978bf80f4bSopenharmony_ci if (EntityToJson(ec, entityIn, jsonOut)) { 3988bf80f4bSopenharmony_ci return true; 3998bf80f4bSopenharmony_ci } 4008bf80f4bSopenharmony_ci 4018bf80f4bSopenharmony_ci // Write render handle reference as render handle desc. 4028bf80f4bSopenharmony_ci auto* rhm = GetManager<IRenderHandleComponentManager>(ec.GetEcs()); 4038bf80f4bSopenharmony_ci if (rhm) { 4048bf80f4bSopenharmony_ci if (auto handle = rhm->Read(entityIn); handle) { 4058bf80f4bSopenharmony_ci json::standalone_value renderHandleJson = json::standalone_value::object {}; 4068bf80f4bSopenharmony_ci if (RenderHandleReferenceToJson(renderContext, ec, handle->reference, renderHandleJson["renderHandle"])) { 4078bf80f4bSopenharmony_ci jsonOut = move(renderHandleJson); 4088bf80f4bSopenharmony_ci return true; 4098bf80f4bSopenharmony_ci } 4108bf80f4bSopenharmony_ci } 4118bf80f4bSopenharmony_ci } 4128bf80f4bSopenharmony_ci 4138bf80f4bSopenharmony_ci return false; 4148bf80f4bSopenharmony_ci} 4158bf80f4bSopenharmony_ci 4168bf80f4bSopenharmony_cibool EntityReferenceFromJson(const IEcsSerializer& ecsSerializer, IRenderContext& renderContext, 4178bf80f4bSopenharmony_ci const IEntityCollection& ec, const json::value& jsonIn, EntityReference& entityOut) 4188bf80f4bSopenharmony_ci{ 4198bf80f4bSopenharmony_ci // A generic handler for any uri to a render handle. 4208bf80f4bSopenharmony_ci const auto* renderHandleJson = jsonIn.find("renderHandle"); 4218bf80f4bSopenharmony_ci if (renderHandleJson) { 4228bf80f4bSopenharmony_ci // Find a shader render handle by desc. 4238bf80f4bSopenharmony_ci RenderHandleReference renderHandle; 4248bf80f4bSopenharmony_ci if (RenderHandleReferenceFromJson(ecsSerializer, renderContext, ec, *renderHandleJson, renderHandle)) { 4258bf80f4bSopenharmony_ci auto* rhm = GetManager<IRenderHandleComponentManager>(ec.GetEcs()); 4268bf80f4bSopenharmony_ci if (rhm && renderHandle) { 4278bf80f4bSopenharmony_ci entityOut = GetOrCreateEntityReference(ec.GetEcs().GetEntityManager(), *rhm, renderHandle); 4288bf80f4bSopenharmony_ci return true; 4298bf80f4bSopenharmony_ci } 4308bf80f4bSopenharmony_ci } 4318bf80f4bSopenharmony_ci } 4328bf80f4bSopenharmony_ci 4338bf80f4bSopenharmony_ci Entity temp; 4348bf80f4bSopenharmony_ci if (!EntityFromJson(ec, jsonIn, temp)) { 4358bf80f4bSopenharmony_ci return false; 4368bf80f4bSopenharmony_ci } 4378bf80f4bSopenharmony_ci entityOut = ec.GetEcs().GetEntityManager().GetReferenceCounted(temp); 4388bf80f4bSopenharmony_ci return true; 4398bf80f4bSopenharmony_ci} 4408bf80f4bSopenharmony_ci} // namespace 4418bf80f4bSopenharmony_ci 4428bf80f4bSopenharmony_civoid EcsSerializer::SetDefaultSerializers() 4438bf80f4bSopenharmony_ci{ 4448bf80f4bSopenharmony_ci // 4458bf80f4bSopenharmony_ci // Basic types (for types that nlohman knows how to serialize). 4468bf80f4bSopenharmony_ci // 4478bf80f4bSopenharmony_ci 4488bf80f4bSopenharmony_ci SetSerializer(PropertyType::FLOAT_T, Add(PropertyToJson<float>, PropertyFromJson<float>)); 4498bf80f4bSopenharmony_ci SetSerializer(PropertyType::DOUBLE_T, Add(PropertyToJson<double>, PropertyFromJson<double>)); 4508bf80f4bSopenharmony_ci 4518bf80f4bSopenharmony_ci SetSerializer(PropertyType::UINT8_T, Add(PropertyToJson<uint8_t>, PropertyFromJson<uint8_t>)); 4528bf80f4bSopenharmony_ci SetSerializer(PropertyType::UINT16_T, Add(PropertyToJson<uint16_t>, PropertyFromJson<uint16_t>)); 4538bf80f4bSopenharmony_ci SetSerializer(PropertyType::UINT32_T, Add(PropertyToJson<uint32_t>, PropertyFromJson<uint32_t>)); 4548bf80f4bSopenharmony_ci SetSerializer(PropertyType::UINT64_T, Add(PropertyToJson<uint64_t>, PropertyFromJson<uint64_t>)); 4558bf80f4bSopenharmony_ci 4568bf80f4bSopenharmony_ci SetSerializer(PropertyType::INT8_T, Add(PropertyToJson<int8_t>, PropertyFromJson<int8_t>)); 4578bf80f4bSopenharmony_ci SetSerializer(PropertyType::INT16_T, Add(PropertyToJson<int16_t>, PropertyFromJson<int16_t>)); 4588bf80f4bSopenharmony_ci SetSerializer(PropertyType::INT32_T, Add(PropertyToJson<int32_t>, PropertyFromJson<int32_t>)); 4598bf80f4bSopenharmony_ci SetSerializer(PropertyType::INT64_T, Add(PropertyToJson<int64_t>, PropertyFromJson<int64_t>)); 4608bf80f4bSopenharmony_ci 4618bf80f4bSopenharmony_ci SetSerializer(PropertyType::VEC2_T, Add(PropertyToJson<Math::Vec2>, PropertyFromJson<Math::Vec2>)); 4628bf80f4bSopenharmony_ci SetSerializer(PropertyType::VEC3_T, Add(PropertyToJson<Math::Vec3>, PropertyFromJson<Math::Vec3>)); 4638bf80f4bSopenharmony_ci SetSerializer(PropertyType::VEC4_T, Add(PropertyToJson<Math::Vec4>, PropertyFromJson<Math::Vec4>)); 4648bf80f4bSopenharmony_ci 4658bf80f4bSopenharmony_ci SetSerializer(PropertyType::UVEC2_T, Add(PropertyToJson<Math::UVec2>, PropertyFromJson<Math::UVec2>)); 4668bf80f4bSopenharmony_ci SetSerializer(PropertyType::UVEC3_T, Add(PropertyToJson<Math::UVec3>, PropertyFromJson<Math::UVec3>)); 4678bf80f4bSopenharmony_ci SetSerializer(PropertyType::UVEC4_T, Add(PropertyToJson<Math::UVec4>, PropertyFromJson<Math::UVec4>)); 4688bf80f4bSopenharmony_ci 4698bf80f4bSopenharmony_ci SetSerializer(PropertyType::BOOL_T, Add(PropertyToJson<bool>, PropertyFromJson<bool>)); 4708bf80f4bSopenharmony_ci SetSerializer(PropertyType::QUAT_T, Add(PropertyToJson<Math::Quat>, PropertyFromJson<Math::Quat>)); 4718bf80f4bSopenharmony_ci SetSerializer(PropertyType::UID_T, Add(PropertyToJson<Uid>, PropertyFromJson<Uid>)); 4728bf80f4bSopenharmony_ci 4738bf80f4bSopenharmony_ci SetSerializer(PropertyType::STRING_T, Add(PropertyToJson<string>, PropertyFromJson<string>)); 4748bf80f4bSopenharmony_ci 4758bf80f4bSopenharmony_ci // 4768bf80f4bSopenharmony_ci // Others 4778bf80f4bSopenharmony_ci // 4788bf80f4bSopenharmony_ci 4798bf80f4bSopenharmony_ci SetSerializer(PropertyType::CHAR_ARRAY_T, 4808bf80f4bSopenharmony_ci Add( 4818bf80f4bSopenharmony_ci [](const IEntityCollection& /*ec*/, const Property& property, uintptr_t offset, 4828bf80f4bSopenharmony_ci json::standalone_value& jsonOut) { 4838bf80f4bSopenharmony_ci const auto* value = &GetPropertyValue<char>(offset); 4848bf80f4bSopenharmony_ci // NOTE: a hacky way to calculate cstring size. 4858bf80f4bSopenharmony_ci string_view view(value); 4868bf80f4bSopenharmony_ci const size_t size = view.size() < property.size ? view.size() : property.size; 4878bf80f4bSopenharmony_ci jsonOut = ToJson(string(value, size)); 4888bf80f4bSopenharmony_ci return true; 4898bf80f4bSopenharmony_ci }, 4908bf80f4bSopenharmony_ci [](const IEntityCollection& /*ec*/, const json::value& jsonIn, const Property& property, uintptr_t offset) { 4918bf80f4bSopenharmony_ci string value; 4928bf80f4bSopenharmony_ci if (FromJson(jsonIn, value)) { 4938bf80f4bSopenharmony_ci char* charArray = &GetPropertyValue<char>(offset); 4948bf80f4bSopenharmony_ci charArray[value.copy(charArray, property.size - 1)] = '\0'; 4958bf80f4bSopenharmony_ci return true; 4968bf80f4bSopenharmony_ci } 4978bf80f4bSopenharmony_ci return false; 4988bf80f4bSopenharmony_ci })); 4998bf80f4bSopenharmony_ci 5008bf80f4bSopenharmony_ci SetSerializer(PropertyType::ENTITY_T, 5018bf80f4bSopenharmony_ci Add( 5028bf80f4bSopenharmony_ci [](const IEntityCollection& ec, const Property& /*property*/, uintptr_t offset, 5038bf80f4bSopenharmony_ci json::standalone_value& jsonOut) { 5048bf80f4bSopenharmony_ci return EntityToJson(ec, GetPropertyValue<const Entity>(offset), jsonOut); 5058bf80f4bSopenharmony_ci }, 5068bf80f4bSopenharmony_ci [](const IEntityCollection& ec, const json::value& jsonIn, const Property& /*property*/, uintptr_t offset) { 5078bf80f4bSopenharmony_ci return EntityFromJson(ec, jsonIn, GetPropertyValue<Entity>(offset)); 5088bf80f4bSopenharmony_ci })); 5098bf80f4bSopenharmony_ci 5108bf80f4bSopenharmony_ci SetSerializer(PropertyType::ENTITY_REFERENCE_T, 5118bf80f4bSopenharmony_ci Add( 5128bf80f4bSopenharmony_ci [this](const IEntityCollection& ec, const Property& /*property*/, uintptr_t offset, 5138bf80f4bSopenharmony_ci json::standalone_value& jsonOut) { 5148bf80f4bSopenharmony_ci return EntityReferenceToJson( 5158bf80f4bSopenharmony_ci renderContext_, ec, GetPropertyValue<const EntityReference>(offset), jsonOut); 5168bf80f4bSopenharmony_ci }, 5178bf80f4bSopenharmony_ci [this](const IEntityCollection& ec, const json::value& jsonIn, const Property& /*property*/, 5188bf80f4bSopenharmony_ci uintptr_t offset) { 5198bf80f4bSopenharmony_ci return EntityReferenceFromJson( 5208bf80f4bSopenharmony_ci *this, renderContext_, ec, jsonIn, GetPropertyValue<EntityReference>(offset)); 5218bf80f4bSopenharmony_ci })); 5228bf80f4bSopenharmony_ci 5238bf80f4bSopenharmony_ci SetSerializer(PROPERTYTYPE(RenderHandleReference), 5248bf80f4bSopenharmony_ci Add( 5258bf80f4bSopenharmony_ci [this](const IEntityCollection& ec, const Property& /*property*/, uintptr_t offset, 5268bf80f4bSopenharmony_ci json::standalone_value& jsonOut) { 5278bf80f4bSopenharmony_ci return RenderHandleReferenceToJson( 5288bf80f4bSopenharmony_ci renderContext_, ec, GetPropertyValue<const RenderHandleReference>(offset), jsonOut); 5298bf80f4bSopenharmony_ci }, 5308bf80f4bSopenharmony_ci [this](const IEntityCollection& ec, const json::value& jsonIn, const Property& /*property*/, 5318bf80f4bSopenharmony_ci uintptr_t offset) { 5328bf80f4bSopenharmony_ci return RenderHandleReferenceFromJson( 5338bf80f4bSopenharmony_ci *this, renderContext_, ec, jsonIn, GetPropertyValue<RenderHandleReference>(offset)); 5348bf80f4bSopenharmony_ci })); 5358bf80f4bSopenharmony_ci} 5368bf80f4bSopenharmony_ci 5378bf80f4bSopenharmony_civoid EcsSerializer::SetListener(IListener* listener) 5388bf80f4bSopenharmony_ci{ 5398bf80f4bSopenharmony_ci listener_ = listener; 5408bf80f4bSopenharmony_ci} 5418bf80f4bSopenharmony_ci 5428bf80f4bSopenharmony_civoid EcsSerializer::SetSerializer(const PropertyTypeDecl& type, IPropertySerializer& serializer) 5438bf80f4bSopenharmony_ci{ 5448bf80f4bSopenharmony_ci typetoSerializerMap_[type] = &serializer; 5458bf80f4bSopenharmony_ci} 5468bf80f4bSopenharmony_ci 5478bf80f4bSopenharmony_cibool EcsSerializer::WriteEntityCollection(const IEntityCollection& ec, json::standalone_value& jsonOut) const 5488bf80f4bSopenharmony_ci{ 5498bf80f4bSopenharmony_ci // NOTE: We make sure collections and entities are written in the output before entity-components to make it 5508bf80f4bSopenharmony_ci // possible to parse the file in one go. 5518bf80f4bSopenharmony_ci 5528bf80f4bSopenharmony_ci jsonOut = json::standalone_value::object(); 5538bf80f4bSopenharmony_ci 5548bf80f4bSopenharmony_ci string type = ec.GetType(); 5558bf80f4bSopenharmony_ci if (type.empty()) { 5568bf80f4bSopenharmony_ci type = "entitycollection"; 5578bf80f4bSopenharmony_ci } 5588bf80f4bSopenharmony_ci 5598bf80f4bSopenharmony_ci const IoUtil::CompatibilityInfo info { VERSION_MAJOR, VERSION_MINOR, type }; 5608bf80f4bSopenharmony_ci if (!IoUtil::WriteCompatibilityInfo(jsonOut, info)) { 5618bf80f4bSopenharmony_ci return false; 5628bf80f4bSopenharmony_ci } 5638bf80f4bSopenharmony_ci 5648bf80f4bSopenharmony_ci if (string rootSrc = ec.GetSrc(); !rootSrc.empty()) { 5658bf80f4bSopenharmony_ci jsonOut["src"] = move(rootSrc); 5668bf80f4bSopenharmony_ci } 5678bf80f4bSopenharmony_ci 5688bf80f4bSopenharmony_ci // Write external collections instanced in this collection. 5698bf80f4bSopenharmony_ci const auto collectionCount = ec.GetSubCollectionCount(); 5708bf80f4bSopenharmony_ci if (collectionCount > 0) { 5718bf80f4bSopenharmony_ci json::standalone_value collectionsJson = json::standalone_value::array(); 5728bf80f4bSopenharmony_ci collectionsJson.array_.reserve(collectionCount); 5738bf80f4bSopenharmony_ci 5748bf80f4bSopenharmony_ci for (size_t i = 0; i < collectionCount; ++i) { 5758bf80f4bSopenharmony_ci json::standalone_value collectionJson = json::standalone_value::object(); 5768bf80f4bSopenharmony_ci auto* collection = ec.GetSubCollection(i); 5778bf80f4bSopenharmony_ci 5788bf80f4bSopenharmony_ci if (!collection || collection->IsMarkedDestroyed() || !collection->IsSerialized()) { 5798bf80f4bSopenharmony_ci // NOTE: Skipping over destroyed collections (same needs to be done when writing entity references). 5808bf80f4bSopenharmony_ci continue; 5818bf80f4bSopenharmony_ci } 5828bf80f4bSopenharmony_ci 5838bf80f4bSopenharmony_ci if (string src = collection->GetSrc(); !src.empty()) { 5848bf80f4bSopenharmony_ci collectionJson["src"] = move(src); 5858bf80f4bSopenharmony_ci } 5868bf80f4bSopenharmony_ci if (string id = collection->GetUri(); !id.empty()) { 5878bf80f4bSopenharmony_ci collectionJson["id"] = move(id); 5888bf80f4bSopenharmony_ci } 5898bf80f4bSopenharmony_ci 5908bf80f4bSopenharmony_ci collectionsJson.array_.emplace_back(move(collectionJson)); 5918bf80f4bSopenharmony_ci } 5928bf80f4bSopenharmony_ci 5938bf80f4bSopenharmony_ci if (!collectionsJson.array_.empty()) { 5948bf80f4bSopenharmony_ci jsonOut["collections"] = move(collectionsJson); 5958bf80f4bSopenharmony_ci } 5968bf80f4bSopenharmony_ci } 5978bf80f4bSopenharmony_ci 5988bf80f4bSopenharmony_ci // Write bare entities without components. 5998bf80f4bSopenharmony_ci const auto entityCount = ec.GetEntityCount(); 6008bf80f4bSopenharmony_ci if (entityCount > 0) { 6018bf80f4bSopenharmony_ci auto& entitiesJson = (jsonOut["entities"] = json::standalone_value::array()); 6028bf80f4bSopenharmony_ci entitiesJson.array_.reserve(entityCount); 6038bf80f4bSopenharmony_ci for (size_t i = 0; i < entityCount; ++i) { 6048bf80f4bSopenharmony_ci json::standalone_value entityJson = json::standalone_value::object(); 6058bf80f4bSopenharmony_ci 6068bf80f4bSopenharmony_ci // Write id if one is defined. 6078bf80f4bSopenharmony_ci auto entity = ec.GetEntity(i); 6088bf80f4bSopenharmony_ci const auto& id = ec.GetId(entity); 6098bf80f4bSopenharmony_ci if (!id.empty()) { 6108bf80f4bSopenharmony_ci entityJson["id"] = string(id); 6118bf80f4bSopenharmony_ci } 6128bf80f4bSopenharmony_ci 6138bf80f4bSopenharmony_ci entitiesJson.array_.emplace_back(move(entityJson)); 6148bf80f4bSopenharmony_ci } 6158bf80f4bSopenharmony_ci } 6168bf80f4bSopenharmony_ci 6178bf80f4bSopenharmony_ci vector<EntityReference> allEntities; 6188bf80f4bSopenharmony_ci ec.GetEntitiesRecursive(false, allEntities, false); 6198bf80f4bSopenharmony_ci if (allEntities.size() > 0) { 6208bf80f4bSopenharmony_ci auto& entityComponentsJson = (jsonOut["entity-components"] = json::standalone_value::array()); 6218bf80f4bSopenharmony_ci for (Entity entity : allEntities) { 6228bf80f4bSopenharmony_ci json::standalone_value componentJson = json::standalone_value::object(); 6238bf80f4bSopenharmony_ci if (WriteComponents(ec, entity, componentJson["components"])) { 6248bf80f4bSopenharmony_ci json::standalone_value entityRefJson; 6258bf80f4bSopenharmony_ci if (EntityToJson(ec, entity, entityRefJson)) { 6268bf80f4bSopenharmony_ci componentJson["entity"] = move(entityRefJson); 6278bf80f4bSopenharmony_ci } 6288bf80f4bSopenharmony_ci entityComponentsJson.array_.emplace_back(move(componentJson)); 6298bf80f4bSopenharmony_ci } 6308bf80f4bSopenharmony_ci } 6318bf80f4bSopenharmony_ci } 6328bf80f4bSopenharmony_ci 6338bf80f4bSopenharmony_ci // NOTE: Always returns true even if parts of the writing failed. 6348bf80f4bSopenharmony_ci return true; 6358bf80f4bSopenharmony_ci} 6368bf80f4bSopenharmony_ci 6378bf80f4bSopenharmony_cibool EcsSerializer::WriteComponents(const IEntityCollection& ec, Entity entity, json::standalone_value& jsonOut) const 6388bf80f4bSopenharmony_ci{ 6398bf80f4bSopenharmony_ci // Write all entity components to json (Sorting by uid to keep the order more stable). 6408bf80f4bSopenharmony_ci vector<string> managerUids; 6418bf80f4bSopenharmony_ci jsonOut = json::standalone_value::object(); 6428bf80f4bSopenharmony_ci auto cms = ec.GetEcs().GetComponentManagers(); 6438bf80f4bSopenharmony_ci for (auto cm : cms) { 6448bf80f4bSopenharmony_ci const auto componentId = cm->GetComponentId(entity); 6458bf80f4bSopenharmony_ci if (componentId != IComponentManager::INVALID_COMPONENT_ID) { 6468bf80f4bSopenharmony_ci auto uidString = to_string(cm->GetUid()); 6478bf80f4bSopenharmony_ci managerUids.emplace_back(string(uidString)); 6488bf80f4bSopenharmony_ci } 6498bf80f4bSopenharmony_ci } 6508bf80f4bSopenharmony_ci std::sort(managerUids.begin(), managerUids.end()); 6518bf80f4bSopenharmony_ci 6528bf80f4bSopenharmony_ci for (auto& uidString : managerUids) { 6538bf80f4bSopenharmony_ci const auto* cm = ec.GetEcs().GetComponentManager(StringToUid(uidString)); 6548bf80f4bSopenharmony_ci const auto componentId = cm->GetComponentId(entity); 6558bf80f4bSopenharmony_ci 6568bf80f4bSopenharmony_ci json::standalone_value componentJson = json::standalone_value::object(); 6578bf80f4bSopenharmony_ci if (WriteComponent(ec, entity, *cm, componentId, componentJson)) { 6588bf80f4bSopenharmony_ci jsonOut[uidString] = move(componentJson); 6598bf80f4bSopenharmony_ci } 6608bf80f4bSopenharmony_ci } 6618bf80f4bSopenharmony_ci 6628bf80f4bSopenharmony_ci return (!jsonOut.empty()); 6638bf80f4bSopenharmony_ci} 6648bf80f4bSopenharmony_ci 6658bf80f4bSopenharmony_cibool EcsSerializer::WriteComponent(const IEntityCollection& ec, Entity entity, const IComponentManager& cm, 6668bf80f4bSopenharmony_ci IComponentManager::ComponentId id, json::standalone_value& jsonOut) const 6678bf80f4bSopenharmony_ci{ 6688bf80f4bSopenharmony_ci // Write all properties to json. 6698bf80f4bSopenharmony_ci json::standalone_value propertiesJson = json::standalone_value::object(); 6708bf80f4bSopenharmony_ci const auto* props = ec.GetSerializedProperties(entity, cm.GetUid()); 6718bf80f4bSopenharmony_ci if (props) { 6728bf80f4bSopenharmony_ci const auto* propertyHandle = cm.GetData(id); 6738bf80f4bSopenharmony_ci if (!propertyHandle) { 6748bf80f4bSopenharmony_ci return false; 6758bf80f4bSopenharmony_ci } 6768bf80f4bSopenharmony_ci for (auto& propertyPath : *props) { 6778bf80f4bSopenharmony_ci const IPropertyHandle* handle = propertyHandle; 6788bf80f4bSopenharmony_ci 6798bf80f4bSopenharmony_ci PropertyData propertyData; 6808bf80f4bSopenharmony_ci PropertyData::PropertyOffset propertyOffset; 6818bf80f4bSopenharmony_ci 6828bf80f4bSopenharmony_ci // Check if this is property container. 6838bf80f4bSopenharmony_ci string path, name; 6848bf80f4bSopenharmony_ci auto containerHandle = ResolveContainerProperty(*handle, propertyPath, path, name); 6858bf80f4bSopenharmony_ci if (containerHandle) { 6868bf80f4bSopenharmony_ci propertyOffset = propertyData.RLock(*containerHandle, name); 6878bf80f4bSopenharmony_ci } else { 6888bf80f4bSopenharmony_ci propertyOffset = propertyData.RLock(*propertyHandle, propertyPath); 6898bf80f4bSopenharmony_ci } 6908bf80f4bSopenharmony_ci 6918bf80f4bSopenharmony_ci if (propertyOffset) { 6928bf80f4bSopenharmony_ci if ((propertyOffset.property->flags & static_cast<uint32_t>(PropertyFlags::NO_SERIALIZE)) != 0) { 6938bf80f4bSopenharmony_ci continue; 6948bf80f4bSopenharmony_ci } 6958bf80f4bSopenharmony_ci 6968bf80f4bSopenharmony_ci json::standalone_value propertyJson; 6978bf80f4bSopenharmony_ci if (WriteProperty(ec, *propertyOffset.property, propertyOffset.offset, propertyJson)) { 6988bf80f4bSopenharmony_ci if (!propertyJson.is_null()) { 6998bf80f4bSopenharmony_ci propertiesJson[propertyPath] = move(propertyJson); 7008bf80f4bSopenharmony_ci } 7018bf80f4bSopenharmony_ci } 7028bf80f4bSopenharmony_ci } 7038bf80f4bSopenharmony_ci } 7048bf80f4bSopenharmony_ci 7058bf80f4bSopenharmony_ci // NOTE: optional name to make reading files easier. 7068bf80f4bSopenharmony_ci jsonOut["name"] = string(cm.GetName()); 7078bf80f4bSopenharmony_ci 7088bf80f4bSopenharmony_ci if (!propertiesJson.empty()) { 7098bf80f4bSopenharmony_ci jsonOut["properties"] = move(propertiesJson); 7108bf80f4bSopenharmony_ci } 7118bf80f4bSopenharmony_ci 7128bf80f4bSopenharmony_ci // NOTE: Maybe return false if any property write fails? 7138bf80f4bSopenharmony_ci return true; 7148bf80f4bSopenharmony_ci } 7158bf80f4bSopenharmony_ci return false; 7168bf80f4bSopenharmony_ci} 7178bf80f4bSopenharmony_ci 7188bf80f4bSopenharmony_cibool EcsSerializer::WriteProperty( 7198bf80f4bSopenharmony_ci const IEntityCollection& ec, const Property& property, uintptr_t offset, json::standalone_value& jsonOut) const 7208bf80f4bSopenharmony_ci{ 7218bf80f4bSopenharmony_ci auto serializer = typetoSerializerMap_.find(property.type); 7228bf80f4bSopenharmony_ci if (serializer != typetoSerializerMap_.end()) { 7238bf80f4bSopenharmony_ci return serializer->second->ToJson(ec, property, offset, jsonOut); 7248bf80f4bSopenharmony_ci 7258bf80f4bSopenharmony_ci } else if (!property.metaData.enumMetaData.empty()) { 7268bf80f4bSopenharmony_ci // Enum type property. 7278bf80f4bSopenharmony_ci switch (property.size) { 7288bf80f4bSopenharmony_ci case sizeof(uint8_t): 7298bf80f4bSopenharmony_ci jsonOut = GetPropertyValue<uint8_t>(offset); 7308bf80f4bSopenharmony_ci return true; 7318bf80f4bSopenharmony_ci case sizeof(uint16_t): 7328bf80f4bSopenharmony_ci jsonOut = GetPropertyValue<uint16_t>(offset); 7338bf80f4bSopenharmony_ci return true; 7348bf80f4bSopenharmony_ci case sizeof(uint32_t): 7358bf80f4bSopenharmony_ci jsonOut = GetPropertyValue<uint32_t>(offset); 7368bf80f4bSopenharmony_ci return true; 7378bf80f4bSopenharmony_ci case sizeof(uint64_t): 7388bf80f4bSopenharmony_ci jsonOut = GetPropertyValue<uint64_t>(offset); 7398bf80f4bSopenharmony_ci return true; 7408bf80f4bSopenharmony_ci } 7418bf80f4bSopenharmony_ci 7428bf80f4bSopenharmony_ci } else if (property.metaData.containerMethods) { 7438bf80f4bSopenharmony_ci const auto& container = *property.metaData.containerMethods; 7448bf80f4bSopenharmony_ci 7458bf80f4bSopenharmony_ci // Container type property. 7468bf80f4bSopenharmony_ci if (property.type.isArray) { 7478bf80f4bSopenharmony_ci // Special handling for byte arrays. Save as a base64 encoded string. 7488bf80f4bSopenharmony_ci if (property.type == PropertyType::UINT8_ARRAY_T) { 7498bf80f4bSopenharmony_ci array_view<const uint8_t> bytes { (const uint8_t*)offset, property.size }; 7508bf80f4bSopenharmony_ci jsonOut = BASE_NS::Base64Encode(bytes); 7518bf80f4bSopenharmony_ci return true; 7528bf80f4bSopenharmony_ci } 7538bf80f4bSopenharmony_ci 7548bf80f4bSopenharmony_ci // C style array. 7558bf80f4bSopenharmony_ci json::standalone_value array = json::standalone_value::array(); 7568bf80f4bSopenharmony_ci array.array_.reserve(property.count); 7578bf80f4bSopenharmony_ci for (size_t i = 0; i < property.count; i++) { 7588bf80f4bSopenharmony_ci uintptr_t ptr = offset + i * container.property.size; 7598bf80f4bSopenharmony_ci // TODO: return false if any recurseive call fails? 7608bf80f4bSopenharmony_ci json::standalone_value elementJson; 7618bf80f4bSopenharmony_ci WriteProperty(ec, container.property, ptr, elementJson); 7628bf80f4bSopenharmony_ci array.array_.push_back(move(elementJson)); 7638bf80f4bSopenharmony_ci } 7648bf80f4bSopenharmony_ci jsonOut = move(array); 7658bf80f4bSopenharmony_ci return true; 7668bf80f4bSopenharmony_ci 7678bf80f4bSopenharmony_ci } else { 7688bf80f4bSopenharmony_ci // This is a "non trivial container". 7698bf80f4bSopenharmony_ci const auto count = container.size(offset); 7708bf80f4bSopenharmony_ci 7718bf80f4bSopenharmony_ci // Special handling for byte arrays. Save as a base64 encoded string. 7728bf80f4bSopenharmony_ci // NOTE: Only specifically vector so we can assume that the memory usage is linear. 7738bf80f4bSopenharmony_ci if (property.type == PROPERTYTYPE(vector<uint8_t>)) { 7748bf80f4bSopenharmony_ci if (count == 0) { 7758bf80f4bSopenharmony_ci jsonOut = ""; 7768bf80f4bSopenharmony_ci } else { 7778bf80f4bSopenharmony_ci auto data = container.get(offset, 0); 7788bf80f4bSopenharmony_ci array_view<const uint8_t> bytes { reinterpret_cast<const uint8_t*>(data), count }; 7798bf80f4bSopenharmony_ci jsonOut = BASE_NS::Base64Encode(bytes); 7808bf80f4bSopenharmony_ci } 7818bf80f4bSopenharmony_ci return true; 7828bf80f4bSopenharmony_ci } 7838bf80f4bSopenharmony_ci 7848bf80f4bSopenharmony_ci json::standalone_value array = json::standalone_value::array(); 7858bf80f4bSopenharmony_ci array.array_.reserve(count); 7868bf80f4bSopenharmony_ci 7878bf80f4bSopenharmony_ci for (size_t i = 0; i < count; i++) { 7888bf80f4bSopenharmony_ci uintptr_t ptr = container.get(offset, i); 7898bf80f4bSopenharmony_ci // TODO: return false if any recurseive call fails? 7908bf80f4bSopenharmony_ci json::standalone_value elementJson; 7918bf80f4bSopenharmony_ci WriteProperty(ec, container.property, ptr, elementJson); 7928bf80f4bSopenharmony_ci array.array_.push_back(move(elementJson)); 7938bf80f4bSopenharmony_ci } 7948bf80f4bSopenharmony_ci jsonOut = move(array); 7958bf80f4bSopenharmony_ci return true; 7968bf80f4bSopenharmony_ci } 7978bf80f4bSopenharmony_ci 7988bf80f4bSopenharmony_ci } else if (!property.metaData.memberProperties.empty()) { 7998bf80f4bSopenharmony_ci // Struct type property (ie. has sub properties). 8008bf80f4bSopenharmony_ci json::standalone_value object = json::standalone_value::object(); 8018bf80f4bSopenharmony_ci for (const auto& subProperty : property.metaData.memberProperties) { 8028bf80f4bSopenharmony_ci json::standalone_value subPropertyJson; 8038bf80f4bSopenharmony_ci if (WriteProperty(ec, subProperty, offset + subProperty.offset, subPropertyJson)) { 8048bf80f4bSopenharmony_ci object[subProperty.name] = move(subPropertyJson); 8058bf80f4bSopenharmony_ci } 8068bf80f4bSopenharmony_ci } 8078bf80f4bSopenharmony_ci // TODO: return false if any recurseive call fails? 8088bf80f4bSopenharmony_ci jsonOut = move(object); 8098bf80f4bSopenharmony_ci return true; 8108bf80f4bSopenharmony_ci 8118bf80f4bSopenharmony_ci } else { 8128bf80f4bSopenharmony_ci CORE_LOG_V("Ecs serializer not found for '%s'", string(property.type.name).c_str()); 8138bf80f4bSopenharmony_ci } 8148bf80f4bSopenharmony_ci return false; 8158bf80f4bSopenharmony_ci} 8168bf80f4bSopenharmony_ci 8178bf80f4bSopenharmony_cibool EcsSerializer::GatherExternalCollections( 8188bf80f4bSopenharmony_ci const json::value& jsonIn, string_view contextUri, vector<ExternalCollection>& externalCollectionsOut) const 8198bf80f4bSopenharmony_ci{ 8208bf80f4bSopenharmony_ci const auto* srcJson = jsonIn.find("src"); 8218bf80f4bSopenharmony_ci string srcUri; 8228bf80f4bSopenharmony_ci if (srcJson && FromJson(*srcJson, srcUri)) { 8238bf80f4bSopenharmony_ci#ifdef VERBOSE_LOGGING 8248bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG( 8258bf80f4bSopenharmony_ci "External Collection: uri='%s' context='%s'", srcUri.c_str(), string(contextUri).c_str()); 8268bf80f4bSopenharmony_ci#endif 8278bf80f4bSopenharmony_ci externalCollectionsOut.emplace_back(ExternalCollection { srcUri, string { contextUri } }); 8288bf80f4bSopenharmony_ci } 8298bf80f4bSopenharmony_ci 8308bf80f4bSopenharmony_ci const auto* collectionsJson = jsonIn.find("collections"); 8318bf80f4bSopenharmony_ci if (collectionsJson && collectionsJson->is_array()) { 8328bf80f4bSopenharmony_ci for (const auto& collectionJson : collectionsJson->array_) { 8338bf80f4bSopenharmony_ci if (collectionJson.is_object()) { 8348bf80f4bSopenharmony_ci const auto* collectionSrcJson = collectionJson.find("src"); 8358bf80f4bSopenharmony_ci if (collectionSrcJson && collectionSrcJson->is_string()) { 8368bf80f4bSopenharmony_ci string collectionSrcUri; 8378bf80f4bSopenharmony_ci FromJson(*collectionSrcJson, collectionSrcUri); 8388bf80f4bSopenharmony_ci externalCollectionsOut.emplace_back(ExternalCollection { collectionSrcUri, string { contextUri } }); 8398bf80f4bSopenharmony_ci } 8408bf80f4bSopenharmony_ci } 8418bf80f4bSopenharmony_ci } 8428bf80f4bSopenharmony_ci } 8438bf80f4bSopenharmony_ci return true; 8448bf80f4bSopenharmony_ci} 8458bf80f4bSopenharmony_ci 8468bf80f4bSopenharmony_ci/*IIoUtil::SerializationResult*/ int EcsSerializer::ReadEntityCollection( 8478bf80f4bSopenharmony_ci IEntityCollection& ec, const json::value& jsonIn, string_view contextUri) const 8488bf80f4bSopenharmony_ci{ 8498bf80f4bSopenharmony_ci // TODO: Move version check to be separately so it can be done before gathering the dependencies. 8508bf80f4bSopenharmony_ci // NOTE: Only comparing the major version. 8518bf80f4bSopenharmony_ci const auto minor = IoUtil::CompatibilityRange::IGNORE_VERSION; 8528bf80f4bSopenharmony_ci // TODO: Type name was changed to be in line with engine naming. Allow the old type name for a while. 8538bf80f4bSopenharmony_ci const IoUtil::CompatibilityRange validVersions[] { 8548bf80f4bSopenharmony_ci { VERSION_MAJOR, VERSION_MAJOR, minor, minor, ec.GetType() }, 8558bf80f4bSopenharmony_ci { VERSION_MAJOR, VERSION_MAJOR, minor, minor, "entity_collection" }, 8568bf80f4bSopenharmony_ci }; 8578bf80f4bSopenharmony_ci 8588bf80f4bSopenharmony_ci auto result = IoUtil::CheckCompatibility(jsonIn, validVersions); 8598bf80f4bSopenharmony_ci if (!result) { 8608bf80f4bSopenharmony_ci CORE_LOG_W("Deprecated compatibility info found \"entity_collection\": '%s'", string(contextUri).c_str()); 8618bf80f4bSopenharmony_ci } 8628bf80f4bSopenharmony_ci 8638bf80f4bSopenharmony_ci const auto* srcJson = jsonIn.find("src"); 8648bf80f4bSopenharmony_ci string srcUri; 8658bf80f4bSopenharmony_ci if (srcJson && FromJson(*srcJson, srcUri)) { 8668bf80f4bSopenharmony_ci#ifdef VERBOSE_LOGGING 8678bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG( 8688bf80f4bSopenharmony_ci "External Collection: uri='%s' context='%s'", srcUri.c_str(), string(contextUri).c_str()); 8698bf80f4bSopenharmony_ci#endif 8708bf80f4bSopenharmony_ci auto* externalCollection = listener_->GetExternalCollection(ec.GetEcs(), srcUri, contextUri); 8718bf80f4bSopenharmony_ci if (externalCollection) { 8728bf80f4bSopenharmony_ci ec.CopyContents(*externalCollection); 8738bf80f4bSopenharmony_ci } 8748bf80f4bSopenharmony_ci } 8758bf80f4bSopenharmony_ci 8768bf80f4bSopenharmony_ci const auto* collectionsJson = jsonIn.find("collections"); 8778bf80f4bSopenharmony_ci if (collectionsJson && collectionsJson->is_array()) { 8788bf80f4bSopenharmony_ci for (const auto& collectionJson : collectionsJson->array_) { 8798bf80f4bSopenharmony_ci if (collectionJson.is_object()) { 8808bf80f4bSopenharmony_ci string id; 8818bf80f4bSopenharmony_ci const auto* idJson = collectionJson.find("id"); 8828bf80f4bSopenharmony_ci if (idJson) { 8838bf80f4bSopenharmony_ci FromJson(*idJson, id); 8848bf80f4bSopenharmony_ci } 8858bf80f4bSopenharmony_ci 8868bf80f4bSopenharmony_ci const auto* collectionSrcJson = collectionJson.find("src"); 8878bf80f4bSopenharmony_ci if (collectionSrcJson && collectionSrcJson->is_string()) { 8888bf80f4bSopenharmony_ci string collectionSrcUri; 8898bf80f4bSopenharmony_ci FromJson(*collectionSrcJson, collectionSrcUri); 8908bf80f4bSopenharmony_ci 8918bf80f4bSopenharmony_ci // Instantiate the collection pointed by src. 8928bf80f4bSopenharmony_ci#ifdef VERBOSE_LOGGING 8938bf80f4bSopenharmony_ci SCENE_PLUGIN_VERBOSE_LOG("External Collection: uri='%s' context='%s'", collectionSrcUri.c_str(), 8948bf80f4bSopenharmony_ci string(contextUri).c_str()); 8958bf80f4bSopenharmony_ci#endif 8968bf80f4bSopenharmony_ci auto* externalCollection = 8978bf80f4bSopenharmony_ci listener_->GetExternalCollection(ec.GetEcs(), collectionSrcUri, contextUri); 8988bf80f4bSopenharmony_ci if (externalCollection) { 8998bf80f4bSopenharmony_ci ec.AddSubCollectionClone(*externalCollection, id).SetSrc(collectionSrcUri); 9008bf80f4bSopenharmony_ci ; 9018bf80f4bSopenharmony_ci } else { 9028bf80f4bSopenharmony_ci CORE_LOG_E("Loading collection failed: '%s'", collectionSrcUri.c_str()); 9038bf80f4bSopenharmony_ci // Just adding an empty collection as a placeholder. 9048bf80f4bSopenharmony_ci ec.AddSubCollection(id, collectionSrcUri).SetSrc(collectionSrcUri); 9058bf80f4bSopenharmony_ci } 9068bf80f4bSopenharmony_ci } else { 9078bf80f4bSopenharmony_ci ec.AddSubCollection(id, {}); 9088bf80f4bSopenharmony_ci } 9098bf80f4bSopenharmony_ci } 9108bf80f4bSopenharmony_ci } 9118bf80f4bSopenharmony_ci } 9128bf80f4bSopenharmony_ci 9138bf80f4bSopenharmony_ci const auto* entitiesJson = jsonIn.find("entities"); 9148bf80f4bSopenharmony_ci bool idSet { false }; 9158bf80f4bSopenharmony_ci if (entitiesJson && entitiesJson->is_array()) { 9168bf80f4bSopenharmony_ci auto& em = ec.GetEcs().GetEntityManager(); 9178bf80f4bSopenharmony_ci 9188bf80f4bSopenharmony_ci // First create all entities so they can be referenced by components. 9198bf80f4bSopenharmony_ci for (const auto& entityJson : entitiesJson->array_) { 9208bf80f4bSopenharmony_ci // Create a new entity. 9218bf80f4bSopenharmony_ci EntityReference entity = em.CreateReferenceCounted(); 9228bf80f4bSopenharmony_ci ec.AddEntity(entity); 9238bf80f4bSopenharmony_ci 9248bf80f4bSopenharmony_ci // Add with an id if one is defined. 9258bf80f4bSopenharmony_ci const auto* idJson = entityJson.find("id"); 9268bf80f4bSopenharmony_ci string id; 9278bf80f4bSopenharmony_ci if (idJson && FromJson(*idJson, id)) { 9288bf80f4bSopenharmony_ci ec.SetId(id, entity); 9298bf80f4bSopenharmony_ci idSet = true; 9308bf80f4bSopenharmony_ci } 9318bf80f4bSopenharmony_ci } 9328bf80f4bSopenharmony_ci } 9338bf80f4bSopenharmony_ci 9348bf80f4bSopenharmony_ci const auto* ecJson = jsonIn.find("entity-components"); 9358bf80f4bSopenharmony_ci if (ecJson && ecJson->is_array()) { 9368bf80f4bSopenharmony_ci // Then load entity contents (i.e. components). 9378bf80f4bSopenharmony_ci for (size_t i = 0; i < ecJson->array_.size(); ++i) { 9388bf80f4bSopenharmony_ci ReadComponents(ec, ecJson->array_.at(i), !idSet); 9398bf80f4bSopenharmony_ci } 9408bf80f4bSopenharmony_ci } 9418bf80f4bSopenharmony_ci 9428bf80f4bSopenharmony_ci if (!ec.IsActive()) { 9438bf80f4bSopenharmony_ci // If the ec is not active also make the newly loaded entities not active. 9448bf80f4bSopenharmony_ci ec.SetActive(false); 9458bf80f4bSopenharmony_ci } 9468bf80f4bSopenharmony_ci 9478bf80f4bSopenharmony_ci // NOTE: Always returns success, even if parts of the load failed. 9488bf80f4bSopenharmony_ci return 1; // result; 9498bf80f4bSopenharmony_ci} 9508bf80f4bSopenharmony_ci 9518bf80f4bSopenharmony_cibool EcsSerializer::ReadComponents(IEntityCollection& ec, const json::value& jsonIn, bool setId) const 9528bf80f4bSopenharmony_ci{ 9538bf80f4bSopenharmony_ci // Figure out to which entity these components belong to. 9548bf80f4bSopenharmony_ci const auto* entityJson = jsonIn.find("entity"); 9558bf80f4bSopenharmony_ci if (!entityJson) { 9568bf80f4bSopenharmony_ci CORE_LOG_W("No entity defined for a component."); 9578bf80f4bSopenharmony_ci return false; 9588bf80f4bSopenharmony_ci } 9598bf80f4bSopenharmony_ci 9608bf80f4bSopenharmony_ci Entity entity {}; 9618bf80f4bSopenharmony_ci 9628bf80f4bSopenharmony_ci if (!EntityFromJson(ec, *entityJson, entity)) { 9638bf80f4bSopenharmony_ci return false; 9648bf80f4bSopenharmony_ci } 9658bf80f4bSopenharmony_ci 9668bf80f4bSopenharmony_ci auto& ecs = ec.GetEcs(); 9678bf80f4bSopenharmony_ci const auto* componentsJson = jsonIn.find("components"); 9688bf80f4bSopenharmony_ci if (componentsJson) { 9698bf80f4bSopenharmony_ci // Read all entity components from json. 9708bf80f4bSopenharmony_ci for (auto& component : componentsJson->object_) { 9718bf80f4bSopenharmony_ci auto& key = component.key; 9728bf80f4bSopenharmony_ci const auto componentUid = StringToUid(key); 9738bf80f4bSopenharmony_ci 9748bf80f4bSopenharmony_ci auto& componentJson = component.value; 9758bf80f4bSopenharmony_ci auto* cm = ecs.GetComponentManager(componentUid); 9768bf80f4bSopenharmony_ci if (cm) { 9778bf80f4bSopenharmony_ci ReadComponent(ec, componentJson, entity, *cm); 9788bf80f4bSopenharmony_ci if (setId && cm->GetName() == "NameComponent") { 9798bf80f4bSopenharmony_ci if (auto handle = reinterpret_cast<CORE3D_NS::INameComponentManager*>(cm)->Read(entity)) { 9808bf80f4bSopenharmony_ci for (auto& ref : ec.GetEntities()) { 9818bf80f4bSopenharmony_ci if (ref == entity) { 9828bf80f4bSopenharmony_ci BASE_NS::string compound = handle->name; 9838bf80f4bSopenharmony_ci compound.append(":"); 9848bf80f4bSopenharmony_ci compound.append(BASE_NS::to_hex(entity.id)); 9858bf80f4bSopenharmony_ci 9868bf80f4bSopenharmony_ci ec.SetUniqueIdentifier(compound, ref); 9878bf80f4bSopenharmony_ci break; 9888bf80f4bSopenharmony_ci } 9898bf80f4bSopenharmony_ci } 9908bf80f4bSopenharmony_ci } 9918bf80f4bSopenharmony_ci } 9928bf80f4bSopenharmony_ci } else { 9938bf80f4bSopenharmony_ci // TODO: Maybe we should try to find a matching component by name as a fallback 9948bf80f4bSopenharmony_ci CORE_LOG_W("Unrecognized component found: '%s'", string(key).c_str()); 9958bf80f4bSopenharmony_ci } 9968bf80f4bSopenharmony_ci } 9978bf80f4bSopenharmony_ci } 9988bf80f4bSopenharmony_ci 9998bf80f4bSopenharmony_ci return true; 10008bf80f4bSopenharmony_ci} 10018bf80f4bSopenharmony_ci 10028bf80f4bSopenharmony_cibool EcsSerializer::ReadComponent( 10038bf80f4bSopenharmony_ci IEntityCollection& ec, const json::value& jsonIn, Entity entity, IComponentManager& component) const 10048bf80f4bSopenharmony_ci{ 10058bf80f4bSopenharmony_ci // Create the component if it does not exist yet. 10068bf80f4bSopenharmony_ci auto componentId = component.GetComponentId(entity); 10078bf80f4bSopenharmony_ci if (componentId == IComponentManager::INVALID_COMPONENT_ID) { 10088bf80f4bSopenharmony_ci component.Create(entity); 10098bf80f4bSopenharmony_ci componentId = component.GetComponentId(entity); 10108bf80f4bSopenharmony_ci } 10118bf80f4bSopenharmony_ci 10128bf80f4bSopenharmony_ci ec.MarkComponentSerialized(entity, component.GetUid(), true); 10138bf80f4bSopenharmony_ci 10148bf80f4bSopenharmony_ci const auto* propertiesJson = jsonIn.find("properties"); 10158bf80f4bSopenharmony_ci if (!propertiesJson || propertiesJson->type != json::type::object) { 10168bf80f4bSopenharmony_ci // No properties. 10178bf80f4bSopenharmony_ci return true; 10188bf80f4bSopenharmony_ci } 10198bf80f4bSopenharmony_ci 10208bf80f4bSopenharmony_ci auto* propertyHandle = component.GetData(componentId); 10218bf80f4bSopenharmony_ci if (!propertyHandle) { 10228bf80f4bSopenharmony_ci return false; 10238bf80f4bSopenharmony_ci } 10248bf80f4bSopenharmony_ci 10258bf80f4bSopenharmony_ci for (auto& propertyJson : propertiesJson->object_) { 10268bf80f4bSopenharmony_ci const auto& propertyPath = propertyJson.key; 10278bf80f4bSopenharmony_ci const auto& propertyValueJson = propertyJson.value; 10288bf80f4bSopenharmony_ci auto pathView = string_view(propertyPath.data(), propertyPath.size()); 10298bf80f4bSopenharmony_ci 10308bf80f4bSopenharmony_ci // Find the property using the propertyName 10318bf80f4bSopenharmony_ci { 10328bf80f4bSopenharmony_ci const IPropertyHandle* handle = propertyHandle; 10338bf80f4bSopenharmony_ci PropertyData propertyData; 10348bf80f4bSopenharmony_ci PropertyData::PropertyOffset propertyOffset; 10358bf80f4bSopenharmony_ci 10368bf80f4bSopenharmony_ci // Check if this is property container. 10378bf80f4bSopenharmony_ci string path, name; 10388bf80f4bSopenharmony_ci auto containerHandle = ResolveContainerProperty(*handle, string(pathView), path, name); 10398bf80f4bSopenharmony_ci if (containerHandle) { 10408bf80f4bSopenharmony_ci propertyOffset = propertyData.WLock(*containerHandle, name); 10418bf80f4bSopenharmony_ci } else { 10428bf80f4bSopenharmony_ci // We can only ask for the property if we first make sure it exists (we may be referencing a dynamic 10438bf80f4bSopenharmony_ci // array). 10448bf80f4bSopenharmony_ci EnsureDynamicArraySize(propertyHandle, pathView); 10458bf80f4bSopenharmony_ci 10468bf80f4bSopenharmony_ci propertyOffset = propertyData.WLock(*propertyHandle, pathView); 10478bf80f4bSopenharmony_ci } 10488bf80f4bSopenharmony_ci 10498bf80f4bSopenharmony_ci if (propertyOffset) { 10508bf80f4bSopenharmony_ci if (ReadProperty(ec, propertyValueJson, *propertyOffset.property, propertyOffset.offset)) { 10518bf80f4bSopenharmony_ci // Mark this property value as serialized (instead of being a cloned from a prototype entity). 10528bf80f4bSopenharmony_ci ec.MarkPropertySerialized(entity, component.GetUid(), pathView, true); 10538bf80f4bSopenharmony_ci } else { 10548bf80f4bSopenharmony_ci CORE_LOG_W("Unrecognized property: Component: '%s' Property: '%s'", component.GetName().data(), 10558bf80f4bSopenharmony_ci string(pathView).c_str()); 10568bf80f4bSopenharmony_ci } 10578bf80f4bSopenharmony_ci } 10588bf80f4bSopenharmony_ci } 10598bf80f4bSopenharmony_ci } 10608bf80f4bSopenharmony_ci return true; 10618bf80f4bSopenharmony_ci} 10628bf80f4bSopenharmony_ci 10638bf80f4bSopenharmony_cibool EcsSerializer::ReadProperty( 10648bf80f4bSopenharmony_ci IEntityCollection& ec, const json::value& jsonIn, const Property& property, uintptr_t offset) const 10658bf80f4bSopenharmony_ci{ 10668bf80f4bSopenharmony_ci // See if there is a serializer for this type. Otherwise recurse further. 10678bf80f4bSopenharmony_ci auto serializer = typetoSerializerMap_.find(property.type); 10688bf80f4bSopenharmony_ci if (serializer != typetoSerializerMap_.end()) { 10698bf80f4bSopenharmony_ci return serializer->second->FromJson(ec, jsonIn, property, offset); 10708bf80f4bSopenharmony_ci 10718bf80f4bSopenharmony_ci } else if (!property.metaData.enumMetaData.empty()) { 10728bf80f4bSopenharmony_ci // Enum type property. 10738bf80f4bSopenharmony_ci if (jsonIn.is_unsigned_int()) { 10748bf80f4bSopenharmony_ci switch (property.size) { 10758bf80f4bSopenharmony_ci case sizeof(uint8_t): 10768bf80f4bSopenharmony_ci GetPropertyValue<uint8_t>(offset) = static_cast<uint8_t>(jsonIn.unsigned_); 10778bf80f4bSopenharmony_ci return true; 10788bf80f4bSopenharmony_ci case sizeof(uint16_t): 10798bf80f4bSopenharmony_ci GetPropertyValue<uint16_t>(offset) = static_cast<uint16_t>(jsonIn.unsigned_); 10808bf80f4bSopenharmony_ci return true; 10818bf80f4bSopenharmony_ci case sizeof(uint32_t): 10828bf80f4bSopenharmony_ci GetPropertyValue<uint32_t>(offset) = static_cast<uint32_t>(jsonIn.unsigned_); 10838bf80f4bSopenharmony_ci return true; 10848bf80f4bSopenharmony_ci case sizeof(uint64_t): 10858bf80f4bSopenharmony_ci GetPropertyValue<uint64_t>(offset) = static_cast<uint64_t>(jsonIn.unsigned_); 10868bf80f4bSopenharmony_ci return true; 10878bf80f4bSopenharmony_ci } 10888bf80f4bSopenharmony_ci } 10898bf80f4bSopenharmony_ci 10908bf80f4bSopenharmony_ci } else if (property.metaData.containerMethods) { 10918bf80f4bSopenharmony_ci // Special handling for byte data encoded as base64. 10928bf80f4bSopenharmony_ci if (jsonIn.is_string()) { 10938bf80f4bSopenharmony_ci // A base64 encoded string containing raw array data 10948bf80f4bSopenharmony_ci auto bytes = BASE_NS::Base64Decode(jsonIn.string_); 10958bf80f4bSopenharmony_ci 10968bf80f4bSopenharmony_ci // Only valid for byte data. 10978bf80f4bSopenharmony_ci if (property.type == PropertyType::UINT8_ARRAY_T) { 10988bf80f4bSopenharmony_ci if (property.size != bytes.size()) { 10998bf80f4bSopenharmony_ci CORE_LOG_W("Invalid base64 data size in: %s", string(property.name).c_str()); 11008bf80f4bSopenharmony_ci return false; 11018bf80f4bSopenharmony_ci } 11028bf80f4bSopenharmony_ci CloneData(GetPropertyValue<uint8_t*>(offset), property.size, &bytes[0], bytes.size()); 11038bf80f4bSopenharmony_ci return true; 11048bf80f4bSopenharmony_ci 11058bf80f4bSopenharmony_ci } else if (property.type == PROPERTYTYPE(vector<uint8_t>)) { 11068bf80f4bSopenharmony_ci GetPropertyValue<vector<uint8_t>>(offset).swap(bytes); 11078bf80f4bSopenharmony_ci return true; 11088bf80f4bSopenharmony_ci } 11098bf80f4bSopenharmony_ci return false; 11108bf80f4bSopenharmony_ci } 11118bf80f4bSopenharmony_ci 11128bf80f4bSopenharmony_ci // Container type property. 11138bf80f4bSopenharmony_ci if (property.type.isArray) { 11148bf80f4bSopenharmony_ci // C style array. 11158bf80f4bSopenharmony_ci if (jsonIn.is_array()) { 11168bf80f4bSopenharmony_ci if (jsonIn.array_.size() != property.count) { 11178bf80f4bSopenharmony_ci CORE_LOG_W("Expecting a json array of size %zu", property.count); 11188bf80f4bSopenharmony_ci return false; 11198bf80f4bSopenharmony_ci } 11208bf80f4bSopenharmony_ci for (size_t i = 0; i < property.count; i++) { 11218bf80f4bSopenharmony_ci uintptr_t ptr = offset + i * property.metaData.containerMethods->property.size; 11228bf80f4bSopenharmony_ci // TODO: return false if any recurseive call fails? 11238bf80f4bSopenharmony_ci ReadProperty(ec, jsonIn.array_.at(i), property.metaData.containerMethods->property, ptr); 11248bf80f4bSopenharmony_ci } 11258bf80f4bSopenharmony_ci return true; 11268bf80f4bSopenharmony_ci 11278bf80f4bSopenharmony_ci } else if (jsonIn.is_object()) { 11288bf80f4bSopenharmony_ci // Allow "sparse arrays" by using objects with the array index as the key. 11298bf80f4bSopenharmony_ci for (auto& element : jsonIn.object_) { 11308bf80f4bSopenharmony_ci const auto& key = element.key; 11318bf80f4bSopenharmony_ci const auto index = static_cast<size_t>(strtol(string(key).c_str(), nullptr, 10)); 11328bf80f4bSopenharmony_ci if ((index == 0 && key != "0") || index >= property.count) { 11338bf80f4bSopenharmony_ci CORE_LOG_W("Invalid array Index: %s", string(key).c_str()); 11348bf80f4bSopenharmony_ci continue; 11358bf80f4bSopenharmony_ci } 11368bf80f4bSopenharmony_ci uintptr_t ptr = offset + index * property.metaData.containerMethods->property.size; 11378bf80f4bSopenharmony_ci ReadProperty(ec, element.value, property.metaData.containerMethods->property, ptr); 11388bf80f4bSopenharmony_ci } 11398bf80f4bSopenharmony_ci return true; 11408bf80f4bSopenharmony_ci } 11418bf80f4bSopenharmony_ci return false; 11428bf80f4bSopenharmony_ci 11438bf80f4bSopenharmony_ci } else { 11448bf80f4bSopenharmony_ci // This is a "non trivial container". 11458bf80f4bSopenharmony_ci if (jsonIn.is_array()) { 11468bf80f4bSopenharmony_ci const auto count = jsonIn.array_.size(); 11478bf80f4bSopenharmony_ci property.metaData.containerMethods->resize(offset, count); 11488bf80f4bSopenharmony_ci for (size_t i = 0; i < count; i++) { 11498bf80f4bSopenharmony_ci uintptr_t ptr = property.metaData.containerMethods->get(offset, i); 11508bf80f4bSopenharmony_ci ReadProperty(ec, jsonIn.array_.at(i), property.metaData.containerMethods->property, ptr); 11518bf80f4bSopenharmony_ci } 11528bf80f4bSopenharmony_ci return true; 11538bf80f4bSopenharmony_ci 11548bf80f4bSopenharmony_ci } else if (jsonIn.is_object()) { 11558bf80f4bSopenharmony_ci // Allow "sparse arrays" by using objects with the array index as the key. 11568bf80f4bSopenharmony_ci for (auto& element : jsonIn.object_) { 11578bf80f4bSopenharmony_ci const auto& key = element.key; 11588bf80f4bSopenharmony_ci const auto index = static_cast<size_t>(strtol(string(key).c_str(), nullptr, 10)); 11598bf80f4bSopenharmony_ci if ((index == 0 && key != "0")) { 11608bf80f4bSopenharmony_ci CORE_LOG_W("Invalid array Index: %s", string(key).c_str()); 11618bf80f4bSopenharmony_ci continue; 11628bf80f4bSopenharmony_ci } 11638bf80f4bSopenharmony_ci 11648bf80f4bSopenharmony_ci const auto count = property.metaData.containerMethods->size(offset); 11658bf80f4bSopenharmony_ci if (count <= index) { 11668bf80f4bSopenharmony_ci property.metaData.containerMethods->resize(offset, index + 1); 11678bf80f4bSopenharmony_ci } 11688bf80f4bSopenharmony_ci uintptr_t ptr = property.metaData.containerMethods->get(offset, index); 11698bf80f4bSopenharmony_ci ReadProperty(ec, element.value, property.metaData.containerMethods->property, ptr); 11708bf80f4bSopenharmony_ci } 11718bf80f4bSopenharmony_ci return true; 11728bf80f4bSopenharmony_ci } 11738bf80f4bSopenharmony_ci return false; 11748bf80f4bSopenharmony_ci } 11758bf80f4bSopenharmony_ci 11768bf80f4bSopenharmony_ci } else if (!property.metaData.memberProperties.empty()) { 11778bf80f4bSopenharmony_ci // Struct type property (ie. has sub properties). 11788bf80f4bSopenharmony_ci if (jsonIn.is_object()) { 11798bf80f4bSopenharmony_ci for (const auto& subProperty : property.metaData.memberProperties) { 11808bf80f4bSopenharmony_ci // TODO: is there a way to not create the string 11818bf80f4bSopenharmony_ci const string name(subProperty.name); 11828bf80f4bSopenharmony_ci const auto* subJson = jsonIn.find(name); 11838bf80f4bSopenharmony_ci if (subJson) { 11848bf80f4bSopenharmony_ci ReadProperty(ec, *subJson, subProperty, offset + subProperty.offset); 11858bf80f4bSopenharmony_ci } 11868bf80f4bSopenharmony_ci } 11878bf80f4bSopenharmony_ci // TODO: return false if any recurseive call fails? 11888bf80f4bSopenharmony_ci return true; 11898bf80f4bSopenharmony_ci } 11908bf80f4bSopenharmony_ci } 11918bf80f4bSopenharmony_ci 11928bf80f4bSopenharmony_ci return false; 11938bf80f4bSopenharmony_ci} 11948bf80f4bSopenharmony_ci 11958bf80f4bSopenharmony_ciRENDER_NS::RenderHandleReference EcsSerializer::LoadImageResource(BASE_NS::string_view uri) const 11968bf80f4bSopenharmony_ci{ 11978bf80f4bSopenharmony_ci // Get rid of a possible query string in the uri. 11988bf80f4bSopenharmony_ci const auto fileUri = PathUtil::ResolvePath({}, uri, false); 11998bf80f4bSopenharmony_ci 12008bf80f4bSopenharmony_ci auto params = PathUtil::GetUriParameters(uri); 12018bf80f4bSopenharmony_ci 12028bf80f4bSopenharmony_ci // Image loading flags can be passed in the uri query string. 12038bf80f4bSopenharmony_ci uint64_t imageLoaderFlags {}; 12048bf80f4bSopenharmony_ci auto loaderFlags = params.find("loaderFlags"); 12058bf80f4bSopenharmony_ci if (loaderFlags != params.end()) { 12068bf80f4bSopenharmony_ci const char* start = loaderFlags->second.data(); 12078bf80f4bSopenharmony_ci const char* end = start + loaderFlags->second.size(); 12088bf80f4bSopenharmony_ci std::from_chars(start, end, imageLoaderFlags); 12098bf80f4bSopenharmony_ci } 12108bf80f4bSopenharmony_ci 12118bf80f4bSopenharmony_ci auto imageLoadResult = renderContext_.GetEngine().GetImageLoaderManager().LoadImage(fileUri, imageLoaderFlags); 12128bf80f4bSopenharmony_ci 12138bf80f4bSopenharmony_ci RenderHandleReference imageHandle {}; 12148bf80f4bSopenharmony_ci if (!imageLoadResult.success) { 12158bf80f4bSopenharmony_ci CORE_LOG_E("Could not load image asset: %s", imageLoadResult.error); 12168bf80f4bSopenharmony_ci 12178bf80f4bSopenharmony_ci } else { 12188bf80f4bSopenharmony_ci auto& gpuResourceMgr = renderContext_.GetDevice().GetGpuResourceManager(); 12198bf80f4bSopenharmony_ci GpuImageDesc gpuDesc = gpuResourceMgr.CreateGpuImageDesc(imageLoadResult.image->GetImageDesc()); 12208bf80f4bSopenharmony_ci gpuDesc.usageFlags = CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_TRANSFER_DST_BIT; 12218bf80f4bSopenharmony_ci if (gpuDesc.engineCreationFlags & EngineImageCreationFlagBits::CORE_ENGINE_IMAGE_CREATION_GENERATE_MIPS) { 12228bf80f4bSopenharmony_ci gpuDesc.usageFlags |= CORE_IMAGE_USAGE_TRANSFER_SRC_BIT; 12238bf80f4bSopenharmony_ci } 12248bf80f4bSopenharmony_ci gpuDesc.memoryPropertyFlags = CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; 12258bf80f4bSopenharmony_ci 12268bf80f4bSopenharmony_ci imageHandle = gpuResourceMgr.Create(uri, gpuDesc, std::move(imageLoadResult.image)); 12278bf80f4bSopenharmony_ci } 12288bf80f4bSopenharmony_ci 12298bf80f4bSopenharmony_ci return imageHandle; 12308bf80f4bSopenharmony_ci} 12318bf80f4bSopenharmony_ci 12328bf80f4bSopenharmony_civoid EcsSerializer::Destroy() 12338bf80f4bSopenharmony_ci{ 12348bf80f4bSopenharmony_ci delete this; 12358bf80f4bSopenharmony_ci} 12368bf80f4bSopenharmony_ci 12378bf80f4bSopenharmony_ciSCENE_END_NAMESPACE() 1238