viotecs 1.1.0
Loading...
Searching...
No Matches
world.hpp
Go to the documentation of this file.
1// SPDX-License-Identifier: MIT
2// Author: Giovanni Santini
3// Mail: giovanni.santini@proton.me
4// Github: @San7o
5
6#pragma once
7
9#include <viotecs/types.hpp>
10#include <viotecs/resource.hpp>
11#include <viotecs/system.hpp>
12
13#include <oak/oak.hpp>
14
15#include <algorithm>
16#include <memory>
17#include <set>
18#include <typeindex>
19#include <typeinfo>
20#include <unordered_map>
21#include <vector>
22
23namespace viotecs
24{
25
26class Entity
27{
28public:
29
30 Entity() = delete;
31 Entity(EntityId e) : _id(e) {}
32 ~Entity() = default;
33
34 class Builder;
35
37
38 template<typename C, typename... Args>
39 Entity &add_component(Args&&... args);
40
41 template <typename C>
42 C *get_component();
43
44 void remove();
45
46private:
47 EntityId _id;
48
49};
50
51using TypeId = const void *;
52
57template <typename T> inline constexpr TypeId type_id = &type_id<T>;
58
66class World
67{
68public:
69 World() = delete;
70
77 static void init();
84 static void destroy();
90 static void tick();
91
96 static std::set<EntityId> *get_entities();
107
113
128 template <typename R> static R *get_resource()
129 {
130 if (!resources)
131 {
132 return nullptr;
133 }
134
135 if (!resources->count(type_id<R>))
136 {
137 return nullptr;
138 }
139
140 auto ret = resources->at(type_id<R>);
141 if (ret)
142 return static_cast<R *>(ret.get());
143 return nullptr;
144 }
145
161 template <typename C, typename... Args>
162 static void add_component(EntityId e, Args&&... args)
163 {
164 if (!components)
165 {
166 return;
167 }
168
169 auto component = std::make_shared<C>(C(std::forward<Args>(args)...));
170
171 component->entity = e;
172
173 if (!components->count(type_id<C>))
174 {
175 components->insert({type_id<C>, {component}});
176 }
177 else
178 {
179 components->at(type_id<C>).push_back(component);
180 }
181
182 OAK_DEBUG("ecs: added component with id: {}", type_id<C>);
183 }
184
195 template <typename R> static void add_resource(R resource)
196 {
197 if (!resources)
198 {
199 return;
200 }
201
202 resources->insert({type_id<R>, std::make_shared<R>(resource)});
203 OAK_DEBUG("ecs: added Resource with type_id: {}", type_id<R>);
204 }
205
220
233 template <typename R> static void remove_resource()
234 {
235 if (!resources)
236 {
237 return;
238 }
239
240 if (!resources->count(type_id<R>))
241 {
242 return;
243 }
244
245 resources->erase(type_id<R>);
246 }
247
264 template <typename C> static C *entity_to_component(EntityId e)
265 {
266 if (!components)
267 {
268 return nullptr;
269 }
270
271 if (!components->count(type_id<C>))
272 {
273 return nullptr;
274 }
275
276 for (auto component : components->at(type_id<C>))
277 {
278 if (component->entity == e)
279 {
280 return static_cast<C *>(component.get());
281 }
282 }
283
284 return nullptr;
285 }
286
292 static std::function<void()> run_systems;
293
294 template<typename... S>
295 static void register_systems()
296 {
297 run_systems = []() {
298 using List = typename RegisteredSystems<S...>::Systems;
299 for_each(List{});
300 };
301 }
302
303private:
304 static SetPtr<EntityId> entities;
305 static UMapPtr<TypeId, Resource> resources;
306 static UMapVecPtr<TypeId, Component> components;
307
308 // Iterate over all systems and run them
309 template <typename Tuple, std::size_t... Is>
310 static void for_each_impl(Tuple &&tuple, std::index_sequence<Is...>)
311 {
312 (..., process(std::get<Is>(std::forward<Tuple>(tuple))));
313 }
314 template <typename Tuple> static void for_each(Tuple &&tuple)
315 {
316 for_each_impl(std::forward<Tuple>(tuple),
317 std::make_index_sequence<
318 std::tuple_size_v<std::remove_reference_t<Tuple>>>{});
319 }
320 template <typename... T>
321 static std::vector<EntityId> query_components_tuple(std::tuple<T...>)
322 {
323 return query_components<T...>();
324 }
325 template <typename System> static void process(const System &system)
326 {
327 using Dependencies = typename System::Dependencies;
328 std::vector<EntityId> matches =
329 query_components_tuple(Dependencies{});
330 system.run(matches);
331 }
332
333 template <typename C, typename... Components, typename N = None>
334 static std::vector<EntityId> query_components()
335 {
336 if (!World::components)
337 {
338 return {};
339 }
340
341 std::vector<EntityId> matched;
342
343 if (components->count(type_id<C>) == 0)
344 {
345 return matched;
346 }
347
348 for (auto component : components->at(type_id<C>))
349 {
350 matched.push_back(component->entity);
351 }
352
353 if (matched.empty())
354 return matched;
355 if (sizeof...(Components) == 0)
356 return matched;
357
358 query_components_rec<Components..., None>(&matched);
359
360 return matched;
361 }
362
363 template <typename C, typename... Components>
364 static void query_components_rec(std::vector<EntityId> *entities)
365 {
366 if (entities->empty())
367 return;
368 std::vector<EntityId> matched;
369
370 if (components->count(type_id<C>) == 0)
371 {
372 return;
373 }
374 for (auto component : components->at(type_id<C>))
375 {
376 if (std::find(entities->begin(), entities->end(),
377 (int &) component->entity)
378 != entities->end())
379 {
380 matched.push_back(component->entity);
381 }
382 }
383 *entities = matched;
384
385 if (sizeof...(Components) == 0)
386 return;
387
388 (query_components_rec<Components>(entities), ...);
389 }
390};
391
392template<typename C, typename... Args>
394 World::add_component<C>(this->id(), std::forward<Args>(args)...);
395 return *this;
396}
397
398template <typename C>
400{
401 return World::entity_to_component<C>(this->id());
402}
403
404
405} // namespace viotecs
~Entity()=default
C * get_component()
Definition world.hpp:399
Entity(EntityId e)
Definition world.hpp:31
Entity & add_component(Args &&... args)
Definition world.hpp:393
EntityId id()
Registered Systems Type.
Definition system.hpp:53
std::tuple< T... > Dependencies
Definition system.hpp:40
World class.
Definition world.hpp:67
static void init()
Initialize the world.
static UMapVec< TypeId, Component > * get_components()
Get the components container.
static void tick()
Tick the world.
static std::function< void()> run_systems
Run all systems.
Definition world.hpp:292
World()=delete
static Entity new_entity()
Create a new entity.
static void register_systems()
Definition world.hpp:295
static void add_component(EntityId e, Args &&... args)
Add a component to an entity.
Definition world.hpp:162
static void remove_entity(EntityId e)
Remove an entity.
static void destroy()
Delete the world.
static void add_resource(R resource)
Add a resource to the world.
Definition world.hpp:195
static R * get_resource()
Get a pointer to a resource.
Definition world.hpp:128
static C * entity_to_component(EntityId e)
Get the component of an entity.
Definition world.hpp:264
static UMap< TypeId, Resource > * get_resources()
Get the resources container.
static void remove_resource()
Remove a resource.
Definition world.hpp:233
static std::set< EntityId > * get_entities()
Get the entities container.
std::unique_ptr< UMap< T, G > > UMapPtr
Definition types.hpp:34
const void * TypeId
Definition world.hpp:51
int EntityId
Definition types.hpp:41
std::unordered_map< T, SPtr< G > > UMap
Definition types.hpp:29
std::unique_ptr< std::set< T > > SetPtr
Definition types.hpp:27
std::unordered_map< T, std::vector< SPtr< G > > > UMapVec
Definition types.hpp:32
std::unique_ptr< UMapVec< T, G > > UMapVecPtr
Definition types.hpp:37
constexpr TypeId type_id
Definition world.hpp:57