- 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
};
FArchive &operator<< (FArchive &arc, botskill_t &skill);
enum
{
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;
FName varname;
DWORD count, j;
int *varloc = NULL;
symt = &GetClass()->Symbols;
if (arc.IsStoring())
if (arc.isWriting())
{
// Write all fields that aren't serialized by native code.
GetClass()->WriteValue(arc, this);
}
else if (SaveVersion >= 4535)
{
GetClass()->ReadValue(arc, this);
}
else
{ // Old version that only deals with ints
// Read user variables until 'None' is encountered.
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;
GetClass()->WriteAllFields(arc, this);
}
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;
}
GetClass()->ReadAllFields(arc, this);
}
}
//==========================================================================
//
//

View file

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

View file

@ -39,7 +39,7 @@
#include "dobject.h"
#include "i_system.h"
#include "farchive.h"
#include "serializer.h"
#include "actor.h"
#include "templates.h"
#include "autosegs.h"
@ -47,6 +47,7 @@
#include "a_pickups.h"
#include "a_weaponpiece.h"
#include "d_player.h"
#include "doomerrors.h"
#include "fragglescript/t_fs.h"
// 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");
}
@ -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");
SkipValue(ar);
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
@ -809,116 +714,41 @@ PInt::PInt(unsigned int size, bool unsign)
//
// 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;
// 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)
if (Size == 8 && Unsigned)
{
bval = *(BYTE *)addr;
}
else if (Unsigned)
{
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);
// this is a special case that cannot be represented by an int64_t.
uint64_t val = *(uint64_t*)addr;
ar(key, val);
}
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
{
QWORD uval;
SQWORD sval;
};
BYTE tag;
union
{
BYTE val8;
WORD val16;
DWORD val32;
float single;
double dbl;
};
NumericValue val;
ar << tag;
switch (tag)
{
case VAL_Zero: uval = 0; break;
case VAL_One: uval = 1; break;
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
}
ar(key, val);
if (val.type == NumericValue::NM_invalid) return false; // not found or usable
if (val.type == NumericValue::NM_float) val.signedval = (int64_t)val.floatval;
// No need to check the unsigned state here. Downcasting to smaller types will yield the same result for both.
switch (Size)
{
case 1: *(BYTE *)addr = (BYTE)uval; break;
case 2: *(WORD *)addr = (WORD)uval; break;
case 4: *(DWORD *)addr = (DWORD)uval; break;
case 8: *(QWORD *)addr = uval; break;
case 1:
*(uint8_t*)addr = (uint8_t)val.signedval;
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;
}
@ -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 it can be written as single precision without information
// 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;
}
ar(key, *(double*)addr);
}
else
{
singleprecision = *(float *)addr;
ar(key, *(float*)addr);
}
ar.WriteByte(VAL_Float32);
ar << singleprecision;
}
//==========================================================================
@ -1293,58 +1101,24 @@ 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;
union
{
BYTE val8;
WORD val16;
DWORD val32;
QWORD val64;
fixed_t fix;
float single;
angle_t ang;
};
NumericValue val;
switch (tag)
{
case VAL_Zero: val = 0; break;
case VAL_One: val = 1; break;
case VAL_Int8: ar << val8; val = (SBYTE)val8; break;
case VAL_UInt8: ar << val8; val = val8; break;
case VAL_Int16: ar << val16; val = (SWORD)val16; break;
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;
}
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;
bool PFloat::ReadValue(FArchive &ar, void *addr) const
{
BYTE tag;
ar << tag;
double val;
if (ReadValueDbl(ar, &val, tag))
if (Size == 8)
{
if (Size == 4)
{
*(float *)addr = (float)val;
*(double*)addr = val.floatval;
}
else
{
*(double *)addr = val;
*(float*)addr = (float)val.floatval;
}
return true;
}
return false;
}
//==========================================================================
@ -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.WriteString(*(const FString *)addr);
ar(key, *(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;
ar << tag;
if (tag == VAL_String)
const char *cptr;
ar.StringPtr(key, cptr);
if (cptr == nullptr)
{
ar << *(FString *)addr;
}
else if (tag == VAL_Name)
{
const char *str = ar.ReadName();
*(FString *)addr = str;
return false;
}
else
{
SkipValue(ar, tag);
return false;
}
*(FString*)addr = cptr;
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);
ar.WriteName(((const FName *)addr)->GetChars());
const char *cptr = ((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;
ar << tag;
if (tag == VAL_Name)
const char *cptr;
ar.StringPtr(key, cptr);
if (cptr == nullptr)
{
*(FName *)addr = FName(ar.ReadName());
}
else if (tag == VAL_String)
{
FString str;
ar << str;
*(FName *)addr = FName(str);
return false;
}
else
{
SkipValue(ar, tag);
return false;
}
*(FName*)addr = FName(cptr);
return true;
}
}
/* 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);
ar.WriteName(*(const FSoundID *)addr);
const char *cptr = *(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;
ar << tag;
if (tag == VAL_Name)
const char *cptr;
ar.StringPtr(key, cptr);
if (cptr == nullptr)
{
const char *str = ar.ReadName();
*(FSoundID *)addr = FSoundID(str);
}
else if (tag == VAL_String)
{
FString str;
ar << str;
*(FSoundID *)addr = FSoundID(str);
return false;
}
else
{
SkipValue(ar, tag);
return false;
}
*(FSoundID *)addr = FSoundID(cptr);
return true;
}
}
/* 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 << *(FState **)addr;
ar(key, *(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;
ar << tag;
if (tag == VAL_State)
{
//ar << *(FState **)addr;
return true;
}
SkipValue(ar, tag);
return false;
bool res = false;
::Serialize(ar, key, *(FState **)addr, nullptr, &res);
return res;
}
/* 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)))
{
ar.WriteByte(VAL_Object);
ar << *(DObject **)addr;
ar(key, *(DObject **)addr);
}
else
{
assert(0 && "Pointer points to a type we don't handle");
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
BYTE tag;
ar << tag;
if (tag == VAL_Object && PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
if (PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
{
ar << *(DObject **)addr;
return true;
bool res = false;
::Serialize(ar, key, *(DObject **)addr, nullptr, &res);
return res;
}
SkipValue(ar, tag);
#endif
return false;
}
@ -2106,16 +1843,18 @@ 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);
ar.WriteCount(ElementCount);
if (ar.BeginArray(key))
{
const BYTE *addrb = (const BYTE *)addr;
for (unsigned i = 0; i < ElementCount; ++i)
{
ElementType->WriteValue(ar, addrb);
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
{
if (ar.BeginArray(key))
{
bool readsomething = false;
BYTE tag;
ar << tag;
if (tag == VAL_Array)
{
unsigned count = ar.ReadCount();
unsigned i;
unsigned count = ar.ArraySize();
unsigned loop = MIN(count, ElementCount);
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;
}
if (i < ElementCount)
if (loop < ElementCount)
{
DPrintf(DMSG_WARNING, "Array on disk (%u) is bigger than in memory (%u)\n",
count, ElementCount);
for (; i < ElementCount; ++i)
{
SkipValue(ar);
}
}
ar.EndArray();
return readsomething;
}
SkipValue(ar, tag);
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);
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;
ar << tag;
if (tag == VAL_Struct)
if (ar.BeginObject(key))
{
return ReadFields(ar, addr);
bool ret = ReadFields(ar, addr);
ar.EndObject();
return ret;
}
SkipValue(ar, tag);
return true;
return false;
}
//==========================================================================
@ -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)
{
@ -2483,11 +2217,9 @@ void PStruct::WriteFields(FArchive &ar, const void *addr, const TArray<PField *>
// Skip fields with native serialization
if (!(field->Flags & VARF_Native))
{
ar.WriteName(field->SymbolName);
field->Type->WriteValue(ar, (const BYTE *)addr + field->Offset);
field->Type->WriteValue(ar, field->SymbolName.GetChars(), (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;
const char *label = ar.ReadName();
if (label == NULL)
{ // If there is nothing to restore, we count it as success.
return true;
}
for (; label != NULL; label = ar.ReadName())
bool foundsomething = false;
const char *label;
while ((label = ar.GetKey()))
{
foundsomething = true;
const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true);
if (sym == NULL)
{
DPrintf(DMSG_ERROR, "Cannot find field %s in %s\n",
label, TypeName.GetChars());
SkipValue(ar);
}
else if (!sym->IsKindOf(RUNTIME_CLASS(PField)))
{
DPrintf(DMSG_ERROR, "Symbol %s in %s is not a field\n",
label, TypeName.GetChars());
SkipValue(ar);
}
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);
}
}
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)
{
@ -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-
// derived class. Whether or not that is a language feature
// that will actually be allowed remains to be seen.
ar.UserWriteClass(const_cast<PClass *>(type));
FString key;
key.Format("class:%s", type->TypeName.GetChars());
if (ar.BeginObject(key.GetChars()))
{
PStruct::WriteFields(ar, addr, type->Fields);
ar.EndObject();
}
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);
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;
ar << tag;
if (tag != VAL_Class)
if (ar.BeginObject(key))
{
SkipValue(ar, tag);
return false;
bool ret = ReadAllFields(ar, addr);
ar.EndObject();
return ret;
}
else
{
return true;
}
bool PClass::ReadAllFields(FSerializer &ar, void *addr) const
{
bool readsomething = false;
PClass *type;
for (ar.UserReadClass(type); type != NULL; ar.UserReadClass(type))
bool foundsomething = false;
const char *key;
while ((key = ar.GetKey()))
{
if (strncmp(key, "class:", 6))
{
// 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.
const PClass *parent;
@ -2808,7 +2563,7 @@ bool PClass::ReadValue(FArchive &ar, void *addr) const
break;
}
}
if (parent != NULL)
if (parent != nullptr)
{
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",
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
// without completely breaking savegames, provided that the change isn't between
// 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.
// If the value was incompatible, then the memory at *addr is unchanged.
virtual bool ReadValue(FArchive &ar, void *addr) const;
// Skips over a value written with WriteValue
static void SkipValue(FArchive &ar);
static void SkipValue(FArchive &ar, int tag);
virtual bool ReadValue(FSerializer &ar, const char *key,void *addr) const;
// Sets the default value for this type at (base + offset)
// If the default value is binary 0, then this function doesn't need
@ -354,8 +350,8 @@ class PInt : public PBasicType
public:
PInt(unsigned int size, bool unsign);
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const 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, double val);
@ -383,8 +379,8 @@ class PFloat : public PBasicType
public:
PFloat(unsigned int size);
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const 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, double val);
@ -421,8 +417,8 @@ public:
virtual int GetRegType() const;
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const 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 InitializeValue(void *addr, const void *def) const override;
void DestroyValue(void *addr) const override;
@ -436,8 +432,8 @@ class PName : public PInt
public:
PName();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
};
class PSound : public PInt
@ -446,8 +442,8 @@ class PSound : public PInt
public:
PSound();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
};
class PColor : public PInt
@ -465,8 +461,8 @@ class PStatePointer : public PBasicType
public:
PStatePointer();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
virtual int GetStoreOp() const;
virtual int GetLoadOp() const;
@ -489,8 +485,8 @@ public:
virtual bool IsMatch(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;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const void *addr) const override;
bool ReadValue(FSerializer &ar, const char *key,void *addr) const override;
protected:
PPointer();
@ -559,8 +555,8 @@ public:
virtual bool IsMatch(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;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const 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;
@ -622,12 +618,12 @@ public:
size_t PropagateMark();
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const 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;
static void WriteFields(FArchive &ar, const void *addr, const TArray<PField *> &fields);
bool ReadFields(FArchive &ar, void *addr) const;
static void WriteFields(FSerializer &ar, const void *addr, const TArray<PField *> &fields);
bool ReadFields(FSerializer &ar, void *addr) const;
protected:
PStruct();
};
@ -692,8 +688,10 @@ public:
typedef PClassClass MetaClass;
MetaClass *GetClass() const;
void WriteValue(FArchive &ar, const void *addr) const override;
bool ReadValue(FArchive &ar, void *addr) const override;
void WriteValue(FSerializer &ar, const char *key,const 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) {}
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::MemberIterator mIterator;
int mIndex;
bool mRandomAccess;
FJSONObject(rapidjson::Value *v)
FJSONObject(rapidjson::Value *v, bool randomaccess = false)
{
mObject = v;
mRandomAccess = randomaccess;
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;
doc.Parse(buffer, length);
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)
@ -108,6 +114,8 @@ struct FReader
FJSONObject &obj = mObjects.Last();
if (obj.mObject->IsObject())
{
if (!obj.mRandomAccess)
{
if (obj.mIterator != obj.mObject->MemberEnd())
{
@ -117,6 +125,14 @@ struct FReader
}
}
}
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())
{
return &obj.mObject[obj.mIndex++];
@ -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())
{
@ -242,7 +258,7 @@ bool FSerializer::BeginObject(const char *name)
{
if (val->IsObject())
{
r->mObjects.Push(FJSONObject(val));
r->mObjects.Push(FJSONObject(val, randomaccess));
}
else
{
@ -530,6 +546,10 @@ FSerializer &FSerializer::StringPtr(const char *key, const char *&charptr)
{
charptr = val->GetString();
}
else
{
charptr = nullptr;
}
}
}
return *this;
@ -550,6 +570,20 @@ unsigned FSerializer::GetSize(const char *group)
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
@ -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 (value != nullptr)
@ -1017,10 +1052,14 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje
if (val != nullptr)
{
}
else
else if (!retcode)
{
value = nullptr;
}
else
{
*retcode = false;
}
}
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.w->inObject() || def == nullptr || state != *def)
{
if (retcode) *retcode = true;
arc.WriteKey(key);
if (state == nullptr)
{
@ -1227,10 +1303,12 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FState *&st
{
if (val->IsNull())
{
if (retcode) *retcode = true;
state = nullptr;
}
else if (val->IsArray())
{
if (retcode) *retcode = true;
const rapidjson::Value &cls = (*val)[0];
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);
}
@ -1455,7 +1533,7 @@ template<> FSerializer &Serialize(FSerializer &arc, const char *key, FFont *&fon
const char *n;
arc.StringPtr(key, n);
font = V_GetFont(n);
if (font == NULL)
if (font == nullptr)
{
Printf("Could not load font %s\n", n);
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 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
@ -24,6 +47,7 @@ public:
FReader *r = nullptr;
int ArraySize();
void WriteKey(const char *key);
public:
@ -34,13 +58,13 @@ public:
bool OpenWriter();
bool OpenReader(const char *buffer, size_t length);
void Close();
void WriteKey(const char *key);
bool BeginObject(const char *name);
bool BeginObject(const char *name, bool randomaccess = false);
void EndObject();
bool BeginArray(const char *name);
void EndArray();
void WriteObjects();
unsigned GetSize(const char *group);
const char *GetKey();
const char *GetOutput(unsigned *len = nullptr);
FSerializer &Args(const char *key, int *args, int *defargs, int special);
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, float &value, float *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, FSoundID &sid, FSoundID *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>
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, FDynamicColormap *&cm, FDynamicColormap **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, FString *&pstr, FString **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, 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)
{