• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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 <cstdint>
18 
19 #include <base/containers/array_view.h>
20 #include <base/containers/atomics.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 <base/util/uid_util.h>
28 #include <core/ecs/entity.h>
29 #include <core/ecs/intf_component_manager.h>
30 #include <core/ecs/intf_ecs.h>
31 #include <core/ecs/intf_system.h>
32 #include <core/log.h>
33 #include <core/namespace.h>
34 #include <core/perf/cpu_perf_scope.h>
35 #include <core/plugin/intf_plugin.h>
36 #include <core/plugin/intf_plugin_register.h>
37 #include <core/threading/intf_thread_pool.h>
38 
39 #include "ecs/entity_manager.h"
40 
41 CORE_BEGIN_NAMESPACE()
42 constexpr bool operator==(const CORE_NS::SystemTypeInfo* info, const BASE_NS::Uid& uid) noexcept
43 {
44     return info->uid == uid;
45 }
46 
operator ==(const BASE_NS::unique_ptr<ISystem,SystemTypeInfo::DestroySystemFn> & ptr,const ISystem * system)47 inline bool operator==(
48     const BASE_NS::unique_ptr<ISystem, SystemTypeInfo::DestroySystemFn>& ptr, const ISystem* system) noexcept
49 {
50     return ptr.get() == system;
51 }
52 
53 namespace {
54 using BASE_NS::array_view;
55 using BASE_NS::pair;
56 using BASE_NS::Uid;
57 using BASE_NS::unique_ptr;
58 using BASE_NS::unordered_map;
59 using BASE_NS::vector;
60 
61 class Ecs final : public IEcs, IPluginRegister::ITypeInfoListener {
62 public:
63     Ecs(IClassFactory&, const IThreadPool::Ptr& threadPool, uint64_t ecsId);
64     ~Ecs() override;
65 
66     Ecs(const Ecs&) = delete;
67     Ecs(const Ecs&&) = delete;
68     Ecs& operator=(const Ecs&) = delete;
69     Ecs& operator=(const Ecs&&) = delete;
70 
71     IEntityManager& GetEntityManager() override;
72     const IEntityManager& GetEntityManager() const override;
73     void GetComponents(Entity entity, vector<IComponentManager*>& result) const override;
74     vector<ISystem*> GetSystems() const override;
75     ISystem* GetSystem(const Uid& uid) const override;
76     vector<IComponentManager*> GetComponentManagers() const override;
77     IComponentManager* GetComponentManager(const Uid& uid) const override;
78     Entity CloneEntity(Entity entity) override;
79     void ProcessEvents() override;
80 
81     void Initialize() override;
82     bool Update(uint64_t time, uint64_t delta) override;
83     void Uninitialize() override;
84 
85     IComponentManager* CreateComponentManager(const ComponentManagerTypeInfo& componentManagerTypeInfo) override;
86     ISystem* CreateSystem(const SystemTypeInfo& systemInfo) override;
87 
88     void AddListener(EntityListener& listener) override;
89     void RemoveListener(EntityListener& listener) override;
90     void AddListener(ComponentListener& listener) override;
91     void RemoveListener(ComponentListener& listener) override;
92     void AddListener(IComponentManager& manager, ComponentListener& listener) override;
93     void RemoveListener(IComponentManager& manager, ComponentListener& listener) override;
94 
95     void RequestRender() override;
96     void SetRenderMode(RenderMode renderMode) override;
97     RenderMode GetRenderMode() override;
98 
99     bool NeedRender() const override;
100 
101     IClassFactory& GetClassFactory() const override;
102 
103     const IThreadPool::Ptr& GetThreadPool() const override;
104 
105     float GetTimeScale() const override;
106     void SetTimeScale(float scale) override;
107 
108     void Ref() noexcept override;
109     void Unref() noexcept override;
110 
111     uint64_t GetId() const override;
112 
113     using SystemPtr = unique_ptr<ISystem, SystemTypeInfo::DestroySystemFn>;
114     using ManagerPtr = unique_ptr<IComponentManager, ComponentManagerTypeInfo::DestroyComponentManagerFn>;
115 
116 protected:
117     // IPluginRegister::ITypeInfoListener
118     void OnTypeInfoEvent(EventType type, array_view<const ITypeInfo* const> typeInfos) override;
119 
120     void ProcessComponentEvents(
121         IEcs::ComponentListener::EventType eventType, array_view<const Entity> removedEntities) const;
122 
123     void CleanupComponentManager(IComponentManager& manager);
124 
125     IThreadPool::Ptr threadPool_;
126 
127     // for storing systems and component managers in creation order
128     vector<SystemPtr> systemOrder_;
129     vector<ManagerPtr> managerOrder_;
130     // for finding systems and component managers with UID
131     unordered_map<Uid, ISystem*> systems_;
132     unordered_map<Uid, IComponentManager*> managers_;
133 
134     vector<EntityListener*> entityListeners_;
135     vector<ComponentListener*> componentListeners_;
136     unordered_map<IComponentManager*, vector<ComponentListener*>> componentManagerListeners_;
137 
138     bool initialized_ { false };
139     bool needRender_ { false };
140     bool renderRequested_ { false };
141     bool processingEvents_ { false };
142     RenderMode renderMode_ { RENDER_ALWAYS };
143 
144     IClassFactory& pluginRegistry_;
145 
146     vector<pair<PluginToken, const IEcsPlugin*>> plugins_;
147     float timeScale_ { 1.f };
148     int32_t refcnt_ { 0 };
149 
150     uint64_t ecsId_ { 0xFFFFFFFFffffffff };
151     EntityManager entityManager_;
152 };
153 
154 template<typename ListType, typename ValueType>
Find(ListType & list,const ValueType & value)155 auto Find(ListType& list, const ValueType& value)
156 {
157     return std::find(list.begin(), list.end(), value);
158 }
159 
ProcessEntityListeners(const array_view<const pair<Entity,IEntityManager::EventType>> states,const array_view<IEcs::EntityListener * > entityListeners)160 void ProcessEntityListeners(const array_view<const pair<Entity, IEntityManager::EventType>> states,
161     const array_view<IEcs::EntityListener*> entityListeners)
162 {
163     // handle state changes (collect to groups of same kind of events)
164     vector<Entity> res;
165     res.reserve(states.size());
166     auto type = states[0U].second;
167     for (const auto& s : states) {
168         if (s.second != type) {
169             if (!res.empty()) {
170                 // Let listeners know that entity state has changed.
171                 for (auto* listener : entityListeners) {
172                     if (listener) {
173                         listener->OnEntityEvent(type, res);
174                     }
175                 }
176                 // start collecting new events.
177                 res.clear();
178             }
179             type = s.second;
180         }
181         // add to event list.
182         res.push_back(s.first);
183     }
184     if (!res.empty()) {
185         // Send the final events.
186         for (auto* listener : entityListeners) {
187             if (listener) {
188                 listener->OnEntityEvent(type, res);
189             }
190         }
191     }
192 }
193 
194 template<class TypeInfo>
FindTypeInfo(const Uid & uid,const array_view<const ITypeInfo * const> & container)195 const TypeInfo* FindTypeInfo(const Uid& uid, const array_view<const ITypeInfo* const>& container)
196 {
197     for (const auto& info : container) {
198         if (static_cast<const TypeInfo* const>(info)->uid == uid) {
199             return static_cast<const TypeInfo*>(info);
200         }
201     }
202 
203     return nullptr;
204 }
205 
GatherComponents(vector<const ComponentManagerTypeInfo * > & componentManagerInfos,const array_view<const ITypeInfo * const> & componentMetadata,array_view<const Uid> componentDependencies)206 bool GatherComponents(vector<const ComponentManagerTypeInfo*>& componentManagerInfos,
207     const array_view<const ITypeInfo* const>& componentMetadata, array_view<const Uid> componentDependencies)
208 {
209     // Ensure we have all components required by this system.
210     for (const auto& dependencyUid : componentDependencies) {
211         if (dependencyUid == Uid {}) {
212             continue;
213         }
214         const auto* componentTypeInfo = FindTypeInfo<ComponentManagerTypeInfo>(dependencyUid, componentMetadata);
215         if (!componentTypeInfo) {
216             return false;
217         }
218         if (std::find(componentManagerInfos.cbegin(), componentManagerInfos.cend(), componentTypeInfo) ==
219             componentManagerInfos.cend()) {
220             componentManagerInfos.push_back(componentTypeInfo);
221         }
222     }
223     return true;
224 }
225 
GetAvailableComponentManagersAndSystems()226 pair<vector<const SystemTypeInfo*>, vector<const ComponentManagerTypeInfo*>> GetAvailableComponentManagersAndSystems()
227 {
228     auto& pluginRegister = GetPluginRegister();
229     auto componentMetadata = pluginRegister.GetTypeInfos(ComponentManagerTypeInfo::UID);
230     auto systemMetadata = pluginRegister.GetTypeInfos(SystemTypeInfo::UID);
231     vector<const ComponentManagerTypeInfo*> componentManagerInfos;
232     componentManagerInfos.reserve(componentMetadata.size());
233     vector<const SystemTypeInfo*> systemInfos;
234     systemInfos.reserve(systemMetadata.size());
235 
236     // Gather systems which have all components available
237     for (const auto* info : systemMetadata) {
238         if (!info || (info->typeUid != SystemTypeInfo::UID)) {
239             continue;
240         }
241         auto* systemTypeInfo = static_cast<const SystemTypeInfo*>(info);
242         if (!systemTypeInfo->createSystem) {
243             continue;
244         }
245 
246         // Ensure we have all components required by this system.
247         if (!GatherComponents(componentManagerInfos, componentMetadata, systemTypeInfo->componentDependencies) ||
248             !GatherComponents(
249                 componentManagerInfos, componentMetadata, systemTypeInfo->readOnlyComponentDependencies)) {
250             CORE_LOG_W("Failed to resolve component dependencies: %s.", systemTypeInfo->typeName);
251             continue;
252         }
253         // At least component managers should be available so add to list.
254         systemInfos.push_back(systemTypeInfo);
255     }
256     return { BASE_NS::move(systemInfos), BASE_NS::move(componentManagerInfos) };
257 }
258 
OrderSystems(vector<const SystemTypeInfo * > & systemInfos)259 void OrderSystems(vector<const SystemTypeInfo*>& systemInfos)
260 {
261     // Order systems based optional afterSystem UIDs.
262     auto begin = systemInfos.begin();
263     auto end = systemInfos.end();
264     for (auto it = begin; it != end;) {
265         if ((*it)->afterSystem == Uid {}) {
266             ++it;
267             continue;
268         }
269         auto pos = std::find(it, end, (*it)->afterSystem);
270         if (pos != end) {
271             // rotate it right after pos
272             std::rotate(it, it + 1, (pos + 1));
273         } else {
274             ++it;
275         }
276     }
277 
278     // Order systems based optional beforeSystem UIDs.
279     for (auto it = begin; it != end;) {
280         if ((*it)->beforeSystem == Uid {}) {
281             ++it;
282             continue;
283         }
284         auto pos = std::find(begin, it, (*it)->beforeSystem);
285         if (pos != it) {
286             // rotate it left before pos
287             std::rotate(pos, it, (it + 1));
288         } else {
289             ++it;
290         }
291     }
292 }
293 
AddListener(EntityListener & listener)294 void Ecs::AddListener(EntityListener& listener)
295 {
296     if (Find(entityListeners_, &listener) != entityListeners_.end()) {
297         // already added.
298         return;
299     }
300     entityListeners_.push_back(&listener);
301 }
302 
RemoveListener(EntityListener & listener)303 void Ecs::RemoveListener(EntityListener& listener)
304 {
305     if (auto it = Find(entityListeners_, &listener); it != entityListeners_.end()) {
306         // Setting the listener to null instead of removing. This allows removing listeners from a listener callback.
307         *it = nullptr;
308         return;
309     }
310 }
311 
AddListener(ComponentListener & listener)312 void Ecs::AddListener(ComponentListener& listener)
313 {
314     if (Find(componentListeners_, &listener) != componentListeners_.end()) {
315         // already added.
316         return;
317     }
318     componentListeners_.push_back(&listener);
319 }
320 
RemoveListener(ComponentListener & listener)321 void Ecs::RemoveListener(ComponentListener& listener)
322 {
323     if (auto it = Find(componentListeners_, &listener); it != componentListeners_.end()) {
324         *it = nullptr;
325         return;
326     }
327 }
328 
AddListener(IComponentManager & manager,ComponentListener & listener)329 void Ecs::AddListener(IComponentManager& manager, ComponentListener& listener)
330 {
331     auto list = componentManagerListeners_.find(&manager);
332     if (list != componentManagerListeners_.end()) {
333         if (auto it = Find(list->second, &listener); it != list->second.end()) {
334             return;
335         }
336         list->second.push_back(&listener);
337         return;
338     }
339     componentManagerListeners_[&manager].push_back(&listener);
340 }
341 
RemoveListener(IComponentManager & manager,ComponentListener & listener)342 void Ecs::RemoveListener(IComponentManager& manager, ComponentListener& listener)
343 {
344     auto list = componentManagerListeners_.find(&manager);
345     if (list == componentManagerListeners_.end()) {
346         return;
347     }
348     if (auto it = Find(list->second, &listener); it != list->second.end()) {
349         *it = nullptr;
350         return;
351     }
352 }
353 
CreateComponentManager(const ComponentManagerTypeInfo & componentManagerTypeInfo)354 IComponentManager* Ecs::CreateComponentManager(const ComponentManagerTypeInfo& componentManagerTypeInfo)
355 {
356     IComponentManager* manager = nullptr;
357     if (componentManagerTypeInfo.createManager) {
358         manager = GetComponentManager(componentManagerTypeInfo.uid);
359         if (manager) {
360             CORE_LOG_W("Duplicate component manager creation, returning existing instance");
361         } else {
362             manager = componentManagerTypeInfo.createManager(*this);
363             if (manager) {
364                 managers_.insert({ componentManagerTypeInfo.uid, manager });
365                 managerOrder_.emplace_back(manager, componentManagerTypeInfo.destroyManager);
366             }
367         }
368     }
369     return manager;
370 }
371 
CreateSystem(const SystemTypeInfo & systemInfo)372 ISystem* Ecs::CreateSystem(const SystemTypeInfo& systemInfo)
373 {
374     ISystem* system = nullptr;
375     if (!systemInfo.createSystem) {
376         return system;
377     }
378 
379     system = GetSystem(systemInfo.uid);
380     if (system) {
381         CORE_LOG_W("Duplicate system creation, returning existing instance.");
382         return system;
383     }
384 
385     system = systemInfo.createSystem(*this);
386     if (!system) {
387         CORE_LOG_E("Failed to create system.");
388         return system;
389     }
390 
391     systems_.insert({ systemInfo.uid, system });
392     systemOrder_.emplace_back(system, systemInfo.destroySystem);
393 
394     if (initialized_) {
395         system->Initialize();
396     }
397 
398     return system;
399 }
400 
Ecs(IClassFactory & registry,const IThreadPool::Ptr & threadPool,const uint64_t ecsId)401 Ecs::Ecs(IClassFactory& registry, const IThreadPool::Ptr& threadPool, const uint64_t ecsId)
402     : threadPool_(threadPool), pluginRegistry_(registry), ecsId_(ecsId)
403 {
404     for (auto info : CORE_NS::GetPluginRegister().GetTypeInfos(IEcsPlugin::UID)) {
405         if (auto ecsPlugin = static_cast<const IEcsPlugin*>(info); ecsPlugin && ecsPlugin->createPlugin) {
406             auto token = ecsPlugin->createPlugin(*this);
407             plugins_.push_back({ token, ecsPlugin });
408         }
409     }
410     GetPluginRegister().AddListener(*this);
411 }
412 
~Ecs()413 Ecs::~Ecs()
414 {
415     GetPluginRegister().RemoveListener(*this);
416 
417     Uninitialize();
418     managerOrder_.clear();
419     systemOrder_.clear();
420 
421     for (auto& plugin : plugins_) {
422         if (plugin.second->destroyPlugin) {
423             plugin.second->destroyPlugin(plugin.first);
424         }
425     }
426 }
427 
GetClassFactory() const428 IClassFactory& Ecs::GetClassFactory() const
429 {
430     return pluginRegistry_;
431 }
432 
GetEntityManager()433 IEntityManager& Ecs::GetEntityManager()
434 {
435     return entityManager_;
436 }
437 
GetEntityManager() const438 const IEntityManager& Ecs::GetEntityManager() const
439 {
440     return entityManager_;
441 }
442 
GetComponents(Entity entity,vector<IComponentManager * > & result) const443 void Ecs::GetComponents(Entity entity, vector<IComponentManager*>& result) const
444 {
445     result.clear();
446     result.reserve(managers_.size());
447     for (auto& m : managerOrder_) {
448         if (m->HasComponent(entity)) {
449             result.push_back(m.get());
450         }
451     }
452 }
453 
GetSystems() const454 vector<ISystem*> Ecs::GetSystems() const
455 {
456     vector<ISystem*> result;
457     result.reserve(systemOrder_.size());
458     for (auto& t : systemOrder_) {
459         result.push_back(t.get());
460     }
461     return result;
462 }
463 
GetSystem(const Uid & uid) const464 ISystem* Ecs::GetSystem(const Uid& uid) const
465 {
466     if (auto pos = systems_.find(uid); pos != systems_.end()) {
467         return pos->second;
468     }
469     return nullptr;
470 }
471 
GetComponentManagers() const472 vector<IComponentManager*> Ecs::GetComponentManagers() const
473 {
474     vector<IComponentManager*> result;
475     result.reserve(managerOrder_.size());
476     for (auto& t : managerOrder_) {
477         result.push_back(t.get());
478     }
479     return result;
480 }
481 
GetComponentManager(const Uid & uid) const482 IComponentManager* Ecs::GetComponentManager(const Uid& uid) const
483 {
484     if (auto pos = managers_.find(uid); pos != managers_.end()) {
485         return pos->second;
486     }
487     return nullptr;
488 }
489 
CloneEntity(const Entity entity)490 Entity Ecs::CloneEntity(const Entity entity)
491 {
492     if (!EntityUtil::IsValid(entity)) {
493         return {};
494     }
495 
496     const Entity clonedEntity = entityManager_.Create();
497     if (entityManager_.IsAlive(entity)) {
498         for (auto& cm : managerOrder_) {
499             const auto id = cm->GetComponentId(entity);
500             if (id != IComponentManager::INVALID_COMPONENT_ID) {
501                 cm->Create(clonedEntity);
502                 if (auto dataHandle = cm->GetData(id); dataHandle != nullptr) {
503                     cm->SetData(clonedEntity, *dataHandle);
504                 }
505             }
506         }
507     }
508     return clonedEntity;
509 }
510 
ProcessComponentEvents(ComponentListener::EventType eventType,const array_view<const Entity> removedEntities) const511 void Ecs::ProcessComponentEvents(
512     ComponentListener::EventType eventType, const array_view<const Entity> removedEntities) const
513 {
514     vector<Entity> (IComponentManager::*getter)();
515     switch (eventType) {
516         case ComponentListener::EventType::CREATED:
517             getter = &IComponentManager::GetAddedComponents;
518             break;
519         case ComponentListener::EventType::MODIFIED:
520             getter = &IComponentManager::GetUpdatedComponents;
521             break;
522         case ComponentListener::EventType::DESTROYED:
523             getter = &IComponentManager::GetRemovedComponents;
524             break;
525         case ComponentListener::EventType::MOVED:
526             getter = &IComponentManager::GetMovedComponents;
527             break;
528         default:
529             return;
530     }
531     for (const auto& m : managerOrder_) {
532         vector<Entity> affectedEntities = (*m.*getter)();
533         if (!removedEntities.empty()) {
534             affectedEntities.erase(
535                 std::remove_if(affectedEntities.begin(), affectedEntities.end(),
536                     [removedEntities](const Entity& entity) {
537                         const auto pos = std::lower_bound(removedEntities.cbegin(), removedEntities.cend(), entity,
538                             [](const Entity& entity, const Entity& removed) { return entity < removed; });
539                         return ((pos != removedEntities.cend()) && entity >= *pos);
540                     }),
541                 affectedEntities.cend());
542         }
543         if (!affectedEntities.empty()) {
544             // global listeners
545             for (auto* listener : componentListeners_) {
546                 if (listener) {
547                     listener->OnComponentEvent(eventType, *m, affectedEntities);
548                 }
549             }
550             // per manager listeners
551             if (auto it = componentManagerListeners_.find(m.get()); it != componentManagerListeners_.cend()) {
552                 for (auto* listener : it->second) {
553                     if (listener) {
554                         listener->OnComponentEvent(eventType, *m, affectedEntities);
555                     }
556                 }
557             }
558         }
559     }
560 }
561 
ProcessEvents()562 void Ecs::ProcessEvents()
563 {
564     if (processingEvents_) {
565         CORE_LOG_W("Calling ProcessEvents() from an event callback is not allowed");
566         return;
567     }
568     processingEvents_ = true;
569 
570     vector<Entity> allRemovedEntities;
571     bool deadEntities = false;
572     do {
573         // Let entity manager check entity reference counts
574         entityManager_.UpdateDeadEntities();
575 
576         // Send entity related events
577         if (const auto events = entityManager_.GetEvents(); !events.empty()) {
578             ProcessEntityListeners(events, entityListeners_);
579         }
580 
581         // Remove components for removed entities.
582         const vector<Entity> removed = entityManager_.GetRemovedEntities();
583         deadEntities = !removed.empty();
584         if (deadEntities) {
585             allRemovedEntities.append(removed.cbegin(), removed.cend());
586         }
587         for (auto& m : managerOrder_) {
588             // Destroy all components related to these entities.
589             if (deadEntities) {
590                 m->Destroy(removed);
591             }
592             m->Gc();
593         }
594         // Destroying components may release the last reference for some entity so we loop until there are no new
595         // deaths reported.
596     } while (deadEntities);
597 
598     if (!allRemovedEntities.empty()) {
599         std::sort(allRemovedEntities.begin(), allRemovedEntities.end());
600     }
601 
602     // Send component related events
603     ProcessComponentEvents(ComponentListener::EventType::CREATED, allRemovedEntities);
604     ProcessComponentEvents(ComponentListener::EventType::MOVED, allRemovedEntities);
605     ProcessComponentEvents(ComponentListener::EventType::MODIFIED, allRemovedEntities);
606     ProcessComponentEvents(ComponentListener::EventType::DESTROYED, {});
607 
608     // Clean-up removed listeners.
609     entityListeners_.erase(
610         std::remove(entityListeners_.begin(), entityListeners_.end(), nullptr), entityListeners_.cend());
611     componentListeners_.erase(
612         std::remove(componentListeners_.begin(), componentListeners_.end(), nullptr), componentListeners_.cend());
613 
614     for (auto it = componentManagerListeners_.begin(); it != componentManagerListeners_.cend();) {
615         auto& listeners = it->second;
616         listeners.erase(std::remove(listeners.begin(), listeners.end(), nullptr), listeners.cend());
617         if (listeners.empty()) {
618             it = componentManagerListeners_.erase(it);
619         } else {
620             ++it;
621         }
622     }
623 
624     processingEvents_ = false;
625 }
626 
Initialize()627 void Ecs::Initialize()
628 {
629     if (systemOrder_.empty()) {
630         auto [systemInfos, componentManagerInfos] = GetAvailableComponentManagersAndSystems();
631         // Create all the required component managers.
632         for (const auto* info : componentManagerInfos) {
633             CreateComponentManager(*info);
634         }
635 
636         OrderSystems(systemInfos);
637         for (const auto* systemInfo : systemInfos) {
638             ISystem* system = systemInfo->createSystem(*this);
639             if (!system) {
640                 CORE_LOG_E("Failed to create system.");
641                 continue;
642             }
643             systems_.insert({ systemInfo->uid, system });
644             systemOrder_.emplace_back(system, systemInfo->destroySystem);
645         }
646     }
647 
648     for (auto& s : systemOrder_) {
649         s->Initialize();
650     }
651     initialized_ = true;
652 }
653 
654 CORE_PROFILER_SYMBOL(escUpdate, "Update");
655 
Update(uint64_t time,uint64_t delta)656 bool Ecs::Update(uint64_t time, uint64_t delta)
657 {
658     CORE_PROFILER_MARK_FRAME_START(escUpdate);
659     CORE_CPU_PERF_SCOPE("CORE", "Update", "Total_Cpu", CORE_PROFILER_DEFAULT_COLOR);
660     bool frameRenderingQueued = false;
661     if (GetRenderMode() == RENDER_ALWAYS || renderRequested_) {
662         frameRenderingQueued = true;
663     }
664 
665     // Update all systems.
666     delta = static_cast<uint64_t>(static_cast<float>(delta) * timeScale_);
667     for (auto& s : systemOrder_) {
668         CORE_CPU_PERF_SCOPE("CORE", "SystemUpdate", s->GetName(), CORE_PROFILER_DEFAULT_COLOR);
669         if (s->Update(frameRenderingQueued, time, delta)) {
670             frameRenderingQueued = true;
671         }
672     }
673 
674     // Clear modification flags from component managers.
675     for (auto& componentManager : managerOrder_) {
676         componentManager->ClearModifiedFlags();
677     }
678 
679     renderRequested_ = false;
680     needRender_ = frameRenderingQueued;
681 
682     CORE_PROFILER_MARK_FRAME_END(escUpdate);
683     return frameRenderingQueued;
684 }
685 
Uninitialize()686 void Ecs::Uninitialize()
687 {
688     // Destroy all entities from scene.
689     entityManager_.DestroyAllEntities();
690 
691     // Garbage-collect.
692     ProcessEvents();
693 
694     // Uninitialize systems.
695     for (auto it = systemOrder_.rbegin(); it != systemOrder_.rend(); ++it) {
696         (*it)->Uninitialize();
697     }
698 
699     initialized_ = false;
700 }
701 
RequestRender()702 void Ecs::RequestRender()
703 {
704     renderRequested_ = true;
705 }
706 
SetRenderMode(RenderMode renderMode)707 void Ecs::SetRenderMode(RenderMode renderMode)
708 {
709     renderMode_ = renderMode;
710 }
711 
GetRenderMode()712 IEcs::RenderMode Ecs::GetRenderMode()
713 {
714     return renderMode_;
715 }
716 
NeedRender() const717 bool Ecs::NeedRender() const
718 {
719     return needRender_;
720 }
721 
GetThreadPool() const722 const IThreadPool::Ptr& Ecs::GetThreadPool() const
723 {
724     return threadPool_;
725 }
726 
GetTimeScale() const727 float Ecs::GetTimeScale() const
728 {
729     return timeScale_;
730 }
731 
SetTimeScale(float scale)732 void Ecs::SetTimeScale(float scale)
733 {
734     timeScale_ = scale;
735 }
736 
GetId() const737 uint64_t Ecs::GetId() const
738 {
739     return ecsId_;
740 }
741 
Ref()742 void Ecs::Ref() noexcept
743 {
744     BASE_NS::AtomicIncrementRelaxed(&refcnt_);
745 }
746 
Unref()747 void Ecs::Unref() noexcept
748 {
749     if (BASE_NS::AtomicDecrementRelease(&refcnt_) == 0) {
750         BASE_NS::AtomicFenceAcquire();
751         delete this;
752     }
753 }
754 
755 template<typename Container>
RemoveUid(Container & container,const Uid & uid)756 inline auto RemoveUid(Container& container, const Uid& uid)
757 {
758     container.erase(std::remove_if(container.begin(), container.end(),
759                                    [&uid](const auto &thing) { return thing->GetUid() == uid; }),
760                     container.cend());
761 }
762 
OnTypeInfoEvent(EventType type,array_view<const ITypeInfo * const> typeInfos)763 void Ecs::OnTypeInfoEvent(EventType type, array_view<const ITypeInfo* const> typeInfos)
764 {
765     if (type == EventType::ADDED) {
766         // not really interesed in these events. systems and component managers are added when SystemGraphLoader parses
767         // a configuration. we could store them in systems_ and managers_ and only define the order based on the graph.
768         for (const auto* info : typeInfos) {
769             if (info && info->typeUid == IEcsPlugin::UID) {
770                 const auto ecsPlugin = static_cast<const IEcsPlugin*>(info);
771                 ecsPlugin->createPlugin(*this);
772             }
773         }
774     } else if (type == EventType::REMOVED) {
775         for (const auto* info : typeInfos) {
776             if (info && info->typeUid == SystemTypeInfo::UID) {
777                 const auto systemInfo = static_cast<const SystemTypeInfo*>(info);
778                 // for systems Untinitialize should be called before destroying the instance
779                 if (const auto pos = systems_.find(systemInfo->uid); pos != systems_.cend()) {
780                     pos->second->Uninitialize();
781                     systems_.erase(pos);
782                 }
783                 RemoveUid(systemOrder_, systemInfo->uid);
784             } else if (info && info->typeUid == ComponentManagerTypeInfo::UID) {
785                 const auto managerInfo = static_cast<const ComponentManagerTypeInfo*>(info);
786                 // BaseManager expects that the component list is empty when it's destroyed. might be also
787                 // nice to notify all the listeners that the components are being destroyed.
788                 if (const auto pos = managers_.find(managerInfo->uid); (pos != managers_.end()) && (pos->second)) {
789                     auto* manager = pos->second;
790                     CleanupComponentManager(*manager);
791                     managers_.erase(pos);
792                 }
793                 RemoveUid(managerOrder_, managerInfo->uid);
794             }
795         }
796     }
797 }
798 
CleanupComponentManager(IComponentManager & manager)799 void Ecs::CleanupComponentManager(IComponentManager& manager)
800 {
801     // remove all the components.
802     const auto components = static_cast<IComponentManager::ComponentId>(manager.GetComponentCount());
803     for (IComponentManager::ComponentId i = 0; i < components; ++i) {
804         manager.Destroy(manager.GetEntity(i));
805     }
806 
807     // check are there generic or specific component listeners to inform.
808     if (const auto listenerIt = componentManagerListeners_.find(&manager);
809         !componentListeners_.empty() ||
810         ((listenerIt != componentManagerListeners_.end()) && !listenerIt->second.empty())) {
811         if (const vector<Entity> removed = manager.GetRemovedComponents(); !removed.empty()) {
812             const auto removedView = array_view<const Entity>(removed);
813             for (auto* lister : componentListeners_) {
814                 if (lister) {
815                     lister->OnComponentEvent(ComponentListener::EventType::DESTROYED, manager, removedView);
816                 }
817             }
818             if (listenerIt != componentManagerListeners_.end()) {
819                 for (auto* lister : listenerIt->second) {
820                     if (lister) {
821                         lister->OnComponentEvent(ComponentListener::EventType::DESTROYED, manager, removedView);
822                     }
823                 }
824                 // remove all the listeners for this manager. RemoveListener won't do anything. this isn't neccessary,
825                 // but rather not leave invalid manager pointer even if it's just used as the key.
826                 componentManagerListeners_.erase(listenerIt);
827             }
828         }
829     }
830     // garbage collection will remove dead entries from the list and BaseManager is happy.
831     manager.Gc();
832 }
833 } // namespace
834 
IEcsInstance(IClassFactory & registry,const IThreadPool::Ptr & threadPool,const uint64_t ecsId)835 IEcs* IEcsInstance(IClassFactory& registry, const IThreadPool::Ptr& threadPool, const uint64_t ecsId)
836 {
837     return new Ecs(registry, threadPool, ecsId);
838 }
839 CORE_END_NAMESPACE()
840