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