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