2011-12-14 00:23:17 +03:00
2012-11-20 20:53:45 +03:00
/*
* Connection . 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
2011-12-14 00:23:17 +03:00
2009-04-16 14:14:13 +03:00
# include <typeinfo> //XXX this is in namespace std if you want w/o use typeinfo.h?
2013-02-23 15:22:23 +03:00
# include <type_traits>
2009-04-16 14:14:13 +03:00
2012-04-14 19:28:36 +03:00
# include <boost/variant.hpp>
2009-04-16 14:14:13 +03:00
# include <boost/mpl/eval_if.hpp>
# include <boost/mpl/equal_to.hpp>
# include <boost/mpl/int.hpp>
# include <boost/mpl/identity.hpp>
2013-12-03 12:03:37 +03:00
# include <boost/mpl/for_each.hpp>
2010-06-26 19:02:10 +03:00
# include <boost/any.hpp>
2009-04-16 14:14:13 +03:00
2010-12-17 20:47:07 +02:00
# include "ConstTransitivePtr.h"
2012-04-14 19:28:36 +03:00
# include "CCreatureSet.h" //for CStackInstance
2012-09-18 20:47:52 +03:00
# include "CObjectHandler.h" //for CArmedInstance
2013-04-07 13:48:07 +03:00
# include "mapping/CCampaignHandler.h" //for CCampaignState
2013-04-15 20:18:04 +03:00
# include "rmg/CMapGenerator.h" // for CMapGenOptions
2010-12-17 20:47:07 +02:00
2014-02-19 04:04:27 +03:00
const ui32 version = 745 ;
const ui32 minSupportedVersion = version ;
2012-05-22 02:39:35 +03:00
2009-04-16 14:14:13 +03:00
class CConnection ;
2009-10-06 03:32:33 +03:00
class CGObjectInstance ;
2012-04-14 05:20:22 +03:00
class CStackInstance ;
2009-10-06 03:32:33 +03:00
class CGameState ;
2010-05-02 21:20:26 +03:00
class CCreature ;
2010-06-26 19:02:10 +03:00
class LibClasses ;
class CHero ;
2010-10-31 00:53:41 +03:00
struct CPack ;
2011-12-14 00:23:17 +03:00
extern DLL_LINKAGE LibClasses * VLC ;
2009-04-16 14:14:13 +03:00
namespace mpl = boost : : mpl ;
2013-02-19 01:37:22 +03:00
const std : : string SAVEGAME_MAGIC = " VCMISVG " ;
2009-04-16 14:14:13 +03:00
namespace boost
{
namespace asio
{
namespace ip
{
class tcp ;
}
class io_service ;
template < typename Protocol > class stream_socket_service ;
template < typename Protocol , typename StreamSocketService >
class basic_stream_socket ;
template < typename Protocol > class socket_acceptor_service ;
template < typename Protocol , typename SocketAcceptorService >
class basic_socket_acceptor ;
}
class mutex ;
2012-09-15 22:16:16 +03:00
}
2009-04-16 14:14:13 +03:00
enum SerializationLvl
{
Wrong = 0 ,
2013-02-02 22:28:39 +03:00
Boolean ,
2009-04-16 14:14:13 +03:00
Primitive ,
Array ,
Pointer ,
2013-02-02 01:04:25 +03:00
Enum ,
2013-02-04 19:58:31 +03:00
Serializable ,
BooleanVector
2009-04-16 14:14:13 +03:00
} ;
struct TypeComparer
{
bool operator ( ) ( const std : : type_info * a , const std : : type_info * b ) const
{
return a - > before ( * b ) ;
}
} ;
2014-02-19 04:04:27 +03:00
struct IPointerCaster
{
virtual boost : : any castRawPtr ( const boost : : any & ptr ) const = 0 ; // takes From*, performs dynamic cast, returns To*
virtual boost : : any castSharedPtr ( const boost : : any & ptr ) const = 0 ; // takes std::shared_ptr<From>, performs dynamic cast, returns std::shared_ptr<To>
virtual boost : : any castWeakPtr ( const boost : : any & ptr ) const = 0 ; // takes std::weak_ptr<From>, performs dynamic cast, returns std::weak_ptr<To>. The object under poitner must live.
//virtual boost::any castUniquePtr(const boost::any &ptr) const = 0; // takes std::unique_ptr<From>, performs dynamic cast, returns std::unique_ptr<To>
} ;
template < typename From , typename To >
struct PointerCaster : IPointerCaster
{
virtual boost : : any castRawPtr ( const boost : : any & ptr ) const override // takes void* pointing to From object, performs dynamic cast, returns void* pointing to To object
{
From * from = ( From * ) boost : : any_cast < void * > ( ptr ) ;
To * ret = dynamic_cast < To * > ( from ) ;
return ( void * ) ret ;
}
// Helper function performing casts between smart pointers using dynamic_pointer_cast
template < typename SmartPt >
boost : : any castSmartPtr ( const boost : : any & ptr ) const
{
try
{
auto from = boost : : any_cast < SmartPt > ( ptr ) ;
auto ret = std : : dynamic_pointer_cast < To > ( from ) ;
return ret ;
}
catch ( std : : exception & e )
{
THROW_FORMAT ( " Failed cast %s -> %s. Given argument was %s. Error message: %s " , typeid ( From ) . name ( ) % typeid ( To ) . name ( ) % ptr . type ( ) . name ( ) % e . what ( ) ) ;
}
}
virtual boost : : any castSharedPtr ( const boost : : any & ptr ) const override
{
return castSmartPtr < std : : shared_ptr < From > > ( ptr ) ;
}
virtual boost : : any castWeakPtr ( const boost : : any & ptr ) const override
{
auto from = boost : : any_cast < std : : weak_ptr < From > > ( ptr ) ;
return castSmartPtr < std : : shared_ptr < From > > ( from . lock ( ) ) ;
}
// virtual boost::any castUniquePtr(const boost::any &ptr) const override
// {
// return castSmartPtr<std::unique_ptr<From>>(ptr);
// }
} ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CTypeList
2009-04-16 14:14:13 +03:00
{
public :
2014-02-19 04:04:27 +03:00
struct TypeDescriptor ;
typedef std : : shared_ptr < TypeDescriptor > TypeInfoPtr ;
struct TypeDescriptor
{
ui16 typeID ;
const char * name ;
std : : vector < TypeInfoPtr > children , parents ;
} ;
private :
std : : map < const std : : type_info * , TypeInfoPtr , TypeComparer > typeInfos ;
std : : map < std : : pair < TypeInfoPtr , TypeInfoPtr > , std : : unique_ptr < const IPointerCaster > > casters ; //for each pair <Base, Der> we provide a caster (each registered relations creates a single entry here)
CTypeList ( CTypeList & )
{
// This type is non-copyable.
// Unfortunately on Windows it is required for DLL_EXPORT-ed type to provide copy c-tor, so we can't =delete it.
assert ( 0 ) ;
}
CTypeList & operator = ( CTypeList & )
{
// As above.
assert ( 0 ) ;
return * this ;
}
public :
2009-04-16 14:14:13 +03:00
CTypeList ( ) ;
2014-02-19 04:04:27 +03:00
TypeInfoPtr registerType ( const std : : type_info * type ) ;
template < typename Base , typename Derived >
void registerType ( const Base * b = nullptr , const Derived * d = nullptr )
2009-04-16 14:14:13 +03:00
{
2014-02-19 04:04:27 +03:00
static_assert ( std : : is_base_of < Base , Derived > : : value , " First registerType template parameter needs to ba a base class of the second one. " ) ;
static_assert ( std : : has_virtual_destructor < Base > : : value , " Base class needs to have a virtual destructor. " ) ;
static_assert ( ! std : : is_same < Base , Derived > : : value , " Parameters of registerTypes should be two diffrenet types. " ) ;
auto bt = getTypeInfo ( b ) , dt = getTypeInfo ( d ) ; //obtain std::type_info
auto bti = registerType ( bt ) , dti = registerType ( dt ) ; //obtain our TypeDescriptor
// register the relation between classes
bti - > children . push_back ( dti ) ;
dti - > parents . push_back ( bti ) ;
casters [ std : : make_pair ( bti , dti ) ] = make_unique < const PointerCaster < Base , Derived > > ( ) ;
casters [ std : : make_pair ( dti , bti ) ] = make_unique < const PointerCaster < Derived , Base > > ( ) ;
2009-04-16 14:14:13 +03:00
}
ui16 getTypeID ( const std : : type_info * type ) ;
2014-02-19 04:04:27 +03:00
TypeInfoPtr getTypeDescriptor ( const std : : type_info * type , bool throws = true ) ; //if not throws, failure returns nullptr
template < typename T >
ui16 getTypeID ( const T * t = nullptr )
2009-04-16 14:14:13 +03:00
{
return getTypeID ( getTypeInfo ( t ) ) ;
}
2014-02-19 04:04:27 +03:00
// Returns sequence of types starting from "from" and ending on "to". Every next type is derived from the previous.
// Throws if there is no link registered.
std : : vector < TypeInfoPtr > castSequence ( TypeInfoPtr from , TypeInfoPtr to ) ;
std : : vector < TypeInfoPtr > castSequence ( const std : : type_info * from , const std : : type_info * to ) ;
template < boost : : any ( IPointerCaster : : * CastingFunction ) ( const boost : : any & ) const >
boost : : any castHelper ( boost : : any inputPtr , const std : : type_info * fromArg , const std : : type_info * toArg )
{
auto typesSequence = castSequence ( fromArg , toArg ) ;
boost : : any ptr = inputPtr ;
for ( int i = 0 ; i < ( int ) typesSequence . size ( ) - 1 ; i + + )
{
auto & from = typesSequence [ i ] ;
auto & to = typesSequence [ i + 1 ] ;
auto castingPair = std : : make_pair ( from , to ) ;
if ( ! casters . count ( castingPair ) )
THROW_FORMAT ( " Cannot find caster for conversion %s -> %s which is needed to cast %s -> %s " , from - > name % to - > name % fromArg - > name ( ) % toArg - > name ( ) ) ;
auto & caster = casters . at ( castingPair ) ;
ptr = ( * caster . * CastingFunction ) ( ptr ) ; //Why does unique_ptr does not have operator->* ..?
}
return ptr ;
}
template < typename TInput >
void * castToMostDerived ( const TInput * inputPtr )
{
auto & baseType = typeid ( typename std : : remove_cv < TInput > : : type ) ;
auto derivedType = getTypeInfo ( inputPtr ) ;
if ( baseType = = * derivedType )
return ( void * ) inputPtr ;
return boost : : any_cast < void * > ( castHelper < & IPointerCaster : : castRawPtr > ( ( void * ) inputPtr , & baseType , derivedType ) ) ;
}
template < typename TInput >
boost : : any castSharedToMostDerived ( const std : : shared_ptr < TInput > inputPtr )
{
auto & baseType = typeid ( typename std : : remove_cv < TInput > : : type ) ;
auto derivedType = getTypeInfo ( inputPtr . get ( ) ) ;
if ( baseType = = * derivedType )
return inputPtr ;
return castHelper < & IPointerCaster : : castSharedPtr > ( inputPtr , & baseType , derivedType ) ;
}
void * castRaw ( void * inputPtr , const std : : type_info * from , const std : : type_info * to )
{
return boost : : any_cast < void * > ( castHelper < & IPointerCaster : : castRawPtr > ( inputPtr , from , to ) ) ;
}
boost : : any castShared ( boost : : any inputPtr , const std : : type_info * from , const std : : type_info * to )
{
return castHelper < & IPointerCaster : : castSharedPtr > ( inputPtr , from , to ) ;
}
2009-04-16 14:14:13 +03:00
2013-06-26 14:18:27 +03:00
template < typename T > const std : : type_info * getTypeInfo ( const T * t = nullptr )
2009-04-16 14:14:13 +03:00
{
if ( t )
return & typeid ( * t ) ;
else
return & typeid ( T ) ;
}
} ;
2011-12-14 00:23:17 +03:00
extern DLL_LINKAGE CTypeList typeList ;
2009-04-16 14:14:13 +03:00
2013-02-02 22:28:39 +03:00
template < typename Ser >
struct SaveBoolean
{
static void invoke ( Ser & s , const bool & data )
{
s . saveBoolean ( data ) ;
}
} ;
template < typename Ser >
struct LoadBoolean
{
static void invoke ( Ser & s , bool & data )
{
s . loadBoolean ( data ) ;
}
} ;
2013-02-04 19:58:31 +03:00
template < typename Ser >
struct SaveBooleanVector
{
2013-02-04 22:43:16 +03:00
static void invoke ( Ser & s , const std : : vector < bool > & data )
2013-02-04 19:58:31 +03:00
{
s . saveBooleanVector ( data ) ;
}
} ;
template < typename Ser >
struct LoadBooleanVector
{
2013-02-04 22:43:16 +03:00
static void invoke ( Ser & s , std : : vector < bool > & data )
2013-02-04 19:58:31 +03:00
{
s . loadBooleanVector ( data ) ;
}
} ;
2009-04-16 14:14:13 +03:00
template < typename Ser , typename T >
struct SavePrimitive
{
static void invoke ( Ser & s , const T & data )
{
s . savePrimitive ( data ) ;
}
} ;
template < typename Ser , typename T >
struct SaveSerializable
{
static void invoke ( Ser & s , const T & data )
{
s . saveSerializable ( data ) ;
}
} ;
2013-02-02 01:04:25 +03:00
template < typename Ser , typename T >
struct SaveEnum
{
static void invoke ( Ser & s , const T & data )
{
s . saveEnum ( data ) ;
}
} ;
template < typename Ser , typename T >
struct LoadEnum
{
static void invoke ( Ser & s , T & data )
{
s . loadEnum ( data ) ;
}
} ;
2009-04-16 14:14:13 +03:00
template < typename Ser , typename T >
struct LoadPrimitive
{
static void invoke ( Ser & s , T & data )
{
s . loadPrimitive ( data ) ;
}
} ;
template < typename Ser , typename T >
struct SavePointer
{
static void invoke ( Ser & s , const T & data )
{
s . savePointer ( data ) ;
}
} ;
template < typename Ser , typename T >
struct LoadPointer
{
static void invoke ( Ser & s , T & data )
{
s . loadPointer ( data ) ;
}
} ;
template < typename Ser , typename T >
struct SaveArray
{
static void invoke ( Ser & s , const T & data )
{
s . saveArray ( data ) ;
}
} ;
template < typename Ser , typename T >
struct LoadArray
{
static void invoke ( Ser & s , T & data )
{
s . loadArray ( data ) ;
}
} ;
template < typename Ser , typename T >
struct LoadSerializable
{
static void invoke ( Ser & s , T & data )
{
s . loadSerializable ( data ) ;
}
} ;
template < typename Ser , typename T >
struct SaveWrong
{
static void invoke ( Ser & s , const T & data )
{
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Wrong save serialization call! " ) ;
2009-04-16 14:14:13 +03:00
}
} ;
template < typename Ser , typename T >
struct LoadWrong
{
static void invoke ( Ser & s , const T & data )
{
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Wrong load serialization call! " ) ;
2009-04-16 14:14:13 +03:00
}
} ;
2013-12-03 12:03:37 +03:00
template < typename Variant , typename Source >
struct VariantLoaderHelper
{
Source & source ;
std : : vector < std : : function < Variant ( ) > > funcs ;
VariantLoaderHelper ( Source & source ) :
source ( source )
{
mpl : : for_each < typename Variant : : types > ( std : : ref ( * this ) ) ;
}
template < typename Type >
void operator ( ) ( Type )
{
funcs . push_back ( [ & ] ( ) - > Variant
{
Type obj ;
source > > obj ;
return Variant ( obj ) ;
} ) ;
}
} ;
2009-04-16 14:14:13 +03:00
template < typename T >
struct SerializationLevel
2012-09-15 22:16:16 +03:00
{
2009-04-16 14:14:13 +03:00
typedef mpl : : integral_c_tag tag ;
typedef
2013-02-02 22:28:39 +03:00
typename mpl : : eval_if <
boost : : is_same < T , bool > ,
mpl : : int_ < Boolean > ,
//else
2013-02-04 19:58:31 +03:00
typename mpl : : eval_if <
boost : : is_same < T , std : : vector < bool > > ,
mpl : : int_ < BooleanVector > ,
//else
2009-04-16 14:14:13 +03:00
typename mpl : : eval_if <
boost : : is_fundamental < T > ,
mpl : : int_ < Primitive > ,
//else
2013-02-02 01:04:25 +03:00
typename mpl : : eval_if <
boost : : is_enum < T > ,
mpl : : int_ < Enum > ,
//else
2009-04-16 14:14:13 +03:00
typename mpl : : eval_if <
boost : : is_class < T > ,
mpl : : int_ < Serializable > ,
//else
typename mpl : : eval_if <
boost : : is_array < T > ,
mpl : : int_ < Array > ,
//else
typename mpl : : eval_if <
boost : : is_pointer < T > ,
mpl : : int_ < Pointer > ,
//else
typename mpl : : eval_if <
boost : : is_enum < T > ,
mpl : : int_ < Primitive > ,
//else
mpl : : int_ < Wrong >
>
>
>
>
2013-02-02 01:04:25 +03:00
>
2013-02-02 22:28:39 +03:00
>
2013-02-04 19:58:31 +03:00
>
2009-04-16 14:14:13 +03:00
> : : type type ;
static const int value = SerializationLevel : : type : : value ;
} ;
2013-05-19 01:30:48 +03:00
template < typename ObjType , typename IdType >
2010-06-26 19:02:10 +03:00
struct VectorisedObjectInfo
{
2013-05-19 01:30:48 +03:00
const std : : vector < ConstTransitivePtr < ObjType > > * vector ; //pointer to the appropriate vector
std : : function < IdType ( const ObjType & ) > idRetriever ;
//const IdType ObjType::*idPtr; //pointer to the field representing the position in the vector
2010-06-26 19:02:10 +03:00
2013-05-19 01:30:48 +03:00
VectorisedObjectInfo ( const std : : vector < ConstTransitivePtr < ObjType > > * Vector , std : : function < IdType ( const ObjType & ) > IdGetter )
: vector ( Vector ) , idRetriever ( IdGetter )
2010-06-26 19:02:10 +03:00
{
}
} ;
2013-02-16 22:53:57 +03:00
template < typename T >
si32 idToNumber ( const T & t , typename boost : : enable_if < boost : : is_convertible < T , si32 > > : : type * dummy = 0 )
{
return t ;
}
2013-03-03 20:06:03 +03:00
template < typename T , typename NT >
NT idToNumber ( const BaseForID < T , NT > & t )
2013-02-16 22:53:57 +03:00
{
return t . getNum ( ) ;
}
2011-02-22 13:52:36 +02:00
/// Class which is responsible for storing and loading data.
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CSerializer
2010-06-26 19:02:10 +03:00
{
public :
typedef std : : map < const std : : type_info * , boost : : any , TypeComparer > TTypeVecMap ;
TTypeVecMap vectors ; //entry must be a pointer to vector containing pointers to the objects of key type
bool smartVectorMembersSerialization ;
2012-09-15 22:16:16 +03:00
bool sendStackInstanceByIds ;
2010-06-26 19:02:10 +03:00
CSerializer ( ) ;
~ CSerializer ( ) ;
2013-04-11 18:58:01 +03:00
virtual void reportState ( CLogger * out ) { } ;
2010-07-14 05:53:21 +03:00
2013-02-07 20:34:50 +03:00
template < typename T , typename U >
2013-05-19 01:30:48 +03:00
void registerVectoredType ( const std : : vector < T * > * Vector , const std : : function < U ( const T & ) > & idRetriever )
2010-06-26 19:02:10 +03:00
{
2013-05-19 01:30:48 +03:00
vectors [ & typeid ( T ) ] = VectorisedObjectInfo < T , U > ( Vector , idRetriever ) ;
2010-06-26 19:02:10 +03:00
}
2013-02-07 20:34:50 +03:00
template < typename T , typename U >
2013-05-19 01:30:48 +03:00
void registerVectoredType ( const std : : vector < ConstTransitivePtr < T > > * Vector , const std : : function < U ( const T & ) > & idRetriever )
2010-12-17 20:47:07 +02:00
{
2013-05-19 01:30:48 +03:00
vectors [ & typeid ( T ) ] = VectorisedObjectInfo < T , U > ( Vector , idRetriever ) ;
2010-12-17 20:47:07 +02:00
}
2010-06-26 19:02:10 +03:00
2013-02-07 20:34:50 +03:00
template < typename T , typename U >
const VectorisedObjectInfo < T , U > * getVectorisedTypeInfo ( )
2010-06-26 19:02:10 +03:00
{
2013-06-26 14:18:27 +03:00
const std : : type_info * myType = nullptr ;
2012-09-15 22:16:16 +03:00
//
2010-06-26 19:02:10 +03:00
// if(boost::is_base_of<CGObjectInstance, T>::value) //ugly workaround to support also types derived from CGObjectInstance -> if we encounter one, treat it aas CGObj..
// myType = &typeid(CGObjectInstance);
// else
myType = & typeid ( T ) ;
TTypeVecMap : : iterator i = vectors . find ( myType ) ;
if ( i = = vectors . end ( ) )
2013-06-26 14:18:27 +03:00
return nullptr ;
2010-06-26 19:02:10 +03:00
else
{
assert ( ! i - > second . empty ( ) ) ;
2013-02-07 20:34:50 +03:00
assert ( i - > second . type ( ) = = typeid ( VectorisedObjectInfo < T , U > ) ) ;
VectorisedObjectInfo < T , U > * ret = & ( boost : : any_cast < VectorisedObjectInfo < T , U > & > ( i - > second ) ) ;
2010-06-26 19:02:10 +03:00
return ret ;
}
}
2013-02-07 20:34:50 +03:00
template < typename T , typename U >
T * getVectorItemFromId ( const VectorisedObjectInfo < T , U > & oInfo , U id ) const
2010-06-26 19:02:10 +03:00
{
2010-10-18 18:08:59 +03:00
/* if(id < 0)
2013-06-26 14:18:27 +03:00
return nullptr ; */
2013-02-14 05:17:46 +03:00
si32 idAsNumber = idToNumber ( id ) ;
2010-06-26 19:02:10 +03:00
assert ( oInfo . vector ) ;
2013-02-19 01:37:22 +03:00
assert ( static_cast < si32 > ( oInfo . vector - > size ( ) ) > idAsNumber ) ;
2013-02-14 05:17:46 +03:00
return const_cast < T * > ( ( * oInfo . vector ) [ idAsNumber ] . get ( ) ) ;
2010-06-26 19:02:10 +03:00
}
2013-02-07 20:34:50 +03:00
template < typename T , typename U >
U getIdFromVectorItem ( const VectorisedObjectInfo < T , U > & oInfo , const T * obj ) const
2010-06-26 19:02:10 +03:00
{
if ( ! obj )
2013-02-11 02:24:57 +03:00
return U ( - 1 ) ;
2010-06-26 19:02:10 +03:00
2013-05-19 01:30:48 +03:00
return oInfo . idRetriever ( * obj ) ;
2010-06-26 19:02:10 +03:00
}
void addStdVecItems ( CGameState * gs , LibClasses * lib = VLC ) ;
} ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CSaverBase : public virtual CSerializer
2009-04-16 14:14:13 +03:00
{
} ;
class CBasicPointerSaver
{
public :
virtual void savePtr ( CSaverBase & ar , const void * data ) const = 0 ;
2012-04-08 13:34:23 +03:00
virtual ~ CBasicPointerSaver ( ) { }
2009-04-16 14:14:13 +03:00
} ;
template < typename Serializer , typename T > class CPointerSaver : public CBasicPointerSaver
{
public :
void savePtr ( CSaverBase & ar , const void * data ) const
{
Serializer & s = static_cast < Serializer & > ( ar ) ;
const T * ptr = static_cast < const T * > ( data ) ;
//T is most derived known type, it's time to call actual serialize
const_cast < T & > ( * ptr ) . serialize ( s , version ) ;
}
} ;
2010-06-26 19:02:10 +03:00
template < typename T > //metafunction returning CGObjectInstance if T is its derivate or T elsewise
struct VectorisedTypeFor
{
2012-09-15 22:16:16 +03:00
typedef typename
2010-06-26 19:02:10 +03:00
//if
2013-05-19 01:30:48 +03:00
mpl : : eval_if < boost : : is_same < CGHeroInstance , T > ,
mpl : : identity < CGHeroInstance > ,
//else if
2010-06-26 19:02:10 +03:00
mpl : : eval_if < boost : : is_base_of < CGObjectInstance , T > ,
mpl : : identity < CGObjectInstance > ,
//else
mpl : : identity < T >
2013-05-19 01:30:48 +03:00
> > : : type type ;
2010-06-26 19:02:10 +03:00
} ;
2013-02-07 20:34:50 +03:00
template < typename U >
struct VectorizedIDType
{
typedef typename
//if
mpl : : eval_if < boost : : is_same < CArtifact , U > ,
2013-02-11 02:24:57 +03:00
mpl : : identity < ArtifactID > ,
2013-02-07 23:53:21 +03:00
//else if
mpl : : eval_if < boost : : is_same < CCreature , U > ,
2013-02-11 02:24:57 +03:00
mpl : : identity < CreatureID > ,
2013-02-14 05:17:46 +03:00
//else if
2013-05-19 01:30:48 +03:00
mpl : : eval_if < boost : : is_same < CHero , U > ,
mpl : : identity < HeroTypeID > ,
//else if
2013-02-14 05:17:46 +03:00
mpl : : eval_if < boost : : is_same < CArtifactInstance , U > ,
mpl : : identity < ArtifactInstanceID > ,
//else if
2013-05-19 01:30:48 +03:00
mpl : : eval_if < boost : : is_same < CGHeroInstance , U > ,
mpl : : identity < HeroTypeID > ,
//else if
2013-02-14 05:17:46 +03:00
mpl : : eval_if < boost : : is_base_of < CGObjectInstance , U > ,
mpl : : identity < ObjectInstanceID > ,
2013-02-07 20:34:50 +03:00
//else
mpl : : identity < si32 >
2013-05-19 01:30:48 +03:00
> > > > > > : : type type ;
2013-02-07 20:34:50 +03:00
} ;
2010-06-26 19:02:10 +03:00
2012-04-14 05:20:22 +03:00
template < typename Handler >
struct VariantVisitorSaver : boost : : static_visitor < >
{
Handler & h ;
VariantVisitorSaver ( Handler & H ) : h ( H )
{
}
template < typename T >
void operator ( ) ( const T & t )
{
h < < t ;
}
} ;
template < typename Ser , typename T >
struct SaveIfStackInstance
{
static bool invoke ( Ser & s , const T & data )
{
return false ;
}
} ;
template < typename Ser >
struct SaveIfStackInstance < Ser , CStackInstance * >
{
static bool invoke ( Ser & s , const CStackInstance * const & data )
{
assert ( data - > armyObj ) ;
2013-02-16 17:03:47 +03:00
SlotID slot ;
2012-05-22 02:39:35 +03:00
2013-02-02 22:28:39 +03:00
if ( data - > getNodeType ( ) = = CBonusSystemNode : : COMMANDER )
2013-02-16 17:03:47 +03:00
slot = SlotID : : COMMANDER_SLOT_PLACEHOLDER ;
2012-05-22 02:39:35 +03:00
else
slot = data - > armyObj - > findStack ( data ) ;
2013-02-16 17:03:47 +03:00
assert ( slot ! = SlotID ( ) ) ;
2012-04-14 05:20:22 +03:00
s < < data - > armyObj < < slot ;
return true ;
}
} ;
template < typename Ser , typename T >
struct LoadIfStackInstance
{
static bool invoke ( Ser & s , T & data )
{
return false ;
}
} ;
2012-05-22 02:39:35 +03:00
2012-04-14 05:20:22 +03:00
template < typename Ser >
struct LoadIfStackInstance < Ser , CStackInstance * >
{
static bool invoke ( Ser & s , CStackInstance * & data )
{
CArmedInstance * armedObj ;
2013-02-16 17:03:47 +03:00
SlotID slot ;
2012-04-14 05:20:22 +03:00
s > > armedObj > > slot ;
2013-02-16 17:03:47 +03:00
if ( slot ! = SlotID : : COMMANDER_SLOT_PLACEHOLDER )
2012-05-22 02:39:35 +03:00
{
assert ( armedObj - > hasStackAtSlot ( slot ) ) ;
data = armedObj - > stacks [ slot ] ;
}
else
{
auto hero = dynamic_cast < CGHeroInstance * > ( armedObj ) ;
assert ( hero ) ;
assert ( hero - > commander ) ;
data = hero - > commander ;
}
2012-04-14 05:20:22 +03:00
return true ;
}
} ;
2011-02-22 13:52:36 +02:00
/// The class which manages saving objects.
2011-12-14 00:23:17 +03:00
template < typename Serializer > class DLL_LINKAGE COSer : public CSaverBase
2009-04-16 14:14:13 +03:00
{
public :
bool saving ;
std : : map < ui16 , CBasicPointerSaver * > savers ; // typeID => CPointerSaver<serializer,type>
2009-12-29 03:07:17 +02:00
std : : map < const void * , ui32 > savedPointers ;
bool smartPointerSerialization ;
2009-04-16 14:14:13 +03:00
COSer ( )
{
saving = true ;
2009-12-29 03:07:17 +02:00
smartPointerSerialization = true ;
2009-04-16 14:14:13 +03:00
}
2009-12-31 13:04:29 +02:00
~ COSer ( )
{
std : : map < ui16 , CBasicPointerSaver * > : : iterator iter ;
for ( iter = savers . begin ( ) ; iter ! = savers . end ( ) ; iter + + )
delete iter - > second ;
}
2009-04-16 14:14:13 +03:00
2014-02-19 04:04:27 +03:00
template < typename T >
void addSaver ( const T * t = nullptr )
2009-04-16 14:14:13 +03:00
{
2014-02-19 04:04:27 +03:00
auto ID = typeList . getTypeID ( t ) ;
if ( ! savers . count ( ID ) )
savers [ ID ] = new CPointerSaver < COSer < Serializer > , T > ;
}
template < typename Base , typename Derived > void registerType ( const Base * b = nullptr , const Derived * d = nullptr )
{
typeList . registerType ( b , d ) ;
addSaver ( b ) ;
addSaver ( d ) ;
2009-04-16 14:14:13 +03:00
}
Serializer * This ( )
{
return static_cast < Serializer * > ( this ) ;
}
template < class T >
Serializer & operator < < ( const T & t )
{
this - > This ( ) - > save ( t ) ;
return * this - > This ( ) ;
}
template < class T >
COSer & operator & ( const T & t )
{
return * this - > This ( ) < < t ;
2012-09-15 22:16:16 +03:00
}
2009-04-16 14:14:13 +03:00
int write ( const void * data , unsigned size ) ;
template < typename T >
void savePrimitive ( const T & data )
{
this - > This ( ) - > write ( & data , sizeof ( data ) ) ;
}
template < typename T >
void savePointer ( const T & data )
{
2013-06-26 14:18:27 +03:00
//write if pointer is not nullptr
ui8 hlp = ( data ! = nullptr ) ;
2009-04-16 14:14:13 +03:00
* this < < hlp ;
2013-06-26 14:18:27 +03:00
//if pointer is nullptr then we don't need anything more...
2009-04-16 14:14:13 +03:00
if ( ! hlp )
return ;
2010-06-26 19:02:10 +03:00
if ( smartVectorMembersSerialization )
{
typedef typename boost : : remove_const < typename boost : : remove_pointer < T > : : type > : : type TObjectType ;
typedef typename VectorisedTypeFor < TObjectType > : : type VType ;
2013-02-07 20:34:50 +03:00
typedef typename VectorizedIDType < TObjectType > : : type IDType ;
if ( const auto * info = getVectorisedTypeInfo < VType , IDType > ( ) )
2010-06-26 19:02:10 +03:00
{
2013-02-14 05:17:46 +03:00
IDType id = getIdFromVectorItem < VType > ( * info , data ) ;
2010-12-26 16:34:11 +02:00
* this < < id ;
2013-02-14 05:17:46 +03:00
if ( id ! = IDType ( - 1 ) ) //vector id is enough
2010-12-26 16:34:11 +02:00
return ;
2010-06-26 19:02:10 +03:00
}
}
2012-04-14 05:20:22 +03:00
if ( sendStackInstanceByIds )
{
const bool gotSaved = SaveIfStackInstance < Serializer , T > : : invoke ( * This ( ) , data ) ;
if ( gotSaved )
return ;
}
2010-12-26 16:34:11 +02:00
2009-12-29 03:07:17 +02:00
if ( smartPointerSerialization )
{
2014-02-19 04:04:27 +03: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.
auto actualPointer = typeList . castToMostDerived ( data ) ;
std : : map < const void * , ui32 > : : iterator i = savedPointers . find ( actualPointer ) ;
2009-12-29 03:07:17 +02:00
if ( i ! = savedPointers . end ( ) )
{
//this pointer has been already serialized - write only it's id
* this < < i - > second ;
return ;
}
//give id to this pointer
ui32 pid = ( ui32 ) savedPointers . size ( ) ;
2014-02-19 04:04:27 +03:00
savedPointers [ actualPointer ] = pid ;
2009-12-29 03:07:17 +02:00
* this < < pid ;
}
2009-04-16 14:14:13 +03:00
//write type identifier
ui16 tid = typeList . getTypeID ( data ) ;
* this < < tid ;
2009-10-06 03:32:33 +03:00
This ( ) - > savePointerHlp ( tid , data ) ;
}
//that part of ptr serialization was extracted to allow customization of its behavior in derived classes
template < typename T >
void savePointerHlp ( ui16 tid , const T & data )
2012-09-15 22:16:16 +03:00
{
2009-04-16 14:14:13 +03:00
if ( ! tid )
* this < < * data ; //if type is unregistered simply write all data in a standard way
else
2014-02-19 04:04:27 +03:00
savers [ tid ] - > savePtr ( * this , typeList . castToMostDerived ( data ) ) ; //call serializer specific for our real type
2009-04-16 14:14:13 +03:00
}
template < typename T >
void saveArray ( const T & data )
{
ui32 size = ARRAY_COUNT ( data ) ;
for ( ui32 i = 0 ; i < size ; i + + )
* this < < data [ i ] ;
}
template < typename T >
void save ( const T & data )
{
2012-09-15 22:16:16 +03:00
typedef
2009-04-16 14:14:13 +03:00
//if
2013-02-02 22:28:39 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Boolean > > ,
mpl : : identity < SaveBoolean < Serializer > > ,
//else if
2013-02-04 19:58:31 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < BooleanVector > > ,
mpl : : identity < SaveBooleanVector < Serializer > > ,
//else if
2009-04-16 14:14:13 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Primitive > > ,
mpl : : identity < SavePrimitive < Serializer , T > > ,
//else if
2013-02-02 01:04:25 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Enum > > ,
mpl : : identity < SaveEnum < Serializer , T > > ,
//else if
2009-04-16 14:14:13 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Pointer > > ,
mpl : : identity < SavePointer < Serializer , T > > ,
//else if
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Array > > ,
mpl : : identity < SaveArray < Serializer , T > > ,
//else if
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Serializable > > ,
mpl : : identity < SaveSerializable < Serializer , T > > ,
//else
mpl : : identity < SaveWrong < Serializer , T > >
>
>
>
2013-02-02 01:04:25 +03:00
>
2013-02-02 22:28:39 +03:00
>
2013-02-04 19:58:31 +03:00
>
2009-04-16 14:14:13 +03:00
> : : type typex ;
typex : : invoke ( * this - > This ( ) , data ) ;
}
template < typename T >
void saveSerializable ( const T & data )
{
const_cast < T & > ( data ) . serialize ( * this , version ) ;
}
template < typename T >
2012-03-06 19:59:55 +03:00
void saveSerializable ( const shared_ptr < T > & data )
2010-11-20 02:03:31 +02:00
{
T * internalPtr = data . get ( ) ;
* this < < internalPtr ;
}
template < typename T >
2012-09-21 20:59:54 +03:00
void saveSerializable ( const unique_ptr < T > & data )
{
T * internalPtr = data . get ( ) ;
* this < < internalPtr ;
}
template < typename T >
2009-04-16 14:14:13 +03:00
void saveSerializable ( const std : : vector < T > & data )
{
2011-12-14 00:23:17 +03:00
ui32 length = data . size ( ) ;
2009-04-16 14:14:13 +03:00
* this < < length ;
for ( ui32 i = 0 ; i < length ; i + + )
* this < < data [ i ] ;
}
2013-05-27 13:53:28 +03:00
template < typename T , size_t N >
void saveSerializable ( const std : : array < T , N > & data )
{
for ( ui32 i = 0 ; i < N ; i + + )
* this < < data [ i ] ;
}
2009-04-16 14:14:13 +03:00
template < typename T >
void saveSerializable ( const std : : set < T > & data )
{
std : : set < T > & d = const_cast < std : : set < T > & > ( data ) ;
2011-12-14 00:23:17 +03:00
ui32 length = d . size ( ) ;
2009-04-16 14:14:13 +03:00
* this < < length ;
for ( typename std : : set < T > : : iterator i = d . begin ( ) ; i ! = d . end ( ) ; i + + )
* this < < * i ;
}
2011-01-20 19:25:15 +02:00
template < typename T , typename U >
2013-06-29 16:05:48 +03:00
void saveSerializable ( const std : : unordered_set < T , U > & data )
2011-01-20 19:25:15 +02:00
{
2013-06-29 16:05:48 +03:00
std : : unordered_set < T , U > & d = const_cast < std : : unordered_set < T , U > & > ( data ) ;
2011-12-14 00:23:17 +03:00
ui32 length = d . size ( ) ;
2011-01-20 19:25:15 +02:00
* this < < length ;
2013-06-29 16:05:48 +03:00
for ( typename std : : unordered_set < T , U > : : iterator i = d . begin ( ) ; i ! = d . end ( ) ; i + + )
2011-01-20 19:25:15 +02:00
* this < < * i ;
}
2009-04-16 14:14:13 +03:00
template < typename T >
void saveSerializable ( const std : : list < T > & data )
{
std : : list < T > & d = const_cast < std : : list < T > & > ( data ) ;
2011-12-14 00:23:17 +03:00
ui32 length = d . size ( ) ;
2009-04-16 14:14:13 +03:00
* this < < length ;
for ( typename std : : list < T > : : iterator i = d . begin ( ) ; i ! = d . end ( ) ; i + + )
* this < < * i ;
}
void saveSerializable ( const std : : string & data )
{
* this < < ui32 ( data . length ( ) ) ;
this - > This ( ) - > write ( data . c_str ( ) , data . size ( ) ) ;
}
template < typename T1 , typename T2 >
void saveSerializable ( const std : : pair < T1 , T2 > & data )
{
* this < < data . first < < data . second ;
}
template < typename T1 , typename T2 >
void saveSerializable ( const std : : map < T1 , T2 > & data )
{
* this < < ui32 ( data . size ( ) ) ;
for ( typename std : : map < T1 , T2 > : : const_iterator i = data . begin ( ) ; i ! = data . end ( ) ; i + + )
* this < < i - > first < < i - > second ;
}
2014-02-02 17:31:56 +03:00
template < typename T1 , typename T2 >
void saveSerializable ( const std : : multimap < T1 , T2 > & data )
{
* this < < ui32 ( data . size ( ) ) ;
for ( typename std : : map < T1 , T2 > : : const_iterator i = data . begin ( ) ; i ! = data . end ( ) ; i + + )
* this < < i - > first < < i - > second ;
}
2012-04-14 05:20:22 +03:00
template < BOOST_VARIANT_ENUM_PARAMS ( typename T ) >
void saveSerializable ( const boost : : variant < BOOST_VARIANT_ENUM_PARAMS ( T ) > & data )
{
si32 which = data . which ( ) ;
* this < < which ;
VariantVisitorSaver < Serializer > visitor ( * this - > This ( ) ) ;
boost : : apply_visitor ( visitor , data ) ;
}
2013-02-06 22:48:09 +03:00
template < typename T >
void saveSerializable ( const boost : : optional < T > & data )
{
if ( data )
{
* this < < ( ui8 ) 1 ;
* this < < * data ;
}
else
{
* this < < ( ui8 ) 0 ;
}
}
2013-02-02 01:04:25 +03:00
template < typename E >
void saveEnum ( const E & data )
{
si32 writ = static_cast < si32 > ( data ) ;
* this < < writ ;
}
2013-02-02 22:28:39 +03:00
void saveBoolean ( const bool & data )
{
ui8 writ = static_cast < ui8 > ( data ) ;
* this < < writ ;
}
2013-02-04 19:58:31 +03:00
void saveBooleanVector ( const std : : vector < bool > & data )
{
std : : vector < ui8 > convData ;
2013-02-05 17:32:59 +03:00
std : : copy ( data . begin ( ) , data . end ( ) , std : : back_inserter ( convData ) ) ;
2013-02-04 19:58:31 +03:00
saveSerializable ( convData ) ;
}
2009-04-16 14:14:13 +03:00
} ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CLoaderBase : public virtual CSerializer
2009-04-16 14:14:13 +03:00
{ } ;
class CBasicPointerLoader
{
public :
2014-02-19 10:27:41 +03:00
virtual const std : : type_info * loadPtr ( CLoaderBase & ar , void * data , ui32 pid ) const = 0 ; //data is pointer to the ACTUAL POINTER
2009-12-31 13:04:29 +02:00
virtual ~ CBasicPointerLoader ( ) { }
2009-04-16 14:14:13 +03:00
} ;
2014-02-19 04:04:27 +03:00
template < typename T , typename Enable = void >
struct ClassObjectCreator
{
static T * invoke ( )
{
2014-02-19 10:27:41 +03:00
static_assert ( ! std : : is_abstract < T > : : value , " Cannot call new upon abstract classes! " ) ;
2014-02-19 04:04:27 +03:00
return new T ( ) ;
}
} ;
template < typename T >
struct ClassObjectCreator < T , typename std : : enable_if < std : : is_abstract < T > : : value > : : type >
{
static T * invoke ( )
{
throw std : : runtime_error ( " Something went really wrong during deserialization. Attempted creating an object of an abstract class " + std : : string ( typeid ( T ) . name ( ) ) ) ;
}
} ;
2009-04-16 14:14:13 +03:00
template < typename Serializer , typename T > class CPointerLoader : public CBasicPointerLoader
{
public :
2014-02-19 10:27:41 +03:00
const std : : type_info * loadPtr ( CLoaderBase & ar , void * data , ui32 pid ) const //data is pointer to the ACTUAL POINTER
2009-04-16 14:14:13 +03:00
{
Serializer & s = static_cast < Serializer & > ( ar ) ;
T * & ptr = * static_cast < T * * > ( data ) ;
//create new object under pointer
typedef typename boost : : remove_pointer < T > : : type npT ;
2014-02-19 04:04:27 +03:00
ptr = ClassObjectCreator < npT > : : invoke ( ) ; //does new npT or throws for abstract classes
2010-05-15 05:26:49 +03:00
s . ptrAllocated ( ptr , pid ) ;
2009-04-16 14:14:13 +03:00
//T is most derived known type, it's time to call actual serialize
ptr - > serialize ( s , version ) ;
2014-02-19 04:04:27 +03:00
return & typeid ( T ) ;
2009-04-16 14:14:13 +03:00
}
} ;
2011-02-22 13:52:36 +02:00
/// The class which manages loading of objects.
2011-12-14 00:23:17 +03:00
template < typename Serializer > class DLL_LINKAGE CISer : public CLoaderBase
2009-04-16 14:14:13 +03:00
{
public :
bool saving ;
std : : map < ui16 , CBasicPointerLoader * > loaders ; // typeID => CPointerSaver<serializer,type>
2014-02-19 04:04:27 +03:00
si32 fileVersion ;
2012-06-01 18:59:26 +03:00
bool reverseEndianess ; //if source has different endianess than us, we reverse bytes
2009-04-16 14:14:13 +03:00
2009-12-29 03:07:17 +02:00
std : : map < ui32 , void * > loadedPointers ;
2014-02-19 04:04:27 +03:00
std : : map < ui32 , const std : : type_info * > loadedPointersTypes ;
2013-05-30 13:44:39 +03:00
std : : map < const void * , boost : : any > loadedSharedPointers ;
2009-12-29 03:07:17 +02:00
bool smartPointerSerialization ;
2009-04-16 14:14:13 +03:00
CISer ( )
{
saving = false ;
2012-06-08 03:12:31 +03:00
fileVersion = 0 ;
2009-12-29 03:07:17 +02:00
smartPointerSerialization = true ;
2012-06-01 18:59:26 +03:00
reverseEndianess = false ;
2009-04-16 14:14:13 +03:00
}
2009-10-24 18:54:08 +03:00
~ CISer ( )
{
std : : map < ui16 , CBasicPointerLoader * > : : iterator iter ;
2012-09-15 22:16:16 +03:00
2009-10-24 18:54:08 +03:00
for ( iter = loaders . begin ( ) ; iter ! = loaders . end ( ) ; iter + + )
delete iter - > second ;
}
2014-02-19 04:04:27 +03:00
template < typename T >
void addLoader ( const T * t = nullptr )
2009-04-16 14:14:13 +03:00
{
2014-02-19 04:04:27 +03:00
auto ID = typeList . getTypeID ( t ) ;
if ( ! loaders . count ( ID ) )
loaders [ ID ] = new CPointerLoader < CISer < Serializer > , T > ;
}
template < typename Base , typename Derived > void registerType ( const Base * b = nullptr , const Derived * d = nullptr )
{
typeList . registerType ( b , d ) ;
addLoader ( b ) ;
addLoader ( d ) ;
2009-04-16 14:14:13 +03:00
}
Serializer * This ( )
{
return static_cast < Serializer * > ( this ) ;
}
template < class T >
Serializer & operator > > ( T & t )
{
this - > This ( ) - > load ( t ) ;
return * this - > This ( ) ;
}
2012-09-15 22:16:16 +03:00
2009-04-16 14:14:13 +03:00
template < class T >
CISer & operator & ( T & t )
{
return * this - > This ( ) > > t ;
2012-09-15 22:16:16 +03:00
}
2009-04-16 14:14:13 +03:00
int write ( const void * data , unsigned size ) ;
template < typename T >
void load ( T & data )
{
2012-09-15 22:16:16 +03:00
typedef
2009-04-16 14:14:13 +03:00
//if
2013-02-02 22:28:39 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Boolean > > ,
mpl : : identity < LoadBoolean < Serializer > > ,
//else if
2013-02-04 19:58:31 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < BooleanVector > > ,
mpl : : identity < LoadBooleanVector < Serializer > > ,
//else if
2009-04-16 14:14:13 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Primitive > > ,
mpl : : identity < LoadPrimitive < Serializer , T > > ,
//else if
2013-02-02 01:04:25 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Enum > > ,
mpl : : identity < LoadEnum < Serializer , T > > ,
//else if
2009-04-16 14:14:13 +03:00
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Pointer > > ,
mpl : : identity < LoadPointer < Serializer , T > > ,
//else if
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Array > > ,
mpl : : identity < LoadArray < Serializer , T > > ,
//else if
typename mpl : : eval_if < mpl : : equal_to < SerializationLevel < T > , mpl : : int_ < Serializable > > ,
mpl : : identity < LoadSerializable < Serializer , T > > ,
//else
mpl : : identity < LoadWrong < Serializer , T > >
>
>
>
2013-02-02 01:04:25 +03:00
>
2013-02-02 22:28:39 +03:00
>
2013-02-04 19:58:31 +03:00
>
2009-04-16 14:14:13 +03:00
> : : type typex ;
typex : : invoke ( * this - > This ( ) , data ) ;
}
template < typename T >
void loadPrimitive ( T & data )
{
2012-06-08 03:12:31 +03:00
if ( 0 ) //for testing #989
{
this - > This ( ) - > read ( & data , sizeof ( data ) ) ;
}
else
{
unsigned length = sizeof ( data ) ;
char * dataPtr = ( char * ) & data ;
this - > This ( ) - > read ( dataPtr , length ) ;
if ( reverseEndianess )
std : : reverse ( dataPtr , dataPtr + length ) ;
}
2009-04-16 14:14:13 +03:00
}
2012-04-14 05:20:22 +03:00
2009-04-16 14:14:13 +03:00
template < typename T >
2012-04-14 05:20:22 +03:00
void loadSerializableBySerializeCall ( T & data )
2009-04-16 14:14:13 +03:00
{
2010-01-29 22:52:45 +02:00
////that const cast is evil because it allows to implicitly overwrite const objects when deserializing
typedef typename boost : : remove_const < T > : : type nonConstT ;
nonConstT & hlp = const_cast < nonConstT & > ( data ) ;
2012-06-08 03:12:31 +03:00
hlp . serialize ( * this , fileVersion ) ;
2010-01-29 22:52:45 +02:00
//data.serialize(*this,myVersion);
2012-09-15 22:16:16 +03:00
}
2012-04-14 05:20:22 +03:00
template < typename T >
void loadSerializable ( T & data )
{
loadSerializableBySerializeCall ( data ) ;
}
2009-04-16 14:14:13 +03:00
template < typename T >
void loadArray ( T & data )
{
ui32 size = ARRAY_COUNT ( data ) ;
2011-12-14 00:23:17 +03:00
for ( ui32 i = 0 ; i < size ; i + + )
2009-04-16 14:14:13 +03:00
* this > > data [ i ] ;
}
template < typename T >
void loadPointer ( T & data )
{
ui8 hlp ;
* this > > hlp ;
if ( ! hlp )
{
2013-06-26 14:18:27 +03:00
data = nullptr ;
2009-04-16 14:14:13 +03:00
return ;
}
2012-09-15 22:16:16 +03:00
2010-06-26 19:02:10 +03:00
if ( smartVectorMembersSerialization )
{
typedef typename boost : : remove_const < typename boost : : remove_pointer < T > : : type > : : type TObjectType ; //eg: const CGHeroInstance * => CGHeroInstance
typedef typename VectorisedTypeFor < TObjectType > : : type VType ; //eg: CGHeroInstance -> CGobjectInstance
2013-02-07 20:34:50 +03:00
typedef typename VectorizedIDType < TObjectType > : : type IDType ;
if ( const auto * info = getVectorisedTypeInfo < VType , IDType > ( ) )
2010-06-26 19:02:10 +03:00
{
2013-02-14 05:17:46 +03:00
IDType id ;
2010-06-26 19:02:10 +03:00
* this > > id ;
2013-02-14 05:17:46 +03:00
if ( id ! = IDType ( - 1 ) )
2010-12-26 16:34:11 +02:00
{
2013-02-14 05:17:46 +03:00
data = static_cast < T > ( getVectorItemFromId < VType , IDType > ( * info , id ) ) ;
2010-12-26 16:34:11 +02:00
return ;
}
2010-06-26 19:02:10 +03:00
}
}
2009-04-16 14:14:13 +03:00
2012-04-14 05:20:22 +03:00
if ( sendStackInstanceByIds )
{
bool gotLoaded = LoadIfStackInstance < Serializer , T > : : invoke ( * This ( ) , data ) ;
if ( gotLoaded )
return ;
}
2012-09-15 22:16:16 +03:00
ui32 pid = 0xffffffff ; //pointer id (or maybe rather pointee id)
2009-12-29 03:07:17 +02:00
if ( smartPointerSerialization )
{
* this > > pid ; //get the id
2010-05-15 05:26:49 +03:00
std : : map < ui32 , void * > : : iterator i = loadedPointers . find ( pid ) ; //lookup
2009-12-29 03:07:17 +02:00
if ( i ! = loadedPointers . end ( ) )
{
2014-02-19 04:04:27 +03:00
// We already got this pointer
// Cast it in case we are loading it to a non-first base pointer
assert ( loadedPointersTypes . count ( pid ) ) ;
data = reinterpret_cast < T > ( typeList . castRaw ( i - > second , loadedPointersTypes . at ( pid ) , & typeid ( typename boost : : remove_const < typename boost : : remove_pointer < T > : : type > : : type ) ) ) ;
2009-12-29 03:07:17 +02:00
return ;
}
}
2009-04-16 14:14:13 +03:00
//get type id
ui16 tid ;
* this > > tid ;
2010-05-15 05:26:49 +03:00
This ( ) - > loadPointerHlp ( tid , data , pid ) ;
2009-10-06 03:32:33 +03:00
}
2009-04-16 14:14:13 +03:00
2009-10-06 03:32:33 +03:00
//that part of ptr deserialization was extracted to allow customization of its behavior in derived classes
template < typename T >
2010-05-15 05:26:49 +03:00
void loadPointerHlp ( ui16 tid , T & data , ui32 pid )
2009-10-06 03:32:33 +03:00
{
2009-04-16 14:14:13 +03:00
if ( ! tid )
{
typedef typename boost : : remove_pointer < T > : : type npT ;
2010-01-29 22:52:45 +02:00
typedef typename boost : : remove_const < npT > : : type ncpT ;
2014-02-19 04:04:27 +03:00
data = ClassObjectCreator < ncpT > : : invoke ( ) ;
2010-05-15 05:26:49 +03:00
ptrAllocated ( data , pid ) ;
2009-04-16 14:14:13 +03:00
* this > > * data ;
}
else
{
2014-02-19 04:04:27 +03:00
auto typeInfo = loaders [ tid ] - > loadPtr ( * this , & data , pid ) ;
data = reinterpret_cast < T > ( typeList . castRaw ( ( void * ) data , typeInfo , & typeid ( typename boost : : remove_const < typename boost : : remove_pointer < T > : : type > : : type ) ) ) ;
2009-04-16 14:14:13 +03:00
}
}
2009-10-06 03:32:33 +03:00
2010-05-15 05:26:49 +03:00
template < typename T >
void ptrAllocated ( const T * ptr , ui32 pid )
{
2010-10-18 18:08:59 +03:00
if ( smartPointerSerialization & & pid ! = 0xffffffff )
2014-02-19 04:04:27 +03:00
{
loadedPointersTypes [ pid ] = & typeid ( T ) ;
2010-05-15 05:26:49 +03:00
loadedPointers [ pid ] = ( void * ) ptr ; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt
2014-02-19 04:04:27 +03:00
}
2010-05-15 05:26:49 +03:00
}
2010-07-14 05:53:21 +03:00
# define READ_CHECK_U32(x) \
2011-12-14 00:23:17 +03:00
ui32 length ; \
2010-07-14 05:53:21 +03:00
* this > > length ; \
2012-01-19 17:33:22 +03:00
if ( length > 500000 ) \
2010-07-14 05:53:21 +03:00
{ \
2013-04-09 17:31:36 +03:00
logGlobal - > warnStream ( ) < < " Warning: very big length: " < < length ; \
reportState ( logGlobal ) ; \
2010-07-14 05:53:21 +03:00
} ;
2010-11-20 02:03:31 +02:00
template < typename T >
2012-03-06 19:59:55 +03:00
void loadSerializable ( shared_ptr < T > & data )
2010-11-20 02:03:31 +02:00
{
2014-02-19 04:04:27 +03:00
typedef typename boost : : remove_const < T > : : type NonConstT ;
NonConstT * internalPtr ;
2010-11-20 02:03:31 +02:00
* this > > internalPtr ;
2013-05-30 13:44:39 +03:00
2014-02-19 04:04:27 +03:00
void * internalPtrDerived = typeList . castToMostDerived ( internalPtr ) ;
2013-05-30 13:44:39 +03:00
if ( internalPtr )
{
2014-02-19 04:04:27 +03:00
auto itr = loadedSharedPointers . find ( internalPtrDerived ) ;
2013-05-30 13:44:39 +03:00
if ( itr ! = loadedSharedPointers . end ( ) )
{
// This pointers is already loaded. The "data" needs to be pointed to it,
// so their shared state is actually shared.
try
{
2014-02-19 04:04:27 +03:00
auto actualType = typeList . getTypeInfo ( internalPtr ) ;
auto typeWeNeedToReturn = typeList . getTypeInfo < T > ( ) ;
if ( * actualType = = * typeWeNeedToReturn )
{
// No casting needed, just unpack already stored shared_ptr and return it
data = boost : : any_cast < std : : shared_ptr < T > > ( itr - > second ) ;
}
else
{
// We need to perform series of casts
auto ret = typeList . castShared ( itr - > second , actualType , typeWeNeedToReturn ) ;
data = boost : : any_cast < std : : shared_ptr < T > > ( ret ) ;
}
2013-05-30 13:44:39 +03:00
}
catch ( std : : exception & e )
{
logGlobal - > errorStream ( ) < < e . what ( ) ;
logGlobal - > errorStream ( ) < < boost : : format ( " Failed to cast stored shared ptr. Real type: %s. Needed type %s. FIXME FIXME FIXME " )
% itr - > second . type ( ) . name ( ) % typeid ( std : : shared_ptr < T > ) . name ( ) ;
//TODO scenario with inheritance -> we can have stored ptr to base and load ptr to derived (or vice versa)
assert ( 0 ) ;
}
}
else
{
2014-02-19 04:04:27 +03:00
auto hlp = std : : shared_ptr < NonConstT > ( internalPtr ) ;
data = hlp ; //possibly adds const
loadedSharedPointers [ internalPtrDerived ] = typeList . castSharedToMostDerived ( hlp ) ;
2013-05-30 13:44:39 +03:00
}
}
else
data . reset ( ) ;
2010-11-20 02:03:31 +02:00
}
2009-04-16 14:14:13 +03:00
template < typename T >
2012-09-21 20:59:54 +03:00
void loadSerializable ( unique_ptr < T > & data )
{
T * internalPtr ;
* this > > internalPtr ;
data . reset ( internalPtr ) ;
}
template < typename T >
2009-04-16 14:14:13 +03:00
void loadSerializable ( std : : vector < T > & data )
{
2010-07-14 05:53:21 +03:00
READ_CHECK_U32 ( length ) ;
2009-04-16 14:14:13 +03:00
data . resize ( length ) ;
for ( ui32 i = 0 ; i < length ; i + + )
* this > > data [ i ] ;
}
2013-05-27 13:53:28 +03:00
template < typename T , size_t N >
void loadSerializable ( std : : array < T , N > & data )
{
for ( ui32 i = 0 ; i < N ; i + + )
* this > > data [ i ] ;
}
2009-04-16 14:14:13 +03:00
template < typename T >
void loadSerializable ( std : : set < T > & data )
{
2010-07-14 05:53:21 +03:00
READ_CHECK_U32 ( length ) ;
2013-05-21 22:08:06 +03:00
data . clear ( ) ;
2009-04-16 14:14:13 +03:00
T ins ;
for ( ui32 i = 0 ; i < length ; i + + )
{
* this > > ins ;
data . insert ( ins ) ;
}
}
2011-01-20 19:25:15 +02:00
template < typename T , typename U >
2013-06-29 16:05:48 +03:00
void loadSerializable ( std : : unordered_set < T , U > & data )
2011-01-20 19:25:15 +02:00
{
READ_CHECK_U32 ( length ) ;
2013-05-21 22:08:06 +03:00
data . clear ( ) ;
2011-01-20 19:25:15 +02:00
T ins ;
for ( ui32 i = 0 ; i < length ; i + + )
{
* this > > ins ;
data . insert ( ins ) ;
}
}
2009-04-16 14:14:13 +03:00
template < typename T >
void loadSerializable ( std : : list < T > & data )
{
2010-07-14 05:53:21 +03:00
READ_CHECK_U32 ( length ) ;
2013-05-21 22:08:06 +03:00
data . clear ( ) ;
2009-04-16 14:14:13 +03:00
T ins ;
for ( ui32 i = 0 ; i < length ; i + + )
{
* this > > ins ;
data . push_back ( ins ) ;
}
}
template < typename T1 , typename T2 >
void loadSerializable ( std : : pair < T1 , T2 > & data )
{
* this > > data . first > > data . second ;
}
template < typename T1 , typename T2 >
void loadSerializable ( std : : map < T1 , T2 > & data )
{
2010-07-14 05:53:21 +03:00
READ_CHECK_U32 ( length ) ;
2013-05-21 22:08:06 +03:00
data . clear ( ) ;
2009-04-16 14:14:13 +03:00
T1 t ;
2009-05-07 08:01:45 +03:00
for ( ui32 i = 0 ; i < length ; i + + )
2009-04-16 14:14:13 +03:00
{
* this > > t ;
* this > > data [ t ] ;
}
}
2014-02-02 17:31:56 +03:00
template < typename T1 , typename T2 >
void loadSerializable ( std : : multimap < T1 , T2 > & data )
{
READ_CHECK_U32 ( length ) ;
data . clear ( ) ;
T1 key ;
T2 value ;
for ( ui32 i = 0 ; i < length ; i + + )
{
* this > > key > > value ;
data . insert ( std : : pair < T1 , T2 > ( std : : move ( key ) , std : : move ( value ) ) ) ;
}
}
2009-04-16 14:14:13 +03:00
void loadSerializable ( std : : string & data )
{
2010-07-14 05:53:21 +03:00
READ_CHECK_U32 ( length ) ;
2009-04-16 14:14:13 +03:00
data . resize ( length ) ;
this - > This ( ) - > read ( ( void * ) data . c_str ( ) , length ) ;
}
2013-12-03 12:03:37 +03:00
2012-04-14 05:20:22 +03:00
template < BOOST_VARIANT_ENUM_PARAMS ( typename T ) >
void loadSerializable ( boost : : variant < BOOST_VARIANT_ENUM_PARAMS ( T ) > & data )
{
2013-12-03 12:03:37 +03:00
typedef boost : : variant < BOOST_VARIANT_ENUM_PARAMS ( T ) > TVariant ;
VariantLoaderHelper < TVariant , CISer > loader ( * this ) ;
2012-04-14 05:20:22 +03:00
si32 which ;
* this > > which ;
2013-12-03 12:03:37 +03:00
assert ( which < loader . funcs . size ( ) ) ;
data = loader . funcs . at ( which ) ( ) ;
2012-04-14 05:20:22 +03:00
}
2013-12-03 12:03:37 +03:00
2013-02-06 22:48:09 +03:00
template < typename T >
void loadSerializable ( boost : : optional < T > & data )
{
ui8 present ;
* this > > present ;
if ( present )
{
T t ;
* this > > t ;
data = t ;
}
else
{
data = boost : : optional < T > ( ) ;
}
}
2013-05-09 14:09:23 +03:00
// void loadSerializable(CStackInstance *&s)
// {
// if(sendStackInstanceByIds)
// {
// CArmedInstance *armed;
// SlotID slot;
// *this >> armed >> slot;
// assert(armed->hasStackAtSlot(slot));
// s = armed->stacks[slot];
// }
// else
// loadSerializableBySerializeCall(s);
// }
2009-04-16 14:14:13 +03:00
2013-02-02 01:04:25 +03:00
template < typename E >
void loadEnum ( E & data )
{
si32 read ;
* this > > read ;
data = static_cast < E > ( read ) ;
}
2013-02-02 22:28:39 +03:00
void loadBoolean ( bool & data )
{
ui8 read ;
* this > > read ;
data = static_cast < bool > ( read ) ;
}
2013-02-04 19:58:31 +03:00
void loadBooleanVector ( std : : vector < bool > & data )
{
std : : vector < ui8 > convData ;
loadSerializable ( convData ) ;
2013-09-09 01:45:40 +03:00
convData . resize ( data . size ( ) ) ;
range : : copy ( convData , data . begin ( ) ) ;
2013-02-04 19:58:31 +03:00
}
2009-04-16 14:14:13 +03:00
} ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CSaveFile
2009-04-16 14:14:13 +03:00
: public COSer < CSaveFile >
{
2013-11-03 15:51:25 +03:00
2009-04-16 14:14:13 +03:00
public :
2010-07-14 05:53:21 +03:00
std : : string fName ;
2012-04-08 04:15:18 +03:00
unique_ptr < std : : ofstream > sfile ;
2010-07-14 05:53:21 +03:00
2012-06-09 22:58:17 +03:00
CSaveFile ( const std : : string & fname ) ; //throws!
2009-04-16 14:14:13 +03:00
~ CSaveFile ( ) ;
int write ( const void * data , unsigned size ) ;
2010-02-26 13:18:09 +02:00
2012-06-09 22:58:17 +03:00
void openNextFile ( const std : : string & fname ) ; //throws!
void clear ( ) ;
2013-04-11 18:58:01 +03:00
void reportState ( CLogger * out ) ;
2013-02-19 01:37:22 +03:00
void putMagicBytes ( const std : : string & text ) ;
2009-04-16 14:14:13 +03:00
} ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CLoadFile
2009-04-16 14:14:13 +03:00
: public CISer < CLoadFile >
{
2013-11-03 15:51:25 +03:00
2009-04-16 14:14:13 +03:00
public :
2010-07-14 05:53:21 +03:00
std : : string fName ;
2012-04-08 04:15:18 +03:00
unique_ptr < std : : ifstream > sfile ;
2010-07-14 05:53:21 +03:00
2012-06-08 03:12:31 +03:00
CLoadFile ( const std : : string & fname , int minimalVersion = version ) ; //throws!
2009-04-16 14:14:13 +03:00
~ CLoadFile ( ) ;
2014-02-09 00:54:35 +03:00
int read ( void * data , unsigned size ) ; //throws!
2010-02-26 13:18:09 +02:00
2012-06-08 03:12:31 +03:00
void openNextFile ( const std : : string & fname , int minimalVersion ) ; //throws!
void clear ( ) ;
2013-04-11 18:58:01 +03:00
void reportState ( CLogger * out ) ;
2013-02-19 01:37:22 +03:00
void checkMagicBytes ( const std : : string & text ) ;
} ;
class DLL_LINKAGE CLoadIntegrityValidator : public CISer < CLoadIntegrityValidator >
{
public :
unique_ptr < CLoadFile > primaryFile , controlFile ;
bool foundDesync ;
CLoadIntegrityValidator ( const std : : string & primaryFileName , const std : : string & controlFileName , int minimalVersion = version ) ; //throws!
2014-02-09 00:54:35 +03:00
int read ( void * data , unsigned size ) ; //throws!
2013-02-19 01:37:22 +03:00
void checkMagicBytes ( const std : : string & text ) ;
unique_ptr < CLoadFile > decay ( ) ; //returns primary file. CLoadIntegrityValidator stops being usable anymore
2009-04-16 14:14:13 +03:00
} ;
2010-05-15 05:26:49 +03:00
typedef boost : : asio : : basic_stream_socket < boost : : asio : : ip : : tcp , boost : : asio : : stream_socket_service < boost : : asio : : ip : : tcp > > TSocket ;
typedef boost : : asio : : basic_socket_acceptor < boost : : asio : : ip : : tcp , boost : : asio : : socket_acceptor_service < boost : : asio : : ip : : tcp > > TAcceptor ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CConnection
2014-02-09 00:54:35 +03:00
: public CISer < CConnection > , public COSer < CConnection >
2009-04-16 14:14:13 +03:00
{
2010-06-26 19:02:10 +03:00
//CGameState *gs;
2009-04-16 14:14:13 +03:00
CConnection ( void ) ;
2009-10-06 03:32:33 +03:00
2009-04-16 14:14:13 +03:00
void init ( ) ;
2013-04-11 18:58:01 +03:00
void reportState ( CLogger * out ) ;
2009-04-16 14:14:13 +03:00
public :
boost : : mutex * rmx , * wmx ; // read/write mutexes
2010-05-15 05:26:49 +03:00
TSocket * socket ;
2009-04-16 14:14:13 +03:00
bool logging ;
bool connected ;
2011-09-24 04:15:36 +03:00
bool myEndianess , contactEndianess ; //true if little endian, if endianess is different we'll have to revert received multi-byte vars
2009-04-16 14:14:13 +03:00
boost : : asio : : io_service * io_service ;
std : : string name ; //who uses this connection
2010-10-24 14:35:14 +03:00
int connectionID ;
boost : : thread * handler ;
bool receivedStop , sendStop ;
2010-05-15 05:26:49 +03:00
CConnection ( std : : string host , std : : string port , std : : string Name ) ;
CConnection ( TAcceptor * acceptor , boost : : asio : : io_service * Io_service , std : : string Name ) ;
CConnection ( TSocket * Socket , std : : string Name ) ; //use immediately after accepting connection into socket
2009-04-16 14:14:13 +03:00
int write ( const void * data , unsigned size ) ;
int read ( void * data , unsigned size ) ;
void close ( ) ;
2010-01-29 22:52:45 +02:00
bool isOpen ( ) const ;
2009-04-16 14:14:13 +03:00
template < class T >
CConnection & operator & ( const T & ) ;
2012-04-08 13:34:23 +03:00
virtual ~ CConnection ( void ) ;
2010-09-03 21:42:54 +03:00
CPack * retreivePack ( ) ; //gets from server next pack (allocates it with new)
2013-03-03 20:06:03 +03:00
void sendPackToServer ( const CPack & pack , PlayerColor player , ui32 requestID ) ;
2012-09-25 21:00:55 +03:00
void disableStackSendingByID ( ) ;
void enableStackSendingByID ( ) ;
void disableSmartPointerSerialization ( ) ;
void enableSmartPointerSerializatoin ( ) ;
2013-07-02 19:48:01 +03:00
void disableSmartVectorMemberSerialization ( ) ;
void enableSmartVectorMemberSerializatoin ( ) ;
2013-02-09 21:18:55 +03:00
void prepareForSendingHeroes ( ) ; //disables sending vectorised, enables smart pointer serialization, clears saved/loaded ptr cache
2013-02-14 18:19:35 +03:00
void enterPregameConnectionMode ( ) ;
2010-09-03 21:42:54 +03:00
} ;
2011-12-14 00:23:17 +03:00
DLL_LINKAGE std : : ostream & operator < < ( std : : ostream & str , const CConnection & cpc ) ;
2010-10-24 14:35:14 +03:00
2014-02-09 00:54:35 +03:00
// Serializer that stores objects in the dynamic buffer. Allows performing deep object copies.
class DLL_LINKAGE CMemorySerializer
: public CISer < CMemorySerializer > , public COSer < CMemorySerializer >
{
std : : vector < ui8 > buffer ;
size_t readPos ; //index of the next byte to be read
public :
int read ( void * data , unsigned size ) ; //throws!
int write ( const void * data , unsigned size ) ;
CMemorySerializer ( ) ;
template < typename T >
static unique_ptr < T > deepCopy ( const T & data )
{
CMemorySerializer mem ;
mem < < & data ;
unique_ptr < T > ret ;
mem > > ret ;
return ret ;
}
} ;
2010-09-03 21:42:54 +03:00
template < typename T >
class CApplier
{
public :
2012-09-15 22:16:16 +03:00
std : : map < ui16 , T * > apps ;
2010-09-03 21:42:54 +03:00
~ CApplier ( )
{
2010-09-04 17:47:39 +03:00
typename std : : map < ui16 , T * > : : iterator iter ;
2010-09-03 21:42:54 +03:00
for ( iter = apps . begin ( ) ; iter ! = apps . end ( ) ; iter + + )
delete iter - > second ;
}
2014-02-19 04:04:27 +03:00
template < typename RegisteredType >
void addApplier ( ui16 ID )
{
if ( ! apps . count ( ID ) )
2014-02-19 10:27:41 +03:00
{
RegisteredType * rtype = nullptr ;
apps [ ID ] = T : : getApplier ( rtype ) ;
}
2014-02-19 04:04:27 +03:00
}
template < typename Base , typename Derived >
void registerType ( const Base * b = nullptr , const Derived * d = nullptr )
2010-09-03 21:42:54 +03:00
{
2014-02-19 04:04:27 +03:00
typeList . registerType ( b , d ) ;
addApplier < Base > ( typeList . getTypeID ( b ) ) ;
addApplier < Derived > ( typeList . getTypeID ( d ) ) ;
2010-09-03 21:42:54 +03:00
}
2009-04-16 14:14:13 +03:00
} ;