← Back to team overview

widelands-dev team mailing list archive

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

 

Added some comments with nits. Not tested yet.

Diff comments:

> === modified file 'src/network/gamehost.cc'
> --- src/network/gamehost.cc	2019-05-26 11:39:41 +0000
> +++ src/network/gamehost.cc	2019-07-18 15:23:31 +0000
> @@ -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;

You can make this const

> +
>  	for (std::vector<Client>::iterator j = d->clients.begin(); j != d->clients.end(); ++j) {
> -		if (j->usernum == -1) {
> +		int usernum = j->usernum;

You can make this const

> +		if (usernum == -1) {
>  			return false;
>  		}
> -		if (!d->settings.users[j->usernum].ready) {
> +		if (users[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;
> @@ -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);

Is this correct? I see an i replaced by a j here.

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

Add {}

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

Add {}, below as well

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

Add {}, in the functions below as well.

> +			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 .... */

Care for -> Take care of

> +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 */

upload -> uploaded

> +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  */

Hanlde -> Handle

> +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) {
> 
> === modified file 'src/network/gamehost.h'
> --- src/network/gamehost.h	2019-05-25 07:36:44 +0000
> +++ src/network/gamehost.h	2019-07-18 15:23:31 +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;

kHostClientNum ? Player number 0 are the spectators.

> +
>  	GameHost(const std::string& playername, bool internet = false);
>  	~GameHost() override;
>  


-- 
https://code.launchpad.net/~widelands-dev/widelands/refactor_gamehost/+merge/370320
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/refactor_gamehost into lp:widelands.


References