• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <algorithm>
17 #include <atomic>
18 #include <cstdint>
19 
20 #include <base/containers/array_view.h>
21 #include <base/containers/iterator.h>
22 #include <base/containers/unique_ptr.h>
23 #include <base/containers/unordered_map.h>
24 #include <base/containers/vector.h>
25 #include <base/namespace.h>
26 #include <base/util/uid.h>
27 #include <core/ecs/entity.h>
28 #include <core/ecs/intf_component_manager.h>
29 #include <core/ecs/intf_ecs.h>
30 #include <core/ecs/intf_system.h>
31 #include <core/log.h>
32 #include <core/namespace.h>
33 #include <core/perf/cpu_perf_scope.h>
34 #include <core/plugin/intf_plugin.h>
35 #include <core/plugin/intf_plugin_register.h>
36 #include <core/threading/intf_thread_pool.h>
37 
38 #include "ecs/entity_manager.h"
39 
40 CORE_BEGIN_NAMESPACE()
41 namespace {
42 using BASE_NS::array_view;
43 using BASE_NS::pair;
44 using BASE_NS::Uid;
45 using BASE_NS::unique_ptr;
46 using BASE_NS::unordered_map;
47 using BASE_NS::vector;
48 
49 class Ecs final : public IEcs, IPluginRegister::ITypeInfoListener {
50 public:
51     Ecs(IClassFactory&, const IThreadPool::Ptr& threadPool);
52     ~Ecs() override;
53 
54     Ecs(const Ecs&) = delete;
55     Ecs(const Ecs&&) = delete;
56     Ecs& operator=(const Ecs&) = delete;
57     Ecs& operator=(const Ecs&&) = delete;
58 
59     IEntityManager& GetEntityManager() override;
60     const IEntityManager& GetEntityManager() const override;
61     void GetComponents(Entity entity, vector<IComponentManager*>& result) const override;
62     vector<ISystem*> GetSystems() const override;
63     ISystem* GetSystem(const Uid& uid) const override;
64     vector<IComponentManager*> GetComponentManagers() const override;
65     IComponentManager* GetComponentManager(const Uid& uid) const override;
66     Entity CloneEntity(Entity entity) override;
67     void ProcessEvents() override;
68 
69     void Initialize() override;
70     bool Update(uint64_t time, uint64_t delta) override;
71     void Uninitialize() override;
72 
73     IComponentManager* CreateComponentManager(const ComponentManagerTypeInfo& componentManagerTypeInfo) override;
74     ISystem* CreateSystem(const SystemTypeInfo& systemInfo) override;
75 
76     void AddListener(EntityListener& listener) override;
77     void RemoveListener(EntityListener& listener) override;
78     void AddListener(ComponentListener& listener) override;
79     void RemoveListener(ComponentListener& listener) override;
80     void AddListener(IComponentManager& manager, ComponentListener& listener) override;
81     void RemoveListener(IComponentManager& manager, ComponentListener& listener) override;
82 
83     void RequestRender() override;
84     void SetRenderMode(RenderMode renderMode) override;
85     RenderMode GetRenderMode() override;
86 
87     bool NeedRender() const override;
88 
89     IClassFactory& GetClassFactory() const override;
90 
91     const IThreadPool::Ptr& GetThreadPool() const override;
92 
93     float GetTimeScale() const override;
94     void SetTimeScale(float scale) override;
95 
96     void Ref() noexcept override;
97     void Unref() noexcept override;
98 
99 protected:
100     using SystemPtr = unique_ptr<ISystem, SystemTypeInfo::DestroySystemFn>;
101     using ManagerPtr = unique_ptr<IComponentManager, ComponentManagerTypeInfo::DestroyComponentManagerFn>;
102 
103     // IPluginRegister::ITypeInfoListener
104     void OnTypeInfoEvent(EventType type, array_view<const ITypeInfo* const> typeInfos) override;
105 
106     void ProcessComponentEvents(
107         IEcs::ComponentListener::EventType eventType, array_view<const Entity> removedEntities) const;
108 
109     IThreadPool::Ptr threadPool_;
110 
111     // for storing systems and component managers in creation order
112     vector<SystemPtr> systemOrder_;
113     vector<ManagerPtr> managerOrder_;
114     // for finding systems and component managers with UID
115     unordered_map<Uid, ISystem*> systems_;
116     unordered_map<Uid, IComponentManager*> managers_;
117 
118     vector<EntityListener*> entityListeners_;
119     vector<ComponentListener*> componentListeners_;
120     unordered_map<IComponentManager*, vector<ComponentListener*>> componentManagerListeners_;
121 
122     bool needRender_ { false };
123     bool renderRequested_ { false };
124     RenderMode renderMode_ { RENDER_ALWAYS };
125 
126     IClassFactory& pluginRegistry_;
127     EntityManager entityManager_;
128 
129     vector<pair<PluginToken, const IEcsPlugin*>> plugins_;
130     float timeScale_ { 1.f };
131     std::atomic<int32_t> refcnt_ { 0 };
132 
133     bool processingEvents_ { false };
134 };
135 
136 template<typename ListType, typename ValueType>
Find(ListType & list,const ValueType & value)137 auto Find(ListType& list, const ValueType& value)
138 {
139     return std::find(list.begin(), list.end(), value);
140 }
141 
ProcessEntityListeners(const array_view<const pair<Entity,IEntityManager::EventType>> states,const array_view<IEcs::EntityListener * > entityListeners)142 void ProcessEntityListeners(const array_view<const pair<Entity, IEntityManager::EventType>> states,
143     const array_view<IEcs::EntityListener*> entityListeners)
144 {
145     // handle state changes (collect to groups of same kind of events)
146     vector<Entity> res;
147     res.reserve(states.size());
148     auto type = states[0U].second;
149     for (const auto& s : states) {
150         if (s.second != type) {
151             if (!res.empty()) {
152                 // Let listeners know that entity state has changed.
153                 for (auto* listener : entityListeners) {
154                     if (listener) {
155                         listener->OnEntityEvent(type, res);
156                     }
157                 }
158                 // start collecting new events.
159                 res.clear();
160             }
161             type = s.second;
162         }
163         // add to event list.
164         res.push_back(s.first);
165     }
166     if (!res.empty()) {
167         // Send the final events.
168         for (auto* listener : entityListeners) {
169             if (listener) {
170                 listener->OnEntityEvent(type, res);
171             }
172         }
173     }
174 }
175 
AddListener(EntityListener & listener)176 void Ecs::AddListener(EntityListener& listener)
177 {
178     if (Find(entityListeners_, &listener) != entityListeners_.end()) {
179         // already added.
180         return;
181     }
182     entityListeners_.push_back(&listener);
183 }
184 
RemoveListener(EntityListener & listener)185 void Ecs::RemoveListener(EntityListener& listener)
186 {
187     if (auto it = Find(entityListeners_, &listener); it != entityListeners_.end()) {
188         // Setting the listener to null instead of removing. This allows removing listeners from a listener callback.
189         *it = nullptr;
190         return;
191     }
192 }
193 
AddListener(ComponentListener & listener)194 void Ecs::AddListener(ComponentListener& listener)
195 {
196     if (Find(componentListeners_, &listener) != componentListeners_.end()) {
197         // already added.
198         return;
199     }
200     componentListeners_.push_back(&listener);
201 }
202 
RemoveListener(ComponentListener & listener)203 void Ecs::RemoveListener(ComponentListener& listener)
204 {
205     if (auto it = Find(componentListeners_, &listener); it != componentListeners_.end()) {
206         *it = nullptr;
207         return;
208     }
209 }
210 
AddListener(IComponentManager & manager,ComponentListener & listener)211 void Ecs::AddListener(IComponentManager& manager, ComponentListener& listener)
212 {
213     auto list = componentManagerListeners_.find(&manager);
214     if (list != componentManagerListeners_.end()) {
215         if (auto it = Find(list->second, &listener); it != list->second.end()) {
216             return;
217         }
218         list->second.push_back(&listener);
219         return;
220     }
221     componentManagerListeners_[&manager].push_back(&listener);
222 }
223 
RemoveListener(IComponentManager & manager,ComponentListener & listener)224 void Ecs::RemoveListener(IComponentManager& manager, ComponentListener& listener)
225 {
226     auto list = componentManagerListeners_.find(&manager);
227     if (list == componentManagerListeners_.end()) {
228         return;
229     }
230     if (auto it = Find(list->second, &listener); it != list->second.end()) {
231         *it = nullptr;
232         return;
233     }
234 }
235 
CreateComponentManager(const ComponentManagerTypeInfo & componentManagerTypeInfo)236 IComponentManager* Ecs::CreateComponentManager(const ComponentManagerTypeInfo& componentManagerTypeInfo)
237 {
238     IComponentManager* manager = nullptr;
239     if (componentManagerTypeInfo.createManager) {
240         manager = GetComponentManager(componentManagerTypeInfo.uid);
241         if (manager) {
242             CORE_LOG_W("Duplicate component manager creation, returning existing instance");
243         } else {
244             manager = componentManagerTypeInfo.createManager(*this);
245             if (manager) {
246                 managers_.insert({ componentManagerTypeInfo.uid, manager });
247                 managerOrder_.emplace_back(manager, componentManagerTypeInfo.destroyManager);
248             }
249         }
250     }
251     return manager;
252 }
253 
CreateSystem(const SystemTypeInfo & systemInfo)254 ISystem* Ecs::CreateSystem(const SystemTypeInfo& systemInfo)
255 {
256     ISystem* system = nullptr;
257     if (systemInfo.createSystem) {
258         system = GetSystem(systemInfo.uid);
259         if (system) {
260             CORE_LOG_W("Duplicate system creation, returning existing instance");
261         } else {
262             system = systemInfo.createSystem(*this);
263             if (system) {
264                 systems_.insert({ systemInfo.uid, system });
265                 systemOrder_.emplace_back(system, systemInfo.destroySystem);
266             }
267         }
268     }
269     return system;
270 }
271 
Ecs(IClassFactory & registry,const IThreadPool::Ptr & threadPool)272 Ecs::Ecs(IClassFactory& registry, const IThreadPool::Ptr& threadPool)
273     : threadPool_(threadPool), pluginRegistry_(registry)
274 {
275     for (auto info : CORE_NS::GetPluginRegister().GetTypeInfos(IEcsPlugin::UID)) {
276         if (auto ecsPlugin = static_cast<const IEcsPlugin*>(info); ecsPlugin && ecsPlugin->createPlugin) {
277             auto token = ecsPlugin->createPlugin(*this);
278             plugins_.push_back({ token, ecsPlugin });
279         }
280     }
281     GetPluginRegister().AddListener(*this);
282 }
283 
~Ecs()284 Ecs::~Ecs()
285 {
286     GetPluginRegister().RemoveListener(*this);
287 
288     Uninitialize();
289     managerOrder_.clear();
290     systemOrder_.clear();
291 
292     for (auto& plugin : plugins_) {
293         if (plugin.second->destroyPlugin) {
294             plugin.second->destroyPlugin(plugin.first);
295         }
296     }
297 }
298 
GetClassFactory() const299 IClassFactory& Ecs::GetClassFactory() const
300 {
301     return pluginRegistry_;
302 }
303 
GetEntityManager()304 IEntityManager& Ecs::GetEntityManager()
305 {
306     return entityManager_;
307 }
308 
GetEntityManager() const309 const IEntityManager& Ecs::GetEntityManager() const
310 {
311     return entityManager_;
312 }
313 
GetComponents(Entity entity,vector<IComponentManager * > & result) const314 void Ecs::GetComponents(Entity entity, vector<IComponentManager*>& result) const
315 {
316     result.clear();
317     result.reserve(managers_.size());
318     for (auto& m : managerOrder_) {
319         if (m->HasComponent(entity)) {
320             result.push_back(m.get());
321         }
322     }
323 }
324 
GetSystems() const325 vector<ISystem*> Ecs::GetSystems() const
326 {
327     vector<ISystem*> result;
328     result.reserve(systemOrder_.size());
329     for (auto& t : systemOrder_) {
330         result.push_back(t.get());
331     }
332     return result;
333 }
334 
GetSystem(const Uid & uid) const335 ISystem* Ecs::GetSystem(const Uid& uid) const
336 {
337     if (auto pos = systems_.find(uid); pos != systems_.end()) {
338         return pos->second;
339     }
340     return nullptr;
341 }
342 
GetComponentManagers() const343 vector<IComponentManager*> Ecs::GetComponentManagers() const
344 {
345     vector<IComponentManager*> result;
346     result.reserve(managerOrder_.size());
347     for (auto& t : managerOrder_) {
348         result.push_back(t.get());
349     }
350     return result;
351 }
352 
GetComponentManager(const Uid & uid) const353 IComponentManager* Ecs::GetComponentManager(const Uid& uid) const
354 {
355     if (auto pos = managers_.find(uid); pos != managers_.end()) {
356         return pos->second;
357     }
358     return nullptr;
359 }
360 
CloneEntity(const Entity entity)361 Entity Ecs::CloneEntity(const Entity entity)
362 {
363     if (!EntityUtil::IsValid(entity)) {
364         return {};
365     }
366 
367     const Entity clonedEntity = entityManager_.Create();
368     if (entityManager_.IsAlive(entity)) {
369         for (auto& cm : managerOrder_) {
370             const auto id = cm->GetComponentId(entity);
371             auto data = cm->GetData(id);
372             if (data && id != IComponentManager::INVALID_COMPONENT_ID) {
373                 cm->Create(clonedEntity);
374                 cm->SetData(clonedEntity, *data);
375             }
376         }
377     }
378     return clonedEntity;
379 }
380 
ProcessComponentEvents(ComponentListener::EventType eventType,const array_view<const Entity> removedEntities) const381 void Ecs::ProcessComponentEvents(
382     ComponentListener::EventType eventType, const array_view<const Entity> removedEntities) const
383 {
384     vector<Entity> (IComponentManager::*getter)();
385     switch (eventType) {
386         case ComponentListener::EventType::CREATED:
387             getter = &IComponentManager::GetAddedComponents;
388             break;
389         case ComponentListener::EventType::MODIFIED:
390             getter = &IComponentManager::GetUpdatedComponents;
391             break;
392         case ComponentListener::EventType::DESTROYED:
393             getter = &IComponentManager::GetRemovedComponents;
394             break;
395         case ComponentListener::EventType::MOVED:
396             getter = &IComponentManager::GetMovedComponents;
397             break;
398         default:
399             return;
400     }
401     for (const auto& m : managerOrder_) {
402         vector<Entity> affectedEntities = (*m.*getter)();
403         if (!removedEntities.empty()) {
404             affectedEntities.erase(
405                 std::remove_if(affectedEntities.begin(), affectedEntities.end(),
406                     [removedEntities](const Entity& entity) {
407                         const auto pos = std::lower_bound(removedEntities.cbegin(), removedEntities.cend(), entity,
408                             [](const Entity& entity, const Entity& removed) { return entity < removed; });
409                         return ((pos != removedEntities.cend()) && entity >= *pos);
410                     }),
411                 affectedEntities.cend());
412         }
413         if (!affectedEntities.empty()) {
414             // global listeners
415             for (auto* listener : componentListeners_) {
416                 if (listener) {
417                     listener->OnComponentEvent(eventType, *m, affectedEntities);
418                 }
419             }
420             // per manager listeners
421             if (auto it = componentManagerListeners_.find(m.get()); it != componentManagerListeners_.cend()) {
422                 for (auto* listener : it->second) {
423                     if (listener) {
424                         listener->OnComponentEvent(eventType, *m, affectedEntities);
425                     }
426                 }
427             }
428         }
429     }
430 }
431 
ProcessEvents()432 void Ecs::ProcessEvents()
433 {
434     if (processingEvents_) {
435         CORE_LOG_W("Calling ProcessEvents() from an event callback is not allowed");
436         return;
437     }
438     processingEvents_ = true;
439 
440     vector<Entity> allRemovedEntities;
441     bool deadEntities = false;
442     do {
443         // Let entity manager check entity reference counts
444         entityManager_.UpdateDeadEntities();
445 
446         // Send entity related events
447         if (const auto events = entityManager_.GetEvents(); !events.empty()) {
448             ProcessEntityListeners(events, entityListeners_);
449         }
450 
451         // Remove components for removed entities.
452         const vector<Entity> removed = entityManager_.GetRemovedEntities();
453         deadEntities = !removed.empty();
454         if (deadEntities) {
455             allRemovedEntities.append(removed.cbegin(), removed.cend());
456         }
457         for (auto& m : managerOrder_) {
458             // Destroy all components related to these entities.
459             if (deadEntities) {
460                 m->Destroy(removed);
461             }
462             m->Gc();
463         }
464         // Destroying components may release the last reference for some entity so we loop until there are no new
465         // deaths reported.
466     } while (deadEntities);
467 
468     if (!allRemovedEntities.empty()) {
469         std::sort(allRemovedEntities.begin(), allRemovedEntities.end());
470     }
471 
472     // Send component related events
473     ProcessComponentEvents(ComponentListener::EventType::CREATED, allRemovedEntities);
474     ProcessComponentEvents(ComponentListener::EventType::MOVED, allRemovedEntities);
475     ProcessComponentEvents(ComponentListener::EventType::MODIFIED, allRemovedEntities);
476     ProcessComponentEvents(ComponentListener::EventType::DESTROYED, {});
477 
478     // Clean-up removed listeners.
479     entityListeners_.erase(
480         std::remove(entityListeners_.begin(), entityListeners_.end(), nullptr), entityListeners_.cend());
481     componentListeners_.erase(
482         std::remove(componentListeners_.begin(), componentListeners_.end(), nullptr), componentListeners_.cend());
483 
484     for (auto it = componentManagerListeners_.begin(); it != componentManagerListeners_.cend();) {
485         auto& listeners = it->second;
486         listeners.erase(std::remove(listeners.begin(), listeners.end(), nullptr), listeners.cend());
487         if (listeners.empty()) {
488             it = componentManagerListeners_.erase(it);
489         } else {
490             ++it;
491         }
492     }
493 
494     processingEvents_ = false;
495 }
496 
Initialize()497 void Ecs::Initialize()
498 {
499     for (auto& s : systemOrder_) {
500         s->Initialize();
501     }
502 }
503 
504 CORE_PROFILER_SYMBOL(escUpdate, "Update");
505 
Update(uint64_t time,uint64_t delta)506 bool Ecs::Update(uint64_t time, uint64_t delta)
507 {
508     CORE_PROFILER_MARK_FRAME_START(escUpdate);
509     CORE_CPU_PERF_SCOPE("CORE", "Update", "Total_Cpu", CORE_PROFILER_DEFAULT_COLOR);
510     bool frameRenderingQueued = false;
511     if (GetRenderMode() == RENDER_ALWAYS || renderRequested_) {
512         frameRenderingQueued = true;
513     }
514 
515     // Update all systems.
516     delta = static_cast<uint64_t>(static_cast<float>(delta) * timeScale_);
517     for (auto& s : systemOrder_) {
518         CORE_CPU_PERF_SCOPE("CORE", "SystemUpdate", s->GetName(), CORE_PROFILER_DEFAULT_COLOR);
519         if (s->Update(frameRenderingQueued, time, delta)) {
520             frameRenderingQueued = true;
521         }
522     }
523 
524     // Clear modification flags from component managers.
525     for (auto& componentManager : managerOrder_) {
526         componentManager->ClearModifiedFlags();
527     }
528 
529     renderRequested_ = false;
530     needRender_ = frameRenderingQueued;
531 
532     CORE_PROFILER_MARK_FRAME_END(escUpdate);
533     return frameRenderingQueued;
534 }
535 
Uninitialize()536 void Ecs::Uninitialize()
537 {
538     // Destroy all entities from scene.
539     entityManager_.DestroyAllEntities();
540 
541     // Garbage-collect.
542     ProcessEvents();
543 
544     // Uninitialize systems.
545     for (auto it = systemOrder_.rbegin(); it != systemOrder_.rend(); ++it) {
546         (*it)->Uninitialize();
547     }
548 }
549 
RequestRender()550 void Ecs::RequestRender()
551 {
552     renderRequested_ = true;
553 }
554 
SetRenderMode(RenderMode renderMode)555 void Ecs::SetRenderMode(RenderMode renderMode)
556 {
557     renderMode_ = renderMode;
558 }
559 
GetRenderMode()560 IEcs::RenderMode Ecs::GetRenderMode()
561 {
562     return renderMode_;
563 }
564 
NeedRender() const565 bool Ecs::NeedRender() const
566 {
567     return needRender_;
568 }
569 
GetThreadPool() const570 const IThreadPool::Ptr& Ecs::GetThreadPool() const
571 {
572     return threadPool_;
573 }
574 
GetTimeScale() const575 float Ecs::GetTimeScale() const
576 {
577     return timeScale_;
578 }
579 
SetTimeScale(float scale)580 void Ecs::SetTimeScale(float scale)
581 {
582     timeScale_ = scale;
583 }
584 
Ref()585 void Ecs::Ref() noexcept
586 {
587     refcnt_.fetch_add(1, std::memory_order_relaxed);
588 }
589 
Unref()590 void Ecs::Unref() noexcept
591 {
592     if (std::atomic_fetch_sub_explicit(&refcnt_, 1, std::memory_order_release) == 1) {
593         std::atomic_thread_fence(std::memory_order_acquire);
594         delete this;
595     }
596 }
597 
598 template<typename Container>
RemoveUid(Container & container,const Uid & uid)599 inline auto RemoveUid(Container& container, const Uid& uid)
600 {
601     container.erase(std::remove_if(container.begin(), container.end(),
602                         [&uid](const auto& thing) { return thing->GetUid() == uid; }),
603         container.cend());
604 }
605 
OnTypeInfoEvent(EventType type,array_view<const ITypeInfo * const> typeInfos)606 void Ecs::OnTypeInfoEvent(EventType type, array_view<const ITypeInfo* const> typeInfos)
607 {
608     if (type == EventType::ADDED) {
609         // not really interesed in these events. systems and component managers are added when SystemGraphLoader parses
610         // a configuration. we could store them in systems_ and managers_ and only define the order based on the graph.
611     } else if (type == EventType::REMOVED) {
612         for (const auto* info : typeInfos) {
613             if (info && info->typeUid == SystemTypeInfo::UID) {
614                 const auto systemInfo = static_cast<const SystemTypeInfo*>(info);
615                 // for systems Untinitialize should be called before destroying the instance
616                 if (const auto pos = systems_.find(systemInfo->uid); pos != systems_.cend()) {
617                     pos->second->Uninitialize();
618                     systems_.erase(pos);
619                 }
620                 RemoveUid(systemOrder_, systemInfo->uid);
621             } else if (info && info->typeUid == ComponentManagerTypeInfo::UID) {
622                 const auto managerInfo = static_cast<const ComponentManagerTypeInfo*>(info);
623                 // BaseManager expects that the component list is empty when it's destroyed. might be also
624                 // nice to notify all the listeners that the components are being destroyed.
625                 if (const auto pos = managers_.find(managerInfo->uid); (pos != managers_.end()) && (pos->second)) {
626                     auto* manager = pos->second;
627 
628                     // remove all the components.
629                     const auto components = static_cast<IComponentManager::ComponentId>(manager->GetComponentCount());
630                     for (IComponentManager::ComponentId i = 0; i < components; ++i) {
631                         manager->Destroy(manager->GetEntity(i));
632                     }
633 
634                     // check are there generic or specific component listeners to inform.
635                     if (const auto listenerIt = componentManagerListeners_.find(manager);
636                         !componentListeners_.empty() ||
637                         ((listenerIt != componentManagerListeners_.end()) && !listenerIt->second.empty())) {
638                         if (const vector<Entity> removed = manager->GetRemovedComponents(); !removed.empty()) {
639                             const auto removedView = array_view<const Entity>(removed);
640                             for (auto* lister : componentListeners_) {
641                                 if (lister) {
642                                     lister->OnComponentEvent(
643                                         ComponentListener::EventType::DESTROYED, *manager, removedView);
644                                 }
645                             }
646                             if (listenerIt != componentManagerListeners_.end()) {
647                                 for (auto* lister : listenerIt->second) {
648                                     if (lister) {
649                                         lister->OnComponentEvent(
650                                             ComponentListener::EventType::DESTROYED, *manager, removedView);
651                                     }
652                                 }
653                                 // remove all the listeners for this manager. RemoveListener won't do anything. this
654                                 // isn't neccessary, but rather not leave invalid manager pointer even if it's just used
655                                 // as the key.
656                                 componentManagerListeners_.erase(listenerIt);
657                             }
658                         }
659                     }
660                     // garbage collection will remove dead entries from the list and BaseManager is happy.
661                     manager->Gc();
662                     managers_.erase(pos);
663                 }
664                 RemoveUid(managerOrder_, managerInfo->uid);
665             }
666         }
667     }
668 }
669 } // namespace
670 
IEcsInstance(IClassFactory & registry,const IThreadPool::Ptr & threadPool)671 IEcs* IEcsInstance(IClassFactory& registry, const IThreadPool::Ptr& threadPool)
672 {
673     return new Ecs(registry, threadPool);
674 }
675 CORE_END_NAMESPACE()
676