• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "entity_manager.h"
17 
18 #include <algorithm>
19 #include <atomic>
20 
21 #include <base/containers/generic_iterator.h>
22 #include <base/containers/iterator.h>
23 #include <base/containers/refcnt_ptr.h>
24 #include <base/containers/type_traits.h>
25 #include <base/containers/unique_ptr.h>
26 #include <base/containers/unordered_map.h>
27 #include <base/containers/vector.h>
28 #include <base/namespace.h>
29 #include <core/ecs/entity.h>
30 #include <core/ecs/entity_reference.h>
31 #include <core/ecs/intf_entity_manager.h>
32 #include <core/log.h>
33 #include <core/namespace.h>
34 
35 CORE_BEGIN_NAMESPACE()
36 using BASE_NS::pair;
37 using BASE_NS::vector;
38 
39 namespace {
GetId(const Entity & e)40 uint32_t GetId(const Entity& e)
41 {
42     return e.id & 0xFFFFFFFF;
43 }
44 
GetGeneration(const Entity & e)45 uint32_t GetGeneration(const Entity& e)
46 {
47     return (e.id >> 32l) & 0xFFFFFFFF;
48 }
49 
MakeEntityId(uint32_t g,uint32_t i)50 Entity MakeEntityId(uint32_t g, uint32_t i)
51 {
52     return { (static_cast<uint64_t>(g) << 32L) | i };
53 }
54 } // namespace
55 
56 class EntityReferenceCounter final : public IEntityReferenceCounter {
57 public:
58     using Ptr = BASE_NS::refcnt_ptr<EntityReferenceCounter>;
59     EntityReferenceCounter() = default;
60     ~EntityReferenceCounter() override = default;
61     EntityReferenceCounter(const EntityReferenceCounter&) = delete;
62     EntityReferenceCounter& operator=(const EntityReferenceCounter&) = delete;
63     EntityReferenceCounter(EntityReferenceCounter&&) = delete;
64     EntityReferenceCounter& operator=(EntityReferenceCounter&&) = delete;
65 
Ref()66     void Ref() noexcept override
67     {
68         refcnt_.fetch_add(1, std::memory_order_relaxed);
69     }
70 
Unref()71     void Unref() noexcept override
72     {
73         if (refcnt_.fetch_sub(1, std::memory_order_release) == 0) {
74             std::atomic_thread_fence(std::memory_order_acquire);
75             delete this;
76         }
77     }
78 
GetRefCount() const79     int32_t GetRefCount() const noexcept override
80     {
81         return refcnt_.load(std::memory_order_relaxed);
82     }
83 
84 private:
85     std::atomic<int32_t> refcnt_ { -1 };
86 };
87 
EntityManager()88 EntityManager::EntityManager() : EntityManager(64u) {}
89 
EntityManager(const size_t entityCount)90 EntityManager::EntityManager(const size_t entityCount)
91 {
92     entities_.reserve(entityCount);
93 }
94 
~EntityManager()95 EntityManager::~EntityManager()
96 {
97     // count live entities, should be zero
98     [[maybe_unused]] int32_t liveEntities = 0;
99     [[maybe_unused]] int32_t inactiveEntities = 0;
100     for (const auto& e : entities_) {
101         if (EntityState::State::ALIVE == e.state) {
102             ++liveEntities;
103         }
104         if (EntityState::State::INACTIVE == e.state) {
105             ++inactiveEntities;
106         }
107     }
108     CORE_ASSERT(inactiveEntities == 0);
109     CORE_ASSERT(liveEntities == 0);
110 }
111 
Create()112 Entity EntityManager::Create()
113 {
114     Entity result;
115     if (freeList_.empty()) {
116         const auto generation = 1U;
117         const auto id = static_cast<uint32_t>(entities_.size());
118         entities_.push_back({ EntityState::State::ALIVE, generation, nullptr });
119         result = MakeEntityId(generation, id);
120     } else {
121         const auto id = freeList_.back();
122         freeList_.pop_back();
123         auto& slot = entities_[id];
124         // if the slot isn't free report a dead entity
125         if (slot.state != EntityState::State::FREE) {
126             const auto deadEntity = MakeEntityId(slot.generation, id);
127             removedList_.push_back(deadEntity);
128             eventList_.push_back({ deadEntity, EventType::DESTROYED });
129         }
130         slot.counter = nullptr; // NOTE: could push to a pool and recycle used often
131         ++slot.generation;
132 
133         slot.state = EntityState::State::ALIVE;
134         result = MakeEntityId(slot.generation, id);
135     }
136     eventList_.push_back({ result, EventType::CREATED });
137     ++generationCounter_;
138     return result;
139 }
140 
CreateReferenceCounted()141 EntityReference EntityManager::CreateReferenceCounted()
142 {
143     Entity result;
144     if (freeList_.empty()) {
145         const auto generation = 1U;
146         const auto id = static_cast<uint32_t>(entities_.size());
147         entities_.push_back(
148             { EntityState::State::ALIVE, generation, EntityReferenceCounter::Ptr { new EntityReferenceCounter } });
149         result = MakeEntityId(generation, id);
150     } else {
151         const auto id = freeList_.back();
152         freeList_.pop_back();
153         auto& slot = entities_[id];
154 
155         // if the slot isn't free report a dead entity
156         if (slot.state != EntityState::State::FREE) {
157             const auto deadEntity = MakeEntityId(slot.generation, id);
158             removedList_.push_back(deadEntity);
159             eventList_.push_back({ deadEntity, EventType::DESTROYED });
160         }
161         if (!slot.counter) {
162             slot.counter.reset(new EntityReferenceCounter);
163         }
164         ++slot.generation;
165         slot.state = EntityState::State::ALIVE;
166         result = MakeEntityId(slot.generation, id);
167     }
168     eventList_.push_back({ result, EventType::CREATED });
169     ++generationCounter_;
170     return EntityReference(result, entities_[GetId(result)].counter);
171 }
172 
GetReferenceCounted(const Entity entity)173 EntityReference EntityManager::GetReferenceCounted(const Entity entity)
174 {
175     if (!EntityUtil::IsValid(entity)) {
176         return {};
177     }
178     const uint32_t id = GetId(entity);
179     if (id >= entities_.size()) {
180         return {};
181     }
182     auto& e = entities_[id];
183     // make sure the given entity id has the same generation and that the entity isn't dead or free.
184     if ((e.generation == GetGeneration(entity)) &&
185         ((e.state == EntityState::State::ALIVE) || (e.state == EntityState::State::INACTIVE))) {
186         if (!e.counter) {
187             // entity wasn't yet reference counted so add a counter
188             e.counter.reset(new EntityReferenceCounter);
189             return { entity, e.counter };
190         }
191         if (e.counter->GetRefCount() > 0) {
192             // reference count is still valid
193             return { entity, e.counter };
194         }
195         // reference count has expired, but we won't revive the entity.
196     }
197 
198     return {};
199 }
200 
Destroy(const Entity entity)201 void EntityManager::Destroy(const Entity entity)
202 {
203     if (EntityUtil::IsValid(entity)) {
204         if (const uint32_t id = GetId(entity); id < entities_.size()) {
205             auto& e = entities_[id];
206             if ((e.generation == GetGeneration(entity)) &&
207                 ((e.state == EntityState::State::ALIVE) || (e.state == EntityState::State::INACTIVE))) {
208                 e.state = EntityState::State::DEAD;
209                 e.counter = nullptr;
210                 removedList_.push_back(entity);
211                 eventList_.push_back({ entity, EventType::DESTROYED });
212                 ++generationCounter_;
213             }
214         }
215     }
216 }
217 
DestroyAllEntities()218 void EntityManager::DestroyAllEntities()
219 {
220     for (uint32_t i = 0, count = static_cast<uint32_t>(entities_.size()); i < count; ++i) {
221         auto& e = entities_[i];
222         if ((EntityState::State::ALIVE == e.state) || (EntityState::State::INACTIVE == e.state)) {
223             auto entity = MakeEntityId(e.generation, i);
224             removedList_.push_back(entity);
225             eventList_.push_back({ entity, EventType::DESTROYED });
226             e.counter = nullptr;
227             e.state = EntityState::State::DEAD;
228         }
229     }
230     ++generationCounter_;
231 }
232 
IsAlive(const Entity entity) const233 bool EntityManager::IsAlive(const Entity entity) const
234 {
235     if (EntityUtil::IsValid(entity)) {
236         const uint32_t id = GetId(entity);
237         if (id < entities_.size()) {
238             const auto& state = entities_[id];
239             if (state.generation == GetGeneration(entity)) {
240                 return (state.state == EntityState::State::ALIVE) &&
241                        (!state.counter || (state.counter->GetRefCount() > 0));
242             }
243         }
244     }
245     return false;
246 }
247 
GetRemovedEntities()248 vector<Entity> EntityManager::GetRemovedEntities()
249 {
250     const auto freeSize = freeList_.size();
251     for (const Entity& e : removedList_) {
252         const uint32_t id = GetId(e);
253         if (id < entities_.size()) {
254             if (entities_[id].generation == GetGeneration(e)) {
255                 CORE_ASSERT(entities_[id].state == EntityState::State::DEAD);
256                 if (id < entities_.size() - 1) {
257                     entities_[id].state = EntityState::State::FREE;
258                     freeList_.push_back(id);
259                 } else {
260                     entities_.resize(entities_.size() - 1);
261                 }
262             }
263         }
264     }
265     if (const auto finalFreeSize = freeList_.size()) {
266         // by sorting with greater and using pop_back in creation we keep entities_ filled from the beginning.
267         // could be removed not useful.
268         if (finalFreeSize != freeSize) {
269             std::sort(freeList_.begin(), freeList_.end(), std::greater {});
270         }
271         // check from the beginning that ids don't go out-of-bounds and remove problematic ones.
272         // most likely they never are so linear is better than lower_bounds.
273         auto count = 0U;
274         while ((count < finalFreeSize) && (freeList_[count] >= entities_.size())) {
275             ++count;
276         }
277         if (count) {
278             freeList_.erase(freeList_.cbegin(), freeList_.cbegin() + count);
279         }
280     }
281     return move(removedList_);
282 }
283 
GetGenerationCounter() const284 uint32_t EntityManager::GetGenerationCounter() const
285 {
286     return generationCounter_;
287 }
288 
GetEvents()289 vector<pair<Entity, IEntityManager::EventType>> EntityManager::GetEvents()
290 {
291     return move(eventList_);
292 }
293 
SetActive(const Entity entity,bool state)294 void EntityManager::SetActive(const Entity entity, bool state)
295 {
296     if (!EntityUtil::IsValid(entity)) {
297         return;
298     }
299     const uint32_t id = GetId(entity);
300     if (id >= entities_.size()) {
301         return;
302     }
303     EntityState::State oldState;
304     EntityState::State newState;
305     EventType event;
306     if (state) {
307         oldState = EntityState::State::INACTIVE;
308         newState = EntityState::State::ALIVE;
309         event = EventType::ACTIVATED;
310     } else {
311         oldState = EntityState::State::ALIVE;
312         newState = EntityState::State::INACTIVE;
313         event = EventType::DEACTIVATED;
314     }
315 
316     if (entities_[id].generation == GetGeneration(entity)) {
317         if (entities_[id].state == oldState) {
318             entities_[id].state = newState;
319             eventList_.push_back({ entity, event });
320             ++generationCounter_;
321         }
322     }
323 }
324 
UpdateDeadEntities()325 void EntityManager::UpdateDeadEntities()
326 {
327     const auto removedCount = removedList_.size();
328     for (uint32_t id = 0, count = static_cast<uint32_t>(entities_.size()); id < count; ++id) {
329         auto& e = entities_[id];
330         if ((e.state != EntityState::State::FREE) && e.counter && (e.counter->GetRefCount() == 0)) {
331             const Entity entity = MakeEntityId(e.generation, id);
332             removedList_.push_back(entity);
333             eventList_.push_back({ entity, EventType::DESTROYED });
334             e.state = EntityState::State::DEAD;
335         }
336     }
337     if (removedCount != removedList_.size()) {
338         ++generationCounter_;
339     }
340 }
341 
IteratorImpl(const EntityManager & owner,size_t index,IteratorType type)342 EntityManager::IteratorImpl::IteratorImpl(const EntityManager& owner, size_t index, IteratorType type)
343     : owner_(&owner), index_(static_cast<uint32_t>(index)), type_(type)
344 {
345     const auto valid = (type == IteratorType::DEACTIVATED) ? EntityState::State::INACTIVE : EntityState::State::ALIVE;
346     if (index < owner.entities_.size()) {
347         const auto& e = owner.entities_[index];
348         if ((e.state != valid) || (e.counter && e.counter->GetRefCount() == 0)) {
349             Next();
350         }
351     }
352 }
353 
GetOwner() const354 const class IEntityManager* EntityManager::IteratorImpl::GetOwner() const
355 {
356     return owner_;
357 }
358 
Compare(const Iterator::Ptr & other) const359 bool EntityManager::IteratorImpl::Compare(const Iterator::Ptr& other) const
360 {
361     if ((other == nullptr) || (other->GetOwner() != owner_)) {
362         return false;
363     }
364     auto* otheri = static_cast<const EntityManager::IteratorImpl*>(other.get());
365     return (index_ == otheri->index_) && (type_ == otheri->type_);
366 }
367 
Next()368 bool EntityManager::IteratorImpl::Next()
369 {
370     const auto& entities = owner_->entities_;
371     if (index_ < entities.size()) {
372         const auto valid =
373             (type_ == IteratorType::DEACTIVATED) ? EntityState::State::INACTIVE : EntityState::State::ALIVE;
374 
375         ++index_;
376         while (index_ < entities.size()) {
377             auto& state = entities[index_];
378             if ((state.state == valid) && ((!state.counter) || (state.counter->GetRefCount() > 0))) {
379                 break;
380             }
381             ++index_;
382         }
383     }
384     return (index_ < owner_->entities_.size());
385 }
386 
Get() const387 Entity EntityManager::IteratorImpl::Get() const
388 {
389     if (index_ >= owner_->entities_.size()) {
390         return {};
391     }
392     return MakeEntityId(owner_->entities_[index_].generation, index_);
393 }
394 
MakeIterator(uint32_t index,IteratorType type) const395 IEntityManager::Iterator::Ptr EntityManager::MakeIterator(uint32_t index, IteratorType type) const
396 {
397     auto del = [](Iterator* it) { delete static_cast<EntityManager::IteratorImpl*>(it); };
398     auto p = new EntityManager::IteratorImpl(*this, index, type);
399     return { p, del };
400 }
401 
Clone() const402 IEntityManager::Iterator::Ptr EntityManager::IteratorImpl::Clone() const
403 {
404     return owner_->MakeIterator(index_, type_);
405 }
406 
Begin(IteratorType type) const407 IEntityManager::Iterator::Ptr EntityManager::Begin(IteratorType type) const
408 {
409     return MakeIterator(0U, type);
410 }
411 
End(IteratorType type) const412 IEntityManager::Iterator::Ptr EntityManager::End(IteratorType type) const
413 {
414     return MakeIterator(static_cast<uint32_t>(entities_.size()), type);
415 }
416 
417 CORE_END_NAMESPACE()
418