From 864908d48a348c7f690eb72cae88aa09ea4b95cd Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 11 Jun 2023 15:42:25 +0300 Subject: [PATCH] Add string interning to the network protocol This allows transmitting commonly used strings using short IDs. --- source/game/messages.h | 6 +++++ source/game/networking.cpp | 54 +++++++++++++++++++++++++++++++++++++- source/game/networking.h | 10 ++++++- source/game/protocol.cpp | 1 + 4 files changed, 69 insertions(+), 2 deletions(-) diff --git a/source/game/messages.h b/source/game/messages.h index 3b18c33..8efc1bd 100644 --- a/source/game/messages.h +++ b/source/game/messages.h @@ -27,6 +27,12 @@ struct PlayerRemoved std::uint16_t id; }; +struct InternString +{ + std::uint16_t id; + std::string value; +}; + } // namespace Messages } // namespace Msp::Game diff --git a/source/game/networking.cpp b/source/game/networking.cpp index 49b7d39..30f6b48 100644 --- a/source/game/networking.cpp +++ b/source/game/networking.cpp @@ -10,7 +10,9 @@ namespace Msp::Game { Networking::Networking(Director &d): event_source(d.get_event_bus()), io_disp(d.get_io_dispatcher()) -{ } +{ + strings.emplace_back(); +} void Networking::start_server(unsigned port) { @@ -44,6 +46,8 @@ void Networking::disable() { server_socket.reset(); connection.reset(); + strings.clear(); + strings.emplace_back(); set_state(DISABLED); } @@ -74,6 +78,34 @@ void Networking::reap_connections() } } +uint16_t Networking::intern_string(const string &value) +{ + auto i = find(strings, value); + if(i==strings.end()) + { + if(!is_server()) + throw invalid_state("Networking::intern_string"); + if(strings.size()>=numeric_limits::max()) + throw invalid_state("Networking::intern_string"); + i = strings.insert(i, value); + + Messages::InternString msg; + msg.id = strings.size()-1; + msg.value = value; + for(const auto &c: clients) + c->get_communicator().send(msg); + } + + return i-strings.begin(); +} + +const string &Networking::get_string(uint16_t id) const +{ + if(id>=strings.size()) + throw key_error(id); + return strings[id]; +} + void Networking::add_player(const string &name, function callback) { if(state!=CONNECTED && state!=SERVER) @@ -202,13 +234,33 @@ void Networking::ServerConnection::receive(const Messages::PlayerRemoved &remove } } +void Networking::ServerConnection::receive(const Messages::InternString &intern) +{ + if(networking.strings.size()<=intern.id) + networking.strings.resize(intern.id+1); + networking.strings[intern.id] = intern.value; +} + Networking::ClientConnection::ClientConnection(Networking &n, unique_ptr s): Connection(n, move(s)) { + communicator.signal_protocol_ready.connect(sigc::mem_fun(this, &ClientConnection::protocol_ready)); communicator.add_protocol(networking.protocol, *this); } +void Networking::ClientConnection::protocol_ready(const Net::Protocol &p) +{ + if(&p==&networking.protocol) + { + size_t n_strings = networking.strings.size(); + for(size_t i=1; i(i), networking.strings[i] }); + if(Stage *stage = networking.director.get_active_stage()) + communicator.send(Messages::StageActivated{ networking.intern_string(stage->get_name()) }); + } +} + void Networking::ClientConnection::receive(const Messages::AddPlayerRequest &add_req) { Player &player = networking.create_player(add_req.name); diff --git a/source/game/networking.h b/source/game/networking.h index eacba93..b0ee366 100644 --- a/source/game/networking.h +++ b/source/game/networking.h @@ -51,7 +51,8 @@ private: class ServerConnection: public Connection, public Net::PacketReceiver, public Net::PacketReceiver, - public Net::PacketReceiver + public Net::PacketReceiver, + public Net::PacketReceiver { public: ServerConnection(Networking &, const Net::SockAddr &); @@ -63,6 +64,7 @@ private: void receive(const Messages::AddPlayerResponse &) override; void receive(const Messages::PlayerAdded &) override; void receive(const Messages::PlayerRemoved &) override; + void receive(const Messages::InternString &) override; }; class ClientConnection: public Connection, @@ -71,6 +73,7 @@ private: public: ClientConnection(Networking &, std::unique_ptr); + void protocol_ready(const Net::Protocol &); void receive(const Messages::AddPlayerRequest &) override; }; @@ -93,15 +96,20 @@ private: std::vector> clients; std::vector players; unsigned next_id = 1; + std::vector strings; public: Networking(Director &); void start_server(unsigned); void connect_to_server(const std::string &); + bool is_server() const { return state==DISABLED || state==SERVER; } void disable(); void reap_connections(); + 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); private: Player &create_player(const std::string &, unsigned = 0); diff --git a/source/game/protocol.cpp b/source/game/protocol.cpp index 1226521..ec34531 100644 --- a/source/game/protocol.cpp +++ b/source/game/protocol.cpp @@ -10,6 +10,7 @@ Protocol::Protocol() add(&AddPlayerRequest::token, &AddPlayerRequest::name); add(&AddPlayerResponse::token, &AddPlayerResponse::id); add(&PlayerAdded::id, &PlayerAdded::name); + add(&InternString::id, &InternString::value); } } // namespace Msp::Game -- 2.45.2