2016-09-19 08:41:21 +00:00
# ifndef __SERIALIZER_H
# define __SERIALIZER_H
# include <stdint.h>
2016-09-19 17:14:30 +00:00
# include <type_traits>
2016-09-19 08:41:21 +00:00
# include "tarray.h"
# include "r_defs.h"
2016-09-20 21:13:12 +00:00
# include "resourcefiles/file_zip.h"
2017-03-10 01:22:42 +00:00
# include "tflags.h"
2019-12-29 10:35:06 +00:00
# include "utility/dictionary.h"
2016-09-19 08:41:21 +00:00
2016-09-23 15:49:33 +00:00
extern bool save_full ;
2016-09-20 23:18:29 +00:00
struct ticcmd_t ;
struct usercmd_t ;
2016-09-19 08:41:21 +00:00
struct FWriter ;
struct FReader ;
2017-03-10 01:22:42 +00:00
class PClass ;
class PClassActor ;
struct FStrifeDialogueNode ;
class FFont ;
struct FState ;
struct FDoorAnimation ;
class FSoundID ;
struct FPolyObj ;
union FRenderStyle ;
2019-01-28 17:26:14 +00:00
struct FInterpolator ;
2016-09-19 08:41:21 +00:00
2016-09-22 22:45:41 +00:00
inline bool nullcmp ( const void * buffer , size_t length )
{
const char * p = ( const char * ) buffer ;
for ( ; length > 0 ; length - - )
{
if ( * p + + ! = 0 ) return false ;
}
return true ;
}
2016-09-19 08:41:21 +00:00
2016-09-20 16:27:47 +00:00
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 ;
}
} ;
2016-09-19 08:41:21 +00:00
class FSerializer
{
public :
FWriter * w = nullptr ;
FReader * r = nullptr ;
2019-01-26 20:23:19 +00:00
FLevelLocals * Level ;
2016-09-19 08:41:21 +00:00
2016-10-17 04:19:08 +00:00
unsigned ArraySize ( ) ;
2016-09-20 16:27:47 +00:00
void WriteKey ( const char * key ) ;
2016-09-22 22:45:41 +00:00
void WriteObjects ( ) ;
2016-09-19 08:41:21 +00:00
public :
2019-01-26 20:23:19 +00:00
FSerializer ( FLevelLocals * l ) : Level ( l )
{ }
2016-09-19 11:36:58 +00:00
~ FSerializer ( )
{
2017-02-27 14:16:03 +00:00
mErrors = 0 ; // The destructor may not throw an exception so silence the error checker.
2016-09-19 11:36:58 +00:00
Close ( ) ;
}
2016-09-21 19:57:24 +00:00
bool OpenWriter ( bool pretty = true ) ;
2016-09-22 22:45:41 +00:00
bool OpenReader ( const char * buffer , size_t length ) ;
bool OpenReader ( FCompressedBuffer * input ) ;
2016-09-19 08:41:21 +00:00
void Close ( ) ;
2016-09-23 15:49:33 +00:00
void ReadObjects ( bool hubtravel ) ;
- removed the sequential processing of JSON objects because the benefit is too small.
After testing with a savegame on ZDCMP2 which is probably the largest map in existence, timing both methods resulted in a speed difference of less than 40 ms (70 vs 110 ms for reading all sectory, linedefs, sidedefs and objects).
This compares to an overall restoration time, including reloading the level, precaching all textures and setting everything up, of approx. 1.2 s, meaning an increase of 3% of the entire reloading time.
That's simply not worth all the negative side effects that may happen with a method that highly depends on proper code construction.
On the other hand, using random access means that a savegame version change is only needed now when the semantics of a field change, but not if some get added or deleted.
- do not I_Error out in the serializer unless caused by a programming error.
It is better to let the serializer finish, collect all the errors and I_Error out when the game is known to be in a stable enough state to allow unwinding.
2016-09-23 12:04:05 +00:00
bool BeginObject ( const char * name ) ;
void EndObject ( ) ;
2016-09-19 08:41:21 +00:00
bool BeginArray ( const char * name ) ;
void EndArray ( ) ;
2016-09-20 07:11:13 +00:00
unsigned GetSize ( const char * group ) ;
2016-09-20 16:27:47 +00:00
const char * GetKey ( ) ;
2016-09-19 08:41:21 +00:00
const char * GetOutput ( unsigned * len = nullptr ) ;
2016-09-20 21:13:12 +00:00
FCompressedBuffer GetCompressedOutput ( ) ;
2016-09-19 08:41:21 +00:00
FSerializer & Args ( const char * key , int * args , int * defargs , int special ) ;
FSerializer & Terrain ( const char * key , int & terrain , int * def = nullptr ) ;
2016-09-19 10:53:42 +00:00
FSerializer & Sprite ( const char * key , int32_t & spritenum , int32_t * def ) ;
2016-09-19 22:41:22 +00:00
FSerializer & StringPtr ( const char * key , const char * & charptr ) ; // This only retrieves the address but creates no permanent copy of the string unlike the regular char* serializer.
2016-09-21 10:19:13 +00:00
FSerializer & AddString ( const char * key , const char * charptr ) ;
2019-02-16 20:29:46 +00:00
const char * GetString ( const char * key ) ;
2016-09-19 22:41:22 +00:00
FSerializer & ScriptNum ( const char * key , int & num ) ;
2016-09-19 08:41:21 +00:00
bool isReading ( ) const
{
return r ! = nullptr ;
}
bool isWriting ( ) const
{
return w ! = nullptr ;
}
bool canSkip ( ) const ;
template < class T >
FSerializer & operator ( ) ( const char * key , T & obj )
{
return Serialize ( * this , key , obj , ( T * ) nullptr ) ;
}
template < class T >
FSerializer & operator ( ) ( const char * key , T & obj , T & def )
{
2016-09-23 15:49:33 +00:00
return Serialize ( * this , key , obj , save_full ? nullptr : & def ) ;
2016-09-19 08:41:21 +00:00
}
template < class T >
FSerializer & Array ( const char * key , T * obj , int count , bool fullcompare = false )
{
2016-09-23 15:49:33 +00:00
if ( ! save_full & & fullcompare & & isWriting ( ) & & nullcmp ( obj , count * sizeof ( T ) ) )
2016-09-19 08:41:21 +00:00
{
return * this ;
}
if ( BeginArray ( key ) )
{
2016-09-22 09:51:29 +00:00
if ( isReading ( ) )
{
int max = ArraySize ( ) ;
if ( max < count ) count = max ;
}
2016-09-19 08:41:21 +00:00
for ( int i = 0 ; i < count ; i + + )
{
Serialize ( * this , nullptr , obj [ i ] , ( T * ) nullptr ) ;
}
EndArray ( ) ;
}
return * this ;
}
template < class T >
FSerializer & Array ( const char * key , T * obj , T * def , int count , bool fullcompare = false )
{
2016-09-23 15:49:33 +00:00
if ( ! save_full & & fullcompare & & isWriting ( ) & & def ! = nullptr & & ! memcmp ( obj , def , count * sizeof ( T ) ) )
2016-09-19 08:41:21 +00:00
{
return * this ;
}
if ( BeginArray ( key ) )
{
2016-09-22 09:53:09 +00:00
if ( isReading ( ) )
{
int max = ArraySize ( ) ;
if ( max < count ) count = max ;
}
2016-09-19 08:41:21 +00:00
for ( int i = 0 ; i < count ; i + + )
{
Serialize ( * this , nullptr , obj [ i ] , def ? & def [ i ] : nullptr ) ;
}
EndArray ( ) ;
}
return * this ;
}
2016-09-19 17:14:30 +00:00
template < class T >
FSerializer & Enum ( const char * key , T & obj )
{
2016-09-24 07:00:31 +00:00
auto val = ( typename std : : underlying_type < T > : : type ) obj ;
2016-09-19 17:14:30 +00:00
Serialize ( * this , key , val , nullptr ) ;
obj = ( T ) val ;
return * this ;
}
- removed the sequential processing of JSON objects because the benefit is too small.
After testing with a savegame on ZDCMP2 which is probably the largest map in existence, timing both methods resulted in a speed difference of less than 40 ms (70 vs 110 ms for reading all sectory, linedefs, sidedefs and objects).
This compares to an overall restoration time, including reloading the level, precaching all textures and setting everything up, of approx. 1.2 s, meaning an increase of 3% of the entire reloading time.
That's simply not worth all the negative side effects that may happen with a method that highly depends on proper code construction.
On the other hand, using random access means that a savegame version change is only needed now when the semantics of a field change, but not if some get added or deleted.
- do not I_Error out in the serializer unless caused by a programming error.
It is better to let the serializer finish, collect all the errors and I_Error out when the game is known to be in a stable enough state to allow unwinding.
2016-09-23 12:04:05 +00:00
int mErrors = 0 ;
2016-09-19 08:41:21 +00:00
} ;
2020-04-11 10:12:22 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , char & value , char * defval ) ;
2016-09-19 08:41:21 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , bool & value , bool * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int64_t & value , int64_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint64_t & value , uint64_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int32_t & value , int32_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint32_t & value , uint32_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int8_t & value , int8_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint8_t & value , uint8_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , int16_t & value , int16_t * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , uint16_t & value , uint16_t * 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 , FTextureID & value , FTextureID * defval ) ;
2016-09-20 16:27:47 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , DObject * & value , DObject * * /*defval*/ , bool * retcode = nullptr ) ;
2016-09-19 08:41:21 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , FName & value , FName * defval ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , FSoundID & sid , FSoundID * def ) ;
2016-09-19 22:41:22 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , FString & sid , FString * def ) ;
2016-09-20 16:27:47 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , NumericValue & sid , NumericValue * def ) ;
2016-09-20 23:18:29 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , ticcmd_t & sid , ticcmd_t * def ) ;
FSerializer & Serialize ( FSerializer & arc , const char * key , usercmd_t & cmd , usercmd_t * def ) ;
2019-01-28 17:26:14 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , FInterpolator & rs , FInterpolator * def ) ;
2016-09-19 08:41:21 +00:00
template < class T >
FSerializer & Serialize ( FSerializer & arc , const char * key , T * & value , T * * )
{
DObject * v = static_cast < DObject * > ( value ) ;
Serialize ( arc , key , v , nullptr ) ;
value = static_cast < T * > ( v ) ;
return arc ;
}
template < class T >
FSerializer & Serialize ( FSerializer & arc , const char * key , TObjPtr < T > & value , TObjPtr < T > * )
{
Serialize ( arc , key , value . o , nullptr ) ;
return arc ;
}
2017-03-18 12:25:22 +00:00
template < class T >
FSerializer & Serialize ( FSerializer & arc , const char * key , TObjPtr < T > & value , T * )
{
Serialize ( arc , key , value . o , nullptr ) ;
return arc ;
}
2016-09-19 08:41:21 +00:00
template < class T , class TT >
2017-03-18 12:25:22 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , TArray < T , TT > & value , TArray < T , TT > * def )
2016-09-19 08:41:21 +00:00
{
if ( arc . isWriting ( ) )
{
if ( value . Size ( ) = = 0 ) return arc ; // do not save empty arrays
}
bool res = arc . BeginArray ( key ) ;
if ( arc . isReading ( ) )
{
if ( ! res )
{
value . Clear ( ) ;
return arc ;
}
value . Resize ( arc . ArraySize ( ) ) ;
}
for ( unsigned i = 0 ; i < value . Size ( ) ; i + + )
{
2017-03-18 12:25:22 +00:00
Serialize ( arc , nullptr , value [ i ] , def ? & ( * def ) [ i ] : nullptr ) ;
2016-09-19 08:41:21 +00:00
}
arc . EndArray ( ) ;
return arc ;
}
2016-09-19 17:14:30 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , FPolyObj * & value , FPolyObj * * defval ) ;
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , sector_t * & value , sector_t * * defval ) ;
2016-09-20 21:13:12 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , const FPolyObj * & value , const FPolyObj * * defval ) ;
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , const sector_t * & value , const sector_t * * defval ) ;
2016-09-19 17:14:30 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , player_t * & value , player_t * * defval ) ;
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , line_t * & value , line_t * * defval ) ;
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , side_t * & value , side_t * * defval ) ;
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , vertex_t * & value , vertex_t * * defval ) ;
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , PClassActor * & clst , PClassActor * * def ) ;
2016-09-20 16:27:47 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , PClass * & clst , PClass * * def ) ;
2016-09-19 17:14:30 +00:00
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 ) ;
2016-09-19 22:41:22 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , char * & pstr , char * * def ) ;
2016-09-20 11:21:41 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , FFont * & font , FFont * * def ) ;
2019-01-26 20:23:19 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , FLevelLocals * & font , FLevelLocals * * def ) ;
2019-12-29 10:35:06 +00:00
template < > FSerializer & Serialize ( FSerializer & arc , const char * key , Dictionary * & dict , Dictionary * * def ) ;
2016-09-19 17:14:30 +00:00
2016-09-20 16:27:47 +00:00
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 ) ;
}
2016-09-19 17:14:30 +00:00
2016-09-19 08:41:21 +00:00
inline FSerializer & Serialize ( FSerializer & arc , const char * key , DVector3 & p , DVector3 * def )
{
return arc . Array < double > ( key , & p [ 0 ] , def ? & ( * def ) [ 0 ] : nullptr , 3 , true ) ;
}
inline FSerializer & Serialize ( FSerializer & arc , const char * key , DRotator & p , DRotator * def )
{
return arc . Array < DAngle > ( key , & p [ 0 ] , def ? & ( * def ) [ 0 ] : nullptr , 3 , true ) ;
}
inline FSerializer & Serialize ( FSerializer & arc , const char * key , DVector2 & p , DVector2 * def )
{
return arc . Array < double > ( key , & p [ 0 ] , def ? & ( * def ) [ 0 ] : nullptr , 2 , true ) ;
}
inline FSerializer & Serialize ( FSerializer & arc , const char * key , DAngle & p , DAngle * def )
{
return Serialize ( arc , key , p . Degrees , def ? & def - > Degrees : nullptr ) ;
}
inline FSerializer & Serialize ( FSerializer & arc , const char * key , PalEntry & pe , PalEntry * def )
{
return Serialize ( arc , key , pe . d , def ? & def - > d : nullptr ) ;
}
2017-03-10 01:22:42 +00:00
FSerializer & Serialize ( FSerializer & arc , const char * key , FRenderStyle & style , FRenderStyle * def ) ;
2016-09-19 08:41:21 +00:00
template < class T , class TT >
FSerializer & Serialize ( FSerializer & arc , const char * key , TFlags < T , TT > & flags , TFlags < T , TT > * def )
{
return Serialize ( arc , key , flags . Value , def ? & def - > Value : nullptr ) ;
}
2019-12-29 10:35:06 +00:00
FString DictionaryToString ( const Dictionary & dict ) ;
Dictionary * DictionaryFromString ( const FString & string ) ;
2016-09-19 08:41:21 +00:00
2016-09-24 07:00:31 +00:00
# endif