diff --git a/src/lang/english.txt b/src/lang/english.txt index edac1dfc81..1167d3c2fc 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -1419,6 +1419,7 @@ STR_NETWORK_CLIENT_LIST :{WHITE}Client L STR_NETWORK_ERR_NOTAVAILABLE :{WHITE} No network devices found or compiled without ENABLE_NETWORK STR_NETWORK_ERR_NOSERVER :{WHITE} Could not find any network games STR_NETWORK_ERR_NOCONNECTION :{WHITE} The server didn't answer the request +STR_NETWORK_ERR_NEWGRF_MISMATCH :{WHITE} Could not connect due to NewGRF mismatch STR_NETWORK_ERR_DESYNC :{WHITE} Network-Game synchronisation failed STR_NETWORK_ERR_LOSTCONNECTION :{WHITE} Network-Game connection lost STR_NETWORK_ERR_SAVEGAMEERROR :{WHITE} Could not load savegame @@ -1440,6 +1441,7 @@ STR_NETWORK_ERR_CLIENT_DESYNC :desync error STR_NETWORK_ERR_CLIENT_SAVEGAME :could not load map STR_NETWORK_ERR_CLIENT_CONNECTION_LOST :connection lost STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR :protocol error +STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH :NewGRF mismatch STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED :not authorized STR_NETWORK_ERR_CLIENT_NOT_EXPECTED :received strange packet STR_NETWORK_ERR_CLIENT_WRONG_REVISION :wrong revision diff --git a/src/network/core/core.h b/src/network/core/core.h index 865213471b..729145e7f8 100644 --- a/src/network/core/core.h +++ b/src/network/core/core.h @@ -19,6 +19,7 @@ void NetworkCoreShutdown(void); typedef enum { NETWORK_RECV_STATUS_OKAY, ///< Everything is okay NETWORK_RECV_STATUS_DESYNC, ///< A desync did occur + NETWORK_RECV_STATUS_NEWGRF_MISMATCH, ///< We did not have the required NewGRFs NETWORK_RECV_STATUS_SAVEGAME, ///< Something went wrong (down)loading the savegame NETWORK_RECV_STATUS_CONN_LOST, ///< The conection is 'just' lost NETWORK_RECV_STATUS_MALFORMED_PACKET, ///< We apparently send a malformed packet diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h index 74e2880e74..232d6f91ab 100644 --- a/src/network/core/tcp.h +++ b/src/network/core/tcp.h @@ -52,6 +52,8 @@ enum { PACKET_SERVER_NEWGAME, PACKET_SERVER_RCON, PACKET_CLIENT_RCON, + PACKET_SERVER_CHECK_NEWGRFS, + PACKET_CLIENT_NEWGRFS_CHECKED, PACKET_END ///< Must ALWAYS be on the end of this list!! (period) }; diff --git a/src/network/network.cpp b/src/network/network.cpp index 4ab8d33900..a181f9055e 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -250,9 +250,10 @@ static void NetworkClientError(NetworkRecvStatus res, NetworkTCPSocketHandler* c } switch (res) { - case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; - case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; - default: errorno = NETWORK_ERROR_GENERAL; break; + case NETWORK_RECV_STATUS_DESYNC: errorno = NETWORK_ERROR_DESYNC; break; + case NETWORK_RECV_STATUS_SAVEGAME: errorno = NETWORK_ERROR_SAVEGAME_FAILED; break; + case NETWORK_RECV_STATUS_NEWGRF_MISMATCH: errorno = NETWORK_ERROR_NEWGRF_MISMATCH; break; + default: errorno = NETWORK_ERROR_GENERAL; break; } // This means we fucked up and the server closed the connection if (res != NETWORK_RECV_STATUS_SERVER_ERROR && res != NETWORK_RECV_STATUS_SERVER_FULL && @@ -282,6 +283,7 @@ char* GetNetworkErrorMsg(char* buf, NetworkErrorCode err, const char* last) STR_NETWORK_ERR_CLIENT_SAVEGAME, STR_NETWORK_ERR_CLIENT_CONNECTION_LOST, STR_NETWORK_ERR_CLIENT_PROTOCOL_ERROR, + STR_NETWORK_ERR_CLIENT_NEWGRF_MISMATCH, STR_NETWORK_ERR_CLIENT_NOT_AUTHORIZED, STR_NETWORK_ERR_CLIENT_NOT_EXPECTED, STR_NETWORK_ERR_CLIENT_WRONG_REVISION, diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 0165298894..abc61ff461 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -78,6 +78,18 @@ DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_JOIN) NetworkSend_Packet(p, MY_CLIENT); } +DEF_CLIENT_SEND_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED) +{ + // + // Packet: CLIENT_NEWGRFS_CHECKED + // Function: Tell the server that we have the required GRFs + // Data: + // + + Packet *p = NetworkSend_Init(PACKET_CLIENT_NEWGRFS_CHECKED); + NetworkSend_Packet(p, MY_CLIENT); +} + DEF_CLIENT_SEND_COMMAND_PARAM(PACKET_CLIENT_PASSWORD)(NetworkPasswordType type, const char *password) { // @@ -408,6 +420,37 @@ DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_ERROR) return NETWORK_RECV_STATUS_SERVER_ERROR; } +DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_CHECK_NEWGRFS) +{ + uint grf_count = NetworkRecv_uint8(MY_CLIENT, p); + NetworkRecvStatus ret = NETWORK_RECV_STATUS_OKAY; + + /* Check all GRFs */ + for (; grf_count > 0; grf_count--) { + GRFConfig c; + MY_CLIENT->Recv_GRFIdentifier(p, &c); + + /* Check whether we know this GRF */ + const GRFConfig *f = FindGRFConfig(c.grfid, c.md5sum); + if (f == NULL) { + /* We do not know this GRF, bail out of initialization */ + char buf[sizeof(c.md5sum) * 2 + 1]; + md5sumToString(buf, lastof(buf), c.md5sum); + DEBUG(grf, 0, "NewGRF %08X not found; checksum %s", BSWAP32(c.grfid), buf); + ret = NETWORK_RECV_STATUS_NEWGRF_MISMATCH; + } + } + + if (ret == NETWORK_RECV_STATUS_OKAY) { + /* Start receiving the map */ + SEND_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED)(); + } else { + /* NewGRF mismatch, bail out */ + _switch_mode_errorstr = STR_NETWORK_ERR_NEWGRF_MISMATCH; + } + return ret; +} + DEF_CLIENT_RECEIVE_COMMAND(PACKET_SERVER_NEED_PASSWORD) { NetworkPasswordType type = (NetworkPasswordType)NetworkRecv_uint8(MY_CLIENT, p); @@ -788,6 +831,8 @@ static NetworkClientPacket* const _network_client_packet[] = { RECEIVE_COMMAND(PACKET_SERVER_NEWGAME), RECEIVE_COMMAND(PACKET_SERVER_RCON), NULL, /*PACKET_CLIENT_RCON,*/ + RECEIVE_COMMAND(PACKET_SERVER_CHECK_NEWGRFS), + NULL, /*PACKET_CLIENT_NEWGRFS_CHECKED,*/ }; // If this fails, check the array above with network_data.h diff --git a/src/network/network_data.h b/src/network/network_data.h index 46561c51fd..676c9b66cd 100644 --- a/src/network/network_data.h +++ b/src/network/network_data.h @@ -34,6 +34,7 @@ typedef enum { NETWORK_ERROR_SAVEGAME_FAILED, NETWORK_ERROR_CONNECTION_LOST, NETWORK_ERROR_ILLEGAL_PACKET, + NETWORK_ERROR_NEWGRF_MISMATCH, // Signals from servers NETWORK_ERROR_NOT_AUTHORIZED, diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index f69340afd5..57a530921b 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -183,6 +183,32 @@ DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_ERROR)(NetworkTCPSocketHandler *cs, NetworkCloseClient(cs); } +DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_CHECK_NEWGRFS)(NetworkTCPSocketHandler *cs) +{ + // + // Packet: PACKET_SERVER_CHECK_NEWGRFS + // Function: Sends info about the used GRFs to the client + // Data: + // uint8: Amount of GRFs + // And then for each GRF: + // uint32: GRF ID + // 16 * uint8: MD5 checksum of the GRF + // + + Packet *p = NetworkSend_Init(PACKET_SERVER_CHECK_NEWGRFS); + const GRFConfig *c; + uint grf_count = 0; + + for (c = _grfconfig; c != NULL; c = c->next) grf_count++; + + NetworkSend_uint8 (p, grf_count); + for (c = _grfconfig; c != NULL; c = c->next) { + cs->Send_GRFIdentifier(p, c); + } + + NetworkSend_Packet(p, cs); +} + DEF_SERVER_SEND_COMMAND_PARAM(PACKET_SERVER_NEED_PASSWORD)(NetworkTCPSocketHandler *cs, NetworkPasswordType type) { // @@ -570,6 +596,22 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_COMPANY_INFO) SEND_COMMAND(PACKET_SERVER_COMPANY_INFO)(cs); } +DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED) +{ + NetworkClientInfo *ci = DEREF_CLIENT_INFO(cs); + + /* We now want a password from the client else we do not allow him in! */ + if (_network_game_info.use_password) { + SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD); + } else { + if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { + SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); + } else { + SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); + } + } +} + DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN) { char name[NETWORK_CLIENT_NAME_LENGTH]; @@ -636,20 +678,14 @@ DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_JOIN) ci->client_playas = playas; ci->client_lang = client_lang; - // We now want a password from the client - // else we do not allow him in! - if (_network_game_info.use_password) { - SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_GAME_PASSWORD); - } else { - if (IsValidPlayer(ci->client_playas) && _network_player_info[ci->client_playas].password[0] != '\0') { - SEND_COMMAND(PACKET_SERVER_NEED_PASSWORD)(cs, NETWORK_COMPANY_PASSWORD); - } else { - SEND_COMMAND(PACKET_SERVER_WELCOME)(cs); - } - } - /* Make sure companies to which people try to join are not autocleaned */ if (IsValidPlayer(playas)) _network_player_info[playas].months_empty = 0; + + if (_grfconfig == NULL) { + RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED)(cs, NULL); + } else { + SEND_COMMAND(PACKET_SERVER_CHECK_NEWGRFS)(cs); + } } DEF_SERVER_RECEIVE_COMMAND(PACKET_CLIENT_PASSWORD) @@ -1184,6 +1220,8 @@ static NetworkServerPacket* const _network_server_packet[] = { NULL, /*PACKET_SERVER_NEWGAME,*/ NULL, /*PACKET_SERVER_RCON,*/ RECEIVE_COMMAND(PACKET_CLIENT_RCON), + NULL, /*PACKET_CLIENT_CHECK_NEWGRFS,*/ + RECEIVE_COMMAND(PACKET_CLIENT_NEWGRFS_CHECKED), }; // If this fails, check the array above with network_data.h