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