Brenta Engine 1.0
Loading...
Searching...
No Matches
world.hpp
1/*
2 * MIT License
3 *
4 * Copyright (c) 2024 Giovanni Santini
5
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 all
15 * copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 *
25 */
26
27#pragma once
28
29#include "ecs.hpp"
30#include "ecs_types.hpp"
31#include "engine_logger.hpp"
32
33#include <algorithm>
34#include <memory>
35#include <set>
36#include <typeindex>
37#include <typeinfo>
38#include <unordered_map>
39#include <vector>
40
41namespace Brenta
42{
43
44namespace ECS
45{
46
47using namespace Types;
48using namespace Brenta::Utils;
49
57class World
58{
59 public:
60 World() = delete;
61
68 static void Init();
75 static void Delete();
81 static void Tick();
82
87 static std::set<Entity> *getEntities();
92 static UMap<std::type_index, Resource> *getResources();
97 static UMapVec<std::type_index, Component> *getComponents();
98
103 static Entity NewEntity();
104
119 template <typename R> static R *GetResource()
120 {
121 if (!resources)
122 {
123 ERROR("Cannot get resource: world not initialized");
124 return nullptr;
125 }
126
127 if (!resources->count(std::type_index(typeid(R))))
128 {
129 ERROR("Resource not found: ", std::type_index(typeid(R)).name());
130 return nullptr;
131 }
132
133 auto ret = resources->at(std::type_index(typeid(R)));
134 if (ret)
135 return static_cast<R *>(ret.get());
136 return nullptr;
137 }
138
154 template <typename C>
155 static void AddComponent(Entity entity, C new_component)
156 {
157 if (!components)
158 {
159 ERROR("Cannot add component: world not initialized");
160 return;
161 }
162
163 auto component = std::make_shared<C>(new_component);
164
165 component->entity = entity;
166
167 if (!components->count(std::type_index(typeid(C))))
168 {
169 components->insert({std::type_index(typeid(C)), {component}});
170 }
171 else
172 {
173 components->at(std::type_index(typeid(C))).push_back(component);
174 }
175
176 INFO("Added component: ", std::type_index(typeid(C)).name());
177 }
178
189 template <typename R> static void AddResource(R resource)
190 {
191 if (!resources)
192 {
193 ERROR("Cannot add resource: world not initialized");
194 return;
195 }
196
197 resources->insert(
198 {std::type_index(typeid(R)), std::make_shared<R>(resource)});
199 INFO("Added Resource: ", std::type_index(typeid(R)).name());
200 }
201
215 static void RemoveEntity(Entity entity);
216
229 template <typename R> static void RemoveResource()
230 {
231 if (!resources)
232 {
233 ERROR("Cannot remove resource: world not initialized");
234 return;
235 }
236
237 if (!resources->count(std::type_index(typeid(R))))
238 {
239 ERROR("Resource not found: ", std::type_index(typeid(R)).name());
240 return;
241 }
242
243 resources->erase(std::type_index(typeid(R)));
244 }
245
262 template <typename C> static C *EntityToComponent(Entity entity)
263 {
264 if (!components)
265 {
266 ERROR("Cannot get component: world not initialized");
267 return nullptr;
268 }
269
270 if (!components->count(std::type_index(typeid(C))))
271 {
272 ERROR("Component not found: ", std::type_index(typeid(C)).name());
273 return nullptr;
274 }
275
276 for (auto component : components->at(std::type_index(typeid(C))))
277 {
278 if (component->entity == entity)
279 {
280 return static_cast<C *>(component.get());
281 }
282 }
283
284 return nullptr;
285 }
286
292 static void RunSystems();
293
294 private:
295 static SetPtr<Entity> entities;
296 static UMapPtr<std::type_index, Resource> resources;
297 static UMapVecPtr<std::type_index, Component> components;
298
299 /* Iterate over all systems and run them */
300 template <typename Tuple, std::size_t... Is>
301 static void for_each_impl(Tuple &&tuple, std::index_sequence<Is...>)
302 {
303 (..., process(std::get<Is>(std::forward<Tuple>(tuple))));
304 }
305 template <typename Tuple> static void for_each(Tuple &&tuple)
306 {
307 for_each_impl(std::forward<Tuple>(tuple),
308 std::make_index_sequence<
309 std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
310 }
311 template <typename... T>
312 static std::vector<ECS::Entity> QueryComponentsTuple(std::tuple<T...>)
313 {
314 return QueryComponents<T...>();
315 }
316 template <typename System> static void process(const System &system)
317 {
318 using Dependencies = typename System::dependencies;
319 std::vector<ECS::Entity> matches = QueryComponentsTuple(Dependencies{});
320 system.run(matches);
321 }
322
323 template <typename C, typename... Components, typename N = None>
324 static std::vector<Entity> QueryComponents()
325 {
326 if (!World::components)
327 {
328 ERROR("Cannot query: world not initialized");
329 return {};
330 }
331
332 std::vector<Entity> matched;
333
334 if (!components->count(std::type_index(typeid(C))))
335 {
336 return matched;
337 }
338
339 for (auto component : components->at(std::type_index(typeid(C))))
340 {
341 matched.push_back(component->entity);
342 }
343
344 if (matched.empty())
345 return matched;
346 if (sizeof...(Components) == 0)
347 return matched;
348
349 QueryComponentsRec<Components..., None>(&matched);
350
351 return matched;
352 }
353
354 template <typename C, typename... Components>
355 static void QueryComponentsRec(std::vector<Entity> *entities)
356 {
357 if (entities->empty())
358 return;
359 std::vector<Entity> matched;
360
361 if (!components->count(std::type_index(typeid(C))))
362 {
363 *entities = matched;
364 return;
365 }
366 for (auto component : components->at(std::type_index(typeid(C))))
367 {
368 if (std::find(entities->begin(), entities->end(),
369 (int &) component->entity)
370 != entities->end())
371 {
372 matched.push_back(component->entity);
373 }
374 }
375 *entities = matched;
376
377 if (sizeof...(Components) == 0)
378 return;
379
380 (QueryComponentsRec<Components>(entities), ...);
381 }
382};
383
384} // namespace ECS
385
386} // namespace Brenta
World class.
Definition world.hpp:58
static UMap< std::type_index, Resource > * getResources()
Get the resources container.
Definition world.cpp:101
static void RemoveEntity(Entity entity)
Remove an entity.
Definition world.cpp:121
static C * EntityToComponent(Entity entity)
Get the component of an entity.
Definition world.hpp:262
static void Tick()
Tick the world.
Definition world.cpp:64
static R * GetResource()
Get a pointer to a resource.
Definition world.hpp:119
static UMapVec< std::type_index, Component > * getComponents()
Get the components container.
Definition world.cpp:111
static void AddResource(R resource)
Add a resource to the world.
Definition world.hpp:189
static void AddComponent(Entity entity, C new_component)
Add a component to an entity.
Definition world.hpp:155
static std::set< Entity > * getEntities()
Get the entities container.
Definition world.cpp:91
static void Init()
Initialize the world.
Definition world.cpp:45
static void RemoveResource()
Remove a resource.
Definition world.hpp:229
static void RunSystems()
Run all systems.
static Entity NewEntity()
Create a new entity.
Definition world.cpp:69
static void Delete()
Delete the world.
Definition world.cpp:55