From 11d1587de563684bd0e3046a7fd82999204282a9 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 10:23:53 +0100 Subject: [PATCH 01/14] fix(Client): Fix Client class destructor and isConnected method This commit fixes the destructor of the Client class and modifies the isConnected method to check the _isConnected flag before returning the result. --- Flakkari/Server/Client/Client.cpp | 13 +++++++++++-- Flakkari/Server/Client/Client.hpp | 3 ++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/Flakkari/Server/Client/Client.cpp b/Flakkari/Server/Client/Client.cpp index 0989df44..00d0b958 100644 --- a/Flakkari/Server/Client/Client.cpp +++ b/Flakkari/Server/Client/Client.cpp @@ -11,11 +11,20 @@ namespace Flakkari { -Client::Client(std::shared_ptr address) : _address(address) { +Client::Client(std::shared_ptr address) + : _address(address) +{ _lastActivity = std::chrono::steady_clock::now(); } -bool Client::isConnected(float timeout) { +Client::~Client() { + _isConnected = false; +} + +bool Client::isConnected(float timeout) +{ + if (!_isConnected) + return false; return std::chrono::duration_cast(std::chrono::steady_clock::now() - _lastActivity).count() < timeout; } diff --git a/Flakkari/Server/Client/Client.hpp b/Flakkari/Server/Client/Client.hpp index 1bb6635b..e85dcd64 100644 --- a/Flakkari/Server/Client/Client.hpp +++ b/Flakkari/Server/Client/Client.hpp @@ -42,7 +42,7 @@ class Client { * @param address The client's address */ Client(std::shared_ptr address); - ~Client() = default; + ~Client(); /** * @brief Check if the client is still connected to the server @@ -70,6 +70,7 @@ class Client { private: std::chrono::steady_clock::time_point _lastActivity; std::shared_ptr _address; + bool _isConnected = true; }; } /* namespace Flakkari */ From 0d22af7a11433338d05308e1318b5a27db645138 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 10:25:32 +0100 Subject: [PATCH 02/14] update(Client): Refactor ClientManager class --- Flakkari/Server/Client/ClientManager.cpp | 13 ++++++++++--- Flakkari/Server/Client/ClientManager.hpp | 13 ++++++++++--- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Flakkari/Server/Client/ClientManager.cpp b/Flakkari/Server/Client/ClientManager.cpp index bc2e1fe0..c7ee1ea5 100644 --- a/Flakkari/Server/Client/ClientManager.cpp +++ b/Flakkari/Server/Client/ClientManager.cpp @@ -11,9 +11,11 @@ namespace Flakkari { + std::shared_ptr ClientManager::_instance = nullptr; -std::shared_ptr ClientManager::getInstance() { +std::shared_ptr ClientManager::getInstance() +{ if (!_instance) _instance = std::make_shared(); return _instance; @@ -24,7 +26,7 @@ void ClientManager::addClient(std::shared_ptr client) auto &clients = getInstance()->_clients; if (clients.find(client->toString().value_or("")) == clients.end()) { clients[client->toString().value_or("")] = std::make_shared(client); - FLAKKARI_LOG_LOG("Client " + client->toString().value_or("") + " connected"); + FLAKKARI_LOG_LOG("Client " + client->toString().value_or("Unknown") + " connected"); } else clients[client->toString().value_or("")]->keepAlive(); } @@ -32,8 +34,9 @@ void ClientManager::addClient(std::shared_ptr client) void ClientManager::removeClient(std::shared_ptr client) { auto &clients = getInstance()->_clients; - if (clients.find(client->toString().value_or("")) != clients.end()) + if (clients.find(client->toString().value_or("")) != clients.end()) { clients.erase(client->toString().value_or("")); + } } void ClientManager::checkInactiveClients() @@ -49,6 +52,10 @@ void ClientManager::checkInactiveClients() } } +std::shared_ptr ClientManager::getClient(std::shared_ptr client) { + return getInstance()->_clients[client->toString().value_or("")]; +} + std::shared_ptr ClientManager::getClient(std::string ip) { return getInstance()->_clients[ip]; } diff --git a/Flakkari/Server/Client/ClientManager.hpp b/Flakkari/Server/Client/ClientManager.hpp index c6314d0e..79da092f 100644 --- a/Flakkari/Server/Client/ClientManager.hpp +++ b/Flakkari/Server/Client/ClientManager.hpp @@ -40,9 +40,8 @@ namespace Flakkari { * @code * #include "ClientManager.hpp" * - * Flakkari::ClientManager clientManager; - * clientManager.addClient(std::make_shared("...")>); - * clientManager.checkInactiveClients(); + * Flakkari::ClientManager::addClient(std::make_shared("...")>); + * Flakkari::ClientManager::checkInactiveClients(); * @endcode */ class ClientManager { @@ -102,6 +101,14 @@ class ClientManager { */ static void checkInactiveClients(); + /** + * @brief Get the Client object + * + * @param client The client's address + * @return std::shared_ptr The client object + */ + static std::shared_ptr getClient(std::shared_ptr client); + /** * @brief Get the Client object * From eb98dc9729329b9e045ef28c7b02c9240643ad71 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 10:32:37 +0100 Subject: [PATCH 03/14] feat(Game): Add Game class to Flakkari Server --- CMakeLists.txt | 23 +++++++ Flakkari/Server/Game/Game.cpp | 99 ++++++++++++++++++++++++++ Flakkari/Server/Game/Game.hpp | 126 ++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+) create mode 100644 Flakkari/Server/Game/Game.cpp create mode 100644 Flakkari/Server/Game/Game.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index ff896106..812b2572 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,10 +13,12 @@ set(SOURCES Flakkari/Network/IOMultiplexer.cpp Flakkari/Protocol/Header.cpp Flakkari/Protocol/Packet.cpp + Flakkari/Engine/Math/Vector.cpp Flakkari/Engine/EntityComponentSystem/Registry.cpp Flakkari/Server/UDPServer.cpp Flakkari/Server/Client/Client.cpp Flakkari/Server/Client/ClientManager.cpp + Flakkari/Server/Game/Game.cpp Flakkari/Server/Internals/CommandManager.cpp ) @@ -28,12 +30,14 @@ set(HEADERS Flakkari/Network/IOMultiplexer.hpp Flakkari/Protocol/Header.hpp Flakkari/Protocol/Packet.hpp + Flakkari/Engine/Math/Vector.hpp Flakkari/Engine/EntityComponentSystem/Entity.hpp Flakkari/Engine/EntityComponentSystem/SparseArrays.hpp Flakkari/Engine/EntityComponentSystem/Registry.hpp Flakkari/Server/UDPServer.hpp Flakkari/Server/Client/Client.hpp Flakkari/Server/Client/ClientManager.hpp + Flakkari/Server/Game/Game.hpp Flakkari/Server/Internals/CommandManager.hpp ) @@ -48,6 +52,17 @@ set(HEADER_LIB_NETWORK Flakkari/Network/IOMultiplexer.hpp ) +# CMake Modules: +INCLUDE(FetchContent) + +FetchContent_Declare( + nlohmann_json + GIT_REPOSITORY https://github.com/nlohmann/json.git + GIT_TAG v3.11.3 +) + +FetchContent_MakeAvailable(nlohmann_json) + # Separate Build Artifacts: set(CMAKE_BINARY_DIR ${CMAKE_SOURCE_DIR}/build) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_BINARY_DIR}) @@ -72,6 +87,9 @@ add_executable(r-type_server ${SOURCES} ${HEADERS}) # Include Directories: target_include_directories(r-type_server PRIVATE ${CMAKE_SOURCE_DIR}/Flakkari) +# Link Libraries: +target_link_libraries(r-type_server PRIVATE nlohmann_json::nlohmann_json) + # Documentation: sudo apt-get install graphviz find_package(Doxygen) if(DOXYGEN_FOUND) @@ -108,6 +126,7 @@ set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") set(CPACK_GENERATOR "DEB") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "R-Type Team") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "nlohmann-json3-dev (>= 3.9.1)" "doxygen (>= 1.8.17)" "graphviz (>= 2.40.1)") set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "amd64") include(CPack) @@ -124,6 +143,10 @@ add_library(r-type_server_network SHARED ${SOURCES_LIB_NETWORK} ${HEADER_LIB_NET # Include Directories: target_include_directories(r-type_server_network PRIVATE ${CMAKE_SOURCE_DIR}/Flakkari) + +# Link Libraries: +target_link_libraries(r-type_server_network PRIVATE nlohmann_json::nlohmann_json) + # Install dynamic library: install(TARGETS r-type_server_network DESTINATION lib) install(FILES ${HEADER_LIB_NETWORK} DESTINATION include/Flakkari/Network) diff --git a/Flakkari/Server/Game/Game.cpp b/Flakkari/Server/Game/Game.cpp new file mode 100644 index 00000000..654ec571 --- /dev/null +++ b/Flakkari/Server/Game/Game.cpp @@ -0,0 +1,99 @@ +/* +** EPITECH PROJECT, 2024 +** Title: Flakkari +** Author: MasterLaplace +** Created: 2023-01-06 +** File description: +** Game +*/ + +#include "Game.hpp" +#include "../Client/Client.hpp" + +namespace Flakkari { + +Game::Game(const std::string &name, std::shared_ptr config) +{ + _name = name; + _config = config; + _time = std::chrono::steady_clock::now(); + if ((*_config)["scenes"].empty()) + throw std::runtime_error("Game: no scenes found"); + loadScene((*_config)["startScene"]); +} + +Game::~Game() +{ + _running = false; + _thread.join(); + FLAKKARI_LOG_INFO("game \"" + _name + "\" is now stopped"); +} + +void Game::loadScene(const std::string &sceneName) +{ + for (auto &scene : (*_config)["scenes"].items()) { + for (auto sceneInfo : scene.value().items()) { + if (sceneInfo.key() != sceneName) + continue; + Engine::ECS::Registry registry; + _scenes[sceneName] = registry; + return; + } + } +} + +void Game::update() +{ + auto now = std::chrono::steady_clock::now(); + _deltaTime = std::chrono::duration_cast>(now - _time).count(); + _time = now; + + for (auto &scene : _scenes) + scene.second.run_systems(); +} + +void Game::start() +{ + _running = true; + _thread = std::thread(&Game::run, this); + FLAKKARI_LOG_INFO("game \"" + _name + "\" is now running"); +} + +void Game::run() +{ + while (_running) + update(); +} + +bool Game::addPlayer(std::shared_ptr player) +{ + if (std::find(_players.begin(), _players.end(), player) != _players.end()) + return false; + if (_players.size() >= (*_config)["maxPlayers"] || !player->isConnected()) + return false; + _players.push_back(player); + return true; +} + +bool Game::removePlayer(std::shared_ptr player) +{ + auto it = std::find(_players.begin(), _players.end(), player); + if (it == _players.end()) + return false; + _players.erase(it); + return true; +} + +bool Game::isRunning() const { + return _running; +} + +std::string Game::getName() const { + return _name; +} + +std::vector> Game::getPlayers() const { + return _players; +} + +} /* namespace Flakkari */ diff --git a/Flakkari/Server/Game/Game.hpp b/Flakkari/Server/Game/Game.hpp new file mode 100644 index 00000000..10caee4f --- /dev/null +++ b/Flakkari/Server/Game/Game.hpp @@ -0,0 +1,126 @@ +/************************************************************************** + * Flakkari Library v0.1.0 + * + * Flakkari Library is a C++ Library for Network. + * @file Game.hpp + * @brief Game class header. Can be used to create a game. + * A game is a collection of scenes. + * A scene is a collection of entities. + * An entity is a collection of components. + * A component is a collection of data. + * + * Flakkari Library is under MIT License. + * https://opensource.org/licenses/MIT + * © 2023 @MasterLaplace + * @version 0.1.0 + * @date 2023-01-06 + **************************************************************************/ + +#ifndef GAME_HPP_ + #define GAME_HPP_ + +#include +#include +#include +#include + +#include "Engine/EntityComponentSystem/Registry.hpp" + +namespace Flakkari { + + class Client; + +class Game { + public: + /** + * @brief Construct a new Game object and load the config file + * of the game. + * + * @param name Name of the game (name of the file in Games/ folder) + * @param config Config of the game (config of the file in Games/ folder) + */ + Game(const std::string &name, std::shared_ptr config); + ~Game(); + + /** + * @brief Load a scene from the game. + * + * @param name Name of the scene to load. + */ + void loadScene(const std::string &name); + + /** + * @brief Update the game. This function is called every frame. + * + */ + void update(); + + /** + * @brief Start the game. This function is called when the game is + * launched. It will start the game loop. + * + */ + void start(); + + /** + * @brief Run the game. This function is called when the game is + * started. It will run the game loop. + * + */ + void run(); + + /** + * @brief Add a player to the game instance. + * + * @param player Player to add to the game instance. + * @return true Player added successfully + * @return false Player not added + */ + [[nodiscard]] bool addPlayer(std::shared_ptr player); + + /** + * @brief Remove a player from the game instance. + * + * @param player Player to remove from the game instance. + * @return true Player removed successfully + * @return false Player not removed + */ + [[nodiscard]] bool removePlayer(std::shared_ptr player); + + /** + * @brief Get if the game is running. + * + * @return true Game is running + * @return false Game is not running + */ + [[nodiscard]] bool isRunning() const; + + /** + * @brief Get the Name object (name of the game). + * + * @return std::string Name of the game + */ + [[nodiscard]] std::string getName() const; + + /** + * @brief Get the Players object (players of the game). + * + * @return std::vector> Players of the game + */ + [[nodiscard]] std::vector> getPlayers() const; + + protected: + private: + bool _running = false; // Is the game running + std::thread _thread; // Thread of the game + std::string _name; // Name of the game + std::shared_ptr _config; // Config of the game + std::vector> _players; // Players of the game + float _deltaTime; // Time between two frames + std::chrono::steady_clock::time_point _time; // Time of the last frame + std::unordered_map _scenes; // Scenes of the game +}; + +} /* namespace Flakkari */ + +#endif /* !GAME_HPP_ */ From 2e87815f84815d1dff470375ed2fa73c688fb647 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 12:52:10 +0100 Subject: [PATCH 04/14] feat(2D): Add Movable component to 2D entity component system --- .../Components/2D/Movable.hpp | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Components/2D/Movable.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Components/2D/Movable.hpp b/Flakkari/Engine/EntityComponentSystem/Components/2D/Movable.hpp new file mode 100644 index 00000000..048e2760 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Components/2D/Movable.hpp @@ -0,0 +1,30 @@ +/* +** EPITECH PROJECT, 2024 +** Title: Flakkari +** Author: MasterLaplace +** Created: 2023-01-06 +** File description: +** Movable +*/ + +#ifndef MOVABLE_HPP_ +#define MOVABLE_HPP_ + +#include "../../../Math/Vector.hpp" + +namespace Flakkari::Engine::ECS::Components::_2D { + +struct Movable { + Math::Vector2d velocity; // pixels / second + double angularVelocity; // degrees / second + Math::Vector2d acceleration; // pixels / second^2 + double angularAcceleration; // degrees / second^2 + + Movable() : velocity(0, 0), acceleration(0, 0) {}; + Movable(const Math::Vector2d &velocity, const Math::Vector2d &acceleration) : velocity(velocity), acceleration(acceleration) {}; + Movable(const Movable &other) : velocity(other.velocity), acceleration(other.acceleration) {}; +}; + +} // namespace Game::ECS::Components::_2D + +#endif /* !MOVABLE_HPP_ */ From c28788ce1c4c0deda9688a0cb7d62ab8b021ddc3 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 12:56:18 +0100 Subject: [PATCH 05/14] feat(Components): Add Transform component to ECS --- .../Components/2D/Transform.hpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Components/2D/Transform.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Components/2D/Transform.hpp b/Flakkari/Engine/EntityComponentSystem/Components/2D/Transform.hpp new file mode 100644 index 00000000..165dc216 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Components/2D/Transform.hpp @@ -0,0 +1,29 @@ +/* +** EPITECH PROJECT, 2024 +** Title: Flakkari +** Author: MasterLaplace +** Created: 2023-01-06 +** File description: +** Transform +*/ + +#ifndef TRANSFORM_HPP_ +#define TRANSFORM_HPP_ + +#include "../../../Math/Vector.hpp" + +namespace Flakkari::Engine::ECS::Components::_2D { + +struct Transform { + Math::Vector2d position; + Math::Vector2d scale; + double rotation; + + Transform() : position(0, 0), scale(1, 1), rotation(0) {}; + Transform(const Math::Vector2d &position, const Math::Vector2d &scale, double rotation) : position(position), scale(scale), rotation(rotation) {}; + Transform(const Transform &other) : position(other.position), scale(other.scale), rotation(other.rotation) {}; +}; + +} // namespace Game::ECS::Components::_2D + +#endif /* !TRANSFORM_HPP_ */ From 01b67032e029e517af0b180f71f79ada399cc4a4 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 12:57:53 +0100 Subject: [PATCH 06/14] feat(Components): Add Components2D header file --- CMakeLists.txt | 1 + .../Components/Components2D.hpp | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Components/Components2D.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 812b2572..53fe6197 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ set(HEADERS Flakkari/Protocol/Header.hpp Flakkari/Protocol/Packet.hpp Flakkari/Engine/Math/Vector.hpp + Flakkari/Engine/EntityComponentSystem/Components/Components2D.hpp Flakkari/Engine/EntityComponentSystem/Entity.hpp Flakkari/Engine/EntityComponentSystem/SparseArrays.hpp Flakkari/Engine/EntityComponentSystem/Registry.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Components/Components2D.hpp b/Flakkari/Engine/EntityComponentSystem/Components/Components2D.hpp new file mode 100644 index 00000000..346df6df --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Components/Components2D.hpp @@ -0,0 +1,22 @@ +/************************************************************************** + * Flakkari Engine Library v0.1.0 + * + * Flakkari Library is a C++ Library for Network. + * @file Components2D.hpp + * @brief Components2D header. Contains all 2D components. + * (Collider, Movable, RigidBody, Transform) + * + * Flakkari Library is under MIT License. + * https://opensource.org/licenses/MIT + * © 2023 @MasterLaplace + * @version 0.1.0 + * @date 2023-01-06 + **************************************************************************/ + +#ifndef COMPONENTS2D_HPP_ +#define COMPONENTS2D_HPP_ + +#include "2D/Movable.hpp" // Movable component (velocity, angularVelocity, acceleration, angularAcceleration) +#include "2D/Transform.hpp" // Transform component (position, rotation, scale) + +#endif /* !COMPONENTS2D_HPP_ */ From 22116bb6af603fdb27c0bd5555c3546243c9aa36 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 12:58:48 +0100 Subject: [PATCH 07/14] feat(Common): Add Child component to ECS --- .../Components/Common/Child.hpp | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Components/Common/Child.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Components/Common/Child.hpp b/Flakkari/Engine/EntityComponentSystem/Components/Common/Child.hpp new file mode 100644 index 00000000..d7ddc6d6 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Components/Common/Child.hpp @@ -0,0 +1,33 @@ +/* +** EPITECH PROJECT, 2024 +** Title: Flakkari +** Author: MasterLaplace +** Created: 2023-01-06 +** File description: +** Child +*/ + +#ifndef CHILD_HPP_ +#define CHILD_HPP_ + +#include + +namespace Flakkari::Engine::ECS::Components::Common { + +/** + * @brief Child component for ECS entities that have a child entity attached to them + * + * @details This component is used to create a child entity based on a prefab + * and attach it to the entity that has this component + */ +struct Child { + std::string name; + + Child() : name("") {} + Child(const std::string &name) : name(name) {} + Child(const Child &other) : name(other.name) {} +}; + +} // namespace Flakkari::Engine::ECS::Components::Common + +#endif /* !CHILD_HPP_ */ From 9a402a70ad6798f4346284700b865147c6599cc8 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 12:59:14 +0100 Subject: [PATCH 08/14] feat(Common): Add Parent component to ECS --- .../Components/Common/Parent.hpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Components/Common/Parent.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Components/Common/Parent.hpp b/Flakkari/Engine/EntityComponentSystem/Components/Common/Parent.hpp new file mode 100644 index 00000000..0e15d141 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Components/Common/Parent.hpp @@ -0,0 +1,32 @@ +/* +** EPITECH PROJECT, 2024 +** Title: Flakkari +** Author: MasterLaplace +** Created: 2023-01-06 +** File description: +** Parent +*/ + +#ifndef PARENT_HPP_ +#define PARENT_HPP_ + +#include + +namespace Flakkari::Engine::ECS::Components::Common { + +/** + * @brief Parent component for ECS entities that have a parent entity attached to them + * + * @details This component is used to store the parent entity of an entity in the ECS + */ +struct Parent { + std::size_t entity; + + Parent() : entity(0) {} + Parent(const std::size_t &entity) : entity(entity) {} + Parent(const Parent &other) : entity(other.entity) {} +}; + +} // namespace Flakkari::Engine::ECS::Components::Common + +#endif /* !PARENT_HPP_ */ From f9405c9fa510b7cd1b18fdca5cf1888d08b3befd Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 13:00:30 +0100 Subject: [PATCH 09/14] feat(Common): Add Tag component to ECS --- .../Components/Common/Tag.hpp | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Components/Common/Tag.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Components/Common/Tag.hpp b/Flakkari/Engine/EntityComponentSystem/Components/Common/Tag.hpp new file mode 100644 index 00000000..35f66384 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Components/Common/Tag.hpp @@ -0,0 +1,32 @@ +/* +** EPITECH PROJECT, 2024 +** Title: Flakkari +** Author: MasterLaplace +** Created: 2023-01-06 +** File description: +** Tag +*/ + +#ifndef TAG_HPP_ +#define TAG_HPP_ + +#include + +namespace Flakkari::Engine::ECS::Components::Common { + +/** + * @brief Tag component for ECS entities that have a script attached to them + * + * @details This component is used to store the path to the script that will be executed + */ +struct Tag { + std::string tag; + + Tag() : tag("") {} + Tag(const std::string &tag) : tag(tag) {} + Tag(const Tag &other) : tag(other.tag) {} +}; + +} // namespace Game::ECS::Components::Common + +#endif /* !TAG_HPP_ */ From 1cd7e1454b3319b75b29d70e4ca25a144a01323e Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 13:05:00 +0100 Subject: [PATCH 10/14] feat(Components): Add ComponentsCommon.hpp for common components --- CMakeLists.txt | 1 + .../Components/ComponentsCommon.hpp | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Components/ComponentsCommon.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 53fe6197..e5da0ec7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ set(HEADERS Flakkari/Protocol/Packet.hpp Flakkari/Engine/Math/Vector.hpp Flakkari/Engine/EntityComponentSystem/Components/Components2D.hpp + Flakkari/Engine/EntityComponentSystem/Components/ComponentsCommon.hpp Flakkari/Engine/EntityComponentSystem/Entity.hpp Flakkari/Engine/EntityComponentSystem/SparseArrays.hpp Flakkari/Engine/EntityComponentSystem/Registry.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Components/ComponentsCommon.hpp b/Flakkari/Engine/EntityComponentSystem/Components/ComponentsCommon.hpp new file mode 100644 index 00000000..b81e1c62 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Components/ComponentsCommon.hpp @@ -0,0 +1,22 @@ +/************************************************************************** + * Flakkari Engine Library v0.1.0 + * + * Flakkari Library is a C++ Library for Network. + * @file ComponentsCommon.hpp + * @brief ComponentsCommon header. Contains all common components. + * (Parent, Tag) + * + * Flakkari Library is under MIT License. + * https://opensource.org/licenses/MIT + * © 2023 @MasterLaplace + * @version 0.1.0 + * @date 2023-01-06 + **************************************************************************/ + +#ifndef COMPONENTSCOMMON_HPP_ +#define COMPONENTSCOMMON_HPP_ + +#include "Common/Parent.hpp" // Parent component (entity) +#include "Common/Tag.hpp" // Tag component (tag) + +#endif /* !COMPONENTSCOMMON_HPP_ */ From 6cd04580ae7755cb9c6ab545e5ef0508e4b6f9be Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 13:06:11 +0100 Subject: [PATCH 11/14] feat(Systems): Add Systems.cpp and Systems.hpp to ECS Systems --- CMakeLists.txt | 2 + .../EntityComponentSystem/Systems/Systems.cpp | 34 ++++++++++++++++ .../EntityComponentSystem/Systems/Systems.hpp | 40 +++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 Flakkari/Engine/EntityComponentSystem/Systems/Systems.cpp create mode 100644 Flakkari/Engine/EntityComponentSystem/Systems/Systems.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e5da0ec7..129d93b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,7 @@ set(SOURCES Flakkari/Protocol/Header.cpp Flakkari/Protocol/Packet.cpp Flakkari/Engine/Math/Vector.cpp + Flakkari/Engine/EntityComponentSystem/Systems/Systems.cpp Flakkari/Engine/EntityComponentSystem/Registry.cpp Flakkari/Server/UDPServer.cpp Flakkari/Server/Client/Client.cpp @@ -33,6 +34,7 @@ set(HEADERS Flakkari/Engine/Math/Vector.hpp Flakkari/Engine/EntityComponentSystem/Components/Components2D.hpp Flakkari/Engine/EntityComponentSystem/Components/ComponentsCommon.hpp + Flakkari/Engine/EntityComponentSystem/Systems/Systems.hpp Flakkari/Engine/EntityComponentSystem/Entity.hpp Flakkari/Engine/EntityComponentSystem/SparseArrays.hpp Flakkari/Engine/EntityComponentSystem/Registry.hpp diff --git a/Flakkari/Engine/EntityComponentSystem/Systems/Systems.cpp b/Flakkari/Engine/EntityComponentSystem/Systems/Systems.cpp new file mode 100644 index 00000000..b760e848 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Systems/Systems.cpp @@ -0,0 +1,34 @@ +/* +** EPITECH PROJECT, 2024 +** Title: Flakkari +** Author: MasterLaplace +** Created: 2023-01-06 +** File description: +** Systems +*/ + +#include "Systems.hpp" + +namespace Flakkari::Engine::ECS::Systems { + +void position(Registry &r, float deltaTime) +{ + if (!r.isRegistered() || !r.isRegistered()) + return; + auto& positions = r.getComponents(); + auto& velocities = r.getComponents(); + + for (Entity i(0); i < positions.size() && i < velocities.size(); ++i) { + auto& pos = positions[i]; + auto& vel = velocities[i]; + + if (pos.has_value() && vel.has_value()) { + pos->position.x += vel->velocity.dx * deltaTime * 0.5f * vel->acceleration.x * deltaTime * deltaTime; + pos->position.y += vel->velocity.dy * deltaTime * 0.5f * vel->acceleration.y * deltaTime * deltaTime; + vel->velocity.dx += vel->acceleration.x * deltaTime; + vel->velocity.dy += vel->acceleration.y * deltaTime; + } + } +} + +} // namespace Flakkari::Engine::ECS::Systems diff --git a/Flakkari/Engine/EntityComponentSystem/Systems/Systems.hpp b/Flakkari/Engine/EntityComponentSystem/Systems/Systems.hpp new file mode 100644 index 00000000..00394084 --- /dev/null +++ b/Flakkari/Engine/EntityComponentSystem/Systems/Systems.hpp @@ -0,0 +1,40 @@ +/************************************************************************** + * Flakkari Engine Library v0.1.0 + * + * Flakkari Library is a C++ Library for Network. + * @file Systems.hpp + * @brief Systems header. Contains all systems. + * (position, rigid_body) + * + * Flakkari Library is under MIT License. + * https://opensource.org/licenses/MIT + * © 2023 @MasterLaplace + * @version 0.1.0 + * @date 2023-01-06 + **************************************************************************/ + +#ifndef SYSTEMS_HPP_ +#define SYSTEMS_HPP_ + +#include "../Registry.hpp" +#include "../Components/Components2D.hpp" +#include "../Components/ComponentsCommon.hpp" + +#include +#include + +namespace Flakkari::Engine::ECS::Systems { + +/** + * @brief Updates the position of all entities with a Position and a Movable component based on their velocity. + * + * @note The velocity vector is normalized following this advice: https://youtube.com/shorts/0cYjreg7dpg + * + * @param r The registry containing the entities to update. + * @param deltaTime The time elapsed since the last update. + */ +void position(Registry &r, float deltaTime); + +} // namespace Flakkari::Engine::ECS::Systems + +#endif /* !SYSTEMS_HPP_ */ From 03e5fb642b30055eff7cd8bf49cada91a5138431 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 13:09:20 +0100 Subject: [PATCH 12/14] feat(Server): Refactor handlePacket function in UDPServer.cpp --- Flakkari/Server/UDPServer.cpp | 69 ++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/Flakkari/Server/UDPServer.cpp b/Flakkari/Server/UDPServer.cpp index 31fb2f58..957c342d 100644 --- a/Flakkari/Server/UDPServer.cpp +++ b/Flakkari/Server/UDPServer.cpp @@ -47,35 +47,46 @@ bool UDPServer::handleInput(int fd) void UDPServer::handlePacket() { - auto packet = _socket.receiveFrom(); - std::cout << (*packet->first.get()); - std::cout << " : "; - std::cout << packet->second << std::endl; - ClientManager::addClient(packet->first); - ClientManager::checkInactiveClients(); - Protocol::API::Header header( - Protocol::API::Priority::LOW, - Protocol::API::ApiVersion::V_1, - int(Protocol::API::FlakkariEventId::REP_ENTITY_SPAWN), - 0 - ); - - Protocol::API::PlayerPacket playerPacket; - - header._contentLength = sizeof(playerPacket); - - Network::Buffer buffer(sizeof(header) + sizeof(playerPacket)); - std::copy(reinterpret_cast(&header), reinterpret_cast(&header) + sizeof(header), buffer.begin()); - - std::cout << "Header: " << std::endl; - std::cout << " Priority: " << (int)header._priority << std::endl; - std::cout << " ApiVersion: " << (int)header._apiVersion << std::endl; - std::cout << " CommandId: " << (int)header._commandId << std::endl; - std::cout << " ContentLength: " << (int)header._contentLength << std::endl; - - std::cout << buffer << std::endl; - - _socket.sendTo(packet->first, buffer); + auto packet = _socket.receiveFrom(); + ClientManager::addClient(packet->first); + ClientManager::checkInactiveClients(); + + // parse packet + Protocol::API::Header header; + std::copy(packet->second.begin(), packet->second.begin() + sizeof(header), reinterpret_cast(&header)); + + std::cout << (*packet->first.get()); // Address + std::cout << " : "; + std::cout << packet->second << std::endl; // Buffer + + std::cout << "RECV Header: " << std::endl; + std::cout << " Priority: " << (int)header._priority << std::endl; + std::cout << " ApiVersion: " << (int)header._apiVersion << std::endl; + std::cout << " CommandId: " << (int)header._commandId << std::endl; + std::cout << " ContentLength: " << (int)header._contentLength << std::endl; + + // send to all clients + Protocol::API::Header sendHeader( + Protocol::API::Priority::LOW, + Protocol::API::ApiVersion::V_1, + int(Protocol::API::FlakkariEventId::REP_ENTITY_SPAWN), + 0 + ); + + Protocol::API::PlayerPacket playerPacket; + + sendHeader._contentLength = sizeof(playerPacket); + + Network::Buffer buffer(sizeof(sendHeader) + sizeof(playerPacket)); + std::copy(reinterpret_cast(&sendHeader), reinterpret_cast(&sendHeader) + sizeof(sendHeader), buffer.begin()); + + std::cout << "SEND Header: " << std::endl; + std::cout << " Priority: " << (int)sendHeader._priority << std::endl; + std::cout << " ApiVersion: " << (int)sendHeader._apiVersion << std::endl; + std::cout << " CommandId: " << (int)sendHeader._commandId << std::endl; + std::cout << " ContentLength: " << (int)sendHeader._contentLength << std::endl; + + _socket.sendTo(packet->first, buffer); } void UDPServer::run() From 1c8aa3e05391860bc70279631b1f961906febbcd Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Mon, 8 Jan 2024 17:05:42 +0100 Subject: [PATCH 13/14] feat(Game): Add functions to load systems, components, and entities from templates --- Flakkari/Server/Game/Game.cpp | 56 +++++++++++++++++++++++++++++++++++ Flakkari/Server/Game/Game.hpp | 32 ++++++++++++++++++++ 2 files changed, 88 insertions(+) diff --git a/Flakkari/Server/Game/Game.cpp b/Flakkari/Server/Game/Game.cpp index 654ec571..bd256118 100644 --- a/Flakkari/Server/Game/Game.cpp +++ b/Flakkari/Server/Game/Game.cpp @@ -29,6 +29,55 @@ Game::~Game() FLAKKARI_LOG_INFO("game \"" + _name + "\" is now stopped"); } +void Game::loadSystems(Engine::ECS::Registry ®istry, const std::string &name) +{ + if (name == "position") + return registry.add_system([ this ](Engine::ECS::Registry &r) { + Engine::ECS::Systems::position(r, _deltaTime); + }), void(); +} + +void Game::loadComponents(Engine::ECS::Registry ®istry, const nl_component &components, Engine::ECS::Entity newEntity) +{ + for (auto &component : components.items()) + { + auto componentName = component.key(); + auto componentContent = component.value(); + + if (componentName == "Transform") { + registry.registerComponent(); + Engine::ECS::Components::_2D::Transform transform; + transform.position = Engine::Math::Vector2d(componentContent["position"]["x"], componentContent["position"]["y"]); + transform.rotation = componentContent["rotation"]; + transform.scale = Engine::Math::Vector2d(componentContent["scale"]["x"], componentContent["scale"]["y"]); + registry.add_component(newEntity, std::move(transform)); + return; + } + + if (componentName == "Movable") { + registry.registerComponent(); + Engine::ECS::Components::_2D::Movable movable; + movable.velocity = Engine::Math::Vector2d(componentContent["velocity"]["x"], componentContent["velocity"]["y"]); + movable.acceleration = Engine::Math::Vector2d(componentContent["acceleration"]["x"], componentContent["acceleration"]["y"]); + registry.add_component(newEntity, std::move(movable)); + return; + } + } +} + +void Game::loadEntityFromTemplate(Engine::ECS::Registry ®istry, const nl_entity &entity, const nl_template &templates) +{ + Engine::ECS::Entity newEntity = registry.spawn_entity(); + + for (auto &componentInfo : entity.begin().value().items()) { + for (auto &templateInfo : templates.items()) { + if (templateInfo.value().begin().key() != componentInfo.value()) + continue; + loadComponents(registry, templateInfo.value().begin().value(), newEntity); + } + } +} + void Game::loadScene(const std::string &sceneName) { for (auto &scene : (*_config)["scenes"].items()) { @@ -36,6 +85,13 @@ void Game::loadScene(const std::string &sceneName) if (sceneInfo.key() != sceneName) continue; Engine::ECS::Registry registry; + + for (auto &system : sceneInfo.value()["systems"].items()) + loadSystems(registry, system.value()); + + for (auto &entity : sceneInfo.value()["entities"].items()) + loadEntityFromTemplate(registry, entity.value().items(), sceneInfo.value()["templates"]); + _scenes[sceneName] = registry; return; } diff --git a/Flakkari/Server/Game/Game.hpp b/Flakkari/Server/Game/Game.hpp index 10caee4f..8781c5c5 100644 --- a/Flakkari/Server/Game/Game.hpp +++ b/Flakkari/Server/Game/Game.hpp @@ -16,6 +16,7 @@ * @date 2023-01-06 **************************************************************************/ + #ifndef GAME_HPP_ #define GAME_HPP_ @@ -25,11 +26,16 @@ #include #include "Engine/EntityComponentSystem/Registry.hpp" +#include "Engine/EntityComponentSystem/Systems/Systems.hpp" namespace Flakkari { class Client; +using nl_entity = nlohmann::json_abi_v3_11_3::detail::iteration_proxy>; +using nl_template = nlohmann::json_abi_v3_11_3::basic_json>, void>; +using nl_component = nlohmann::json_abi_v3_11_3::json ; + class Game { public: /** @@ -42,6 +48,32 @@ class Game { Game(const std::string &name, std::shared_ptr config); ~Game(); + /** + * @brief Add all the systems of the game to the registry. + * + * @param registry Registry to add the systems to. + * @param name Name of the scene to load. + */ + void loadSystems(Engine::ECS::Registry ®istry, const std::string &name); + + /** + * @brief Add all the components of the game to the registry. + * + * @param registry Registry to add the components to. + * @param componentInfo Info of the components to add. + * @param newEntity Entity to add the components to. + */ + void loadComponents(Engine::ECS::Registry ®istry, const nl_component &componentInfo, Engine::ECS::Entity newEntity); + + /** + * @brief Add all the entities of the game to the registry. + * + * @param registry Registry to add the entities to. + * @param entity Entity to add to the registry. + * @param templates Templates of the game. + */ + void loadEntityFromTemplate(Engine::ECS::Registry ®istry, const nl_entity &entity, const nl_template &templates); + /** * @brief Load a scene from the game. * From 7595d02b2e372bab5393db4190f2456c35e23e56 Mon Sep 17 00:00:00 2001 From: Master_Laplace Date: Tue, 9 Jan 2024 06:28:54 +0100 Subject: [PATCH 14/14] fix(Network): Fix socket address nullptr bug and add socket to IO multiplexer --- Flakkari/Network/IOMultiplexer.cpp | 1 + Flakkari/Network/Socket.cpp | 38 +++++++++++++++++++++++++++++- Flakkari/Server/UDPServer.cpp | 7 +++--- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/Flakkari/Network/IOMultiplexer.cpp b/Flakkari/Network/IOMultiplexer.cpp index fb14cb9e..03e2caa9 100644 --- a/Flakkari/Network/IOMultiplexer.cpp +++ b/Flakkari/Network/IOMultiplexer.cpp @@ -72,6 +72,7 @@ void PSELECT::removeSocket(FileDescriptor socket) throw std::runtime_error("Index out of range"); FD_CLR(socket, &_fds); _sockets.erase(std::remove(_sockets.begin(), _sockets.end(), socket), _sockets.end()); + _maxFd = *std::max_element(_sockets.begin(), _sockets.end()); } int PSELECT::wait() diff --git a/Flakkari/Network/Socket.cpp b/Flakkari/Network/Socket.cpp index 894ba506..5dd4f174 100644 --- a/Flakkari/Network/Socket.cpp +++ b/Flakkari/Network/Socket.cpp @@ -23,6 +23,12 @@ Socket::Socket(std::shared_ptr
address) #endif auto &addr = _address->getAddrInfo(); + + if (addr == nullptr) { + FLAKKARI_LOG_ERROR("Address is nullptr"); + return; + } + _socket = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (_socket == INVALID_SOCKET) { FLAKKARI_LOG_FATAL("Failed to create socket, error: " + STD_ERROR); @@ -64,6 +70,12 @@ Socket::Socket(Address address) #endif auto &addr = _address->getAddrInfo(); + + if (addr == nullptr) { + FLAKKARI_LOG_ERROR("Address is nullptr"); + return; + } + _socket = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (_socket == INVALID_SOCKET) { FLAKKARI_LOG_FATAL("Failed to create socket, error: " + STD_ERROR); @@ -88,6 +100,12 @@ Socket::Socket(ip_t ip, port_t port, Address::IpType ip_type, Address::SocketTyp #endif auto &addr = _address->getAddrInfo(); + + if (addr == nullptr) { + FLAKKARI_LOG_ERROR("Address is nullptr"); + return; + } + _socket = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (_socket == INVALID_SOCKET) { FLAKKARI_LOG_FATAL("Failed to create socket, error: " + STD_ERROR); @@ -117,6 +135,9 @@ void Socket::bind() { auto &addr = _address->getAddrInfo(); + if (addr == nullptr) + return FLAKKARI_LOG_ERROR("Address is nullptr"), void(); + if (::bind(_socket, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR) { FLAKKARI_LOG_FATAL("Failed to bind socket, error: " + STD_ERROR); return; @@ -135,6 +156,9 @@ void Socket::connect() { auto &addr = _address->getAddrInfo(); + if (addr == nullptr) + return FLAKKARI_LOG_ERROR("Address is nullptr"), void(); + if (::connect(_socket, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR) { FLAKKARI_LOG_FATAL("Failed to connect socket, error: " + STD_ERROR); return; @@ -152,7 +176,9 @@ std::shared_ptr Socket::accept() return nullptr; } - auto _ip_type = (clientAddr.ss_family == AF_INET) ? Address::IpType::IPv4 : (clientAddr.ss_family == AF_INET6) ? Address::IpType::IPv6 : Address::IpType::None; + auto _ip_type = (clientAddr.ss_family == AF_INET) + ? Address::IpType::IPv4 : (clientAddr.ss_family == AF_INET6) + ? Address::IpType::IPv6 : Address::IpType::None; auto clientAddress = std::make_shared
(clientAddr, _address->getSocketType(), _ip_type); return std::make_shared(clientSocket, clientAddress); @@ -178,6 +204,9 @@ void Socket::sendTo(const std::shared_ptr
&address, const Buffer &data, { auto &addr = address->getAddrInfo(); + if (addr == nullptr) + return FLAKKARI_LOG_ERROR("Address is nullptr"), void(); + if (::sendto(_socket, data.getData(), data.getSize(), flags, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR) { FLAKKARI_LOG_ERROR("Failed to send \"" + std::string(data) + "\" to \"" + address->toString().value_or("No address") + "\", error: " + STD_ERROR); return; @@ -188,6 +217,9 @@ void Socket::sendTo(const std::shared_ptr
&address, const byte *data, c { auto &addr = address->getAddrInfo(); + if (addr == nullptr) + return FLAKKARI_LOG_ERROR("Address is nullptr"), void(); + if (::sendto(_socket, data, size, flags, addr->ai_addr, addr->ai_addrlen) == SOCKET_ERROR) { FLAKKARI_LOG_ERROR( "Failed to send \"" @@ -234,6 +266,7 @@ std::optional, Buffer>> Socket::receiveFrom(s FLAKKARI_LOG_ERROR("Failed to receive data from \"" + _address->toString().value_or("No address") + "\", error: " + STD_ERROR); return {}; } + auto _ip_type = (addr.ss_family == AF_INET) ? Address::IpType::IPv4 : (addr.ss_family == AF_INET6) ? Address::IpType::IPv6 : Address::IpType::None; @@ -248,6 +281,8 @@ std::optional, Buffer>> Socket::receiveFrom(i socklen_t addrlen = sizeof(addr); if (::recvfrom(_socket, &data[0], 4096, flags, (sockaddr*)&addr, &addrlen) == SOCKET_ERROR) { + if (errno == EAGAIN || errno == EWOULDBLOCK) + return {}; FLAKKARI_LOG_ERROR("Failed to receive data from \"" + _address->toString().value_or("No address") + "\", error: " + STD_ERROR); return {}; } @@ -283,6 +318,7 @@ void Socket::setBlocking(bool blocking) int result = ::fcntl(_socket, F_SETFL, flags | (blocking ? 0 : O_NONBLOCK)); #endif + if (result == SOCKET_ERROR) FLAKKARI_LOG_ERROR("Failed to set socket to " + std::string(blocking?"":"non") + "blocking, error: " + STD_ERROR); } diff --git a/Flakkari/Server/UDPServer.cpp b/Flakkari/Server/UDPServer.cpp index 957c342d..0729ea81 100644 --- a/Flakkari/Server/UDPServer.cpp +++ b/Flakkari/Server/UDPServer.cpp @@ -24,16 +24,17 @@ UDPServer::UDPServer(std::string ip, std::size_t port) : _io = std::make_unique(); _io->addSocket(_socket.getSocket()); + _io->addSocket(STDIN_FILENO); } bool UDPServer::handleTimeout(int event) { if (event != 0) return false; - FLAKKARI_LOG_DEBUG("ppoll timed out"); - ClientManager::checkInactiveClients(); + FLAKKARI_LOG_DEBUG("ppoll timed out"); + ClientManager::checkInactiveClients(); return true; - } +} bool UDPServer::handleInput(int fd) {