• 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 <core/log.h>
17
18CORE_BEGIN_NAMESPACE()
19namespace {
20constexpr uint32_t MODIFIED = 0x80000000;
21
22// Default initial reservation for 8 components/entities.
23// Will resize as needed.
24constexpr size_t INITIAL_COMPONENT_RESERVE_SIZE = 8;
25
26template<typename Container>
27inline auto ItemOrNull(Container&& v, IComponentManager::ComponentId index)
28{
29    if (index < v.size()) {
30        return &(v[index]);
31    }
32    return (BASE_NS::remove_reference_t<decltype(v[index])>*)(nullptr);
33}
34
35template<typename EntityMap>
36inline auto ItemId(EntityMap&& entities, Entity entity)
37{
38    if (EntityUtil::IsValid(entity)) {
39        if (const auto it = entities.find(entity); it != entities.end()) {
40            return it->second;
41        }
42    }
43    return IComponentManager::INVALID_COMPONENT_ID;
44}
45} // namespace
46
47// IPropertyApi
48template<typename ComponentType, typename BaseClass>
49IPropertyHandle* BaseManager<ComponentType, BaseClass>::Create() const
50{
51    return new BaseComponentHandle(const_cast<BaseManager<ComponentType, BaseClass>*>(this), {}, {});
52}
53
54template<typename ComponentType, typename BaseClass>
55IPropertyHandle* BaseManager<ComponentType, BaseClass>::Clone(const IPropertyHandle* src) const
56{
57    if (src->Owner() == this) {
58        auto* h = static_cast<const BaseComponentHandle*>(src);
59        return new BaseComponentHandle(const_cast<BaseManager<ComponentType, BaseClass>*>(this), {}, h->data_);
60    }
61    return nullptr;
62}
63
64template<typename ComponentType, typename BaseClass>
65void BaseManager<ComponentType, BaseClass>::Release(IPropertyHandle* dst) const
66{
67    if (dst && (dst->Owner() == this)) {
68        // we can only destroy things we "own" (know)
69        auto* handle = static_cast<BaseComponentHandle*>(dst);
70        if (auto id = GetComponentId(handle->entity_); id != IComponentManager::INVALID_COMPONENT_ID) {
71            if (&components_[id] == handle) {
72                // This is one of the components (bound to an entity) so do nothing
73                return;
74            }
75        }
76        delete handle;
77    }
78}
79
80template<typename ComponentType, typename BaseClass>
81uint64_t BaseManager<ComponentType, BaseClass>::Type() const
82{
83    return typeHash_;
84}
85
86// IComponentManager
87template<typename ComponentType, typename BaseClass>
88BASE_NS::string_view BaseManager<ComponentType, BaseClass>::GetName() const
89{
90    return name_;
91}
92
93template<typename ComponentType, typename BaseClass>
94BASE_NS::Uid BaseManager<ComponentType, BaseClass>::GetUid() const
95{
96    return BaseClass::UID;
97}
98
99template<typename ComponentType, typename BaseClass>
100size_t BaseManager<ComponentType, BaseClass>::GetComponentCount() const
101{
102    return components_.size();
103}
104
105template<typename ComponentType, typename BaseClass>
106const IPropertyApi& BaseManager<ComponentType, BaseClass>::GetPropertyApi() const
107{
108    return *this;
109}
110
111template<typename ComponentType, typename BaseClass>
112CORE_NS::Entity BaseManager<ComponentType, BaseClass>::GetEntity(ComponentId index) const
113{
114    if (index < components_.size()) {
115        return components_[index].entity_;
116    }
117    return CORE_NS::Entity();
118}
119
120template<typename ComponentType, typename BaseClass>
121uint32_t BaseManager<ComponentType, BaseClass>::GetComponentGeneration(ComponentId index) const
122{
123    if (index < components_.size()) {
124        return components_[index].generation_;
125    }
126    return 0;
127}
128
129template<typename ComponentType, typename BaseClass>
130bool BaseManager<ComponentType, BaseClass>::HasComponent(CORE_NS::Entity entity) const
131{
132    return GetComponentId(entity) != IComponentManager::INVALID_COMPONENT_ID;
133}
134
135template<typename ComponentType, typename BaseClass>
136IComponentManager::ComponentId BaseManager<ComponentType, BaseClass>::GetComponentId(CORE_NS::Entity entity) const
137{
138    if (EntityUtil::IsValid(entity)) {
139        if (auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
140            return it->second;
141        }
142    }
143    return IComponentManager::INVALID_COMPONENT_ID;
144}
145
146template<typename ComponentType, typename BaseClass>
147void BaseManager<ComponentType, BaseClass>::Create(CORE_NS::Entity entity)
148{
149    if (EntityUtil::IsValid(entity)) {
150        if (auto it = entityComponent_.find(entity); it == entityComponent_.end()) {
151            entityComponent_.insert({ entity, static_cast<ComponentId>(components_.size()) });
152            const auto oldCapacity = components_.capacity();
153            components_.emplace_back(this, entity);
154            if (components_.capacity() != oldCapacity) {
155                moved_.reserve(moved_.size() + components_.size());
156                for (const auto& handle : components_) {
157                    moved_.push_back(handle.entity_);
158                }
159                modifiedFlags_ |= CORE_COMPONENT_MANAGER_COMPONENT_MOVED_BIT;
160            }
161            added_.push_back(entity);
162            modifiedFlags_ |= CORE_COMPONENT_MANAGER_COMPONENT_ADDED_BIT;
163            ++generationCounter_;
164        } else {
165            if (auto dst = ScopedHandle<ComponentType>(&components_[it->second]); dst) {
166                *dst = {};
167            }
168        }
169    }
170}
171
172template<typename ComponentType, typename BaseClass>
173bool BaseManager<ComponentType, BaseClass>::Destroy(CORE_NS::Entity entity)
174{
175    if (EntityUtil::IsValid(entity)) {
176        if (auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
177            components_[it->second].entity_ = {}; // invalid entity. (marks it as ready for re-use)
178            entityComponent_.erase(it);
179            removed_.push_back(entity);
180            modifiedFlags_ |= CORE_COMPONENT_MANAGER_COMPONENT_REMOVED_BIT;
181            ++generationCounter_;
182            return true;
183        }
184    }
185    return false;
186}
187
188template<typename ComponentType, typename BaseClass>
189void BaseManager<ComponentType, BaseClass>::Gc()
190{
191    const bool hasRemovedComponents = modifiedFlags_ & CORE_COMPONENT_MANAGER_COMPONENT_REMOVED_BIT;
192    if (!hasRemovedComponents) {
193        return;
194    }
195    ComponentId componentCount = static_cast<ComponentId>(components_.size());
196    for (ComponentId id = 0; id < componentCount;) {
197        if (EntityUtil::IsValid(components_[id].entity_)) {
198            ++id;
199            continue;
200        }
201        // invalid entity.. if so clean garbage
202        // find last valid and swap with it
203        ComponentId rid = componentCount - 1;
204        while ((rid > id) && !EntityUtil::IsValid(components_[rid].entity_)) {
205            --rid;
206        }
207        if ((rid > id) && EntityUtil::IsValid(components_[rid].entity_)) {
208            moved_.push_back(components_[rid].entity_);
209            // fix the entityComponent_ map (update the component id for the entity)
210            entityComponent_[components_[rid].entity_] = id;
211            components_[id] = BASE_NS::move(components_[rid]);
212        }
213        --componentCount;
214    }
215    if (!moved_.empty()) {
216        modifiedFlags_ |= CORE_COMPONENT_MANAGER_COMPONENT_MOVED_BIT;
217    }
218    if (components_.size() > componentCount) {
219        auto diff = static_cast<typename decltype(components_)::difference_type>(componentCount);
220        components_.erase(components_.cbegin() + diff, components_.cend());
221    }
222}
223
224template<typename ComponentType, typename BaseClass>
225void BaseManager<ComponentType, BaseClass>::Destroy(BASE_NS::array_view<const CORE_NS::Entity> gcList)
226{
227    for (const CORE_NS::Entity e : gcList) {
228        Destroy(e);
229    }
230}
231
232template<typename ComponentType, typename BaseClass>
233BASE_NS::vector<CORE_NS::Entity> BaseManager<ComponentType, BaseClass>::GetAddedComponents()
234{
235    return BASE_NS::move(added_);
236}
237
238template<typename ComponentType, typename BaseClass>
239BASE_NS::vector<CORE_NS::Entity> BaseManager<ComponentType, BaseClass>::GetRemovedComponents()
240{
241    return BASE_NS::move(removed_);
242}
243
244template<typename ComponentType, typename BaseClass>
245BASE_NS::vector<CORE_NS::Entity> BaseManager<ComponentType, BaseClass>::GetUpdatedComponents()
246{
247    BASE_NS::vector<CORE_NS::Entity> updated;
248    if (modifiedFlags_ & MODIFIED) {
249        modifiedFlags_ &= ~MODIFIED;
250        updated.reserve(components_.size() / 2U); // 2: approximation for vector reserve size
251        for (auto& handle : components_) {
252            if (handle.dirty_) {
253                handle.dirty_ = false;
254                updated.push_back(handle.entity_);
255            }
256        }
257    }
258    return updated;
259}
260
261template<typename ComponentType, typename BaseClass>
262BASE_NS::vector<CORE_NS::Entity> BaseManager<ComponentType, BaseClass>::GetMovedComponents()
263{
264    return BASE_NS::move(moved_);
265}
266
267template<typename ComponentType, typename BaseClass>
268CORE_NS::ComponentManagerModifiedFlags BaseManager<ComponentType, BaseClass>::GetModifiedFlags() const
269{
270    return modifiedFlags_ & ~MODIFIED;
271}
272
273template<typename ComponentType, typename BaseClass>
274void BaseManager<ComponentType, BaseClass>::ClearModifiedFlags()
275{
276    modifiedFlags_ &= MODIFIED;
277}
278
279template<typename ComponentType, typename BaseClass>
280uint32_t BaseManager<ComponentType, BaseClass>::GetGenerationCounter() const
281{
282    return generationCounter_;
283}
284
285template<typename ComponentType, typename BaseClass>
286void BaseManager<ComponentType, BaseClass>::SetData(CORE_NS::Entity entity, const IPropertyHandle& dataHandle)
287{
288    if (!IsMatchingHandle(dataHandle)) {
289        return;
290    }
291    if (const auto src = ScopedHandle<const ComponentType>(&dataHandle); src) {
292        if (const auto it = entityComponent_.find(entity); it != entityComponent_.end()) {
293            if (auto dst = ScopedHandle<ComponentType>(&components_[it->second]); dst) {
294                *dst = *src;
295            }
296        }
297    }
298}
299
300template<typename ComponentType, typename BaseClass>
301const IPropertyHandle* BaseManager<ComponentType, BaseClass>::GetData(CORE_NS::Entity entity) const
302{
303    return ItemOrNull(components_, ItemId(entityComponent_, entity));
304}
305
306template<typename ComponentType, typename BaseClass>
307IPropertyHandle* BaseManager<ComponentType, BaseClass>::GetData(CORE_NS::Entity entity)
308{
309    return ItemOrNull(components_, ItemId(entityComponent_, entity));
310}
311
312template<typename ComponentType, typename BaseClass>
313void BaseManager<ComponentType, BaseClass>::SetData(ComponentId index, const IPropertyHandle& dataHandle)
314{
315    if (!IsMatchingHandle(dataHandle)) {
316        // We could verify the metadata here.
317        // And in copy only the matching properties one-by-one also.
318        return;
319    }
320    if (index < components_.size()) {
321        if (const auto src = ScopedHandle<const ComponentType>(&dataHandle); src) {
322            if (auto dst = ScopedHandle<ComponentType>(&components_[index]); dst) {
323                *dst = *src;
324            }
325        }
326    }
327}
328
329template<typename ComponentType, typename BaseClass>
330const IPropertyHandle* BaseManager<ComponentType, BaseClass>::GetData(ComponentId index) const
331{
332    return ItemOrNull(components_, index);
333}
334
335template<typename ComponentType, typename BaseClass>
336IPropertyHandle* BaseManager<ComponentType, BaseClass>::GetData(ComponentId index)
337{
338    return ItemOrNull(components_, index);
339}
340
341template<typename ComponentType, typename BaseClass>
342IEcs& BaseManager<ComponentType, BaseClass>::GetEcs() const
343{
344    return ecs_;
345}
346
347// "base class"
348template<typename ComponentType, typename BaseClass>
349ComponentType BaseManager<ComponentType, BaseClass>::Get(ComponentId index) const
350{
351    if (auto handle = ScopedHandle<const ComponentType>(ItemOrNull(components_, index))) {
352        return *handle;
353    }
354    return ComponentType {};
355}
356
357template<typename ComponentType, typename BaseClass>
358ComponentType BaseManager<ComponentType, BaseClass>::Get(CORE_NS::Entity entity) const
359{
360    if (auto handle = ScopedHandle<const ComponentType>(ItemOrNull(components_, ItemId(entityComponent_, entity)))) {
361        return *handle;
362    }
363    return ComponentType {};
364}
365
366template<typename ComponentType, typename BaseClass>
367void BaseManager<ComponentType, BaseClass>::Set(ComponentId index, const ComponentType& data)
368{
369    if (auto handle = ScopedHandle<ComponentType>(ItemOrNull(components_, index))) {
370        *handle = data;
371    }
372}
373
374template<typename ComponentType, typename BaseClass>
375void BaseManager<ComponentType, BaseClass>::Set(CORE_NS::Entity entity, const ComponentType& data)
376{
377    if (EntityUtil::IsValid(entity)) {
378        if (const auto it = entityComponent_.find(entity); it == entityComponent_.end()) {
379            entityComponent_.insert({ entity, static_cast<ComponentId>(components_.size()) });
380            const auto oldCapacity = components_.capacity();
381            components_.emplace_back(this, entity, data).generation_ = 1;
382            if (components_.capacity() != oldCapacity) {
383                moved_.reserve(moved_.size() + components_.size());
384                for (const auto& handle : components_) {
385                    moved_.push_back(handle.entity_);
386                }
387                modifiedFlags_ |= CORE_COMPONENT_MANAGER_COMPONENT_MOVED_BIT;
388            }
389            added_.push_back(entity);
390            modifiedFlags_ |= CORE_COMPONENT_MANAGER_COMPONENT_ADDED_BIT;
391            ++generationCounter_;
392        } else {
393            if (auto handle = ScopedHandle<ComponentType>(&components_[it->second]); handle) {
394                *handle = data;
395            }
396        }
397    }
398}
399
400template<typename ComponentType, typename BaseClass>
401ScopedHandle<const ComponentType> BaseManager<ComponentType, BaseClass>::Read(ComponentId index) const
402{
403    return ScopedHandle<const ComponentType> { ItemOrNull(components_, index) };
404}
405
406template<typename ComponentType, typename BaseClass>
407ScopedHandle<const ComponentType> BaseManager<ComponentType, BaseClass>::Read(CORE_NS::Entity entity) const
408{
409    return ScopedHandle<const ComponentType> { ItemOrNull(components_, ItemId(entityComponent_, entity)) };
410}
411
412template<typename ComponentType, typename BaseClass>
413ScopedHandle<ComponentType> BaseManager<ComponentType, BaseClass>::Write(ComponentId index)
414{
415    return ScopedHandle<ComponentType> { ItemOrNull(components_, index) };
416}
417
418template<typename ComponentType, typename BaseClass>
419ScopedHandle<ComponentType> BaseManager<ComponentType, BaseClass>::Write(CORE_NS::Entity entity)
420{
421    return ScopedHandle<ComponentType> { ItemOrNull(components_, ItemId(entityComponent_, entity)) };
422}
423
424// internal
425template<typename ComponentType, typename BaseClass>
426void BaseManager<ComponentType, BaseClass>::Updated(CORE_NS::Entity entity)
427{
428    CORE_ASSERT_MSG(EntityUtil::IsValid(entity), "Invalid ComponentId, bound to INVALID_ENTITY");
429    modifiedFlags_ |= CORE_COMPONENT_MANAGER_COMPONENT_UPDATED_BIT | MODIFIED;
430    ++generationCounter_;
431}
432
433template<typename ComponentType, typename BaseClass>
434BaseManager<ComponentType, BaseClass>::BaseManager(IEcs& ecs, const BASE_NS::string_view name) noexcept
435    : BaseManager(ecs, name, INITIAL_COMPONENT_RESERVE_SIZE)
436{}
437
438template<typename ComponentType, typename BaseClass>
439BaseManager<ComponentType, BaseClass>::BaseManager(
440    IEcs& ecs, const BASE_NS::string_view name, const size_t preallocate) noexcept
441    : ecs_(ecs), name_(name), typeHash_(BASE_NS::FNV1aHash(name.data(), name.size()))
442{
443    if (preallocate) {
444        components_.reserve(preallocate);
445        entityComponent_.reserve(preallocate);
446    }
447}
448
449template<typename ComponentType, typename BaseClass>
450BaseManager<ComponentType, BaseClass>::~BaseManager()
451{
452    CORE_ASSERT(GetComponentCount() == 0);
453}
454
455template<typename ComponentType, typename BaseClass>
456bool BaseManager<ComponentType, BaseClass>::IsMatchingHandle(const IPropertyHandle& dataHandle)
457{
458    if (dataHandle.Owner() == this) {
459        return true;
460    }
461    if (dataHandle.Owner() && (dataHandle.Owner()->Type() == typeHash_)) {
462        return true;
463    }
464    return false;
465}
466
467// handle implementation
468template<typename ComponentType, typename BaseClass>
469BaseManager<ComponentType, BaseClass>::BaseComponentHandle::BaseComponentHandle(
470    BaseManager* owner, CORE_NS::Entity entity) noexcept
471    : manager_(owner), entity_(entity)
472{}
473
474template<typename ComponentType, typename BaseClass>
475BaseManager<ComponentType, BaseClass>::BaseComponentHandle::BaseComponentHandle(
476    BaseManager* owner, CORE_NS::Entity entity, const ComponentType& data) noexcept
477    : manager_(owner), entity_(entity), data_(data)
478{}
479
480template<typename ComponentType, typename BaseClass>
481BaseManager<ComponentType, BaseClass>::BaseComponentHandle::BaseComponentHandle(BaseComponentHandle&& other) noexcept
482    :
483#ifndef NDEBUG
484    rLocked_(other.rLocked_.exchange(0U)),
485    wLocked_(BASE_NS::exchange(other.wLocked_, false)),
486#endif
487    manager_(other.manager_),
488    generation_(BASE_NS::exchange(other.generation_, 0U)),
489    entity_(BASE_NS::exchange(other.entity_, {})),
490    data_(BASE_NS::exchange(other.data_, {}))
491{
492#ifndef NDEBUG
493    CORE_ASSERT((rLocked_ == 0U) && !wLocked_);
494#endif
495}
496
497template<typename ComponentType, typename BaseClass>
498typename BaseManager<ComponentType, BaseClass>::BaseComponentHandle&
499BaseManager<ComponentType, BaseClass>::BaseComponentHandle::operator=(BaseComponentHandle&& other) noexcept
500{
501    if (this != &other) {
502        CORE_ASSERT(manager_ == other.manager_);
503#ifndef NDEBUG
504        CORE_ASSERT((other.rLocked_ == 0U) && !other.wLocked_);
505        rLocked_ = other.rLocked_.exchange(0U);
506        wLocked_ = BASE_NS::exchange(other.wLocked_, false);
507#endif
508        generation_ = BASE_NS::exchange(other.generation_, 0U);
509        entity_ = BASE_NS::exchange(other.entity_, {});
510        data_ = BASE_NS::exchange(other.data_, {});
511    }
512    return *this;
513}
514
515template<typename ComponentType, typename BaseClass>
516const IPropertyApi* BaseManager<ComponentType, BaseClass>::BaseComponentHandle::Owner() const
517{
518    return manager_;
519}
520
521template<typename ComponentType, typename BaseClass>
522size_t BaseManager<ComponentType, BaseClass>::BaseComponentHandle::Size() const
523{
524    return sizeof(ComponentType);
525}
526
527template<typename ComponentType, typename BaseClass>
528const void* BaseManager<ComponentType, BaseClass>::BaseComponentHandle::RLock() const
529{
530    CORE_ASSERT(manager_);
531#ifndef NDEBUG
532    CORE_ASSERT(!wLocked_);
533    ++rLocked_;
534#endif
535    return &data_;
536}
537
538template<typename ComponentType, typename BaseClass>
539void BaseManager<ComponentType, BaseClass>::BaseComponentHandle::RUnlock() const
540{
541    CORE_ASSERT(manager_);
542#ifndef NDEBUG
543    CORE_ASSERT(rLocked_ > 0U);
544    --rLocked_;
545#endif
546}
547
548template<typename ComponentType, typename BaseClass>
549void* BaseManager<ComponentType, BaseClass>::BaseComponentHandle::WLock()
550{
551    CORE_ASSERT(manager_);
552#ifndef NDEBUG
553    CORE_ASSERT(rLocked_ <= 1U && !wLocked_);
554    wLocked_ = true;
555#endif
556    return &data_;
557}
558
559template<typename ComponentType, typename BaseClass>
560void BaseManager<ComponentType, BaseClass>::BaseComponentHandle::WUnlock()
561{
562    CORE_ASSERT(manager_);
563#ifndef NDEBUG
564    CORE_ASSERT(wLocked_);
565    wLocked_ = false;
566#endif
567    // update generation etc..
568    ++generation_;
569    if (EntityUtil::IsValid(entity_)) {
570        dirty_ = true;
571        manager_->Updated(entity_);
572    }
573}
574CORE_END_NAMESPACE()
575