Changeset - r5067:7312b67c8cc3
[Not reviewed]
master
0 3 0
Darkvater - 18 years ago 2006-11-10 17:52:51
darkvater@openttd.org
(svn r7125) -Fix: Several errors/glitches related to multiplayer and bankrupcy, mainly such a
thing happening to a server, and non updated company-information. Also fixes FS#393.
3 files changed with 98 insertions and 77 deletions:
0 comments (0 inline, 0 general)
command.c
Show inline comments
 
@@ -424,9 +424,9 @@ bool DoCommandP(TileIndex tile, uint32 p
 
	error_part1 = GB(cmd, 16, 16);
 
	_additional_cash_required = 0;
 

	
 
	/** Spectator has no rights except for the dedicated server which
 
	 * is a spectator but is the server, so can do anything */
 
	if (_current_player == PLAYER_SPECTATOR && !_network_dedicated) {
 
	/** Spectator has no rights except for the (dedicated) server which
 
	 * is/can be a spectator but as the server it can do anything */
 
	if (_current_player == PLAYER_SPECTATOR && !_network_server) {
 
		ShowErrorMessage(_error_message, error_part1, x, y);
 
		_cmd_text = NULL;
 
		return false;
 
@@ -495,12 +495,14 @@ bool DoCommandP(TileIndex tile, uint32 p
 
	 * send it to the command-queue and abort execution
 
	 * If we are a dedicated server temporarily switch local player, otherwise
 
	 * the other parties won't be able to execute our command and will desync.
 
	 * @todo Rewrite dedicated server to something more than a dirty hack!
 
	 * We also need to do this if the server's company has gone bankrupt
 
	 * @todo Rewrite (dedicated) server to something more than a dirty hack!
 
	 */
 
	if (_networking && !(cmd & CMD_NETWORK_COMMAND)) {
 
		if (_network_dedicated) _local_player = 0;
 
		PlayerID pbck = _local_player;
 
		if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = 0;
 
		NetworkSend_Command(tile, p1, p2, cmd, callback);
 
		if (_network_dedicated) _local_player = PLAYER_SPECTATOR;
 
		if (_network_dedicated || (_network_server && pbck == PLAYER_SPECTATOR)) _local_player = pbck;
 
		_docommand_recursive = 0;
 
		_cmd_text = NULL;
 
		return true;
economy.c
Show inline comments
 
@@ -414,40 +414,51 @@ static void PlayersCheckBankrupt(Player 
 
			SetDParam(1, p->name_2);
 
			AddNewsItem( (StringID)(owner | NB_BBANKRUPT), NEWS_FLAGS(NM_CALLBACK, 0, NT_COMPANY_INFO, DNC_BANKRUPCY),0,0);
 

	
 
			// If the player is human, and it is no network play, leave the player playing
 
			if (IsHumanPlayer(owner) && !_networking) {
 
				p->bankrupt_asked = 255;
 
				p->bankrupt_timeout = 0x456;
 
			} else {
 
			if (IsHumanPlayer(owner)) {
 
				/* XXX - If we are in offline mode, leave the player playing. Eg. there
 
				 * is no THE-END, otherwise mark the player as spectator to make sure
 
				 * he/she is no long in control of this company */
 
				if (!_networking) {
 
					p->bankrupt_asked = 0xFF;
 
					p->bankrupt_timeout = 0x456;
 
					break;
 
				} else if (owner == _local_player) {
 
					_local_player = _network_playas = PLAYER_SPECTATOR;
 
				}
 

	
 
#ifdef ENABLE_NETWORK
 
				/* If we are the server make sure it is clear that this player is not active */
 
				if (IsHumanPlayer(owner) && _network_server) {
 
				/* The server has to handle all administrative issues, for example
 
				 * updating and notifying all clients of what has happened */
 
				if (_network_server) {
 
					const NetworkClientState *cs;
 
					/* Find all clients that were in control of this company */
 
					NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(NETWORK_SERVER_INDEX);
 

	
 
					/* The server has just gone belly-up, mark it as spectator */
 
					if (owner == ci->client_playas) {
 
						ci->client_playas = PLAYER_SPECTATOR;
 
						NetworkUpdateClientInfo(NETWORK_SERVER_INDEX);
 
					}
 

	
 
					/* Find all clients that were in control of this company,
 
					 * and mark them as spectator; broadcast this message to everyone */
 
					FOR_ALL_CLIENTS(cs) {
 
						NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs);
 
						ci = DEREF_CLIENT_INFO(cs);
 
						if (ci->client_playas == owner) {
 
							ci->client_playas = PLAYER_SPECTATOR;
 
							// Send the new info to all the clients
 
							NetworkUpdateClientInfo(_network_own_client_index);
 
							NetworkUpdateClientInfo(ci->client_index);
 
						}
 
					}
 
				}
 
				// Make sure the player no longer controls the company
 
				if (IsHumanPlayer(owner) && owner == _local_player) {
 
					// Switch the player to spectator..
 
					_local_player = PLAYER_SPECTATOR;
 
				}
 
#endif /* ENABLE_NETWORK */
 
			}
 

	
 
				/* Remove the player */
 
				ChangeOwnershipOfPlayerItems(owner, PLAYER_SPECTATOR);
 
				// Register the player as not-active
 
				p->is_active = false;
 
			/* Remove the player */
 
			ChangeOwnershipOfPlayerItems(owner, PLAYER_SPECTATOR);
 
			/* Register the player as not-active */
 
			p->is_active = false;
 

	
 
				if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
 
					AI_PlayerDied(owner);
 
			}
 
			if (!IsHumanPlayer(owner) && (!_networking || _network_server) && _ai.enabled)
 
				AI_PlayerDied(owner);
 
		}
 
	}
 
}
players.c
Show inline comments
 
@@ -819,74 +819,81 @@ int32 CmdPlayerCtrl(TileIndex tile, uint
 

	
 
	switch (p1) {
 
	case 0: { /* Create a new player */
 
		/* Joining Client:
 
		 * _local_player: PLAYER_SPECTATOR
 
		 * _network_playas/cid = requested company/player
 
		 *
 
		 * Other client(s)/server:
 
		 * _local_player/_network_playas: what they play as
 
		 * cid = requested company/player of joining client */
 
		Player *p;
 
		uint16 cid = p2; // ClientID
 

	
 
		/* This command is only executed in a multiplayer game */
 
		if (!_networking) return CMD_ERROR;
 

	
 
		/* ClientID would be valid up to MAX_CLIENT_INFO, but as it has to be a
 
		 * new player, its valid range is restricted to that of players */
 
		if (!(flags & DC_EXEC) || !IsValidPlayer((PlayerID)cid)) return 0;
 

	
 
		/* Delete multiplayer progress bar */
 
		DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 

	
 
		p = DoStartupNewPlayer(false);
 

	
 
#ifdef ENABLE_NETWORK
 
		if (_networking && !_network_server && _local_player == PLAYER_SPECTATOR) {
 
			/* In case we are a client joining a server... */
 
			DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
 
		}
 
#endif /* ENABLE_NETWORK */
 

	
 
		if (p != NULL) {
 
			if (_local_player == PLAYER_SPECTATOR) {
 
				/* Check if we do not want to be a spectator in network */
 
				if (!_networking ||
 
						(_network_server && !_network_dedicated) ||
 
						_network_playas != PLAYER_SPECTATOR) {
 
						_local_player = p->index;
 
					MarkWholeScreenDirty();
 
				}
 
			} else if (p->index == _local_player) {
 
				DoCommandP(0, (_patches.autorenew << 15 ) | (_patches.autorenew_months << 16) | 4, _patches.autorenew_money, NULL, CMD_SET_AUTOREPLACE);
 
			}
 
		/* A new player could not be created, revert to being a spectator */
 
		if (p == NULL) {
 
#ifdef ENABLE_NETWORK
 
			if (_network_server) {
 
				/* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at
 
				 * server-side in network_server.c:838, function
 
				 * DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
 
				NetworkClientInfo *ci = &_network_client_info[cid];
 
				ci->client_playas = p->index;
 
				ci->client_playas = PLAYER_SPECTATOR;
 
				NetworkUpdateClientInfo(ci->client_index);
 

	
 
				if (IsValidPlayer(ci->client_playas)) {
 
					PlayerID player_backup = _local_player;
 
					_network_player_info[p->index].months_empty = 0;
 
			} else
 
#endif /* ENABLE_NETWORK */
 
			{
 
				_local_player = _network_playas = PLAYER_SPECTATOR;
 
			}
 
			break;
 
		}
 

	
 
					/* XXX - When a client joins, we automatically set its name to the
 
					 * player's name (for some reason). As it stands now only the server
 
					 * knows the client's name, so it needs to send out a "broadcast" to
 
					 * do this. To achieve this we send a network command. However, it
 
					 * uses _local_player to execute the command as.  To prevent abuse
 
					 * (eg. only yourself can change your name/company), we 'cheat' by
 
					 * impersonation _local_player as the server. Not the best solution;
 
					 * but it works.
 
					 * TODO: Perhaps this could be improved by when the client is ready
 
					 * with joining to let it send itself the command, and not the server?
 
					 * For example in network_client.c:534? */
 
					_cmd_text = ci->client_name;
 
					_local_player = ci->client_playas;
 
					NetworkSend_Command(0, 0, 0, CMD_CHANGE_PRESIDENT_NAME, NULL);
 
					_local_player = player_backup;
 
				}
 
			}
 
		} else if (_network_server) {
 
			// Creating player failed, defer client to spectator
 
		/* This is the joining client who wants a new company */
 
		if (_local_player != _network_playas) {
 
			assert(_local_player == PLAYER_SPECTATOR && _network_playas == p->index);
 
			_local_player = p->index;
 
			MarkWholeScreenDirty();
 
		}
 

	
 
#ifdef ENABLE_NETWORK
 
		if (_network_server) {
 
			/* XXX - UGLY! p2 (pid) is mis-used to fetch the client-id, done at
 
			 * server-side in network_server.c:838, function
 
			 * DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) */
 
			NetworkClientInfo *ci = &_network_client_info[cid];
 
			ci->client_playas = PLAYER_SPECTATOR;
 
			ci->client_playas = p->index;
 
			NetworkUpdateClientInfo(ci->client_index);
 

	
 
			if (IsValidPlayer(ci->client_playas)) {
 
				PlayerID player_backup = _local_player;
 
				_network_player_info[p->index].months_empty = 0;
 

	
 
				/* XXX - When a client joins, we automatically set its name to the
 
				 * player's name (for some reason). As it stands now only the server
 
				 * knows the client's name, so it needs to send out a "broadcast" to
 
				 * do this. To achieve this we send a network command. However, it
 
				 * uses _local_player to execute the command as.  To prevent abuse
 
				 * (eg. only yourself can change your name/company), we 'cheat' by
 
				 * impersonation _local_player as the server. Not the best solution;
 
				 * but it works.
 
				 * TODO: Perhaps this could be improved by when the client is ready
 
				 * with joining to let it send itself the command, and not the server?
 
				 * For example in network_client.c:534? */
 
				_cmd_text = ci->client_name;
 
				_local_player = ci->client_playas;
 
				NetworkSend_Command(0, 0, 0, CMD_CHANGE_PRESIDENT_NAME, NULL);
 
				_local_player = player_backup;
 
			}
 
		}
 
#endif /* ENABLE_NETWORK */
 
		}
 
	} break;
 

	
 
	case 1: /* Make a new AI player */
 
@@ -933,6 +940,7 @@ int32 CmdPlayerCtrl(TileIndex tile, uint
 
		ChangeOwnershipOfPlayerItems(pid_old, pid_new);
 
		DeletePlayerStuff(pid_old);
 
	} break;
 

	
 
	default: return CMD_ERROR;
 
	}
 

	
0 comments (0 inline, 0 general)