From 392eaeab83b0c00ba0b247fa1cf44cb1a396c148 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Mon, 22 Jul 2024 12:58:40 +0200 Subject: [PATCH] implement server and client player join/leave notifications --- include/blitz/common/Types.h | 9 +++ include/blitz/components/PlayerInfo.h | 13 ++++ include/blitz/protocol/PacketData.h | 19 ++++-- include/client/Client.h | 3 +- include/client/components/LocalPlayer.h | 13 ++++ include/client/handlers/KeepAliveHandler.h | 3 + .../client/handlers/LoggingSuccessHandler.h | 18 +++++ include/client/handlers/PlayerJoinHandler.h | 18 +++++ include/client/handlers/PlayerLeaveHandler.h | 18 +++++ include/client/handlers/PlayerListHandler.h | 18 +++++ include/server/Server.h | 4 ++ include/server/components/ServerIdCounter.h | 13 ++++ include/server/handlers/PlayerLoginHandler.h | 20 ++++++ src/blitz/protocol/PacketSerializer.cpp | 42 +++++++++--- src/client/Client.cpp | 23 ++++++- src/client/handlers/KeepAliveHandler.cpp | 7 +- src/client/handlers/LoggingSuccessHandler.cpp | 22 ++++++ src/client/handlers/PlayerJoinHandler.cpp | 35 ++++++++++ src/client/handlers/PlayerLeaveHandler.cpp | 29 ++++++++ src/client/handlers/PlayerListHandler.cpp | 22 ++++++ src/server/Server.cpp | 14 +++- src/server/handlers/PlayerLoginHandler.cpp | 68 +++++++++++++++++++ src/server/systems/DisconnectSystem.cpp | 16 ++++- 23 files changed, 422 insertions(+), 25 deletions(-) create mode 100644 include/blitz/common/Types.h create mode 100644 include/blitz/components/PlayerInfo.h create mode 100644 include/client/components/LocalPlayer.h create mode 100644 include/client/handlers/LoggingSuccessHandler.h create mode 100644 include/client/handlers/PlayerJoinHandler.h create mode 100644 include/client/handlers/PlayerLeaveHandler.h create mode 100644 include/client/handlers/PlayerListHandler.h create mode 100644 include/server/components/ServerIdCounter.h create mode 100644 include/server/handlers/PlayerLoginHandler.h create mode 100644 src/client/handlers/LoggingSuccessHandler.cpp create mode 100644 src/client/handlers/PlayerJoinHandler.cpp create mode 100644 src/client/handlers/PlayerLeaveHandler.cpp create mode 100644 src/client/handlers/PlayerListHandler.cpp create mode 100644 src/server/handlers/PlayerLoginHandler.cpp diff --git a/include/blitz/common/Types.h b/include/blitz/common/Types.h new file mode 100644 index 0000000..549c39a --- /dev/null +++ b/include/blitz/common/Types.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +namespace blitz { + +using EntityID = std::uint32_t; + +} // namespace blitz diff --git a/include/blitz/components/PlayerInfo.h b/include/blitz/components/PlayerInfo.h new file mode 100644 index 0000000..951214d --- /dev/null +++ b/include/blitz/components/PlayerInfo.h @@ -0,0 +1,13 @@ +#pragma once + +#include +#include + +namespace blitz { + +struct PlayerInfoComponent { + EntityID m_PlayerId; + std::string m_Pseudo; +}; + +} // namespace blitz diff --git a/include/blitz/protocol/PacketData.h b/include/blitz/protocol/PacketData.h index 26de0d4..dce3299 100644 --- a/include/blitz/protocol/PacketData.h +++ b/include/blitz/protocol/PacketData.h @@ -1,6 +1,7 @@ #pragma once -#include +#include +#include namespace blitz { namespace protocol { @@ -14,17 +15,25 @@ struct UpdateHealth { float m_NewHealth; }; -struct LoggingSuccess {}; +struct LoggingSuccess { + EntityID m_PlayerId; +}; struct PlayerDeath {}; -struct PlayerJoin {}; +struct PlayerJoin { + PlayerInfoComponent m_Player; +}; -struct PlayerLeave {}; +struct PlayerLeave { + EntityID m_PlayerId; +}; struct PlayerStats {}; -struct PlayerList {}; +struct PlayerList { + std::vector m_Players; +}; struct ServerConfig {}; diff --git a/include/client/Client.h b/include/client/Client.h index 68c9f50..9debeaa 100644 --- a/include/client/Client.h +++ b/include/client/Client.h @@ -10,7 +10,7 @@ namespace client { class Client : private NonCopyable { public: - Client(); + Client(std::shared_ptr a_World); ~Client(); void Connect(const Nz::IpAddress& a_Ip); @@ -25,6 +25,7 @@ class Client : private NonCopyable { void BindHandlers(); void UnbindHandlers(); + void Login(); }; } // namespace client diff --git a/include/client/components/LocalPlayer.h b/include/client/components/LocalPlayer.h new file mode 100644 index 0000000..32066c1 --- /dev/null +++ b/include/client/components/LocalPlayer.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace blitz { +namespace client { + +struct LocalPlayerComponent { + EntityID m_LocalPlayerId; +}; + +} // namespace client +} // namespace blitz diff --git a/include/client/handlers/KeepAliveHandler.h b/include/client/handlers/KeepAliveHandler.h index e63eafe..82e8601 100644 --- a/include/client/handlers/KeepAliveHandler.h +++ b/include/client/handlers/KeepAliveHandler.h @@ -9,6 +9,9 @@ class KeepAliveHandler : public protocol::PacketHandler { ~KeepAliveHandler(); NazaraSlot(network::EnetConnection, OnKeepAlive, m_Slot); + + private: + void Handle(const protocol::data::KeepAlive&); }; } // namespace client diff --git a/include/client/handlers/LoggingSuccessHandler.h b/include/client/handlers/LoggingSuccessHandler.h new file mode 100644 index 0000000..55d582a --- /dev/null +++ b/include/client/handlers/LoggingSuccessHandler.h @@ -0,0 +1,18 @@ +#include + +namespace blitz { +namespace client { + +class LoggingSuccessHandler : public protocol::PacketHandler { + public: + LoggingSuccessHandler(network::EnetConnection& a_Connection, EnttWorld& a_World); + ~LoggingSuccessHandler(); + + NazaraSlot(network::EnetConnection, OnLoggingSuccess, m_Slot); + + private: + void Handle(const protocol::data::LoggingSuccess&); +}; + +} // namespace client +} // namespace blitz diff --git a/include/client/handlers/PlayerJoinHandler.h b/include/client/handlers/PlayerJoinHandler.h new file mode 100644 index 0000000..6995cc2 --- /dev/null +++ b/include/client/handlers/PlayerJoinHandler.h @@ -0,0 +1,18 @@ +#include + +namespace blitz { +namespace client { + +class PlayerJoinHandler : public protocol::PacketHandler { + public: + PlayerJoinHandler(network::EnetConnection& a_Connection, EnttWorld& a_World); + ~PlayerJoinHandler(); + + NazaraSlot(network::EnetConnection, OnPlayerJoin, m_Slot); + + private: + void Handle(const protocol::data::PlayerJoin&); +}; + +} // namespace client +} // namespace blitz diff --git a/include/client/handlers/PlayerLeaveHandler.h b/include/client/handlers/PlayerLeaveHandler.h new file mode 100644 index 0000000..cd41526 --- /dev/null +++ b/include/client/handlers/PlayerLeaveHandler.h @@ -0,0 +1,18 @@ +#include + +namespace blitz { +namespace client { + +class PlayerLeaveHandler : public protocol::PacketHandler { + public: + PlayerLeaveHandler(network::EnetConnection& a_Connection, EnttWorld& a_World); + ~PlayerLeaveHandler(); + + NazaraSlot(network::EnetConnection, OnPlayerLeave, m_Slot); + + private: + void Handle(const protocol::data::PlayerLeave&); +}; + +} // namespace client +} // namespace blitz diff --git a/include/client/handlers/PlayerListHandler.h b/include/client/handlers/PlayerListHandler.h new file mode 100644 index 0000000..dc9e09c --- /dev/null +++ b/include/client/handlers/PlayerListHandler.h @@ -0,0 +1,18 @@ +#include + +namespace blitz { +namespace client { + +class PlayerListHandler : public protocol::PacketHandler { + public: + PlayerListHandler(network::EnetConnection& a_Connection, EnttWorld& a_World); + ~PlayerListHandler(); + + NazaraSlot(network::EnetConnection, OnPlayerList, m_Slot); + + private: + void Handle(const protocol::data::PlayerList&); +}; + +} // namespace client +} // namespace blitz diff --git a/include/server/Server.h b/include/server/Server.h index 1e9525f..2bc1f4f 100644 --- a/include/server/Server.h +++ b/include/server/Server.h @@ -8,6 +8,10 @@ namespace server { class Server { public: + /** + * \brief Construct a server + * \pre Two instances of Server should not share the same world + */ Server(std::uint16_t a_Port, std::shared_ptr a_World); ~Server(); diff --git a/include/server/components/ServerIdCounter.h b/include/server/components/ServerIdCounter.h new file mode 100644 index 0000000..7f2b020 --- /dev/null +++ b/include/server/components/ServerIdCounter.h @@ -0,0 +1,13 @@ +#pragma once + +#include + +namespace blitz { +namespace server { + +struct ServerIdCounterComponent { + EntityID m_NextEntityId; +}; + +} // namespace server +} // namespace blitz diff --git a/include/server/handlers/PlayerLoginHandler.h b/include/server/handlers/PlayerLoginHandler.h new file mode 100644 index 0000000..63a8230 --- /dev/null +++ b/include/server/handlers/PlayerLoginHandler.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +namespace blitz { +namespace server { + +class PlayerLoginHandler : public protocol::PacketHandler { + public: + PlayerLoginHandler(network::EnetConnection& a_Connection, EnttWorld& a_World); + ~PlayerLoginHandler(); + + NazaraSlot(network::EnetConnection, OnPlayerLogin, m_Slot); + + private: + void Handle(std::uint16_t, const protocol::data::PlayerLogin&); +}; + +} // namespace server +} // namespace blitz diff --git a/src/blitz/protocol/PacketSerializer.cpp b/src/blitz/protocol/PacketSerializer.cpp index c798a44..8473ca3 100644 --- a/src/blitz/protocol/PacketSerializer.cpp +++ b/src/blitz/protocol/PacketSerializer.cpp @@ -152,10 +152,13 @@ void Deserializer::DeserializePacketData(data::UpdateHealth& a_Packet) { +void Serializer::SerializePacketData(const data::LoggingSuccess& a_Packet) { + m_Buffer << a_Packet.m_PlayerId; +} -void Serializer::SerializePacketData(const data::LoggingSuccess& a_Packet) {} - -void Deserializer::DeserializePacketData(data::LoggingSuccess& a_Packet) {} +void Deserializer::DeserializePacketData(data::LoggingSuccess& a_Packet) { + m_Buffer >> a_Packet.m_PlayerId; +} @@ -167,23 +170,44 @@ void Deserializer::DeserializePacketData(data::PlayerDeath& a_Packet) {} -void Serializer::SerializePacketData(const data::PlayerJoin& a_Packet) {} +void Serializer::SerializePacketData(const data::PlayerJoin& a_Packet) { + m_Buffer << a_Packet.m_Player.m_PlayerId << a_Packet.m_Player.m_Pseudo; +} -void Deserializer::DeserializePacketData(data::PlayerJoin& a_Packet) {} +void Deserializer::DeserializePacketData(data::PlayerJoin& a_Packet) { + m_Buffer >> a_Packet.m_Player.m_PlayerId >> a_Packet.m_Player.m_Pseudo; +} -void Serializer::SerializePacketData(const data::PlayerLeave& a_Packet) {} +void Serializer::SerializePacketData(const data::PlayerLeave& a_Packet) { + m_Buffer << a_Packet.m_PlayerId; +} -void Deserializer::DeserializePacketData(data::PlayerLeave& a_Packet) {} +void Deserializer::DeserializePacketData(data::PlayerLeave& a_Packet) { + m_Buffer >> a_Packet.m_PlayerId; +} -void Serializer::SerializePacketData(const data::PlayerList& a_Packet) {} +void Serializer::SerializePacketData(const data::PlayerList& a_Packet) { + m_Buffer << static_cast(a_Packet.m_Players.size()); + for (auto player : a_Packet.m_Players) { + m_Buffer << player.m_PlayerId << player.m_Pseudo; + } +} -void Deserializer::DeserializePacketData(data::PlayerList& a_Packet) {} +void Deserializer::DeserializePacketData(data::PlayerList& a_Packet) { + std::uint8_t playerCount; + m_Buffer >> playerCount; + for (std::uint8_t i = 0; i < playerCount; i++) { + PlayerInfoComponent player; + m_Buffer >> player.m_PlayerId >> player.m_Pseudo; + a_Packet.m_Players.push_back(player); + } +} diff --git a/src/client/Client.cpp b/src/client/Client.cpp index 24f89bf..ef34c30 100644 --- a/src/client/Client.cpp +++ b/src/client/Client.cpp @@ -1,12 +1,18 @@ #include #include +#include +#include +#include +#include + +#define RegisterHandler(Handler) m_Handlers.push_back(std::make_unique(m_NetworkClient->GetConnection(), m_World)) namespace blitz { namespace client { -Client::Client() : m_World() { - m_World.store(std::make_shared()); +Client::Client(std::shared_ptr a_World) { + m_World.store(a_World); } Client::~Client() { @@ -14,7 +20,11 @@ Client::~Client() { } void Client::BindHandlers() { - m_Handlers.push_back(std::make_unique(m_NetworkClient->GetConnection(), m_World)); + RegisterHandler(KeepAliveHandler); + RegisterHandler(LoggingSuccessHandler); + RegisterHandler(PlayerJoinHandler); + RegisterHandler(PlayerLeaveHandler); + RegisterHandler(PlayerListHandler); } void Client::UnbindHandlers() { @@ -24,6 +34,7 @@ void Client::UnbindHandlers() { void Client::Connect(const Nz::IpAddress& a_Ip) { m_NetworkClient = std::make_unique(a_Ip); BindHandlers(); + m_NetworkClient->OnConnect.Connect([this]() { Login(); }); } void Client::Disconnect() { @@ -41,5 +52,11 @@ bool Client::IsConnected() { return m_NetworkClient->GetConnection().IsConnected(); } +void Client::Login() { + if (!m_NetworkClient || !m_NetworkClient->GetConnection().IsConnected()) + return; + m_NetworkClient->GetConnection().SendPlayerLogin({"Player_" + std::to_string(rand() % 100)}); +} + } // namespace client } // namespace blitz diff --git a/src/client/handlers/KeepAliveHandler.cpp b/src/client/handlers/KeepAliveHandler.cpp index 4f81fbc..8253439 100644 --- a/src/client/handlers/KeepAliveHandler.cpp +++ b/src/client/handlers/KeepAliveHandler.cpp @@ -5,8 +5,11 @@ namespace client { KeepAliveHandler::KeepAliveHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) : protocol::PacketHandler(a_Connection, a_World) { - m_Slot.Connect(m_Connection.OnKeepAlive, - [this](const blitz::protocol::data::KeepAlive& a_KeepAlive) { m_Connection.SendKeepAlive(a_KeepAlive); }); + m_Slot.Connect(m_Connection.OnKeepAlive, this, &KeepAliveHandler::Handle); +} + +void KeepAliveHandler::Handle(const blitz::protocol::data::KeepAlive& a_KeepAlive) { + m_Connection.SendKeepAlive(a_KeepAlive); } KeepAliveHandler::~KeepAliveHandler() {} diff --git a/src/client/handlers/LoggingSuccessHandler.cpp b/src/client/handlers/LoggingSuccessHandler.cpp new file mode 100644 index 0000000..1d0adde --- /dev/null +++ b/src/client/handlers/LoggingSuccessHandler.cpp @@ -0,0 +1,22 @@ +#include + +#include + +namespace blitz { +namespace client { + +LoggingSuccessHandler::LoggingSuccessHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) : + protocol::PacketHandler(a_Connection, a_World) { + m_Slot.Connect(m_Connection.OnLoggingSuccess, this, &LoggingSuccessHandler::Handle); +} + +void LoggingSuccessHandler::Handle(const blitz::protocol::data::LoggingSuccess& a_LoggingSuccess) { + auto world = m_World.load(); + auto player = world->CreateEntity(); + player.emplace(a_LoggingSuccess.m_PlayerId); +} + +LoggingSuccessHandler::~LoggingSuccessHandler() {} + +} // namespace client +} // namespace blitz diff --git a/src/client/handlers/PlayerJoinHandler.cpp b/src/client/handlers/PlayerJoinHandler.cpp new file mode 100644 index 0000000..73d0c70 --- /dev/null +++ b/src/client/handlers/PlayerJoinHandler.cpp @@ -0,0 +1,35 @@ +#include + +#include + +namespace blitz { +namespace client { + +PlayerJoinHandler::PlayerJoinHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) : + protocol::PacketHandler(a_Connection, a_World) { + m_Slot.Connect(m_Connection.OnPlayerJoin, this, &PlayerJoinHandler::Handle); +} + +void PlayerJoinHandler::Handle(const protocol::data::PlayerJoin& a_PlayerJoin) { + auto world = m_World.load(); + assert(world->GetRegistry().view().size() == 1 && "There should be only one local player !"); + + auto localPlayer = world->GetRegistry().view().front(); + auto localPlayerId = world->GetRegistry().get(localPlayer).m_LocalPlayerId; + + if (a_PlayerJoin.m_Player.m_PlayerId != localPlayerId) { + auto newPlayer = world->CreateEntity(); + + newPlayer.emplace(a_PlayerJoin.m_Player); + return; + } + + world->GetRegistry().emplace(localPlayer, a_PlayerJoin.m_Player); + + // we are now into the game so we can begin to load the world for example +} + +PlayerJoinHandler::~PlayerJoinHandler() {} + +} // namespace client +} // namespace blitz diff --git a/src/client/handlers/PlayerLeaveHandler.cpp b/src/client/handlers/PlayerLeaveHandler.cpp new file mode 100644 index 0000000..7d01d78 --- /dev/null +++ b/src/client/handlers/PlayerLeaveHandler.cpp @@ -0,0 +1,29 @@ +#include + +namespace blitz { +namespace client { + +PlayerLeaveHandler::PlayerLeaveHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) : + protocol::PacketHandler(a_Connection, a_World) { + m_Slot.Connect(m_Connection.OnPlayerLeave, this, &PlayerLeaveHandler::Handle); +} + +void PlayerLeaveHandler::Handle(const protocol::data::PlayerLeave& a_PlayerLeave) { + auto world = m_World.load(); + + entt::entity playerLeft; + + for (auto [player, playerInfo] : world->GetRegistry().view().each()) { + if (playerInfo.m_PlayerId == a_PlayerLeave.m_PlayerId) { + playerLeft = player; + break; + } + } + + world->GetRegistry().destroy(playerLeft); +} + +PlayerLeaveHandler::~PlayerLeaveHandler() {} + +} // namespace client +} // namespace blitz diff --git a/src/client/handlers/PlayerListHandler.cpp b/src/client/handlers/PlayerListHandler.cpp new file mode 100644 index 0000000..997aa67 --- /dev/null +++ b/src/client/handlers/PlayerListHandler.cpp @@ -0,0 +1,22 @@ +#include + +namespace blitz { +namespace client { + +PlayerListHandler::PlayerListHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) : + protocol::PacketHandler(a_Connection, a_World) { + m_Slot.Connect(m_Connection.OnPlayerList, this, &PlayerListHandler::Handle); +} + +void PlayerListHandler::Handle(const protocol::data::PlayerList& a_PlayerList) { + auto world = m_World.load(); + for (auto playerInfo : a_PlayerList.m_Players) { + auto player = world->CreateEntity(); + player.emplace(playerInfo); + } +} + +PlayerListHandler::~PlayerListHandler() {} + +} // namespace client +} // namespace blitz diff --git a/src/server/Server.cpp b/src/server/Server.cpp index d1abd97..4f6e232 100644 --- a/src/server/Server.cpp +++ b/src/server/Server.cpp @@ -1,14 +1,19 @@ #include #include -#include +#include + #include +#include + #include #include namespace blitz { namespace server { +#define RegisterHandler(Handler) session.m_Handlers.push_back(std::make_unique(*session.m_Connection, m_World)) + Server::Server(std::uint16_t a_Port, std::shared_ptr a_World) : m_NetworkServer(a_Port) { m_World.store(a_World); RegisterSystems(); @@ -39,7 +44,6 @@ void Server::CreateEntity(network::EnetConnection& a_Connection) { auto entity = world->CreateEntity(); - entity.emplace(a_Connection.GetPeerId(), 69, Nz::GetElapsedMilliseconds(), true); entity.emplace(&a_Connection); } @@ -47,10 +51,14 @@ void Server::RegisterSystems() { auto world = m_World.load(); world->AddSystem(); world->AddSystem(*this); + + auto counter = world->CreateEntity(); + counter.emplace(0); } void Server::RegisterHandlers(Session& session) { - session.m_Handlers.push_back(std::make_unique(*session.m_Connection, m_World)); + RegisterHandler(KeepAliveHandler); + RegisterHandler(PlayerLoginHandler); } network::EnetConnection* Server::GetConnection(std::uint16_t a_PeerId) { diff --git a/src/server/handlers/PlayerLoginHandler.cpp b/src/server/handlers/PlayerLoginHandler.cpp new file mode 100644 index 0000000..0119349 --- /dev/null +++ b/src/server/handlers/PlayerLoginHandler.cpp @@ -0,0 +1,68 @@ +#include + +#include +#include +#include +#include +#include + +namespace blitz { +namespace server { + +PlayerLoginHandler::PlayerLoginHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) : + protocol::PacketHandler(a_Connection, a_World) { + m_Slot.Connect(a_Connection.OnPlayerLogin, + [this](const protocol::data::PlayerLogin& a_PlayerLogin) { Handle(m_Connection.GetPeerId(), a_PlayerLogin); }); +} + +PlayerLoginHandler::~PlayerLoginHandler() {} + +void PlayerLoginHandler::Handle(std::uint16_t a_PeerId, const protocol::data::PlayerLogin& a_PlayerLogin) { + auto world = m_World.load(); + + std::vector players; + + for (auto [entity, playerInfo] : world->GetRegistry().view().each()) { + players.push_back(playerInfo); + } + + assert(world->GetRegistry().view().size() == 1 && "There should be only one counter !"); + + auto& serverCounter = + world->GetRegistry().get(world->GetRegistry().view().front()); + + EntityID newEntityId = serverCounter.m_NextEntityId++; + + PlayerInfoComponent newPlayer; + + for (auto [entity, connection] : world->GetRegistry().view().each()) { + if (connection.m_Connection->GetPeerId() == m_Connection.GetPeerId()) { + // players should not try to log in twice + auto previousPlayerInfo = world->GetRegistry().try_get(entity); + if (previousPlayerInfo) + return; + + newPlayer = world->GetRegistry().emplace(entity, newEntityId, a_PlayerLogin.m_PlayerName); + + world->GetRegistry().emplace( + entity, m_Connection.GetPeerId(), 69, Nz::GetElapsedMilliseconds(), true); + + break; + } + } + + // send logging success + m_Connection.SendLoggingSuccess({newEntityId}); + + // send player list + if (!players.empty()) + m_Connection.SendPlayerList({players}); + + // broadcast player join + for (auto [entity, connection] : world->GetRegistry().view().each()) { + connection.m_Connection->SendPlayerJoin({newPlayer}); + } +} + +} // namespace server +} // namespace blitz diff --git a/src/server/systems/DisconnectSystem.cpp b/src/server/systems/DisconnectSystem.cpp index 60e2c3a..93e0c38 100644 --- a/src/server/systems/DisconnectSystem.cpp +++ b/src/server/systems/DisconnectSystem.cpp @@ -11,14 +11,26 @@ namespace server { DisconectSystem::DisconectSystem(entt::registry& a_Registry, Server& a_Server) : m_Registry(a_Registry), m_Server(a_Server) {} void DisconectSystem::Update(Nz::Time elapsedTime) { + auto disconnects = m_Registry.view(); + + // broadcast player leave + for (auto entity : disconnects) { + auto* player = m_Registry.try_get(entity); + if (player) { + for (auto [entity, connection] : m_Registry.view().each()) { + connection.m_Connection->SendPlayerLeave({player->m_PlayerId}); + } + } + } + + // close connections m_Registry.view().each( [this](auto entity, EnetConnectionComponent& connection, DisconnectComponent disconnect) { m_Server.CloseConnection(connection.m_Connection->GetPeerId()); }); // remove the entities - auto it = m_Registry.view(); - m_Registry.destroy(it.begin(), it.end()); + m_Registry.destroy(disconnects.begin(), disconnects.end()); } } // namespace server