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?
# include <boost/type_traits/is_fundamental.hpp>
# include <boost/type_traits/is_enum.hpp>
2012-09-15 22:16:16 +03:00
# include <boost/type_traits/is_pointer.hpp>
# include <boost/type_traits/is_class.hpp>
2009-10-06 17:02:47 +03:00
# include <boost/type_traits/is_base_of.hpp>
2010-01-29 22:52:45 +02:00
# include <boost/type_traits/is_array.hpp>
# include <boost/type_traits/remove_pointer.hpp>
# include <boost/type_traits/remove_const.hpp>
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>
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-01-03 15:19:20 +03:00
# include "Mapping/CCampaignHandler.h" //for CCampaignState
2010-12-17 20:47:07 +02:00
2013-02-01 11:44:20 +03:00
const ui32 version = 734 ;
2012-05-22 02:39:35 +03:00
const TSlot COMMANDER_SLOT_PLACEHOLDER = - 2 ;
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 ;
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 ,
Primitive ,
Array ,
Pointer ,
2013-02-02 01:04:25 +03:00
Enum ,
2009-04-16 14:14:13 +03:00
Serializable
} ;
struct TypeComparer
{
bool operator ( ) ( const std : : type_info * a , const std : : type_info * b ) const
{
return a - > before ( * b ) ;
}
} ;
2011-12-14 00:23:17 +03:00
class DLL_LINKAGE CTypeList
2009-04-16 14:14:13 +03:00
{
typedef std : : multimap < const std : : type_info * , ui16 , TypeComparer > TTypeMap ;
2010-02-08 16:38:06 +02:00
TTypeMap types ;
2009-04-16 14:14:13 +03:00
public :
CTypeList ( ) ;
ui16 registerType ( const std : : type_info * type ) ;
template < typename T > ui16 registerType ( const T * t = NULL )
{
return registerType ( getTypeInfo ( t ) ) ;
}
ui16 getTypeID ( const std : : type_info * type ) ;
2011-07-17 21:49:05 +03:00
template < typename T > ui16 getTypeID ( const T * t = NULL )
2009-04-16 14:14:13 +03:00
{
return getTypeID ( getTypeInfo ( t ) ) ;
}
template < typename T > const std : : type_info * getTypeInfo ( const T * t = NULL )
{
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
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
}
} ;
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
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
>
2009-04-16 14:14:13 +03:00
> : : type type ;
static const int value = SerializationLevel : : type : : value ;
} ;
2010-06-26 19:02:10 +03:00
template < typename T >
struct VectorisedObjectInfo
{
2010-12-17 20:47:07 +02:00
const std : : vector < ConstTransitivePtr < T > > * vector ; //pointer to the appropriate vector
2010-06-26 19:02:10 +03:00
const si32 T : : * idPtr ; //pointer to the field representing the position in the vector
2010-12-17 20:47:07 +02:00
VectorisedObjectInfo ( const std : : vector < ConstTransitivePtr < T > > * Vector , const si32 T : : * IdPtr )
2010-06-26 19:02:10 +03:00
: vector ( Vector ) , idPtr ( IdPtr )
{
}
} ;
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 ( ) ;
2010-07-14 05:53:21 +03:00
virtual void reportState ( CLogger & out ) { } ;
2010-06-26 19:02:10 +03:00
template < typename T >
void registerVectoredType ( const std : : vector < T * > * Vector , const si32 T : : * IdPtr )
{
vectors [ & typeid ( T ) ] = VectorisedObjectInfo < T > ( Vector , IdPtr ) ;
}
2010-12-17 20:47:07 +02:00
template < typename T >
void registerVectoredType ( const std : : vector < ConstTransitivePtr < T > > * Vector , const si32 T : : * IdPtr )
{
vectors [ & typeid ( T ) ] = VectorisedObjectInfo < T > ( Vector , IdPtr ) ;
}
2010-06-26 19:02:10 +03:00
template < typename T >
const VectorisedObjectInfo < T > * getVectorisedTypeInfo ( )
{
const std : : type_info * myType = NULL ;
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 ( ) )
return NULL ;
else
{
assert ( ! i - > second . empty ( ) ) ;
assert ( i - > second . type ( ) = = typeid ( VectorisedObjectInfo < T > ) ) ;
VectorisedObjectInfo < T > * ret = & ( boost : : any_cast < VectorisedObjectInfo < T > & > ( i - > second ) ) ;
return ret ;
}
}
template < typename T >
2010-10-18 18:08:59 +03:00
T * getVectorItemFromId ( const VectorisedObjectInfo < T > & oInfo , ui32 id ) const
2010-06-26 19:02:10 +03:00
{
2010-10-18 18:08:59 +03:00
/* if(id < 0)
return NULL ; */
2010-06-26 19:02:10 +03:00
assert ( oInfo . vector ) ;
assert ( oInfo . vector - > size ( ) > id ) ;
2010-12-19 00:11:28 +02:00
return const_cast < T * > ( ( * oInfo . vector ) [ id ] . get ( ) ) ;
2010-06-26 19:02:10 +03:00
}
template < typename T >
si32 getIdFromVectorItem ( const VectorisedObjectInfo < T > & oInfo , const T * obj ) const
{
if ( ! obj )
return - 1 ;
return obj - > * oInfo . idPtr ;
}
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
mpl : : eval_if < boost : : is_base_of < CGObjectInstance , T > ,
mpl : : identity < CGObjectInstance > ,
//else
mpl : : identity < T >
> : : type type ;
} ;
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 ) ;
2012-05-22 02:39:35 +03:00
TSlot slot = - 1 ;
if ( data - > getNodeType ( ) = = Bonus : : COMMANDER )
slot = COMMANDER_SLOT_PLACEHOLDER ;
else
slot = data - > armyObj - > findStack ( data ) ;
assert ( slot ! = - 1 ) ;
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 ;
TSlot slot ;
s > > armedObj > > slot ;
2012-05-22 02:39:35 +03:00
if ( slot ! = COMMANDER_SLOT_PLACEHOLDER )
{
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
template < typename T > void registerType ( const T * t = NULL )
{
ui16 ID = typeList . registerType ( t ) ;
savers [ ID ] = new CPointerSaver < COSer < Serializer > , T > ;
}
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 )
{
//write if pointer is not NULL
ui8 hlp = ( data ! = NULL ) ;
* this < < hlp ;
//if pointer is NULL then we don't need anything more...
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 ;
if ( const VectorisedObjectInfo < VType > * info = getVectorisedTypeInfo < VType > ( ) )
{
2010-12-26 16:34:11 +02:00
si32 id = getIdFromVectorItem < VType > ( * info , data ) ;
* this < < id ;
if ( id ! = - 1 ) //vector id is enough
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 )
{
std : : map < const void * , ui32 > : : iterator i = savedPointers . find ( data ) ;
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 ( ) ;
savedPointers [ data ] = pid ;
* 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
savers [ tid ] - > savePtr ( * this , data ) ; //call serializer specific for our real type
}
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
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
>
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 ] ;
}
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 >
void saveSerializable ( const boost : : unordered_set < T , U > & data )
{
boost : : unordered_set < T , U > & d = const_cast < boost : : 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 ;
for ( typename boost : : unordered_set < T , U > : : iterator i = d . begin ( ) ; i ! = d . end ( ) ; i + + )
* 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 ;
}
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-02 01:04:25 +03:00
template < typename E >
void saveEnum ( const E & data )
{
si32 writ = static_cast < si32 > ( data ) ;
* this < < writ ;
}
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 :
2010-05-15 05:26:49 +03:00
virtual void 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
} ;
template < typename Serializer , typename T > class CPointerLoader : public CBasicPointerLoader
{
public :
2010-05-15 05:26:49 +03:00
void 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 ;
ptr = new npT ;
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 ) ;
}
} ;
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>
2012-06-08 03:12:31 +03:00
ui32 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 ;
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 ;
}
2009-04-16 14:14:13 +03:00
template < typename T > void registerType ( const T * t = NULL )
{
ui16 ID = typeList . registerType ( t ) ;
loaders [ ID ] = new CPointerLoader < CISer < Serializer > , T > ;
}
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
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
>
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 )
{
data = NULL ;
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
if ( const VectorisedObjectInfo < VType > * info = getVectorisedTypeInfo < VType > ( ) )
{
2010-12-26 16:34:11 +02:00
si32 id ;
2010-06-26 19:02:10 +03:00
* this > > id ;
2010-12-26 16:34:11 +02:00
if ( id ! = - 1 )
{
data = static_cast < T > ( getVectorItemFromId ( * info , id ) ) ;
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 ( ) )
{
//we already got this pointer
data = static_cast < T > ( i - > second ) ;
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 ;
data = new ncpT ;
2010-05-15 05:26:49 +03:00
ptrAllocated ( data , pid ) ;
2009-04-16 14:14:13 +03:00
* this > > * data ;
}
else
{
2010-05-15 05:26:49 +03:00
loaders [ tid ] - > loadPtr ( * this , & data , pid ) ;
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 )
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
}
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
{ \
tlog2 < < " Warning: very big length: " < < length < < " \n " ; \
reportState ( tlog2 ) ; \
} ;
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
{
T * internalPtr ;
* this > > internalPtr ;
data . reset ( internalPtr ) ;
}
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 ] ;
}
template < typename T >
void loadSerializable ( std : : set < T > & data )
{
2010-07-14 05:53:21 +03:00
READ_CHECK_U32 ( length ) ;
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 >
void loadSerializable ( boost : : unordered_set < T , U > & data )
{
READ_CHECK_U32 ( length ) ;
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 ) ;
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 ) ;
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 ] ;
}
}
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 ) ;
}
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 )
{
si32 which ;
* this > > which ;
if ( which = = 0 )
{
T0 obj ;
* this > > obj ;
data = obj ;
}
else if ( which = = 1 )
{
T1 obj ;
* this > > obj ;
data = obj ;
}
else
assert ( 0 ) ;
//TODO write more if needed, general solution would be much longer
}
void loadSerializable ( CStackInstance * & s )
{
if ( sendStackInstanceByIds )
{
CArmedInstance * armed ;
TSlot 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 ) ;
}
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 >
{
void dummyMagicFunction ( )
{
* this < < std : : string ( " This function makes stuff working. " ) ;
}
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 ( ) ;
2010-07-14 05:53:21 +03:00
void reportState ( CLogger & out ) ;
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 >
{
void dummyMagicFunction ( )
{
std : : string dummy = " This function makes stuff working. " ;
* this > > dummy ;
}
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 ( ) ;
2012-06-09 22:58:17 +03:00
int read ( const 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 ( ) ;
2010-07-14 05:53:21 +03:00
void reportState ( CLogger & out ) ;
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
2009-04-16 14:14:13 +03:00
: public CISer < CConnection > , public COSer < CConnection >
{
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 ( ) ;
2010-07-14 05:53:21 +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)
2012-03-26 01:46:14 +03:00
void sendPackToServer ( const CPack & pack , ui8 player , ui32 requestID ) ;
2012-09-25 21:00:55 +03:00
void disableStackSendingByID ( ) ;
void enableStackSendingByID ( ) ;
void disableSmartPointerSerialization ( ) ;
void enableSmartPointerSerializatoin ( ) ;
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
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 ;
}
template < typename U > void registerType ( const U * t = NULL )
{
ui16 ID = typeList . registerType ( t ) ;
apps [ ID ] = T : : getApplier ( t ) ;
}
2009-04-16 14:14:13 +03:00
} ;