mirror of
https://github.com/JGRennison/OpenTTD-patches.git
synced 2024-11-04 06:00:15 +00:00
(svn r19975) -Add: SL_LOAD_CHECK mode for partial reading of savegames.
This commit is contained in:
parent
3d38176cd5
commit
ec903570f1
20
src/fios.h
20
src/fios.h
@ -17,6 +17,26 @@
|
|||||||
#include "core/enum_type.hpp"
|
#include "core/enum_type.hpp"
|
||||||
#include "gfx_type.h"
|
#include "gfx_type.h"
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for loading in mode SL_LOAD_CHECK.
|
||||||
|
*/
|
||||||
|
struct LoadCheckData {
|
||||||
|
bool checkable; ///< True if the savegame could be checked by SL_LOAD_CHECK. (Old savegames are not checkable.)
|
||||||
|
StringID error; ///< Error message from loading. INVALID_STRING_ID if no error.
|
||||||
|
char *error_data; ///< Data to pass to SetDParamStr when displaying #error.
|
||||||
|
|
||||||
|
LoadCheckData() : error_data(NULL)
|
||||||
|
{
|
||||||
|
this->Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clear();
|
||||||
|
};
|
||||||
|
|
||||||
|
extern LoadCheckData _load_check_data;
|
||||||
|
|
||||||
|
|
||||||
enum FileSlots {
|
enum FileSlots {
|
||||||
/**
|
/**
|
||||||
* Slot used for the GRF scanning and such. This slot cannot be reused
|
* Slot used for the GRF scanning and such. This slot cannot be reused
|
||||||
|
@ -29,11 +29,24 @@
|
|||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
SaveLoadDialogMode _saveload_mode;
|
SaveLoadDialogMode _saveload_mode;
|
||||||
|
LoadCheckData _load_check_data; ///< Data loaded from save during SL_LOAD_CHECK.
|
||||||
|
|
||||||
static bool _fios_path_changed;
|
static bool _fios_path_changed;
|
||||||
static bool _savegame_sort_dirty;
|
static bool _savegame_sort_dirty;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset read data.
|
||||||
|
*/
|
||||||
|
void LoadCheckData::Clear()
|
||||||
|
{
|
||||||
|
this->checkable = false;
|
||||||
|
this->error = INVALID_STRING_ID;
|
||||||
|
free(this->error_data);
|
||||||
|
this->error_data = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
enum SaveLoadWindowWidgets {
|
enum SaveLoadWindowWidgets {
|
||||||
SLWW_WINDOWTITLE,
|
SLWW_WINDOWTITLE,
|
||||||
SLWW_SORT_BYNAME,
|
SLWW_SORT_BYNAME,
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "../string_func.h"
|
#include "../string_func.h"
|
||||||
#include "../engine_base.h"
|
#include "../engine_base.h"
|
||||||
#include "../company_base.h"
|
#include "../company_base.h"
|
||||||
|
#include "../fios.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
@ -64,6 +65,7 @@ enum SaveLoadAction {
|
|||||||
SLA_SAVE, ///< saving
|
SLA_SAVE, ///< saving
|
||||||
SLA_PTRS, ///< fixing pointers
|
SLA_PTRS, ///< fixing pointers
|
||||||
SLA_NULL, ///< null all pointers (on loading error)
|
SLA_NULL, ///< null all pointers (on loading error)
|
||||||
|
SLA_LOAD_CHECK, ///< partial loading into #_load_check_data
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NeedLength {
|
enum NeedLength {
|
||||||
@ -194,6 +196,12 @@ static void SlNullPointers()
|
|||||||
* pretty ugly, and seriously interferes with any multithreaded approaches */
|
* pretty ugly, and seriously interferes with any multithreaded approaches */
|
||||||
static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
|
static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
|
||||||
{
|
{
|
||||||
|
/* Distinguish between loading into _load_check_data vs. normal save/load. */
|
||||||
|
if (_sl.action == SLA_LOAD_CHECK) {
|
||||||
|
_load_check_data.error = string;
|
||||||
|
free(_load_check_data.error_data);
|
||||||
|
_load_check_data.error_data = (extra_msg == NULL) ? NULL : strdup(extra_msg);
|
||||||
|
} else {
|
||||||
_sl.error_str = string;
|
_sl.error_str = string;
|
||||||
free(_sl.extra_msg);
|
free(_sl.extra_msg);
|
||||||
_sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
|
_sl.extra_msg = (extra_msg == NULL) ? NULL : strdup(extra_msg);
|
||||||
@ -201,6 +209,7 @@ static void NORETURN SlError(StringID string, const char *extra_msg = NULL)
|
|||||||
* the pointers are actually filled with indices, which means that
|
* the pointers are actually filled with indices, which means that
|
||||||
* when we access them during cleaning the pool dereferences of
|
* when we access them during cleaning the pool dereferences of
|
||||||
* those indices will be made with segmentation faults as result. */
|
* those indices will be made with segmentation faults as result. */
|
||||||
|
}
|
||||||
if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
|
if (_sl.action == SLA_LOAD || _sl.action == SLA_PTRS) SlNullPointers();
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
}
|
}
|
||||||
@ -560,6 +569,7 @@ static void SlCopyBytes(void *ptr, size_t length)
|
|||||||
byte *p = (byte *)ptr;
|
byte *p = (byte *)ptr;
|
||||||
|
|
||||||
switch (_sl.action) {
|
switch (_sl.action) {
|
||||||
|
case SLA_LOAD_CHECK:
|
||||||
case SLA_LOAD:
|
case SLA_LOAD:
|
||||||
for (; length != 0; length--) { *p++ = SlReadByteInternal(); }
|
for (; length != 0; length--) { *p++ = SlReadByteInternal(); }
|
||||||
break;
|
break;
|
||||||
@ -647,6 +657,7 @@ static void SlSaveLoadConv(void *ptr, VarType conv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SLA_LOAD_CHECK:
|
||||||
case SLA_LOAD: {
|
case SLA_LOAD: {
|
||||||
int64 x;
|
int64 x;
|
||||||
/* Read a value from the file */
|
/* Read a value from the file */
|
||||||
@ -743,6 +754,7 @@ static void SlString(void *ptr, size_t length, VarType conv)
|
|||||||
SlCopyBytes(ptr, len);
|
SlCopyBytes(ptr, len);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SLA_LOAD_CHECK:
|
||||||
case SLA_LOAD: {
|
case SLA_LOAD: {
|
||||||
size_t len = SlReadArrayLength();
|
size_t len = SlReadArrayLength();
|
||||||
|
|
||||||
@ -890,6 +902,7 @@ static void SlList(void *list, SLRefType conv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SLA_LOAD_CHECK:
|
||||||
case SLA_LOAD: {
|
case SLA_LOAD: {
|
||||||
size_t length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
|
size_t length = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
|
||||||
|
|
||||||
@ -1009,6 +1022,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
|
|||||||
case SLA_SAVE:
|
case SLA_SAVE:
|
||||||
SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
|
SlWriteUint32((uint32)ReferenceToInt(*(void **)ptr, (SLRefType)conv));
|
||||||
break;
|
break;
|
||||||
|
case SLA_LOAD_CHECK:
|
||||||
case SLA_LOAD:
|
case SLA_LOAD:
|
||||||
*(size_t *)ptr = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
|
*(size_t *)ptr = CheckSavegameVersion(69) ? SlReadUint16() : SlReadUint32();
|
||||||
break;
|
break;
|
||||||
@ -1036,6 +1050,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld)
|
|||||||
case SL_WRITEBYTE:
|
case SL_WRITEBYTE:
|
||||||
switch (_sl.action) {
|
switch (_sl.action) {
|
||||||
case SLA_SAVE: SlWriteByte(sld->version_to); break;
|
case SLA_SAVE: SlWriteByte(sld->version_to); break;
|
||||||
|
case SLA_LOAD_CHECK:
|
||||||
case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
|
case SLA_LOAD: *(byte *)ptr = sld->version_from; break;
|
||||||
case SLA_PTRS: break;
|
case SLA_PTRS: break;
|
||||||
case SLA_NULL: break;
|
case SLA_NULL: break;
|
||||||
@ -1150,6 +1165,56 @@ static void SlLoadChunk(const ChunkHandler *ch)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a chunk of data for checking savegames.
|
||||||
|
* If the chunkhandler is NULL, the chunk is skipped.
|
||||||
|
* @param ch The chunkhandler that will be used for the operation
|
||||||
|
*/
|
||||||
|
static void SlLoadCheckChunk(const ChunkHandler *ch)
|
||||||
|
{
|
||||||
|
byte m = SlReadByte();
|
||||||
|
size_t len;
|
||||||
|
size_t endoffs;
|
||||||
|
|
||||||
|
_sl.block_mode = m;
|
||||||
|
_sl.obj_len = 0;
|
||||||
|
|
||||||
|
switch (m) {
|
||||||
|
case CH_ARRAY:
|
||||||
|
_sl.array_index = 0;
|
||||||
|
if (ch->load_check_proc) {
|
||||||
|
ch->load_check_proc();
|
||||||
|
} else {
|
||||||
|
SlSkipArray();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CH_SPARSE_ARRAY:
|
||||||
|
if (ch->load_check_proc) {
|
||||||
|
ch->load_check_proc();
|
||||||
|
} else {
|
||||||
|
SlSkipArray();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ((m & 0xF) == CH_RIFF) {
|
||||||
|
/* Read length */
|
||||||
|
len = (SlReadByte() << 16) | ((m >> 4) << 24);
|
||||||
|
len += SlReadUint16();
|
||||||
|
_sl.obj_len = len;
|
||||||
|
endoffs = SlGetOffs() + len;
|
||||||
|
if (ch->load_check_proc) {
|
||||||
|
ch->load_check_proc();
|
||||||
|
} else {
|
||||||
|
SlSkipBytes(len);
|
||||||
|
}
|
||||||
|
if (SlGetOffs() != endoffs) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk size");
|
||||||
|
} else {
|
||||||
|
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Invalid chunk type");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Stub Chunk handlers to only calculate length and do nothing else */
|
/* Stub Chunk handlers to only calculate length and do nothing else */
|
||||||
static ChunkSaveLoadProc *_tmp_proc_1;
|
static ChunkSaveLoadProc *_tmp_proc_1;
|
||||||
static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
|
static inline void SlStubSaveProc2(void *arg) {_tmp_proc_1();}
|
||||||
@ -1233,6 +1298,21 @@ static void SlLoadChunks()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Load all chunks for savegame checking */
|
||||||
|
static void SlLoadCheckChunks()
|
||||||
|
{
|
||||||
|
uint32 id;
|
||||||
|
const ChunkHandler *ch;
|
||||||
|
|
||||||
|
for (id = SlReadUint32(); id != 0; id = SlReadUint32()) {
|
||||||
|
DEBUG(sl, 2, "Loading chunk %c%c%c%c", id >> 24, id >> 16, id >> 8, id);
|
||||||
|
|
||||||
|
ch = SlFindChunkHandler(id);
|
||||||
|
if (ch == NULL) SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, "Unknown chunk type");
|
||||||
|
SlLoadCheckChunk(ch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Fix all pointers (convert index -> pointer) */
|
/** Fix all pointers (convert index -> pointer) */
|
||||||
static void SlFixPointers()
|
static void SlFixPointers()
|
||||||
{
|
{
|
||||||
@ -1850,6 +1930,8 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
}
|
}
|
||||||
WaitTillSaved();
|
WaitTillSaved();
|
||||||
|
|
||||||
|
/* Clear previous check data */
|
||||||
|
if (mode == SL_LOAD_CHECK) _load_check_data.Clear();
|
||||||
_next_offs = 0;
|
_next_offs = 0;
|
||||||
|
|
||||||
/* Load a TTDLX or TTDPatch game */
|
/* Load a TTDLX or TTDPatch game */
|
||||||
@ -1875,13 +1957,16 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
return SL_OK;
|
return SL_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Mark SL_LOAD_CHECK as supported for this savegame. */
|
||||||
|
if (mode == SL_LOAD_CHECK) _load_check_data.checkable = true;
|
||||||
|
|
||||||
_sl.excpt_uninit = NULL;
|
_sl.excpt_uninit = NULL;
|
||||||
try {
|
try {
|
||||||
_sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
|
_sl.fh = (mode == SL_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
|
||||||
|
|
||||||
/* Make it a little easier to load savegames from the console */
|
/* Make it a little easier to load savegames from the console */
|
||||||
if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
|
if (_sl.fh == NULL && mode != SL_SAVE) _sl.fh = FioFOpenFile(filename, "rb", SAVE_DIR);
|
||||||
if (_sl.fh == NULL && mode == SL_LOAD) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
|
if (_sl.fh == NULL && mode != SL_SAVE) _sl.fh = FioFOpenFile(filename, "rb", BASE_DIR);
|
||||||
|
|
||||||
if (_sl.fh == NULL) {
|
if (_sl.fh == NULL) {
|
||||||
SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
|
SlError(mode == SL_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
|
||||||
@ -1889,7 +1974,12 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
|
|
||||||
_sl.bufe = _sl.bufp = NULL;
|
_sl.bufe = _sl.bufp = NULL;
|
||||||
_sl.offs_base = 0;
|
_sl.offs_base = 0;
|
||||||
_sl.action = (mode != 0) ? SLA_SAVE : SLA_LOAD;
|
switch (mode) {
|
||||||
|
case SL_LOAD_CHECK: _sl.action = SLA_LOAD_CHECK; break;
|
||||||
|
case SL_LOAD: _sl.action = SLA_LOAD; break;
|
||||||
|
case SL_SAVE: _sl.action = SLA_SAVE; break;
|
||||||
|
default: NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
/* General tactic is to first save the game to memory, then use an available writer
|
/* General tactic is to first save the game to memory, then use an available writer
|
||||||
* to write it to file, either in threaded mode if possible, or single-threaded */
|
* to write it to file, either in threaded mode if possible, or single-threaded */
|
||||||
@ -1917,7 +2007,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
} else { // LOAD game
|
} else { // LOAD game
|
||||||
assert(mode == SL_LOAD);
|
assert(mode == SL_LOAD || mode == SL_LOAD_CHECK);
|
||||||
DEBUG(desync, 1, "load: %s", filename);
|
DEBUG(desync, 1, "load: %s", filename);
|
||||||
|
|
||||||
/* Can't fseek to 0 as in tar files that is not correct */
|
/* Can't fseek to 0 as in tar files that is not correct */
|
||||||
@ -1983,6 +2073,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
|
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_INTERNAL_ERROR, err_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mode != SL_LOAD_CHECK) {
|
||||||
_engine_mngr.ResetToDefaultMapping();
|
_engine_mngr.ResetToDefaultMapping();
|
||||||
|
|
||||||
/* Old maps were hardcoded to 256x256 and thus did not contain
|
/* Old maps were hardcoded to 256x256 and thus did not contain
|
||||||
@ -2016,16 +2107,25 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
*/
|
*/
|
||||||
ClearGRFConfigList(&_grfconfig);
|
ClearGRFConfigList(&_grfconfig);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == SL_LOAD_CHECK) {
|
||||||
|
/* Load chunks into _load_check_data.
|
||||||
|
* No pools are loaded. References are not possible, and thus do not need resolving. */
|
||||||
|
SlLoadCheckChunks();
|
||||||
|
} else {
|
||||||
|
/* Load chunks and resolve references */
|
||||||
SlLoadChunks();
|
SlLoadChunks();
|
||||||
SlFixPointers();
|
SlFixPointers();
|
||||||
|
}
|
||||||
fmt->uninit_read();
|
fmt->uninit_read();
|
||||||
fclose(_sl.fh);
|
fclose(_sl.fh);
|
||||||
|
|
||||||
GamelogStartAction(GLAT_LOAD);
|
|
||||||
|
|
||||||
_savegame_type = SGT_OTTD;
|
_savegame_type = SGT_OTTD;
|
||||||
|
|
||||||
|
if (mode != SL_LOAD_CHECK) {
|
||||||
|
GamelogStartAction(GLAT_LOAD);
|
||||||
|
|
||||||
/* After loading fix up savegame for any internal changes that
|
/* After loading fix up savegame for any internal changes that
|
||||||
* might've occured since then. If it fails, load back the old game */
|
* might've occured since then. If it fails, load back the old game */
|
||||||
if (!AfterLoadGame()) {
|
if (!AfterLoadGame()) {
|
||||||
@ -2035,6 +2135,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
|
|
||||||
GamelogStopAction();
|
GamelogStopAction();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SL_OK;
|
return SL_OK;
|
||||||
}
|
}
|
||||||
@ -2045,7 +2146,7 @@ SaveOrLoadResult SaveOrLoad(const char *filename, int mode, Subdirectory sb, boo
|
|||||||
if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
|
if (_sl.excpt_uninit != NULL) _sl.excpt_uninit();
|
||||||
|
|
||||||
/* Skip the "colour" character */
|
/* Skip the "colour" character */
|
||||||
DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
|
if (mode != SL_LOAD_CHECK) DEBUG(sl, 0, "%s", GetSaveLoadErrorString() + 3);
|
||||||
|
|
||||||
/* A saver/loader exception!! reinitialize all variables to prevent crash! */
|
/* A saver/loader exception!! reinitialize all variables to prevent crash! */
|
||||||
return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
|
return (mode == SL_LOAD) ? SL_REINIT : SL_ERROR;
|
||||||
|
@ -33,6 +33,7 @@ enum SaveOrLoadMode {
|
|||||||
SL_OLD_LOAD = 2,
|
SL_OLD_LOAD = 2,
|
||||||
SL_PNG = 3,
|
SL_PNG = 3,
|
||||||
SL_BMP = 4,
|
SL_BMP = 4,
|
||||||
|
SL_LOAD_CHECK = 5,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SavegameType {
|
enum SavegameType {
|
||||||
@ -216,6 +217,7 @@ typedef SaveLoad SaveLoadGlobVarList;
|
|||||||
#define SLE_ARR(base, variable, type, length) SLE_CONDARR(base, variable, type, length, 0, SL_MAX_VERSION)
|
#define SLE_ARR(base, variable, type, length) SLE_CONDARR(base, variable, type, length, 0, SL_MAX_VERSION)
|
||||||
#define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, type, length, 0, SL_MAX_VERSION)
|
#define SLE_STR(base, variable, type, length) SLE_CONDSTR(base, variable, type, length, 0, SL_MAX_VERSION)
|
||||||
#define SLE_LST(base, variable, type) SLE_CONDLST(base, variable, type, 0, SL_MAX_VERSION)
|
#define SLE_LST(base, variable, type) SLE_CONDLST(base, variable, type, 0, SL_MAX_VERSION)
|
||||||
|
#define SLE_NULL(length) SLE_CONDNULL(length, 0, SL_MAX_VERSION)
|
||||||
|
|
||||||
#define SLE_CONDNULL(length, from, to) SLE_CONDARR(NullStruct, null, SLE_FILE_U8 | SLE_VAR_NULL | SLF_CONFIG_NO, length, from, to)
|
#define SLE_CONDNULL(length, from, to) SLE_CONDARR(NullStruct, null, SLE_FILE_U8 | SLE_VAR_NULL | SLF_CONFIG_NO, length, from, to)
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user