From: Mikko Rasa Date: Thu, 11 Jan 2024 21:15:25 +0000 (+0200) Subject: Avoid sending a packet to the same connection more than once X-Git-Url: https://git.tdb.fi/?a=commitdiff_plain;h=61e45174d9e487800845a36c77dac83ad3a5cb0c;p=libs%2Fgame.git Avoid sending a packet to the same connection more than once To keep things efficient, player IDs are now stored as 32-bit quantities, with the high 16 bits containing an ID for the client connection. Only the lower 16 bits are transmitted on the network to avoid leaking information on which players share the same connection. --- diff --git a/source/game/events.h b/source/game/events.h index 436537e..2e8f0af 100644 --- a/source/game/events.h +++ b/source/game/events.h @@ -17,13 +17,13 @@ struct NetworkStateChanged; struct NetworkPlayerArrived { - unsigned id; + std::uint32_t id; std::string name; }; struct NetworkPlayerDeparted { - unsigned id; + std::uint32_t id; }; struct EntityCreated @@ -74,18 +74,18 @@ struct CameraChanged struct RemotePlayerEntered { - unsigned id; + std::uint32_t id; }; struct PossessionChanged { Handle entity; - unsigned player_id; + std::uint32_t player_id; }; struct RemotePlayerExited { - unsigned id; + std::uint32_t id; }; } // namespace Events diff --git a/source/game/networking.cpp b/source/game/networking.cpp index 7228a82..fb3d977 100644 --- a/source/game/networking.cpp +++ b/source/game/networking.cpp @@ -130,7 +130,7 @@ const string &Networking::get_string(uint16_t id) const return strings[id]; } -void Networking::add_player(const string &name, function callback) +void Networking::add_player(const string &name, function callback) { if(state!=CONNECTED && state!=SERVER) throw invalid_state("Networking::add_player"); @@ -160,10 +160,15 @@ void Networking::add_player(const string &name, function callbac } } -Networking::Player &Networking::create_player(const string &name, unsigned id) +Networking::Player &Networking::create_player(const string &name, uint32_t id) { - Player &player = players.emplace_back(); - player.id = (id ? id : next_player_id++); + if(!(id&PLAYER_ID_MASK)) + id |= next_player_id++; + + auto i = lower_bound_member(players, id, &Player::id); + + Player &player = *players.emplace(i); + player.id = id; player.name = name; return player; } @@ -291,7 +296,7 @@ void Networking::ServerConnection::receive(const Messages::PlayerAdded &added) void Networking::ServerConnection::receive(const Messages::PlayerRemoved &removed) { - auto i = find_member(networking.players, static_cast(removed.id), &Player::id); + auto i = lower_bound_member(networking.players, static_cast(removed.id), &Player::id); if(i!=networking.players.end()) { networking.event_source.emit(i->id); @@ -315,7 +320,8 @@ void Networking::ServerConnection::receive(const Messages::StageActivated &activ Networking::ClientConnection::ClientConnection(Networking &n, unique_ptr s): - Connection(n, move(s)) + Connection(n, move(s)), + id(networking.next_client_id++) { communicator.signal_protocol_ready.connect(sigc::mem_fun(this, &ClientConnection::protocol_ready)); communicator.add_protocol(networking.core_protocol, *this); @@ -343,16 +349,16 @@ void Networking::ClientConnection::protocol_ready(const Net::Protocol &p) void Networking::ClientConnection::receive(const Messages::AddPlayerRequest &add_req) { - Player &player = networking.create_player(add_req.name); + Player &player = networking.create_player(add_req.name, id<<16); player.owner = this; Messages::AddPlayerResponse add_resp; add_resp.token = add_req.token; - add_resp.id = player.id; + add_resp.id = player.id&PLAYER_ID_MASK; communicator.send(add_resp); Messages::PlayerAdded added; - added.id = player.id; + added.id = player.id&PLAYER_ID_MASK; added.name = player.name; for(const auto &c: networking.clients) if(c.get()!=this) diff --git a/source/game/networking.h b/source/game/networking.h index f3d8e82..5ee1734 100644 --- a/source/game/networking.h +++ b/source/game/networking.h @@ -99,6 +99,7 @@ private: { private: std::string active_stage; + std::uint16_t id = 0; public: ClientConnection(Networking &, std::unique_ptr); @@ -111,12 +112,13 @@ private: struct Player { ClientConnection *owner = nullptr; - unsigned id = 0; + std::uint32_t id = 0; std::string name; - std::function add_callback; + std::function add_callback; }; - static constexpr unsigned ID_PENDING = 0x8000; + static constexpr std::uint32_t PLAYER_ID_MASK = 0xFFFF; + static constexpr std::uint32_t ID_PENDING = 0x8000; Director &director; EventSource event_source; @@ -129,7 +131,8 @@ private: std::unique_ptr connection; std::vector> clients; std::vector players; - unsigned next_player_id = 1; + std::uint16_t next_client_id = 1; + std::uint16_t next_player_id = 1; std::vector strings; Connection *current_sender = nullptr; @@ -155,16 +158,19 @@ public: std::uint16_t intern_string(const std::string &); const std::string &get_string(std::uint16_t) const; - void add_player(const std::string &, std::function); + void add_player(const std::string &, std::function); private: - Player &create_player(const std::string &, unsigned = 0); + Player &create_player(const std::string &, std::uint32_t = 0); public: template void send(const P &); template - void send(unsigned, const P &); + void send(std::uint32_t, const P &); + + template + void send(const P &, F &&); private: void set_state(State); @@ -204,7 +210,7 @@ void Networking::send(const P &packet) } template -void Networking::send(unsigned target, const P &packet) +void Networking::send(std::uint32_t target, const P &packet) { if(state!=SERVER) throw invalid_state("Networking::send"); @@ -216,6 +222,25 @@ void Networking::send(unsigned target, const P &packet) i->owner->get_communicator().send(packet); } +template +void Networking::send(const P &packet, F &&filter) +{ + if(state!=SERVER) + throw invalid_state("Networking::send"); + + for(auto i=players.begin(); i!=players.end(); ) + { + if(filter(i->id)) + { + ClientConnection *client = i->owner; + client->get_communicator().send(packet); + for(; (i!=players.end() && i->owner==client); ++i) ; + } + else + ++i; + } +} + namespace Events { diff --git a/source/game/possessed.cpp b/source/game/possessed.cpp index cc52e1c..3e52cde 100644 --- a/source/game/possessed.cpp +++ b/source/game/possessed.cpp @@ -1,8 +1,10 @@ #include "possessed.h" +using namespace std; + namespace Msp::Game { -void Possessed::set_player_id(unsigned p) +void Possessed::set_player_id(uint32_t p) { if(p!=player_id) changed = true; diff --git a/source/game/possessed.h b/source/game/possessed.h index 54350da..e49eb32 100644 --- a/source/game/possessed.h +++ b/source/game/possessed.h @@ -9,14 +9,14 @@ namespace Msp::Game { class MSPGAME_API Possessed: public Component { private: - unsigned player_id = 0; + std::uint32_t player_id = 0; bool changed = false; public: Possessed(Handle e): Component(e) { } - void set_player_id(unsigned); - unsigned get_player_id() const { return player_id; } + void set_player_id(std::uint32_t); + std::uint32_t get_player_id() const { return player_id; } bool has_changed() const { return changed; } void clear_changed(); }; diff --git a/source/game/replicator.cpp b/source/game/replicator.cpp index 5a90aef..acdc6d0 100644 --- a/source/game/replicator.cpp +++ b/source/game/replicator.cpp @@ -37,9 +37,10 @@ void Replicator::add_spawner(Spawner &spawner, const string &type) spawners.push_back(&spawner); } -void Replicator::add_target_player(unsigned id) +void Replicator::add_target_player(uint32_t id) { - players.push_back(id); + auto i = lower_bound(players, id); + players.insert(i, id); for(const ReplicatedEntity &e: entities) send_spawn(e, id); } @@ -101,7 +102,7 @@ void Replicator::component_created(const Events::ComponentCreated &event) } } -void Replicator::send_spawn(const ReplicatedEntity &re, unsigned target) +void Replicator::send_spawn(const ReplicatedEntity &re, uint32_t target) { if(!target && players.empty()) return; @@ -123,7 +124,7 @@ void Replicator::send_spawn(const ReplicatedEntity &re, unsigned target) send_possession(re, target); } -void Replicator::send_possession(const ReplicatedEntity &re, unsigned target) +void Replicator::send_possession(const ReplicatedEntity &re, uint32_t target) { if(!target && players.empty()) return; diff --git a/source/game/replicator.h b/source/game/replicator.h index 1efc30b..c9c918f 100644 --- a/source/game/replicator.h +++ b/source/game/replicator.h @@ -39,7 +39,7 @@ private: const Net::Protocol &protocol; std::vector spawners; std::vector entities; - std::vector players; + std::vector players; std::uint32_t next_entity_id = 1; std::uint32_t received_entity_id = Zygote::NO_ID; @@ -47,7 +47,7 @@ public: Replicator(Stage &, Networking &); void add_spawner(Spawner &, const std::string &); - void add_target_player(unsigned); + void add_target_player(std::uint32_t); bool is_server() const { return networking.is_server(); } template @@ -60,7 +60,7 @@ public: void send(Handle, const P &); template - void send(unsigned, const P &); + void send(std::uint32_t, const P &); Handle find_entity(std::uint32_t) const; @@ -69,8 +69,8 @@ public: private: void component_created(const Events::ComponentCreated &); - void send_spawn(const ReplicatedEntity &, unsigned); - void send_possession(const ReplicatedEntity &, unsigned); + void send_spawn(const ReplicatedEntity &, std::uint32_t); + void send_possession(const ReplicatedEntity &, std::uint32_t); void receive(const Messages::SpawnEntity &) override; void receive(const Messages::GrantPossession &) override; @@ -85,8 +85,14 @@ void Replicator::add_receiver(Net::PacketReceiver

