From 8bc2f265786e1fa893bd822fa08bd6f4c9148802 Mon Sep 17 00:00:00 2001 From: Persson-dev Date: Thu, 18 Jul 2024 20:45:55 +0200 Subject: [PATCH] improve packet interface --- include/blitz/network/EnetClient.h | 38 ++++++++ include/blitz/network/EnetConnexion.h | 50 ++++++++++ include/blitz/network/EnetServer.h | 43 +++++++++ include/blitz/protocol/PacketDeclare.h | 19 ++++ include/blitz/protocol/PacketVisitor.h | 23 ++--- include/blitz/protocol/Packets.h | 34 ++----- src/blitz/network/EnetClient.cpp | 69 ++++++++++++++ src/blitz/network/EnetConnexion.cpp | 48 ++++++++++ src/blitz/network/EnetServer.cpp | 94 +++++++++++++++++++ src/blitz/protocol/PacketSerializer.cpp | 41 ++------ test/blitz/protocol/PacketSerializer_test.cpp | 20 ++-- 11 files changed, 400 insertions(+), 79 deletions(-) create mode 100644 include/blitz/network/EnetClient.h create mode 100644 include/blitz/network/EnetConnexion.h create mode 100644 include/blitz/network/EnetServer.h create mode 100644 include/blitz/protocol/PacketDeclare.h create mode 100644 src/blitz/network/EnetClient.cpp create mode 100644 src/blitz/network/EnetConnexion.cpp create mode 100644 src/blitz/network/EnetServer.cpp diff --git a/include/blitz/network/EnetClient.h b/include/blitz/network/EnetClient.h new file mode 100644 index 0000000..bec0660 --- /dev/null +++ b/include/blitz/network/EnetClient.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +namespace blitz { +namespace network { + +class EnetClient : private NonCopyable { + public: + EnetClient(const Nz::IpAddress& address); + ~EnetClient(); + + void Disconnect(); + + NazaraSignal(OnConnect); + NazaraSignal(OnDisconnect); + NazaraSignal(OnDisconnectTimeout); + + const EnetConnexion& GetConnexion() const { + return m_Connexion; + } + + private: + EnetConnexion m_Connexion; + Nz::ENetHost m_Host; + Nz::ENetPeer* m_Peer; + std::thread m_Thread; + bool m_Running; + + void Update(); + void WorkerThread(); +}; + +} // namespace network +} // namespace blitz diff --git a/include/blitz/network/EnetConnexion.h b/include/blitz/network/EnetConnexion.h new file mode 100644 index 0000000..6b0e309 --- /dev/null +++ b/include/blitz/network/EnetConnexion.h @@ -0,0 +1,50 @@ +#pragma once + +#include +#include +#include + +namespace blitz { +namespace network { + +class EnetClient; +class EnetServer; + + + +#define DeclarePacket(Name, NFlag) \ + void Send##Name(const blitz::protocol::data::Name& a_##Name) const { \ + m_Peer->Send(0, NFlag, protocol::PacketSerializer::Serialize(protocol::packets::Name(a_##Name))); \ + } \ + NazaraSignal(On##Name, const blitz::protocol::data::Name&) + + + + + +class EnetConnexion { + public: + EnetConnexion(Nz::ENetPeer* a_Peer = nullptr); + + bool IsConnected() const { + if (!m_Peer) + return false; + return m_Peer->IsConnected(); + } + + DeclareAllPacket() + + private: + Nz::ENetPeer* m_Peer; + + void Recieve(Nz::ByteArray&); + void SetPeer(Nz::ENetPeer* a_Peer); + + friend class EnetClient; + friend class EnetServer; +}; + +#undef DeclarePacket + +} // namespace network +} // namespace blitz diff --git a/include/blitz/network/EnetServer.h b/include/blitz/network/EnetServer.h new file mode 100644 index 0000000..29d3a1d --- /dev/null +++ b/include/blitz/network/EnetServer.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace blitz { +namespace network { + +class EnetServer : private NonCopyable { + public: + EnetServer(std::uint16_t port); + ~EnetServer(); + + void Destroy(); + + void BroadcastPacket(const protocol::Packet& a_Packet, Nz::ENetPacketFlags a_Flags); + + EnetConnexion* GetConnexion(std::uint16_t a_PeerId); + + NazaraSignal(OnClientConnect, EnetConnexion& /*a_Peer*/); + NazaraSignal(OnClientDisconnect, EnetConnexion& /*a_Peer*/); + NazaraSignal(OnClientDisconnectTimeout, EnetConnexion& /*a_Peer*/); + + private: + void Update(); + void WorkerThread(); + + void RemoveConnexion(std::uint16_t a_PeerId); + + Nz::ENetHost m_Host; + bool m_Running; + std::thread m_Thread; + std::map m_Connexion; +}; + +} // namespace network +} // namespace blitz diff --git a/include/blitz/protocol/PacketDeclare.h b/include/blitz/protocol/PacketDeclare.h new file mode 100644 index 0000000..d3eac6a --- /dev/null +++ b/include/blitz/protocol/PacketDeclare.h @@ -0,0 +1,19 @@ +#pragma once + +#define DeclareAllPacket() \ +DeclarePacket(PlayerLogin, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(UpdateHealth, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(LoggingSuccess, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(PlayerDeath, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(PlayerJoin, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(PlayerLeave, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(PlayerStats, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(PlayerList, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(ServerConfig, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(ServerTps, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(UpdateGameState, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(KeepAlive, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(Disconnect, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(ChatMessage, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(PlayerPositionAndRotation, Nz::ENetPacketFlag::Reliable); \ +DeclarePacket(PlayerShoot, Nz::ENetPacketFlag::Reliable); diff --git a/include/blitz/protocol/PacketVisitor.h b/include/blitz/protocol/PacketVisitor.h index 7ce8ef7..cb37bf1 100644 --- a/include/blitz/protocol/PacketVisitor.h +++ b/include/blitz/protocol/PacketVisitor.h @@ -1,10 +1,14 @@ #pragma once #include +#include namespace blitz { namespace protocol { +#define DeclarePacket(PacketName, ...) \ + virtual void Visit(const packets::PacketName&) {} + class PacketVisitor { protected: PacketVisitor() {} @@ -13,23 +17,10 @@ class PacketVisitor { public: void Check(const Packet& packet); - virtual void Visit(const packets::PlayerLogin&) {} - virtual void Visit(const packets::UpdateHealth&) {} - virtual void Visit(const packets::LoggingSuccess&) {} - virtual void Visit(const packets::PlayerDeath&) {} - virtual void Visit(const packets::PlayerJoin&) {} - virtual void Visit(const packets::PlayerLeave&) {} - virtual void Visit(const packets::PlayerList&) {} - virtual void Visit(const packets::PlayerStats&) {} - virtual void Visit(const packets::ServerConfig&) {} - virtual void Visit(const packets::ServerTps&) {} - virtual void Visit(const packets::UpdateGameState&) {} - virtual void Visit(const packets::KeepAlive&) {} - virtual void Visit(const packets::Disconnect&) {} - virtual void Visit(const packets::ChatMessage&) {} - virtual void Visit(const packets::PlayerPositionAndRotation&) {} - virtual void Visit(const packets::PlayerShoot&) {} + DeclareAllPacket() }; +#undef DeclarePacket + } // namespace protocol } // namespace blitz diff --git a/include/blitz/protocol/Packets.h b/include/blitz/protocol/Packets.h index 02970b6..897fd14 100644 --- a/include/blitz/protocol/Packets.h +++ b/include/blitz/protocol/Packets.h @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include namespace blitz { namespace protocol { @@ -64,7 +65,7 @@ template class ConcretePacket : public Packet { public: using PacketDataType = Data; - + PacketDataType m_Data; ConcretePacket(const PacketDataType& a_Data = {}); @@ -87,33 +88,16 @@ class ConcretePacket : public Packet { // before including this file // if you want to instantiate templates #ifdef BLITZ_INSTANCIATE_PACKETS -#define DeclarePacket(Type) \ - using Type = ConcretePacket; \ - template class ConcretePacket +#define DeclarePacket(PacketName, ...) \ + using PacketName = ConcretePacket; \ + template class ConcretePacket #else -#define DeclarePacket(Type) using Type = ConcretePacket +#define DeclarePacket(PacketName, ...) using PacketName = ConcretePacket #endif +DeclareAllPacket() - - - -DeclarePacket(PlayerLogin); -DeclarePacket(UpdateHealth); -DeclarePacket(LoggingSuccess); -DeclarePacket(PlayerDeath); -DeclarePacket(PlayerJoin); -DeclarePacket(PlayerLeave); -DeclarePacket(PlayerStats); -DeclarePacket(PlayerList); -DeclarePacket(ServerConfig); -DeclarePacket(ServerTps); -DeclarePacket(UpdateGameState); -DeclarePacket(KeepAlive); -DeclarePacket(Disconnect); -DeclarePacket(ChatMessage); -DeclarePacket(PlayerPositionAndRotation); -DeclarePacket(PlayerShoot); +#undef DeclarePacket } // namespace packets diff --git a/src/blitz/network/EnetClient.cpp b/src/blitz/network/EnetClient.cpp new file mode 100644 index 0000000..9fd7444 --- /dev/null +++ b/src/blitz/network/EnetClient.cpp @@ -0,0 +1,69 @@ +#include + +#include + +namespace blitz { +namespace network { + + + + +EnetClient::EnetClient(const Nz::IpAddress& address) : m_Running(true) { + m_Host.Create(Nz::IpAddress::LoopbackIpV4, 1); + m_Peer = m_Host.Connect(address); + m_Thread = std::thread(&EnetClient::WorkerThread, this); + m_Connexion.SetPeer(m_Peer); +} + +EnetClient::~EnetClient() { + if (m_Peer->IsConnected()) + Disconnect(); + m_Host.Destroy(); + m_Running = false; + m_Thread.join(); +} + +void EnetClient::Disconnect() { + m_Peer->DisconnectNow(0); + m_Connexion.SetPeer(nullptr); +} + +void EnetClient::WorkerThread() { + while (m_Running) { + Update(); + } +} + +void EnetClient::Update() { + Nz::ENetEvent event; + int service = m_Host.Service(&event, 5); + if (service > 0) { + do { + switch (event.type) { + case Nz::ENetEventType::Disconnect: + OnDisconnect(); + break; + + case Nz::ENetEventType::DisconnectTimeout: + OnDisconnectTimeout(); + break; + + case Nz::ENetEventType::OutgoingConnect: + OnConnect(); + break; + + case Nz::ENetEventType::Receive: + m_Connexion.Recieve(event.packet.m_packet->data); + break; + + case Nz::ENetEventType::None: + case Nz::ENetEventType::IncomingConnect: + break; + } + } while (m_Host.CheckEvents(&event)); + } +} + + +} // namespace network +} // namespace blitz diff --git a/src/blitz/network/EnetConnexion.cpp b/src/blitz/network/EnetConnexion.cpp new file mode 100644 index 0000000..ed3a177 --- /dev/null +++ b/src/blitz/network/EnetConnexion.cpp @@ -0,0 +1,48 @@ +#include + +#include +#include + +namespace blitz { +namespace network { + +namespace packets = blitz::protocol::packets; + + +#define DeclarePacket(PacketName, ...) \ + void Visit(const protocol::packets::PacketName& a_Packet) { \ + m_Connexion.On##PacketName(a_Packet.m_Data); \ + } + + + +class PacketDispatcher : public protocol::PacketVisitor { + public: + PacketDispatcher(EnetConnexion& a_Connexion) : m_Connexion(a_Connexion) {} + + DeclareAllPacket(); + + private: + EnetConnexion& m_Connexion; +}; + + + + + +EnetConnexion::EnetConnexion(Nz::ENetPeer* a_Peer) : m_Peer(a_Peer) {} + +void EnetConnexion::SetPeer(Nz::ENetPeer* a_Peer) { + m_Peer = a_Peer; +} + +void EnetConnexion::Recieve(Nz::ByteArray& a_Data) { + auto packet = protocol::PacketSerializer::Deserialize(a_Data); + if (!packet) + return; + PacketDispatcher dispatcher(*this); + dispatcher.Check(*packet.get()); +} + +} // namespace network +} // namespace blitz diff --git a/src/blitz/network/EnetServer.cpp b/src/blitz/network/EnetServer.cpp new file mode 100644 index 0000000..da17961 --- /dev/null +++ b/src/blitz/network/EnetServer.cpp @@ -0,0 +1,94 @@ +#include + +#include + +namespace blitz { +namespace network { + +EnetServer::EnetServer(std::uint16_t port) : m_Running(true) { + m_Host.Create(Nz::NetProtocol::Any, port, 80); + m_Host.AllowsIncomingConnections(true); + m_Thread = std::thread(&EnetServer::WorkerThread, this); +} + +void EnetServer::WorkerThread() { + while (m_Running) { + Update(); + } +} + +EnetServer::~EnetServer() { + if (m_Running) + Destroy(); +} + +void EnetServer::Update() { + Nz::ENetEvent event; + int service = m_Host.Service(&event, 5); + if (service > 0) { + do { + switch (event.type) { + case Nz::ENetEventType::Disconnect: { + EnetConnexion* connexion = GetConnexion(event.peer->GetPeerId()); + if (!connexion) + break; + OnClientDisconnect(*connexion); + break; + } + + case Nz::ENetEventType::DisconnectTimeout: { + EnetConnexion* connexion = GetConnexion(event.peer->GetPeerId()); + if (!connexion) + break; + OnClientDisconnectTimeout(*connexion); + break; + } + + case Nz::ENetEventType::IncomingConnect: { + Nz::ENetPeer* peer = event.peer; + m_Connexion.insert({peer->GetPeerId(), EnetConnexion(peer)}); + OnClientConnect(*GetConnexion(peer->GetPeerId())); + break; + } + + case Nz::ENetEventType::Receive: { + EnetConnexion* connexion = GetConnexion(event.peer->GetPeerId()); + if (!connexion) + break; + connexion->Recieve(event.packet.m_packet->data); + break; + } + + case Nz::ENetEventType::OutgoingConnect: + case Nz::ENetEventType::None: + break; + } + } while (m_Host.CheckEvents(&event)); + } +} + +EnetConnexion* EnetServer::GetConnexion(std::uint16_t a_PeerId) { + auto it = m_Connexion.find(a_PeerId); + + if (it == m_Connexion.end()) + return nullptr; + + return &it->second; +} + +void EnetServer::BroadcastPacket(const protocol::Packet& a_Packet, Nz::ENetPacketFlags a_Flags) { + // m_Host.Broadcast(0, a_Flags, std::move(a_Data)); +} + +void EnetServer::RemoveConnexion(std::uint16_t a_PeerId) { + m_Connexion.erase(a_PeerId); +} + +void EnetServer::Destroy() { + m_Running = false; + m_Thread.join(); + m_Host.Destroy(); +} + +} // namespace network +} // namespace blitz diff --git a/src/blitz/protocol/PacketSerializer.cpp b/src/blitz/protocol/PacketSerializer.cpp index d893ea0..014aabe 100644 --- a/src/blitz/protocol/PacketSerializer.cpp +++ b/src/blitz/protocol/PacketSerializer.cpp @@ -32,6 +32,9 @@ namespace PacketSerializer { void DeserializePacketData(ClassName::PacketDataType& a_Packet) +#define DeclarePacket(PacketName, ...) \ + VisitSerialize(packets::PacketName) + class Serializer : public PacketVisitor { private: Nz::ByteStream& m_Buffer; @@ -44,24 +47,13 @@ class Serializer : public PacketVisitor { Check(a_Packet); } - VisitSerialize(packets::PlayerLogin); - VisitSerialize(packets::UpdateHealth); - VisitSerialize(packets::LoggingSuccess); - VisitSerialize(packets::PlayerDeath); - VisitSerialize(packets::PlayerJoin); - VisitSerialize(packets::PlayerLeave); - VisitSerialize(packets::PlayerList); - VisitSerialize(packets::PlayerStats); - VisitSerialize(packets::ServerConfig); - VisitSerialize(packets::ServerTps); - VisitSerialize(packets::UpdateGameState); - VisitSerialize(packets::KeepAlive); - VisitSerialize(packets::Disconnect); - VisitSerialize(packets::ChatMessage); - VisitSerialize(packets::PlayerPositionAndRotation); - VisitSerialize(packets::PlayerShoot); + DeclareAllPacket() }; +#undef DeclarePacket +#define DeclarePacket(PacketName, ...) \ + VisitDeserialize(packets::PacketName) + class Deserializer : public PacketVisitor { private: Nz::ByteStream& m_Buffer; @@ -83,22 +75,7 @@ class Deserializer : public PacketVisitor { return m_Packet; } - VisitDeserialize(packets::PlayerLogin); - VisitDeserialize(packets::UpdateHealth); - VisitDeserialize(packets::LoggingSuccess); - VisitDeserialize(packets::PlayerDeath); - VisitDeserialize(packets::PlayerJoin); - VisitDeserialize(packets::PlayerLeave); - VisitDeserialize(packets::PlayerList); - VisitDeserialize(packets::PlayerStats); - VisitDeserialize(packets::ServerConfig); - VisitDeserialize(packets::ServerTps); - VisitDeserialize(packets::UpdateGameState); - VisitDeserialize(packets::KeepAlive); - VisitDeserialize(packets::Disconnect); - VisitDeserialize(packets::ChatMessage); - VisitDeserialize(packets::PlayerPositionAndRotation); - VisitDeserialize(packets::PlayerShoot); + DeclareAllPacket() }; diff --git a/test/blitz/protocol/PacketSerializer_test.cpp b/test/blitz/protocol/PacketSerializer_test.cpp index ead8b2a..eefb348 100644 --- a/test/blitz/protocol/PacketSerializer_test.cpp +++ b/test/blitz/protocol/PacketSerializer_test.cpp @@ -3,13 +3,15 @@ #include #include -static int Test() { - for (std::size_t i = 0; i < static_cast(blitz::protocol::PacketType::PACKET_COUNT); i++) { - const auto& packet = blitz::protocol::PacketFactory::CreateReadOnlyPacket(blitz::protocol::PacketType(i)); +namespace bp = blitz::protocol; - Nz::ByteArray buffer = blitz::protocol::PacketSerializer::Serialize(*packet.get()); +static int TestAllPackets() { + for (std::size_t i = 0; i < static_cast(bp::PacketType::PACKET_COUNT); i++) { + const auto& packet = bp::PacketFactory::CreateReadOnlyPacket(bp::PacketType(i)); - blitz::protocol::PacketPtr packet2 = blitz::protocol::PacketSerializer::Deserialize(buffer); + Nz::ByteArray buffer = bp::PacketSerializer::Serialize(*packet.get()); + + bp::PacketPtr packet2 = bp::PacketSerializer::Deserialize(buffer); blitz_test_assert(packet2 != nullptr); @@ -18,6 +20,12 @@ static int Test() { return 0; } +static void Test() { + bp::packets::ChatMessage packet({"caca"}); + Nz::ByteArray buffer = bp::PacketSerializer::Serialize(packet); +} + int main() { - return Test(); + Test(); + return TestAllPackets(); } \ No newline at end of file