fully implement KeepAlive behavior

This commit is contained in:
2024-07-21 20:59:13 +02:00
parent 36a2e67ac4
commit 92a2e53036
25 changed files with 513 additions and 61 deletions

View File

@@ -1,18 +1,13 @@
#include <blitz/network/EnetClient.h>
#include <iostream>
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);
m_Connection.SetPeer(m_Peer);
}
EnetClient::~EnetClient() {
@@ -25,7 +20,7 @@ EnetClient::~EnetClient() {
void EnetClient::Disconnect() {
m_Peer->DisconnectNow(0);
m_Connexion.SetPeer(nullptr);
m_Connection.SetPeer(nullptr);
}
void EnetClient::WorkerThread() {
@@ -53,7 +48,7 @@ void EnetClient::Update() {
break;
case Nz::ENetEventType::Receive:
m_Connexion.Recieve(event.packet.m_packet->data);
m_Connection.Recieve(event.packet.m_packet->data);
break;
case Nz::ENetEventType::None:

View File

@@ -1,4 +1,4 @@
#include <blitz/network/EnetConnexion.h>
#include <blitz/network/EnetConnection.h>
#include <Nazara/Network/ENetPeer.hpp>
#include <blitz/protocol/PacketSerializer.h>
@@ -11,20 +11,17 @@ namespace packets = blitz::protocol::packets;
#define DeclarePacket(PacketName, ...) \
void Visit(const protocol::packets::PacketName& a_Packet) { \
m_Connexion.On##PacketName(a_Packet.m_Data); \
}
void Visit(const protocol::packets::PacketName& a_Packet) { m_Connection.On##PacketName(a_Packet.m_Data); }
class PacketDispatcher : public protocol::PacketVisitor {
public:
PacketDispatcher(EnetConnexion& a_Connexion) : m_Connexion(a_Connexion) {}
PacketDispatcher(EnetConnection& a_Connection) : m_Connection(a_Connection) {}
DeclareAllPacket()
private:
EnetConnexion& m_Connexion;
private : EnetConnection& m_Connection;
};
#undef DeclarePacket
@@ -33,19 +30,24 @@ class PacketDispatcher : public protocol::PacketVisitor {
EnetConnexion::EnetConnexion(Nz::ENetPeer* a_Peer) : m_Peer(a_Peer) {}
EnetConnection::EnetConnection(Nz::ENetPeer* a_Peer) : m_Peer(a_Peer) {}
void EnetConnexion::SetPeer(Nz::ENetPeer* a_Peer) {
void EnetConnection::SetPeer(Nz::ENetPeer* a_Peer) {
m_Peer = a_Peer;
}
bool EnetConnexion::IsConnected() const {
std::uint16_t EnetConnection::GetPeerId() const {
assert(m_Peer);
return m_Peer->GetPeerId();
}
bool EnetConnection::IsConnected() const {
if (!m_Peer)
return false;
return m_Peer->IsConnected();
}
void EnetConnexion::Recieve(Nz::ByteArray& a_Data) {
void EnetConnection::Recieve(Nz::ByteArray& a_Data) {
auto packet = protocol::PacketSerializer::Deserialize(a_Data);
if (!packet)
return;
@@ -54,8 +56,8 @@ void EnetConnexion::Recieve(Nz::ByteArray& a_Data) {
}
#define DeclarePacket(Name, NFlag, ...) \
void EnetConnexion::Send##Name(const blitz::protocol::data::Name& a_##Name) const { \
m_Peer->Send(0, Nz::ENetPacketFlag::NFlag, protocol::PacketSerializer::Serialize(protocol::packets::Name(a_##Name))); \
void EnetConnection::Send##Name(const blitz::protocol::data::Name& a_##Name) const { \
m_Peer->Send(0, Nz::ENetPacketFlag::NFlag, protocol::PacketSerializer::Serialize(protocol::packets::Name(a_##Name))); \
}
DeclareAllPacket()

View File

@@ -29,34 +29,36 @@ void EnetServer::Update() {
do {
switch (event.type) {
case Nz::ENetEventType::Disconnect: {
EnetConnexion* connexion = GetConnexion(event.peer->GetPeerId());
if (!connexion)
EnetConnection* connection = GetConnection(event.peer->GetPeerId());
if (!connection)
break;
OnClientDisconnect(*connexion);
OnClientDisconnect(*connection);
RemoveConnection(connection->GetPeerId());
break;
}
case Nz::ENetEventType::DisconnectTimeout: {
EnetConnexion* connexion = GetConnexion(event.peer->GetPeerId());
if (!connexion)
EnetConnection* connection = GetConnection(event.peer->GetPeerId());
if (!connection)
break;
OnClientDisconnectTimeout(*connexion);
OnClientDisconnectTimeout(*connection);
RemoveConnection(connection->GetPeerId());
break;
}
case Nz::ENetEventType::IncomingConnect: {
Nz::ENetPeer* peer = event.peer;
auto con = std::make_unique<EnetConnexion>(peer);
m_Connexion.insert({peer->GetPeerId(), std::move(con)});
OnClientConnect(*GetConnexion(peer->GetPeerId()));
auto con = std::make_unique<EnetConnection>(peer);
m_Connections.insert({peer->GetPeerId(), std::move(con)});
OnClientConnect(*GetConnection(peer->GetPeerId()));
break;
}
case Nz::ENetEventType::Receive: {
EnetConnexion* connexion = GetConnexion(event.peer->GetPeerId());
if (!connexion)
EnetConnection* connection = GetConnection(event.peer->GetPeerId());
if (!connection)
break;
connexion->Recieve(event.packet.m_packet->data);
connection->Recieve(event.packet.m_packet->data);
break;
}
@@ -68,21 +70,28 @@ void EnetServer::Update() {
}
}
EnetConnexion* EnetServer::GetConnexion(std::uint16_t a_PeerId) {
auto it = m_Connexion.find(a_PeerId);
EnetConnection* EnetServer::GetConnection(std::uint16_t a_PeerId) {
auto it = m_Connections.find(a_PeerId);
if (it == m_Connexion.end())
if (it == m_Connections.end())
return nullptr;
return it->second.get();
}
/*void EnetServer::BroadcastPacket(const protocol::Packet& a_Packet, Nz::ENetPacketFlags a_Flags) {
m_Host.Broadcast(0, a_Flags, std::move(a_Data));
}*/
void EnetServer::CloseConnection(std::uint16_t a_PeerId) {
auto connection = GetConnection(a_PeerId);
void EnetServer::RemoveConnexion(std::uint16_t a_PeerId) {
m_Connexion.erase(a_PeerId);
if (!connection)
return;
connection->m_Peer->DisconnectNow(0);
OnClientDisconnect(*connection);
RemoveConnection(a_PeerId);
}
void EnetServer::RemoveConnection(std::uint16_t a_PeerId) {
m_Connections.erase(a_PeerId);
}
void EnetServer::Destroy() {

View File

@@ -0,0 +1,12 @@
#include <blitz/protocol/PacketHandler.h>
namespace blitz {
namespace protocol {
PacketHandler::PacketHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) :
m_Connection(a_Connection), m_World(a_World) {}
PacketHandler::~PacketHandler() {}
} // namespace protocol
} // namespace blitz

View File

@@ -4,8 +4,6 @@
#include <blitz/protocol/PacketFactory.h>
#include <blitz/protocol/PacketVisitor.h>
#include <iostream>
namespace blitz {
namespace protocol {

45
src/client/Client.cpp Normal file
View File

@@ -0,0 +1,45 @@
#include <client/Client.h>
#include <client/handlers/KeepAliveHandler.h>
namespace blitz {
namespace client {
Client::Client() : m_World() {
m_World.store(std::make_shared<Nz::EnttWorld>());
}
Client::~Client() {
Disconnect();
}
void Client::BindHandlers() {
m_Handlers.push_back(std::make_unique<KeepAliveHandler>(m_NetworkClient->GetConnection(), m_World));
}
void Client::UnbindHandlers() {
m_Handlers.clear();
}
void Client::Connect(const Nz::IpAddress& a_Ip) {
m_NetworkClient = std::make_unique<network::EnetClient>(a_Ip);
BindHandlers();
}
void Client::Disconnect() {
if (!m_NetworkClient)
return;
m_NetworkClient->Disconnect();
UnbindHandlers();
m_NetworkClient.reset(nullptr);
}
bool Client::IsConnected() {
if (!m_NetworkClient)
return false;
return m_NetworkClient->GetConnection().IsConnected();
}
} // namespace client
} // namespace blitz

View File

@@ -0,0 +1,15 @@
#include <client/handlers/KeepAliveHandler.h>
namespace blitz {
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); });
}
KeepAliveHandler::~KeepAliveHandler() {}
} // namespace client
} // namespace blitz

70
src/server/Server.cpp Normal file
View File

@@ -0,0 +1,70 @@
#include <server/Server.h>
#include <server/components/EnetConnection.h>
#include <server/components/KeepAliveSession.h>
#include <server/handlers/KeepAliveHandler.h>
#include <server/systems/DisconnectSystem.h>
#include <server/systems/KeepAliveSystem.h>
namespace blitz {
namespace server {
Server::Server(std::uint16_t a_Port, std::shared_ptr<Nz::EnttWorld> a_World) : m_NetworkServer(a_Port) {
m_World.store(a_World);
RegisterSystems();
m_NetworkServer.OnClientConnect.Connect(this, &Server::HandleConnect);
m_NetworkServer.OnClientDisconnect.Connect(this, &Server::HandleDisconnect);
m_NetworkServer.OnClientDisconnectTimeout.Connect(this, &Server::HandleDisconnect);
}
Server::~Server() {}
void Server::HandleConnect(network::EnetConnection& a_Connection) {
Session newSession;
newSession.m_Connection = &a_Connection;
RegisterHandlers(newSession);
m_Sessions.insert({a_Connection.GetPeerId(), std::move(newSession)});
CreateEntity(a_Connection);
}
void Server::HandleDisconnect(network::EnetConnection& a_Connection) {
m_Sessions.erase(a_Connection.GetPeerId());
}
void Server::CreateEntity(network::EnetConnection& a_Connection) {
auto world = m_World.load();
auto entity = world->CreateEntity();
entity.emplace<KeepAliveSessionComponent>(a_Connection.GetPeerId(), 69, Nz::GetElapsedMilliseconds(), true);
entity.emplace<EnetConnectionComponent>(&a_Connection);
}
void Server::RegisterSystems() {
auto world = m_World.load();
world->AddSystem<KeepAliveSystem>();
world->AddSystem<DisconectSystem>(*this);
}
void Server::RegisterHandlers(Session& session) {
session.m_Handlers.push_back(std::make_unique<KeepAliveHandler>(*session.m_Connection, m_World));
}
network::EnetConnection* Server::GetConnection(std::uint16_t a_PeerId) {
auto it = m_Sessions.find(a_PeerId);
if (it == m_Sessions.end())
return nullptr;
return it->second.m_Connection;
}
void Server::CloseConnection(std::uint16_t a_PeerId) {
m_NetworkServer.CloseConnection(a_PeerId);
}
} // namespace server
} // namespace blitz

View File

@@ -0,0 +1,29 @@
#include <server/handlers/KeepAliveHandler.h>
#include <server/components/KeepAliveSession.h>
#include <Nazara/Core/Time.hpp>
namespace blitz {
namespace server {
KeepAliveHandler::KeepAliveHandler(network::EnetConnection& a_Connection, EnttWorld& a_World) :
protocol::PacketHandler(a_Connection, a_World) {
m_Slot.Connect(a_Connection.OnKeepAlive,
[this](const protocol::data::KeepAlive& a_KeepAlive) { Handle(m_Connection.GetPeerId(), a_KeepAlive); });
}
KeepAliveHandler::~KeepAliveHandler() {}
void KeepAliveHandler::Handle(std::uint16_t a_PeerId, const protocol::data::KeepAlive& a_KeepAlive) {
auto world = m_World.load();
world->GetRegistry().view<KeepAliveSessionComponent>().each([a_PeerId, &a_KeepAlive](auto& keepAliveSession) {
if (keepAliveSession.m_PeerId == a_PeerId && keepAliveSession.m_LastKeepAliveId == a_KeepAlive.m_KeepAliveId) {
keepAliveSession.m_LastTime = Nz::GetElapsedMilliseconds();
keepAliveSession.m_RecievedResponse = true;
}
});
}
} // namespace server
} // namespace blitz

View File

@@ -0,0 +1,25 @@
#include <server/systems/DisconnectSystem.h>
#include <server/components/Disconnect.h>
#include <server/components/EnetConnection.h>
#include <server/Server.h>
namespace blitz {
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) {
m_Registry.view<EnetConnectionComponent, DisconnectComponent>().each(
[this](auto entity, EnetConnectionComponent& connection, DisconnectComponent disconnect) {
m_Server.CloseConnection(connection.m_Connection->GetPeerId());
});
// remove the entities
auto it = m_Registry.view<DisconnectComponent>();
m_Registry.destroy(it.begin(), it.end());
}
} // namespace server
} // namespace blitz

View File

@@ -0,0 +1,38 @@
#include <server/systems/KeepAliveSystem.h>
#include <server/components/Disconnect.h>
#include <server/components/EnetConnection.h>
#include <server/components/KeepAliveSession.h>
#include <random>
namespace blitz {
namespace server {
KeepAliveSystem::KeepAliveSystem(entt::registry& a_Registry) : m_Registry(a_Registry) {}
void KeepAliveSystem::Update(Nz::Time elapsedTime) {
m_Registry.view<KeepAliveSessionComponent, EnetConnectionComponent>().each(
[this](auto entity, auto& keepAliveSession, auto& connection) {
auto duration = Nz::GetElapsedMilliseconds() - keepAliveSession.m_LastTime;
if (duration > Nz::Time::Seconds(10)) {
if (keepAliveSession.m_RecievedResponse) {
keepAliveSession.m_RecievedResponse = false;
keepAliveSession.m_LastTime = Nz::GetElapsedMilliseconds();
std::random_device rd;
std::uniform_int_distribution<std::uint64_t> dis(0, std::numeric_limits<std::uint64_t>::max());
std::uint64_t keepAliveId = dis(rd);
keepAliveSession.m_LastKeepAliveId = keepAliveId;
connection.m_Connection->SendKeepAlive({keepAliveId});
} else {
// We kick the player because he's not responding anymore
m_Registry.emplace<DisconnectComponent>(entity);
}
}
});
}
} // namespace server
} // namespace blitz