From f6a8f275018797c39003975a931be41d2cb9715e Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 23 Nov 2015 19:47:59 +0000 Subject: [PATCH] Make server and all clients run desync checks if a client desyncs. --- src/command.cpp | 4 ++++ src/command_type.h | 2 ++ src/network/network_client.cpp | 3 +++ src/network/network_server.cpp | 5 +++++ src/openttd.cpp | 32 ++++++++++++++++++++++++++------ 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/src/command.cpp b/src/command.cpp index 6575fc34aa..660a9c0f37 100644 --- a/src/command.cpp +++ b/src/command.cpp @@ -212,6 +212,8 @@ CommandProc CmdRemovePlan; CommandProc CmdRemovePlanLine; CommandProc CmdChangePlanVisibility; +CommandProc CmdDesyncCheck; + #define DEF_CMD(proc, flags, type) {proc, #proc, (CommandFlags)flags, type} /** @@ -382,6 +384,8 @@ static const Command _command_proc_table[] = { DEF_CMD(CmdRemovePlan, 0, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_PLAN DEF_CMD(CmdRemovePlanLine, 0, CMDT_OTHER_MANAGEMENT ), // CMD_REMOVE_PLAN_LINE DEF_CMD(CmdChangePlanVisibility, 0, CMDT_OTHER_MANAGEMENT ), // CMD_CHANGE_PLAN_VISIBILITY + + DEF_CMD(CmdDesyncCheck, CMD_SERVER, CMDT_SERVER_SETTING ), // CMD_DESYNC_CHECK }; /*! diff --git a/src/command_type.h b/src/command_type.h index 6736c29892..4351086ae1 100644 --- a/src/command_type.h +++ b/src/command_type.h @@ -343,6 +343,8 @@ enum Commands { CMD_REMOVE_PLAN_LINE, CMD_CHANGE_PLAN_VISIBILITY, + CMD_DESYNC_CHECK, ///< Force desync checks to be run + CMD_END, ///< Must ALWAYS be on the end of this list!! (period) }; diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index f84cfb912b..a9a707d5f0 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -256,6 +256,9 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) DEBUG(desync, 1, "sync_err: %08x; %02x; %02X", _date, _date_fract, _tick_skip_counter); DEBUG(net, 0, "Sync error detected!"); my_client->ClientError(NETWORK_RECV_STATUS_DESYNC); + + extern void CheckCaches(bool force_check); + CheckCaches(true); return false; } diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index ed9ae4d140..6fbbed6f20 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -1179,6 +1179,11 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_ERROR(Packet *p NetworkAdminClientError(this->client_id, errorno); + if (errorno == NETWORK_ERROR_DESYNC) { + // have the server and all clients run some sanity checks + NetworkSendCommand(0, 0, 0, CMD_DESYNC_CHECK, NULL, NULL, _local_company, 0); + } + return this->CloseConnection(NETWORK_RECV_STATUS_CONN_LOST); } diff --git a/src/openttd.cpp b/src/openttd.cpp index 2f401793bf..cb33f8b748 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1232,13 +1232,15 @@ void SwitchToMode(SwitchMode new_mode) * the cached value and what the value would * be when calculated from the 'base' data. */ -static void CheckCaches() +void CheckCaches(bool force_check) { - /* Return here so it is easy to add checks that are run - * always to aid testing of caches. */ - if (_debug_desync_level < 1) return; + if (!force_check) { + /* Return here so it is easy to add checks that are run + * always to aid testing of caches. */ + if (_debug_desync_level < 1) return; - if (_debug_desync_level == 1 && CURRENT_SCALED_TICKS % 500 != 0) return; + if (_debug_desync_level == 1 && CURRENT_SCALED_TICKS % 500 != 0) return; + } /* Check the town caches. */ SmallVector old_town_caches; @@ -1432,6 +1434,24 @@ static void CheckCaches() } } +/** + * Network-safe forced desync check. + * @param tile unused + * @param flags operation to perform + * @param p1 unused + * @param p2 unused + * @param text unused + * @return the cost of this operation or an error + */ +CommandCost CmdDesyncCheck(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) +{ + if (flags & DC_EXEC) { + CheckCaches(true); + } + + return CommandCost(); +} + /** * State controlling game loop. * The state must not be changed from anywhere but here. @@ -1475,7 +1495,7 @@ void StateGameLoop() SaveOrLoad(name, SL_SAVE, AUTOSAVE_DIR, false); } - CheckCaches(); + CheckCaches(false); /* All these actions has to be done from OWNER_NONE * for multiplayer compatibility */