- converted the user variable serializer.

This commit is contained in:
Christoph Oelckers 2016-09-20 18:27:47 +02:00
parent e41296a64d
commit e101014432
8 changed files with 419 additions and 569 deletions

View file

@ -58,8 +58,6 @@ struct botskill_t
int isp; //Instincts of Self Preservation. Personality int isp; //Instincts of Self Preservation. Personality
}; };
FArchive &operator<< (FArchive &arc, botskill_t &skill);
enum enum
{ {
BOTINUSE_No, BOTINUSE_No,

View file

@ -478,68 +478,20 @@ size_t DObject::StaticPointerSubstitution (DObject *old, DObject *notOld)
// //
//========================================================================== //==========================================================================
void DObject::SerializeUserVars(FArchive &arc) void DObject::SerializeUserVars(FSerializer &arc)
{ {
PSymbolTable *symt; if (arc.isWriting())
FName varname;
DWORD count, j;
int *varloc = NULL;
symt = &GetClass()->Symbols;
if (arc.IsStoring())
{ {
// Write all fields that aren't serialized by native code. // Write all fields that aren't serialized by native code.
GetClass()->WriteValue(arc, this); GetClass()->WriteAllFields(arc, this);
}
else if (SaveVersion >= 4535)
{
GetClass()->ReadValue(arc, this);
} }
else else
{ // Old version that only deals with ints {
// Read user variables until 'None' is encountered. GetClass()->ReadAllFields(arc, this);
arc << varname;
while (varname != NAME_None)
{
PField *var = dyn_cast<PField>(symt->FindSymbol(varname, true));
DWORD wanted = 0;
if (var != NULL && !(var->Flags & VARF_Native))
{
PType *type = var->Type;
PArray *arraytype = dyn_cast<PArray>(type);
if (arraytype != NULL)
{
wanted = arraytype->ElementCount;
type = arraytype->ElementType;
}
else
{
wanted = 1;
}
assert(type == TypeSInt32);
varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->Offset);
}
count = arc.ReadCount();
for (j = 0; j < MIN(wanted, count); ++j)
{
arc << varloc[j];
}
if (wanted < count)
{
// Ignore remaining values from archive.
for (; j < count; ++j)
{
int foo;
arc << foo;
}
}
arc << varname;
}
} }
} }
//========================================================================== //==========================================================================
// //
// //

View file

@ -460,8 +460,6 @@ public:
inline bool IsKindOf (const PClass *base) const; inline bool IsKindOf (const PClass *base) const;
inline bool IsA (const PClass *type) const; inline bool IsA (const PClass *type) const;
void SerializeUserVars(FArchive &arc);
void SerializeUserVars(FSerializer &arc); void SerializeUserVars(FSerializer &arc);
virtual void Serialize(FSerializer &arc); virtual void Serialize(FSerializer &arc);

View file

