← Back to team overview

widelands-dev team mailing list archive

[Merge] lp:~widelands-dev/widelands/refactor_gamehost into lp:widelands

 

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);
 


Follow ups