Skip to main content

EntityManager.ixx File

Central manager for entity lifecycle and component storage. More...

Included Headers

#include <memory> #include <vector> #include <cstddef> #include <cassert> #include "helios-ecs-config.h" #include <helios.ecs.types> #include <helios.ecs.components> #include <helios.ecs.ComponentOpsRegistry> #include <helios.ecs.concepts.Traits> #include <helios.ecs.EntityRegistry> #include <helios.ecs.SparseSet>

Namespaces Index

namespacehelios
namespaceecs

Classes Index

classEntityManager<THandle, TEntityRegistry, TCapacity>

Manages entities and their associated components. More...

Description

Central manager for entity lifecycle and component storage.

File Listing

The file content with the documentation metadata removed is:

1
5module;
6
7#include <memory>
8#include <vector>
9#include <cstddef>
10#include <cassert>
11
12#include "helios-ecs-config.h"
13
14export module helios.ecs.EntityManager;
15
16import helios.ecs.SparseSet;
17import helios.ecs.EntityRegistry;
18import helios.ecs.ComponentOpsRegistry;
19
20import helios.ecs.types;
21import helios.ecs.components;
22
23import helios.ecs.concepts.Traits;
24
25
26using namespace helios::ecs::types;
27using namespace helios::ecs::components;
28using namespace helios::ecs::concepts;
29export namespace helios::ecs {
30
73 template<
74 typename THandle,
75 typename TEntityRegistry,
76 size_t TCapacity
77 >
79
80
81 public:
82
84 using EntityRegistry_type = TEntityRegistry;
86 using Handle_type = THandle;
88 using StrongId_type = Handle_type::StrongId_type;
93
97 EntityManager(const EntityManager&) = delete;
99
103 EntityManager(EntityManager&&) noexcept = default;
104
108 EntityManager& operator=(EntityManager&&) noexcept = default;
109
110
120 explicit EntityManager(const size_t capacity = TCapacity)
121 : registry_(EntityRegistry_type{capacity}), capacity_(capacity) {
122 int i = 1;
123 }
124
134 [[nodiscard]] Handle_type create(StrongId_type strongId = StrongId_type{}) {
135 return registry_.create(strongId);
136 }
137
145 [[nodiscard]] bool isValid(const Handle_type handle) const noexcept {
146 return registry_.isValid(handle);
147 }
148
156 [[nodiscard]] bool isValid(const EntityId entityId) const noexcept {
157 return registry_.isValid(handle(entityId));
158 }
159
171 [[nodiscard]] bool destroy(const Handle_type handle) {
172
173 if (!registry_.isValid(handle)) {
174 return false;
175 }
176
177 for (size_t i = 0; i < components_.size(); i++) {
178
179 if (!components_[i]) {
180 continue;
181 }
182 const auto typeId = ComponentTypeId_type{i};
183 if (void* rawCmp = raw(handle, typeId)) {
184 if (const auto& ops = ComponentOpsRegistry_type::ops(typeId); ops.onRemove) {
185 ops.onRemove(rawCmp);
186 }
187 }
188
189 components_[i]->remove(handle.entityId);
190 }
191
192 registry_.destroy(handle);
193
194 return true;
195 }
196
207 template<typename T>
208 [[nodiscard]] T* get(const Handle_type handle) const {
209 if (!has<T>(handle)) {
210 return nullptr;
211 }
212
213 const auto entityId = handle.entityId;
214 const auto typeId = ComponentTypeId_type::template id<T>().value();
215
216 auto* sparseSet = static_cast<SparseSet<T>*>(components_[typeId].get());
217
218 return sparseSet->get(entityId);
219 }
220
228 template<typename T>
229 [[nodiscard]] SparseSet<T>* sparseSet() {
230
231 const auto typeId = ComponentTypeId_type::template id<T>().value();
232
233 if (typeId >= components_.size() || !components_[typeId]) {
234 return nullptr;
235 }
236
237 return static_cast<SparseSet<T>*>(components_[typeId].get());
238 }
239
247 template<typename T>
248 [[nodiscard]] const SparseSet<T>* sparseSet() const {
249
250 const auto typeId = ComponentTypeId_type::template id<T>().value();
251
252 if (typeId >= components_.size()) {
253 return nullptr;
254 }
255
256 return static_cast<SparseSet<T>*>(components_[typeId].get());
257 }
258
269 template<typename T>
270 [[nodiscard]] bool has(const Handle_type handle) const {
271 if (!registry_.isValid(handle)) {
272 return false;
273 }
274
275 const auto typeId = ComponentTypeId_type::template id<T>().value();
276
277 if (typeId < components_.size() && components_[typeId]) {
278 return components_[typeId]->contains(handle.entityId);
279 }
280
281 return false;
282 }
283
292 [[nodiscard]] bool has(const Handle_type handle,
293 const ComponentTypeId_type typeId) const {
294 if (!registry_.isValid(handle)) {
295 return false;
296 }
297
298 const auto tvalue = typeId.value();
299
300 if (tvalue < components_.size() && components_[tvalue]) {
301 return components_[tvalue]->contains(handle.entityId);
302 }
303
304 return false;
305 }
306
316 template<typename TComponent>
318
319 const auto typeId = ComponentTypeId_type::template id<TComponent>().value();
320
321 if (typeId >= components_.size()) {
322 components_.resize(typeId + 1);
323 }
324
325 if (!components_[typeId]) {
326 components_[typeId] = std::make_unique<SparseSet<TComponent>>(capacity_);
327 }
328
329 return static_cast<SparseSet<TComponent>*>(components_[typeId].get());
330 }
331
349 template<typename T, typename... Args>
350 T* emplace(const Handle_type handle, Args&& ...args) {
351
352 if (!registry_.isValid(handle)) {
353 return nullptr;
354 }
355
356 const auto entityId = handle.entityId;
357
358 const auto typeId = ComponentTypeId_type::template id<T>().value();
359
360 auto* sparseSet = ensureSparseSet<T>();
361
362 if (sparseSet->contains(entityId)) {
363 return nullptr;
364 }
365
366 return sparseSet->emplace(entityId, std::forward<Args>(args)...);
367 }
368
381 template<typename T, typename... Args>
382 T* emplaceOrGet(const Handle_type handle, Args&& ...args) {
383
384 if (!registry_.isValid(handle)) {
385 return nullptr;
386 }
387
388 auto* raw = emplace<T>(handle, std::forward<Args>(args)...);
389
390 if (!raw) {
391 return get<T>(handle);
392 }
393
394 return raw;
395 }
396
414 template<typename T>
415 [[nodiscard]] bool remove(const Handle_type& handle) {
416
417 if (!has<T>(handle)) {
418 return false;
419 }
420
421 const auto typeId = ComponentTypeId_type::template id<T>();
422 void* rawCmp = raw(handle, typeId);
423 if (!rawCmp) {
424 return false;
425 }
426 const auto& ops = ComponentOpsRegistry_type::ops(typeId);
427
428 if (ops.onRemove && !ops.onRemove(rawCmp)) {
429 return false;
430 }
431
432 return components_[typeId.value()]->remove(handle.entityId);
433 }
434
442 template<typename TComponent>
443 [[nodiscard]] bool managesDirty() {
444
445 auto typeId = ComponentTypeId_type::template id<DirtyComponentSpec<TComponent>>().value();
446
447 return typeId < components_.size() && components_[typeId];
448 }
449
457 template<typename TComponent>
458 void trackDirty() {
459 auto typeId = ComponentTypeId_type::template id<DirtyComponentSpec<TComponent>>().value();
460
461 if (typeId >= components_.size()) {
462 components_.resize(typeId + 1);
463 }
464
465 // not calling ensureSparseSet() since we need to make sure registeredDirtySets
466 // is pushed once with typeId
467 if (!components_[typeId]) {
468 components_[typeId] = std::make_unique<SparseSet<DirtyComponentSpec<TComponent>>>(capacity_);
469 registeredDirtySets_.push_back(typeId);
470 }
471 #if HELIOS_DEBUG
472 else {
473 bool found = false;
474 for (auto id : registeredDirtySets_) {
475 if (id == typeId) {
476 found = true;
477 break;
478 }
479 }
480 if (!found) {
481 assert(false && "typeId found, but was missing in registeredDirtySets_");
482 //registeredDirtySets_.push_back(typeId);
483 }
484
485 }
486 #endif
487
488
489 }
490
497
498 for (const auto id : registeredDirtySets_) {
499 if (id < components_.size() && components_[id]) {
500 components_[id]->clear();
501 }
502 }
503 }
504
512 template<typename... T>
514 ([this] {
515 const auto typeId = ComponentTypeId_type::template id<DirtyComponentSpec<T>>().value();
516 if (typeId < components_.size() && components_[typeId]) {
517 components_[typeId]->clear();
518 }
519 }(), ...);
520 }
521
533 template<typename TFunc>
534 void forEachComponentTypeId(const Handle_type handle, TFunc&& func) const {
535 if (!registry_.isValid(handle)) {
536 return;
537 }
538
539 for (size_t i = 0; i < components_.size(); i++) {
540 if (components_[i] && components_[i]->contains(handle.entityId)) {
541 std::forward<TFunc>(func)(ComponentTypeId_type{i});
542 }
543 }
544 }
545
556 void clone(const Handle_type source, const Handle_type target) {
557
558 if (!registry_.isValid(source)) {
559 return;
560 }
561
563 [&](const ComponentTypeId_type typeId) {
564 if (!has(target, typeId)) {
565
566 const auto& ops = ComponentOpsRegistry_type::ops(typeId);
567 const void* sourceCmp = raw(source, typeId);
568
569 if (sourceCmp && ops.clone) {
570 ops.clone(this, sourceCmp, &target);
571 }
572 }
573 }
574 );
575
576 }
577
586 [[nodiscard]] void* raw(const Handle_type handle, const ComponentTypeId_type typeId ) const {
587 if (!has(handle, typeId)) {
588 return nullptr;
589 }
590
591 return components_[typeId.value()]->raw(handle.entityId);
592 }
593
601 [[nodiscard]] Handle_type handle(const EntityId entityId) const {
602 return Handle_type{entityId, registry_.version(entityId), registry_.strongId(entityId)};
603 }
604
605 private:
606
608 std::vector<size_t> registeredDirtySets_;
609
610
616 std::vector<std::unique_ptr<SparseSetBase>> components_;
617
621 EntityRegistry_type registry_;
622
626 const size_t capacity_;
627
628 };
629
630
631}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.