@ -39,7 +39,7 @@
#include "dobject.h" #include "dobject.h"
#include "i_system.h" #include "i_system.h"
#include "farchive.h" #include "serializer.h"
#include "actor.h" #include "actor.h"
#include "templates.h" #include "templates.h"
#include "autosegs.h" #include "autosegs.h"
@ -47,6 +47,7 @@
#include "a_pickups.h" #include "a_pickups.h"
#include "a_weaponpiece.h" #include "a_weaponpiece.h"
#include "d_player.h" #include "d_player.h"
#include "doomerrors.h"
#include "fragglescript/t_fs.h" #include "fragglescript/t_fs.h"
// MACROS ------------------------------------------------------------------ // MACROS ------------------------------------------------------------------
@ -390,7 +391,7 @@ bool PType::VisitedNodeSet::Check(const PType *node)
// //
//========================================================================== //==========================================================================
void PType::WriteValue(FArchive &ar, const void *addr) const void PType::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
assert(0 && "Cannot write value for this type"); assert(0 && "Cannot write value for this type");
} }
@ -401,108 +402,12 @@ void PType::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PType::ReadValue(FArchive &ar, void *addr) const bool PType::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
assert(0 && "Cannot read value for this type"); assert(0 && "Cannot read value for this type");
SkipValue(ar);
return false; return false;
} }
//==========================================================================
//
// PType :: SkipValue STATIC
//
//==========================================================================
void PType::SkipValue(FArchive &ar)
{
BYTE tag;
ar << tag;
SkipValue(ar, tag);
}
void PType::SkipValue(FArchive &ar, int tag)
{
assert(ar.IsLoading() && "SkipValue passed an archive that is writing");
BYTE buff[8];
switch (tag)
{
case VAL_Zero: case VAL_One:
break;
case VAL_Int8: case VAL_UInt8:
ar.Read(buff, 1);
break;
case VAL_Int16: case VAL_UInt16:
ar.Read(buff, 2);
break;
case VAL_Int32: case VAL_UInt32: case VAL_Float32:
ar.Read(buff, 4);
break;
case VAL_Int64: case VAL_UInt64: case VAL_Float64:
ar.Read(buff, 8);
break;
case VAL_Name:
ar.ReadName();
break;
case VAL_Object:
{
#if 0
DObject *skipper;
ar << skipper;
#endif
break;
}
case VAL_State:
{
#if 0
FState *skipper;
ar << skipper;
#endif
break;
}
case VAL_String:
{
FString skipper;
ar << skipper;
break;
}
case VAL_Array:
{
DWORD count = ar.ReadCount();
while (count-- > 0)
{
SkipValue(ar);
}
break;
}
case VAL_Struct:
{
const char *label;
for (label = ar.ReadName(); label != NULL; label = ar.ReadName())
{
SkipValue(ar);
}
break;
}
case VAL_Class:
{
PClass *type;
for (ar.UserReadClass(type); type != NULL; ar.UserReadClass(type))
{
SkipValue(ar, VAL_Struct);
}
break;
}
}
}
//========================================================================== //==========================================================================
// //
// PType :: SetDefaultValue // PType :: SetDefaultValue
@ -809,116 +714,41 @@ PInt::PInt(unsigned int size, bool unsign)
// //
// PInt :: WriteValue // PInt :: WriteValue
// //
// Write the value using the minimum byte size needed to represent it. This
// means that the value as written is not necessarily of the same type as
// stored, but the signedness information is preserved.
//
//========================================================================== //==========================================================================
void PInt::WriteValue(FArchive &ar, const void *addr) const void PInt::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
BYTE bval; if (Size == 8 && Unsigned)
// The process for bytes is the same whether signed or unsigned, since
// they can't be compacted into a representation with fewer bytes.
if (Size == 1)
{ {
bval = *(BYTE *)addr; // this is a special case that cannot be represented by an int64_t.
} uint64_t val = *(uint64_t*)addr;
else if (Unsigned) ar(key, val);
{
unsigned val;
if (Size == 8)
{
QWORD qval = *(QWORD *)addr;
if (qval & 0xFFFFFFFF00000000llu)
{ // Value needs 64 bits
ar.WriteByte(VAL_UInt64);
ar.WriteInt64(qval);
return;
}
// Value can fit in 32 bits or less
val = (unsigned)qval;
goto check_u32;
}
else if (Size == 4)
{
val = *(DWORD *)addr;
check_u32: if (val & 0xFFFF0000u)
{ // Value needs 32 bits
ar.WriteByte(VAL_UInt32);
ar.WriteInt32(val);
return;
}
// Value can fit in 16 bits or less
goto check_u16;
}
else// if (Size == 2)
{
val = *(WORD *)addr;
check_u16: if (val & 0xFFFFFF00u)
{ // Value needs 16 bits
ar.WriteByte(VAL_UInt16);
ar.WriteInt16(val);
return;
}
// Value can fit in 8 bits
bval = (BYTE)val;
}
}
else // Signed
{
int val;
if (Size == 8)
{
SQWORD qval = *(SQWORD *)addr;
INT_MIN;
if (qval < (-0x7FFFFFFF - 1) || qval > 0x7FFFFFFF)
{ // Value needs 64 bits
ar.WriteByte(VAL_Int64);
ar.WriteInt64(qval);
return;
}
// Value can fit in 32 bits or less
val = (int)qval;
goto check_s32;
}
else if (Size == 4)
{
val = *(SDWORD *)addr;
check_s32: if (val < -0x8000 || val > 0x7FFF)
{ // Value needs 32 bits
ar.WriteByte(VAL_Int32);
ar.WriteInt32(val);
return;
}
// Value can fit in 16 bits or less
goto check_s16;
}
else// if (Size == 2)
{
val = *(SWORD *)addr;
check_s16: if (val < -0x80 || val > 0x7F)
{ // Value needs 16 bits
ar.WriteByte(VAL_Int16);
ar.WriteInt16(val);
return;
}
// Value can fit in 8 bits
bval = (BYTE)val;
}
}
// If we get here, the value fits in a byte. Values of 0 and 1 are
// optimized away into the tag so they don't require any extra space
// to store.
if (bval & 0xFE)
{
BYTE out[2] = { Unsigned ? VAL_UInt8 : VAL_Int8, bval };
ar.Write(out, 2);
} }
else else
{ {
ar.WriteByte(VAL_Zero + bval); int64_t val;
switch (Size)
{
case 1:
val = Unsigned ? *(uint8_t*)addr : *(int8_t*)addr;
break;
case 2:
val = Unsigned ? *(uint16_t*)addr : *(int16_t*)addr;
break;
case 4:
val = Unsigned ? *(uint32_t*)addr : *(int32_t*)addr;
break;
case 8:
val = *(int64_t*)addr;
break;
default:
return; // something invalid
}
ar(key, val);
} }
} }
@ -928,47 +758,37 @@ check_s16: if (val < -0x80 || val > 0x7F)
// //
//========================================================================== //==========================================================================
bool PInt::ReadValue(FArchive &ar, void *addr) const bool PInt::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
union NumericValue val;
{
QWORD uval;
SQWORD sval;
};
BYTE tag;
union
{
BYTE val8;
WORD val16;
DWORD val32;
float single;
double dbl;
};
ar << tag; ar(key, val);
switch (tag) if (val.type == NumericValue::NM_invalid) return false; // not found or usable
{ if (val.type == NumericValue::NM_float) val.signedval = (int64_t)val.floatval;
case VAL_Zero: uval = 0; break;
case VAL_One: uval = 1; break; // No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both.
case VAL_Int8: ar << val8; sval = (SBYTE)val8; break;
case VAL_UInt8: ar << val8; uval = val8; break;
case VAL_Int16: ar << val16; sval = (SWORD)val16; break;
case VAL_UInt16: ar << val16; uval = val16; break;
case VAL_Int32: ar << val32; sval = (SDWORD)val32; break;
case VAL_UInt32: ar << val32; uval = val32; break;
case VAL_Int64: ar << sval; break;
case VAL_UInt64: ar << uval; break;
case VAL_Float32: ar << single; sval = (SQWORD)single; break;
case VAL_Float64: ar << dbl; sval = (SQWORD)dbl; break;
default: SkipValue(ar, tag); return false; // Incompatible type
}
switch (Size) switch (Size)
{ {
case 1: *(BYTE *)addr = (BYTE)uval; break; case 1:
case 2: *(WORD *)addr = (WORD)uval; break; *(uint8_t*)addr = (uint8_t)val.signedval;
case 4: *(DWORD *)addr = (DWORD)uval; break; break;
case 8: *(QWORD *)addr = uval; break;
case 2:
*(uint16_t*)addr = (uint16_t)val.signedval;
break;
case 4:
*(uint32_t*)addr = (uint32_t)val.signedval;
break;
case 8:
*(uint64_t*)addr = (uint64_t)val.signedval;
break;
default:
return false; // something invalid
} }
return true; return true;
} }
@ -1263,28 +1083,16 @@ void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count)
// //
//========================================================================== //==========================================================================
void PFloat::WriteValue(FArchive &ar, const void *addr) const void PFloat::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
float singleprecision;
if (Size == 8) if (Size == 8)
{ {
// If it can be written as single precision without information ar(key, *(double*)addr);
// loss, then prefer that over writing a full-sized double.
double doubleprecision = *(double *)addr;
singleprecision = (float)doubleprecision;
if (singleprecision != doubleprecision)
{
ar.WriteByte(VAL_Float64);
ar << doubleprecision;
return;
}
} }
else else
{ {
singleprecision = *(float *)addr; ar(key, *(float*)addr);
} }
ar.WriteByte(VAL_Float32);
ar << singleprecision;
} }
//========================================================================== //==========================================================================
@ -1293,60 +1101,26 @@ void PFloat::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
static bool ReadValueDbl(FArchive &ar, double *addr, unsigned tag) bool PFloat::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
double val; NumericValue val;
union
{
BYTE val8;
WORD val16;
DWORD val32;
QWORD val64;
fixed_t fix;
float single;
angle_t ang;
};
switch (tag) ar(key, val);
if (val.type == NumericValue::NM_invalid) return false; // not found or usable
else if (val.type == NumericValue::NM_signed) val.floatval = (double)val.signedval;
else if (val.type == NumericValue::NM_unsigned) val.floatval = (double)val.unsignedval;
if (Size == 8)
{ {
case VAL_Zero: val = 0; break; *(double*)addr = val.floatval;
case VAL_One: val = 1; break; }
case VAL_Int8: ar << val8; val = (SBYTE)val8; break; else
case VAL_UInt8: ar << val8; val = val8; break; {
case VAL_Int16: ar << val16; val = (SWORD)val16; break; *(float*)addr = (float)val.floatval;
case VAL_UInt16: ar << val16; val = val16; break;
case VAL_Int32: ar << val32; val = (SDWORD)val32; break;
case VAL_UInt32: ar << val32; val = val32; break;
case VAL_Int64: ar << val64; val = (double)(SQWORD)val64; break;
case VAL_UInt64: ar << val64; val = (double)val64; break;
case VAL_Float32: ar << single; val = single; break;
case VAL_Float64: ar << val; break;
default: PType::SkipValue(ar, tag); return false; // Incompatible type
} }
*(double *)addr = val;
return true; return true;
} }
bool PFloat::ReadValue(FArchive &ar, void *addr) const
{
BYTE tag;
ar << tag;
double val;
if (ReadValueDbl(ar, &val, tag))
{
if (Size == 4)
{
*(float *)addr = (float)val;
}
else
{
*(double *)addr = val;
}
return true;
}
return false;
}
//========================================================================== //==========================================================================
// //
// PFloat :: SetValue // PFloat :: SetValue
@ -1486,10 +1260,9 @@ int PString::GetRegType() const
// //
//========================================================================== //==========================================================================
void PString::WriteValue(FArchive &ar, const void *addr) const void PString::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
ar.WriteByte(VAL_String); ar(key, *(FString*)addr);
ar.WriteString(*(const FString *)addr);
} }
//========================================================================== //==========================================================================
@ -1498,25 +1271,19 @@ void PString::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PString::ReadValue(FArchive &ar, void *addr) const bool PString::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
BYTE tag; const char *cptr;
ar << tag; ar.StringPtr(key, cptr);
if (tag == VAL_String) if (cptr == nullptr)
{ {
ar << *(FString *)addr; return false;
}
else if (tag == VAL_Name)
{
const char *str = ar.ReadName();
*(FString *)addr = str;
} }
else else
{ {
SkipValue(ar, tag); *(FString*)addr = cptr;
return false; return true;
} }
return true;
} }
//========================================================================== //==========================================================================
@ -1578,10 +1345,10 @@ PName::PName()
// //
//========================================================================== //==========================================================================
void PName::WriteValue(FArchive &ar, const void *addr) const void PName::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
ar.WriteByte(VAL_Name); const char *cptr = ((const FName*)addr)->GetChars();
ar.WriteName(((const FName *)addr)->GetChars()); ar.StringPtr(key, cptr);
} }
//========================================================================== //==========================================================================
@ -1590,26 +1357,19 @@ void PName::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PName::ReadValue(FArchive &ar, void *addr) const bool PName::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
BYTE tag; const char *cptr;
ar << tag; ar.StringPtr(key, cptr);
if (tag == VAL_Name) if (cptr == nullptr)
{ {
*(FName *)addr = FName(ar.ReadName()); return false;
}
else if (tag == VAL_String)
{
FString str;
ar << str;
*(FName *)addr = FName(str);
} }
else else
{ {
SkipValue(ar, tag); *(FName*)addr = FName(cptr);
return false; return true;
} }
return true;
} }
/* PSound *****************************************************************/ /* PSound *****************************************************************/
@ -1634,10 +1394,10 @@ PSound::PSound()
// //
//========================================================================== //==========================================================================
void PSound::WriteValue(FArchive &ar, const void *addr) const void PSound::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
ar.WriteByte(VAL_Name); const char *cptr = *(const FSoundID *)addr;
ar.WriteName(*(const FSoundID *)addr); ar.StringPtr(key, cptr);
} }
//========================================================================== //==========================================================================
@ -1646,28 +1406,19 @@ void PSound::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PSound::ReadValue(FArchive &ar, void *addr) const bool PSound::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
BYTE tag; const char *cptr;
ar.StringPtr(key, cptr);
ar << tag; if (cptr == nullptr)
if (tag == VAL_Name)
{ {
const char *str = ar.ReadName(); return false;
*(FSoundID *)addr = FSoundID(str);
}
else if (tag == VAL_String)
{
FString str;
ar << str;
*(FSoundID *)addr = FSoundID(str);
} }
else else
{ {
SkipValue(ar, tag); *(FSoundID *)addr = FSoundID(cptr);
return false; return true;
} }
return true;
} }
/* PColor *****************************************************************/ /* PColor *****************************************************************/
@ -1740,10 +1491,9 @@ int PStatePointer::GetRegType() const
// //
//========================================================================== //==========================================================================
void PStatePointer::WriteValue(FArchive &ar, const void *addr) const void PStatePointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
ar.WriteByte(VAL_State); ar(key, *(FState **)addr);
//ar << *(FState **)addr;
} }
//========================================================================== //==========================================================================
@ -1752,17 +1502,11 @@ void PStatePointer::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PStatePointer::ReadValue(FArchive &ar, void *addr) const bool PStatePointer::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
BYTE tag; bool res = false;
ar << tag; ::Serialize(ar, key, *(FState **)addr, nullptr, &res);
if (tag == VAL_State) return res;
{
//ar << *(FState **)addr;
return true;
}
SkipValue(ar, tag);
return false;
} }
/* PPointer ***************************************************************/ /* PPointer ***************************************************************/
@ -1858,20 +1602,17 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
// //
//========================================================================== //==========================================================================
void PPointer::WriteValue(FArchive &ar, const void *addr) const void PPointer::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
#if 0
if (PointedType->IsKindOf(RUNTIME_CLASS(PClass))) if (PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
{ {
ar.WriteByte(VAL_Object); ar(key, *(DObject **)addr);
ar << *(DObject **)addr;
} }
else else
{ {
assert(0 && "Pointer points to a type we don't handle"); assert(0 && "Pointer points to a type we don't handle");
I_Error("Attempt to save pointer to unhandled type"); I_Error("Attempt to save pointer to unhandled type");
} }
#endif
} }
//========================================================================== //==========================================================================
@ -1880,18 +1621,14 @@ void PPointer::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PPointer::ReadValue(FArchive &ar, void *addr) const bool PPointer::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
#if 0 if (PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
BYTE tag;
ar << tag;
if (tag == VAL_Object && PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
{ {
ar << *(DObject **)addr; bool res = false;
return true; ::Serialize(ar, key, *(DObject **)addr, nullptr, &res);
return res;
} }
SkipValue(ar, tag);
#endif
return false; return false;
} }
@ -2106,15 +1843,17 @@ void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
// //
//========================================================================== //==========================================================================
void PArray::WriteValue(FArchive &ar, const void *addr) const void PArray::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
ar.WriteByte(VAL_Array); if (ar.BeginArray(key))
ar.WriteCount(ElementCount);
const BYTE *addrb = (const BYTE *)addr;
for (unsigned i = 0; i < ElementCount; ++i)
{ {
ElementType->WriteValue(ar, addrb); const BYTE *addrb = (const BYTE *)addr;
addrb += ElementSize; for (unsigned i = 0; i < ElementCount; ++i)
{
ElementType->WriteValue(ar, nullptr, addrb);
addrb += ElementSize;
}
ar.EndArray();
} }
} }
@ -2124,34 +1863,27 @@ void PArray::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PArray::ReadValue(FArchive &ar, void *addr) const bool PArray::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
bool readsomething = false; if (ar.BeginArray(key))
BYTE tag;
ar << tag;
if (tag == VAL_Array)
{ {
unsigned count = ar.ReadCount(); bool readsomething = false;
unsigned i; unsigned count = ar.ArraySize();
unsigned loop = MIN(count, ElementCount);
BYTE *addrb = (BYTE *)addr; BYTE *addrb = (BYTE *)addr;
for (i = 0; i < MIN(count, ElementCount); ++i) for(unsigned i=0;i<loop;i++)
{ {
readsomething |= ElementType->ReadValue(ar, addrb); readsomething |= ElementType->ReadValue(ar, key, addrb);
addrb += ElementSize; addrb += ElementSize;
} }
if (i < ElementCount) if (loop < ElementCount)
{ {
DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n", DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n",
count, ElementCount); count, ElementCount);
for (; i < ElementCount; ++i)
{
SkipValue(ar);
}
} }
ar.EndArray();
return readsomething; return readsomething;
} }
SkipValue(ar, tag);
return false; return false;
} }
@ -2445,10 +2177,13 @@ void PStruct::SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset
// //
//========================================================================== //==========================================================================
void PStruct::WriteValue(FArchive &ar, const void *addr) const void PStruct::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{ {
ar.WriteByte(VAL_Struct); if (ar.BeginObject(key))
WriteFields(ar, addr, Fields); {
WriteFields(ar, addr, Fields);
ar.EndObject();
}
} }
//========================================================================== //==========================================================================
@ -2457,16 +2192,15 @@ void PStruct::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PStruct::ReadValue(FArchive &ar, void *addr) const bool PStruct::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
BYTE tag; if (ar.BeginObject(key))
ar << tag;
if (tag == VAL_Struct)
{ {
return ReadFields(ar, addr); bool ret = ReadFields(ar, addr);
ar.EndObject();
return ret;
} }
SkipValue(ar, tag); return false;
return true;
} }
//========================================================================== //==========================================================================
@ -2475,7 +2209,7 @@ bool PStruct::ReadValue(FArchive &ar, void *addr) const
// //
//========================================================================== //==========================================================================
void PStruct::WriteFields(FArchive &ar, const void *addr, const TArray<PField *> &fields) void PStruct::WriteFields(FSerializer &ar, const void *addr, const TArray<PField *> &fields)
{ {
for (unsigned i = 0; i < fields.Size(); ++i) for (unsigned i = 0; i < fields.Size(); ++i)
{ {
@ -2483,11 +2217,9 @@ void PStruct::WriteFields(FArchive &ar, const void *addr, const TArray<PField *>
// Skip fields with native serialization // Skip fields with native serialization
if (!(field->Flags & VARF_Native)) if (!(field->Flags & VARF_Native))
{ {
ar.WriteName(field->SymbolName); field->Type->WriteValue(ar, field->SymbolName.GetChars(), (const BYTE *)addr + field->Offset);
field->Type->WriteValue(ar, (const BYTE *)addr + field->Offset);
} }
} }
ar.WriteName(NULL);
} }
//========================================================================== //==========================================================================
@ -2496,36 +2228,33 @@ void PStruct::WriteFields(FArchive &ar, const void *addr, const TArray<PField *>
// //
//========================================================================== //==========================================================================
bool PStruct::ReadFields(FArchive &ar, void *addr) const bool PStruct::ReadFields(FSerializer &ar, void *addr) const
{ {
bool readsomething = false; bool readsomething = false;
const char *label = ar.ReadName(); bool foundsomething = false;
if (label == NULL) const char *label;
{ // If there is nothing to restore, we count it as success. while ((label = ar.GetKey()))
return true;
}
for (; label != NULL; label = ar.ReadName())
{ {
foundsomething = true;
const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true); const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true);
if (sym == NULL) if (sym == NULL)
{ {
DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n", DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n",
label, TypeName.GetChars()); label, TypeName.GetChars());
SkipValue(ar);
} }
else if (!sym->IsKindOf(RUNTIME_CLASS(PField))) else if (!sym->IsKindOf(RUNTIME_CLASS(PField)))
{ {
DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n", DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n",
label, TypeName.GetChars()); label, TypeName.GetChars());
SkipValue(ar);
} }
else else
{ {
readsomething |= static_cast<const PField *>(sym)->Type->ReadValue(ar, readsomething |= static_cast<const PField *>(sym)->Type->ReadValue(ar, label,
(BYTE *)addr + static_cast<const PField *>(sym)->Offset); (BYTE *)addr + static_cast<const PField *>(sym)->Offset);
} }
} }
return readsomething; return readsomething || !foundsomething;
} }
//========================================================================== //==========================================================================
@ -2749,7 +2478,7 @@ END_POINTERS
// //
//========================================================================== //==========================================================================
static void RecurseWriteFields(const PClass *type, FArchive &ar, const void *addr) static void RecurseWriteFields(const PClass *type, FSerializer &ar, const void *addr)
{ {
if (type != NULL) if (type != NULL)
{ {
@ -2763,19 +2492,33 @@ static void RecurseWriteFields(const PClass *type, FArchive &ar, const void *add
// a more-derived class has variables that shadow a less- // a more-derived class has variables that shadow a less-
// derived class. Whether or not that is a language feature // derived class. Whether or not that is a language feature
// that will actually be allowed remains to be seen. // that will actually be allowed remains to be seen.
ar.UserWriteClass(const_cast<PClass *>(type)); FString key;
PStruct::WriteFields(ar, addr, type->Fields); key.Format("class:%s", type->TypeName.GetChars());
if (ar.BeginObject(key.GetChars()))
{
PStruct::WriteFields(ar, addr, type->Fields);
ar.EndObject();
}
break; break;
} }
} }
} }
} }
void PClass::WriteValue(FArchive &ar, const void *addr) const void PClass::WriteValue(FSerializer &ar, const char *key,const void *addr) const
{
if (ar.BeginObject(key))
{
RecurseWriteFields(this, ar, addr);
ar.EndObject();
}
}
// Same as WriteValue, but does not create a new object in the serializer
// This is so that user variables do not contain unnecessary subblocks.
void PClass::WriteAllFields(FSerializer &ar, const void *addr) const
{ {
ar.WriteByte(VAL_Class);
RecurseWriteFields(this, ar, addr); RecurseWriteFields(this, ar, addr);
ar.UserWriteClass(NULL);
} }
//========================================================================== //==========================================================================
@ -2784,20 +2527,32 @@ void PClass::WriteValue(FArchive &ar, const void *addr) const
// //
//========================================================================== //==========================================================================
bool PClass::ReadValue(FArchive &ar, void *addr) const bool PClass::ReadValue(FSerializer &ar, const char *key, void *addr) const
{ {
BYTE tag; if (ar.BeginObject(key))
ar << tag;
if (tag != VAL_Class)
{ {
SkipValue(ar, tag); bool ret = ReadAllFields(ar, addr);
return false; ar.EndObject();
return ret;
} }
else return true;
}
bool PClass::ReadAllFields(FSerializer &ar, void *addr) const
{
bool readsomething = false;
bool foundsomething = false;
const char *key;
while ((key = ar.GetKey()))
{ {
bool readsomething = false; if (strncmp(key, "class:", 6))
PClass *type; {
for (ar.UserReadClass(type); type != NULL; ar.UserReadClass(type)) // This key does not represent any class fields anymore
break;
}
foundsomething = true;
PClass *type = PClass::FindClass(key + 6);
if (type != nullptr)
{ {
// Only read it if the type is related to this one. // Only read it if the type is related to this one.
const PClass *parent; const PClass *parent;
@ -2808,7 +2563,7 @@ bool PClass::ReadValue(FArchive &ar, void *addr) const
break; break;
} }
} }
if (parent != NULL) if (parent != nullptr)
{ {
readsomething |= type->ReadFields(ar, addr); readsomething |= type->ReadFields(ar, addr);
} }
@ -2816,11 +2571,15 @@ bool PClass::ReadValue(FArchive &ar, void *addr) const
{ {
DPrintf(DMSG_ERROR, "Unknown superclass %s of class %s\n", DPrintf(DMSG_ERROR, "Unknown superclass %s of class %s\n",
type->TypeName.GetChars(), TypeName.GetChars()); type->TypeName.GetChars(), TypeName.GetChars());
SkipValue(ar, VAL_Struct);
} }
} }
return readsomething; else
{
DPrintf(DMSG_ERROR, "Unknown superclass %s of class %s\n",
key+6, TypeName.GetChars());
}
} }
return readsomething || !foundsomething;
} }
//========================================================================== //==========================================================================

