Codechange: ability to store structs and list of structs in savegames

The commits following this will use this new functionality.

Currently, a few places do this manually. This has as drawback that
the Save() and Load() code need to be in sync, and that any change
can result in (old) savegames no longer loading. In general, it is
annoying code to maintain.

By putting everything in a description table, and use that for
both Save() and Load(), it becomes easier to see what is going on,
and hopefully less likely for people to make mistakes.
This commit is contained in:
Patric Stout
2021-06-08 13:21:31 +02:00
committed by Patric Stout
parent 909f3f25bd
commit 4600d289b5
3 changed files with 157 additions and 19 deletions

View File

@@ -1450,6 +1450,27 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld)
case SL_WRITEBYTE: return 1; // a byte is logically of size 1
case SL_VEH_INCLUDE: return SlCalcObjLength(object, GetVehicleDescription(VEH_END));
case SL_ST_INCLUDE: return SlCalcObjLength(object, GetBaseStationDescription());
case SL_STRUCT:
case SL_STRUCTLIST: {
if (!SlIsObjectValidInSavegame(sld)) break;
NeedLength old_need_length = _sl.need_length;
size_t old_obj_len = _sl.obj_len;
_sl.need_length = NL_CALCLENGTH;
_sl.obj_len = 0;
/* Pretend that we are saving to collect the object size. Other
* means are difficult, as we don't know the length of the list we
* are about to store. */
sld.handler->Save(const_cast<void *>(object));
size_t length = _sl.obj_len;
_sl.obj_len = old_obj_len;
_sl.need_length = old_need_length;
return length;
}
default: NOT_REACHED();
}
return 0;
@@ -1505,8 +1526,6 @@ size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld)
static bool SlObjectMember(void *object, const SaveLoad &sld)
{
void *ptr = GetVariableAddress(object, sld);
assert(IsVariableSizeRight(sld));
VarType conv = GB(sld.conv, 0, 8);
@@ -1517,10 +1536,12 @@ static bool SlObjectMember(void *object, const SaveLoad &sld)
case SL_STR:
case SL_REFLIST:
case SL_DEQUE:
case SL_STDSTR:
case SL_STDSTR: {
/* CONDITIONAL saveload types depend on the savegame version */
if (!SlIsObjectValidInSavegame(sld)) return false;
void *ptr = GetVariableAddress(object, sld);
switch (sld.cmd) {
case SL_VAR: SlSaveLoadConv(ptr, conv); break;
case SL_REF: SlSaveLoadRef(ptr, conv); break;
@@ -1532,11 +1553,14 @@ static bool SlObjectMember(void *object, const SaveLoad &sld)
default: NOT_REACHED();
}
break;
}
/* SL_WRITEBYTE writes a value to the savegame to identify the type of an object.
* When loading, the value is read explicitly with SlReadByte() to determine which
* object description to use. */
case SL_WRITEBYTE:
case SL_WRITEBYTE: {
void *ptr = GetVariableAddress(object, sld);
switch (_sl.action) {
case SLA_SAVE: SlWriteByte(*(uint8 *)ptr); break;
case SLA_LOAD_CHECK:
@@ -1546,15 +1570,34 @@ static bool SlObjectMember(void *object, const SaveLoad &sld)
default: NOT_REACHED();
}
break;
}
/* SL_VEH_INCLUDE loads common code for vehicles */
case SL_VEH_INCLUDE:
case SL_VEH_INCLUDE: {
void *ptr = GetVariableAddress(object, sld);
SlObject(ptr, GetVehicleDescription(VEH_END));
break;
}
case SL_ST_INCLUDE:
case SL_ST_INCLUDE: {
void *ptr = GetVariableAddress(object, sld);
SlObject(ptr, GetBaseStationDescription());
break;
}
case SL_STRUCT:
case SL_STRUCTLIST:
if (!SlIsObjectValidInSavegame(sld)) return false;
switch (_sl.action) {
case SLA_SAVE: sld.handler->Save(object); break;
case SLA_LOAD_CHECK: sld.handler->LoadCheck(object); break;
case SLA_LOAD: sld.handler->Load(object); break;
case SLA_PTRS: sld.handler->FixPointers(object); break;
case SLA_NULL: break;
default: NOT_REACHED();
}
break;
default: NOT_REACHED();
}