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