From 04709f279809125e24c3652f182eac0e56c1d90f Mon Sep 17 00:00:00 2001 From: rubidium Date: Fri, 23 Jan 2009 22:18:06 +0000 Subject: (svn r15242) -Feature: allow moving clients between companies/spectators by the server and the clients themselves (dihedral) --- src/network/network_server.cpp | 125 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) (limited to 'src/network/network_server.cpp') diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index d291bb92a..647358ecf 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -586,6 +586,32 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_RCON)(NetworkClientSocket *cs, uint1 cs->Send_Packet(p); } +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_MOVE)(NetworkClientSocket *cs, ClientID client_id, CompanyID company_id) +{ + Packet *p = NetworkSend_Init(PACKET_SERVER_MOVE); + + p->Send_uint32(client_id); + p->Send_uint8(company_id); + cs->Send_Packet(p); +} + +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_COMPANY_UPDATE)(NetworkClientSocket *cs) +{ + Packet *p = NetworkSend_Init(PACKET_SERVER_COMPANY_UPDATE); + + p->Send_uint16(_network_company_passworded); + cs->Send_Packet(p); +} + +DEF_SERVER_SEND_COMMAND(PACKET_SERVER_CONFIG_UPDATE) +{ + Packet *p = NetworkSend_Init(PACKET_SERVER_CONFIG_UPDATE); + + p->Send_uint8(_settings_client.network.max_companies); + p->Send_uint8(_settings_client.network.max_spectators); + cs->Send_Packet(p); +} + // ********** // Receiving functions // DEF_SERVER_RECEIVE_COMMAND has parameter: NetworkClientSocket *cs, Packet *p @@ -803,6 +829,12 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MAP_OK) NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_BROADCAST, 0, "", CLIENT_ID_SERVER, NETWORK_SERVER_MESSAGE_GAME_PAUSED_CONNECT); } + + /* also update the new client with our max values */ + SEND_COMMAND(PACKET_SERVER_CONFIG_UPDATE)(cs); + + /* quickly update the syncing client with company details */ + SEND_COMMAND(PACKET_SERVER_COMPANY_UPDATE)(cs); } else { // Wrong status for this packet, give a warning to client, and close connection SEND_COMMAND(PACKET_SERVER_ERROR)(cs, NETWORK_ERROR_NOT_EXPECTED); @@ -872,6 +904,12 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMMAND) return; } + /* Check if we are full - else it's possible for spectators to send a CMD_COMPANY_CTRL and the company is created regardless of max_companies! */ + if (ActiveCompanyCount() >= _settings_client.network.max_companies) { + NetworkServerSendChat(NETWORK_ACTION_SERVER_MESSAGE, DESTTYPE_CLIENT, ci->client_id, "cannot create new company, server full", CLIENT_ID_SERVER); + return; + } + /* XXX - Execute the command as a valid company. Normally this would be done by a * spectator, but that is not allowed any commands. So do an impersonation. The drawback * of this is that the first company's last_built_tile is also updated... */ @@ -1145,6 +1183,7 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_SET_PASSWORD) if (IsValidCompanyID(ci->client_playas)) { strecpy(_network_company_states[ci->client_playas].password, password, lastof(_network_company_states[ci->client_playas].password)); + NetworkServerUpdateCompanyPassworded(ci->client_playas, !StrEmpty(_network_company_states[ci->client_playas].password)); } } @@ -1197,6 +1236,30 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_RCON) return; } +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_MOVE) +{ + CompanyID company_id = (Owner)p->Recv_uint8(); + + /* Check if the company is valid */ + if (!IsValidCompanyID(company_id) && company_id != COMPANY_SPECTATOR) return; + + /* Check if we require a password for this company */ + if (company_id != COMPANY_SPECTATOR && !StrEmpty(_network_company_states[company_id].password)) { + /* we need a password from the client - should be in this packet */ + char password[NETWORK_PASSWORD_LENGTH]; + p->Recv_string(password, sizeof(password)); + + /* Incorrect password sent, return! */ + if (strcmp(password, _network_company_states[company_id].password) != 0) { + DEBUG(net, 2, "[move] wrong password from client-id #%d for company #%d", cs->client_id, company_id + 1); + return; + } + } + + /* if we get here we can move the client */ + NetworkServerDoMove(cs->client_id, company_id); +} + // The layout for the receive-functions by the server typedef void NetworkServerPacket(NetworkClientSocket *cs, Packet *p); @@ -1240,6 +1303,10 @@ static NetworkServerPacket * const _network_server_packet[] = { RECEIVE_COMMAND(PACKET_CLIENT_RCON), NULL, /*PACKET_CLIENT_CHECK_NEWGRFS,*/ RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED), + NULL, /*PACKET_SERVER_MOVE,*/ + RECEIVE_COMMAND(PACKET_CLIENT_MOVE), + NULL, /*PACKET_SERVER_COMPANY_UPDATE,*/ + NULL, /*PACKET_SERVER_CONFIG_UPDATE,*/ }; // If this fails, check the array above with network_data.h @@ -1394,6 +1461,7 @@ static void NetworkAutoCleanCompanies() _network_company_states[c->index].password[0] = '\0'; IConsolePrintF(CC_DEFAULT, "Auto-removed protection from company #%d", c->index + 1); _network_company_states[c->index].months_empty = 0; + NetworkServerUpdateCompanyPassworded(c->index, false); } } else { /* It is not empty, reset the date */ @@ -1635,6 +1703,63 @@ void NetworkServerShowStatusToConsole() } } +/** + * Send Config Update + */ +void NetworkServerSendConfigUpdate() +{ + NetworkClientSocket *cs; + + FOR_ALL_CLIENT_SOCKETS(cs) { + SEND_COMMAND(PACKET_SERVER_CONFIG_UPDATE)(cs); + } +} + +void NetworkServerUpdateCompanyPassworded(CompanyID company_id, bool passworded) +{ + if (NetworkCompanyIsPassworded(company_id) == passworded) return; + + SB(_network_company_passworded, company_id, 1, !!passworded); + + NetworkClientSocket *cs; + FOR_ALL_CLIENT_SOCKETS(cs) { + SEND_COMMAND(PACKET_SERVER_COMPANY_UPDATE)(cs); + } +} + +/** + * Handle the tid-bits of moving a client from one company to another. + * @param client_id id of the client we want to move. + * @param company_id id of the company we want to move the client to. + * @return void + **/ +void NetworkServerDoMove(ClientID client_id, CompanyID company_id) +{ + /* Only allow non-dedicated servers and normal clients to be moved */ + if (client_id == CLIENT_ID_SERVER && _network_dedicated) return; + + NetworkClientInfo *ci = NetworkFindClientInfoFromClientID(client_id); + + /* No need to waste network resources if the client is in the company already! */ + if (ci->client_playas == company_id) return; + + ci->client_playas = company_id; + + if (client_id == CLIENT_ID_SERVER) { + SetLocalCompany(company_id); + } else { + SEND_COMMAND(PACKET_SERVER_MOVE)(NetworkFindClientStateFromClientID(client_id), client_id, company_id); + } + + /* announce the client's move */ + NetworkUpdateClientInfo(client_id); + + NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN; + NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1); + + CheckMinActiveClients(); +} + void NetworkServerSendRcon(ClientID client_id, ConsoleColour colour_code, const char *string) { SEND_COMMAND(PACKET_SERVER_RCON)(NetworkFindClientStateFromClientID(client_id), colour_code, string); -- cgit v1.2.3-54-g00ecf