true atomic EnttWorld

This commit is contained in:
2024-07-23 01:10:20 +02:00
parent 392eaeab83
commit 89d5ad5f54
16 changed files with 61 additions and 35 deletions

View File

@@ -1,9 +1,31 @@
#pragma once
#include <cstdint>
#include <Nazara/Core/EnttWorld.hpp>
namespace blitz {
struct AtomicEnttWorld {
Nz::EnttWorld& m_World;
std::lock_guard<std::mutex> m_LockGuard;
Nz::EnttWorld* operator->() {
return &m_World;
}
};
struct EnttWorld {
Nz::EnttWorld& m_World;
std::mutex m_Mutex;
/**
* \return an AtomicEnttWorld structure which will lock the associated mutex until destruction
* \warning Do not hold more than one instance or the current thread will self lock
*/
operator AtomicEnttWorld() {
return {m_World, std::lock_guard<std::mutex>(m_Mutex)};
}
};
using EntityID = std::uint32_t;
} // namespace blitz

View File

@@ -4,9 +4,6 @@
#include <blitz/network/EnetConnection.h>
namespace blitz {
using EnttWorld = std::atomic<std::shared_ptr<Nz::EnttWorld>>;
namespace protocol {
class PacketHandler : private NonCopyable {

View File

@@ -10,7 +10,7 @@ namespace client {
class Client : private NonCopyable {
public:
Client(std::shared_ptr<Nz::EnttWorld> a_World);
Client(Nz::EnttWorld& a_World);
~Client();
void Connect(const Nz::IpAddress& a_Ip);

View File

@@ -12,7 +12,7 @@ class Server {
* \brief Construct a server
* \pre Two instances of Server should not share the same world
*/
Server(std::uint16_t a_Port, std::shared_ptr<Nz::EnttWorld> a_World);
Server(std::uint16_t a_Port, Nz::EnttWorld& a_World);
~Server();
network::EnetConnection* GetConnection(std::uint16_t a_PeerId);

View File

@@ -2,6 +2,7 @@
#include <Nazara/Core/Time.hpp>
#include <entt/entity/registry.hpp>
#include <blitz/common/Types.h>
namespace blitz {
namespace server {
@@ -10,12 +11,12 @@ class Server;
class DisconectSystem {
public:
DisconectSystem(entt::registry& a_Registry, Server& a_Server);
DisconectSystem(entt::registry&, EnttWorld& a_World, Server& a_Server);
void Update(Nz::Time elapsedTime);
private:
entt::registry& m_Registry;
EnttWorld& m_World;
Server& m_Server;
};

View File

@@ -2,18 +2,19 @@
#include <Nazara/Core/Time.hpp>
#include <entt/entity/registry.hpp>
#include <blitz/common/Types.h>
namespace blitz {
namespace server {
class KeepAliveSystem {
public:
KeepAliveSystem(entt::registry& a_Registry);
KeepAliveSystem(entt::registry&, EnttWorld& a_World);
void Update(Nz::Time elapsedTime);
private:
entt::registry& m_Registry;
EnttWorld& m_World;
};
} // namespace server

View File

@@ -11,9 +11,7 @@
namespace blitz {
namespace client {
Client::Client(std::shared_ptr<Nz::EnttWorld> a_World) {
m_World.store(a_World);
}
Client::Client(Nz::EnttWorld& a_World) : m_World({a_World}) {}
Client::~Client() {
Disconnect();

View File

@@ -11,7 +11,7 @@ LoggingSuccessHandler::LoggingSuccessHandler(network::EnetConnection& a_Connecti
}
void LoggingSuccessHandler::Handle(const blitz::protocol::data::LoggingSuccess& a_LoggingSuccess) {
auto world = m_World.load();
AtomicEnttWorld world = m_World;
auto player = world->CreateEntity();
player.emplace<LocalPlayerComponent>(a_LoggingSuccess.m_PlayerId);
}

View File

@@ -11,7 +11,7 @@ PlayerJoinHandler::PlayerJoinHandler(network::EnetConnection& a_Connection, Entt
}
void PlayerJoinHandler::Handle(const protocol::data::PlayerJoin& a_PlayerJoin) {
auto world = m_World.load();
AtomicEnttWorld world = m_World;
assert(world->GetRegistry().view<LocalPlayerComponent>().size() == 1 && "There should be only one local player !");
auto localPlayer = world->GetRegistry().view<LocalPlayerComponent>().front();

View File

@@ -9,7 +9,7 @@ PlayerLeaveHandler::PlayerLeaveHandler(network::EnetConnection& a_Connection, En
}
void PlayerLeaveHandler::Handle(const protocol::data::PlayerLeave& a_PlayerLeave) {
auto world = m_World.load();
AtomicEnttWorld world = m_World;
entt::entity playerLeft;

View File

@@ -9,7 +9,7 @@ PlayerListHandler::PlayerListHandler(network::EnetConnection& a_Connection, Entt
}
void PlayerListHandler::Handle(const protocol::data::PlayerList& a_PlayerList) {
auto world = m_World.load();
AtomicEnttWorld world = m_World;
for (auto playerInfo : a_PlayerList.m_Players) {
auto player = world->CreateEntity();
player.emplace<PlayerInfoComponent>(playerInfo);

View File

@@ -14,8 +14,7 @@ namespace server {
#define RegisterHandler(Handler) session.m_Handlers.push_back(std::make_unique<Handler>(*session.m_Connection, m_World))
Server::Server(std::uint16_t a_Port, std::shared_ptr<Nz::EnttWorld> a_World) : m_NetworkServer(a_Port) {
m_World.store(a_World);
Server::Server(std::uint16_t a_Port, Nz::EnttWorld& a_World) : m_World({a_World}), m_NetworkServer(a_Port) {
RegisterSystems();
m_NetworkServer.OnClientConnect.Connect(this, &Server::HandleConnect);
m_NetworkServer.OnClientDisconnect.Connect(this, &Server::HandleDisconnect);
@@ -40,7 +39,7 @@ void Server::HandleDisconnect(network::EnetConnection& a_Connection) {
}
void Server::CreateEntity(network::EnetConnection& a_Connection) {
auto world = m_World.load();
AtomicEnttWorld world = m_World;
auto entity = world->CreateEntity();
@@ -48,9 +47,9 @@ void Server::CreateEntity(network::EnetConnection& a_Connection) {
}
void Server::RegisterSystems() {
auto world = m_World.load();
world->AddSystem<KeepAliveSystem>();
world->AddSystem<DisconectSystem>(*this);
AtomicEnttWorld world = m_World;
world->AddSystem<KeepAliveSystem>(m_World);
world->AddSystem<DisconectSystem>(m_World, *this);
auto counter = world->CreateEntity();
counter.emplace<ServerIdCounterComponent>(0);

View File

@@ -16,7 +16,7 @@ KeepAliveHandler::KeepAliveHandler(network::EnetConnection& a_Connection, EnttWo
KeepAliveHandler::~KeepAliveHandler() {}
void KeepAliveHandler::Handle(std::uint16_t a_PeerId, const protocol::data::KeepAlive& a_KeepAlive) {
auto world = m_World.load();
AtomicEnttWorld world = m_World;
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();

View File

@@ -18,7 +18,7 @@ PlayerLoginHandler::PlayerLoginHandler(network::EnetConnection& a_Connection, En
PlayerLoginHandler::~PlayerLoginHandler() {}
void PlayerLoginHandler::Handle(std::uint16_t a_PeerId, const protocol::data::PlayerLogin& a_PlayerLogin) {
auto world = m_World.load();
AtomicEnttWorld world = m_World;
std::vector<PlayerInfoComponent> players;

View File

@@ -8,29 +8,33 @@
namespace blitz {
namespace server {
DisconectSystem::DisconectSystem(entt::registry& a_Registry, Server& a_Server) : m_Registry(a_Registry), m_Server(a_Server) {}
DisconectSystem::DisconectSystem(entt::registry&, EnttWorld& a_World, Server& a_Server) : m_World(a_World), m_Server(a_Server) {}
void DisconectSystem::Update(Nz::Time elapsedTime) {
auto disconnects = m_Registry.view<DisconnectComponent>();
AtomicEnttWorld world = m_World;
entt::registry& registry = world->GetRegistry();
auto disconnects = registry.view<DisconnectComponent>();
// broadcast player leave
for (auto entity : disconnects) {
auto* player = m_Registry.try_get<PlayerInfoComponent>(entity);
auto* player = registry.try_get<PlayerInfoComponent>(entity);
if (player) {
for (auto [entity, connection] : m_Registry.view<EnetConnectionComponent>().each()) {
for (auto [entity, connection] : registry.view<EnetConnectionComponent>().each()) {
connection.m_Connection->SendPlayerLeave({player->m_PlayerId});
}
}
}
// close connections
m_Registry.view<EnetConnectionComponent, DisconnectComponent>().each(
registry.view<EnetConnectionComponent, DisconnectComponent>().each(
[this](auto entity, EnetConnectionComponent& connection, DisconnectComponent disconnect) {
m_Server.CloseConnection(connection.m_Connection->GetPeerId());
});
// remove the entities
m_Registry.destroy(disconnects.begin(), disconnects.end());
registry.destroy(disconnects.begin(), disconnects.end());
}
} // namespace server

View File

@@ -9,11 +9,15 @@
namespace blitz {
namespace server {
KeepAliveSystem::KeepAliveSystem(entt::registry& a_Registry) : m_Registry(a_Registry) {}
KeepAliveSystem::KeepAliveSystem(entt::registry&, EnttWorld& a_World) : m_World(a_World) {}
void KeepAliveSystem::Update(Nz::Time elapsedTime) {
m_Registry.view<KeepAliveSessionComponent, EnetConnectionComponent>().each(
[this](auto entity, auto& keepAliveSession, auto& connection) {
AtomicEnttWorld world = m_World;
entt::registry& registry = world->GetRegistry();
registry.view<KeepAliveSessionComponent, EnetConnectionComponent>().each(
[&registry](auto entity, auto& keepAliveSession, auto& connection) {
auto duration = Nz::GetElapsedMilliseconds() - keepAliveSession.m_LastTime;
if (duration > Nz::Time::Seconds(10)) {
if (keepAliveSession.m_RecievedResponse) {
@@ -28,7 +32,7 @@ void KeepAliveSystem::Update(Nz::Time elapsedTime) {
connection.m_Connection->SendKeepAlive({keepAliveId});
} else {
// We kick the player because he's not responding anymore
m_Registry.emplace<DisconnectComponent>(entity);
registry.emplace<DisconnectComponent>(entity);
}
}
});