mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-11-11 07:12:16 +00:00
Added methods for PTypes to serialize their values
- Values are tagged to allow for some measure of changing variable types without automatically breaking savegames. - Use these new methods to serialize the non-native variables in an object. This allows for achiving non-ints.
This commit is contained in:
parent
da496bbe62
commit
85c8218441
6 changed files with 1027 additions and 42 deletions
|
@ -417,46 +417,15 @@ void DObject::SerializeUserVars(FArchive &arc)
|
|||
|
||||
if (arc.IsStoring())
|
||||
{
|
||||
// Write all user variables.
|
||||
for (; symt != NULL; symt = symt->ParentSymbolTable)
|
||||
{
|
||||
PSymbolTable::MapType::Iterator it(symt->Symbols);
|
||||
PSymbolTable::MapType::Pair *pair;
|
||||
|
||||
while (it.NextPair(pair))
|
||||
{
|
||||
PField *var = dyn_cast<PField>(pair->Value);
|
||||
if (var != NULL && !(var->Flags & VARF_Native))
|
||||
{
|
||||
PType *type = var->Type;
|
||||
PArray *arraytype = dyn_cast<PArray>(type);
|
||||
if (arraytype == NULL)
|
||||
{
|
||||
count = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
count = arraytype->ElementCount;
|
||||
type = arraytype->ElementType;
|
||||
}
|
||||
assert(type == TypeSInt32);
|
||||
varloc = (int *)(reinterpret_cast<BYTE *>(this) + var->Offset);
|
||||
|
||||
arc << var->SymbolName;
|
||||
arc.WriteCount(count);
|
||||
for (j = 0; j < count; ++j)
|
||||
{
|
||||
arc << varloc[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Write terminator.
|
||||
varname = NAME_None;
|
||||
arc << varname;
|
||||
// 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)
|
||||
|
|
894
src/dobjtype.cpp
894
src/dobjtype.cpp
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "dobject.h"
|
||||
#include "i_system.h"
|
||||
#include "farchive.h"
|
||||
#include "actor.h"
|
||||
#include "templates.h"
|
||||
#include "autosegs.h"
|
||||
|
@ -384,6 +385,121 @@ bool PType::VisitedNodeSet::Check(const PType *node)
|
|||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PType::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
assert(0 && "Cannot write value for this type");
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PType :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PType::ReadValue(FArchive &ar, 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: case VAL_Fixed: case VAL_BAM:
|
||||
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:
|
||||
{
|
||||
DObject *skipper;
|
||||
ar << skipper;
|
||||
break;
|
||||
}
|
||||
case VAL_State:
|
||||
{
|
||||
FState *skipper;
|
||||
ar << skipper;
|
||||
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 :: SetValue
|
||||
|
@ -662,6 +778,177 @@ 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
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
ar.WriteByte(VAL_Zero + bval);
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PInt :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PInt::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
union
|
||||
{
|
||||
QWORD uval;
|
||||
SQWORD sval;
|
||||
};
|
||||
BYTE tag;
|
||||
union
|
||||
{
|
||||
BYTE val8;
|
||||
WORD val16;
|
||||
DWORD val32;
|
||||
fixed_t fix;
|
||||
float single;
|
||||
double dbl;
|
||||
angle_t ang;
|
||||
};
|
||||
|
||||
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_Fixed: ar << fix; sval = fix >> FRACBITS; break; // fixed -> int
|
||||
case VAL_BAM: ar << ang; uval = ang / ANGLE_1; break; // BAM -> degrees
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PInt :: SetValue
|
||||
|
@ -947,6 +1234,97 @@ void PFloat::SetSymbols(const PFloat::SymbolInitI *sym, size_t count)
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFloat :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PFloat::WriteValue(FArchive &ar, 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;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
singleprecision = *(float *)addr;
|
||||
}
|
||||
ar.WriteByte(VAL_Float32);
|
||||
ar << singleprecision;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFloat :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static bool ReadValueDbl(FArchive &ar, double *addr, unsigned tag)
|
||||
{
|
||||
double val;
|
||||
union
|
||||
{
|
||||
BYTE val8;
|
||||
WORD val16;
|
||||
DWORD val32;
|
||||
QWORD val64;
|
||||
fixed_t fix;
|
||||
float single;
|
||||
angle_t ang;
|
||||
};
|
||||
|
||||
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_Fixed: ar << fix; val = FIXED2DBL(fix); break;
|
||||
case VAL_BAM: ar << ang; val = ang * (90.0 / ANGLE_90); break; // BAM -> degrees
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -1080,6 +1458,45 @@ int PString::GetRegType() const
|
|||
return REGT_STRING;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PString :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PString::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_String);
|
||||
ar.WriteString(*(const FString *)addr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PString :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PString::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag == VAL_String)
|
||||
{
|
||||
ar << *(FString *)addr;
|
||||
}
|
||||
else if (tag == VAL_Name)
|
||||
{
|
||||
const char *str = ar.ReadName();
|
||||
*(FString *)addr = str;
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipValue(ar, tag);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* PName ******************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PName)
|
||||
|
@ -1096,6 +1513,46 @@ PName::PName()
|
|||
assert(sizeof(FName) == __alignof(FName));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PName :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PName::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_Name);
|
||||
ar.WriteName(((const FName *)addr)->GetChars());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PName :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PName::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag == VAL_Name)
|
||||
{
|
||||
*(FName *)addr = FName(ar.ReadName());
|
||||
}
|
||||
else if (tag == VAL_String)
|
||||
{
|
||||
FString str;
|
||||
ar << str;
|
||||
*(FName *)addr = FName(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipValue(ar, tag);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* PSound *****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PSound)
|
||||
|
@ -1112,6 +1569,48 @@ PSound::PSound()
|
|||
assert(sizeof(FSoundID) == __alignof(FSoundID));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PSound :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PSound::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_Name);
|
||||
ar.WriteName(*(const FSoundID *)addr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PSound :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PSound::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
|
||||
ar << tag;
|
||||
if (tag == VAL_Name)
|
||||
{
|
||||
const char *str = ar.ReadName();
|
||||
*(FSoundID *)addr = FSoundID(str);
|
||||
}
|
||||
else if (tag == VAL_String)
|
||||
{
|
||||
FString str;
|
||||
ar << str;
|
||||
*(FSoundID *)addr = FSoundID(str);
|
||||
}
|
||||
else
|
||||
{
|
||||
SkipValue(ar, tag);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* PColor *****************************************************************/
|
||||
|
||||
IMPLEMENT_CLASS(PColor)
|
||||
|
@ -1143,6 +1642,45 @@ PFixed::PFixed()
|
|||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFixed :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PFixed::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_Fixed);
|
||||
ar << *(fixed_t *)addr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFixed :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PFixed::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag == VAL_Fixed)
|
||||
{
|
||||
ar << *(fixed_t *)addr;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
double val;
|
||||
if (ReadValueDbl(ar, &val, tag))
|
||||
{
|
||||
*(fixed_t *)addr = FLOAT2FIXED(val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PFixed :: SetValue
|
||||
|
@ -1222,6 +1760,45 @@ PAngle::PAngle()
|
|||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PAngle :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PAngle::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_BAM);
|
||||
ar.WriteInt32(*(angle_t *)addr);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PAngle :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PAngle::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag == VAL_BAM)
|
||||
{
|
||||
ar << *(angle_t *)addr;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
double val;
|
||||
if (ReadValueDbl(ar, &val, tag))
|
||||
{
|
||||
*(angle_t *)addr = FLOAT2ANGLE(val);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PAngle :: SetValue
|
||||
|
@ -1334,6 +1911,37 @@ int PStatePointer::GetRegType() const
|
|||
return REGT_POINTER;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PStatePointer::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_State);
|
||||
ar << *(FState **)addr;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStatePointer :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PStatePointer::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag == VAL_State)
|
||||
{
|
||||
ar << *(FState **)addr;
|
||||
return true;
|
||||
}
|
||||
SkipValue(ar, tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* PPointer ***************************************************************/
|
||||
|
||||
IMPLEMENT_POINTY_CLASS(PPointer)
|
||||
|
@ -1421,6 +2029,45 @@ void PPointer::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
|||
id2 = 0;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PPointer :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PPointer::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
if (PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||
{
|
||||
ar.WriteByte(VAL_Object);
|
||||
ar << *(DObject **)addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0 && "Pointer points to a type we don't handle");
|
||||
I_Error("Attempt to save pointer to unhandled type");
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PPointer :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PPointer::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag == VAL_Object && PointedType->IsKindOf(RUNTIME_CLASS(PClass)))
|
||||
{
|
||||
ar << *(DObject **)addr;
|
||||
return true;
|
||||
}
|
||||
SkipValue(ar, tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NewPointer
|
||||
|
@ -1626,6 +2273,61 @@ void PArray::GetTypeIDs(intptr_t &id1, intptr_t &id2) const
|
|||
id2 = ElementCount;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PArray :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PArray::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_Array);
|
||||
ar.WriteCount(ElementCount);
|
||||
const BYTE *addrb = (const BYTE *)addr;
|
||||
for (unsigned i = 0; i < ElementCount; ++i)
|
||||
{
|
||||
ElementType->WriteValue(ar, addrb);
|
||||
addrb += ElementSize;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PArray :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PArray::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
bool readsomething = false;
|
||||
BYTE tag;
|
||||
|
||||
ar << tag;
|
||||
if (tag == VAL_Array)
|
||||
{
|
||||
unsigned count = ar.ReadCount();
|
||||
unsigned i;
|
||||
BYTE *addrb = (BYTE *)addr;
|
||||
for (i = 0; i < MIN(count, ElementCount); ++i)
|
||||
{
|
||||
readsomething |= ElementType->ReadValue(ar, addrb);
|
||||
addrb += ElementSize;
|
||||
}
|
||||
if (i < ElementCount)
|
||||
{
|
||||
DPrintf("Array on disk (%u) is bigger than in memory (%u)\n",
|
||||
count, ElementCount);
|
||||
for (; i < ElementCount; ++i)
|
||||
{
|
||||
SkipValue(ar);
|
||||
}
|
||||
}
|
||||
return readsomething;
|
||||
}
|
||||
SkipValue(ar, tag);
|
||||
return false;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// NewArray
|
||||
|
@ -1879,6 +2581,95 @@ PStruct::PStruct(FName name, DObject *outer)
|
|||
{
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: WriteValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PStruct::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_Struct);
|
||||
WriteFields(ar, addr, Fields);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PStruct::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag == VAL_Struct)
|
||||
{
|
||||
return ReadFields(ar, addr);
|
||||
}
|
||||
SkipValue(ar, tag);
|
||||
return true;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: WriteFields STATIC
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
void PStruct::WriteFields(FArchive &ar, const void *addr, const TArray<PField *> &fields)
|
||||
{
|
||||
for (unsigned i = 0; i < fields.Size(); ++i)
|
||||
{
|
||||
const PField *field = fields[i];
|
||||
// Skip fields with native serialization
|
||||
if (!(field->Flags & VARF_Native))
|
||||
{
|
||||
ar.WriteName(field->SymbolName);
|
||||
field->Type->WriteValue(ar, (const BYTE *)addr + field->Offset);
|
||||
}
|
||||
}
|
||||
ar.WriteName(NULL);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: ReadFields
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PStruct::ReadFields(FArchive &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())
|
||||
{
|
||||
const PSymbol *sym = Symbols.FindSymbol(FName(label, true), true);
|
||||
if (sym == NULL)
|
||||
{
|
||||
DPrintf("Cannot find field %s in %s\n",
|
||||
label, TypeName.GetChars());
|
||||
SkipValue(ar);
|
||||
}
|
||||
else if (!sym->IsKindOf(RUNTIME_CLASS(PField)))
|
||||
{
|
||||
DPrintf("Symbol %s in %s is not a field\n",
|
||||
label, TypeName.GetChars());
|
||||
SkipValue(ar);
|
||||
}
|
||||
else
|
||||
{
|
||||
readsomething |= static_cast<const PField *>(sym)->Type->ReadValue(ar,
|
||||
(BYTE *)addr + static_cast<const PField *>(sym)->Offset);
|
||||
}
|
||||
}
|
||||
return readsomething;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PStruct :: AddField
|
||||
|
@ -2091,6 +2882,89 @@ IMPLEMENT_POINTY_CLASS(PClass)
|
|||
DECLARE_POINTER(ParentClass)
|
||||
END_POINTERS
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: WriteValue
|
||||
//
|
||||
// Similar to PStruct's version, except it also needs to traverse parent
|
||||
// classes.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
static void RecurseWriteFields(const PClass *type, FArchive &ar, const void *addr)
|
||||
{
|
||||
if (type != NULL)
|
||||
{
|
||||
RecurseWriteFields(type->ParentClass, ar, addr);
|
||||
// Don't write this part if it has no non-native variables
|
||||
for (unsigned i = 0; i < type->Fields.Size(); ++i)
|
||||
{
|
||||
if (!(type->Fields[i]->Flags & VARF_Native))
|
||||
{
|
||||
// Tag this section with the class it came from in case
|
||||
// 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));
|
||||
PStruct::WriteFields(ar, addr, type->Fields);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PClass::WriteValue(FArchive &ar, const void *addr) const
|
||||
{
|
||||
ar.WriteByte(VAL_Class);
|
||||
RecurseWriteFields(this, ar, addr);
|
||||
ar.UserWriteClass(NULL);
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: ReadValue
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool PClass::ReadValue(FArchive &ar, void *addr) const
|
||||
{
|
||||
BYTE tag;
|
||||
ar << tag;
|
||||
if (tag != VAL_Class)
|
||||
{
|
||||
SkipValue(ar, tag);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool readsomething = false;
|
||||
PClass *type;
|
||||
for (ar.UserReadClass(type); type != NULL; ar.UserReadClass(type))
|
||||
{
|
||||
// Only read it if the type is related to this one.
|
||||
const PClass *parent;
|
||||
for (parent = this; parent != NULL; parent = parent->ParentClass)
|
||||
{
|
||||
if (parent == type)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parent != NULL)
|
||||
{
|
||||
readsomething |= type->ReadFields(ar, addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
DPrintf("Unknown superclass %s of class %s\n",
|
||||
type->TypeName.GetChars(), TypeName.GetChars());
|
||||
SkipValue(ar, VAL_Struct);
|
||||
}
|
||||
}
|
||||
return readsomething;
|
||||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// cregcmp
|
||||
|
@ -2354,6 +3228,26 @@ void PClass::InsertIntoHash ()
|
|||
}
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: FindParentClass
|
||||
//
|
||||
// Finds a parent class that matches the given name, including itself.
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
const PClass *PClass::FindParentClass(FName name) const
|
||||
{
|
||||
for (const PClass *type = this; type != NULL; type = type->ParentClass)
|
||||
{
|
||||
if (type->TypeName == name)
|
||||
{
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// PClass :: FindClass
|
||||
|
|
|
@ -186,6 +186,20 @@ public:
|
|||
|
||||
int FindConversion(PType *target, const Conversion **slots, int numslots);
|
||||
|
||||
// Writes the value of a variable of this type at (addr) to an archive, preceded by
|
||||
// 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;
|
||||
|
||||
// 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);
|
||||
|
||||
// Sets the value of a variable of this type at (addr)
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
|
@ -321,6 +335,9 @@ 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;
|
||||
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
|
@ -347,6 +364,9 @@ 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;
|
||||
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
|
@ -381,6 +401,9 @@ public:
|
|||
PString();
|
||||
|
||||
virtual int GetRegType() const;
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
};
|
||||
|
||||
// Variations of integer types ----------------------------------------------
|
||||
|
@ -390,6 +413,9 @@ class PName : public PInt
|
|||
DECLARE_CLASS(PName, PInt);
|
||||
public:
|
||||
PName();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
};
|
||||
|
||||
class PSound : public PInt
|
||||
|
@ -397,6 +423,9 @@ class PSound : public PInt
|
|||
DECLARE_CLASS(PSound, PInt);
|
||||
public:
|
||||
PSound();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
};
|
||||
|
||||
class PColor : public PInt
|
||||
|
@ -415,6 +444,9 @@ class PFixed : public PFloat
|
|||
public:
|
||||
PFixed();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
|
@ -429,6 +461,9 @@ class PAngle : public PFloat
|
|||
public:
|
||||
PAngle();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
|
||||
virtual void SetValue(void *addr, int val);
|
||||
virtual void SetValue(void *addr, double val);
|
||||
virtual int GetValueInt(void *addr) const;
|
||||
|
@ -445,6 +480,9 @@ class PStatePointer : public PBasicType
|
|||
public:
|
||||
PStatePointer();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
|
||||
virtual int GetStoreOp() const;
|
||||
virtual int GetLoadOp() const;
|
||||
virtual int GetRegType() const;
|
||||
|
@ -465,6 +503,10 @@ 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;
|
||||
|
||||
protected:
|
||||
PPointer();
|
||||
};
|
||||
|
@ -531,6 +573,10 @@ 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;
|
||||
|
||||
protected:
|
||||
PArray();
|
||||
};
|
||||
|
@ -588,6 +634,12 @@ public:
|
|||
virtual PField *AddField(FName name, PType *type, DWORD flags=0);
|
||||
|
||||
size_t PropagateMark();
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
|
||||
static void WriteFields(FArchive &ar, const void *addr, const TArray<PField *> &fields);
|
||||
bool ReadFields(FArchive &ar, void *addr) const;
|
||||
protected:
|
||||
PStruct();
|
||||
};
|
||||
|
@ -650,6 +702,9 @@ public:
|
|||
typedef PClassClass MetaClass;
|
||||
MetaClass *GetClass() const;
|
||||
|
||||
void WriteValue(FArchive &ar, const void *addr) const override;
|
||||
bool ReadValue(FArchive &ar, void *addr) const override;
|
||||
|
||||
virtual void DeriveData(PClass *newclass) {}
|
||||
static void StaticInit();
|
||||
static void StaticShutdown();
|
||||
|
@ -694,6 +749,9 @@ public:
|
|||
}
|
||||
|
||||
// Find a type, given its name.
|
||||
const PClass *FindParentClass(FName name) const;
|
||||
PClass *FindParentClass(FName name) { return const_cast<PClass *>(const_cast<const PClass *>(this)->FindParentClass(name)); }
|
||||
|
||||
static PClass *FindClass(const char *name) { return FindClass(FName(name, true)); }
|
||||
static PClass *FindClass(const FString &name) { return FindClass(FName(name, true)); }
|
||||
static PClass *FindClass(ENamedName name) { return FindClass(FName(name)); }
|
||||
|
@ -844,4 +902,31 @@ public:
|
|||
|
||||
void ReleaseGlobalSymbols();
|
||||
|
||||
// Enumerations for serializing types in an archive -------------------------
|
||||
|
||||
enum ETypeVal : BYTE
|
||||
{
|
||||
VAL_Int8,
|
||||
VAL_UInt8,
|
||||
VAL_Int16,
|
||||
VAL_UInt16,
|
||||
VAL_Int32,
|
||||
VAL_UInt32,
|
||||
VAL_Int64,
|
||||
VAL_UInt64,
|
||||
VAL_Zero,
|
||||
VAL_One,
|
||||
VAL_Float32,
|
||||
VAL_Float64,
|
||||
VAL_Fixed,
|
||||
VAL_BAM,
|
||||
VAL_String,
|
||||
VAL_Name,
|
||||
VAL_Struct,
|
||||
VAL_Array,
|
||||
VAL_Object,
|
||||
VAL_State,
|
||||
VAL_Class,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -721,6 +721,29 @@ void FArchive::Close ()
|
|||
}
|
||||
}
|
||||
|
||||
void FArchive::WriteByte(BYTE val)
|
||||
{
|
||||
m_File->Write(&val, 1);
|
||||
}
|
||||
|
||||
void FArchive::WriteInt16(WORD val)
|
||||
{
|
||||
WORD out = LittleShort(val);
|
||||
m_File->Write(&out, 2);
|
||||
}
|
||||
|
||||
void FArchive::WriteInt32(DWORD val)
|
||||
{
|
||||
int out = LittleLong(val);
|
||||
m_File->Write(&out, 4);
|
||||
}
|
||||
|
||||
void FArchive::WriteInt64(QWORD val)
|
||||
{
|
||||
long long out = SWAP_QWORD(val);
|
||||
m_File->Write(&out, 8);
|
||||
}
|
||||
|
||||
void FArchive::WriteCount (DWORD count)
|
||||
{
|
||||
BYTE out;
|
||||
|
@ -832,6 +855,14 @@ void FArchive::WriteString (const char *str)
|
|||
}
|
||||
}
|
||||
|
||||
void FArchive::WriteString(const FString &str)
|
||||
{
|
||||
// The count includes the '\0' terminator, but we don't
|
||||
// actually write it out.
|
||||
WriteCount(str.Len() + 1);
|
||||
Write(str, str.Len());
|
||||
}
|
||||
|
||||
FArchive &FArchive::operator<< (char *&str)
|
||||
{
|
||||
if (m_Storing)
|
||||
|
@ -868,7 +899,7 @@ FArchive &FArchive::operator<< (FString &str)
|
|||
{
|
||||
if (m_Storing)
|
||||
{
|
||||
WriteString (str.GetChars());
|
||||
WriteString (str);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -883,8 +914,7 @@ FArchive &FArchive::operator<< (FString &str)
|
|||
char *str2 = (char *)alloca(size*sizeof(char));
|
||||
size--;
|
||||
Read (str2, size);
|
||||
str2[size] = 0;
|
||||
str = str2;
|
||||
str = FString(str2, size);
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
|
|
@ -166,7 +166,14 @@ public:
|
|||
virtual void Write (const void *mem, unsigned int len);
|
||||
virtual void Read (void *mem, unsigned int len);
|
||||
|
||||
void WriteString(const FString &str);
|
||||
void WriteString (const char *str);
|
||||
|
||||
void WriteByte(BYTE val);
|
||||
void WriteInt16(WORD val);
|
||||
void WriteInt32(DWORD val);
|
||||
void WriteInt64(QWORD val);
|
||||
|
||||
void WriteCount (DWORD count);
|
||||
DWORD ReadCount ();
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ const char *GetVersionString();
|
|||
|
||||
// Use 4500 as the base git save version, since it's higher than the
|
||||
// SVN revision ever got.
|
||||
#define SAVEVER 4534
|
||||
#define SAVEVER 4535
|
||||
|
||||
#define SAVEVERSTRINGIFY2(x) #x
|
||||
#define SAVEVERSTRINGIFY(x) SAVEVERSTRINGIFY2(x)
|
||||
|
|
Loading…
Reference in a new issue