Skip to content

Commit

Permalink
Send vehicle caches to network clients to prevent desyncs due to bad …
Browse files Browse the repository at this point in the history
…GRFs
  • Loading branch information
JGRennison committed Nov 22, 2020
1 parent 4ba11fa commit 1f54c8a
Show file tree
Hide file tree
Showing 8 changed files with 283 additions and 16 deletions.
2 changes: 1 addition & 1 deletion src/network/network_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -617,7 +617,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::SendMap()
sent_packets = 4; // We start with trying 4 packets

/* Make a dump of the current game */
if (SaveWithFilter(this->savegame, true) != SL_OK) usererror("network savedump failed");
if (SaveWithFilter(this->savegame, true, true) != SL_OK) usererror("network savedump failed");
}

if (this->status == STATUS_MAP) {
Expand Down
29 changes: 17 additions & 12 deletions src/openttd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,22 @@ void SwitchToMode(SwitchMode new_mode)
SmallMapWindow::RebuildColourIndexIfNecessary();
}

void WriteVehicleInfo(char *&p, const char *last, const Vehicle *u, const Vehicle *v, uint length)
{
p += seprintf(p, last, ": type %i, vehicle %i (%i), company %i, unit number %i, wagon %i, engine: ",
(int)u->type, u->index, v->index, (int)u->owner, v->unitnumber, length);
SetDParam(0, u->engine_type);
p = GetString(p, STR_ENGINE_NAME, last);
uint32 grfid = u->GetGRFID();
if (grfid) {
p += seprintf(p, last, ", GRF: %08X", BSWAP32(grfid));
GRFConfig *grfconfig = GetGRFConfig(grfid);
if (grfconfig) {
p += seprintf(p, last, ", %s, %s", grfconfig->GetName(), grfconfig->filename);
}
}
}

/**
* Check the validity of some of the caches.
* Especially in the sense of desyncs between
Expand Down Expand Up @@ -1359,18 +1375,7 @@ void CheckCaches(bool force_check, std::function<void(const char *)> log)
}

auto output_veh_info = [&](char *&p, const Vehicle *u, const Vehicle *v, uint length) {
p += seprintf(p, lastof(cclog_buffer), ": type %i, vehicle %i (%i), company %i, unit number %i, wagon %i, engine: ",
(int)u->type, u->index, v->index, (int)u->owner, v->unitnumber, length);
SetDParam(0, u->engine_type);
p = GetString(p, STR_ENGINE_NAME, lastof(cclog_buffer));
uint32 grfid = u->GetGRFID();
if (grfid) {
p += seprintf(p, lastof(cclog_buffer), ", GRF: %08X", BSWAP32(grfid));
GRFConfig *grfconfig = GetGRFConfig(grfid);
if (grfconfig) {
p += seprintf(p, lastof(cclog_buffer), ", %s, %s", grfconfig->GetName(), grfconfig->filename);
}
}
WriteVehicleInfo(p, lastof(cclog_buffer), u, v, length);
};

#define CCLOGV(...) { \
Expand Down
4 changes: 4 additions & 0 deletions src/saveload/afterload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3840,6 +3840,10 @@ bool AfterLoadGame()
extern void YapfCheckRailSignalPenalties();
YapfCheckRailSignalPenalties();

if (_networking && !_network_server) {
SlProcessVENC();
}

/* Show this message last to avoid covering up an error message if we bail out part way */
switch (gcf_res) {
case GLC_COMPATIBLE: ShowErrorMessage(STR_NEWGRF_COMPATIBLE_LOAD_WARNING, INVALID_STRING_ID, WL_CRITICAL); break;
Expand Down
1 change: 1 addition & 0 deletions src/saveload/extended_ver_sl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
{ XSLFI_ORDER_FLAGS_EXTRA, XSCF_NULL, 1, 1, "order_flags_extra", nullptr, nullptr, nullptr },
{ XSLFI_ONE_WAY_DT_ROAD_STOP, XSCF_NULL, 1, 1, "one_way_dt_road_stop", nullptr, nullptr, nullptr },
{ XSLFI_ONE_WAY_ROAD_STATE, XSCF_NULL, 1, 1, "one_way_road_state", nullptr, nullptr, nullptr },
{ XSLFI_VENC_CHUNK, XSCF_IGNORABLE_ALL, 1, 1, "venc_chunk", nullptr, nullptr, "VENC" },
{ XSLFI_NULL, XSCF_NULL, 0, 0, nullptr, nullptr, nullptr, nullptr },// This is the end marker
};

