Network: Add state checksum which is checked in network sync

desync-debugging
Jonathan G Rennison 5 years ago
parent 46d5afd6e8
commit 888fd9ce1e

@ -37,6 +37,7 @@
#include "disaster_vehicle.h"
#include "newgrf_airporttiles.h"
#include "framerate_type.h"
#include "core/checksum_func.hpp"
#include "table/strings.h"
@ -2066,6 +2067,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;
PerformanceAccumulator framerate(PFE_GL_AIRCRAFT);

@ -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 <http://www.gnu.org/licenses/>.
*/
/** @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 */

@ -10,6 +10,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

@ -45,6 +45,7 @@
#include "company_base.h"
#include "core/random_func.hpp"
#include "core/backup_type.hpp"
#include "core/checksum_func.hpp"
#include "table/strings.h"
@ -691,6 +692,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);
}

@ -16,6 +16,7 @@
#include "animated_tile_func.h"
#include "effectvehicle_func.h"
#include "effectvehicle_base.h"
#include "core/checksum_func.hpp"
#include "safeguards.h"
@ -642,6 +643,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);
}

@ -33,6 +33,7 @@
#include "../core/pool_func.hpp"
#include "../gfx_func.h"
#include "../error.h"
#include "../core/checksum_func.hpp"
#include "../safeguards.h"
@ -72,6 +73,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?
@ -986,6 +988,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 {

@ -29,6 +29,7 @@
#include "../core/backup_type.hpp"
#include "../thread.h"
#include "../crashlog.h"
#include "../core/checksum_func.hpp"
#include "table/strings.h"
@ -277,9 +278,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: %08x; %02x", _date, _date_fract);
@ -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;
}

@ -116,6 +116,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 */

@ -681,6 +681,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. */
@ -703,6 +704,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;
}

@ -65,7 +65,7 @@
#include "viewport_sprite_sorter.h"
#include "framerate_type.h"
#include "industry.h"
#include "string_func.h"
#include "core/checksum_func.hpp"
#include "linkgraph/linkgraphschedule.h"
@ -89,6 +89,8 @@ extern char *_config_file;
time_t _game_load_time;
SimpleChecksum64 _state_checksum;
/**
* Error handling for fatal user errors.
* @param s the string to print.
@ -1535,6 +1537,10 @@ void StateGameLoop()
CallWindowGameTickEvent();
NewsLoop();
cur_company.Restore();
for (const Company *c : Company::Iterate()) {
UpdateStateChecksum(c->money);
}
}
assert(IsLocalCompany());

@ -34,6 +34,7 @@
#include "newgrf.h"
#include "zoom_func.h"
#include "framerate_type.h"
#include "core/checksum_func.hpp"
#include "table/strings.h"
@ -990,6 +991,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:;
@ -1634,6 +1636,9 @@ bool RoadVehicle::Tick()
this->tick_counter++;
UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos);
UpdateStateChecksum((((uint64) this->state) << 32) | this->frame);
if (this->IsFrontEngine()) {
if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
return RoadVehController(this);

@ -16,6 +16,7 @@
#include "../gfx_func.h"
#include "../core/random_func.hpp"
#include "../fios.h"
#include "../core/checksum_func.hpp"
#include "saveload.h"
@ -82,6 +83,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(_state_checksum.state, SLE_UINT64, SLV_DESYNC_STATE_CHECKSUM, SL_MAX_VERSION),
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),
@ -107,6 +109,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(8, SLV_DESYNC_STATE_CHECKSUM, SL_MAX_VERSION), // _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

@ -303,6 +303,8 @@ enum SaveLoadVersion : uint16 {
SLV_TRADING_AGE, ///< 217 PR#7780 Configurable company trading age.
SLV_ENDING_YEAR, ///< 218 PR#7747 v1.10 Configurable ending year.
SLV_DESYNC_STATE_CHECKSUM = 1000, ///< 1000 NB: not a proper savegame version, this is done correctly in source branch
SL_MAX_VERSION, ///< Highest possible saveload version
};

@ -34,6 +34,7 @@
#include "framerate_type.h"
#include "industry.h"
#include "industry_map.h"
#include "core/checksum_func.hpp"
#include "table/strings.h"
@ -492,6 +493,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;
@ -799,6 +801,8 @@ bool Ship::Tick()
{
PerformanceAccumulator framerate(PFE_GL_SHIPS);
UpdateStateChecksum((((uint64) this->x_pos) << 32) | this->y_pos);
if (!(this->vehstatus & VS_STOPPED)) this->running_ticks++;
ShipController(this);

@ -34,6 +34,7 @@
#include "zoom_func.h"
#include "newgrf_debug.h"
#include "framerate_type.h"
#include "core/checksum_func.hpp"
#include "table/strings.h"
#include "table/train_cmd.h"
@ -2580,6 +2581,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);
}
@ -3898,6 +3900,8 @@ bool Train::Tick()
this->tick_counter++;
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++;

Loading…
Cancel
Save