diff --git a/source.list b/source.list index 2dc1659aec..a530151757 100644 --- a/source.list +++ b/source.list @@ -460,6 +460,7 @@ core/alloc_type.hpp core/backup_type.hpp core/bitmath_func.cpp core/bitmath_func.hpp +core/checksum_func.hpp core/container_func.hpp core/dyn_arena_alloc.hpp core/endian_func.hpp diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 00d4ddad04..2ca4b84e16 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -40,6 +40,7 @@ #include "disaster_vehicle.h" #include "newgrf_airporttiles.h" #include "framerate_type.h" +#include "core/checksum_func.hpp" #include "table/strings.h" @@ -2127,6 +2128,7 @@ static bool AircraftEventHandler(Aircraft *v, int loop) bool Aircraft::Tick() { + UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos); if (!this->IsNormalAircraft()) return true; this->tick_counter++; diff --git a/src/core/checksum_func.hpp b/src/core/checksum_func.hpp new file mode 100644 index 0000000000..6845e14dae --- /dev/null +++ b/src/core/checksum_func.hpp @@ -0,0 +1,33 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file checksum_func.hpp Checksum utility functions. */ + +#ifndef CHECKSUM_FUNC_HPP +#define CHECKSUM_FUNC_HPP + +#include "bitmath_func.hpp" + +struct SimpleChecksum64 { + uint64 state = 0; + + void Update(uint64 input) + { + this->state = ROL(this->state, 1) ^ input ^ 0x123456789ABCDEF7ULL; + } +}; + +extern SimpleChecksum64 _state_checksum; + +inline void UpdateStateChecksum(uint64 input) +{ + _state_checksum.Update(input); +} + +#endif /* CHECKSUM_FUNC_HPP */ diff --git a/src/core/random_func.hpp b/src/core/random_func.hpp index 934703d6fb..d65060ccb7 100644 --- a/src/core/random_func.hpp +++ b/src/core/random_func.hpp @@ -12,6 +12,8 @@ #ifndef RANDOM_FUNC_HPP #define RANDOM_FUNC_HPP +#include "bitmath_func.hpp" + #if defined(__APPLE__) /* Apple already has Random declared */ #define Random OTTD_Random diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 2d52609dd3..ba5f30428d 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -47,6 +47,7 @@ #include "company_base.h" #include "core/random_func.hpp" #include "core/backup_type.hpp" +#include "core/checksum_func.hpp" #include "table/strings.h" @@ -707,6 +708,7 @@ static DisasterVehicleTickProc * const _disastervehicle_tick_procs[] = { bool DisasterVehicle::Tick() { + UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos); return _disastervehicle_tick_procs[this->subtype](this); } diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index 5ea274db69..bee23ac373 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -18,6 +18,7 @@ #include "animated_tile_func.h" #include "effectvehicle_func.h" #include "effectvehicle_base.h" +#include "core/checksum_func.hpp" #include @@ -670,6 +671,7 @@ EffectVehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, Eff bool EffectVehicle::Tick() { + UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos); return _effect_tick_procs[this->subtype](this); } diff --git a/src/network/network.cpp b/src/network/network.cpp index e705d74ba5..43e1922a3d 100644 --- a/src/network/network.cpp +++ b/src/network/network.cpp @@ -35,6 +35,7 @@ #include "../core/pool_func.hpp" #include "../gfx_func.h" #include "../error.h" +#include "../core/checksum_func.hpp" #include "../safeguards.h" @@ -74,6 +75,7 @@ uint32 _sync_seed_1; ///< Seed to compare during sync checks. #ifdef NETWORK_SEND_DOUBLE_SEED uint32 _sync_seed_2; ///< Second part of the seed. #endif +uint64 _sync_state_checksum; ///< State checksum to compare during sync checks. uint32 _sync_frame; ///< The frame to perform the sync check. bool _network_first_time; ///< Whether we have finished joining or not. bool _network_udp_server; ///< Is the UDP server started? @@ -1028,6 +1030,7 @@ void NetworkGameLoop() #ifdef NETWORK_SEND_DOUBLE_SEED _sync_seed_2 = _random.state[1]; #endif + _sync_state_checksum = _state_checksum.state; NetworkServer_Tick(send_frame); } else { diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index f7d779b9d7..dc03be2aff 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -32,6 +32,7 @@ #include "../core/backup_type.hpp" #include "../thread.h" #include "../crashlog.h" +#include "../core/checksum_func.hpp" #include "table/strings.h" @@ -282,9 +283,9 @@ void ClientNetworkGameSocketHandler::ClientError(NetworkRecvStatus res) if (_sync_frame != 0) { if (_sync_frame == _frame_counter) { #ifdef NETWORK_SEND_DOUBLE_SEED - if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1]) { + if (_sync_seed_1 != _random.state[0] || _sync_seed_2 != _random.state[1] || _sync_state_checksum != _state_checksum.state) { #else - if (_sync_seed_1 != _random.state[0]) { + if (_sync_seed_1 != _random.state[0] || _sync_state_checksum != _state_checksum.state) { #endif NetworkError(STR_NETWORK_ERROR_DESYNC); DEBUG(desync, 1, "sync_err: date{%08x; %02x; %02x}", _date, _date_fract, _tick_skip_counter); @@ -945,6 +946,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_FRAME(Packet *p #ifdef NETWORK_SEND_DOUBLE_SEED _sync_seed_2 = p->Recv_uint32(); #endif + _sync_state_checksum = p->Recv_uint64(); } #endif /* Receive the token. */ @@ -972,6 +974,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_SYNC(Packet *p) #ifdef NETWORK_SEND_DOUBLE_SEED _sync_seed_2 = p->Recv_uint32(); #endif + _sync_state_checksum = p->Recv_uint64(); return NETWORK_RECV_STATUS_OKAY; } diff --git a/src/network/network_internal.h b/src/network/network_internal.h index 73a8a56947..85b16923c7 100644 --- a/src/network/network_internal.h +++ b/src/network/network_internal.h @@ -118,6 +118,7 @@ extern uint32 _sync_seed_1; #ifdef NETWORK_SEND_DOUBLE_SEED extern uint32 _sync_seed_2; #endif +extern uint64 _sync_state_checksum; extern uint32 _sync_frame; extern bool _network_first_time; /* Vars needed for the join-GUI */ diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 1265bb6cf1..0ff9f53e95 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -689,6 +689,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendFrame() #ifdef NETWORK_SEND_DOUBLE_SEED p->Send_uint32(_sync_seed_2); #endif + p->Send_uint64(_sync_state_checksum); #endif /* If token equals 0, we need to make a new token and send that. */ @@ -711,6 +712,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendSync() #ifdef NETWORK_SEND_DOUBLE_SEED p->Send_uint32(_sync_seed_2); #endif + p->Send_uint64(_sync_state_checksum); this->SendPacket(p); return NETWORK_RECV_STATUS_OKAY; } diff --git a/src/openttd.cpp b/src/openttd.cpp index 88a100ae5b..2be27d8e82 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -77,6 +77,7 @@ #include "string_func_extra.h" #include "industry.h" #include "cargopacket.h" +#include "core/checksum_func.hpp" #include "linkgraph/linkgraphschedule.h" #include "tracerestrict.h" @@ -103,6 +104,8 @@ GameEventFlags _game_events_overall; time_t _game_load_time; +SimpleChecksum64 _state_checksum; + /** * Error handling for fatal user errors. * @param s the string to print. @@ -1749,6 +1752,11 @@ void StateGameLoop() CallWindowGameTickEvent(); NewsLoop(); cur_company.Restore(); + + Company *c; + FOR_ALL_COMPANIES(c) { + UpdateStateChecksum(c->money); + } } assert(IsLocalCompany()); diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index 746b5786ce..d26e5217ca 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -39,6 +39,7 @@ #include "framerate_type.h" #include "scope_info.h" #include "string_func.h" +#include "core/checksum_func.hpp" #include "table/strings.h" @@ -1061,6 +1062,7 @@ static Trackdir RoadFindPathToDest(RoadVehicle *v, TileIndex tile, DiagDirection default: NOT_REACHED(); } + UpdateStateChecksum((((uint64) v->index) << 32) | (path_found << 16) | best_track); v->HandlePathfindingResult(path_found); found_best_track:; @@ -1726,6 +1728,8 @@ Money RoadVehicle::GetRunningCost() const bool RoadVehicle::Tick() { + UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos); + UpdateStateChecksum((((uint64) this->state) << 32) | this->frame); if (this->IsFrontEngine()) { if (!(this->IsRoadVehicleStopped())) this->running_ticks++; return RoadVehController(this); diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index afdab325fb..377f507635 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -108,6 +108,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_GAME_EVENTS, XSCF_NULL, 1, 1, "game_events", nullptr, nullptr, nullptr }, { XSLFI_ROAD_LAYOUT_CHANGE_CTR, XSCF_NULL, 1, 1, "road_layout_change_ctr", nullptr, nullptr, nullptr }, { XSLFI_TOWN_CARGO_MATRIX, XSCF_NULL, 1, 1, "town_cargo_matrix", nullptr, nullptr, nullptr }, + { XSLFI_STATE_CHECKSUM, XSCF_NULL, 1, 1, "state_checksum", nullptr, nullptr, nullptr }, { XSLFI_DEBUG, XSCF_IGNORABLE_ALL, 1, 1, "debug", nullptr, nullptr, "DBGL" }, { XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker }; diff --git a/src/saveload/extended_ver_sl.h b/src/saveload/extended_ver_sl.h index 2011fab96a..a52e0c955a 100644 --- a/src/saveload/extended_ver_sl.h +++ b/src/saveload/extended_ver_sl.h @@ -75,6 +75,7 @@ enum SlXvFeatureIndex { XSLFI_GAME_EVENTS, ///< Game event flags XSLFI_ROAD_LAYOUT_CHANGE_CTR, ///< Road layout change counter XSLFI_TOWN_CARGO_MATRIX, ///< Town cargo matrix savegame format changes + XSLFI_STATE_CHECKSUM, ///< State checksum XSLFI_DEBUG, ///< Debugging info XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit diff --git a/src/saveload/misc_sl.cpp b/src/saveload/misc_sl.cpp index 77167d08d6..a6eee84661 100644 --- a/src/saveload/misc_sl.cpp +++ b/src/saveload/misc_sl.cpp @@ -19,6 +19,7 @@ #include "../core/random_func.hpp" #include "../fios.h" #include "../road_type.h" +#include "../core/checksum_func.hpp" #include "saveload.h" @@ -86,6 +87,7 @@ static const SaveLoadGlobVarList _date_desc[] = { SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120), SLEG_VAR(_random.state[0], SLE_UINT32), SLEG_VAR(_random.state[1], SLE_UINT32), + SLEG_CONDVAR_X(_state_checksum.state, SLE_UINT64, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATE_CHECKSUM)), SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10), SLE_CONDNULL(4, SLV_10, SLV_120), SLEG_VAR(_cur_company_tick_index, SLE_FILE_U8 | SLE_VAR_U32), @@ -114,6 +116,7 @@ static const SaveLoadGlobVarList _date_check_desc[] = { SLE_CONDNULL(2, SL_MIN_VERSION, SLV_120), SLE_NULL(4), // _random.state[0] SLE_NULL(4), // _random.state[1] + SLE_CONDNULL_X(8, SL_MIN_VERSION, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_STATE_CHECKSUM)), // _state_checksum.state SLE_CONDNULL(1, SL_MIN_VERSION, SLV_10), SLE_CONDNULL(4, SLV_10, SLV_120), SLE_NULL(1), // _cur_company_tick_index diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index 2ecde98843..45c33414e3 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -36,6 +36,7 @@ #include "tunnelbridge_map.h" #include "zoom_func.h" #include "framerate_type.h" +#include "core/checksum_func.hpp" #include "table/strings.h" @@ -523,6 +524,7 @@ static Track ChooseShipTrack(Ship *v, TileIndex tile, DiagDirection enterdir, Tr default: NOT_REACHED(); } } + UpdateStateChecksum((((uint64) v->index) << 32) | (path_found << 16) | track); v->HandlePathfindingResult(path_found); return track; @@ -948,6 +950,7 @@ reverse_direction: bool Ship::Tick() { + UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos); if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++; ShipController(this); diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index 2a146dc2a6..071d78acd3 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -43,6 +43,7 @@ #include "engine_func.h" #include "bridge_signal_map.h" #include "scope_info.h" +#include "core/checksum_func.hpp" #include "table/strings.h" #include "table/train_cmd.h" @@ -3127,6 +3128,7 @@ static Track ChooseTrainTrack(Train *v, TileIndex tile, DiagDirection enterdir, TileIndex new_tile = res_dest.tile; Track next_track = DoTrainPathfind(v, new_tile, dest_enterdir, tracks, path_found, do_track_reservation, &res_dest); + UpdateStateChecksum((((uint64) v->index) << 32) | (path_found << 16) | next_track); if (new_tile == tile) best_track = next_track; v->HandlePathfindingResult(path_found); } @@ -4971,6 +4973,7 @@ Money Train::GetRunningCost() const */ bool Train::Tick() { + UpdateStateChecksum((((uint64) this->x_pos) << 32) | (this->y_pos << 16) | this->track ); if (this->IsFrontEngine()) { if (!(this->vehstatus & VS_STOPPED) || this->cur_speed > 0) this->running_ticks++;