2008-07-25 20:28:28 +03:00
# include "../CCallback.h"
# include "../CConsoleHandler.h"
2008-11-09 00:29:19 +02:00
# include "../CGameInfo.h"
# include "../CGameState.h"
# include "../CPlayerInterface.h"
# include "../StartInfo.h"
# include "../hch/CArtHandler.h"
2009-01-11 00:08:18 +02:00
# include "../hch/CDefObjInfoHandler.h"
2008-11-09 00:29:19 +02:00
# include "../hch/CGeneralTextHandler.h"
2009-01-11 00:08:18 +02:00
# include "../hch/CHeroHandler.h"
# include "../hch/CTownHandler.h"
2008-11-09 00:29:19 +02:00
# include "../hch/CObjectHandler.h"
2009-01-11 00:08:18 +02:00
# include "../hch/CBuildingHandler.h"
# include "../hch/CSpellHandler.h"
2008-11-09 00:29:19 +02:00
# include "../lib/Connection.h"
2009-01-11 00:08:18 +02:00
# include "../lib/Interprocess.h"
2008-07-26 16:57:32 +03:00
# include "../lib/NetPacks.h"
2008-11-09 00:29:19 +02:00
# include "../lib/VCMI_Lib.h"
# include "../map.h"
# include "../mapHandler.h"
# include "CConfigHandler.h"
# include "Client.h"
2008-07-27 20:07:37 +03:00
# include <boost/bind.hpp>
2008-08-01 14:21:15 +03:00
# include <boost/foreach.hpp>
2008-11-09 00:29:19 +02:00
# include <boost/thread.hpp>
2008-07-30 20:51:19 +03:00
# include <boost/thread/shared_mutex.hpp>
2008-12-27 03:01:59 +02:00
# include <sstream>
2009-03-07 00:25:19 +02:00
# undef DLL_EXPORT
# define DLL_EXPORT
2009-03-15 14:53:58 +02:00
# include "../lib/RegisterTypes.cpp"
2009-01-11 00:08:18 +02:00
extern std : : string NAME ;
namespace intpr = boost : : interprocess ;
2008-07-28 15:44:08 +03:00
2009-03-07 00:25:19 +02:00
class CBaseForCLApply
{
public :
virtual void applyOnClAfter ( CClient * cl , void * pack ) const = 0 ;
virtual void applyOnClBefore ( CClient * cl , void * pack ) const = 0 ;
} ;
template < typename T > class CApplyOnCL : public CBaseForCLApply
{
public :
void applyOnClAfter ( CClient * cl , void * pack ) const
{
T * ptr = static_cast < T * > ( pack ) ;
ptr - > applyCl ( cl ) ;
}
void applyOnClBefore ( CClient * cl , void * pack ) const
{
T * ptr = static_cast < T * > ( pack ) ;
ptr - > applyFirstCl ( cl ) ;
}
} ;
class CCLApplier
{
public :
std : : map < ui16 , CBaseForCLApply * > apps ;
CCLApplier ( )
{
registerTypes2 ( * this ) ;
}
template < typename T > void registerType ( const T * t = NULL )
{
2009-03-07 17:54:12 +02:00
ui16 ID = typeList . registerType ( t ) ;
2009-03-07 00:25:19 +02:00
apps [ ID ] = new CApplyOnCL < T > ;
}
2009-03-07 17:54:12 +02:00
} * applier = NULL ;
2009-03-07 00:25:19 +02:00
2009-01-30 23:28:02 +02:00
void CClient : : init ( )
2008-07-25 20:28:28 +03:00
{
2009-03-07 17:54:12 +02:00
applier = new CCLApplier ;
2009-02-01 16:11:41 +02:00
IObjectInterface : : cb = this ;
2009-01-11 00:08:18 +02:00
serv = NULL ;
gs = NULL ;
cb = NULL ;
2009-01-31 00:23:13 +02:00
try
{
shared = new SharedMem ( ) ;
} HANDLE_EXCEPTION
2009-01-30 23:28:02 +02:00
}
CClient : : CClient ( void )
{
init ( ) ;
2008-07-25 20:28:28 +03:00
}
CClient : : CClient ( CConnection * con , StartInfo * si )
2009-01-11 00:08:18 +02:00
{
2009-01-30 23:28:02 +02:00
init ( ) ;
2009-01-11 00:08:18 +02:00
newGame ( con , si ) ;
2008-07-25 20:28:28 +03:00
}
CClient : : ~ CClient ( void )
{
2009-03-07 17:54:12 +02:00
delete applier ;
2009-01-30 23:28:02 +02:00
delete shared ;
2008-07-25 20:28:28 +03:00
}
2008-08-04 18:56:36 +03:00
void CClient : : waitForMoveAndSend ( int color )
{
2008-08-30 00:41:32 +03:00
try
{
BattleAction ba = playerint [ color ] - > activeStack ( gs - > curB - > activeStack ) ;
2009-03-09 21:40:43 +02:00
* serv < < & MakeAction ( ba ) ;
2008-08-30 00:41:32 +03:00
return ;
} HANDLE_EXCEPTION
2008-09-19 11:16:19 +03:00
tlog1 < < " We should not be here! " < < std : : endl ;
2008-08-04 18:56:36 +03:00
}
2008-07-25 20:28:28 +03:00
void CClient : : run ( )
{
2009-03-07 00:25:19 +02:00
CPack * pack ;
2009-03-07 17:54:12 +02:00
while ( 1 )
2008-07-25 20:28:28 +03:00
{
2009-03-19 16:17:19 +02:00
tlog5 < < " Listening... " ;
2009-03-07 00:25:19 +02:00
* serv > > pack ;
2009-03-19 16:17:19 +02:00
tlog5 < < " \t received server message of type " < < typeid ( * pack ) . name ( ) < < std : : endl ;
2009-03-07 17:54:12 +02:00
CBaseForCLApply * apply = applier - > apps [ typeList . getTypeID ( pack ) ] ;
if ( apply )
{
apply - > applyOnClBefore ( this , pack ) ;
2009-03-19 16:17:19 +02:00
tlog5 < < " \t Made first apply on cl \n " ;
2009-03-07 17:54:12 +02:00
gs - > apply ( pack ) ;
2009-03-19 16:17:19 +02:00
tlog5 < < " \t Applied on gs \n " ;
2009-03-07 17:54:12 +02:00
apply - > applyOnClAfter ( this , pack ) ;
2009-03-19 16:17:19 +02:00
tlog5 < < " \t Made second apply on cl \n " ;
2009-03-07 17:54:12 +02:00
}
else
{
2009-03-09 21:40:43 +02:00
tlog5 < < " Message cannot be applied, cannot find applier! \n " ;
2009-03-07 17:54:12 +02:00
}
2009-03-07 00:25:19 +02:00
delete pack ;
pack = NULL ;
2009-03-07 17:54:12 +02:00
}
2008-08-04 12:05:52 +03:00
}
2008-08-25 13:25:16 +03:00
void CClient : : close ( )
{
2009-01-11 00:08:18 +02:00
if ( ! serv )
return ;
2008-09-19 11:16:19 +03:00
tlog3 < < " Connection has been requested to be closed. \n " ;
2008-08-28 20:36:34 +03:00
boost : : unique_lock < boost : : mutex > ( * serv - > wmx ) ;
2009-03-09 12:37:49 +02:00
* serv < < & CloseServer ( ) ;
2009-01-11 00:08:18 +02:00
tlog3 < < " Sent closing signal to the server \n " ;
2008-08-25 13:25:16 +03:00
serv - > close ( ) ;
2008-09-19 11:16:19 +03:00
tlog3 < < " Our socket has been closed. \n " ;
2008-08-25 13:25:16 +03:00
}
2008-11-16 03:06:15 +02:00
void CClient : : save ( const std : : string & fname )
{
2009-02-11 19:03:30 +02:00
if ( gs - > curB )
{
tlog1 < < " Game cannot be saved during battle! \n " ;
return ;
}
2009-03-09 12:37:49 +02:00
* serv < < & SaveGame ( fname ) ;
2008-11-16 03:06:15 +02:00
}
2008-12-27 03:01:59 +02:00
2009-01-11 00:08:18 +02:00
void CClient : : load ( const std : : string & fname )
{
tlog0 < < " \n \n Loading procedure started! \n \n " ;
timeHandler tmh ;
close ( ) ; //kill server
tlog0 < < " Sent kill signal to the server: " < < tmh . getDif ( ) < < std : : endl ;
VLC - > clear ( ) ; //delete old handlers
delete CGI - > mh ;
delete CGI - > state ;
//TODO: del callbacks
for ( std : : map < ui8 , CGameInterface * > : : iterator i = playerint . begin ( ) ; i ! = playerint . end ( ) ; i + + )
{
delete i - > second ; //delete player interfaces
2009-03-19 16:17:19 +02:00
}
2009-01-11 00:08:18 +02:00
tlog0 < < " Deleting old data: " < < tmh . getDif ( ) < < std : : endl ;
char portc [ 10 ] ;
SDL_itoa ( conf . cc . port , portc , 10 ) ;
runServer ( portc ) ; //create new server
tlog0 < < " Restarting server: " < < tmh . getDif ( ) < < std : : endl ;
{
2009-02-01 16:11:41 +02:00
ui32 ver ;
2009-01-11 00:08:18 +02:00
char sig [ 8 ] ;
CMapHeader dum ;
CGI - > mh = new CMapHandler ( ) ;
CLoadFile lf ( fname + " .vlgm1 " ) ;
2009-02-01 16:11:41 +02:00
lf > > sig > > ver > > dum > > * sig ;
2009-01-11 00:08:18 +02:00
tlog0 < < " Reading save signature: " < < tmh . getDif ( ) < < std : : endl ;
lf > > * VLC ;
CGI - > setFromLib ( ) ;
tlog0 < < " Reading handlers: " < < tmh . getDif ( ) < < std : : endl ;
lf > > gs ;
tlog0 < < " Reading gamestate: " < < tmh . getDif ( ) < < std : : endl ;
CGI - > state = gs ;
CGI - > mh - > map = gs - > map ;
CGI - > mh - > init ( ) ;
tlog0 < < " Initing maphandler: " < < tmh . getDif ( ) < < std : : endl ;
}
waitForServer ( ) ;
tlog0 < < " Waiting for server: " < < tmh . getDif ( ) < < std : : endl ;
serv = new CConnection ( conf . cc . server , portc , NAME ) ;
tlog0 < < " Setting up connection: " < < tmh . getDif ( ) < < std : : endl ;
ui8 pom8 ;
* serv < < ui8 ( 3 ) < < ui8 ( 1 ) ; //load game; one client
* serv < < fname ;
* serv > > pom8 ;
if ( pom8 )
throw " Server cannot open the savegame! " ;
else
tlog0 < < " Server opened savegame properly. \n " ;
* serv < < ui8 ( gs - > scenarioOps - > playerInfos . size ( ) + 1 ) ; //number of players + neutral
for ( size_t i = 0 ; i < gs - > scenarioOps - > playerInfos . size ( ) ; i + + )
{
* serv < < ui8 ( gs - > scenarioOps - > playerInfos [ i ] . color ) ; //players
}
* serv < < ui8 ( 255 ) ; // neutrals
tlog0 < < " Sent info to server: " < < tmh . getDif ( ) < < std : : endl ;
for ( size_t i = 0 ; i < gs - > scenarioOps - > playerInfos . size ( ) ; + + i ) //initializing interfaces for players
{
ui8 color = gs - > scenarioOps - > playerInfos [ i ] . color ;
CCallback * cb = new CCallback ( gs , color , this ) ;
if ( ! gs - > scenarioOps - > playerInfos [ i ] . human ) {
playerint [ color ] = static_cast < CGameInterface * > ( CAIHandler : : getNewAI ( cb , conf . cc . defaultAI ) ) ;
}
else {
playerint [ color ] = new CPlayerInterface ( color , i ) ;
}
gs - > currentPlayer = color ;
playerint [ color ] - > init ( cb ) ;
tlog0 < < " Setting up interface for player " < < ( int ) color < < " : " < < tmh . getDif ( ) < < std : : endl ;
}
playerint [ 255 ] = CAIHandler : : getNewAI ( cb , conf . cc . defaultAI ) ;
playerint [ 255 ] - > init ( new CCallback ( gs , 255 , this ) ) ;
tlog0 < < " Setting up interface for neutral \" player \" " < < tmh . getDif ( ) < < std : : endl ;
}
2008-12-27 03:01:59 +02:00
int CClient : : getCurrentPlayer ( )
{
return gs - > currentPlayer ;
}
int CClient : : getSelectedHero ( )
{
return IGameCallback : : getSelectedHero ( getCurrentPlayer ( ) ) - > id ;
2009-01-11 00:08:18 +02:00
}
void CClient : : newGame ( CConnection * con , StartInfo * si )
{
timeHandler tmh ;
CGI - > state = new CGameState ( ) ;
tlog0 < < " \t Gamestate: " < < tmh . getDif ( ) < < std : : endl ;
serv = con ;
CConnection & c ( * con ) ;
////////////////////////////////////////////////////
ui8 pom8 ;
c < < ui8 ( 2 ) < < ui8 ( 1 ) ; //new game; one client
c < < * si ;
c > > pom8 ;
if ( pom8 )
throw " Server cannot open the map! " ;
else
tlog0 < < " Server opened map properly. \n " ;
c < < ui8 ( si - > playerInfos . size ( ) + 1 ) ; //number of players + neutral
for ( size_t i = 0 ; i < si - > playerInfos . size ( ) ; i + + )
{
c < < ui8 ( si - > playerInfos [ i ] . color ) ; //players
}
c < < ui8 ( 255 ) ; // neutrals
ui32 seed , sum ;
std : : string mapname ;
c > > mapname > > sum > > seed ;
tlog0 < < " \t Sending/Getting info to/from the server: " < < tmh . getDif ( ) < < std : : endl ;
Mapa * mapa = new Mapa ( mapname ) ;
tlog0 < < " Reading and detecting map file (together): " < < tmh . getDif ( ) < < std : : endl ;
tlog0 < < " \t Server checksum for " < < mapname < < " : " < < sum < < std : : endl ;
tlog0 < < " \t Our checksum for the map: " < < mapa - > checksum < < std : : endl ;
if ( mapa - > checksum ! = sum )
{
tlog1 < < " Wrong map checksum!!! " < < std : : endl ;
throw std : : string ( " Wrong checksum " ) ;
}
tlog0 < < " \t Using random seed: " < < seed < < std : : endl ;
gs = CGI - > state ;
gs - > scenarioOps = si ;
gs - > init ( si , mapa , seed ) ;
CGI - > mh = new CMapHandler ( ) ;
tlog0 < < " Initializing GameState (together): " < < tmh . getDif ( ) < < std : : endl ;
CGI - > mh - > map = mapa ;
tlog0 < < " Creating mapHandler: " < < tmh . getDif ( ) < < std : : endl ;
CGI - > mh - > init ( ) ;
tlog0 < < " Initializing mapHandler (together): " < < tmh . getDif ( ) < < std : : endl ;
for ( size_t i = 0 ; i < CGI - > state - > scenarioOps - > playerInfos . size ( ) ; + + i ) //initializing interfaces for players
{
ui8 color = gs - > scenarioOps - > playerInfos [ i ] . color ;
CCallback * cb = new CCallback ( gs , color , this ) ;
if ( ! gs - > scenarioOps - > playerInfos [ i ] . human ) {
playerint [ color ] = static_cast < CGameInterface * > ( CAIHandler : : getNewAI ( cb , conf . cc . defaultAI ) ) ;
}
else {
playerint [ color ] = new CPlayerInterface ( color , i ) ;
}
gs - > currentPlayer = color ;
playerint [ color ] - > init ( cb ) ;
}
playerint [ 255 ] = CAIHandler : : getNewAI ( cb , conf . cc . defaultAI ) ;
playerint [ 255 ] - > init ( new CCallback ( gs , 255 , this ) ) ;
}
void CClient : : runServer ( const char * portc )
{
static std : : string comm = std : : string ( SERVER_NAME ) + " " + portc + " > server_log.txt " ; //needs to be static, if not - will be probably destroyed before new thread reads it
boost : : thread servthr ( boost : : bind ( system , comm . c_str ( ) ) ) ; //runs server executable; //TODO: will it work on non-windows platforms?
}
void CClient : : waitForServer ( )
{
2009-01-30 23:28:02 +02:00
intpr : : scoped_lock < intpr : : interprocess_mutex > slock ( shared - > sr - > mutex ) ;
while ( ! shared - > sr - > ready )
2009-01-11 00:08:18 +02:00
{
2009-01-30 23:28:02 +02:00
shared - > sr - > cond . wait ( slock ) ;
2009-01-11 00:08:18 +02:00
}
2009-01-30 23:28:02 +02:00
}
2009-03-28 20:46:20 +02:00
template < typename Handler >
void CClient : : serialize ( Handler & h , const int version )
{
if ( h . saving )
{
ui8 players = playerint . size ( ) ;
h & players ;
for ( std : : map < ui8 , CGameInterface * > : : iterator i = playerint . begin ( ) ; i ! = playerint . end ( ) ; i + + )
{
h & i - > first & i - > second - > dllName ;
i - > second - > serialize ( h , version ) ;
}
}
else
{
ui8 players ;
h & players ;
for ( int i = 0 ; i < players ; i + + )
{
std : : string dllname ;
ui8 pid ;
h & pid & dllname ;
if ( dllname . length ( ) )
{
CCallback * callback = new CCallback ( gs , pid , this ) ;
callbacks . insert ( callback ) ;
playerint [ pid ] = CAIHandler : : getNewAI ( callback , dllname ) ;
playerint [ pid ] - > init ( callback ) ;
}
}
}
}
template void CClient : : serialize ( CISer < CLoadFile > & h , const int version ) ;
template void CClient : : serialize ( COSer < CSaveFile > & h , const int version ) ;