View file

@ -193,15 +193,11 @@ public:
// a tag indicating its type. The tag is there so that variable types can be changed // a tag indicating its type. The tag is there so that variable types can be changed
// without completely breaking savegames, provided that the change isn't between // without completely breaking savegames, provided that the change isn't between
// totally unrelated types. // totally unrelated types.
virtual void WriteValue(FArchive &ar, const void *addr) const; virtual void WriteValue(FSerializer &ar, const char *key,const void *addr) const;
// Returns true if the stored value was compatible. False otherwise. // Returns true if the stored value was compatible. False otherwise.
// If the value was incompatible, then the memory at *addr is unchanged. // If the value was incompatible, then the memory at *addr is unchanged.
virtual bool ReadValue(FArchive &ar, void *addr) const; virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const;
// Skips over a value written with WriteValue
static void SkipValue(FArchive &ar);
static void SkipValue(FArchive &ar, int tag);
// Sets the default value for this type at (base + offset) // Sets the default value for this type at (base + offset)
// If the default value is binary 0, then this function doesn't need // If the default value is binary 0, then this function doesn't need
@ -354,8 +350,8 @@ class PInt : public PBasicType
public: public:
PInt(unsigned int size, bool unsign); PInt(unsigned int size, bool unsign);
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val); virtual void SetValue(void *addr, double val);
@ -383,8 +379,8 @@ class PFloat : public PBasicType
public: public:
PFloat(unsigned int size); PFloat(unsigned int size);
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
virtual void SetValue(void *addr, int val); virtual void SetValue(void *addr, int val);
virtual void SetValue(void *addr, double val); virtual void SetValue(void *addr, double val);
@ -421,8 +417,8 @@ public:
virtual int GetRegType() const; virtual int GetRegType() const;
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const override; void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special=NULL) const override;
void InitializeValue(void *addr, const void *def) const override; void InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override; void DestroyValue(void *addr) const override;
@ -436,8 +432,8 @@ class PName : public PInt
public: public:
PName(); PName();
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
}; };
class PSound : public PInt class PSound : public PInt
@ -446,8 +442,8 @@ class PSound : public PInt
public: public:
PSound(); PSound();
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
}; };
class PColor : public PInt class PColor : public PInt
@ -465,8 +461,8 @@ class PStatePointer : public PBasicType
public: public:
PStatePointer(); PStatePointer();
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
virtual int GetStoreOp() const; virtual int GetStoreOp() const;
virtual int GetLoadOp() const; virtual int GetLoadOp() const;
@ -489,8 +485,8 @@ public:
virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
protected: protected:
PPointer(); PPointer();
@ -559,8 +555,8 @@ public:
virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual bool IsMatch(intptr_t id1, intptr_t id2) const;
virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const;
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) const override; void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *special) const override;
@ -622,12 +618,12 @@ public:
size_t PropagateMark(); size_t PropagateMark();
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override; void SetDefaultValue(void *base, unsigned offset, TArray<FTypeAndOffset> *specials) const override;
static void WriteFields(FArchive &ar, const void *addr, const TArray<PField *> &fields); static void WriteFields(FSerializer &ar, const void *addr, const TArray<PField *> &fields);
bool ReadFields(FArchive &ar, void *addr) const; bool ReadFields(FSerializer &ar, void *addr) const;
protected: protected:
PStruct(); PStruct();
}; };
@ -692,8 +688,10 @@ public:
typedef PClassClass MetaClass; typedef PClassClass MetaClass;
MetaClass *GetClass() const; MetaClass *GetClass() const;
void WriteValue(FArchive &ar, const void *addr) const override; void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override; void WriteAllFields(FSerializer &ar, const void *addr) const;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
bool ReadAllFields(FSerializer &ar, void *addr) const;
virtual void DeriveData(PClass *newclass) {} virtual void DeriveData(PClass *newclass) {}
static void StaticInit(); static void StaticInit();

