PixelBullet  0.0.1
A C++ game engine
Loading...
Searching...
No Matches
scene.h
1#pragma once
2
4#include "pixelbullet/scene/component_storage.h"
5#include "pixelbullet/scene/entity_id.h"
6#include "pixelbullet/scene/scene_environment_settings.h"
7
8#include <cstdint>
9#include <functional>
10#include <memory>
11#include <stdexcept>
12#include <string>
13#include <string_view>
14#include <type_traits>
15#include <typeindex>
16#include <unordered_map>
17#include <vector>
18
19namespace pixelbullet
20{
21class SceneSerializer;
22
23enum class SceneComponentDefaults
24{
25 None,
26 Engine,
27};
28
29class Scene
30{
31public:
32 explicit Scene(SceneComponentDefaults defaults = SceneComponentDefaults::Engine);
33
34 EntityId CreateEntity();
35 void DestroyEntity(EntityId entity_id);
36
37 [[nodiscard]] bool IsAlive(EntityId entity_id) const
38 {
39 return entity_id.Index() < entities_.size() && entities_[entity_id.Index()] == entity_id;
40 }
41
42 [[nodiscard]] std::vector<EntityId> GetEntities() const
43 {
44 std::vector<EntityId> entities;
45 entities.reserve(entities_.size());
46 for (const EntityId entity : entities_)
47 {
48 if (entity)
49 {
50 entities.push_back(entity);
51 }
52 }
53 return entities;
54 }
55
56 template <typename T, typename... Args>
57 T& AddComponent(EntityId entity_id, Args&&... args)
58 {
59 ASSERT(IsAlive(entity_id), "Cannot add component to stale or invalid entity");
60 auto storage = GetOrCreateComponentStorage<T>();
61 T& component = storage->components.emplace(entity_id.Index(), std::forward<Args>(args)...);
62 ++mutation_generation_;
63 return component;
64 }
65
66 template <typename T>
67 void RemoveComponent(EntityId entity_id)
68 {
69 ASSERT(IsAlive(entity_id), "Cannot remove component from stale or invalid entity");
70 auto storage = GetOrCreateComponentStorage<T>();
71 storage->components.erase(entity_id.Index());
72 ++mutation_generation_;
73 }
74
75 template <typename T>
76 bool HasComponent(EntityId entity_id) const
77 {
78 if (!IsAlive(entity_id))
79 {
80 return false;
81 }
82
83 const auto type_id = std::type_index(typeid(T));
84 auto it = component_storage_.find(type_id);
85 if (it != component_storage_.end())
86 {
87 const auto* storage = static_cast<const ComponentStorage<T>*>(it->second.get());
88 return storage->components.contains(entity_id.Index());
89 }
90 return false;
91 }
92
93 template <typename T>
94 void RegisterComponent(std::string_view serialization_name)
95 {
96 RegisterComponentType(std::type_index(typeid(T)), std::string(serialization_name),
97 []() { return std::make_unique<ComponentStorage<T>>(); });
98 }
99
100 void RegisterComponentTypesFrom(const Scene& source);
101 [[nodiscard]] std::vector<std::string> GetRegisteredComponentNames() const;
102
103 template <typename T>
104 T& GetComponent(EntityId entity_id)
105 {
106 ASSERT(IsAlive(entity_id), "Cannot get component from stale or invalid entity");
107 auto storage = GetOrCreateComponentStorage<T>();
108 return storage->components.at(entity_id.Index());
109 }
110
111 template <typename T>
112 const T& GetComponent(EntityId entity_id) const
113 {
114 ASSERT(IsAlive(entity_id), "Cannot get component from stale or invalid entity");
115 const auto* storage = TryGetComponentStorage<T>();
116 ASSERT(storage, "Component not found");
117 return storage->components.at(entity_id.Index());
118 }
119
120 template <typename T>
121 const SparseSet<T>& GetComponentSet() const
122 {
123 const auto type_id = std::type_index(typeid(T));
124 auto it = component_storage_.find(type_id);
125 if (it != component_storage_.end())
126 {
127 const auto* storage = static_cast<const ComponentStorage<T>*>(it->second.get());
128 return storage->components;
129 }
130 throw std::runtime_error("Component not found");
131 }
132
133 template <typename T, typename Func>
134 void Each(Func&& func)
135 {
136 auto* storage = TryGetComponentStorage<T>();
137 if (!storage)
138 {
139 return;
140 }
141
142 for (const auto& entry : storage->components)
143 {
144 if (entry.id >= entities_.size())
145 {
146 continue;
147 }
148
149 const EntityId entity = entities_[entry.id];
150 if (!entity)
151 {
152 continue;
153 }
154
155 func(entity, storage->components.at(entry.id));
156 }
157 }
158
159 template <typename T, typename Func>
160 void Each(Func&& func) const
161 {
162 const auto* storage = TryGetComponentStorage<T>();
163 if (!storage)
164 {
165 return;
166 }
167
168 for (const auto& entry : storage->components)
169 {
170 if (entry.id >= entities_.size())
171 {
172 continue;
173 }
174
175 const EntityId entity = entities_[entry.id];
176 if (!entity)
177 {
178 continue;
179 }
180
181 func(entity, storage->components.at(entry.id));
182 }
183 }
184
185 SceneEnvironmentSettings& GetEnvironmentSettings() noexcept
186 {
187 return environment_settings_;
188 }
189
190 const SceneEnvironmentSettings& GetEnvironmentSettings() const noexcept
191 {
192 return environment_settings_;
193 }
194
195 void SetEnvironmentSettings(SceneEnvironmentSettings settings) noexcept
196 {
197 environment_settings_ = std::move(settings);
198 ++mutation_generation_;
199 }
200
201 [[nodiscard]] uint64_t GetMutationGeneration() const noexcept
202 {
203 return mutation_generation_;
204 }
205
206 template <typename T, typename U, typename Func>
207 void Each(Func&& func)
208 {
209 auto* primary = TryGetComponentStorage<T>();
210 auto* secondary = TryGetComponentStorage<U>();
211 if (!primary || !secondary)
212 {
213 return;
214 }
215
216 if (secondary->components.size() < primary->components.size())
217 {
218 for (const auto& entry : secondary->components)
219 {
220 if (entry.id >= entities_.size())
221 {
222 continue;
223 }
224
225 const EntityId entity = entities_[entry.id];
226 if (!entity || !primary->components.contains(entry.id))
227 {
228 continue;
229 }
230
231 func(entity, primary->components.at(entry.id), secondary->components.at(entry.id));
232 }
233 return;
234 }
235
236 for (const auto& entry : primary->components)
237 {
238 if (entry.id >= entities_.size())
239 {
240 continue;
241 }
242
243 const EntityId entity = entities_[entry.id];
244 if (!entity || !secondary->components.contains(entry.id))
245 {
246 continue;
247 }
248
249 func(entity, primary->components.at(entry.id), secondary->components.at(entry.id));
250 }
251 }
252
253 template <typename T, typename U, typename Func>
254 void Each(Func&& func) const
255 {
256 const auto* primary = TryGetComponentStorage<T>();
257 const auto* secondary = TryGetComponentStorage<U>();
258 if (!primary || !secondary)
259 {
260 return;
261 }
262
263 if (secondary->components.size() < primary->components.size())
264 {
265 for (const auto& entry : secondary->components)
266 {
267 if (entry.id >= entities_.size())
268 {
269 continue;
270 }
271
272 const EntityId entity = entities_[entry.id];
273 if (!entity || !primary->components.contains(entry.id))
274 {
275 continue;
276 }
277
278 func(entity, primary->components.at(entry.id), secondary->components.at(entry.id));
279 }
280 return;
281 }
282
283 for (const auto& entry : primary->components)
284 {
285 if (entry.id >= entities_.size())
286 {
287 continue;
288 }
289
290 const EntityId entity = entities_[entry.id];
291 if (!entity || !secondary->components.contains(entry.id))
292 {
293 continue;
294 }
295
296 func(entity, primary->components.at(entry.id), secondary->components.at(entry.id));
297 }
298 }
299
300 friend Node& operator<<(Node& node, const Scene& scene);
301 friend const Node& operator>>(const Node& node, Scene& scene);
302 friend class SceneSerializer;
303
304private:
305 using ComponentTypeId = std::type_index;
306 using ComponentStorageFactory = std::function<std::unique_ptr<ComponentStorageBase>()>;
307
308 struct ComponentRegistration
309 {
310 std::string name;
311 ComponentStorageFactory factory;
312 };
313
314 void ClearSceneState();
315 void RegisterComponentType(ComponentTypeId type_id, std::string serialization_name, ComponentStorageFactory factory);
316 ComponentStorageBase* FindOrCreateStorage(ComponentTypeId type_id, std::string_view serialization_name);
317 [[nodiscard]] const ComponentRegistration* FindComponentRegistration(ComponentTypeId type_id) const;
318
319private:
320 std::vector<EntityId> entities_;
321 std::vector<uint8_t> entity_versions_;
322 std::vector<uint32_t> free_entities_;
323 std::unordered_map<ComponentTypeId, std::unique_ptr<ComponentStorageBase>> component_storage_;
324 std::unordered_map<ComponentTypeId, ComponentRegistration> component_registrations_;
325 std::unordered_map<std::string, ComponentTypeId> component_types_by_name_;
326 std::unordered_map<std::string, ComponentStorageFactory> component_storage_factories_by_name_;
327 SceneEnvironmentSettings environment_settings_;
328 uint64_t mutation_generation_ = 1;
329
330private:
331 template <typename T>
332 ComponentStorage<T>* GetOrCreateComponentStorage()
333 {
334 const auto type_id = std::type_index(typeid(T));
335 auto it = component_storage_.find(type_id);
336 if (it != component_storage_.end())
337 {
338 return static_cast<ComponentStorage<T>*>(it->second.get());
339 }
340 else
341 {
342 auto storage = std::make_unique<ComponentStorage<T>>();
343 ComponentStorage<T>* ptr = storage.get();
344 component_storage_[type_id] = std::move(storage);
345 return ptr;
346 }
347 }
348
349 template <typename T>
350 ComponentStorage<T>* TryGetComponentStorage()
351 {
352 const auto type_id = std::type_index(typeid(T));
353 auto it = component_storage_.find(type_id);
354 if (it == component_storage_.end())
355 {
356 return nullptr;
357 }
358 return static_cast<ComponentStorage<T>*>(it->second.get());
359 }
360
361 template <typename T>
362 const ComponentStorage<T>* TryGetComponentStorage() const
363 {
364 const auto type_id = std::type_index(typeid(T));
365 auto it = component_storage_.find(type_id);
366 if (it == component_storage_.end())
367 {
368 return nullptr;
369 }
370 return static_cast<const ComponentStorage<T>*>(it->second.get());
371 }
372};
373
374void RegisterEngineSceneComponents(Scene& scene);
375
376} // namespace pixelbullet
Provides assertion and panic mechanisms with optional custom formatting.
#define ASSERT(condition,...)
Asserts that a condition is true.
Definition assert.h:142
Definition entity_id.h:11
Represents a hierarchical node capable of storing various data types and supporting YAML serializatio...
Definition node.h:49
Definition scene.h:30
Definition sparse_set.h:16
Definition component_storage.h:15
Definition component_storage.h:25
Definition scene_environment_settings.h:13