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