View file

@ -7,26 +7,6 @@
void DObject::SerializeUserVars(FSerializer &arc)
{
PSymbolTable *symt;
FName varname;
//DWORD count, j;
int *varloc = NULL;
symt = &GetClass()->Symbols;
if (arc.isWriting())
{
// Write all fields that aren't serialized by native code.
//GetClass()->WriteValue(arc, this);
}
else
{
//GetClass()->ReadValue(arc, this);
}
}
//========================================================================== //==========================================================================
// //
// //

View file

@ -44,12 +44,18 @@ struct FJSONObject
rapidjson::Value *mObject; rapidjson::Value *mObject;
rapidjson::Value::MemberIterator mIterator; rapidjson::Value::MemberIterator mIterator;
int mIndex; int mIndex;
bool mRandomAccess;
FJSONObject(rapidjson::Value *v) FJSONObject(rapidjson::Value *v, bool randomaccess = false)
{ {
mObject = v; mObject = v;
mRandomAccess = randomaccess;
if (v->IsObject()) mIterator = v->MemberBegin(); if (v->IsObject()) mIterator = v->MemberBegin();
else if (v->IsArray()) mIndex = 0; else if (v->IsArray())
{
mIndex = 0;
mIterator = v->MemberEnd();
}
} }
}; };
@ -100,7 +106,7 @@ struct FReader
rapidjson::Document doc; rapidjson::Document doc;
doc.Parse(buffer, length); doc.Parse(buffer, length);
mDocObj = doc.GetObject(); mDocObj = doc.GetObject();
mObjects.Push(FJSONObject(&mDocObj)); mObjects.Push(FJSONObject(&mDocObj)); // Todo: Decide if this should be made random access...
} }
rapidjson::Value *FindKey(const char *key) rapidjson::Value *FindKey(const char *key)
@ -109,13 +115,23 @@ struct FReader
if (obj.mObject->IsObject()) if (obj.mObject->IsObject())
{ {
if (obj.mIterator != obj.mObject->MemberEnd()) if (!obj.mRandomAccess)
{ {
if (!strcmp(key, obj.mIterator->name.GetString())) if (obj.mIterator != obj.mObject->MemberEnd())
{ {
return &(obj.mIterator++)->value; if (!strcmp(key, obj.mIterator->name.GetString()))
{
return &(obj.mIterator++)->value;
}
} }
} }
else
{
// for unordered searches. This is slower but will not rely on sequential order of items.
auto it = obj.mObject->FindMember(key);
if (it == obj.mObject->MemberEnd()) return nullptr;
return &it->value;
}
} }
else if (obj.mObject->IsArray()) else if (obj.mObject->IsArray())
{ {
@ -227,7 +243,7 @@ void FSerializer::WriteKey(const char *key)
// //
//========================================================================== //==========================================================================
bool FSerializer::BeginObject(const char *name) bool FSerializer::BeginObject(const char *name, bool randomaccess)
{ {
if (isWriting()) if (isWriting())
{ {
@ -242,7 +258,7 @@ bool FSerializer::BeginObject(const char *name)
{ {
if (val->IsObject()) if (val->IsObject())
{ {
r->mObjects.Push(FJSONObject(val)); r->mObjects.Push(FJSONObject(val, randomaccess));
} }
else else
{ {
@ -530,6 +546,10 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr)
{ {
charptr = val->GetString(); charptr = val->GetString();
} }
else
{
charptr = nullptr;
}
} }
} }
return *this; return *this;
@ -550,6 +570,20 @@ unsigned FSerializer::GetSize(const char *group)
return val.Size(); return val.Size();
} }
//==========================================================================
//
//
//
//==========================================================================
const char *FSerializer::GetKey()
{
if (isWriting()) return nullptr; // we do not know this when writing.
auto &it = r->mObjects.Last().mIterator;
if (it == r->mObjects.Last().mObject->MemberEnd()) return nullptr;
return it->name.GetString();
}
//========================================================================== //==========================================================================
// //
// Writes out all collected objects // Writes out all collected objects
@ -994,8 +1028,9 @@ FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTe
// //
//========================================================================== //==========================================================================
FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/) FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode)
{ {
if (retcode) *retcode = true;
if (arc.isWriting()) if (arc.isWriting())
{ {
if (value != nullptr) if (value != nullptr)
@ -1017,10 +1052,14 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje
if (val != nullptr) if (val != nullptr)
{ {
} }
else else if (!retcode)
{ {
value = nullptr; value = nullptr;
} }
else
{
*retcode = false;
}
} }
return arc; return arc;
} }
@ -1185,18 +1224,55 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor
} }
//==========================================================================
//
// almost, but not quite the same as the above.
//
//==========================================================================
template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&clst, PClass **def)
{
if (arc.isWriting())
{
if (!arc.w->inObject() || def == nullptr || clst != *def)
{
arc.WriteKey(key);
arc.w->mWriter.String(clst->TypeName.GetChars());
}
}
else
{
auto val = arc.r->FindKey(key);
if (val != nullptr)
{
if (val->IsString())
{
clst = PClass::FindClass(val->GetString());
}
else
{
I_Error("string type expected for '%s'", key);
}
}
}
return arc;
}
//========================================================================== //==========================================================================
// //
// //
// //
//========================================================================== //==========================================================================
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def) FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode)
{ {
if (retcode) *retcode = false;
if (arc.isWriting()) if (arc.isWriting())
{ {
if (!arc.w->inObject() || def == nullptr || state != *def) if (!arc.w->inObject() || def == nullptr || state != *def)
{ {
if (retcode) *retcode = true;
arc.WriteKey(key); arc.WriteKey(key);
if (state == nullptr) if (state == nullptr)
{ {
@ -1227,10 +1303,12 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&st
{ {
if (val->IsNull()) if (val->IsNull())
{ {
if (retcode) *retcode = true;
state = nullptr; state = nullptr;
} }
else if (val->IsArray()) else if (val->IsArray())
{ {
if (retcode) *retcode = true;
const rapidjson::Value &cls = (*val)[0]; const rapidjson::Value &cls = (*val)[0];
const rapidjson::Value &ndx = (*val)[1]; const rapidjson::Value &ndx = (*val)[1];
@ -1244,7 +1322,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&st
} }
} }
} }
else else if (!retcode)
{ {
I_Error("array type expected for '%s'", key); I_Error("array type expected for '%s'", key);
} }
@ -1455,7 +1533,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon
const char *n; const char *n;
arc.StringPtr(key, n); arc.StringPtr(key, n);
font = V_GetFont(n); font = V_GetFont(n);
if (font == NULL) if (font == nullptr)
{ {
Printf("Could not load font %s\n", n); Printf("Could not load font %s\n", n);
font = SmallFont; font = SmallFont;
@ -1465,3 +1543,59 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon
} }
//==========================================================================
//
// Handler to retrieve a numeric value of any kind.
//
//==========================================================================
FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &value, NumericValue *defval)
{
if (arc.isWriting())
{
if (!arc.w->inObject() || defval == nullptr || value != *defval)
{
arc.WriteKey(key);
switch (value.type)
{
case NumericValue::NM_signed:
arc.w->mWriter.Int64(value.signedval);
break;
case NumericValue::NM_unsigned:
arc.w->mWriter.Uint64(value.unsignedval);
break;
case NumericValue::NM_float:
arc.w->mWriter.Double(value.floatval);
break;
default:
arc.w->mWriter.Null();
break;
}
}
}
else
{
auto val = arc.r->FindKey(key);
value.signedval = 0;
value.type = NumericValue::NM_invalid;
if (val != nullptr)
{
if (val->IsUint64())
{
value.unsignedval = val->GetUint64();
value.type = NumericValue::NM_unsigned;
}
else if (val->IsInt64())
{
value.signedval = val->GetInt64();
value.type = NumericValue::NM_signed;
}
else if (val->IsDouble())
{
value.floatval = val->GetDouble();
value.type = NumericValue::NM_float;
}
}
}
return arc;
}

View file

@ -14,6 +14,29 @@ extern TArray<line_t> loadlines;
extern TArray<side_t> loadsides; extern TArray<side_t> loadsides;
extern char nulspace[]; extern char nulspace[];
struct NumericValue
{
enum EType
{
NM_invalid,
NM_signed,
NM_unsigned,
NM_float
} type;
union
{
int64_t signedval;
uint64_t unsignedval;
double floatval;
};
bool operator !=(const NumericValue &other)
{
return type != other.type || signedval != other.signedval;
}
};
class FSerializer class FSerializer
@ -24,6 +47,7 @@ public:
FReader *r = nullptr; FReader *r = nullptr;
int ArraySize(); int ArraySize();
void WriteKey(const char *key);
public: public:
@ -34,13 +58,13 @@ public:
bool OpenWriter(); bool OpenWriter();
bool OpenReader(const char *buffer, size_t length); bool OpenReader(const char *buffer, size_t length);
void Close(); void Close();
void WriteKey(const char *key); bool BeginObject(const char *name, bool randomaccess = false);
bool BeginObject(const char *name);
void EndObject(); void EndObject();
bool BeginArray(const char *name); bool BeginArray(const char *name);
void EndArray(); void EndArray();
void WriteObjects(); void WriteObjects();
unsigned GetSize(const char *group); unsigned GetSize(const char *group);
const char *GetKey();
const char *GetOutput(unsigned *len = nullptr); const char *GetOutput(unsigned *len = nullptr);
FSerializer &Args(const char *key, int *args, int *defargs, int special); FSerializer &Args(const char *key, int *args, int *defargs, int special);
FSerializer &Terrain(const char *key, int &terrain, int *def = nullptr); FSerializer &Terrain(const char *key, int &terrain, int *def = nullptr);
@ -130,10 +154,11 @@ FSerializer &Serialize(FSerializer &arc, const char *key, uint16_t &value, uint1
FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval); FSerializer &Serialize(FSerializer &arc, const char *key, double &value, double *defval);
FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval); FSerializer &Serialize(FSerializer &arc, const char *key, float &value, float *defval);
FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval); FSerializer &Serialize(FSerializer &arc, const char *key, FTextureID &value, FTextureID *defval);
FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/); FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObject ** /*defval*/, bool *retcode = nullptr);
FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *defval); FSerializer &Serialize(FSerializer &arc, const char *key, FName &value, FName *defval);
FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def); FSerializer &Serialize(FSerializer &arc, const char *key, FSoundID &sid, FSoundID *def);
FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def); FSerializer &Serialize(FSerializer &arc, const char *key, FString &sid, FString *def);
FSerializer &Serialize(FSerializer &arc, const char *key, NumericValue &sid, NumericValue *def);
template<class T> template<class T>
FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **) FSerializer &Serialize(FSerializer &arc, const char *key, T *&value, T **)
@ -184,13 +209,19 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, side_t *&va
template<> FSerializer &Serialize(FSerializer &arc, const char *key, vertex_t *&value, vertex_t **defval); template<> FSerializer &Serialize(FSerializer &arc, const char *key, vertex_t *&value, vertex_t **defval);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicColormap *&cm, FDynamicColormap **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDynamicColormap *&cm, FDynamicColormap **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClassActor *&clst, PClassActor **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, PClass *&clst, PClass **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FStrifeDialogueNode *&node, FStrifeDialogueNode **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FString *&pstr, FString **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimation *&pstr, FDoorAnimation **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FDoorAnimation *&pstr, FDoorAnimation **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, char *&pstr, char **def);
template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def); template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&font, FFont **def);
FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def, bool *retcode);
template<> inline FSerializer &Serialize(FSerializer &arc, const char *key, FState *&state, FState **def)
{
return Serialize(arc, key, state, def, nullptr);
}
inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p, DVector3 *def) inline FSerializer &Serialize(FSerializer &arc, const char *key, DVector3 &p, DVector3 *def)
{ {