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)
{
{
server_socket.reset();
connection.reset();
+ strings.clear();
+ strings.emplace_back();
set_state(DISABLED);
}
}
}
+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<uint16_t>::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<void(unsigned)> callback)
{
if(state!=CONNECTED && state!=SERVER)
}
}
+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<Net::StreamSocket> 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<n_strings; ++i)
+ communicator.send(Messages::InternString{ static_cast<uint16_t>(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);
class ServerConnection: public Connection,
public Net::PacketReceiver<Messages::AddPlayerResponse>,
public Net::PacketReceiver<Messages::PlayerAdded>,
- public Net::PacketReceiver<Messages::PlayerRemoved>
+ public Net::PacketReceiver<Messages::PlayerRemoved>,
+ public Net::PacketReceiver<Messages::InternString>
{
public:
ServerConnection(Networking &, const Net::SockAddr &);
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,
public:
ClientConnection(Networking &, std::unique_ptr<Net::StreamSocket>);
+ void protocol_ready(const Net::Protocol &);
void receive(const Messages::AddPlayerRequest &) override;
};
std::vector<std::unique_ptr<ClientConnection>> clients;
std::vector<Player> players;
unsigned next_id = 1;
+ std::vector<std::string> 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<void(unsigned)>);
private:
Player &create_player(const std::string &, unsigned = 0);