]> git.tdb.fi Git - libs/game.git/commitdiff
Avoid sending a packet to the same connection more than once
authorMikko Rasa <tdb@tdb.fi>
Thu, 11 Jan 2024 21:15:25 +0000 (23:15 +0200)
committerMikko Rasa <tdb@tdb.fi>
Thu, 11 Jan 2024 21:45:57 +0000 (23:45 +0200)
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.

source/game/events.h
source/game/networking.cpp
source/game/networking.h
source/game/possessed.cpp
source/game/possessed.h
source/game/replicator.cpp
source/game/replicator.h
source/game/spawner.cpp
source/game/spawner.h

index 436537e08f33300987ab2af3abaeeb617c3a6916..2e8f0af69f66e1eb1eb8f2d0ec89d9032d9879a9 100644 (file)
@@ -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> entity;
-       unsigned player_id;
+       std::uint32_t player_id;
 };
 
 struct RemotePlayerExited
 {
-       unsigned id;
+       std::uint32_t id;
 };
 
 } // namespace Events
index 7228a827dd672322eef259593b6a729d532033c6..fb3d977219b944dfed61567597e1f25cb63428f8 100644 (file)
@@ -130,7 +130,7 @@ const string &Networking::get_string(uint16_t id) const
        return strings[id];
 }
 
-void Networking::add_player(const string &name, function<void(unsigned)> callback)
+void Networking::add_player(const string &name, function<void(uint32_t)> callback)
 {
        if(state!=CONNECTED && state!=SERVER)
                throw invalid_state("Networking::add_player");
@@ -160,10 +160,15 @@ void Networking::add_player(const string &name, function<void(unsigned)> 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<unsigned>(removed.id), &Player::id);
+       auto i = lower_bound_member(networking.players, static_cast<uint32_t>(removed.id), &Player::id);
        if(i!=networking.players.end())
        {
                networking.event_source.emit<Events::NetworkPlayerDeparted>(i->id);
@@ -315,7 +320,8 @@ void Networking::ServerConnection::receive(const Messages::StageActivated &activ
 
 
 Networking::ClientConnection::ClientConnection(Networking &n, unique_ptr<Net::StreamSocket> 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)
index f3d8e82e9fec0594ee4b94f0b47f286e754a1fc9..5ee173451e66b7657c488c025116f381ff0696c9 100644 (file)
@@ -99,6 +99,7 @@ private:
        {
        private:
                std::string active_stage;
+               std::uint16_t id = 0;
 
        public:
                ClientConnection(Networking &, std::unique_ptr<Net::StreamSocket>);
@@ -111,12 +112,13 @@ private:
        struct Player
        {
                ClientConnection *owner = nullptr;
-               unsigned id = 0;
+               std::uint32_t id = 0;
                std::string name;
-               std::function<void(unsigned)> add_callback;
+               std::function<void(std::uint32_t)> 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<ServerConnection> connection;
        std::vector<std::unique_ptr<ClientConnection>> clients;
        std::vector<Player> players;
-       unsigned next_player_id = 1;
+       std::uint16_t next_client_id = 1;
+       std::uint16_t next_player_id = 1;
        std::vector<std::string> 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(unsigned)>);
+       void add_player(const std::string &, std::function<void(std::uint32_t)>);
 private:
-       Player &create_player(const std::string &, unsigned = 0);
+       Player &create_player(const std::string &, std::uint32_t = 0);
 
 public:
        template<typename P>
        void send(const P &);
 
        template<typename P>
-       void send(unsigned, const P &);
+       void send(std::uint32_t, const P &);
+
+       template<typename P, typename F>
+       void send(const P &, F &&);
 
 private:
        void set_state(State);
@@ -204,7 +210,7 @@ void Networking::send(const P &packet)
 }
 
 template<typename P>
-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<typename P, typename F>
+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 {
 
index cc52e1cf45b5183f9d3fa11f06ec73ad47576fcd..3e52cdeb88a94152a82c9f2c26dabee862039f75 100644 (file)
@@ -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;
index 54350dabe009a613cc047cd83b19a09d9d59f5eb..e49eb322a5c1809d3a2b5f5e734d3b99114fcdb3 100644 (file)
@@ -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<Entity> 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();
 };
index 5a90aefe05f1ffbaf4a55a8c103c3d8a389f7716..acdc6d0e2f3c5897a44db120991351c5aadaf85d 100644 (file)
@@ -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;
index 1efc30bf288495fe5ab3779a40da11360bd981f2..c9c918f9b07c5e70c088f997309f08fd91a40f1b 100644 (file)
@@ -39,7 +39,7 @@ private:
        const Net::Protocol &protocol;
        std::vector<Spawner *> spawners;
        std::vector<ReplicatedEntity> entities;
-       std::vector<unsigned> players;
+       std::vector<std::uint32_t> 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<typename P>
@@ -60,7 +60,7 @@ public:
        void send(Handle<Entity>, const P &);
 
        template<typename P>
-       void send(unsigned, const P &);
+       void send(std::uint32_t, const P &);
 
        Handle<Entity> 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<P> &recv)
 template<typename P>
 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<players.size() && players[i]==player_id)
+               {
+                       ++i;
+                       return true;
+               }
+               return false;
+       });
 }
 
 template<typename P>
@@ -102,7 +108,7 @@ void Replicator::send(Handle<Entity> entity, const P &packet)
 }
 
 template<typename P>
-void Replicator::send(unsigned target, const P &packet)
+void Replicator::send(std::uint32_t target, const P &packet)
 {
        if(target)
                networking.send(target, packet);
index 5053999f0534c43219ee48081d8e5dff636e0db8..e1281bec9e9e14b5b71f8a594b7875d3e0c06862 100644 (file)
@@ -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> entity, unsigned target) const
+void Spawner::notify_spawn_sent(Handle<Entity> entity, uint32_t target) const
 {
        handler.spawn_sent(entity, target);
 }
index f3f48cf8f69623591a184de4781f1688e68bea15..e9d9673dded076dfe04b6dd5cb214a0bef618072 100644 (file)
@@ -24,7 +24,7 @@ class MSPGAME_API SpawningHandler
 {
 public:
        virtual void spawned(Owned<Entity>) = 0;
-       virtual void spawn_sent(Handle<Entity>, unsigned) { }
+       virtual void spawn_sent(Handle<Entity>, std::uint32_t) { }
 };
 
 
@@ -78,7 +78,7 @@ private:
        void spawn(const SpawnableType &, const std::string &, const TransformValues &);
 
 public:
-       void notify_spawn_sent(Handle<Entity>, unsigned) const;
+       void notify_spawn_sent(Handle<Entity>, std::uint32_t) const;
 };