-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #18 from MasterLaplace/51-implement-ecs-in-flakkar…
…i-server 51 implement ecs in flakkari server
- Loading branch information
Showing
5 changed files
with
508 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/************************************************************************** | ||
* Flakkari Library v0.1.0 | ||
* | ||
* Flakkari Library is a C++ Library for Network. | ||
* @file Entity.hpp | ||
* @brief Entity class for ECS (Entity Component System). | ||
* | ||
* Flakkari Library is under MIT License. | ||
* https://opensource.org/licenses/MIT | ||
* © 2023 @MasterLaplace | ||
* @version 0.1.0 | ||
* @date 2023-01-05 | ||
**************************************************************************/ | ||
|
||
|
||
#ifndef ENTITY_HPP_ | ||
#define ENTITY_HPP_ | ||
|
||
#include <cstddef> | ||
|
||
namespace Flakkari::Engine::ECS { | ||
|
||
class Registry; | ||
|
||
class Entity { | ||
public: | ||
friend class Registry; | ||
|
||
explicit Entity(std::size_t id) : _id(id) {} | ||
Entity() : _id(0) {} | ||
|
||
operator std::size_t() const { return _id;} | ||
|
||
std::size_t operator++() { return ++_id; } | ||
Entity &operator=(std::size_t id) { _id = id; return *this; } | ||
Entity &operator=(int id) { _id = (id < 0) ? 0 : id; return *this; } | ||
|
||
private: | ||
std::size_t _id; | ||
}; | ||
|
||
} // namespace Flakkari::Engine::ECS | ||
|
||
#endif /* !ENTITY_HPP_ */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* | ||
** EPITECH PROJECT, 2024 | ||
** Title: Flakkari | ||
** Author: MasterLaplace | ||
** Created: 2023-01-05 | ||
** File description: | ||
** Registry | ||
*/ | ||
|
||
#include "Registry.hpp" | ||
|
||
namespace Flakkari::Engine::ECS { | ||
|
||
using entity_type = Registry::entity_type; | ||
|
||
entity_type Registry::spawn_entity() | ||
{ | ||
if (!_deadEntities.empty()) { | ||
entity_type e = _deadEntities.front(); | ||
_deadEntities.pop(); | ||
return e; | ||
} | ||
if (_nextEntity < SIZE_MAX) | ||
return Entity(_nextEntity++); | ||
throw std::runtime_error("No more available entities to spawn."); | ||
} | ||
|
||
entity_type Registry::entity_from_index(std::size_t idx) { | ||
return Entity(idx); | ||
} | ||
|
||
void Registry::kill_entity(const entity_type &e) | ||
{ | ||
for (auto &pair : _eraseFunctions) | ||
pair.second(*this, e); | ||
|
||
_deadEntities.push(e); | ||
} | ||
|
||
void Registry::run_systems() | ||
{ | ||
for (auto &system : _systems) | ||
system(*this); | ||
} | ||
|
||
} // namespace Flakkari::Engine::ECS |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,217 @@ | ||
/************************************************************************** | ||
* Flakkari Library v0.1.0 | ||
* | ||
* Flakkari Library is a C++ Library for Network. | ||
* @file Registry.hpp | ||
* @brief Registry class for ECS (Entity Component System). | ||
* | ||
* Flakkari Library is under MIT License. | ||
* https://opensource.org/licenses/MIT | ||
* © 2023 @MasterLaplace | ||
* @version 0.1.0 | ||
* @date 2023-01-05 | ||
**************************************************************************/ | ||
|
||
|
||
#ifndef REGISTRY_HPP_ | ||
#define REGISTRY_HPP_ | ||
|
||
#include "SparseArrays.hpp" | ||
#include "Entity.hpp" | ||
|
||
#include <unordered_map> | ||
#include <typeindex> | ||
#include <any> | ||
#include <functional> | ||
#include <queue> | ||
#include <stdexcept> | ||
#include <climits> | ||
#include <iostream> | ||
|
||
namespace Flakkari::Engine::ECS { | ||
|
||
class Registry { | ||
public: | ||
using entity_type = Entity; | ||
using EraseFn = std::function<void(Registry&, const entity_type&)>; | ||
using SystemFn = std::function<void(Registry&)>; | ||
|
||
/** | ||
* @brief Spawn a new entity in the registry. | ||
* | ||
* @return entity_type The entity created. | ||
*/ | ||
entity_type spawn_entity(); | ||
|
||
/** | ||
* @brief Get the entity from index object from the registry. | ||
* | ||
* @param idx The index of the entity. | ||
* @return entity_type The entity. | ||
*/ | ||
entity_type entity_from_index(std::size_t idx); | ||
|
||
/** | ||
* @brief Kill an entity from the registry. | ||
* | ||
* @param e The entity to kill. | ||
*/ | ||
void kill_entity(const entity_type &e); | ||
|
||
/** | ||
* @brief Check if an entity is registered in the registry. | ||
* | ||
* @tparam Component The component to check. | ||
* @param entity The entity to check. | ||
* @return true If the entity is registered. | ||
* @return false If the entity is not registered. | ||
*/ | ||
template <typename Component> | ||
[[nodiscard]] bool isRegistered(entity_type const &entity) | ||
{ | ||
auto componentIt = _components.find(std::type_index(typeid(Component))); | ||
|
||
if (componentIt != _components.end()) { | ||
auto &component = std::any_cast<SparseArrays<Component>&>(componentIt->second); | ||
if (entity < component.size()) | ||
return component[entity].has_value(); | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* @brief Check if a component is registered in the registry. | ||
* | ||
* @tparam Component The component to check. | ||
* @return true If the component is registered. | ||
* @return false If the component is not registered. | ||
*/ | ||
template <typename Component> | ||
[[nodiscard]] bool isRegistered() | ||
{ | ||
auto componentIt = _components.find(std::type_index(typeid(Component))); | ||
|
||
if (componentIt != _components.end()) { | ||
auto &component = std::any_cast<SparseArrays<Component>&>(componentIt->second); | ||
return component.size() > 0; | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* @brief Get the component from an entity. | ||
* | ||
* @tparam Component The component to get. | ||
* @param to The entity to get the component from. | ||
* @param c The component to get. | ||
* @return SparseArrays<Component>::reference_type The component. | ||
*/ | ||
template <typename Component> | ||
typename SparseArrays<Component>::reference_type add_component(const entity_type &to, Component &&c) { | ||
return getComponents<Component>().insert_at(to, std::forward<Component>(c)); | ||
} | ||
|
||
/** | ||
* @brief Get the component from an entity. | ||
* | ||
* @tparam Component The component to get. | ||
* @tparam Params The parameters to construct the component. | ||
* @param to The entity to get the component from. | ||
* @param p The parameters to construct the component. | ||
* @return SparseArrays<Component>::reference_type The component. | ||
*/ | ||
template <typename Component, typename... Params> | ||
typename SparseArrays<Component>::reference_type emplace_component(const entity_type &to, Params&&... p) { | ||
return getComponents<Component>().emplace_at(to, std::forward<Params>(p)...); | ||
} | ||
|
||
/** | ||
* @brief Remove a component from an entity in the registry. | ||
* | ||
* @tparam Component The component to remove. | ||
* @param from The entity to remove the component from. | ||
*/ | ||
template <typename Component> | ||
void remove_component(const entity_type &from) { | ||
getComponents<Component>().erase(from); | ||
} | ||
|
||
/** | ||
* @brief Get the component from an entity. | ||
* | ||
* @tparam Component The component to get. | ||
* @return SparseArrays<Component>& The component. | ||
*/ | ||
template <typename Component> | ||
SparseArrays<Component> ®isterComponent() | ||
{ | ||
if (isRegistered<Component>()) | ||
return getComponents<Component>(); | ||
|
||
auto ti = std::type_index(typeid(Component)); | ||
_components[ti] = std::make_any<SparseArrays<Component>>(); | ||
_eraseFunctions[ti] = [](Registry &r, const entity_type &e) { | ||
r.remove_component<Component>(e); | ||
}; | ||
return std::any_cast<SparseArrays<Component>&>(_components[ti]); | ||
} | ||
|
||
/** | ||
* @brief Get the Components object from the registry. | ||
* | ||
* @tparam Component The component to get. | ||
* @return SparseArrays<Component>& The component array. | ||
*/ | ||
template <typename Component> | ||
SparseArrays<Component> &getComponents() | ||
{ | ||
if (!isRegistered<Component>()) | ||
return registerComponent<Component>(); | ||
|
||
auto ti = std::type_index(typeid(Component)); | ||
return std::any_cast<SparseArrays<Component>&>(_components[ti]); | ||
} | ||
|
||
/** | ||
* @brief Get the Components object from the registry. | ||
* | ||
* @tparam Component The component to get. | ||
* @return const SparseArrays<Component>& The component array. | ||
*/ | ||
template <typename Component> | ||
const SparseArrays<Component> &getComponents() const { | ||
auto ti = std::type_index(typeid(Component)); | ||
return std::any_cast<const SparseArrays<Component>&>(_components.at(ti)); | ||
} | ||
|
||
/** | ||
* @brief Add a system to the registry. | ||
* | ||
* @tparam Components The components to add to the system. | ||
* @tparam Function The function to add to the system. | ||
* @param f The function to add to the system. | ||
*/ | ||
template <typename... Components, typename Function> | ||
void add_system(Function &&f) { | ||
_systems.emplace_back([sys{std::forward<Function>(f)}](Registry &r) { | ||
sys(r, r.getComponents<Components>()...); | ||
}); | ||
} | ||
|
||
/** | ||
* @brief Run all the systems in the registry. | ||
* | ||
*/ | ||
void run_systems(); | ||
|
||
private: | ||
std::unordered_map<std::type_index, std::any> _components; | ||
std::unordered_map<std::type_index, EraseFn> _eraseFunctions; | ||
std::vector<SystemFn> _systems; | ||
std::queue<entity_type> _deadEntities; | ||
size_t _nextEntity = 0; | ||
}; | ||
|
||
} // namespace Flakkari::Engine::ECS | ||
|
||
#endif /* !REGISTRY_HPP_ */ |
Oops, something went wrong.