&recv) template void Replicator::send(const P &packet) { - for(unsigned p: players) - networking.send(p, packet); + networking.send(packet, [this, i=0u](std::uint32_t player_id) mutable { + if(i @@ -102,7 +108,7 @@ void Replicator::send(Handle entity, const P &packet) } template -void Replicator::send(unsigned target, const P &packet) +void Replicator::send(std::uint32_t target, const P &packet) { if(target) networking.send(target, packet); diff --git a/source/game/spawner.cpp b/source/game/spawner.cpp index 5053999..e1281be 100644 --- a/source/game/spawner.cpp +++ b/source/game/spawner.cpp @@ -51,7 +51,7 @@ void Spawner::spawn(const SpawnableType &type, const string &setup_name, const T handler.spawned(move(entity)); } -void Spawner::notify_spawn_sent(Handle entity, unsigned target) const +void Spawner::notify_spawn_sent(Handle entity, uint32_t target) const { handler.spawn_sent(entity, target); } diff --git a/source/game/spawner.h b/source/game/spawner.h index f3f48cf..e9d9673 100644 --- a/source/game/spawner.h +++ b/source/game/spawner.h @@ -24,7 +24,7 @@ class MSPGAME_API SpawningHandler { public: virtual void spawned(Owned) = 0; - virtual void spawn_sent(Handle, unsigned) { } + virtual void spawn_sent(Handle, std::uint32_t) { } }; @@ -78,7 +78,7 @@ private: void spawn(const SpawnableType &, const std::string &, const TransformValues &); public: - void notify_spawn_sent(Handle, unsigned) const; + void notify_spawn_sent(Handle, std::uint32_t) const; };