From cdfecd431084f096a81a9e2fe628e576cd89a8a9 Mon Sep 17 00:00:00 2001 From: Quentin Bazin Date: Mon, 1 Jun 2020 21:31:00 +0200 Subject: [PATCH] Now using entt::registry::visit to serialize entities. Closed #102. --- .../client/network/ClientCommandHandler.cpp | 73 +++++-------------- .../client/network/ClientCommandHandler.hpp | 8 +- source/common/scene/Scene.cpp | 31 ++++++-- .../scene/component/AnimationComponent.hpp | 2 + source/common/scene/component/DrawableDef.hpp | 2 + .../scene/component/PositionComponent.hpp | 13 +++- .../scene/component/RotationComponent.hpp | 9 ++- .../server/network/ServerCommandHandler.cpp | 40 ---------- .../server/network/ServerCommandHandler.hpp | 4 - .../scene/controller/NetworkController.cpp | 64 +++++----------- 10 files changed, 89 insertions(+), 157 deletions(-) diff --git a/source/client/network/ClientCommandHandler.cpp b/source/client/network/ClientCommandHandler.cpp index 3bc20e186..331a8a102 100644 --- a/source/client/network/ClientCommandHandler.cpp +++ b/source/client/network/ClientCommandHandler.cpp @@ -127,6 +127,22 @@ void ClientCommandHandler::sendChatMessage(const std::string &message) { m_client.send(packet); } +template +static void addComponentCommandCallback(Network::Command command, Client &client, ClientCommandHandler::EntityMap &entityMap, ClientWorld &world) { + client.setCommandCallback(command, [&](Network::Packet &packet) { + entt::entity entityID; + packet >> entityID; + + auto it = entityMap.find(entityID); + if (it != entityMap.end()) { + auto &component = world.scene().registry().get_or_emplace(it->second); + component.deserialize(packet); + } + else + gkError() << Network::commandToString(command) + ": Entity ID" << std::underlying_type_t(entityID) << "is invalid"; + }); +} + void ClientCommandHandler::setupCallbacks() { m_client.setCommandCallback(Network::Command::ClientDisconnect, [this](Network::Packet &packet) { u16 clientID; @@ -290,58 +306,9 @@ void ClientCommandHandler::setupCallbacks() { gkError() << "EntityDespawn: Entity ID" << std::underlying_type_t(entityID) << "is invalid"; }); - m_client.setCommandCallback(Network::Command::EntityPosition, [this](Network::Packet &packet) { - entt::entity entityID; - packet >> entityID; - - auto it = m_entityMap.find(entityID); - if (it != m_entityMap.end()) { - auto &position = m_world.scene().registry().get_or_emplace(it->second); - packet >> position.x >> position.y >> position.z; - } - else - gkError() << "EntityPosition: Entity ID" << std::underlying_type_t(entityID) << "is invalid"; - }); - - m_client.setCommandCallback(Network::Command::EntityRotation, [this](Network::Packet &packet) { - entt::entity entityID; - packet >> entityID; - - auto it = m_entityMap.find(entityID); - if (it != m_entityMap.end()) { - float w, x, y, z; - packet >> w >> x >> y >> z; - - auto &rotation = m_world.scene().registry().get_or_emplace(it->second); - rotation.quat = glm::quat(w, x, y, z); - } - else - gkError() << "EntityRotation: Entity ID" << std::underlying_type_t(entityID) << "is invalid"; - }); - - m_client.setCommandCallback(Network::Command::EntityAnimation, [this](Network::Packet &packet) { - entt::entity entityID; - packet >> entityID; - - auto it = m_entityMap.find(entityID); - if (it != m_entityMap.end()) { - auto &animation = m_world.scene().registry().get_or_emplace(it->second); - animation.deserialize(packet); - } - else - gkError() << "EntityAnimation: Entity ID" << std::underlying_type_t(entityID) << "is invalid"; - }); - - m_client.setCommandCallback(Network::Command::EntityDrawableDef, [this](Network::Packet &packet) { - entt::entity entityID; - packet >> entityID; - - auto it = m_entityMap.find(entityID); - if (it != m_entityMap.end()) { - packet >> m_world.scene().registry().get_or_emplace(it->second); - } - else - gkError() << "EntityDrawableDef: Entity ID" << std::underlying_type_t(entityID) << "is invalid"; - }); + addComponentCommandCallback(Network::Command::EntityPosition, m_client, m_entityMap, m_world); + addComponentCommandCallback(Network::Command::EntityRotation, m_client, m_entityMap, m_world); + addComponentCommandCallback(Network::Command::EntityAnimation, m_client, m_entityMap, m_world); + addComponentCommandCallback(Network::Command::EntityDrawableDef, m_client, m_entityMap, m_world); } diff --git a/source/client/network/ClientCommandHandler.hpp b/source/client/network/ClientCommandHandler.hpp index d8c59e4a1..3c714a5a2 100644 --- a/source/client/network/ClientCommandHandler.hpp +++ b/source/client/network/ClientCommandHandler.hpp @@ -65,14 +65,16 @@ class ClientCommandHandler { void setSingleplayer(bool isSingleplayer) { m_isSingleplayer = isSingleplayer; } + using PlayerBoxMap = std::unordered_map; + using EntityMap = std::unordered_map; + private: Client &m_client; ClientWorld &m_world; ClientPlayer &m_player; - std::unordered_map &m_playerBoxes; - - std::unordered_map m_entityMap; + PlayerBoxMap &m_playerBoxes; + EntityMap m_entityMap; bool m_isRegistryInitialized = false; diff --git a/source/common/scene/Scene.cpp b/source/common/scene/Scene.cpp index 1b14e1e2f..7b1d10311 100644 --- a/source/common/scene/Scene.cpp +++ b/source/common/scene/Scene.cpp @@ -28,6 +28,8 @@ #include +#include "Network.hpp" +#include "NetworkUtils.hpp" #include "Scene.hpp" static bool areComponentsRegistered = false; @@ -52,7 +54,7 @@ entt::entity Scene::createEntityFromModel(entt::registry &modelRegistry, entt::e } auto other = m_registry.create(); - modelRegistry.visit(modelEntity, [&](const auto component) { + modelRegistry.visit(modelEntity, [&](const auto &component) { const auto type = entt::resolve_type(component); const auto any = type.func("get"_hs).invoke({}, std::ref(modelRegistry), modelEntity); type.func("set"_hs).invoke({}, std::ref(m_registry), other, any); @@ -60,21 +62,34 @@ entt::entity Scene::createEntityFromModel(entt::registry &modelRegistry, entt::e return other; } -template -Type &get(entt::registry ®istry, entt::entity entity) { - return registry.get_or_emplace(entity); +template +T &get(entt::registry ®istry, entt::entity entity) { + return registry.get_or_emplace(entity); } -template -Type &set(entt::registry ®istry, entt::entity entity, const Type &instance) { - return registry.emplace_or_replace(entity, instance); +template +T &set(entt::registry ®istry, entt::entity entity, const T &instance) { + return registry.emplace_or_replace(entity, instance); +} + +template +Network::Packet serialize(entt::entity entity, T &component) { + Network::Packet packet; + if constexpr(std::is_base_of_v>) { + if (component.isUpdated) { + packet << component.packetType << entity << component; + component.isUpdated = false; + } + } + return packet; } template void extend_meta_type() { entt::meta().type() .template func<&get, entt::as_ref_t>("get"_hs) - .template func<&set>("set"_hs); + .template func<&set>("set"_hs) + .template func<&serialize>("serialize"_hs); } #include diff --git a/source/common/scene/component/AnimationComponent.hpp b/source/common/scene/component/AnimationComponent.hpp index a730a5c04..62c065129 100644 --- a/source/common/scene/component/AnimationComponent.hpp +++ b/source/common/scene/component/AnimationComponent.hpp @@ -32,6 +32,7 @@ #include #include "ISerializable.hpp" +#include "Network.hpp" #include "NetworkUtils.hpp" enum class AnimationType { @@ -123,6 +124,7 @@ struct AnimationComponent : public ISerializable { void serialize(sf::Packet &packet) const override { packet << list; } void deserialize(sf::Packet &packet) override { packet >> list; } + Network::Command packetType = Network::Command::EntityAnimation; std::vector list; diff --git a/source/common/scene/component/DrawableDef.hpp b/source/common/scene/component/DrawableDef.hpp index 4dc1f6f76..74e1d5e4a 100644 --- a/source/common/scene/component/DrawableDef.hpp +++ b/source/common/scene/component/DrawableDef.hpp @@ -31,6 +31,7 @@ #include "ISerializable.hpp" #include "InventoryCubeDef.hpp" +#include "Network.hpp" namespace DrawableType { enum : u8 { @@ -49,6 +50,7 @@ class DrawableDef : public ISerializable { void serialize(sf::Packet &packet) const override; void deserialize(sf::Packet &packet) override; + Network::Command packetType = Network::Command::EntityDrawableDef; bool isUpdated = true; diff --git a/source/common/scene/component/PositionComponent.hpp b/source/common/scene/component/PositionComponent.hpp index e85e2c90d..8cd7939a9 100644 --- a/source/common/scene/component/PositionComponent.hpp +++ b/source/common/scene/component/PositionComponent.hpp @@ -29,7 +29,14 @@ #include -struct PositionComponent { +#include "ISerializable.hpp" +#include "Network.hpp" + +struct PositionComponent : public ISerializable { + PositionComponent() = default; + PositionComponent(double x_, double y_, double z_, u16 dimension_) + : x(x_), y(y_), z(z_), dimension(dimension_) {} + double x = 0; double y = 0; double z = 0; @@ -37,6 +44,10 @@ struct PositionComponent { u16 dimension = 0; bool isUpdated = true; + + void serialize(sf::Packet &packet) const override { packet << x << y << z; } + void deserialize(sf::Packet &packet) override { packet >> x >> y >> z; } + Network::Command packetType = Network::Command::EntityPosition; }; #endif // POSITIONCOMPONENT_HPP_ diff --git a/source/common/scene/component/RotationComponent.hpp b/source/common/scene/component/RotationComponent.hpp index 010fb2bf6..ebb93040d 100644 --- a/source/common/scene/component/RotationComponent.hpp +++ b/source/common/scene/component/RotationComponent.hpp @@ -29,10 +29,17 @@ #include -struct RotationComponent { +#include "ISerializable.hpp" +#include "Network.hpp" + +struct RotationComponent : public ISerializable { glm::quat quat{1, 0, 0, 0}; bool isUpdated = true; + + void serialize(sf::Packet &packet) const override { packet << quat.w << quat.x << quat.y << quat.z; } + void deserialize(sf::Packet &packet) override { packet >> quat.w >> quat.x >> quat.y >> quat.z; } + Network::Command packetType = Network::Command::EntityRotation; }; #endif // ROTATIONCOMPONENT_HPP_ diff --git a/source/server/network/ServerCommandHandler.cpp b/source/server/network/ServerCommandHandler.cpp index 554437965..30e9b58ea 100644 --- a/source/server/network/ServerCommandHandler.cpp +++ b/source/server/network/ServerCommandHandler.cpp @@ -148,46 +148,6 @@ void ServerCommandHandler::sendEntityDespawn(entt::entity entityID, const Client client->tcpSocket->send(packet); } -void ServerCommandHandler::sendEntityPosition(entt::entity entityID, double x, double y, double z, const ClientInfo *client) const { - Network::Packet packet; - packet << Network::Command::EntityPosition << entityID << x << y << z; - - if (!client) - m_server.sendToAllClients(packet); - else - client->tcpSocket->send(packet); -} - -void ServerCommandHandler::sendEntityRotation(entt::entity entityID, float w, float x, float y, float z, const ClientInfo *client) const { - Network::Packet packet; - packet << Network::Command::EntityRotation << entityID << w << x << y << z; - - if (!client) - m_server.sendToAllClients(packet); - else - client->tcpSocket->send(packet); -} - -void ServerCommandHandler::sendEntityAnimation(entt::entity entityID, const AnimationComponent &animation, const ClientInfo *client) const { - Network::Packet packet; - packet << Network::Command::EntityAnimation << entityID << animation; - - if (!client) - m_server.sendToAllClients(packet); - else - client->tcpSocket->send(packet); -} - -void ServerCommandHandler::sendEntityDrawableDef(entt::entity entityID, const DrawableDef &drawableDef, const ClientInfo *client) const { - Network::Packet packet; - packet << Network::Command::EntityDrawableDef << entityID << drawableDef; - - if (!client) - m_server.sendToAllClients(packet); - else - client->tcpSocket->send(packet); -} - void ServerCommandHandler::setupCallbacks() { m_server.setConnectionCallback([this](ClientInfo &client) { Network::Packet packet; diff --git a/source/server/network/ServerCommandHandler.hpp b/source/server/network/ServerCommandHandler.hpp index a85cddcec..040d27232 100644 --- a/source/server/network/ServerCommandHandler.hpp +++ b/source/server/network/ServerCommandHandler.hpp @@ -70,10 +70,6 @@ class ServerCommandHandler { void sendChatMessage(u16 clientID, const std::string &message, const ClientInfo *client = nullptr) const; void sendEntitySpawn(entt::entity entityID, const ClientInfo *client = nullptr) const; void sendEntityDespawn(entt::entity entityID, const ClientInfo *client = nullptr) const; - void sendEntityPosition(entt::entity entityID, double x, double y, double z, const ClientInfo *client = nullptr) const; - void sendEntityRotation(entt::entity entityID, float w, float x, float y, float z, const ClientInfo *client = nullptr) const; - void sendEntityAnimation(entt::entity entityID, const AnimationComponent &animation, const ClientInfo *client = nullptr) const; - void sendEntityDrawableDef(entt::entity entityID, const DrawableDef &drawableDef, const ClientInfo *client = nullptr) const; void setupCallbacks(); diff --git a/source/server/scene/controller/NetworkController.cpp b/source/server/scene/controller/NetworkController.cpp index 930b1a193..59ea9ae87 100644 --- a/source/server/scene/controller/NetworkController.cpp +++ b/source/server/scene/controller/NetworkController.cpp @@ -24,48 +24,26 @@ * * ===================================================================================== */ -#include "AnimationComponent.hpp" -#include "DrawableDef.hpp" +#include "Network.hpp" #include "NetworkComponent.hpp" #include "NetworkController.hpp" -#include "PositionComponent.hpp" -#include "RotationComponent.hpp" +#include "Server.hpp" #include "ServerCommandHandler.hpp" void NetworkController::update(entt::registry ®istry) { - registry.view().each([this] (auto, auto &network) { + registry.view().each([&] (auto entity, auto &network) { if (!network.hasSpawned) { m_server->sendEntitySpawn(network.entityID); network.hasSpawned = true; } - }); - - registry.view().each([this] (auto, auto &network, auto &position) { - if (position.isUpdated) { - m_server->sendEntityPosition(network.entityID, position.x, position.y, position.z); - position.isUpdated = false; - } - }); - - registry.view().each([this] (auto, auto &network, auto &rotation) { - if (rotation.isUpdated) { - m_server->sendEntityRotation(network.entityID, rotation.quat.w, rotation.quat.x, rotation.quat.y, rotation.quat.z); - rotation.isUpdated = false; - } - }); - registry.view().each([this] (auto, auto &network, auto &animation) { - if (animation.isUpdated) { - m_server->sendEntityAnimation(network.entityID, animation); - animation.isUpdated = false; - } - }); - - registry.view().each([this] (auto, auto &network, auto &drawableDef) { - if (drawableDef.isUpdated) { - m_server->sendEntityDrawableDef(network.entityID, drawableDef); - drawableDef.isUpdated = false; - } + registry.visit(entity, [&] (const auto &component_type) { + const auto &type = entt::resolve_type(component_type); + const auto &component = type.func("get"_hs).invoke({}, std::ref(registry), entity); + Network::Packet packet = type.func("serialize"_hs).invoke({}, entity, component).template cast(); + if (packet.getDataSize()) + m_server->server().sendToAllClients(packet); + }); }); } @@ -73,21 +51,13 @@ void NetworkController::sendEntities(entt::registry ®istry, const ClientInfo registry.view().each([&] (auto entity, auto &network) { m_server->sendEntitySpawn(network.entityID, &client); - if (auto *position = registry.try_get(entity) ; position) { - m_server->sendEntityPosition(network.entityID, position->x, position->y, position->z, &client); - } - - if (auto *rotation = registry.try_get(entity) ; rotation) { - m_server->sendEntityRotation(network.entityID, rotation->quat.w, rotation->quat.x, rotation->quat.y, rotation->quat.z, &client); - } - - if (auto *animation = registry.try_get(entity) ; animation) { - m_server->sendEntityAnimation(network.entityID, *animation, &client); - } - - if (auto *drawableDef = registry.try_get(entity) ; drawableDef) { - m_server->sendEntityDrawableDef(network.entityID, *drawableDef, &client); - } + registry.visit(entity, [&] (const auto &component_type) { + const auto &type = entt::resolve_type(component_type); + const auto &component = type.func("get"_hs).invoke({}, std::ref(registry), entity); + Network::Packet packet = type.func("serialize"_hs).invoke({}, entity, component).template cast(); + if (packet.getDataSize()) + client.tcpSocket->send(packet); + }); }); }