2016-09-10 02:28:11 +02:00
/*
* BinarySerializer . h , part of VCMI engine
*
* Authors : listed in file AUTHORS in main folder
*
* License : GNU General Public License v2 .0 or later
* Full text of license available in license . txt file , in main folder
*
*/
# pragma once
2023-11-08 22:05:36 +02:00
# include "CSerializer.h"
2016-09-10 02:28:11 +02:00
# include "CTypeList.h"
2024-08-24 00:32:02 +02:00
# include "SerializerReflection.h"
2024-01-20 23:26:04 +02:00
# include "ESerializationVersion.h"
2024-05-07 21:17:05 +02:00
# include "Serializeable.h"
2016-09-10 02:28:11 +02:00
# include "../mapObjects/CArmedInstance.h"
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_BEGIN
2016-09-10 02:28:11 +02:00
class DLL_LINKAGE CSaverBase
{
protected :
IBinaryWriter * writer ;
public :
CSaverBase ( IBinaryWriter * w ) : writer ( w ) { } ;
2024-05-17 18:36:07 +02:00
void write ( const void * data , unsigned size )
2016-09-10 02:28:11 +02:00
{
2024-02-02 02:36:57 +02:00
writer - > write ( reinterpret_cast < const std : : byte * > ( data ) , size ) ;
2016-09-10 02:28:11 +02:00
} ;
} ;
/// Main class for serialization of classes into binary form
/// Behaviour for various classes is following:
/// Primitives: copy memory into underlying stream (defined in CSaverBase)
/// Containers: custom overloaded method that decouples class into primitives
/// VCMI Classes: recursively serialize them via ClassName::serialize( BinarySerializer &, int version) call
2024-05-17 15:09:45 +02:00
class BinarySerializer : public CSaverBase
2016-09-10 02:28:11 +02:00
{
2023-04-16 23:24:11 +02:00
template < typename Handler >
struct VariantVisitorSaver
2016-09-10 02:28:11 +02:00
{
Handler & h ;
VariantVisitorSaver ( Handler & H ) : h ( H )
{
}
template < typename T >
void operator ( ) ( const T & t )
{
h & t ;
}
} ;
2024-07-20 20:29:41 +02:00
template < typename Fake , typename T >
bool saveIfStackInstance ( const T & data )
2016-09-10 02:28:11 +02:00
{
2024-07-20 20:29:41 +02:00
return false ;
}
2016-09-10 02:28:11 +02:00
2024-07-20 20:29:41 +02:00
template < typename Fake >
bool saveIfStackInstance ( const CStackInstance * const & data )
2016-09-10 02:28:11 +02:00
{
2024-07-20 20:29:41 +02:00
assert ( data - > armyObj ) ;
2016-09-10 02:28:11 +02:00
2024-07-20 20:29:41 +02:00
SlotID slot ;
2016-09-10 02:28:11 +02:00
2024-07-20 20:29:41 +02:00
if ( data - > getNodeType ( ) = = CBonusSystemNode : : COMMANDER )
slot = SlotID : : COMMANDER_SLOT_PLACEHOLDER ;
else
slot = data - > armyObj - > findStack ( data ) ;
assert ( slot ! = SlotID ( ) ) ;
save ( data - > armyObj - > id ) ;
save ( slot ) ;
if ( data - > armyObj - > id ! = ObjectInstanceID : : NONE )
2016-09-10 02:28:11 +02:00
return true ;
2024-07-20 20:29:41 +02:00
else
return false ;
}
2016-09-10 02:28:11 +02:00
public :
2024-01-20 20:34:51 +02:00
using Version = ESerializationVersion ;
2024-05-07 16:50:21 +02:00
std : : map < std : : string , uint32_t > savedStrings ;
2024-05-17 18:36:07 +02:00
std : : map < const Serializeable * , uint32_t > savedPointers ;
2016-09-10 02:28:11 +02:00
2024-05-29 22:08:32 +02:00
Version version = Version : : CURRENT ;
2024-07-27 18:51:23 +02:00
static constexpr bool trackSerializedPointers = true ;
static constexpr bool saving = true ;
bool loadingGamestate = false ;
2016-09-10 02:28:11 +02:00
2024-05-17 18:36:07 +02:00
bool hasFeature ( Version what ) const
2024-05-07 16:48:40 +02:00
{
return version > = what ;
} ;
2024-05-17 15:09:45 +02:00
DLL_LINKAGE BinarySerializer ( IBinaryWriter * w ) ;
2016-09-10 02:28:11 +02:00
template < class T >
BinarySerializer & operator & ( const T & t )
{
this - > save ( t ) ;
return * this ;
}
2024-05-16 20:53:49 +02:00
void saveEncodedInteger ( int64_t value )
2024-05-07 17:39:43 +02:00
{
2024-05-16 20:53:49 +02:00
uint64_t valueUnsigned = std : : abs ( value ) ;
2024-05-07 17:39:43 +02:00
while ( valueUnsigned > 0x3f )
{
uint8_t byteValue = ( valueUnsigned & 0x7f ) | 0x80 ;
valueUnsigned = valueUnsigned > > 7 ;
save ( byteValue ) ;
}
uint8_t lastByteValue = valueUnsigned & 0x3f ;
2024-05-16 20:53:49 +02:00
if ( value < 0 )
lastByteValue | = 0x40 ;
2024-05-07 17:39:43 +02:00
save ( lastByteValue ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_same_v < T , bool > , int > = 0 >
2016-09-10 02:28:11 +02:00
void save ( const T & data )
{
2024-05-17 18:36:07 +02:00
uint8_t writ = static_cast < uint8_t > ( data ) ;
2016-09-10 02:28:11 +02:00
save ( writ ) ;
}
2024-05-07 17:39:43 +02:00
template < class T , typename std : : enable_if_t < std : : is_floating_point_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void save ( const T & data )
{
// save primitive - simply dump binary data to output
2024-02-02 02:36:57 +02:00
this - > write ( static_cast < const void * > ( & data ) , sizeof ( data ) ) ;
2016-09-10 02:28:11 +02:00
}
2024-05-07 17:39:43 +02:00
template < class T , typename std : : enable_if_t < std : : is_integral_v < T > & & ! std : : is_same_v < T , bool > , int > = 0 >
void save ( const T & data )
{
if constexpr ( sizeof ( T ) = = 1 )
{
// save primitive - simply dump binary data to output
this - > write ( static_cast < const void * > ( & data ) , sizeof ( data ) ) ;
}
else
{
if ( hasFeature ( Version : : COMPACT_INTEGER_SERIALIZATION ) )
saveEncodedInteger ( data ) ;
else
this - > write ( static_cast < const void * > ( & data ) , sizeof ( data ) ) ;
}
}
void save ( const Version & data )
{
this - > write ( static_cast < const void * > ( & data ) , sizeof ( data ) ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_enum_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void save ( const T & data )
{
2024-05-17 18:36:07 +02:00
int32_t writ = static_cast < int32_t > ( data ) ;
2016-09-10 02:28:11 +02:00
* this & writ ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_array_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void save ( const T & data )
{
2024-05-17 18:36:07 +02:00
uint32_t size = std : : size ( data ) ;
for ( uint32_t i = 0 ; i < size ; i + + )
2016-09-10 02:28:11 +02:00
* this & data [ i ] ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_pointer_v < T > , int > = 0 >
2016-09-10 02:28:11 +02:00
void save ( const T & data )
{
//write if pointer is not nullptr
2023-11-07 17:29:57 +02:00
bool isNull = ( data = = nullptr ) ;
save ( isNull ) ;
2016-09-10 02:28:11 +02:00
//if pointer is nullptr then we don't need anything more...
2023-11-07 17:29:57 +02:00
if ( data = = nullptr )
2016-09-10 02:28:11 +02:00
return ;
2023-11-04 19:25:50 +02:00
savePointerImpl ( data ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < std : : is_base_of_v < Entity , std : : remove_pointer_t < T > > , int > = 0 >
2023-11-04 19:25:50 +02:00
void savePointerImpl ( const T & data )
{
auto index = data - > getId ( ) ;
save ( index ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < ! std : : is_base_of_v < Entity , std : : remove_pointer_t < T > > , int > = 0 >
2023-11-04 19:25:50 +02:00
void savePointerImpl ( const T & data )
{
2024-03-02 13:48:17 +02:00
typedef typename std : : remove_const_t < typename std : : remove_pointer_t < T > > TObjectType ;
2023-11-08 22:05:36 +02:00
2016-09-10 02:28:11 +02:00
if ( writer - > smartVectorMembersSerialization )
{
typedef typename VectorizedTypeFor < TObjectType > : : type VType ;
typedef typename VectorizedIDType < TObjectType > : : type IDType ;
if ( const auto * info = writer - > getVectorizedTypeInfo < VType , IDType > ( ) )
{
IDType id = writer - > getIdFromVectorItem < VType > ( * info , data ) ;
save ( id ) ;
if ( id ! = IDType ( - 1 ) ) //vector id is enough
return ;
}
}
if ( writer - > sendStackInstanceByIds )
{
2024-07-20 20:29:41 +02:00
const bool gotSaved = saveIfStackInstance < void > ( data ) ;
2016-09-10 02:28:11 +02:00
if ( gotSaved )
return ;
}
2024-07-27 18:51:23 +02:00
if ( trackSerializedPointers )
2016-09-10 02:28:11 +02:00
{
// We might have an object that has multiple inheritance and store it via the non-first base pointer.
// Therefore, all pointers need to be normalized to the actual object address.
2024-05-17 18:36:07 +02:00
const auto * actualPointer = static_cast < const Serializeable * > ( data ) ;
2023-04-17 23:11:16 +02:00
auto i = savedPointers . find ( actualPointer ) ;
2016-09-10 02:28:11 +02:00
if ( i ! = savedPointers . end ( ) )
{
//this pointer has been already serialized - write only it's id
save ( i - > second ) ;
return ;
}
//give id to this pointer
2024-05-17 18:36:07 +02:00
uint32_t pid = savedPointers . size ( ) ;
2016-09-10 02:28:11 +02:00
savedPointers [ actualPointer ] = pid ;
save ( pid ) ;
}
//write type identifier
2023-11-08 22:05:36 +02:00
uint16_t tid = CTypeList : : getInstance ( ) . getTypeID ( data ) ;
2016-09-10 02:28:11 +02:00
save ( tid ) ;
if ( ! tid )
save ( * data ) ; //if type is unregistered simply write all data in a standard way
else
2024-08-24 00:32:02 +02:00
CSerializationApplier : : getInstance ( ) . getApplier ( tid ) - > savePtr ( * this , static_cast < const Serializeable * > ( data ) ) ; //call serializer specific for our real type
2016-09-10 02:28:11 +02:00
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < is_serializeable < BinarySerializer , T > : : value , int > = 0 >
2016-09-10 02:28:11 +02:00
void save ( const T & data )
{
2024-01-20 20:34:51 +02:00
const_cast < T & > ( data ) . serialize ( * this ) ;
2016-09-10 02:28:11 +02:00
}
2023-10-21 18:48:07 +02:00
void save ( const std : : monostate & data )
{
// no-op
}
2016-09-10 02:28:11 +02:00
template < typename T >
void save ( const std : : shared_ptr < T > & data )
{
T * internalPtr = data . get ( ) ;
2022-09-11 15:12:35 +02:00
save ( internalPtr ) ;
}
template < typename T >
void save ( const std : : shared_ptr < const T > & data )
{
const T * internalPtr = data . get ( ) ;
2016-09-10 02:28:11 +02:00
save ( internalPtr ) ;
}
template < typename T >
void save ( const std : : unique_ptr < T > & data )
{
T * internalPtr = data . get ( ) ;
save ( internalPtr ) ;
}
2024-03-02 13:48:17 +02:00
template < typename T , typename std : : enable_if_t < ! std : : is_same_v < T , bool > , int > = 0 >
2016-09-10 02:28:11 +02:00
void save ( const std : : vector < T > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = data . size ( ) ;
2016-09-10 02:28:11 +02:00
* this & length ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2016-09-10 02:28:11 +02:00
save ( data [ i ] ) ;
}
2024-03-05 17:59:56 +02:00
template < typename T , typename std : : enable_if_t < ! std : : is_same_v < T , bool > , int > = 0 >
void save ( const std : : deque < T > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = data . size ( ) ;
2024-03-05 17:59:56 +02:00
* this & length ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2024-03-05 17:59:56 +02:00
save ( data [ i ] ) ;
}
2016-09-10 02:28:11 +02:00
template < typename T , size_t N >
void save ( const std : : array < T , N > & data )
{
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < N ; i + + )
2016-09-10 02:28:11 +02:00
save ( data [ i ] ) ;
}
template < typename T >
void save ( const std : : set < T > & data )
{
2023-04-17 23:11:16 +02:00
auto & d = const_cast < std : : set < T > & > ( data ) ;
2024-05-17 18:36:07 +02:00
uint32_t length = d . size ( ) ;
2016-09-10 02:28:11 +02:00
save ( length ) ;
2023-04-17 23:11:16 +02:00
for ( auto i = d . begin ( ) ; i ! = d . end ( ) ; i + + )
2016-09-10 02:28:11 +02:00
save ( * i ) ;
}
template < typename T , typename U >
void save ( const std : : unordered_set < T , U > & data )
{
2023-04-17 23:11:16 +02:00
auto & d = const_cast < std : : unordered_set < T , U > & > ( data ) ;
2024-05-17 18:36:07 +02:00
uint32_t length = d . size ( ) ;
2016-09-10 02:28:11 +02:00
* this & length ;
2023-04-17 23:11:16 +02:00
for ( auto i = d . begin ( ) ; i ! = d . end ( ) ; i + + )
2016-09-10 02:28:11 +02:00
save ( * i ) ;
}
template < typename T >
void save ( const std : : list < T > & data )
{
2023-04-17 23:11:16 +02:00
auto & d = const_cast < std : : list < T > & > ( data ) ;
2024-05-17 18:36:07 +02:00
uint32_t length = d . size ( ) ;
2016-09-10 02:28:11 +02:00
* this & length ;
2023-04-17 23:11:16 +02:00
for ( auto i = d . begin ( ) ; i ! = d . end ( ) ; i + + )
2016-09-10 02:28:11 +02:00
save ( * i ) ;
}
2024-05-07 16:50:21 +02:00
2016-09-10 02:28:11 +02:00
void save ( const std : : string & data )
{
2024-05-07 16:50:21 +02:00
if ( hasFeature ( Version : : COMPACT_STRING_SERIALIZATION ) )
{
if ( data . empty ( ) )
{
2024-05-17 18:36:07 +02:00
save ( static_cast < uint32_t > ( 0 ) ) ;
2024-05-07 16:50:21 +02:00
return ;
}
auto it = savedStrings . find ( data ) ;
if ( it = = savedStrings . end ( ) )
{
2024-05-17 18:36:07 +02:00
save ( static_cast < uint32_t > ( data . length ( ) ) ) ;
2024-05-07 16:50:21 +02:00
this - > write ( static_cast < const void * > ( data . data ( ) ) , data . size ( ) ) ;
// -1, -2...
int32_t newStringID = - 1 - savedStrings . size ( ) ;
savedStrings [ data ] = newStringID ;
}
else
{
int32_t index = it - > second ;
save ( index ) ;
}
}
else
{
2024-05-17 18:36:07 +02:00
save ( static_cast < uint32_t > ( data . length ( ) ) ) ;
2024-05-07 16:50:21 +02:00
this - > write ( static_cast < const void * > ( data . data ( ) ) , data . size ( ) ) ;
}
2016-09-10 02:28:11 +02:00
}
2024-05-07 16:50:21 +02:00
2016-09-10 02:28:11 +02:00
template < typename T1 , typename T2 >
void save ( const std : : pair < T1 , T2 > & data )
{
save ( data . first ) ;
save ( data . second ) ;
}
template < typename T1 , typename T2 >
2024-05-16 21:03:04 +02:00
void save ( const std : : unordered_map < T1 , T2 > & data )
{
2024-05-17 18:36:07 +02:00
* this & static_cast < uint32_t > ( data . size ( ) ) ;
2024-05-16 21:03:04 +02:00
for ( auto i = data . begin ( ) ; i ! = data . end ( ) ; i + + )
{
save ( i - > first ) ;
save ( i - > second ) ;
}
}
template < typename T1 , typename T2 >
2016-09-10 02:28:11 +02:00
void save ( const std : : map < T1 , T2 > & data )
{
2024-05-17 18:36:07 +02:00
* this & static_cast < uint32_t > ( data . size ( ) ) ;
2023-04-17 23:11:16 +02:00
for ( auto i = data . begin ( ) ; i ! = data . end ( ) ; i + + )
2016-09-10 02:28:11 +02:00
{
save ( i - > first ) ;
save ( i - > second ) ;
}
}
template < typename T1 , typename T2 >
void save ( const std : : multimap < T1 , T2 > & data )
{
2024-05-17 18:36:07 +02:00
* this & static_cast < uint32_t > ( data . size ( ) ) ;
2023-04-17 23:11:16 +02:00
for ( auto i = data . begin ( ) ; i ! = data . end ( ) ; i + + )
2016-09-10 02:28:11 +02:00
{
save ( i - > first ) ;
save ( i - > second ) ;
}
}
2023-04-16 23:24:11 +02:00
template < typename T0 , typename . . . TN >
void save ( const std : : variant < T0 , TN . . . > & data )
2016-09-10 02:28:11 +02:00
{
2024-05-17 18:36:07 +02:00
int32_t which = data . index ( ) ;
2016-09-10 02:28:11 +02:00
save ( which ) ;
VariantVisitorSaver < BinarySerializer > visitor ( * this ) ;
2023-04-15 03:33:00 +02:00
std : : visit ( visitor , data ) ;
2016-09-10 02:28:11 +02:00
}
2023-04-16 19:42:56 +02:00
template < typename T >
void save ( const std : : optional < T > & data )
2016-09-10 02:28:11 +02:00
{
if ( data )
{
2024-05-17 18:36:07 +02:00
save ( static_cast < uint8_t > ( 1 ) ) ;
2016-09-10 02:28:11 +02:00
save ( * data ) ;
}
else
{
2024-05-17 18:36:07 +02:00
save ( static_cast < uint32_t > ( 0 ) ) ;
2016-09-10 02:28:11 +02:00
}
}
2022-09-18 16:39:10 +02:00
template < typename T >
void save ( const boost : : multi_array < T , 3 > & data )
{
2024-05-17 18:36:07 +02:00
uint32_t length = data . num_elements ( ) ;
2022-09-18 16:39:10 +02:00
* this & length ;
auto shape = data . shape ( ) ;
2024-05-17 18:36:07 +02:00
uint32_t x = shape [ 0 ] ;
uint32_t y = shape [ 1 ] ;
uint32_t z = shape [ 2 ] ;
2022-09-18 16:39:10 +02:00
* this & x & y & z ;
2024-05-17 18:36:07 +02:00
for ( uint32_t i = 0 ; i < length ; i + + )
2022-09-18 16:39:10 +02:00
save ( data . data ( ) [ i ] ) ;
}
2023-05-05 11:56:11 +02:00
template < std : : size_t T >
void save ( const std : : bitset < T > & data )
{
static_assert ( T < = 64 ) ;
if constexpr ( T < = 16 )
{
auto writ = static_cast < uint16_t > ( data . to_ulong ( ) ) ;
save ( writ ) ;
}
else if constexpr ( T < = 32 )
{
auto writ = static_cast < uint32_t > ( data . to_ulong ( ) ) ;
save ( writ ) ;
}
else if constexpr ( T < = 64 )
{
auto writ = static_cast < uint64_t > ( data . to_ulong ( ) ) ;
save ( writ ) ;
}
}
2016-09-10 02:28:11 +02:00
} ;
2022-07-26 15:07:42 +02:00
VCMI_LIB_NAMESPACE_END