summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarkvater <darkvater@openttd.org>2006-11-10 17:52:51 +0000
committerDarkvater <darkvater@openttd.org>2006-11-10 17:52:51 +0000
commit73ca5faa2efe6abd28aadacbccf9d5a02f13c7a3 (patch)
tree6abf7ee63a84078c6b20f1f317de5a1483ccf058
parent82f7140357b8b13e5f3c2eea715af936e5debb28 (diff)
downloadopenttd-73ca5faa2efe6abd28aadacbccf9d5a02f13c7a3.tar.xz
(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.
-rw-r--r--command.c14
-rw-r--r--economy.c57
-rw-r--r--players.c104
3 files changed, 98 insertions, 77 deletions
diff --git a/command.c b/command.c
index 17fa5490c..7c07c5d37 100644
--- a/command.c
+++ b/command.c
@@ -424,9 +424,9 @@ bool DoCommandP(TileIndex tile, uint32 p1, uint32 p2, CommandCallback *callback,
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 p1, uint32 p2, CommandCallback *callback,
* 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;
diff --git a/economy.c b/economy.c
index f41db66a9..cee067b42 100644
--- a/economy.c
+++ b/economy.c
@@ -414,40 +414,51 @@ static void PlayersCheckBankrupt(Player *p)
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);
}
}
}
diff --git a/players.c b/players.c
index e71e07efd..623636b95 100644
--- a/players.c
+++ b/players.c
@@ -819,74 +819,81 @@ int32 CmdPlayerCtrl(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
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;
-
- /* 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
+#endif /* ENABLE_NETWORK */
+ {
+ _local_player = _network_playas = PLAYER_SPECTATOR;
}
- } else if (_network_server) {
- // Creating player failed, defer client to spectator
+ break;
+ }
+
+ /* 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);
-#endif /* ENABLE_NETWORK */
+
+ 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, uint32 flags, uint32 p1, uint32 p2)
ChangeOwnershipOfPlayerItems(pid_old, pid_new);
DeletePlayerStuff(pid_old);
} break;
+
default: return CMD_ERROR;
}