viotecs 1.0
Loading...
Searching...
No Matches
world.hpp
Go to the documentation of this file.
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 "viotecs/component.hpp"
30#include "viotecs/ecs_types.hpp"
31#include "viotecs/entity.hpp"
32#include "viotecs/resource.hpp"
33#include "viotecs/system.hpp"
34#include "viotecs/ecs_types.hpp"
35#include "oak/oak.hpp"
36
37#include <algorithm>
38#include <memory>
39#include <set>
40#include <typeindex>
41#include <typeinfo>
42#include <unordered_map>
43#include <vector>
44
45namespace viotecs
46{
47
48using namespace types;
49
57class world
58{
59 public:
60 world() = delete;
61
68 static void init();
75 static void destroy();
81 static void tick();
82
87 static std::set<entity_t> *get_entities();
98
104
119 template <typename R> static R *get_resource()
120 {
121 if (!resources)
122 {
123 OAK_ERROR("Cannot get resource: world not initialized");
124 return nullptr;
125 }
126
127 if (!resources->count(std::type_index(typeid(R))))
128 {
129 OAK_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 add_component(entity_t entity, C new_component)
156 {
157 if (!components)
158 {
159 OAK_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 OAK_INFO("Added component: {}", std::type_index(typeid(C)).name());
177 }
178
189 template <typename R> static void add_resource(R resource)
190 {
191 if (!resources)
192 {
193 OAK_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 OAK_INFO("Added Resource: {}", std::type_index(typeid(R)).name());
200 }
201
215 static void remove_entity(entity_t entity);
216
229 template <typename R> static void remove_resource()
230 {
231 if (!resources)
232 {
233 OAK_ERROR("Cannot remove resource: world not initialized");
234 return;
235 }
236
237 if (!resources->count(std::type_index(typeid(R))))
238 {
239 OAK_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 *entity_to_component(entity_t entity)
263 {
264 if (!components)
265 {
266 OAK_ERROR("Cannot get component: world not initialized");
267 return nullptr;
268 }
269
270 if (!components->count(std::type_index(typeid(C))))
271 {
272 OAK_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 run_systems();
293
294 private:
295 static SetPtr<viotecs::entity_t> entities;
296 static UMapPtr<std::type_index, resource> resources;
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<viotecs::entity_t> query_components_tuple(std::tuple<T...>)
313 {
314 return query_components<T...>();
315 }
316 template <typename System> static void process(const System &system)
317 {
318 using dependencies = typename System::dependencies;
319 std::vector<viotecs::entity_t> matches =
320 query_components_tuple(dependencies{});
321 system.run(matches);
322 }
323
324 template <typename C, typename... Components, typename N = none>
325 static std::vector<entity_t> query_components()
326 {
327 if (!world::components)
328 {
329 OAK_ERROR("Cannot query: world not initialized");
330 return {};
331 }
332
333 std::vector<entity_t> matched;
334
335 if (!components->count(std::type_index(typeid(C))))
336 {
337 return matched;
338 }
339
340 for (auto component : components->at(std::type_index(typeid(C))))
341 {
342 matched.push_back(component->entity);
343 }
344
345 if (matched.empty())
346 return matched;
347 if (sizeof...(Components) == 0)
348 return matched;
349
350 query_components_rec<Components..., none>(&matched);
351
352 return matched;
353 }
354
355 template <typename C, typename... Components>
356 static void query_components_rec(std::vector<entity_t> *entities)
357 {
358 if (entities->empty())
359 return;
360 std::vector<entity_t> matched;
361
362 if (!components->count(std::type_index(typeid(C))))
363 {
364 *entities = matched;
365 return;
366 }
367 for (auto component : components->at(std::type_index(typeid(C))))
368 {
369 if (std::find(entities->begin(), entities->end(),
370 (int &) component->entity)
371 != entities->end())
372 {
373 matched.push_back(component->entity);
374 }
375 }
376 *entities = matched;
377
378 if (sizeof...(Components) == 0)
379 return;
380
381 (query_components_rec<Components>(entities), ...);
382 }
383};
384
385} // namespace viotecs
World class.
Definition world.hpp:58
static void add_resource(R resource)
Add a resource to the world.
Definition world.hpp:189
static void run_systems()
Run all systems.
static void init()
Initialize the world.
world()=delete
static std::set< entity_t > * get_entities()
Get the entities container.
static void add_component(entity_t entity, C new_component)
Add a component to an entity.
Definition world.hpp:155
static void remove_entity(entity_t entity)
Remove an entity.
static void remove_resource()
Remove a resource.
Definition world.hpp:229
static C * entity_to_component(entity_t entity)
Get the component of an entity.
Definition world.hpp:262
static void destroy()
Delete the world.
static UMap< std::type_index, resource > * get_resources()
Get the resources container.
static entity_t new_entity()
Create a new entity.
static UMapVec< std::type_index, component > * get_components()
Get the components container.
static void tick()
Tick the world.
static R * get_resource()
Get a pointer to a resource.
Definition world.hpp:119
std::unique_ptr< std::set< T > > SetPtr
Definition ecs_types.hpp:51
std::unique_ptr< UMapVec< T, G > > UMapVecPtr
Definition ecs_types.hpp:61
std::unordered_map< T, std::vector< SPtr< G > > > UMapVec
Definition ecs_types.hpp:56
std::unordered_map< T, SPtr< G > > UMap
Definition ecs_types.hpp:53
std::unique_ptr< UMap< T, G > > UMapPtr
Definition ecs_types.hpp:58
int entity_t
Entity type.
Definition entity.hpp:37
Component class.
Definition component.hpp:58
Resource type.
Definition resource.hpp:54