Klaus Halfmann has proposed merging lp:~widelands-dev/widelands/refactor_gamehost into lp:widelands.
Commit message: Refactoring of gamehost.cc for better readability. Requested reviews: Widelands Developers (widelands-dev) For more details, see: https://code.launchpad.net/~widelands-dev/widelands/refactor_gamehost/+merge/370320 Refactoring of gamehost.cc for better readability, should be completly compatible with trunk. Please contact me, so we can do some testing vs. trunk. -- Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/refactor_gamehost into lp:widelands.
=== modified file 'src/network/gamehost.cc' --- src/network/gamehost.cc 2019-05-26 11:39:41 +0000 +++ src/network/gamehost.cc 2019-07-18 14:48:27 +0000 @@ -903,7 +903,8 @@ } /** - * If the host sends a chat message with formation /kick <name> <reason> + * If the host sends a chat message with formation /kick <name> <reason>. + * * This function will handle this command and try to kick the user. */ void GameHost::kick_user(uint32_t client, const std::string& reason) { @@ -980,18 +981,22 @@ return false; // if there is one client that is currently receiving a file, we can not launch. + + std::vector<UserSettings> &users = d->settings.users; + for (std::vector<Client>::iterator j = d->clients.begin(); j != d->clients.end(); ++j) { - if (j->usernum == -1) { + int usernum = j->usernum; + if (usernum == -1) { return false; } - if (!d->settings.users[j->usernum].ready) { + if (users[j->usernum].ready) { return false; } } // all players must be connected to a controller (human/ai) or be closed. // but not all should be closed! - bool one_not_closed = false; + bool one_not_closed = false; // TODO(k.halfmann): check this logic for (PlayerSettings& setting : d->settings.players) { if (setting.state != PlayerSettings::State::kClosed) one_not_closed = true; @@ -1011,14 +1016,15 @@ std::vector<PlayerSettings>::size_type oldplayers = d->settings.players.size(); - SendPacket packet; - // Care about the host if (static_cast<int32_t>(maxplayers) <= d->settings.playernum && d->settings.playernum != UserSettings::none()) { set_player_number(UserSettings::none()); } + SendPacket packet; + + // Drop players not matching map any longer while (oldplayers > maxplayers) { --oldplayers; for (uint16_t i = 1; i < d->settings.users.size(); ++i) @@ -1033,16 +1039,13 @@ d->clients.at(j).playernum = UserSettings::none(); // Broadcast change - packet.reset(); - packet.unsigned_8(NETCMD_SETTING_USER); - packet.unsigned_32(i); - write_setting_user(packet, i); - broadcast(packet); + broadcast_setting_user(packet, d->clients.at(j).usernum); } } d->settings.players.resize(maxplayers); + // Open slots for new players found on the map. while (oldplayers < maxplayers) { PlayerSettings& player = d->settings.players.at(oldplayers); player.state = PlayerSettings::State::kOpen; @@ -1110,9 +1113,12 @@ } } +// TODO(k.halfmann): refactor this void GameHost::set_player_state(uint8_t const number, PlayerSettings::State const state, bool const host) { + + // ignore player numbers out of range if (number >= d->settings.players.size()) return; @@ -1122,9 +1128,9 @@ return; if (player.state == PlayerSettings::State::kHuman) { - // 0 is host and has no client - if (d->settings.users.at(0).position == number) { - d->settings.users.at(0).position = UserSettings::none(); + // kHostPlayerNum has no client + if (d->settings.users.at(kHostPlayerNum).position == number) { + d->settings.users.at(kHostPlayerNum).position = UserSettings::none(); d->settings.playernum = UserSettings::none(); } for (uint8_t i = 1; i < d->settings.users.size(); ++i) { @@ -1184,11 +1190,7 @@ // Broadcast change to player SendPacket packet; - packet.reset(); - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); + broadcast_setting_player(packet, number); // Let clients know whether their slot has changed packet.reset(); @@ -1205,6 +1207,7 @@ PlayerSettings& player = d->settings.players.at(number); + // TODDO(k.halfmann): check this logic, will tribe "survive" een when random is selected? if (player.tribe == tribe && player.random_tribe == random_tribe) return; @@ -1225,11 +1228,8 @@ // broadcast changes SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); - return; + broadcast_setting_player(packet, number); + return; // TODO(k.halfmann): check this logic } } log("Player %u attempted to change to tribe %s; not a valid tribe\n", number, tribe.c_str()); @@ -1251,10 +1251,7 @@ // broadcast changes SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); + broadcast_setting_player(packet, number); return; } else log("Attempted to change to out-of-range initialization index %u " @@ -1276,10 +1273,7 @@ // Broadcast changes SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); + broadcast_setting_player(packet, number); } void GameHost::set_player_name(uint8_t const number, const std::string& name) { @@ -1295,10 +1289,7 @@ // Broadcast changes SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); + broadcast_setting_player(packet, number); } void GameHost::set_player_closeable(uint8_t const number, bool closeable) { @@ -1334,10 +1325,7 @@ // Broadcast changes SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); + broadcast_setting_player(packet, number); } void GameHost::set_player(uint8_t const number, const PlayerSettings& ps) { @@ -1349,10 +1337,7 @@ // Broadcast changes SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); + broadcast_setting_player(packet, number); } void GameHost::set_player_number(uint8_t const number) { @@ -1423,10 +1408,7 @@ // Broadcast the user changes to everybody SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_USER); - packet.unsigned_32(user); - write_setting_user(packet, user); - broadcast(packet); + broadcast_setting_user(packet, user); } void GameHost::set_player_team(uint8_t number, Widelands::TeamNumber team) { @@ -1436,10 +1418,7 @@ // Broadcast changes SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_PLAYER); - packet.unsigned_8(number); - write_setting_player(packet, number); - broadcast(packet); + broadcast_setting_player(packet, number); } void GameHost::set_multiplayer_game_settings() { @@ -1509,6 +1488,14 @@ Notifications::publish(NoteGameSettings(NoteGameSettings::Action::kPlayer, number)); } +void GameHost::broadcast_setting_player(SendPacket& packet, uint8_t const number) { + packet.reset(); + packet.unsigned_8(NETCMD_SETTING_PLAYER); + packet.unsigned_8(number); + write_setting_player(packet, number); + broadcast(packet); +} + void GameHost::write_setting_all_players(SendPacket& packet) { packet.unsigned_8(d->settings.players.size()); for (uint8_t i = 0; i < d->settings.players.size(); ++i) { @@ -1526,6 +1513,14 @@ NoteGameSettings::Action::kUser, d->settings.users.at(number).position, number)); } +void GameHost::broadcast_setting_user(SendPacket& packet, uint32_t const number) { + packet.reset(); + packet.unsigned_8(NETCMD_SETTING_USER); + packet.unsigned_32(number); + write_setting_user(packet, number); + broadcast(packet); +} + void GameHost::write_setting_all_users(SendPacket& packet) { packet.unsigned_8(d->settings.users.size()); for (uint32_t i = 0; i < d->settings.users.size(); ++i) @@ -1693,11 +1688,7 @@ d->net->send(client.sock_id, packet); // Broadcast new information about the player to everybody - packet.reset(); - packet.unsigned_8(NETCMD_SETTING_USER); - packet.unsigned_32(client.usernum); - write_setting_user(packet, client.usernum); - broadcast(packet); + broadcast_setting_user(packet, client.usernum); // Check if there is an unoccupied player left and if, assign. for (uint8_t i = 0; i < d->settings.players.size(); ++i) @@ -2026,6 +2017,170 @@ reaper(); } +void GameHost::handle_disconnect(uint32_t const client_num, RecvPacket& r) { + uint8_t number = r.unsigned_8(); + std::string reason = r.string(); + if (number == 1) + disconnect_client(client_num, reason, false); + else { + std::string arg = r.string(); + disconnect_client(client_num, reason, false, arg); + } + return; +} + +void GameHost::handle_ping(Client& client) { + log("[Host]: Received ping from metaserver.\n"); + // Send PING back + SendPacket packet; + packet.unsigned_8(NETCMD_METASERVER_PING); + d->net->send(client.sock_id, packet); + + // Remove metaserver from list of clients + client.playernum = UserSettings::not_connected(); + d->net->close(client.sock_id); + client.sock_id = 0; + return; +} + +/** Wait for NETCMD_HELLO and handle unexpected other commands */ +void GameHost::handle_hello(uint32_t const client_num, uint8_t const cmd, Client& client, RecvPacket& r) { + // Now we wait for the client to say Hi in the right language, + // unless the game has already started + if (d->game) + throw DisconnectException("GAME_ALREADY_STARTED"); + + if (cmd != NETCMD_HELLO) + throw ProtocolException(cmd); + + uint8_t version = r.unsigned_8(); + if (version != NETWORK_PROTOCOL_VERSION) + throw DisconnectException("DIFFERENT_PROTOCOL_VERS"); + + std::string clientname = r.string(); + client.build_id = r.string(); + + welcome_client(client_num, clientname); + return; +} + +void GameHost::handle_changetribe(Client& client, RecvPacket& r) { + // Do not be harsh about packets of this type arriving out of order - + // the client might just have had bad luck with the timing. + if (!d->game) { + uint8_t num = r.unsigned_8(); + if (num != client.playernum) + throw DisconnectException("NO_ACCESS_TO_PLAYER"); + std::string tribe = r.string(); + bool random_tribe = r.unsigned_8() == 1; + set_player_tribe(num, tribe, random_tribe); + } +} + +/** Handle changed sharing of clients by users */ +void GameHost::handle_changeshared(Client& client, RecvPacket& r) { + // Do not be harsh about packets of this type arriving out of order - + // the client might just have had bad luck with the timing. + if (!d->game) { + uint8_t num = r.unsigned_8(); + if (num != client.playernum) + throw DisconnectException("NO_ACCESS_TO_PLAYER"); + set_player_shared(num, r.unsigned_8()); + } +} + +void GameHost::handle_changeteam(Client& client, RecvPacket& r) { + if (!d->game) { + uint8_t num = r.unsigned_8(); + if (num != client.playernum) + throw DisconnectException("NO_ACCESS_TO_PLAYER"); + set_player_team(num, r.unsigned_8()); + } +} + +void GameHost::handle_changeinit(Client& client, RecvPacket& r) { + if (!d->game) { + // TODO(GunChleoc): For some nebulous reason, we don't receive the num that the client is + // sending when a player changes slot. So, keeping the access to the client off for now. + // Would be nice to have though. + uint8_t num = r.unsigned_8(); + if (num != client.playernum) + throw DisconnectException("NO_ACCESS_TO_PLAYER"); + set_player_init(num, r.unsigned_8()); + } +} + +void GameHost::handle_changeposition(Client& client, RecvPacket& r) { + if (!d->game) { + uint8_t const pos = r.unsigned_8(); + switch_to_player(client.usernum, pos); + } +} + +void GameHost::handle_nettime(uint32_t const client_num, RecvPacket& r) { + if (!d->game) + throw DisconnectException("TIME_SENT_NOT_READY"); + receive_client_time(client_num, r.signed_32()); +} + +void GameHost::handle_playercommmand(uint32_t const client_num, Client& client, RecvPacket& r) { + if (!d->game) + throw DisconnectException("PLAYERCMD_WO_GAME"); + int32_t time = r.signed_32(); + Widelands::PlayerCommand* plcmd = Widelands::PlayerCommand::deserialize(r); + log("[Host]: Client %u (%u) sent player command %u for %u, time = %i\n", client_num, client.playernum, + static_cast<unsigned int>(plcmd->id()), plcmd->sender(), time); + receive_client_time(client_num, time); + if (plcmd->sender() != client.playernum + 1) + throw DisconnectException("PLAYERCMD_FOR_OTHER"); + send_player_command(plcmd); +} + +void GameHost::handle_syncreport(uint32_t const client_num, Client& client, RecvPacket& r) { + if (!d->game || !d->syncreport_pending || client.syncreport_arrived) { + throw DisconnectException("UNEXPECTED_SYNC_REP"); + } + int32_t time = r.signed_32(); + r.data(client.syncreport.data, 16); + client.syncreport_arrived = true; + receive_client_time(client_num, time); + check_sync_reports(); +} + +void GameHost::handle_chat(Client& client, RecvPacket& r) { + ChatMessage c(r.string()); + c.playern = d->settings.users.at(client.usernum).position; + c.sender = d->settings.users.at(client.usernum).name; + if (c.msg.size() && *c.msg.begin() == '@') { + // Personal message + std::string::size_type const space = c.msg.find(' '); + if (space >= c.msg.size() - 1) + return; // No Message after '@<User>' + c.recipient = c.msg.substr(1, space - 1); + c.msg = c.msg.substr(space + 1); + } + send(c); +} + +/** Care for change of game speed PAUSE, 1x 2x 3x .... */ +void GameHost::handle_speed(Client& client, RecvPacket& r) { + client.desiredspeed = r.unsigned_16(); + update_network_speed(); +} + +/** a new file should be upload to all players */ +void GameHost::handle_new_file(Client& client) { + if (!file_) // Do we have a file for sending? + throw DisconnectException("REQUEST_OF_N_E_FILE"); + send_system_message_code( + "STARTED_SENDING_FILE", file_->filename, d->settings.users.at(client.usernum).name); + send_file_part(client.sock_id, 0); + // Remember client as "currently receiving file" + d->settings.users[client.usernum].ready = false; + SendPacket packet; + broadcast_setting_user(packet, client.usernum); +} + /** * Handle a single received packet. * @@ -2034,246 +2189,82 @@ * \param i the client number * \param r the received packet */ -void GameHost::handle_packet(uint32_t const i, RecvPacket& r) { - Client& client = d->clients.at(i); +void GameHost::handle_packet(uint32_t const client_num, RecvPacket& r) { + Client& client = d->clients.at(client_num); uint8_t const cmd = r.unsigned_8(); if (cmd == NETCMD_DISCONNECT) { - uint8_t number = r.unsigned_8(); - std::string reason = r.string(); - if (number == 1) - disconnect_client(i, reason, false); - else { - std::string arg = r.string(); - disconnect_client(i, reason, false, arg); - } - return; + return handle_disconnect(client_num, r); } if (client.playernum == UserSettings::not_connected()) { if (cmd == NETCMD_METASERVER_PING) { - log("[Host]: Received ping from metaserver.\n"); - // Send PING back - SendPacket packet; - packet.unsigned_8(NETCMD_METASERVER_PING); - d->net->send(client.sock_id, packet); - - // Remove metaserver from list of clients - client.playernum = UserSettings::not_connected(); - d->net->close(client.sock_id); - client.sock_id = 0; - return; + return handle_ping(client); } - // Now we wait for the client to say Hi in the right language, - // unless the game has already started - if (d->game) - throw DisconnectException("GAME_ALREADY_STARTED"); - - if (cmd != NETCMD_HELLO) - throw ProtocolException(cmd); - - uint8_t version = r.unsigned_8(); - if (version != NETWORK_PROTOCOL_VERSION) - throw DisconnectException("DIFFERENT_PROTOCOL_VERS"); - - std::string clientname = r.string(); - client.build_id = r.string(); - - welcome_client(i, clientname); - return; + return handle_hello(client_num, cmd, client, r); } switch (cmd) { - case NETCMD_PONG: - log("[Host]: Client %u: got pong\n", i); - break; - - case NETCMD_SETTING_MAP: - if (!d->game) { - throw DisconnectException("NO_ACCESS_TO_SERVER"); - } - break; - - case NETCMD_SETTING_CHANGETRIBE: - // Do not be harsh about packets of this type arriving out of order - - // the client might just have had bad luck with the timing. - if (!d->game) { - uint8_t num = r.unsigned_8(); - if (num != client.playernum) - throw DisconnectException("NO_ACCESS_TO_PLAYER"); - std::string tribe = r.string(); - bool random_tribe = r.unsigned_8() == 1; - set_player_tribe(num, tribe, random_tribe); - } - break; - - case NETCMD_SETTING_CHANGESHARED: - // Do not be harsh about packets of this type arriving out of order - - // the client might just have had bad luck with the timing. - if (!d->game) { - uint8_t num = r.unsigned_8(); - if (num != client.playernum) - throw DisconnectException("NO_ACCESS_TO_PLAYER"); - set_player_shared(num, r.unsigned_8()); - } - break; - - case NETCMD_SETTING_CHANGETEAM: - if (!d->game) { - uint8_t num = r.unsigned_8(); - if (num != client.playernum) - throw DisconnectException("NO_ACCESS_TO_PLAYER"); - set_player_team(num, r.unsigned_8()); - } - break; - - case NETCMD_SETTING_CHANGEINIT: - if (!d->game) { - // TODO(GunChleoc): For some nebulous reason, we don't receive the num that the client is - // sending when a player changes slot. So, keeping the access to the client off for now. - // Would be nice to have though. - uint8_t num = r.unsigned_8(); - if (num != client.playernum) - throw DisconnectException("NO_ACCESS_TO_PLAYER"); - set_player_init(num, r.unsigned_8()); - } - break; - - case NETCMD_SETTING_CHANGEPOSITION: - if (!d->game) { - uint8_t const pos = r.unsigned_8(); - switch_to_player(client.usernum, pos); - } - break; - - case NETCMD_SETTING_PLAYER: - if (!d->game) { - throw DisconnectException("NO_ACCESS_TO_SERVER"); - } - break; - - case NETCMD_WIN_CONDITION: - if (!d->game) { - throw DisconnectException("NO_ACCESS_TO_SERVER"); - } - break; - - case NETCMD_PEACEFUL_MODE: - if (!d->game) { - throw DisconnectException("NO_ACCESS_TO_SERVER"); - } - break; - - case NETCMD_LAUNCH: - if (!d->game) { - throw DisconnectException("NO_ACCESS_TO_SERVER"); - } - break; - - case NETCMD_TIME: - if (!d->game) - throw DisconnectException("TIME_SENT_NOT_READY"); - receive_client_time(i, r.signed_32()); - break; - - case NETCMD_PLAYERCOMMAND: { - if (!d->game) - throw DisconnectException("PLAYERCMD_WO_GAME"); - int32_t time = r.signed_32(); - Widelands::PlayerCommand* plcmd = Widelands::PlayerCommand::deserialize(r); - log("[Host]: Client %u (%u) sent player command %u for %u, time = %i\n", i, client.playernum, - static_cast<unsigned int>(plcmd->id()), plcmd->sender(), time); - receive_client_time(i, time); - if (plcmd->sender() != client.playernum + 1) - throw DisconnectException("PLAYERCMD_FOR_OTHER"); - send_player_command(plcmd); - } break; - - case NETCMD_SYNCREPORT: { - if (!d->game || !d->syncreport_pending || client.syncreport_arrived) - throw DisconnectException("UNEXPECTED_SYNC_REP"); - int32_t time = r.signed_32(); - r.data(client.syncreport.data, 16); - client.syncreport_arrived = true; - receive_client_time(i, time); - check_sync_reports(); - break; - } - - case NETCMD_CHAT: { - ChatMessage c(r.string()); - c.playern = d->settings.users.at(client.usernum).position; - c.sender = d->settings.users.at(client.usernum).name; - if (c.msg.size() && *c.msg.begin() == '@') { - // Personal message - std::string::size_type const space = c.msg.find(' '); - if (space >= c.msg.size() - 1) - break; - c.recipient = c.msg.substr(1, space - 1); - c.msg = c.msg.substr(space + 1); - } - send(c); - break; - } - - case NETCMD_SETSPEED: { - client.desiredspeed = r.unsigned_16(); - update_network_speed(); - break; - } - - case NETCMD_NEW_FILE_AVAILABLE: { - if (!file_) // Do we have a file for sending - throw DisconnectException("REQUEST_OF_N_E_FILE"); + case NETCMD_PONG: + log("[Host]: Client %u: got pong\n", client_num); + break; + + case NETCMD_SETTING_CHANGETRIBE: return handle_changetribe(client, r); + case NETCMD_SETTING_CHANGESHARED: return handle_changeshared(client, r); + case NETCMD_SETTING_CHANGETEAM: return handle_changeteam(client, r); + case NETCMD_SETTING_CHANGEINIT: return handle_changeinit(client, r); + case NETCMD_SETTING_CHANGEPOSITION: return handle_changeposition(client, r); + case NETCMD_TIME: return handle_nettime(client_num, r); + case NETCMD_PLAYERCOMMAND: return handle_playercommmand(client_num, client, r); + case NETCMD_SYNCREPORT: return handle_syncreport(client_num, client, r); + case NETCMD_CHAT: return handle_chat(client, r); + case NETCMD_SETSPEED: return handle_speed(client, r); + case NETCMD_NEW_FILE_AVAILABLE: return handle_new_file(client); + case NETCMD_FILE_PART: return handle_file_part(client, r); + + case NETCMD_SETTING_MAP: + case NETCMD_SETTING_PLAYER: + case NETCMD_WIN_CONDITION: + case NETCMD_PEACEFUL_MODE: + case NETCMD_LAUNCH: + if (!d->game) { // not expected whe game is in progress -> somethings wrong here + throw DisconnectException("NO_ACCESS_TO_SERVER"); + } + break; + + default: + throw ProtocolException(cmd); + } +} + +/** Hanlde uploading part of a file */ +void GameHost::handle_file_part(Client& client, RecvPacket& r) { + if (!file_) // Do we have a file for sending + throw DisconnectException("REQUEST_OF_N_E_FILE"); + uint32_t part = r.unsigned_32(); + std::string x = r.string(); + if (x != file_->md5sum) { + log( + "[Host]: File transfer checksum mismatch %s != %s\n", x.c_str(), file_->md5sum.c_str()); + return; // Surely the file was changed, so we cancel here. + } + if (part >= file_->parts.size()) + throw DisconnectException("REQUEST_OF_N_E_FILEPART"); + if (part == file_->parts.size() - 1) { send_system_message_code( - "STARTED_SENDING_FILE", file_->filename, d->settings.users.at(client.usernum).name); - send_file_part(client.sock_id, 0); - // Remember client as "currently receiving file" - d->settings.users[client.usernum].ready = false; + "COMPLETED_FILE_TRANSFER", file_->filename, d->settings.users.at(client.usernum).name); + d->settings.users[client.usernum].ready = true; SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_USER); - packet.unsigned_32(client.usernum); - write_setting_user(packet, client.usernum); - broadcast(packet); - break; - } - - case NETCMD_FILE_PART: { - if (!file_) // Do we have a file for sending - throw DisconnectException("REQUEST_OF_N_E_FILE"); - uint32_t part = r.unsigned_32(); - std::string x = r.string(); - if (x != file_->md5sum) { - log( - "[Host]: File transfer checksum mismatch %s != %s\n", x.c_str(), file_->md5sum.c_str()); - return; // Surely the file was changed, so we cancel here. - } - if (part >= file_->parts.size()) - throw DisconnectException("REQUEST_OF_N_E_FILEPART"); - if (part == file_->parts.size() - 1) { - send_system_message_code( - "COMPLETED_FILE_TRANSFER", file_->filename, d->settings.users.at(client.usernum).name); - d->settings.users[client.usernum].ready = true; - SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_USER); - packet.unsigned_32(client.usernum); - write_setting_user(packet, client.usernum); - broadcast(packet); - return; - } - ++part; - if (part % 100 == 0) - send_system_message_code("SENDING_FILE_PART", - (boost::format("%i/%i") % part % (file_->parts.size() + 1)).str(), - file_->filename, d->settings.users.at(client.usernum).name); - send_file_part(client.sock_id, part); - break; - } - - default: - throw ProtocolException(cmd); - } + broadcast_setting_user(packet, client.usernum); + return; + } + ++part; + if (part % 100 == 0) // Show Progress message every 100th transfer + send_system_message_code("SENDING_FILE_PART", + (boost::format("%i/%i") % part % (file_->parts.size() + 1)).str(), + file_->filename, d->settings.users.at(client.usernum).name); + send_file_part(client.sock_id, part); } void GameHost::send_file_part(NetHostInterface::ConnectionId csock_id, uint32_t part) { @@ -2314,13 +2305,13 @@ // Don't replace player with AI, let host choose what to do } -void GameHost::disconnect_client(uint32_t const number, +void GameHost::disconnect_client(uint32_t const client_number, const std::string& reason, bool const sendreason, const std::string& arg) { - assert(number < d->clients.size()); + assert(client_number < d->clients.size()); - Client& client = d->clients.at(number); + Client& client = d->clients.at(client_number); // If the client is linked to a player and it is the client that closes the connection // and the game has already started ... @@ -2358,8 +2349,7 @@ disconnect_player_controller(position, d->settings.users.at(client.usernum).name); } // Do NOT reset the clients name in the corresponding UserSettings, that way we keep the name - // for the - // statistics. + // for the statistics. // d->settings.users.at(client.usernum).name = std::string(); // Broadcast the user changes to everybody @@ -2367,14 +2357,11 @@ "CLIENT_X_LEFT_GAME", d->settings.users.at(client.usernum).name, reason, arg); SendPacket packet; - packet.unsigned_8(NETCMD_SETTING_USER); - packet.unsigned_32(client.usernum); - write_setting_user(packet, client.usernum); - broadcast(packet); - } else + broadcast_setting_user(packet, client.usernum); + } else { send_system_message_code("UNKNOWN_LEFT_GAME", reason, arg); - - log("[Host]: disconnect_client(%u, %s, %s)\n", number, reason.c_str(), arg.c_str()); + } + log("[Host]: disconnect_client(%u, %s, %s)\n", client_number, reason.c_str(), arg.c_str()); if (client.sock_id > 0) { if (sendreason) { === modified file 'src/network/gamehost.h' --- src/network/gamehost.h 2019-05-25 07:36:44 +0000 +++ src/network/gamehost.h 2019-07-18 14:48:27 +0000 @@ -41,6 +41,9 @@ * launch, as well as dealing with the actual network protocol. */ struct GameHost : public GameController { + /** playernumber 0 actually identifies the host */ + static constexpr uint8_t kHostPlayerNum = 0; + GameHost(const std::string& playername, bool internet = false); ~GameHost() override; @@ -63,6 +66,7 @@ // Pregame-related stuff const GameSettings& settings(); + /** return true in case all conditions for the game start are met */ bool can_launch(); void set_scenario(bool); void set_map(const std::string& mapname, @@ -129,6 +133,22 @@ void init_computer_player(Widelands::PlayerNumber p); void init_computer_players(); + void handle_disconnect(uint32_t client_num, RecvPacket& r); + void handle_ping(Client& client); + void handle_hello(uint32_t client_num, uint8_t cmd, Client& client, RecvPacket& r); + void handle_changetribe(Client& client, RecvPacket& r); + void handle_changeshared(Client& client, RecvPacket& r); + void handle_changeteam(Client& client, RecvPacket& r); + void handle_changeinit(Client& client, RecvPacket& r); + void handle_changeposition(Client& client, RecvPacket& r); + void handle_nettime(uint32_t client_num, RecvPacket& r); + void handle_playercommmand(uint32_t client_num, Client& client, RecvPacket& r); + void handle_syncreport(uint32_t client_num, Client& client, RecvPacket& r); + void handle_chat(Client& client, RecvPacket& r); + void handle_speed(Client& client, RecvPacket& r); + void handle_new_file(Client& client); + void handle_file_part(Client& client, RecvPacket& r); + void handle_packet(uint32_t i, RecvPacket&); void handle_network(); void send_file_part(NetHostInterface::ConnectionId client_sock_id, uint32_t part); @@ -145,9 +165,11 @@ void broadcast(SendPacket&); void write_setting_map(SendPacket&); - void write_setting_player(SendPacket&, uint8_t number); + void write_setting_player(SendPacket&, uint8_t number); + void broadcast_setting_player(SendPacket&, uint8_t number); void write_setting_all_players(SendPacket&); - void write_setting_user(SendPacket&, uint32_t number); + void write_setting_user(SendPacket& packet, uint32_t number); + void broadcast_setting_user(SendPacket& packet, uint32_t number); void write_setting_all_users(SendPacket&); bool write_map_transfer_info(SendPacket&, std::string);
_______________________________________________ Mailing list: https://launchpad.net/~widelands-dev Post to : widelands-dev@lists.launchpad.net Unsubscribe : https://launchpad.net/~widelands-dev More help : https://help.launchpad.net/ListHelp