11#include "ecs/component/core/hierarchy.h"
12#include "core/memory/type_registry.h"
13#include "ecs/environment.h"
14#include "ecs/physics_settings.h"
15#include "ecs/entity.h"
16#include "ecs/scene_observer.h"
17#include "core/memory/slot_allocator.h"
18#include "core/memory/sparse_set.h"
19#include "core/memory/types.h"
21namespace Vkm::Engine {
34 Scene(
const Scene& other) =
delete;
35 Scene& operator=(
const Scene& other) =
delete;
37 Scene(Scene && other) =
delete;
38 Scene& operator=(Scene && other) =
delete;
51 bool recycled =
false;
52 const EntityId id{m_entityAllocator.allocate(&recycled)};
70 const EntityId id{m_entityAllocator.allocateAt(index)};
86 VKM_ASSERT(isAlive(
id),
"Scene::destroyEntity called with dead/stale entity");
87 if (!isAlive(
id))
return;
91 observer->onEntityDestroyed(
id);
93 detachFromHierarchy(*
this,
id);
96 m_entityAllocator.free(
id.key);
99 bool isAlive(
EntityId id)
const {
return m_entityAllocator.
has(
id.key); }
100 bool isAliveAtIndex(uint32_t index)
const {
return m_entityAllocator.
isAliveAtIndex(index); }
101 size_t entityCount()
const {
return m_entityAllocator.
size(); }
112 return EntityId{m_entityAllocator.handleAt(index)};
129 VKM_ASSERT(isAlive(entity),
"Scene::add called with dead/stale entity");
130 using U = std::remove_cv_t<std::remove_reference_t<T>>;
131 VKM_ASSERT(!
has<U>(entity),
"Scene::add: entity already carries this component type");
132 return getStorage<U>().add(entity.slot(), std::forward<T>(component));
146 VKM_ASSERT(isAlive(entity),
"Scene::remove called with dead/stale entity");
147 if (!isAlive(entity))
return;
148 auto* store = findStorage<T>();
149 if (store && store->contains(entity.slot())) {
150 store->remove(entity.slot());
163 if (!isAlive(entity))
return false;
164 auto* store = findStorage<T>();
165 return store && store->contains(entity.slot());
177 VKM_ASSERT(isAlive(entity),
"Scene::get called with dead/stale entity");
178 auto* store = findStorage<T>();
179 VKM_ASSERT(store,
"Scene::get called for unregistered component type");
180 return store->get(entity.slot());
192 VKM_ASSERT(isAlive(entity),
"Scene::get called with dead/stale entity");
193 auto* store = findStorage<T>();
194 VKM_ASSERT(store,
"Scene::get called for unregistered component type");
195 return store->get(entity.slot());
207 if (!isAlive(entity))
return nullptr;
208 auto* store = findStorage<T>();
209 if (!store || !store->contains(entity.slot()))
return nullptr;
210 return &store->get(entity.slot());
216 if (!isAlive(entity))
return nullptr;
217 const auto* store = findStorage<T>();
218 if (!store || !store->contains(entity.slot()))
return nullptr;
219 return &store->get(entity.slot());
230 auto* store = findStorage<T>();
231 return store ? store->size() : 0;
246 template<
typename First,
typename... Rest,
typename Fn>
250 auto* firstStorage = findStorage<First>();
251 if (!firstStorage)
return;
253 if constexpr (
sizeof...(Rest) == 0) {
254 firstStorage->forEach([&](uint32_t entityIdx, First& first) {
259 auto restStorages = std::make_tuple(findStorage<Rest>()...);
262 firstStorage->forEach([&](uint32_t entityIdx, First& first) {
263 if (!(std::get<
SparseSet<Rest>*>(restStorages)->contains(entityIdx) && ...))
return;
271 template<
typename First,
typename... Rest,
typename Fn>
273 auto* firstStorage = findStorage<First>();
274 if (!firstStorage)
return;
276 if constexpr (
sizeof...(Rest) == 0) {
277 firstStorage->forEach([&](uint32_t entityIdx,
const First& first) {
282 auto restStorages = std::make_tuple(findStorage<Rest>()...);
283 if (!(std::get<
const SparseSet<Rest>*>(restStorages) && ...))
return;
285 firstStorage->forEach([&](uint32_t entityIdx,
const First& first) {
286 if (!(std::get<
const SparseSet<Rest>*>(restStorages)->contains(entityIdx) && ...))
return;
289 fn(eid, first, std::get<
const SparseSet<Rest>*>(restStorages)->
get(entityIdx)...);
300 template<
typename Fn>
302 m_entityAllocator.forEach([&](uint32_t idx) {
317 m_components.clear();
318 m_entityAllocator.clear();
339 void swap(Scene& other)
noexcept {
341 m_entityAllocator.swap(other.m_entityAllocator);
342 m_components.swap(other.m_components);
343 swap(m_environment, other.m_environment);
344 swap(m_physics, other.m_physics);
357 m_observers.push_back(observer);
366 for (
auto it = m_observers.begin(); it != m_observers.end(); ++it) {
367 if (*it == observer) {
368 m_observers.erase(it);
397 uint64_t
epoch()
const {
return m_epoch; }
423 SparseSet<T>& getStorage() {
424 ISparseSet& base = m_components.ensure<T>([] {
return std::make_unique<SparseSet<T>>(); });
425 return static_cast<SparseSet<T>&
>(base);
435 SparseSet<T>* findStorage() {
436 return static_cast<SparseSet<T>*
>(m_components.find<T>());
440 const SparseSet<T>* findStorage()
const {
441 return static_cast<const SparseSet<T>*
>(m_components.find<T>());
445 Environment m_environment;
446 PhysicsSettings m_physics;
448 uint64_t m_epoch = 0;
450 SlotAllocator m_entityAllocator;
451 TypeRegistry<ISparseSet> m_components;
452 std::vector<ISceneObserver*> m_observers;
467template <
typename First,
typename... Rest,
typename Pred>
470 scene.forEach<First, Rest...>([&](
EntityId id,
const First& first,
const Rest&... rest) {
471 if (!pred(first, rest...))
return;
472 if (!found ||
id.slot() < found.slot()) found = id;
Observer notified by a Scene when an entity is destroyed.
Definition scene_observer.h:13
Type-erased interface for SparseSet, so one registry holds every type.
Definition sparse_set.h:15
virtual void compact()=0
Release the sparse array's slack, keeping every live element.
virtual void removeIfPresent(uint32_t key)=0
Remove the element at the given key, if this set holds one.
Central registry managing entities and an open set of component types.
Definition scene.h:29
const T * tryGet(EntityId entity) const
The entity's T, or null when it has none.
Definition scene.h:215
void removeObserver(ISceneObserver *observer)
Unregister an observer added with addObserver.
Definition scene.h:365
uint64_t epoch() const
Identity of the world these entities belong to, bumped by clear() and swap().
Definition scene.h:397
void forEachEntity(Fn &&fn) const
Invoke fn(EntityId) for every live entity in this scene.
Definition scene.h:301
void clear()
Drop every component set and reset the entity allocator, the environment and the physics settings in ...
Definition scene.h:315
void forEach(Fn &&fn)
Iterate all live components densely (no holes).
Definition scene.h:247
size_t count() const
Number of live components of type T.
Definition scene.h:229
T * tryGet(EntityId entity)
The entity's T, or null when it has none.
Definition scene.h:206
void destroyEntity(EntityId id)
Destroy an entity by removing all of its components and recycling its slot.
Definition scene.h:85
T & get(EntityId entity)
Get a mutable reference to an entity's component of type T.
Definition scene.h:176
EntityId createEntity()
Create a new entity and assign a unique EntityId.
Definition scene.h:50
PhysicsSettings & physics()
The scene's physics world parameters, saved with it.
Definition scene.h:412
bool has(EntityId entity) const
Check if an entity has a component of type T.
Definition scene.h:162
SparseSet< T > * storage()
Direct access to the typed SparseSet for component type T.
Definition scene.h:384
void addObserver(ISceneObserver *observer)
Register an observer, notified at the start of every destroyEntity.
Definition scene.h:356
const T & get(EntityId entity) const
Get a const reference to an entity's component of type T.
Definition scene.h:191
EntityId createEntityAt(uint32_t index)
Allocate an entity at the requested slot index.
Definition scene.h:69
auto & add(EntityId entity, T &&component)
Give an entity a component it does not have yet.
Definition scene.h:128
Environment & environment()
The scene's lighting environment, saved with it.
Definition scene.h:404
void compact()
Compact every component SparseSet to reclaim wasted memory.
Definition scene.h:327
void remove(EntityId entity)
Take a component of type T off an entity.
Definition scene.h:145
void swap(Scene &other) noexcept
Swap internal state with another Scene.
Definition scene.h:339
EntityId entityAt(uint32_t index) const
The full id of the entity in slot index, generation included.
Definition scene.h:111
bool isAliveAtIndex(uint32_t index) const
Check whether index currently holds a live slot.
Definition slot_allocator.h:104
size_t size() const
Number of live slots.
Definition slot_allocator.h:192
bool has(StorageIndex id) const
Test whether a handle is still valid.
Definition slot_allocator.h:78
Dense-packed storage indexed by external uint32_t keys.
Definition sparse_set.h:50
Names one entity of one Scene, for as long as that slot holds it.
Definition entity.h:23
The scene's lighting environment: sky, night sky and fog.
Definition environment.h:130
The physics world's own parameters, read once per fixed step.
Definition physics_settings.h:14