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