• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef API_ECS_SERIALIZER_ECSUTIL_H
17 #define API_ECS_SERIALIZER_ECSUTIL_H
18 
19 #include <base/containers/unordered_map.h>
20 #include <core/ecs/entity.h>
21 #include <core/ecs/intf_component_manager.h>
22 #include <core/ecs/intf_ecs.h>
23 #include <core/ecs/intf_entity_manager.h>
24 #include <core/property/intf_property_api.h>
25 #include <core/property/intf_property_handle.h>
26 #include <core/property/property_types.h>
27 #include <ecs_serializer/namespace.h>
28 
ECS_SERIALIZER_BEGIN_NAMESPACE()29 ECS_SERIALIZER_BEGIN_NAMESPACE()
30 
31 inline void CloneComponent(CORE_NS::Entity srcEntity, const CORE_NS::IComponentManager& srcManager,
32     CORE_NS::IEcs& dstEcs, CORE_NS::Entity dstEntity)
33 {
34     auto* dstManager = dstEcs.GetComponentManager(srcManager.GetUid());
35     if (dstManager) {
36         // Get copy destiantion property handle.
37         auto componentId = dstManager->GetComponentId(dstEntity);
38         if (componentId == CORE_NS::IComponentManager::INVALID_COMPONENT_ID) {
39             dstManager->Create(dstEntity);
40             componentId = dstManager->GetComponentId(dstEntity);
41         }
42         BASE_ASSERT(componentId != CORE_NS::IComponentManager::INVALID_COMPONENT_ID);
43         const auto* srcHandle = srcManager.GetData(srcEntity);
44         if (srcHandle) {
45             dstManager->SetData(dstEntity, *srcHandle);
46         }
47     }
48 }
49 
CloneComponents(CORE_NS::IEcs & srcEcs,CORE_NS::Entity srcEntity,CORE_NS::IEcs & dstEcs,CORE_NS::Entity dstEntity)50 inline void CloneComponents(
51     CORE_NS::IEcs& srcEcs, CORE_NS::Entity srcEntity, CORE_NS::IEcs& dstEcs, CORE_NS::Entity dstEntity)
52 {
53     BASE_NS::vector<CORE_NS::IComponentManager*> managers;
54     srcEcs.GetComponents(srcEntity, managers);
55     for (auto* srcManager : managers) {
56         CloneComponent(srcEntity, *srcManager, dstEcs, dstEntity);
57     }
58 }
59 
CloneEntity(CORE_NS::IEcs & srcEcs,CORE_NS::Entity src,CORE_NS::IEcs & dstEcs)60 inline CORE_NS::Entity CloneEntity(CORE_NS::IEcs& srcEcs, CORE_NS::Entity src, CORE_NS::IEcs& dstEcs)
61 {
62     CORE_NS::Entity dst = dstEcs.GetEntityManager().Create();
63     CloneComponents(srcEcs, src, dstEcs, dst);
64     return dst;
65 }
66 
CloneEntityReference(CORE_NS::IEcs & srcEcs,CORE_NS::Entity src,CORE_NS::IEcs & dstEcs)67 inline CORE_NS::EntityReference CloneEntityReference(CORE_NS::IEcs& srcEcs, CORE_NS::Entity src, CORE_NS::IEcs& dstEcs)
68 {
69     CORE_NS::EntityReference dst = dstEcs.GetEntityManager().CreateReferenceCounted();
70     CloneComponents(srcEcs, src, dstEcs, dst);
71     return dst;
72 }
73 
74 inline void GatherEntityReferences(BASE_NS::vector<CORE_NS::Entity*>& entities,
75     BASE_NS::vector<CORE_NS::EntityReference*>& entityReferences, const CORE_NS::Property& property,
76     uintptr_t offset = 0)
77 {
78     if (property.type == CORE_NS::PropertyType::ENTITY_T) {
79         entities.emplace_back(reinterpret_cast<CORE_NS::Entity*>(offset));
80     } else if (property.type == CORE_NS::PropertyType::ENTITY_REFERENCE_T) {
81         entityReferences.emplace_back(reinterpret_cast<CORE_NS::EntityReference*>(offset));
82     } else if (property.metaData.containerMethods) {
83         auto& containerProperty = property.metaData.containerMethods->property;
84         if (property.type.isArray) {
85             // Array of properties.
86             for (size_t i = 0; i < property.count; i++) {
87                 uintptr_t ptr = offset + i * containerProperty.size;
88                 GatherEntityReferences(entities, entityReferences, containerProperty, ptr);
89             }
90         } else {
91             // This is a "non trivial container"
92             // (So it needs to read the data and not just the metadata to figure out the data structure).
93             const auto count = property.metaData.containerMethods->size(offset);
94             for (size_t i = 0; i < count; i++) {
95                 uintptr_t ptr = property.metaData.containerMethods->get(offset, i);
96                 GatherEntityReferences(entities, entityReferences, containerProperty, ptr);
97             }
98         }
99     } else if (!property.metaData.memberProperties.empty()) {
100         // Custom type (struct). Process sub properties recursively.
101         for (size_t i = 0; i < property.count; i++) {
102             for (const auto& child : property.metaData.memberProperties) {
103                 GatherEntityReferences(entities, entityReferences, child, offset + child.offset);
104             }
105             offset += property.size / property.count;
106         }
107     }
108 }
109 
RewriteEntityReferences(CORE_NS::IEcs & ecs,CORE_NS::Entity entity,BASE_NS::unordered_map<CORE_NS::Entity,CORE_NS::Entity> & oldToNew)110 inline void RewriteEntityReferences(
111     CORE_NS::IEcs& ecs, CORE_NS::Entity entity, BASE_NS::unordered_map<CORE_NS::Entity, CORE_NS::Entity>& oldToNew)
112 {
113     // Go through the entity properties and update any entity references to point to the ones pointed by the oldToNew
114     // map.
115     auto managers = ecs.GetComponentManagers();
116     for (auto cm : managers) {
117         if (auto id = cm->GetComponentId(entity); id != CORE_NS::IComponentManager::INVALID_COMPONENT_ID) {
118             auto* data = cm->GetData(id);
119             if (data) {
120                 // Find all entity references from this component.
121                 BASE_NS::vector<CORE_NS::Entity*> entities;
122                 BASE_NS::vector<CORE_NS::EntityReference*> entityRefs;
123                 uintptr_t offset = (uintptr_t)data->RLock();
124                 if (offset) {
125                     for (const auto& property : data->Owner()->MetaData()) {
126                         GatherEntityReferences(entities, entityRefs, property, offset + property.offset);
127                     }
128 
129                     // Rewrite old entity values with new ones. Assuming that the memory locations are the same as in
130                     // the RLock. NOTE: Keeping the read access open and we must not change any container sizes.
131                     if (!entities.empty() || !entityRefs.empty()) {
132                         data->WLock();
133                         for (CORE_NS::Entity* current : entities) {
134                             if (const auto it = oldToNew.find(*current); it != oldToNew.end()) {
135                                 *current = it->second;
136                             }
137                         }
138                         for (CORE_NS::EntityReference* current : entityRefs) {
139                             if (const auto it = oldToNew.find(*current); it != oldToNew.end()) {
140                                 *current = ecs.GetEntityManager().GetReferenceCounted(it->second);
141                             }
142                         }
143                         data->WUnlock();
144                     }
145                 }
146 
147                 data->RUnlock();
148             }
149         }
150     }
151 }
152 
CloneEntities(CORE_NS::IEcs & srcEcs,BASE_NS::array_view<const CORE_NS::Entity> src,CORE_NS::IEcs & dstEcs)153 inline BASE_NS::vector<CORE_NS::Entity> CloneEntities(
154     CORE_NS::IEcs& srcEcs, BASE_NS::array_view<const CORE_NS::Entity> src, CORE_NS::IEcs& dstEcs)
155 {
156     BASE_NS::vector<CORE_NS::Entity> clonedEntities;
157     clonedEntities.reserve(src.size());
158     for (auto srcEntity : src) {
159         clonedEntities.emplace_back(CloneEntity(srcEcs, srcEntity, dstEcs));
160     }
161     return clonedEntities;
162 }
163 
CloneEntityReferences(CORE_NS::IEcs & srcEcs,BASE_NS::array_view<const CORE_NS::EntityReference> src,CORE_NS::IEcs & dstEcs)164 inline BASE_NS::vector<CORE_NS::EntityReference> CloneEntityReferences(
165     CORE_NS::IEcs& srcEcs, BASE_NS::array_view<const CORE_NS::EntityReference> src, CORE_NS::IEcs& dstEcs)
166 {
167     BASE_NS::vector<CORE_NS::EntityReference> clonedEntities;
168     clonedEntities.reserve(src.size());
169     for (const auto& srcEntity : src) {
170         clonedEntities.emplace_back(CloneEntityReference(srcEcs, srcEntity, dstEcs));
171     }
172     return clonedEntities;
173 }
174 
CloneEntitiesUpdateRefs(CORE_NS::IEcs & srcEcs,BASE_NS::array_view<const CORE_NS::EntityReference> src,CORE_NS::IEcs & dstEcs)175 inline BASE_NS::vector<CORE_NS::EntityReference> CloneEntitiesUpdateRefs(
176     CORE_NS::IEcs& srcEcs, BASE_NS::array_view<const CORE_NS::EntityReference> src, CORE_NS::IEcs& dstEcs)
177 {
178     BASE_NS::unordered_map<CORE_NS::Entity, CORE_NS::Entity> oldToNew;
179 
180     BASE_NS::vector<CORE_NS::EntityReference> clonedEntities;
181     clonedEntities.reserve(src.size());
182     for (const auto& srcEntity : src) {
183         clonedEntities.emplace_back(CloneEntityReference(srcEcs, srcEntity, dstEcs));
184         oldToNew[srcEntity] = clonedEntities.back();
185     }
186 
187     for (const auto& entity : clonedEntities) {
188         RewriteEntityReferences(dstEcs, entity, oldToNew);
189     }
190     return clonedEntities;
191 }
192 
193 ECS_SERIALIZER_END_NAMESPACE()
194 
195 #endif
196