Expand Down
1 change: 1 addition & 0 deletions src/saveload/extended_ver_sl.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ enum SlXvFeatureIndex {
XSLFI_ORDER_FLAGS_EXTRA, ///< Order flags field extra size
XSLFI_ONE_WAY_DT_ROAD_STOP, ///< One-way drive-through road stops
XSLFI_ONE_WAY_ROAD_STATE, ///< One-way road state cache
XSLFI_VENC_CHUNK, ///< VENC chunk

XSLFI_RIFF_HEADER_60_BIT, ///< Size field in RIFF chunk header is 60 bit
XSLFI_HEIGHT_8_BIT, ///< Map tile height is 8 bit instead of 4 bit, but savegame version may be before this became true in trunk
Expand Down
18 changes: 17 additions & 1 deletion src/saveload/saveload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "../string_func_extra.h"
#include "../fios.h"
#include "../error.h"
#include "../scope.h"
#include <atomic>
#include <string>

Expand Down Expand Up @@ -226,6 +227,7 @@ struct SaveLoadParams {

byte ff_state; ///< The state of fast-forward when saving started.
bool saveinprogress; ///< Whether there is currently a save in progress.
bool networkserversave; ///< Whether this save is being sent to a network client
};

static SaveLoadParams _sl; ///< Parameters used for/at saveload.
Expand Down Expand Up @@ -2896,6 +2898,8 @@ static inline void ClearSaveLoadState()
delete _sl.lf;
_sl.lf = nullptr;

_sl.networkserversave = false;

GamelogStopAnyAction();
}

Expand Down Expand Up @@ -3042,19 +3046,26 @@ static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
* Save the game using a (writer) filter.
* @param writer The filter to write the savegame to.
* @param threaded Whether to try to perform the saving asynchronously.
* @param networkserversave Whether this is a network server save.
* @return Return the result of the action. #SL_OK or #SL_ERROR
*/
SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded, bool networkserversave)
{
try {
_sl.action = SLA_SAVE;
_sl.networkserversave = networkserversave;
return DoSave(writer, threaded);
} catch (...) {
ClearSaveLoadState();
return SL_ERROR;
}
}

bool IsNetworkServerSave()
{
return _sl.networkserversave;
}

struct ThreadedLoadFilter : LoadFilter {
static const size_t BUFFER_COUNT = 4;

Expand Down Expand Up @@ -3179,6 +3190,10 @@ static SaveOrLoadResult DoLoad(LoadFilter *reader, bool load_check)
}

SlXvResetState();
SlResetVENC();
auto guard = scope_guard([&]() {
SlResetVENC();
});

uint32 hdr[2];
if (_sl.lf->Read((byte*)hdr, sizeof(hdr)) != sizeof(hdr)) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
Expand Down Expand Up @@ -3396,6 +3411,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, SaveLoadOperation fop, Detaile

default: NOT_REACHED();
}
_sl.networkserversave = false;

FILE *fh = (fop == SLO_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);

Expand Down
6 changes: 5 additions & 1 deletion src/saveload/saveload.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,8 +376,9 @@ void WaitTillSaved();
void ProcessAsyncSaveFinish();
void DoExitSave();

SaveOrLoadResult SaveWithFilter(struct SaveFilter *writer, bool threaded);
SaveOrLoadResult SaveWithFilter(struct SaveFilter *writer, bool threaded, bool networkserversave);
SaveOrLoadResult LoadWithFilter(struct LoadFilter *reader);
bool IsNetworkServerSave();

typedef void ChunkSaveLoadProc();
typedef void AutolengthProc(void *arg);
Expand Down Expand Up @@ -1085,6 +1086,9 @@ void NORETURN CDECL SlErrorCorruptFmt(const char *format, ...) WARN_FORMAT(1, 2)

bool SaveloadCrashWithMissingNewGRFs();

void SlResetVENC();
void SlProcessVENC();

extern char _savegame_format[8];
extern bool _do_autosave;

Expand Down

0 comments on commit 1f54c8a

Please sign in to comment.