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#ifndef SCENE_PLUGIN_ECSUTIL_H 178bf80f4bSopenharmony_ci#define SCENE_PLUGIN_ECSUTIL_H 188bf80f4bSopenharmony_ci 198bf80f4bSopenharmony_ci#include <PropertyTools/property_data.h> 208bf80f4bSopenharmony_ci 218bf80f4bSopenharmony_ci#include <base/containers/string.h> 228bf80f4bSopenharmony_ci#include <base/containers/unordered_map.h> 238bf80f4bSopenharmony_ci#include <base/math/vector.h> 248bf80f4bSopenharmony_ci#include <core/ecs/entity.h> 258bf80f4bSopenharmony_ci#include <core/ecs/intf_component_manager.h> 268bf80f4bSopenharmony_ci#include <core/ecs/intf_ecs.h> 278bf80f4bSopenharmony_ci#include <core/ecs/intf_entity_manager.h> 288bf80f4bSopenharmony_ci#include <core/property/intf_property_api.h> 298bf80f4bSopenharmony_ci#include <core/property/property_types.h> 308bf80f4bSopenharmony_ci#include <core/property/scoped_handle.h> 318bf80f4bSopenharmony_ci 328bf80f4bSopenharmony_ciCORE_BEGIN_NAMESPACE() 338bf80f4bSopenharmony_ci 348bf80f4bSopenharmony_ciinline void CloneComponent(CORE_NS::Entity srcEntity, const CORE_NS::IComponentManager& srcManager, 358bf80f4bSopenharmony_ci CORE_NS::IEcs& dstEcs, CORE_NS::Entity dstEntity) 368bf80f4bSopenharmony_ci{ 378bf80f4bSopenharmony_ci auto* dstManager = dstEcs.GetComponentManager(srcManager.GetUid()); 388bf80f4bSopenharmony_ci if (dstManager) { 398bf80f4bSopenharmony_ci // Get copy destiantion property handle. 408bf80f4bSopenharmony_ci auto componentId = dstManager->GetComponentId(dstEntity); 418bf80f4bSopenharmony_ci if (componentId == CORE_NS::IComponentManager::INVALID_COMPONENT_ID) { 428bf80f4bSopenharmony_ci dstManager->Create(dstEntity); 438bf80f4bSopenharmony_ci componentId = dstManager->GetComponentId(dstEntity); 448bf80f4bSopenharmony_ci } 458bf80f4bSopenharmony_ci BASE_ASSERT(componentId != CORE_NS::IComponentManager::INVALID_COMPONENT_ID); 468bf80f4bSopenharmony_ci const auto* srcHandle = srcManager.GetData(srcEntity); 478bf80f4bSopenharmony_ci if (srcHandle) { 488bf80f4bSopenharmony_ci dstManager->SetData(dstEntity, *srcHandle); 498bf80f4bSopenharmony_ci } 508bf80f4bSopenharmony_ci } 518bf80f4bSopenharmony_ci} 528bf80f4bSopenharmony_ci 538bf80f4bSopenharmony_ciinline void CloneComponents( 548bf80f4bSopenharmony_ci CORE_NS::IEcs& srcEcs, CORE_NS::Entity srcEntity, CORE_NS::IEcs& dstEcs, CORE_NS::Entity dstEntity) 558bf80f4bSopenharmony_ci{ 568bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::IComponentManager*> managers; 578bf80f4bSopenharmony_ci srcEcs.GetComponents(srcEntity, managers); 588bf80f4bSopenharmony_ci for (auto* srcManager : managers) { 598bf80f4bSopenharmony_ci CloneComponent(srcEntity, *srcManager, dstEcs, dstEntity); 608bf80f4bSopenharmony_ci } 618bf80f4bSopenharmony_ci} 628bf80f4bSopenharmony_ci 638bf80f4bSopenharmony_ciinline CORE_NS::Entity CloneEntity(CORE_NS::IEcs& srcEcs, CORE_NS::Entity src, CORE_NS::IEcs& dstEcs) 648bf80f4bSopenharmony_ci{ 658bf80f4bSopenharmony_ci CORE_NS::Entity dst = dstEcs.GetEntityManager().Create(); 668bf80f4bSopenharmony_ci CloneComponents(srcEcs, src, dstEcs, dst); 678bf80f4bSopenharmony_ci return dst; 688bf80f4bSopenharmony_ci} 698bf80f4bSopenharmony_ci 708bf80f4bSopenharmony_ciinline CORE_NS::EntityReference CloneEntityReference(CORE_NS::IEcs& srcEcs, CORE_NS::Entity src, CORE_NS::IEcs& dstEcs) 718bf80f4bSopenharmony_ci{ 728bf80f4bSopenharmony_ci CORE_NS::EntityReference dst = dstEcs.GetEntityManager().CreateReferenceCounted(); 738bf80f4bSopenharmony_ci CloneComponents(srcEcs, src, dstEcs, dst); 748bf80f4bSopenharmony_ci return dst; 758bf80f4bSopenharmony_ci} 768bf80f4bSopenharmony_ci 778bf80f4bSopenharmony_ciinline void GatherEntityReferences(BASE_NS::vector<CORE_NS::Entity*>& entities, 788bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::EntityReference*>& entityReferences, const CORE_NS::Property& property, 798bf80f4bSopenharmony_ci uintptr_t offset = 0) 808bf80f4bSopenharmony_ci{ 818bf80f4bSopenharmony_ci if (property.type == CORE_NS::PropertyType::ENTITY_T) { 828bf80f4bSopenharmony_ci entities.emplace_back(reinterpret_cast<CORE_NS::Entity*>(offset)); 838bf80f4bSopenharmony_ci } else if (property.type == CORE_NS::PropertyType::ENTITY_REFERENCE_T) { 848bf80f4bSopenharmony_ci entityReferences.emplace_back(reinterpret_cast<CORE_NS::EntityReference*>(offset)); 858bf80f4bSopenharmony_ci } else if (property.metaData.containerMethods) { 868bf80f4bSopenharmony_ci auto& containerProperty = property.metaData.containerMethods->property; 878bf80f4bSopenharmony_ci if (property.type.isArray) { 888bf80f4bSopenharmony_ci // Array of properties. 898bf80f4bSopenharmony_ci for (size_t i = 0; i < property.count; i++) { 908bf80f4bSopenharmony_ci uintptr_t ptr = offset + i * containerProperty.size; 918bf80f4bSopenharmony_ci GatherEntityReferences(entities, entityReferences, containerProperty, ptr); 928bf80f4bSopenharmony_ci } 938bf80f4bSopenharmony_ci } else { 948bf80f4bSopenharmony_ci // This is a "non trivial container" 958bf80f4bSopenharmony_ci // (So it needs to read the data and not just the metadata to figure out the data structure). 968bf80f4bSopenharmony_ci const auto count = property.metaData.containerMethods->size(offset); 978bf80f4bSopenharmony_ci for (size_t i = 0; i < count; i++) { 988bf80f4bSopenharmony_ci uintptr_t ptr = property.metaData.containerMethods->get(offset, i); 998bf80f4bSopenharmony_ci GatherEntityReferences(entities, entityReferences, containerProperty, ptr); 1008bf80f4bSopenharmony_ci } 1018bf80f4bSopenharmony_ci } 1028bf80f4bSopenharmony_ci 1038bf80f4bSopenharmony_ci } else if (!property.metaData.memberProperties.empty()) { 1048bf80f4bSopenharmony_ci // Custom type (struct). Process sub properties recursively. 1058bf80f4bSopenharmony_ci for (size_t i = 0; i < property.count; i++) { 1068bf80f4bSopenharmony_ci for (const auto& child : property.metaData.memberProperties) { 1078bf80f4bSopenharmony_ci GatherEntityReferences(entities, entityReferences, child, offset + child.offset); 1088bf80f4bSopenharmony_ci } 1098bf80f4bSopenharmony_ci offset += property.size / property.count; 1108bf80f4bSopenharmony_ci } 1118bf80f4bSopenharmony_ci } 1128bf80f4bSopenharmony_ci} 1138bf80f4bSopenharmony_ci 1148bf80f4bSopenharmony_ciinline void RewriteEntityReferences( 1158bf80f4bSopenharmony_ci CORE_NS::IEcs& ecs, CORE_NS::Entity entity, BASE_NS::unordered_map<CORE_NS::Entity, CORE_NS::Entity>& oldToNew) 1168bf80f4bSopenharmony_ci{ 1178bf80f4bSopenharmony_ci // Go through the entity properties and update any entity references to point to the ones pointed by the oldToNew 1188bf80f4bSopenharmony_ci // map. 1198bf80f4bSopenharmony_ci auto managers = ecs.GetComponentManagers(); 1208bf80f4bSopenharmony_ci for (auto cm : managers) { 1218bf80f4bSopenharmony_ci if (auto id = cm->GetComponentId(entity); id != CORE_NS::IComponentManager::INVALID_COMPONENT_ID) { 1228bf80f4bSopenharmony_ci auto* data = cm->GetData(id); 1238bf80f4bSopenharmony_ci if (data) { 1248bf80f4bSopenharmony_ci // Find all entity references from this component. 1258bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::Entity*> entities; 1268bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::EntityReference*> entityRefs; 1278bf80f4bSopenharmony_ci uintptr_t offset = (uintptr_t)data->RLock(); 1288bf80f4bSopenharmony_ci if (offset) { 1298bf80f4bSopenharmony_ci for (const auto& property : data->Owner()->MetaData()) { 1308bf80f4bSopenharmony_ci GatherEntityReferences(entities, entityRefs, property, offset + property.offset); 1318bf80f4bSopenharmony_ci } 1328bf80f4bSopenharmony_ci 1338bf80f4bSopenharmony_ci // Rewrite old entity values with new ones. Assuming that the memory locations are the same as in 1348bf80f4bSopenharmony_ci // the RLock. NOTE: Keeping the read access open and we must not change any container sizes. 1358bf80f4bSopenharmony_ci if (!entities.empty() || !entityRefs.empty()) { 1368bf80f4bSopenharmony_ci data->WLock(); 1378bf80f4bSopenharmony_ci for (CORE_NS::Entity* entity : entities) { 1388bf80f4bSopenharmony_ci if (const auto it = oldToNew.find(*entity); it != oldToNew.end()) { 1398bf80f4bSopenharmony_ci *entity = it->second; 1408bf80f4bSopenharmony_ci } 1418bf80f4bSopenharmony_ci } 1428bf80f4bSopenharmony_ci for (CORE_NS::EntityReference* entity : entityRefs) { 1438bf80f4bSopenharmony_ci if (const auto it = oldToNew.find(*entity); it != oldToNew.end()) { 1448bf80f4bSopenharmony_ci *entity = ecs.GetEntityManager().GetReferenceCounted(it->second); 1458bf80f4bSopenharmony_ci } 1468bf80f4bSopenharmony_ci } 1478bf80f4bSopenharmony_ci data->WUnlock(); 1488bf80f4bSopenharmony_ci } 1498bf80f4bSopenharmony_ci } 1508bf80f4bSopenharmony_ci 1518bf80f4bSopenharmony_ci data->RUnlock(); 1528bf80f4bSopenharmony_ci } 1538bf80f4bSopenharmony_ci } 1548bf80f4bSopenharmony_ci } 1558bf80f4bSopenharmony_ci} 1568bf80f4bSopenharmony_ci 1578bf80f4bSopenharmony_ciinline BASE_NS::vector<CORE_NS::Entity> CloneEntities( 1588bf80f4bSopenharmony_ci CORE_NS::IEcs& srcEcs, BASE_NS::array_view<const CORE_NS::Entity> src, CORE_NS::IEcs& dstEcs) 1598bf80f4bSopenharmony_ci{ 1608bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::Entity> clonedEntities; 1618bf80f4bSopenharmony_ci clonedEntities.reserve(src.size()); 1628bf80f4bSopenharmony_ci for (const auto& srcEntity : src) { 1638bf80f4bSopenharmony_ci clonedEntities.emplace_back(CloneEntity(srcEcs, srcEntity, dstEcs)); 1648bf80f4bSopenharmony_ci } 1658bf80f4bSopenharmony_ci return clonedEntities; 1668bf80f4bSopenharmony_ci} 1678bf80f4bSopenharmony_ci 1688bf80f4bSopenharmony_ciinline BASE_NS::vector<CORE_NS::EntityReference> CloneEntityReferences( 1698bf80f4bSopenharmony_ci CORE_NS::IEcs& srcEcs, BASE_NS::array_view<const CORE_NS::EntityReference> src, CORE_NS::IEcs& dstEcs) 1708bf80f4bSopenharmony_ci{ 1718bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::EntityReference> clonedEntities; 1728bf80f4bSopenharmony_ci clonedEntities.reserve(src.size()); 1738bf80f4bSopenharmony_ci for (const auto& srcEntity : src) { 1748bf80f4bSopenharmony_ci clonedEntities.emplace_back(CloneEntityReference(srcEcs, srcEntity, dstEcs)); 1758bf80f4bSopenharmony_ci } 1768bf80f4bSopenharmony_ci return clonedEntities; 1778bf80f4bSopenharmony_ci} 1788bf80f4bSopenharmony_ci 1798bf80f4bSopenharmony_ciinline BASE_NS::vector<CORE_NS::EntityReference> CloneEntitiesUpdateRefs( 1808bf80f4bSopenharmony_ci CORE_NS::IEcs& srcEcs, BASE_NS::array_view<const CORE_NS::EntityReference> src, CORE_NS::IEcs& dstEcs) 1818bf80f4bSopenharmony_ci{ 1828bf80f4bSopenharmony_ci BASE_NS::unordered_map<CORE_NS::Entity, CORE_NS::Entity> oldToNew; 1838bf80f4bSopenharmony_ci 1848bf80f4bSopenharmony_ci BASE_NS::vector<CORE_NS::EntityReference> clonedEntities; 1858bf80f4bSopenharmony_ci clonedEntities.reserve(src.size()); 1868bf80f4bSopenharmony_ci for (const auto& srcEntity : src) { 1878bf80f4bSopenharmony_ci clonedEntities.emplace_back(CloneEntityReference(srcEcs, srcEntity, dstEcs)); 1888bf80f4bSopenharmony_ci oldToNew[srcEntity] = clonedEntities.back(); 1898bf80f4bSopenharmony_ci } 1908bf80f4bSopenharmony_ci 1918bf80f4bSopenharmony_ci for (auto& entity : clonedEntities) { 1928bf80f4bSopenharmony_ci RewriteEntityReferences(dstEcs, entity, oldToNew); 1938bf80f4bSopenharmony_ci } 1948bf80f4bSopenharmony_ci return clonedEntities; 1958bf80f4bSopenharmony_ci} 1968bf80f4bSopenharmony_ci 1978bf80f4bSopenharmony_ciinline bool isPropertyContainer(const CORE_NS::Property& property) 1988bf80f4bSopenharmony_ci{ 1998bf80f4bSopenharmony_ci return property.type == PROPERTYTYPE(CORE_NS::IPropertyHandle*); 2008bf80f4bSopenharmony_ci} 2018bf80f4bSopenharmony_ci 2028bf80f4bSopenharmony_ciinline CORE_NS::IPropertyHandle* ResolveContainerProperty(const CORE_NS::IPropertyHandle& handle, 2038bf80f4bSopenharmony_ci const BASE_NS::string& propertyPath, BASE_NS::string& path, BASE_NS::string& name) 2048bf80f4bSopenharmony_ci{ 2058bf80f4bSopenharmony_ci // Extract property path. 2068bf80f4bSopenharmony_ci auto separatorPosition = propertyPath.find_first_of('.'); 2078bf80f4bSopenharmony_ci if (separatorPosition == BASE_NS::string::npos) { 2088bf80f4bSopenharmony_ci return nullptr; 2098bf80f4bSopenharmony_ci } 2108bf80f4bSopenharmony_ci 2118bf80f4bSopenharmony_ci path = propertyPath.substr(0, separatorPosition); 2128bf80f4bSopenharmony_ci name = propertyPath.substr(separatorPosition + 1); 2138bf80f4bSopenharmony_ci 2148bf80f4bSopenharmony_ci CORE_NS::IPropertyHandle* result = nullptr; 2158bf80f4bSopenharmony_ci 2168bf80f4bSopenharmony_ci uintptr_t offset = uintptr_t(handle.RLock()); 2178bf80f4bSopenharmony_ci 2188bf80f4bSopenharmony_ci // Get potential container. 2198bf80f4bSopenharmony_ci auto propertyData = CORE_NS::PropertyData::FindProperty(handle.Owner()->MetaData(), path, offset); 2208bf80f4bSopenharmony_ci if (propertyData) { 2218bf80f4bSopenharmony_ci // Ensure it is a container. 2228bf80f4bSopenharmony_ci if (CORE_NS::isPropertyContainer(*propertyData.property)) { 2238bf80f4bSopenharmony_ci // Try to flush value to container. 2248bf80f4bSopenharmony_ci result = *(CORE_NS::IPropertyHandle**)(propertyData.offset); 2258bf80f4bSopenharmony_ci } 2268bf80f4bSopenharmony_ci } 2278bf80f4bSopenharmony_ci 2288bf80f4bSopenharmony_ci handle.RUnlock(); 2298bf80f4bSopenharmony_ci 2308bf80f4bSopenharmony_ci return result; 2318bf80f4bSopenharmony_ci} 2328bf80f4bSopenharmony_ci 2338bf80f4bSopenharmony_ciCORE_END_NAMESPACE() 2348bf80f4bSopenharmony_ci 2358bf80f4bSopenharmony_ci#endif 236