2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2008-07-03 18:03:32 +03:00
# include "Connection.h"
2009-10-06 03:32:33 +03:00
2014-02-24 22:57:33 +03:00
# include "registerTypes/RegisterTypes.h"
2015-12-02 21:05:10 +02:00
# include "mapping/CMap.h"
2015-12-02 21:39:53 +02:00
# include "CGameState.h"
2016-01-16 17:36:16 +02:00
# include "filesystem/FileStream.h"
2009-10-06 03:32:33 +03:00
2011-12-14 00:23:17 +03:00
# include <boost/asio.hpp>
2009-10-06 03:32:33 +03:00
2009-04-15 17:03:31 +03:00
/*
* Connection . cpp , 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
*
*/
2014-12-21 16:27:50 +02:00
extern template void registerTypes < CISer > ( CISer & s ) ;
extern template void registerTypes < COSer > ( COSer & s ) ;
2013-02-23 15:22:23 +03:00
extern template void registerTypes < CTypeList > ( CTypeList & s ) ;
2008-07-03 18:03:32 +03:00
2009-03-07 00:11:17 +02:00
CTypeList typeList ;
2008-07-03 18:03:32 +03:00
# define LOG(a) \
if ( logging ) \
out < < a
# if defined(__hppa__) || \
defined ( __m68k__ ) | | defined ( mc68000 ) | | defined ( _M_M68K ) | | \
( defined ( __MIPS__ ) & & defined ( __MISPEB__ ) ) | | \
defined ( __ppc__ ) | | defined ( __POWERPC__ ) | | defined ( _M_PPC ) | | \
defined ( __sparc__ )
# define BIG_ENDIAN
# else
# define LIL_ENDIAN
# endif
2014-02-09 00:54:35 +03:00
2008-07-09 20:22:28 +03:00
void CConnection : : init ( )
2008-07-03 18:03:32 +03:00
{
2014-09-21 16:43:25 +03:00
boost : : asio : : ip : : tcp : : no_delay option ( true ) ;
socket - > set_option ( option ) ;
2012-09-25 21:00:55 +03:00
enableSmartPointerSerializatoin ( ) ;
disableStackSendingByID ( ) ;
2014-12-21 16:27:50 +02:00
registerTypes ( iser ) ;
registerTypes ( oser ) ;
2008-07-03 18:03:32 +03:00
# ifdef LIL_ENDIAN
myEndianess = true ;
# else
myEndianess = false ;
# endif
2008-07-09 20:22:28 +03:00
connected = true ;
std : : string pom ;
//we got connection
2014-12-21 16:27:50 +02:00
oser < < std : : string ( " Aiya! \n " ) < < name < < myEndianess ; //identify ourselves
iser > > pom > > pom > > contactEndianess ;
2016-03-12 03:41:27 +02:00
logNetwork - > infoStream ( ) < < " Established connection with " < < pom ;
2008-07-26 16:57:32 +03:00
wmx = new boost : : mutex ;
rmx = new boost : : mutex ;
2010-10-24 14:35:14 +03:00
2013-06-26 14:18:27 +03:00
handler = nullptr ;
2010-10-24 14:35:14 +03:00
receivedStop = sendStop = false ;
static int cid = 1 ;
connectionID = cid + + ;
2008-07-09 20:22:28 +03:00
}
2009-01-11 00:08:18 +02:00
CConnection : : CConnection ( std : : string host , std : : string port , std : : string Name )
2015-12-29 01:14:08 +02:00
: iser ( this ) , oser ( this ) , io_service ( new boost : : asio : : io_service ) , name ( Name )
2008-07-09 20:22:28 +03:00
{
2008-09-10 00:10:24 +03:00
int i ;
2015-12-29 01:14:08 +02:00
boost : : system : : error_code error = boost : : asio : : error : : host_not_found ;
socket = new boost : : asio : : ip : : tcp : : socket ( * io_service ) ;
boost : : asio : : ip : : tcp : : resolver resolver ( * io_service ) ;
boost : : asio : : ip : : tcp : : resolver : : iterator end , pom , endpoint_iterator = resolver . resolve ( boost : : asio : : ip : : tcp : : resolver : : query ( host , port ) , error ) ;
2008-09-07 06:38:37 +03:00
if ( error )
{
2016-03-12 03:41:27 +02:00
logNetwork - > errorStream ( ) < < " Problem with resolving: \n " < < error ;
2008-09-07 06:38:37 +03:00
goto connerror1 ;
}
pom = endpoint_iterator ;
if ( pom ! = end )
2016-03-12 03:41:27 +02:00
logNetwork - > infoStream ( ) < < " Found endpoints: " ;
2008-09-07 06:38:37 +03:00
else
{
2016-03-12 03:41:27 +02:00
logNetwork - > errorStream ( ) < < " Critical problem: No endpoints found! " ;
2008-09-07 06:38:37 +03:00
goto connerror1 ;
}
2008-09-10 00:10:24 +03:00
i = 0 ;
2008-09-07 06:38:37 +03:00
while ( pom ! = end )
{
2016-03-12 03:41:27 +02:00
logNetwork - > infoStream ( ) < < " \t " < < i < < " : " < < ( boost : : asio : : ip : : tcp : : endpoint & ) * pom ;
2008-09-07 06:38:37 +03:00
pom + + ;
}
2008-09-09 10:05:02 +03:00
i = 0 ;
2008-09-07 06:38:37 +03:00
while ( endpoint_iterator ! = end )
{
2016-03-12 03:41:27 +02:00
logNetwork - > infoStream ( ) < < " Trying connection to " < < ( boost : : asio : : ip : : tcp : : endpoint & ) * endpoint_iterator < < " ( " < < i + + < < " ) " ;
2008-09-07 06:38:37 +03:00
socket - > connect ( * endpoint_iterator , error ) ;
if ( ! error )
{
init ( ) ;
return ;
}
else
{
2016-03-12 03:41:27 +02:00
logNetwork - > errorStream ( ) < < " Problem with connecting: " < < error ;
2008-09-07 06:38:37 +03:00
}
2008-09-09 10:05:02 +03:00
endpoint_iterator + + ;
2008-09-07 06:38:37 +03:00
}
//we shouldn't be here - error handling
connerror1 :
2016-08-12 11:10:27 +02:00
logNetwork - > error ( " Something went wrong... checking for error info " ) ;
2008-09-07 06:38:37 +03:00
if ( error )
2016-03-12 03:41:27 +02:00
logNetwork - > errorStream ( ) < < error ;
2008-09-07 06:38:37 +03:00
else
2016-08-12 11:10:27 +02:00
logNetwork - > error ( " No error info. " ) ;
2008-09-07 06:38:37 +03:00
delete io_service ;
2015-10-25 12:04:21 +02:00
//delete socket;
2012-04-22 10:32:45 +03:00
throw std : : runtime_error ( " Can't establish connection :( " ) ;
2008-07-03 18:03:32 +03:00
}
2010-05-15 05:26:49 +03:00
CConnection : : CConnection ( TSocket * Socket , std : : string Name )
2014-12-21 16:27:50 +02:00
: iser ( this ) , oser ( this ) , socket ( Socket ) , io_service ( & Socket - > get_io_service ( ) ) , name ( Name ) //, send(this), rec(this)
2008-07-03 18:03:32 +03:00
{
2008-07-09 20:22:28 +03:00
init ( ) ;
}
2010-05-15 05:26:49 +03:00
CConnection : : CConnection ( TAcceptor * acceptor , boost : : asio : : io_service * Io_service , std : : string Name )
2014-12-21 16:27:50 +02:00
: iser ( this ) , oser ( this ) , name ( Name ) //, send(this), rec(this)
2008-07-09 20:22:28 +03:00
{
2015-12-29 01:14:08 +02:00
boost : : system : : error_code error = boost : : asio : : error : : host_not_found ;
socket = new boost : : asio : : ip : : tcp : : socket ( * io_service ) ;
2008-07-09 20:22:28 +03:00
acceptor - > accept ( * socket , error ) ;
2008-09-09 10:05:02 +03:00
if ( error )
2015-10-25 12:04:21 +02:00
{
2016-03-12 03:41:27 +02:00
logNetwork - > errorStream ( ) < < " Error on accepting: " < < error ;
2015-10-25 12:04:21 +02:00
delete socket ;
throw std : : runtime_error ( " Can't establish connection :( " ) ;
2008-09-09 10:05:02 +03:00
}
2008-07-09 20:22:28 +03:00
init ( ) ;
2008-07-03 18:03:32 +03:00
}
int CConnection : : write ( const void * data , unsigned size )
{
2008-09-17 13:18:22 +03:00
//LOG("Sending " << size << " byte(s) of data" <<std::endl);
2010-01-29 22:52:45 +02:00
try
{
int ret ;
2015-12-29 01:14:08 +02:00
ret = boost : : asio : : write ( * socket , boost : : asio : : const_buffers_1 ( boost : : asio : : const_buffer ( data , size ) ) ) ;
2010-01-29 22:52:45 +02:00
return ret ;
}
catch ( . . . )
{
//connection has been lost
connected = false ;
throw ;
}
2008-07-03 18:03:32 +03:00
}
int CConnection : : read ( void * data , unsigned size )
{
2008-09-17 13:18:22 +03:00
//LOG("Receiving " << size << " byte(s) of data" <<std::endl);
2010-01-29 22:52:45 +02:00
try
{
2015-12-29 01:14:08 +02:00
int ret = boost : : asio : : read ( * socket , boost : : asio : : mutable_buffers_1 ( boost : : asio : : mutable_buffer ( data , size ) ) ) ;
2010-01-29 22:52:45 +02:00
return ret ;
}
catch ( . . . )
{
//connection has been lost
connected = false ;
throw ;
}
2008-07-03 18:03:32 +03:00
}
CConnection : : ~ CConnection ( void )
{
2010-10-24 14:35:14 +03:00
if ( handler )
handler - > join ( ) ;
delete handler ;
2008-08-25 13:25:16 +03:00
close ( ) ;
2010-01-29 22:52:45 +02:00
delete io_service ;
delete wmx ;
delete rmx ;
2008-07-03 18:03:32 +03:00
}
2008-08-04 12:05:52 +03:00
2009-03-16 00:57:04 +02:00
template < class T >
CConnection & CConnection : : operator & ( const T & t ) {
2013-06-29 16:05:48 +03:00
// throw std::exception();
2009-03-16 00:57:04 +02:00
//XXX this is temporaly ? solution to fix gcc (4.3.3, other?) compilation
// problem for more details contact t0@czlug.icis.pcz.pl or impono@gmail.com
// do not remove this exception it shoudnt be called
2012-11-20 20:53:45 +03:00
return * this ;
2009-03-16 00:57:04 +02:00
}
2008-08-25 13:25:16 +03:00
void CConnection : : close ( )
{
if ( socket )
{
socket - > close ( ) ;
delete socket ;
2013-06-26 14:18:27 +03:00
socket = nullptr ;
2008-08-25 13:25:16 +03:00
}
}
2008-11-16 03:06:15 +02:00
2010-01-29 22:52:45 +02:00
bool CConnection : : isOpen ( ) const
{
return socket & & connected ;
}
2013-04-11 18:58:01 +03:00
void CConnection : : reportState ( CLogger * out )
2010-07-14 05:53:21 +03:00
{
2016-03-12 03:41:27 +02:00
out - > debugStream ( ) < < " CConnection " ;
2010-07-14 05:53:21 +03:00
if ( socket & & socket - > is_open ( ) )
{
2016-03-12 03:41:27 +02:00
out - > debugStream ( ) < < " \t We have an open and valid socket " ;
out - > debugStream ( ) < < " \t " < < socket - > available ( ) < < " bytes awaiting " ;
2010-07-14 05:53:21 +03:00
}
}
2010-09-03 21:42:54 +03:00
CPack * CConnection : : retreivePack ( )
{
2013-06-26 14:18:27 +03:00
CPack * ret = nullptr ;
2010-09-03 21:42:54 +03:00
boost : : unique_lock < boost : : mutex > lock ( * rmx ) ;
2016-03-12 03:41:27 +02:00
logNetwork - > traceStream ( ) < < " Listening... " ;
2014-12-21 16:27:50 +02:00
iser > > ret ;
2013-12-08 20:54:13 +03:00
logNetwork - > traceStream ( ) < < " \t received server message of type " < < typeid ( * ret ) . name ( ) < < " , data: " < < ret ;
2010-09-03 21:42:54 +03:00
return ret ;
}
2013-03-03 20:06:03 +03:00
void CConnection : : sendPackToServer ( const CPack & pack , PlayerColor player , ui32 requestID )
2011-08-25 18:24:37 +03:00
{
boost : : unique_lock < boost : : mutex > lock ( * wmx ) ;
2016-03-12 03:41:27 +02:00
logNetwork - > traceStream ( ) < < " Sending to server a pack of type " < < typeid ( pack ) . name ( ) ;
2014-12-21 16:27:50 +02:00
oser < < player < < requestID < < & pack ; //packs has to be sent as polymorphic pointers!
2011-08-25 18:24:37 +03:00
}
2012-09-25 21:00:55 +03:00
void CConnection : : disableStackSendingByID ( )
{
2015-10-25 12:04:21 +02:00
CSerializer : : sendStackInstanceByIds = false ;
2012-09-25 21:00:55 +03:00
}
void CConnection : : enableStackSendingByID ( )
{
2015-10-25 12:04:21 +02:00
CSerializer : : sendStackInstanceByIds = true ;
2012-09-25 21:00:55 +03:00
}
void CConnection : : disableSmartPointerSerialization ( )
{
2014-12-21 18:25:12 +02:00
iser . smartPointerSerialization = oser . smartPointerSerialization = false ;
2012-09-25 21:00:55 +03:00
}
void CConnection : : enableSmartPointerSerializatoin ( )
{
2014-12-21 18:25:12 +02:00
iser . smartPointerSerialization = oser . smartPointerSerialization = true ;
2012-09-25 21:00:55 +03:00
}
2013-02-09 21:18:55 +03:00
void CConnection : : prepareForSendingHeroes ( )
{
2014-12-21 16:27:50 +02:00
iser . loadedPointers . clear ( ) ;
oser . savedPointers . clear ( ) ;
2013-07-02 19:48:01 +03:00
disableSmartVectorMemberSerialization ( ) ;
2013-02-14 18:19:35 +03:00
enableSmartPointerSerializatoin ( ) ;
2013-12-20 16:07:58 +03:00
disableStackSendingByID ( ) ;
2013-02-14 18:19:35 +03:00
}
void CConnection : : enterPregameConnectionMode ( )
{
2014-12-21 16:27:50 +02:00
iser . loadedPointers . clear ( ) ;
oser . savedPointers . clear ( ) ;
2013-07-02 19:48:01 +03:00
disableSmartVectorMemberSerialization ( ) ;
2013-02-14 18:19:35 +03:00
disableSmartPointerSerialization ( ) ;
2013-02-09 21:18:55 +03:00
}
2013-07-02 19:48:01 +03:00
void CConnection : : disableSmartVectorMemberSerialization ( )
{
2014-12-21 18:25:12 +02:00
CSerializer : : smartVectorMembersSerialization = false ;
2013-07-02 19:48:01 +03:00
}
void CConnection : : enableSmartVectorMemberSerializatoin ( )
{
2014-12-21 18:25:12 +02:00
CSerializer : : smartVectorMembersSerialization = true ;
2013-07-02 19:48:01 +03:00
}
2016-01-16 17:36:16 +02:00
CSaveFile : : CSaveFile ( const boost : : filesystem : : path & fname ) : serializer ( this )
2008-08-04 12:05:52 +03:00
{
2014-12-21 16:27:50 +02:00
registerTypes ( serializer ) ;
2010-02-26 13:18:09 +02:00
openNextFile ( fname ) ;
}
CSaveFile : : ~ CSaveFile ( )
{
}
int CSaveFile : : write ( const void * data , unsigned size )
{
sfile - > write ( ( char * ) data , size ) ;
return size ;
}
2016-01-16 17:36:16 +02:00
void CSaveFile : : openNextFile ( const boost : : filesystem : : path & fname )
2010-02-26 13:18:09 +02:00
{
2010-07-14 05:53:21 +03:00
fName = fname ;
2012-06-09 22:58:17 +03:00
try
2009-06-02 01:31:11 +03:00
{
2016-01-16 17:36:16 +02:00
sfile = make_unique < FileStream > ( fname , std : : ios : : out | std : : ios : : binary ) ;
2012-06-09 22:58:17 +03:00
sfile - > exceptions ( std : : ifstream : : failbit | std : : ifstream : : badbit ) ; //we throw a lot anyway
if ( ! ( * sfile ) )
THROW_FORMAT ( " Error: cannot open to write %s! " , fname ) ;
2009-06-02 01:31:11 +03:00
sfile - > write ( " VCMI " , 4 ) ; //write magic identifier
2014-12-21 16:27:50 +02:00
serializer < < version ; //write format version
2009-06-02 01:31:11 +03:00
}
2012-06-09 22:58:17 +03:00
catch ( . . . )
{
2016-03-12 03:41:27 +02:00
logGlobal - > errorStream ( ) < < " Failed to save to " < < fname ;
2012-06-09 22:58:17 +03:00
clear ( ) ;
throw ;
}
2008-08-04 12:05:52 +03:00
}
2013-04-11 18:58:01 +03:00
void CSaveFile : : reportState ( CLogger * out )
2010-07-14 05:53:21 +03:00
{
2016-03-12 03:41:27 +02:00
out - > debugStream ( ) < < " CSaveFile " ;
2012-04-08 04:15:18 +03:00
if ( sfile . get ( ) & & * sfile )
2010-07-14 05:53:21 +03:00
{
2016-03-12 03:41:27 +02:00
out - > debugStream ( ) < < " \t Opened " < < fName < < " \n \t Position: " < < sfile - > tellp ( ) ;
2010-07-14 05:53:21 +03:00
}
}
2012-06-09 22:58:17 +03:00
void CSaveFile : : clear ( )
{
fName . clear ( ) ;
sfile = nullptr ;
}
2013-02-19 01:37:22 +03:00
void CSaveFile : : putMagicBytes ( const std : : string & text )
{
write ( text . c_str ( ) , text . length ( ) ) ;
}
2014-12-21 16:27:50 +02:00
CLoadFile : : CLoadFile ( const boost : : filesystem : : path & fname , int minimalVersion /*= version*/ ) : serializer ( this )
2010-02-26 13:18:09 +02:00
{
2014-12-21 16:27:50 +02:00
registerTypes ( serializer ) ;
2010-10-24 14:35:14 +03:00
openNextFile ( fname , minimalVersion ) ;
2010-02-26 13:18:09 +02:00
}
CLoadFile : : ~ CLoadFile ( )
2008-08-04 12:05:52 +03:00
{
}
2008-11-16 03:06:15 +02:00
2014-02-09 00:54:35 +03:00
int CLoadFile : : read ( void * data , unsigned size )
2008-11-16 03:06:15 +02:00
{
2014-02-09 00:54:35 +03:00
sfile - > read ( ( char * ) data , size ) ;
2008-11-16 03:06:15 +02:00
return size ;
2009-01-06 20:42:20 +02:00
}
2014-08-27 13:31:58 +03:00
void CLoadFile : : openNextFile ( const boost : : filesystem : : path & fname , int minimalVersion )
2010-02-26 13:18:09 +02:00
{
2014-12-21 16:27:50 +02:00
assert ( ! serializer . reverseEndianess ) ;
2012-06-08 03:12:31 +03:00
assert ( minimalVersion < = version ) ;
try
2009-06-02 01:31:11 +03:00
{
2014-08-27 13:31:58 +03:00
fName = fname . string ( ) ;
2016-01-16 17:36:16 +02:00
sfile = make_unique < FileStream > ( fname , std : : ios : : in | std : : ios : : binary ) ;
2012-06-08 03:12:31 +03:00
sfile - > exceptions ( std : : ifstream : : failbit | std : : ifstream : : badbit ) ; //we throw a lot anyway
if ( ! ( * sfile ) )
2014-08-27 13:31:58 +03:00
THROW_FORMAT ( " Error: cannot open to read %s! " , fName ) ;
2012-06-08 03:12:31 +03:00
//we can read
2009-06-02 01:31:11 +03:00
char buffer [ 4 ] ;
sfile - > read ( buffer , 4 ) ;
if ( std : : memcmp ( buffer , " VCMI " , 4 ) )
2014-08-27 13:31:58 +03:00
THROW_FORMAT ( " Error: not a VCMI file(%s)! " , fName ) ;
2009-06-02 01:31:11 +03:00
2015-10-25 12:04:21 +02:00
serializer > > serializer . fileVersion ;
2014-12-21 16:27:50 +02:00
if ( serializer . fileVersion < minimalVersion )
2014-08-27 13:31:58 +03:00
THROW_FORMAT ( " Error: too old file format (%s)! " , fName ) ;
2012-06-08 03:12:31 +03:00
2014-12-21 16:27:50 +02:00
if ( serializer . fileVersion > version )
2012-04-17 15:46:21 +03:00
{
2014-12-21 16:27:50 +02:00
logGlobal - > warnStream ( ) < < boost : : format ( " Warning format version mismatch: found %d when current is %d! (file %s) \n " ) % serializer . fileVersion % version % fName ;
2012-06-08 03:12:31 +03:00
2014-12-21 16:27:50 +02:00
auto versionptr = ( char * ) & serializer . fileVersion ;
2012-06-01 18:59:26 +03:00
std : : reverse ( versionptr , versionptr + 4 ) ;
2014-12-21 16:27:50 +02:00
logGlobal - > warnStream ( ) < < " Version number reversed is " < < serializer . fileVersion < < " , checking... " ;
2012-06-08 03:12:31 +03:00
2014-12-21 16:27:50 +02:00
if ( serializer . fileVersion = = version )
2012-06-01 18:59:26 +03:00
{
2014-03-20 21:17:40 +03:00
logGlobal - > warnStream ( ) < < fname < < " seems to have different endianness! Entering reversing mode. " ;
2014-12-21 16:27:50 +02:00
serializer . reverseEndianess = true ;
2012-06-01 18:59:26 +03:00
}
else
2014-08-27 13:31:58 +03:00
THROW_FORMAT ( " Error: too new file format (%s)! " , fName ) ;
2009-06-02 01:31:11 +03:00
}
}
2012-06-08 03:12:31 +03:00
catch ( . . . )
{
clear ( ) ; //if anything went wrong, we delete file and rethrow
throw ;
}
2009-01-06 20:42:20 +02:00
}
2013-04-11 18:58:01 +03:00
void CLoadFile : : reportState ( CLogger * out )
2010-07-14 05:53:21 +03:00
{
2016-03-12 03:41:27 +02:00
out - > debugStream ( ) < < " CLoadFile " ;
2012-04-08 04:15:18 +03:00
if ( ! ! sfile & & * sfile )
2010-07-14 05:53:21 +03:00
{
2016-03-12 03:41:27 +02:00
out - > debugStream ( ) < < " \t Opened " < < fName < < " \n \t Position: " < < sfile - > tellg ( ) ;
2010-07-14 05:53:21 +03:00
}
}
2012-06-08 03:12:31 +03:00
void CLoadFile : : clear ( )
{
sfile = nullptr ;
fName . clear ( ) ;
2014-12-21 16:27:50 +02:00
serializer . fileVersion = 0 ;
2012-06-08 03:12:31 +03:00
}
2013-02-19 01:37:22 +03:00
void CLoadFile : : checkMagicBytes ( const std : : string & text )
{
std : : string loaded = text ;
2014-02-09 00:54:35 +03:00
read ( ( void * ) loaded . data ( ) , text . length ( ) ) ;
2013-02-19 01:37:22 +03:00
if ( loaded ! = text )
throw std : : runtime_error ( " Magic bytes doesn't match! " ) ;
}
2009-03-07 00:11:17 +02:00
CTypeList : : CTypeList ( )
{
2009-03-12 01:25:59 +02:00
registerTypes ( * this ) ;
2009-03-07 00:11:17 +02:00
}
2014-02-19 04:04:27 +03:00
CTypeList : : TypeInfoPtr CTypeList : : registerType ( const std : : type_info * type )
2015-12-29 01:14:08 +02:00
{
2014-02-19 04:04:27 +03:00
if ( auto typeDescr = getTypeDescriptor ( type , false ) )
return typeDescr ; //type found, return ptr to structure
2009-03-07 00:11:17 +02:00
2009-03-07 17:54:12 +02:00
//type not found - add it to the list and return given ID
2015-12-29 04:43:33 +02:00
auto newType = std : : make_shared < TypeDescriptor > ( ) ;
2014-02-19 04:04:27 +03:00
newType - > typeID = typeInfos . size ( ) + 1 ;
newType - > name = type - > name ( ) ;
typeInfos [ type ] = newType ;
return newType ;
2009-03-07 00:11:17 +02:00
}
2015-10-25 12:04:21 +02:00
ui16 CTypeList : : getTypeID ( const std : : type_info * type , bool throws ) const
2015-12-29 01:14:08 +02:00
{
2015-10-25 12:04:21 +02:00
auto descriptor = getTypeDescriptor ( type , throws ) ;
if ( descriptor = = nullptr )
{
2009-03-07 00:11:17 +02:00
return 0 ;
2015-10-25 12:04:21 +02:00
}
return descriptor - > typeID ;
2009-10-04 05:02:45 +03:00
}
2010-06-26 19:02:10 +03:00
2015-10-25 00:38:30 +02:00
std : : vector < CTypeList : : TypeInfoPtr > CTypeList : : castSequence ( TypeInfoPtr from , TypeInfoPtr to ) const
2014-02-19 04:04:27 +03:00
{
2015-10-27 08:09:42 +02:00
if ( ! strcmp ( from - > name , to - > name ) )
2014-02-19 04:04:27 +03:00
return std : : vector < CTypeList : : TypeInfoPtr > ( ) ;
// Perform a simple BFS in the class hierarchy.
auto BFS = [ & ] ( bool upcast )
{
std : : map < TypeInfoPtr , TypeInfoPtr > previous ;
std : : queue < TypeInfoPtr > q ;
q . push ( to ) ;
while ( q . size ( ) )
{
auto typeNode = q . front ( ) ;
q . pop ( ) ;
2016-08-30 08:47:33 +02:00
for ( auto & weakNode : ( upcast ? typeNode - > parents : typeNode - > children ) )
2014-02-19 04:04:27 +03:00
{
2016-08-30 08:47:33 +02:00
auto nodeBase = weakNode . lock ( ) ;
2014-02-19 04:04:27 +03:00
if ( ! previous . count ( nodeBase ) )
{
previous [ nodeBase ] = typeNode ;
q . push ( nodeBase ) ;
}
}
}
2015-10-25 12:04:21 +02:00
2014-02-19 04:04:27 +03:00
std : : vector < TypeInfoPtr > ret ;
if ( ! previous . count ( from ) )
return ret ;
ret . push_back ( from ) ;
TypeInfoPtr ptr = from ;
do
{
ptr = previous . at ( ptr ) ;
ret . push_back ( ptr ) ;
} while ( ptr ! = to ) ;
return ret ;
} ;
// Try looking both up and down.
auto ret = BFS ( true ) ;
if ( ret . empty ( ) )
ret = BFS ( false ) ;
if ( ret . empty ( ) )
THROW_FORMAT ( " Cannot find relation between types %s and %s. Were they (and all classes between them) properly registered? " , from - > name % to - > name ) ;
return ret ;
}
2015-10-25 00:38:30 +02:00
std : : vector < CTypeList : : TypeInfoPtr > CTypeList : : castSequence ( const std : : type_info * from , const std : : type_info * to ) const
2014-02-19 04:04:27 +03:00
{
//This additional if is needed because getTypeDescriptor might fail if type is not registered
// (and if casting is not needed, then registereing should no be required)
2015-10-27 08:09:42 +02:00
if ( ! strcmp ( from - > name ( ) , to - > name ( ) ) )
2014-02-19 04:04:27 +03:00
return std : : vector < CTypeList : : TypeInfoPtr > ( ) ;
return castSequence ( getTypeDescriptor ( from ) , getTypeDescriptor ( to ) ) ;
}
2015-10-25 00:38:30 +02:00
CTypeList : : TypeInfoPtr CTypeList : : getTypeDescriptor ( const std : : type_info * type , bool throws ) const
2014-02-19 04:04:27 +03:00
{
auto i = typeInfos . find ( type ) ;
if ( i ! = typeInfos . end ( ) )
2015-10-25 12:04:21 +02:00
return i - > second ; //type found, return ptr to structure
2014-02-19 04:04:27 +03:00
if ( ! throws )
return nullptr ;
THROW_FORMAT ( " Cannot find type descriptor for type %s. Was it registered? " , type - > name ( ) ) ;
}
2010-10-24 14:35:14 +03:00
std : : ostream & operator < < ( std : : ostream & str , const CConnection & cpc )
{
return str < < " Connection with " < < cpc . name < < " (ID: " < < cpc . connectionID < < /*", " << (cpc.host ? "host" : "guest") <<*/ " ) " ;
}
2010-06-26 19:02:10 +03:00
CSerializer : : ~ CSerializer ( )
{
}
CSerializer : : CSerializer ( )
{
smartVectorMembersSerialization = false ;
2012-04-14 05:20:22 +03:00
sendStackInstanceByIds = false ;
2010-06-26 19:02:10 +03:00
}
void CSerializer : : addStdVecItems ( CGameState * gs , LibClasses * lib )
{
2015-10-25 12:04:21 +02:00
registerVectoredType < CGObjectInstance , ObjectInstanceID > ( & gs - > map - > objects ,
2013-05-19 01:30:48 +03:00
[ ] ( const CGObjectInstance & obj ) { return obj . id ; } ) ;
2015-10-25 12:04:21 +02:00
registerVectoredType < CHero , HeroTypeID > ( & lib - > heroh - > heroes ,
2013-05-19 01:30:48 +03:00
[ ] ( const CHero & h ) { return h . ID ; } ) ;
registerVectoredType < CGHeroInstance , HeroTypeID > ( & gs - > map - > allHeroes ,
[ ] ( const CGHeroInstance & h ) { return h . type - > ID ; } ) ;
2015-10-25 12:04:21 +02:00
registerVectoredType < CCreature , CreatureID > ( & lib - > creh - > creatures ,
2013-05-19 01:30:48 +03:00
[ ] ( const CCreature & cre ) { return cre . idNumber ; } ) ;
registerVectoredType < CArtifact , ArtifactID > ( & lib - > arth - > artifacts ,
[ ] ( const CArtifact & art ) { return art . id ; } ) ;
2015-10-25 12:04:21 +02:00
registerVectoredType < CArtifactInstance , ArtifactInstanceID > ( & gs - > map - > artInstances ,
2013-05-19 01:30:48 +03:00
[ ] ( const CArtifactInstance & artInst ) { return artInst . id ; } ) ;
2015-10-25 12:04:21 +02:00
registerVectoredType < CQuest , si32 > ( & gs - > map - > quests ,
2013-05-19 01:30:48 +03:00
[ ] ( const CQuest & q ) { return q . qid ; } ) ;
2010-06-26 19:02:10 +03:00
smartVectorMembersSerialization = true ;
2010-08-21 03:37:19 +03:00
}
2013-02-19 01:37:22 +03:00
2016-01-16 17:36:16 +02:00
CLoadIntegrityValidator : : CLoadIntegrityValidator ( const boost : : filesystem : : path & primaryFileName , const boost : : filesystem : : path & controlFileName , int minimalVersion /*= version*/ )
2014-12-21 16:27:50 +02:00
: serializer ( this ) , foundDesync ( false )
2013-02-19 01:37:22 +03:00
{
2014-12-21 16:27:50 +02:00
registerTypes ( serializer ) ;
2013-02-19 01:37:22 +03:00
primaryFile = make_unique < CLoadFile > ( primaryFileName , minimalVersion ) ;
controlFile = make_unique < CLoadFile > ( controlFileName , minimalVersion ) ;
2014-02-02 17:54:12 +03:00
2014-12-21 16:27:50 +02:00
assert ( primaryFile - > serializer . fileVersion = = controlFile - > serializer . fileVersion ) ;
serializer . fileVersion = primaryFile - > serializer . fileVersion ;
2013-02-19 01:37:22 +03:00
}
2014-02-09 00:54:35 +03:00
int CLoadIntegrityValidator : : read ( void * data , unsigned size )
2013-02-19 01:37:22 +03:00
{
assert ( primaryFile ) ;
assert ( controlFile ) ;
if ( ! size )
return size ;
std : : vector < ui8 > controlData ( size ) ;
auto ret = primaryFile - > read ( data , size ) ;
2013-02-19 15:24:17 +03:00
if ( ! foundDesync )
2013-02-19 01:37:22 +03:00
{
2013-02-19 15:24:17 +03:00
controlFile - > read ( controlData . data ( ) , size ) ;
if ( std : : memcmp ( data , controlData . data ( ) , size ) )
{
2016-03-12 03:41:27 +02:00
logGlobal - > errorStream ( ) < < " Desync found! Position: " < < primaryFile - > sfile - > tellg ( ) ;
2013-02-19 15:24:17 +03:00
foundDesync = true ;
//throw std::runtime_error("Savegame dsynchronized!");
}
2013-02-19 01:37:22 +03:00
}
return ret ;
}
2015-12-29 04:43:33 +02:00
std : : unique_ptr < CLoadFile > CLoadIntegrityValidator : : decay ( )
2013-02-19 01:37:22 +03:00
{
2014-12-21 16:27:50 +02:00
primaryFile - > serializer . loadedPointers = this - > serializer . loadedPointers ;
primaryFile - > serializer . loadedPointersTypes = this - > serializer . loadedPointersTypes ;
2013-02-19 01:37:22 +03:00
return std : : move ( primaryFile ) ;
}
void CLoadIntegrityValidator : : checkMagicBytes ( const std : : string & text )
{
assert ( primaryFile ) ;
assert ( controlFile ) ;
primaryFile - > checkMagicBytes ( text ) ;
controlFile - > checkMagicBytes ( text ) ;
}
2014-02-09 00:54:35 +03:00
int CMemorySerializer : : read ( void * data , unsigned size )
{
if ( buffer . size ( ) < readPos + size )
throw std : : runtime_error ( boost : : str ( boost : : format ( " Cannot read past the buffer (accessing index %d, while size is %d)! " ) % ( readPos + size - 1 ) % buffer . size ( ) ) ) ;
std : : memcpy ( data , buffer . data ( ) + readPos , size ) ;
readPos + = size ;
return size ;
}
int CMemorySerializer : : write ( const void * data , unsigned size )
{
auto oldSize = buffer . size ( ) ; //and the pos to write from
buffer . resize ( oldSize + size ) ;
std : : memcpy ( buffer . data ( ) + oldSize , data , size ) ;
return size ;
}
2014-12-21 16:27:50 +02:00
CMemorySerializer : : CMemorySerializer ( ) : iser ( this ) , oser ( this )
2014-02-09 00:54:35 +03:00
{
readPos = 0 ;
2014-12-21 16:27:50 +02:00
registerTypes ( iser ) ;
registerTypes ( oser ) ;
2014-02-09 00:54:35 +03:00
}