1 /*
2  * Copyright (c) 2024 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 #include "entity_collection.h"
17 
18 #include <cinttypes>
19 #include <PropertyTools/property_data.h>
20 
21 #include <base/containers/fixed_string.h>
22 #include <core/ecs/intf_entity_manager.h>
23 #include <core/log.h>
24 #include <core/property/intf_property_api.h>
25 
26 #include "ecs_util.h"
27 
28 using namespace BASE_NS;
29 using namespace CORE_NS;
30 
SCENE_BEGIN_NAMESPACE()31 SCENE_BEGIN_NAMESPACE()
32 
33 EntityCollection::EntityCollection(IEcs& ecs, string_view uri, string_view contextUri)
34     : ecs_(ecs), uri_(uri), contextUri_(contextUri)
35 {}
36 
AddListener(IEntityCollection::IListener & listener)37 void EntityCollection::AddListener(IEntityCollection::IListener& listener)
38 {
39     BASE_ASSERT(&listener);
40     listeners_.emplace_back(&listener);
41 }
42 
RemoveListener(IEntityCollection::IListener & listener)43 void EntityCollection::RemoveListener(IEntityCollection::IListener& listener)
44 {
45     BASE_ASSERT(&listener);
46     for (size_t i = 0; i < listeners_.size(); ++i) {
47         if (&listener == listeners_[i]) {
48             listeners_.erase(listeners_.begin() + i);
49             return;
50         }
51     }
52 
53     // trying to remove a non-existent listener.
54     BASE_ASSERT(true);
55 }
56 
GetEcs() const57 IEcs& EntityCollection::GetEcs() const
58 {
59     return ecs_;
60 }
61 
GetUri() const62 string EntityCollection::GetUri() const
63 {
64     return uri_;
65 }
66 
SetUri(const BASE_NS::string & uri)67 void EntityCollection::SetUri(const BASE_NS::string& uri)
68 {
69     uri_ = uri;
70 }
71 
GetContextUri() const72 string EntityCollection::GetContextUri() const
73 {
74     return contextUri_;
75 }
76 
GetSrc() const77 string EntityCollection::GetSrc() const
78 {
79     return src_;
80 }
81 
SetSrc(string_view src)82 void EntityCollection::SetSrc(string_view src)
83 {
84     src_ = src;
85     MarkModified(true);
86 }
87 
GetType() const88 string EntityCollection::GetType() const
89 {
90     return type_;
91 }
92 
SetType(string_view type)93 void EntityCollection::SetType(string_view type)
94 {
95     type_ = type;
96     MarkModified(true);
97 }
98 
GetEntityCount() const99 size_t EntityCollection::GetEntityCount() const
100 {
101     return entities_.size();
102 }
103 
GetEntity(size_t collectionIndex) const104 EntityReference EntityCollection::GetEntity(size_t collectionIndex) const
105 {
106     BASE_ASSERT(collectionIndex < entities_.size());
107     if (collectionIndex >= entities_.size()) {
108         return EntityReference {};
109     }
110     return entities_[collectionIndex];
111 }
112 
GetEntity(string_view localContextId) const113 EntityReference EntityCollection::GetEntity(string_view localContextId) const
114 {
115     const auto it = entityIdentifiers_.find(localContextId);
116     if (it != entityIdentifiers_.end()) {
117         return it->second;
118     }
119     const auto itt = namedEntities_.find(localContextId);
120     if (itt != namedEntities_.end()) {
121         return itt->second;
122     }
123     return EntityReference {};
124 }
125 
GetEntityRecursive(string_view localContextId) const126 EntityReference EntityCollection::GetEntityRecursive(string_view localContextId) const
127 {
128     auto ret = GetEntity(localContextId);
129 
130     if (!CORE_NS::EntityUtil::IsValid(ret)) {
131         for (auto& it : collections_) {
132             ret = it->GetEntityRecursive(localContextId);
133             if (CORE_NS::EntityUtil::IsValid(ret)) {
134                 break;
135             }
136         }
137     }
138 
139     return ret;
140 }
141 
RemoveEntityRecursive(CORE_NS::Entity entity)142 void EntityCollection::RemoveEntityRecursive(CORE_NS::Entity entity)
143 {
144     for (auto entityRef = entities_.cbegin(); entityRef != entities_.cend();) {
145         if (entity == *entityRef) {
146             entityRef = entities_.erase(entityRef);
147         } else {
148             entityRef++;
149         }
150     }
151 
152     for (auto entityRef = namedEntities_.cbegin(); entityRef != namedEntities_.cend();) {
153         if (entityRef->second == entity) {
154             entityRef = namedEntities_.erase(entityRef);
155         } else {
156             ++entityRef;
157         }
158     }
159 
160     auto uniqueIdentifier = GetUniqueIdentifier(entity);
161     if (!uniqueIdentifier.empty()) {
162         entityIdentifiers_.erase(uniqueIdentifier);
163     }
164 
165     for (auto& it : collections_) {
166         it->RemoveEntityRecursive(entity);
167     }
168 }
169 
GetEntities() const170 array_view<const EntityReference> EntityCollection::GetEntities() const
171 {
172     return entities_;
173 }
174 
AddEntity(EntityReference entity)175 void EntityCollection::AddEntity(EntityReference entity)
176 {
177     AddEntities({ &entity, 1 });
178 }
179 
AddEntities(array_view<const EntityReference> entities)180 void EntityCollection::AddEntities(array_view<const EntityReference> entities)
181 {
182     entities_.reserve(entities_.size() + entities.size());
183     for (const auto& entity : entities) {
184         if (entity != Entity {}) {
185             // TODO: make sure that the same entity is not added twice.
186             entities_.emplace_back(entity);
187         } else {
188             CORE_LOG_D("Trying to add null entity reference to a collection");
189         }
190     }
191     MarkModified(true);
192 }
193 
RemoveEntity(EntityReference entity)194 bool EntityCollection::RemoveEntity(EntityReference entity)
195 {
196     for (size_t i = 0; i < entities_.size(); ++i) {
197         if (entities_[i] == entity) {
198             entities_.erase(entities_.begin() + i);
199 
200             // Also remove any related id mappings.
201             for (auto it = namedEntities_.begin(); it != namedEntities_.end(); ++it) {
202                 if (it->second == entity) {
203                     namedEntities_.erase(it);
204                     break;
205                 }
206             }
207 
208             auto uniqueIdentifier = GetUniqueIdentifier(entity);
209             if (!uniqueIdentifier.empty()) {
210                 entityIdentifiers_.erase(uniqueIdentifier);
211             }
212 
213             // TODO:  If this collection is overriding another "template" collection, when removing entities, we
214             // need to remember that and the information about deletion needs to be serialized. Maybe check if
215             // (src_.empty()). However this also needs to work with undo
216 
217             MarkModified(true);
218             return true;
219         }
220     }
221 
222     // Not found. Check the sub-collections.
223     for (auto& collection : collections_) {
224         BASE_ASSERT(collection);
225         if (collection->RemoveEntity(entity)) {
226             MarkModified(true);
227             return true;
228         }
229     }
230 
231     return false;
232 }
233 
RemoveEntities(array_view<const EntityReference> entities)234 void EntityCollection::RemoveEntities(array_view<const EntityReference> entities)
235 {
236     for (auto& entity : entities) {
237         RemoveEntity(entity);
238     }
239 }
240 
SetId(string_view id,EntityReference entity)241 void EntityCollection::SetId(string_view id, EntityReference entity)
242 {
243     namedEntities_[id] = entity;
244 }
245 
GetId(Entity entity) const246 string_view EntityCollection::GetId(Entity entity) const
247 {
248     for (auto& it : namedEntities_) {
249         if (it.second == entity) {
250             return it.first;
251         }
252     }
253     return {};
254 }
255 
GetIdRecursive(Entity entity) const256 string_view EntityCollection::GetIdRecursive(Entity entity) const
257 {
258     auto ret = GetId(entity);
259     if (ret.empty()) {
260         for (auto& it : collections_) {
261             ret = it->GetIdRecursive(entity);
262             if (!ret.empty()) {
263                 break;
264             }
265         }
266     }
267     return ret;
268 }
269 
SetUniqueIdentifier(string_view id,EntityReference entity)270 void EntityCollection::SetUniqueIdentifier(string_view id, EntityReference entity)
271 {
272     entityIdentifiers_[id] = entity;
273 }
274 
GetUniqueIdentifier(Entity entity) const275 string_view EntityCollection::GetUniqueIdentifier(Entity entity) const
276 {
277     for (auto& it : entityIdentifiers_) {
278         if (it.second == entity) {
279             return it.first;
280         }
281     }
282     return {};
283 }
284 
GetUniqueIdentifierRecursive(Entity entity) const285 string_view EntityCollection::GetUniqueIdentifierRecursive(Entity entity) const
286 {
287     auto ret = GetUniqueIdentifier(entity);
288     if (ret.empty()) {
289         for (auto& it : collections_) {
290             ret = it->GetUniqueIdentifierRecursive(entity);
291             if (!ret.empty()) {
292                 break;
293             }
294         }
295     }
296     return ret;
297 }
298 
GetSubCollectionCount() const299 size_t EntityCollection::GetSubCollectionCount() const
300 {
301     return collections_.size();
302 }
303 
GetSubCollection(size_t index)304 IEntityCollection* EntityCollection::GetSubCollection(size_t index)
305 {
306     if (index < 0 || index >= collections_.size()) {
307         return nullptr;
308     }
309     return collections_.at(index).get();
310 }
311 
GetSubCollection(size_t index) const312 const IEntityCollection* EntityCollection::GetSubCollection(size_t index) const
313 {
314     if (index < 0 || index >= collections_.size()) {
315         return nullptr;
316     }
317     return collections_.at(index).get();
318 }
319 
GetSubCollectionIndex(string_view uri) const320 int32_t EntityCollection::GetSubCollectionIndex(string_view uri) const
321 {
322     for (size_t i = 0; i < collections_.size(); ++i) {
323         BASE_ASSERT(collections_[i]);
324         if (collections_[i]->GetUri() == uri) {
325             return static_cast<int32_t>(i);
326         }
327     }
328     return -1;
329 }
330 
GetSubCollectionIndexByRoot(Entity entity) const331 int32_t EntityCollection::GetSubCollectionIndexByRoot(Entity entity) const
332 {
333     if (entity != Entity {}) {
334         for (size_t i = 0; i < collections_.size(); ++i) {
335             BASE_ASSERT(collections_[i]);
336             if (collections_[i]->GetEntity("/") == entity) {
337                 return static_cast<int32_t>(i);
338             }
339         }
340     }
341     return -1;
342 }
343 
AddSubCollection(string_view uri,string_view contextUri,bool serializable)344 IEntityCollection& EntityCollection::AddSubCollection(string_view uri, string_view contextUri, bool serializable)
345 {
346     auto collection = EntityCollection::Ptr { new EntityCollection(ecs_, uri, contextUri) };
347     collection->SetSerialized(serializable);
348     collections_.emplace_back(move(collection));
349 
350     // listen to changes in subcollection
351     collections_.back()->AddListener(*this);
352 
353     if (serializable) {
354         MarkModified(true);
355     }
356     return *collections_.back();
357 }
358 
AddSubCollectionClone(IEntityCollection & collection,string_view uri)359 IEntityCollection& EntityCollection::AddSubCollectionClone(IEntityCollection& collection, string_view uri)
360 {
361     // TODO: use just the public api
362     collections_.emplace_back(EntityCollection::Ptr { new EntityCollection(ecs_, uri, collection.GetContextUri()) });
363     auto& ec = *collections_.back();
364     static_cast<EntityCollection&>(collection).ClonePrivate(ec);
365 
366     // listen to changes in subcollection
367     ec.AddListener(*this);
368 
369     MarkModified(true);
370     return ec;
371 }
372 
RemoveSubCollection(size_t index)373 void EntityCollection::RemoveSubCollection(size_t index)
374 {
375     BASE_ASSERT(index < collections_.size());
376     if (index < collections_.size()) {
377         // stop listening to changes in subcollection
378         auto& ec = collections_.at(index);
379         ec->RemoveListener(*this);
380 
381         collections_.erase(collections_.begin() + index);
382         MarkModified(true);
383     }
384 }
385 
GetEntityCountRecursive(bool includeDestroyed,bool includeNonSerialized) const386 size_t EntityCollection::GetEntityCountRecursive(bool includeDestroyed, bool includeNonSerialized) const
387 {
388     if (!includeDestroyed && IsMarkedDestroyed()) {
389         return 0;
390     }
391 
392     if (!includeNonSerialized && !IsSerialized()) {
393         return 0;
394     }
395 
396     auto size = entities_.size();
397     for (const auto& collection : collections_) {
398         BASE_ASSERT(collection);
399         size += collection->GetEntityCountRecursive(includeDestroyed, includeNonSerialized);
400     }
401     return size;
402 }
403 
GetEntitiesRecursive(bool includeDestroyed,vector<EntityReference> & entitiesOut,bool includeNonSerialized) const404 void EntityCollection::GetEntitiesRecursive(
405     bool includeDestroyed, vector<EntityReference>& entitiesOut, bool includeNonSerialized) const
406 {
407     // NOTE: Cloning depends on ordering of entitiesOut.
408     entitiesOut.reserve(entitiesOut.size() + GetEntityCountRecursive(includeDestroyed, includeNonSerialized));
409     DoGetEntitiesRecursive(includeDestroyed, includeNonSerialized, entitiesOut);
410 }
411 
DoGetEntitiesRecursive(bool includeDestroyed,bool includeNonSerialized,vector<EntityReference> & entitiesOut) const412 void EntityCollection::DoGetEntitiesRecursive(
413     bool includeDestroyed, bool includeNonSerialized, vector<EntityReference>& entitiesOut) const
414 {
415     if (!includeDestroyed && IsMarkedDestroyed()) {
416         return;
417     }
418 
419     if (!includeNonSerialized && !IsSerialized()) {
420         return;
421     }
422 
423     entitiesOut.insert(entitiesOut.end(), entities_.begin(), entities_.end());
424     for (const auto& collection : collections_) {
425         BASE_ASSERT(collection);
426         collection->DoGetEntitiesRecursive(includeDestroyed, includeNonSerialized, entitiesOut);
427     }
428 }
429 
Contains(Entity entity) const430 bool EntityCollection::Contains(Entity entity) const
431 {
432     for (auto& it : entities_) {
433         if (it == entity) {
434             return true;
435         }
436     }
437     for (const auto& collection : collections_) {
438         if (!collection->IsMarkedDestroyed()) {
439             if (collection->Contains(entity)) {
440                 return true;
441             }
442         }
443     }
444     return false;
445 }
446 
IsExternal(Entity entity) const447 bool EntityCollection::IsExternal(Entity entity) const
448 {
449     for (auto& it : entities_) {
450         if (it == entity) {
451             return false;
452         }
453     }
454     return true;
455 }
456 
isSubCollectionRoot(Entity entity) const457 bool EntityCollection::isSubCollectionRoot(Entity entity) const
458 {
459     if (entity == Entity {}) {
460         return false;
461     }
462 
463     for (const auto& collection : collections_) {
464         if (collection->GetEntity("/") == entity) {
465             return true;
466         }
467     }
468 
469     return false;
470 }
471 
GetReference(CORE_NS::Entity entity) const472 CORE_NS::EntityReference EntityCollection::GetReference(CORE_NS::Entity entity) const
473 {
474     if (Contains(entity)) {
475         auto ref = GetEcs().GetEntityManager().GetReferenceCounted(entity);
476 
477         // Check that this entity was reference counted already (it should be part of the collection).
478         CORE_ASSERT(ref.GetRefCount() > 1);
479 
480         return ref;
481     }
482     return {};
483 }
484 
SetActive(bool active)485 void EntityCollection::SetActive(bool active)
486 {
487     isActive_ = active;
488     const bool effectivelyActive = isActive_ && !isMarkedDestroyed_;
489 
490     auto& em = ecs_.GetEntityManager();
491     for (auto& entity : entities_) {
492         em.SetActive(entity, effectivelyActive);
493     }
494 
495     for (auto& collection : collections_) {
496         BASE_ASSERT(collection);
497         collection->SetActive(active);
498     }
499 }
500 
IsActive() const501 bool EntityCollection::IsActive() const
502 {
503     return isActive_;
504 }
505 
MarkDestroyed(bool destroyed)506 void EntityCollection::MarkDestroyed(bool destroyed)
507 {
508     MarkModified(true);
509     isMarkedDestroyed_ = destroyed;
510     const bool effectivelyActive = isActive_ && !isMarkedDestroyed_;
511 
512     // Change the active state of entities without changing the active state of the collection itself.
513     auto& em = ecs_.GetEntityManager();
514     for (auto& entity : entities_) {
515         em.SetActive(entity, effectivelyActive);
516     }
517 
518     for (auto& collection : collections_) {
519         BASE_ASSERT(collection);
520         collection->MarkDestroyed(destroyed);
521     }
522 }
523 
IsMarkedDestroyed() const524 bool EntityCollection::IsMarkedDestroyed() const
525 {
526     return isMarkedDestroyed_;
527 }
528 
MarkModified(bool modified)529 void EntityCollection::MarkModified(bool modified)
530 {
531     if (!IsSerialized()) {
532         return;
533     }
534 
535     if (isMarkedModified_ != modified) {
536         isMarkedModified_ = modified;
537         for (auto* l : listeners_) {
538             l->ModifiedChanged(*this, modified);
539         }
540     }
541 }
542 
MarkModified(bool modified,bool recursive)543 void EntityCollection::MarkModified(bool modified, bool recursive)
544 {
545     if (!IsSerialized()) {
546         return;
547     }
548 
549     if (recursive && !collections_.empty()) {
550         for (auto& c : collections_) {
551             c->MarkModified(modified, true);
552         }
553     }
554     MarkModified(modified);
555 }
556 
IsMarkedModified() const557 bool EntityCollection::IsMarkedModified() const
558 {
559     return isMarkedModified_;
560 }
561 
Clear()562 void EntityCollection::Clear()
563 {
564     serializationInfo_.clear();
565     namedEntities_.clear();
566     entityIdentifiers_.clear();
567     entities_.clear();
568     collections_.clear();
569     listeners_.clear();
570 
571     MarkModified(true);
572 }
573 
CopyContents(IEntityCollection & srcCollection)574 void EntityCollection::CopyContents(IEntityCollection& srcCollection)
575 {
576     // TODO: use just the public api
577     static_cast<EntityCollection&>(srcCollection).ClonePrivate(*this);
578     MarkModified(true);
579 }
580 
AddEntityToSubcollection(BASE_NS::string_view collection,BASE_NS::string_view name,CORE_NS::Entity entity,bool makeUnique)581 void EntityCollection::AddEntityToSubcollection(
582     BASE_NS::string_view collection, BASE_NS::string_view name, CORE_NS::Entity entity, bool makeUnique)
583 {
584     auto collectionIx = GetSubCollectionIndex(collection);
585     if (collectionIx == -1) {
586         AddSubCollection(collection, {}, !makeUnique);
587         collectionIx = GetSubCollectionCount() - 1;
588     }
589 
590     if (auto targetCollection = GetSubCollection(collectionIx)) {
591         BASE_NS::string postFixed(name.data(), name.size());
592         if (makeUnique) {
593             postFixed.append(":");
594             postFixed.append(BASE_NS::to_hex(entity.id));
595         }
596         if (!CORE_NS::EntityUtil::IsValid(targetCollection->GetEntity(postFixed))) {
597             auto ref = ecs_.GetEntityManager().GetReferenceCounted(entity);
598             targetCollection->AddEntity(ref);
599             targetCollection->SetUniqueIdentifier(postFixed, ref);
600         }
601     }
602 }
603 
IsSerialized() const604 bool EntityCollection::IsSerialized() const
605 {
606     return isSerialized_;
607 }
608 
SetSerialized(bool serialize)609 void EntityCollection::SetSerialized(bool serialize)
610 {
611     isSerialized_ = serialize;
612 }
613 
614 // TODO: clean up copying.
615 namespace {
CloneEntitiesFromCollection(IEntityCollection & srcCollection,IEntityCollection & dstCollection,IEntityCollection & srcSerializationCollection,IEntityCollection & dstSerializationCollection,array_view<const EntityReference> entities,unordered_map<Entity,Entity> & oldToNew,vector<EntityReference> & clonedOut)616 void CloneEntitiesFromCollection(IEntityCollection& srcCollection, IEntityCollection& dstCollection,
617     IEntityCollection& srcSerializationCollection, IEntityCollection& dstSerializationCollection,
618     array_view<const EntityReference> entities, unordered_map<Entity, Entity>& oldToNew,
619     vector<EntityReference>& clonedOut)
620 {
621     const size_t entityCount = entities.size();
622     for (size_t i = 0; i < entityCount; ++i) {
623         auto srcEntity = entities[i];
624 
625         // Copy the serialization and subcollection info.
626         auto subCollectionIndex = srcCollection.GetSubCollectionIndexByRoot(srcEntity);
627         if (subCollectionIndex >= 0) {
628             auto* srcSubCollection = srcCollection.GetSubCollection(subCollectionIndex);
629             auto& dstSubCollection =
630                 dstCollection.AddSubCollection(srcSubCollection->GetUri(), srcSubCollection->GetContextUri());
631             dstSubCollection.SetSrc(srcSubCollection->GetSrc());
632 
633             // Recursively copy sub collection.
634             CloneEntitiesFromCollection(*srcSubCollection, dstSubCollection, srcSerializationCollection,
635                 dstSerializationCollection, srcSubCollection->GetEntities(), oldToNew, clonedOut);
636 
637             // Need to find the collection roots manually.
638             // TODO: a bit messy that the colelctions are iterated separately.
639             // TODO: no easy way to get the root entity.
640             const size_t collectionCount = srcSubCollection->GetSubCollectionCount();
641             for (size_t j = 0; j < collectionCount; ++j) {
642                 auto* sc = srcSubCollection->GetSubCollection(j);
643                 auto root = sc->GetEntity("/");
644                 if (root != Entity {}) {
645                     CloneEntitiesFromCollection(*srcSubCollection, dstSubCollection, srcSerializationCollection,
646                         dstSerializationCollection, { &root, 1 }, oldToNew, clonedOut);
647                 }
648             }
649 
650         } else if (!srcCollection.IsExternal(srcEntity)) {
651             auto dstEntity = CloneEntityReference(srcCollection.GetEcs(), srcEntity, dstCollection.GetEcs());
652 
653             clonedOut.emplace_back(dstEntity);
654             oldToNew[srcEntity] = dstEntity;
655 
656             dstCollection.AddEntity(dstEntity);
657             auto id = srcCollection.GetId(srcEntity);
658             if (!id.empty()) {
659                 dstCollection.SetId(id, dstEntity);
660             }
661 
662             // Note that the root collections contain all the serialization info.
663             for (auto& cm : srcCollection.GetEcs().GetComponentManagers()) {
664                 auto* properties = srcSerializationCollection.GetSerializedProperties(srcEntity, cm->GetUid());
665                 if (properties) {
666                     dstSerializationCollection.MarkComponentSerialized(dstEntity, cm->GetUid(), true);
667                     for (auto& property : *properties) {
668                         dstSerializationCollection.MarkPropertySerialized(dstEntity, cm->GetUid(), property, true);
669                     }
670                 }
671             }
672         }
673     }
674 }
675 } // namespace
676 
CopyContentsWithSerialization(IEntityCollection & srcCollection,array_view<const EntityReference> entities)677 vector<EntityReference> EntityCollection::CopyContentsWithSerialization(
678     IEntityCollection& srcCollection, array_view<const EntityReference> entities)
679 {
680     unordered_map<Entity, Entity> oldToNew;
681 
682     vector<EntityReference> entitiesOut;
683     entitiesOut.reserve(entities.size());
684     CloneEntitiesFromCollection(srcCollection, *this, srcCollection, *this, entities, oldToNew, entitiesOut);
685 
686     for (auto& entity : entitiesOut) {
687         RewriteEntityReferences(GetEcs(), entity, oldToNew);
688     }
689     return entitiesOut;
690 }
691 
CopyContentsWithSerialization(IEntityCollection & srcCollection)692 vector<EntityReference> EntityCollection::CopyContentsWithSerialization(IEntityCollection& srcCollection)
693 {
694     vector<EntityReference> entitiesIn;
695     srcCollection.GetEntitiesRecursive(false, entitiesIn);
696     return CopyContentsWithSerialization(srcCollection, entitiesIn);
697 }
698 
ClonePrivate(EntityCollection & dst) const699 void EntityCollection::ClonePrivate(EntityCollection& dst) const
700 {
701     // Clone all collections recursively.
702     DoCloneRecursive(dst);
703 
704     //
705     // Remap entity properties that are pointing to the src entities to point to cloned ones.
706     //
707     unordered_map<Entity, Entity> oldToNew;
708 
709     vector<EntityReference> sourceEntities;
710     GetEntitiesRecursive(false, sourceEntities);
711     vector<EntityReference> clonedEntities;
712     dst.GetEntitiesRecursive(false, clonedEntities);
713 
714     // NOTE: Assuming the order in GetEntitiesRecursive is consistent.
715     BASE_ASSERT(sourceEntities.size() == clonedEntities.size());
716     const auto entityCount = sourceEntities.size();
717     for (size_t i = 0; i < entityCount; ++i) {
718         oldToNew[sourceEntities[i]] = clonedEntities[i];
719     }
720     for (auto& entity : clonedEntities) {
721         RewriteEntityReferences(dst.GetEcs(), entity, oldToNew);
722     }
723 }
724 
DoCloneRecursive(EntityCollection & dst) const725 void EntityCollection::DoCloneRecursive(EntityCollection& dst) const
726 {
727     // Clone entities.
728     dst.entities_ = CloneEntityReferences(ecs_, { entities_.data(), entities_.size() }, dst.GetEcs());
729 
730     // Create id mapping but reference cloned entities instead of the original
731     BASE_ASSERT(entities_.size() == dst.entities_.size());
732     dst.namedEntities_.clear();
733     dst.namedEntities_.reserve(namedEntities_.size());
734     const auto entityCount = entities_.size();
735     for (const auto& it : namedEntities_) {
736         for (size_t i = 0; i < entityCount; ++i) {
737             if (it.second == entities_[i]) {
738                 dst.SetId(it.first, dst.entities_[i]);
739                 break;
740             }
741         }
742     }
743 
744     // Recurse.
745     dst.collections_.reserve(collections_.size());
746     for (auto& collection : collections_) {
747         BASE_ASSERT(collection);
748 
749         if (!collection->IsMarkedDestroyed()) {
750             dst.collections_.emplace_back(EntityCollection::Ptr {
751                 new EntityCollection(dst.GetEcs(), collection->GetUri(), collection->GetContextUri()) });
752             auto& clonedChild = *dst.collections_.back();
753             collection->DoCloneRecursive(clonedChild);
754         }
755     }
756 }
757 
758 namespace {
759 
SetPropertyDefined(EntityCollection::PropertyList & pl,string_view propertyPath)760 bool SetPropertyDefined(EntityCollection::PropertyList& pl, string_view propertyPath)
761 {
762     for (const auto& prop : pl) {
763         if (prop == propertyPath) {
764             // Already marked as a property defined by this node.
765             return false;
766         }
767 
768         // check if the property we are trying to set is a sub-property of an already defined property
769         auto len1 = prop.length();
770         auto len2 = propertyPath.length();
771         if (len2 > len1) {
772             auto view1 = prop.substr(0, len1);
773             auto view2 = propertyPath.substr(0, len1);
774             if (view1 == view2) {
775                 // already defined in a higher level, so no need to define this sub-property
776                 return false;
777             }
778         }
779     }
780     pl.push_back(string(propertyPath));
781     return true;
782 }
SetPropertyUndefined(EntityCollection::PropertyList & pl,string_view propertyPath)783 bool SetPropertyUndefined(EntityCollection::PropertyList& pl, string_view propertyPath)
784 {
785     for (size_t i = 0; i < pl.size(); ++i) {
786         if (pl[i] == propertyPath) {
787             pl.erase(pl.begin() + i);
788             return true;
789         }
790     }
791     return false;
792 }
793 
794 } // namespace
795 
MarkComponentSerialized(Entity entity,Uid component,bool serialize)796 bool EntityCollection::MarkComponentSerialized(Entity entity, Uid component, bool serialize)
797 {
798     bool changed = false;
799     const auto entityInfo = serializationInfo_.find(entity);
800     const bool entityFound = (entityInfo != serializationInfo_.end());
801     if (serialize) {
802         if (!entityFound) {
803             serializationInfo_[entity][component] = {};
804             changed = true;
805         } else {
806             const auto componentInfo = entityInfo->second.find(component);
807             const bool componentFound = (componentInfo != entityInfo->second.end());
808             if (!componentFound) {
809                 entityInfo->second[component] = {};
810                 changed = true;
811             }
812         }
813     } else {
814         if (entityFound) {
815             entityInfo->second.erase(component);
816             changed = true;
817         }
818     }
819 
820     if (changed) {
821         MarkModified(true);
822     }
823 
824     return changed;
825 }
826 
MarkAllPropertiesSerialized(Entity entity,Uid component)827 bool EntityCollection::MarkAllPropertiesSerialized(Entity entity, Uid component)
828 {
829     bool changed = false;
830 
831     auto cm = GetEcs().GetComponentManager(component);
832     if (!cm) {
833         CORE_LOG_W("Set modified: Unrecognized component");
834         return false;
835     }
836 
837     auto info = serializationInfo_.find(entity);
838     if (info == serializationInfo_.end()) {
839         serializationInfo_[entity] = {};
840         info = serializationInfo_.find(entity);
841         changed = true;
842     }
843 
844     const auto& propertyApi = cm->GetPropertyApi();
845     const auto propertyCount = propertyApi.PropertyCount();
846     for (size_t i = 0; i < propertyCount; ++i) {
847         auto* property = propertyApi.MetaData(i);
848         changed = changed | SetPropertyDefined(info->second[component], property->name);
849     }
850 
851     if (changed) {
852         MarkModified(true);
853     }
854 
855     return changed;
856 }
857 
MarkPropertySerialized(Entity entity,Uid component,string_view propertyPath,bool serialize)858 bool EntityCollection::MarkPropertySerialized(Entity entity, Uid component, string_view propertyPath, bool serialize)
859 {
860     bool changed = false;
861 
862     auto* cm = GetEcs().GetComponentManager(component);
863     if (cm) {
864         auto info = serializationInfo_.find(entity);
865         if (serialize) {
866             if (info == serializationInfo_.end()) {
867                 serializationInfo_[entity][component] = {};
868                 info = serializationInfo_.find(entity);
869                 changed = true;
870             }
871             changed = changed | SetPropertyDefined(info->second[component], propertyPath);
872         } else {
873             if (info != serializationInfo_.end()) {
874                 changed = changed | SetPropertyUndefined(info->second[component], propertyPath);
875             }
876         }
877     }
878 
879     if (changed) {
880         MarkModified(true);
881     }
882 
883     return changed;
884 }
885 
GetSerializedProperties(Entity entity,Uid component) const886 const IEntityCollection::PropertyList* EntityCollection::GetSerializedProperties(Entity entity, Uid component) const
887 {
888     const auto info = serializationInfo_.find(entity);
889     if (info != serializationInfo_.end()) {
890         const auto props = info->second.find(component);
891         if (props != info->second.end()) {
892             return &props->second;
893         }
894     }
895     return nullptr;
896 }
897 
IsPropertySerialized(Entity entity,Uid component,string_view propertyPath)898 bool EntityCollection::IsPropertySerialized(Entity entity, Uid component, string_view propertyPath)
899 {
900     auto info = serializationInfo_.find(entity);
901     if (info == serializationInfo_.end()) {
902         return false;
903     } else {
904         const auto props = info->second.find(component);
905         if (props == info->second.end()) {
906             return false;
907         } else {
908             for (auto& prop : props->second) {
909                 if (prop == propertyPath) {
910                     return true;
911                 }
912             }
913         }
914     }
915     return false;
916 }
917 
Destroy()918 void EntityCollection::Destroy()
919 {
920     delete this;
921 }
922 
~EntityCollection()923 EntityCollection::~EntityCollection()
924 {
925     Clear();
926 }
927 
ModifiedChanged(IEntityCollection & entityCollection,bool modified)928 void EntityCollection::ModifiedChanged(IEntityCollection& entityCollection, bool modified)
929 {
930     // subcollection changed, propagate modified status
931     if (modified) {
932         MarkModified(modified);
933     }
934 }
935 
CreateNewEntityCollection(string_view uri,string_view contextUri)936 IEntityCollection::Ptr EntityCollection::CreateNewEntityCollection(string_view uri, string_view contextUri)
937 {
938     return EntityCollection::Ptr { new EntityCollection(ecs_, uri, contextUri) };
939 }
940 
941 SCENE_END_NAMESPACE()
942