Index: src/console_cmds.cpp =================================================================== --- src/console_cmds.cpp (Revision 12767) +++ src/console_cmds.cpp (Arbeitskopie) @@ -670,6 +670,62 @@ return true; } +DEF_CONSOLE_CMD(ConMoveClient) +{ + const Player *p; + NetworkClientInfo *ci; + uint16 client_index; + PlayerID player_index; + + if (argc < 2) { + IConsoleHelp("Move a player to another company. Usage: move []"); + IConsoleHelp("For client-id see 'clients', company-id must be between 1 and 8, ommit if moving to spectators"); + return true; + } + + client_index = (uint16)atoi(argv[1]); + player_index = (argc == 3) ? (PlayerID)(atoi(argv[2]) - 1) : PLAYER_SPECTATOR; + + if (client_index == NETWORK_SERVER_INDEX) { + IConsoleError("Silly boy, you can not move the server!"); + return true; + } + + if (client_index == 0) { + IConsoleError("Invalid client"); + return true; + } + + ci = NetworkFindClientInfoFromIndex(client_index); + + if (!IsValidPlayer(player_index) && player_index != PLAYER_SPECTATOR) { + IConsolePrintF(_icolour_err, "Company does not exist. Company-id must be between 1 and %d.", ActivePlayerCount()); + return true; + } + + if (player_index != PLAYER_SPECTATOR) { + p = GetPlayer(player_index); + if (!p->is_active && player_index) { + IConsoleError("Company does not exist, see command 'players'."); + return true; + } + } + + if (ci != NULL) { + /* We are good to make the change, after passing all tests. */ + ci->client_playas = player_index; + /* First update the client itself, so that client side windows can be disabled in time. */ + SEND_COMMAND(PACKET_CLIENT_MOVE)(NetworkFindClientStateFromIndex(client_index), client_index, player_index); + /* Now spread the workd to everyone else. */ + NetworkUpdateClientInfo(client_index); + IConsolePrintF(_icolour_err, "[move] client %d to company %d.", client_index, min(player_index+1, PLAYER_SPECTATOR)); + } else { + IConsoleError("Client not found"); + } + + return true; +} + DEF_CONSOLE_CMD(ConResetCompany) { const Player *p; @@ -1572,6 +1628,8 @@ IConsoleCmdRegister("rcon", ConRcon); IConsoleCmdHookAdd("rcon", ICONSOLE_HOOK_ACCESS, ConHookNeedNetwork); + IConsoleCmdRegister("move", ConMoveClient); + IConsoleCmdHookAdd("move", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); IConsoleCmdRegister("reset_company", ConResetCompany); IConsoleCmdHookAdd("reset_company", ICONSOLE_HOOK_ACCESS, ConHookServerOnly); IConsoleAliasRegister("clean_company", "reset_company %A"); Index: src/network/core/tcp.h =================================================================== --- src/network/core/tcp.h (Revision 12767) +++ src/network/core/tcp.h (Arbeitskopie) @@ -55,6 +55,7 @@ PACKET_CLIENT_RCON, PACKET_SERVER_CHECK_NEWGRFS, PACKET_CLIENT_NEWGRFS_CHECKED, + PACKET_CLIENT_MOVE, PACKET_END ///< Must ALWAYS be on the end of this list!! (period) }; Index: src/network/network_server.cpp =================================================================== --- src/network/network_server.cpp (Revision 12767) +++ src/network/network_server.cpp (Arbeitskopie) @@ -597,6 +597,25 @@ cs->Send_Packet(p); } +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_CLIENT_MOVE)(NetworkTCPSocketHandler *cs, uint16 client_index, uint8 player_index) +{ + // + // Packet: PACKET_CLIENT_MOVE + // Function: Move a client from one company to another, or to Spectator. + // Data: + // uint16: Client-index + // uint8: PlayerID + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_MOVE); + + DEBUG(net, 0, "[move] client %d to player %d", client_index, min(player_index+1, PLAYER_SPECTATOR)); + + p->Send_uint16(client_index); + p->Send_uint8(player_index); + cs->Send_Packet(p); +} + // ********** // Receiving functions // DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkTCPSocketHandler *cs, Packet *p @@ -1246,6 +1265,7 @@ RECEIVE_COMMAND(PACKET_CLIENT_RCON), NULL, /*PACKET_CLIENT_CHECK_NEWGRFS,*/ RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED), + NULL /*PACKET_CLIENT_MOVE,*/ }; // If this fails, check the array above with network_data.h Index: src/network/network_server.h =================================================================== --- src/network/network_server.h (Revision 12767) +++ src/network/network_server.h (Arbeitskopie) @@ -11,6 +11,7 @@ DEF_SERVER_SEND_COMMAND(PACKET_SERVER_SHUTDOWN); DEF_SERVER_SEND_COMMAND(PACKET_SERVER_NEWGAME); DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkTCPSocketHandler *cs, uint16 color, const char *command); +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_CLIENT_MOVE)(NetworkTCPSocketHandler *cs, uint16 client_index, uint8 player_index); bool NetworkFindName(char new_name[NETWORK_CLIENT_NAME_LENGTH]); void NetworkServer_HandleChat(NetworkAction action, DestType type, int dest, const char *msg, uint16 from_index); Index: src/network/network_client.cpp =================================================================== --- src/network/network_client.cpp (Revision 12767) +++ src/network/network_client.cpp (Arbeitskopie) @@ -5,6 +5,7 @@ #include "../stdafx.h" #include "../debug.h" #include "../openttd.h" +#include "../gfx_func.h" #include "network_data.h" #include "core/tcp.h" #include "network_client.h" @@ -394,6 +395,7 @@ // which is always an unique number on a server. DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CLIENT_INFO) { + const Player *player; NetworkClientInfo *ci; uint16 index = p->Recv_uint16(); PlayerID playas = (Owner)p->Recv_uint8(); @@ -414,8 +416,25 @@ // Client name changed, display the change NetworkTextMessage(NETWORK_ACTION_NAME_CHANGE, 1, false, ci->client_name, "%s", name); } else if (playas != ci->client_playas) { - // The player changed from client-player.. - // Do not display that for now + /* Client has been moved to another company or to spectator, show a message. */ + if (ci->client_playas != PLAYER_NEW_COMPANY && ci->client_playas != PLAYER_INACTIVE_CLIENT) { + /* if not valid player, force spectator, else check player exists */ + if (!IsValidPlayer(playas)) { + playas = PLAYER_SPECTATOR; + } else { + /* only if it's a valid player, actually get the player and check it */ + player = GetPlayer(playas); + if (!player->is_active) { + playas = PLAYER_SPECTATOR; + } + } + + if (playas == PLAYER_SPECTATOR || playas > MAX_PLAYERS) { + NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, 1, false, ci->client_name, "'%s' Moved To Spectators", ci->client_name); + } else { + NetworkTextMessage(NETWORK_ACTION_SERVER_MESSAGE, 1, false, ci->client_name, "'%s' Moved To Company #%d", ci->client_name, playas+1); + } + } } ci->client_playas = playas; @@ -855,6 +874,51 @@ return NETWORK_RECV_STATUS_OKAY; } +DEF_CLIENT_RECEIVE_COMMAND(PACKET_CLIENT_MOVE) +{ + const Player *player; + uint16 client_index; + PlayerID player_index; + + /* Nothing more in this packet... */ + client_index = p->Recv_uint16(); + player_index = (Owner)p->Recv_uint8(); + + if (client_index == 0) { + /* deffinately an invalide client id, debug message and do nothing. */ + DEBUG(net, 0, "[move] received client index = 0"); + return NETWORK_RECV_STATUS_OKAY; + } + + const NetworkClientInfo *ci = NetworkFindClientInfoFromIndex(client_index); + /* Just make sure we do not try to use a client_index that does not exist */ + if (ci != NULL) { + /* if not valid player, force spectator, else check player exists */ + if (!IsValidPlayer(player_index)) { + player_index = PLAYER_SPECTATOR; + } else { + /* only if it's a valid player, actually get the player and check it */ + player = GetPlayer(player_index); + if (!player->is_active) { + player_index = PLAYER_SPECTATOR; + } + } + + if (client_index == _network_own_client_index) { + /* this packet is actually for this client... apply the new player_index */ + DEBUG(net, 0, "[move] client %d to player %d", client_index, min(player_index+1, PLAYER_SPECTATOR)); + + _network_playas = player_index; + SetLocalPlayer(player_index); + + /* Disable any buttons in any windows the client is now not supposed to get to, and do it fast. */ + /* If this is not done fast enough, it can cause the client to be kicked or have an assert! */ + MarkWholeScreenDirty(); + } + } + + return NETWORK_RECV_STATUS_OKAY; +} // The layout for the receive-functions by the client @@ -899,6 +963,7 @@ NULL, /*PACKET_CLIENT_RCON,*/ RECEIVE_COMMAND(PACKET_SERVER_CHECK_NEWGRFS), NULL, /*PACKET_CLIENT_NEWGRFS_CHECKED,*/ + RECEIVE_COMMAND(PACKET_CLIENT_MOVE), }; // If this fails, check the array above with network_data.h