2010-12-20 23:22:53 +02:00
# include "CMusicHandler.h"
# include "../lib/CCampaignHandler.h"
2008-07-25 20:28:28 +03:00
# include "../CCallback.h"
# include "../CConsoleHandler.h"
2009-05-20 13:08:56 +03:00
# include "CGameInfo.h"
# include "../lib/CGameState.h"
# include "CPlayerInterface.h"
2008-11-09 00:29:19 +02:00
# include "../StartInfo.h"
2010-12-25 21:23:30 +02:00
# include "../lib/BattleState.h"
2010-12-20 23:22:53 +02:00
# include "../lib/CArtHandler.h"
# include "../lib/CDefObjInfoHandler.h"
# include "../lib/CGeneralTextHandler.h"
# include "../lib/CHeroHandler.h"
# include "../lib/CTownHandler.h"
# include "../lib/CObjectHandler.h"
# include "../lib/CBuildingHandler.h"
# include "../lib/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"
2009-05-20 13:08:56 +03:00
# include "../lib/map.h"
2011-09-01 04:40:46 +03:00
# include "../lib/JsonNode.h"
2010-04-06 16:19:54 +03:00
# include "mapHandler.h"
2008-11-09 00:29:19 +02:00
# include "CConfigHandler.h"
# include "Client.h"
2009-11-01 03:15:16 +02:00
# include "GUIBase.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>
2010-09-03 21:42:54 +03:00
# include <boost/lexical_cast.hpp>
2008-12-27 03:01:59 +02:00
# include <sstream>
2010-08-20 16:34:39 +03:00
# include "CPreGame.h"
2011-02-24 15:57:47 +02:00
# include "CBattleInterface.h"
# include "../CThreadHelper.h"
2011-06-20 14:41:04 +03:00
# include "../lib/CScriptingModule.h"
# include "../lib/CFileUtility.h"
2009-03-07 00:25:19 +02:00
2010-09-03 21:42:54 +03:00
# define NOT_LIB
2009-03-15 14:53:58 +02:00
# include "../lib/RegisterTypes.cpp"
2011-05-10 01:20:47 +03:00
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-04-15 17:03:31 +03:00
/*
* Client . 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
*
*/
2010-09-03 21:42:54 +03:00
template < typename T > class CApplyOnCL ;
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 ;
2010-01-02 03:48:44 +02:00
virtual ~ CBaseForCLApply ( ) { }
2010-09-03 21:42:54 +03:00
template < typename U > static CBaseForCLApply * getApplier ( const U * t = NULL )
{
return new CApplyOnCL < U > ;
}
2009-03-07 00:25:19 +02:00
} ;
2010-09-03 21:42:54 +03:00
2009-03-07 00:25:19 +02:00
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 ) ;
}
} ;
2010-09-04 17:47:39 +03:00
static CApplier < CBaseForCLApply > * 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
{
2010-02-20 15:24:38 +02:00
hotSeat = false ;
2009-12-28 06:08:24 +02:00
connectionHandler = NULL ;
2009-08-30 15:47:40 +03:00
pathInfo = NULL ;
2010-09-03 21:42:54 +03:00
applier = new CApplier < CBaseForCLApply > ;
registerTypes2 ( * applier ) ;
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 ;
2011-06-11 02:50:32 +03:00
erm = NULL ;
2009-11-01 03:15:16 +02:00
terminate = false ;
2009-01-30 23:28:02 +02:00
}
CClient : : CClient ( void )
{
init ( ) ;
2008-07-25 20:28:28 +03:00
}
2010-09-03 21:42:54 +03:00
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
}
2010-09-03 21:42:54 +03:00
2008-07-25 20:28:28 +03:00
CClient : : ~ CClient ( void )
{
2009-08-30 15:47:40 +03:00
delete pathInfo ;
2009-03-07 17:54:12 +02:00
delete applier ;
2008-07-25 20:28:28 +03:00
}
2010-09-03 21:42:54 +03:00
2008-08-04 18:56:36 +03:00
void CClient : : waitForMoveAndSend ( int color )
{
2008-08-30 00:41:32 +03:00
try
{
2010-12-25 03:43:40 +02:00
assert ( vstd : : contains ( battleints , color ) ) ;
BattleAction ba = battleints [ color ] - > activeStack ( gs - > curB - > getStack ( gs - > curB - > activeStack , false ) ) ;
2011-06-11 07:54:41 +03:00
MakeAction temp_action ( ba ) ;
* serv < < & temp_action ;
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
}
2009-12-28 06:08:24 +02:00
2008-07-25 20:28:28 +03:00
void CClient : : run ( )
{
2011-02-24 15:57:47 +02:00
setThreadName ( - 1 , " CClient::run " ) ;
2009-04-11 04:32:50 +03:00
try
2008-07-25 20:28:28 +03:00
{
2010-01-02 03:48:44 +02:00
CPack * pack = NULL ;
2009-12-28 06:08:24 +02:00
while ( ! terminate )
2009-03-07 17:54:12 +02:00
{
2010-09-03 21:42:54 +03:00
pack = serv - > retreivePack ( ) ; //get the package from the server
2010-01-02 03:48:44 +02:00
2009-12-28 06:08:24 +02:00
if ( terminate )
{
2009-11-01 03:15:16 +02:00
delete pack ;
2010-01-02 03:48:44 +02:00
pack = NULL ;
2009-11-01 03:15:16 +02:00
break ;
}
2010-01-02 03:48:44 +02:00
handlePack ( pack ) ;
2009-04-11 04:32:50 +03:00
pack = NULL ;
2009-03-07 17:54:12 +02:00
}
2010-01-29 22:52:45 +02:00
}
catch ( const std : : exception & e )
{
2010-05-02 21:20:26 +03:00
tlog3 < < " Lost connection to server, ending listening thread! \n " ;
2010-01-29 22:52:45 +02:00
tlog1 < < e . what ( ) < < std : : endl ;
if ( ! terminate ) //rethrow (-> boom!) only if closing connection was unexpected
{
tlog1 < < " Something wrong, lost connection while game is still ongoing... \n " ;
throw ;
}
}
2008-08-04 12:05:52 +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 ;
}
2011-06-11 07:54:41 +03:00
SaveGame save_game ( fname ) ;
* serv < < & save_game ;
2008-11-16 03:06:15 +02:00
}
2008-12-27 03:01:59 +02:00
2010-08-20 16:34:39 +03:00
void CClient : : endGame ( bool closeConnection /*= true*/ )
2009-01-11 00:08:18 +02:00
{
2010-08-20 16:34:39 +03:00
// Game is ending
// Tell the network thread to reach a stable state
2011-05-30 02:49:25 +03:00
if ( closeConnection )
stopConnection ( ) ;
tlog0 < < " Closed connection. " < < std : : endl ;
2010-08-20 16:34:39 +03:00
GH . curInt = NULL ;
LOCPLINT - > terminate_cond . setn ( true ) ;
LOCPLINT - > pim - > lock ( ) ;
2009-11-01 03:15:16 +02:00
tlog0 < < " \n \n Ending current game! " < < std : : endl ;
2010-01-30 14:46:15 +02:00
if ( GH . topInt ( ) )
GH . topInt ( ) - > deactivate ( ) ;
2009-12-28 06:08:24 +02:00
GH . listInt . clear ( ) ;
GH . objsToBlit . clear ( ) ;
2010-02-20 15:24:38 +02:00
GH . statusbar = NULL ;
2010-02-13 23:45:46 +02:00
tlog0 < < " Removed GUI. " < < std : : endl ;
2009-01-11 00:08:18 +02:00
2011-05-30 02:49:25 +03:00
2009-01-11 00:08:18 +02:00
delete CGI - > mh ;
2010-12-19 00:11:28 +02:00
const_cast < CGameInfo * > ( CGI ) - > mh = NULL ;
2009-06-23 11:14:49 +03:00
2010-12-26 16:34:11 +02:00
const_cast < CGameInfo * > ( CGI ) - > state . dellNull ( ) ;
2010-02-13 23:45:46 +02:00
tlog0 < < " Deleted mapHandler and gameState. " < < std : : endl ;
2009-01-11 00:08:18 +02:00
2011-01-17 18:07:08 +02:00
CPlayerInterface * oldInt = LOCPLINT ;
2009-12-28 06:08:24 +02:00
LOCPLINT = NULL ;
2011-01-17 18:07:08 +02:00
oldInt - > pim - > unlock ( ) ;
2009-11-01 03:15:16 +02:00
while ( ! playerint . empty ( ) )
2009-01-11 00:08:18 +02:00
{
2010-09-03 21:42:54 +03:00
CGameInterface * pint = playerint . begin ( ) - > second ;
2009-11-01 03:15:16 +02:00
playerint . erase ( playerint . begin ( ) ) ;
2010-09-03 21:42:54 +03:00
delete pint ;
2009-03-19 16:17:19 +02:00
}
2009-06-23 11:14:49 +03:00
2011-09-06 09:00:32 +03:00
callbacks . clear ( ) ;
2010-02-13 23:45:46 +02:00
tlog0 < < " Deleted playerInts. " < < std : : endl ;
2009-11-01 03:15:16 +02:00
2010-08-20 16:34:39 +03:00
tlog0 < < " Client stopped. " < < std : : endl ;
2009-11-01 03:15:16 +02:00
}
void CClient : : loadGame ( const std : : string & fname )
{
tlog0 < < " \n \n Loading procedure started! \n \n " ;
2010-09-03 21:42:54 +03:00
CServerHandler sh ;
sh . startServer ( ) ;
2009-01-11 00:08:18 +02:00
2010-09-03 21:42:54 +03:00
timeHandler tmh ;
2009-01-11 00:08:18 +02:00
{
char sig [ 8 ] ;
CMapHeader dum ;
2010-12-19 00:11:28 +02:00
const_cast < CGameInfo * > ( CGI ) - > mh = new CMapHandler ( ) ;
2010-02-24 15:03:36 +02:00
StartInfo * si ;
2009-01-11 00:08:18 +02:00
CLoadFile lf ( fname + " .vlgm1 " ) ;
2010-02-24 15:03:36 +02:00
lf > > sig > > dum > > si ;
2009-01-11 00:08:18 +02:00
tlog0 < < " Reading save signature: " < < tmh . getDif ( ) < < std : : endl ;
2010-02-24 15:03:36 +02:00
2009-01-11 00:08:18 +02:00
lf > > * VLC ;
2010-12-19 00:11:28 +02:00
const_cast < CGameInfo * > ( CGI ) - > setFromLib ( ) ;
2009-01-11 00:08:18 +02:00
tlog0 < < " Reading handlers: " < < tmh . getDif ( ) < < std : : endl ;
lf > > gs ;
tlog0 < < " Reading gamestate: " < < tmh . getDif ( ) < < std : : endl ;
2010-12-19 00:11:28 +02:00
const_cast < CGameInfo * > ( CGI ) - > state = gs ;
const_cast < CGameInfo * > ( CGI ) - > mh - > map = gs - > map ;
2009-08-30 15:47:40 +03:00
pathInfo = new CPathsInfo ( int3 ( gs - > map - > width , gs - > map - > height , gs - > map - > twoLevel + 1 ) ) ;
2009-01-11 00:08:18 +02:00
CGI - > mh - > init ( ) ;
2010-08-16 16:51:31 +03:00
2009-01-11 00:08:18 +02:00
tlog0 < < " Initing maphandler: " < < tmh . getDif ( ) < < std : : endl ;
}
2010-09-03 21:42:54 +03:00
serv = sh . connectToServer ( ) ;
2010-06-26 19:02:10 +03:00
serv - > addStdVecItems ( gs ) ;
2009-01-11 00:08:18 +02:00
2010-09-03 21:42:54 +03:00
tmh . update ( ) ;
2009-01-11 00:08:18 +02:00
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 " ;
2010-11-03 13:34:25 +02:00
* serv < < ui32 ( gs - > scenarioOps - > playerInfos . size ( ) + 1 ) ; //number of players + neutral
2010-08-03 14:36:52 +03:00
for ( std : : map < int , PlayerSettings > : : iterator it = gs - > scenarioOps - > playerInfos . begin ( ) ;
it ! = gs - > scenarioOps - > playerInfos . end ( ) ; + + it )
2009-01-11 00:08:18 +02:00
{
2010-08-03 14:36:52 +03:00
* serv < < ui8 ( it - > first ) ; //players
2009-01-11 00:08:18 +02:00
}
* serv < < ui8 ( 255 ) ; // neutrals
tlog0 < < " Sent info to server: " < < tmh . getDif ( ) < < std : : endl ;
2009-07-18 06:13:13 +03:00
{
CLoadFile lf ( fname + " .vcgm1 " ) ;
lf > > * this ;
2009-01-11 00:08:18 +02:00
}
}
void CClient : : newGame ( CConnection * con , StartInfo * si )
{
2010-10-24 14:35:14 +03:00
enum { SINGLE , HOST , GUEST } networkMode = SINGLE ;
std : : set < ui8 > myPlayers ;
2009-12-20 19:14:14 +02:00
if ( con = = NULL )
{
2010-09-03 21:42:54 +03:00
CServerHandler sh ;
2010-10-24 14:35:14 +03:00
serv = sh . connectToServer ( ) ;
}
else
{
serv = con ;
networkMode = ( con - > connectionID = = 1 ) ? HOST : GUEST ;
2009-11-01 03:15:16 +02:00
}
2010-10-24 14:35:14 +03:00
for ( std : : map < int , PlayerSettings > : : iterator it = si - > playerInfos . begin ( ) ;
it ! = si - > playerInfos . end ( ) ; + + it )
{
2011-05-30 22:20:14 +03:00
if ( ( networkMode = = SINGLE ) //single - one client has all player
| | ( networkMode ! = SINGLE & & serv - > connectionID = = it - > second . human ) //multi - client has only "its players"
| | ( networkMode = = HOST & & it - > second . human = = false ) ) //multi - host has all AI players
2010-10-24 14:35:14 +03:00
{
myPlayers . insert ( ui8 ( it - > first ) ) ; //add player
}
}
if ( networkMode ! = GUEST )
myPlayers . insert ( 255 ) ; //neutral
2009-01-11 00:08:18 +02:00
timeHandler tmh ;
2010-12-19 00:11:28 +02:00
const_cast < CGameInfo * > ( CGI ) - > state = new CGameState ( ) ;
2009-01-11 00:08:18 +02:00
tlog0 < < " \t Gamestate: " < < tmh . getDif ( ) < < std : : endl ;
2010-10-24 14:35:14 +03:00
CConnection & c ( * serv ) ;
2009-01-11 00:08:18 +02:00
////////////////////////////////////////////////////
2010-10-24 14:35:14 +03:00
if ( networkMode = = SINGLE )
2009-01-11 00:08:18 +02:00
{
2010-10-24 14:35:14 +03:00
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 " ;
2009-01-11 00:08:18 +02:00
}
2010-10-24 14:35:14 +03:00
c < < myPlayers ;
2009-01-11 00:08:18 +02:00
ui32 seed , sum ;
2010-05-08 21:56:38 +03:00
c > > si > > sum > > seed ;
2009-01-11 00:08:18 +02:00
tlog0 < < " \t Sending/Getting info to/from the server: " < < tmh . getDif ( ) < < std : : endl ;
tlog0 < < " \t Using random seed: " < < seed < < std : : endl ;
2010-12-20 15:04:24 +02:00
gs = const_cast < CGameInfo * > ( CGI ) - > state ;
2009-01-11 00:08:18 +02:00
gs - > scenarioOps = si ;
2010-05-08 21:56:38 +03:00
gs - > init ( si , sum , seed ) ;
2009-01-11 00:08:18 +02:00
tlog0 < < " Initializing GameState (together): " < < tmh . getDif ( ) < < std : : endl ;
2010-12-22 22:14:40 +02:00
2010-12-23 02:33:48 +02:00
if ( gs - > map )
2010-12-22 22:14:40 +02:00
{
const_cast < CGameInfo * > ( CGI ) - > mh = new CMapHandler ( ) ;
CGI - > mh - > map = gs - > map ;
tlog0 < < " Creating mapHandler: " < < tmh . getDif ( ) < < std : : endl ;
2011-09-03 06:04:06 +03:00
CGI - > mh - > init ( ) ;
2010-12-22 22:14:40 +02:00
pathInfo = new CPathsInfo ( int3 ( gs - > map - > width , gs - > map - > height , gs - > map - > twoLevel + 1 ) ) ;
tlog0 < < " Initializing mapHandler (together): " < < tmh . getDif ( ) < < std : : endl ;
}
2009-01-11 00:08:18 +02:00
2010-02-20 15:24:38 +02:00
int humanPlayers = 0 ;
2010-08-03 14:36:52 +03:00
for ( std : : map < int , PlayerSettings > : : iterator it = gs - > scenarioOps - > playerInfos . begin ( ) ;
it ! = gs - > scenarioOps - > playerInfos . end ( ) ; + + it ) //initializing interfaces for players
2009-01-11 00:08:18 +02:00
{
2010-08-03 14:36:52 +03:00
ui8 color = it - > first ;
2010-12-22 22:14:40 +02:00
gs - > currentPlayer = color ;
2010-10-24 14:35:14 +03:00
if ( ! vstd : : contains ( myPlayers , color ) )
continue ;
2010-12-22 22:14:40 +02:00
if ( si - > mode ! = StartInfo : : DUEL )
2010-02-20 15:24:38 +02:00
{
2010-12-22 22:14:40 +02:00
CCallback * cb = new CCallback ( gs , color , this ) ;
if ( ! it - > second . human )
{
2011-06-20 14:41:04 +03:00
playerint [ color ] = static_cast < CGameInterface * > ( CDynLibHandler : : getNewAI ( conf . cc . defaultPlayerAI ) ) ;
2010-12-22 22:14:40 +02:00
}
else
{
playerint [ color ] = new CPlayerInterface ( color ) ;
humanPlayers + + ;
}
2010-12-25 03:43:40 +02:00
battleints [ color ] = playerint [ color ] ;
2010-12-22 22:14:40 +02:00
playerint [ color ] - > init ( cb ) ;
2011-09-10 12:42:09 +03:00
callbacks [ color ] = boost : : shared_ptr < CCallback > ( cb ) ;
2009-01-11 00:08:18 +02:00
}
2010-12-22 22:14:40 +02:00
else
2010-02-20 15:24:38 +02:00
{
2010-12-22 22:14:40 +02:00
CBattleCallback * cbc = new CBattleCallback ( gs , color , this ) ;
2011-06-20 14:41:04 +03:00
battleints [ color ] = CDynLibHandler : : getNewBattleAI ( " StupidAI " ) ;
2010-12-22 22:14:40 +02:00
battleints [ color ] - > init ( cbc ) ;
2009-01-11 00:08:18 +02:00
}
}
2010-02-20 15:24:38 +02:00
2010-12-23 02:33:48 +02:00
if ( si - > mode = = StartInfo : : DUEL )
{
CPlayerInterface * p = new CPlayerInterface ( - 1 ) ;
p - > observerInDuelMode = true ;
2010-12-25 03:43:40 +02:00
battleints [ 254 ] = playerint [ 254 ] = p ;
GH . curInt = p ;
2010-12-23 02:33:48 +02:00
p - > init ( new CCallback ( gs , - 1 , this ) ) ;
battleStarted ( gs - > curB ) ;
}
2010-12-25 03:43:40 +02:00
else
{
2011-02-27 21:58:14 +02:00
loadNeutralBattleAI ( ) ;
2010-12-25 03:43:40 +02:00
}
2010-12-22 22:14:40 +02:00
2010-12-20 15:04:24 +02:00
serv - > addStdVecItems ( const_cast < CGameInfo * > ( CGI ) - > state ) ;
2010-02-20 15:24:38 +02:00
hotSeat = ( humanPlayers > 1 ) ;
2011-07-17 21:49:05 +03:00
// std::vector<FileInfo> scriptModules;
// CFileUtility::getFilesWithExt(scriptModules, LIB_DIR "/Scripting", "." LIB_EXT);
// BOOST_FOREACH(FileInfo &m, scriptModules)
// {
// CScriptingModule * nm = CDynLibHandler::getNewScriptingModule(m.name);
// privilagedGameEventReceivers.push_back(nm);
// privilagedBattleEventReceivers.push_back(nm);
// nm->giveActionCB(this);
// nm->giveInfoCB(this);
// nm->init();
//
// erm = nm; //something tells me that there'll at most one module and it'll be ERM
// }
2009-01-11 00:08:18 +02:00
}
2011-09-30 00:29:54 +03:00
void CClient : : newDuel ( CConnection * con , StartInfo * si )
{
serv = con ;
if ( ! serv )
{
std : : string host = " 127.0.0.1 " ;
std : : string port = " 3030 " ;
int i = 3 ;
while ( ! serv )
{
try
{
tlog0 < < " Establishing connection... \n " ;
serv = new CConnection ( host , port , " DLL host " ) ;
}
catch ( . . . )
{
tlog1 < < " \n Cannot establish connection! Retrying within 2 seconds " < < std : : endl ;
boost : : this_thread : : sleep ( boost : : posix_time : : seconds ( 2 ) ) ;
if ( ! - - i )
exit ( 0 ) ;
}
}
}
ui8 color ;
std : : string battleAIName ;
* serv > > * si > > battleAIName > > color ;
assert ( si - > mode = = StartInfo : : DUEL ) ;
assert ( color > 1 ) ; //we are NOT participants
//tlog0 << format("Server wants us to be %s in battle %s as side %d") % battleAIName % si.mapname % (int)color;
gs = new CGameState ( ) ;
const_cast < CGameInfo * > ( CGI ) - > state = gs ;
//gs->scenarioOps = si;
gs - > init ( si , 0 , 0 ) ;
CPlayerInterface * p = new CPlayerInterface ( - 1 ) ;
privilagedBattleEventReceivers . push_back ( p ) ;
p - > observerInDuelMode = true ;
battleints [ 254 ] = playerint [ 254 ] = p ;
GH . curInt = p ;
p - > init ( new CCallback ( gs , - 1 , this ) ) ;
battleStarted ( gs - > curB ) ;
serv - > addStdVecItems ( const_cast < CGameInfo * > ( CGI ) - > state ) ;
}
2009-03-28 20:46:20 +02:00
template < typename Handler >
void CClient : : serialize ( Handler & h , const int version )
{
2010-02-20 15:24:38 +02:00
h & hotSeat ;
2009-03-28 20:46:20 +02:00
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 ;
2009-07-18 06:13:13 +03:00
2011-02-23 05:57:45 +02:00
CGameInterface * nInt = NULL ;
2009-03-28 20:46:20 +02:00
if ( dllname . length ( ) )
2011-02-23 05:57:45 +02:00
{
if ( pid = = 255 )
{
2011-08-19 22:50:24 +03:00
//CBattleCallback * cbc = new CBattleCallback(gs, pid, this);//FIXME: unused?
2011-06-20 14:41:04 +03:00
CBattleGameInterface * cbgi = CDynLibHandler : : getNewBattleAI ( dllname ) ;
2011-02-23 05:57:45 +02:00
battleints [ pid ] = cbgi ;
cbgi - > init ( cb ) ;
//TODO? consider serialization
continue ;
}
else
2011-06-20 14:41:04 +03:00
nInt = CDynLibHandler : : getNewAI ( dllname ) ;
2011-02-23 05:57:45 +02:00
}
2009-07-18 06:13:13 +03:00
else
2010-08-03 14:36:52 +03:00
nInt = new CPlayerInterface ( pid ) ;
2009-07-18 06:13:13 +03:00
2011-09-10 12:42:09 +03:00
callbacks [ pid ] = boost : : shared_ptr < CCallback > ( new CCallback ( gs , pid , this ) ) ;
2011-02-22 11:47:25 +02:00
battleints [ pid ] = playerint [ pid ] = nInt ;
2011-09-06 09:00:32 +03:00
nInt - > init ( callbacks [ pid ] . get ( ) ) ;
2009-07-18 06:13:13 +03:00
nInt - > serialize ( h , version ) ;
2009-03-28 20:46:20 +02:00
}
2011-02-27 21:58:14 +02:00
if ( ! vstd : : contains ( battleints , NEUTRAL_PLAYER ) )
loadNeutralBattleAI ( ) ;
2009-03-28 20:46:20 +02:00
}
}
2010-01-02 03:48:44 +02:00
void CClient : : handlePack ( CPack * pack )
{
CBaseForCLApply * apply = applier - > apps [ typeList . getTypeID ( pack ) ] ; //find the applier
if ( apply )
{
apply - > applyOnClBefore ( this , pack ) ;
tlog5 < < " \t Made first apply on cl \n " ;
gs - > apply ( pack ) ;
tlog5 < < " \t Applied on gs \n " ;
apply - > applyOnClAfter ( this , pack ) ;
tlog5 < < " \t Made second apply on cl \n " ;
}
else
{
2011-06-18 07:56:32 +03:00
tlog1 < < " Message cannot be applied, cannot find applier! TypeID " < < typeList . getTypeID ( pack ) < < std : : endl ;
2010-01-02 03:48:44 +02:00
}
delete pack ;
}
2009-08-04 02:53:18 +03:00
2010-03-11 01:16:30 +02:00
void CClient : : updatePaths ( )
2011-08-25 18:24:37 +03:00
{
//TODO? lazy evaluation? paths now can get recalculated multiple times upon various game events
2011-05-22 21:46:52 +03:00
const CGHeroInstance * h = getSelectedHero ( ) ;
2010-03-11 01:16:30 +02:00
if ( h ) //if we have selected hero...
2011-06-25 17:22:19 +03:00
calculatePaths ( h ) ;
2010-03-11 01:16:30 +02:00
}
2010-08-20 16:34:39 +03:00
void CClient : : finishCampaign ( CCampaignState * camp )
{
}
void CClient : : proposeNextMission ( CCampaignState * camp )
{
GH . pushInt ( new CBonusSelection ( camp ) ) ;
GH . curInt = CGP ;
}
void CClient : : stopConnection ( )
{
terminate = true ;
2011-01-17 18:07:08 +02:00
if ( serv ) //request closing connection
2010-08-20 16:34:39 +03:00
{
tlog0 < < " Connection has been requested to be closed. \n " ;
boost : : unique_lock < boost : : mutex > ( * serv - > wmx ) ;
2011-06-11 07:54:41 +03:00
CloseServer close_server ;
* serv < < & close_server ;
2010-08-20 16:34:39 +03:00
tlog0 < < " Sent closing signal to the server \n " ;
}
2011-01-17 18:07:08 +02:00
if ( connectionHandler ) //end connection handler
2010-08-20 16:34:39 +03:00
{
if ( connectionHandler - > get_id ( ) ! = boost : : this_thread : : get_id ( ) )
connectionHandler - > join ( ) ;
tlog0 < < " Connection handler thread joined " < < std : : endl ;
delete connectionHandler ;
connectionHandler = NULL ;
}
2011-01-17 18:07:08 +02:00
if ( serv ) //and delete connection
{
serv - > close ( ) ;
delete serv ;
serv = NULL ;
tlog3 < < " Our socket has been closed. " < < std : : endl ;
}
2010-08-20 16:34:39 +03:00
}
2010-12-23 02:33:48 +02:00
void CClient : : battleStarted ( const BattleInfo * info )
{
CPlayerInterface * att , * def ;
2011-01-09 19:41:46 +02:00
if ( vstd : : contains ( playerint , info - > sides [ 0 ] ) & & playerint [ info - > sides [ 0 ] ] - > human )
att = static_cast < CPlayerInterface * > ( playerint [ info - > sides [ 0 ] ] ) ;
2010-12-23 02:33:48 +02:00
else
att = NULL ;
2011-01-09 19:41:46 +02:00
if ( vstd : : contains ( playerint , info - > sides [ 1 ] ) & & playerint [ info - > sides [ 1 ] ] - > human )
def = static_cast < CPlayerInterface * > ( playerint [ info - > sides [ 1 ] ] ) ;
2010-12-23 02:33:48 +02:00
else
def = NULL ;
2011-07-17 21:49:05 +03:00
if ( att | | def | | gs - > scenarioOps - > mode = = StartInfo : : DUEL )
new CBattleInterface ( info - > belligerents [ 0 ] , info - > belligerents [ 1 ] , info - > heroes [ 0 ] , info - > heroes [ 1 ] , Rect ( ( conf . cc . resx - 800 ) / 2 , ( conf . cc . resy - 600 ) / 2 , 800 , 600 ) , att , def ) ;
2010-12-23 02:33:48 +02:00
2011-01-09 19:41:46 +02:00
if ( vstd : : contains ( battleints , info - > sides [ 0 ] ) )
battleints [ info - > sides [ 0 ] ] - > battleStart ( info - > belligerents [ 0 ] , info - > belligerents [ 1 ] , info - > tile , info - > heroes [ 0 ] , info - > heroes [ 1 ] , 0 ) ;
if ( vstd : : contains ( battleints , info - > sides [ 1 ] ) )
battleints [ info - > sides [ 1 ] ] - > battleStart ( info - > belligerents [ 0 ] , info - > belligerents [ 1 ] , info - > tile , info - > heroes [ 0 ] , info - > heroes [ 1 ] , 1 ) ;
2010-12-25 03:43:40 +02:00
if ( vstd : : contains ( battleints , 254 ) )
battleints [ 254 ] - > battleStart ( info - > belligerents [ 0 ] , info - > belligerents [ 1 ] , info - > tile , info - > heroes [ 0 ] , info - > heroes [ 1 ] , 1 ) ;
2011-08-25 18:24:37 +03:00
if ( info - > tacticDistance & & vstd : : contains ( battleints , info - > sides [ info - > tacticsSide ] ) )
{
2011-08-26 00:08:53 +03:00
boost : : thread ( & CClient : : commenceTacticPhaseForInt , this , battleints [ info - > sides [ info - > tacticsSide ] ] ) ;
2011-08-25 18:24:37 +03:00
}
2010-12-23 02:33:48 +02:00
}
2011-02-27 21:58:14 +02:00
void CClient : : loadNeutralBattleAI ( )
{
2011-06-20 14:41:04 +03:00
battleints [ 255 ] = CDynLibHandler : : getNewBattleAI ( conf . cc . defaultBattleAI ) ;
2011-02-27 21:58:14 +02:00
battleints [ 255 ] - > init ( new CBattleCallback ( gs , 255 , this ) ) ;
}
2011-05-22 21:46:52 +03:00
void CClient : : commitPackage ( CPackForClient * pack )
{
CommitPackage cp ;
2011-06-11 02:50:32 +03:00
cp . freePack = false ;
2011-05-22 21:46:52 +03:00
cp . packToCommit = pack ;
* serv < < & cp ;
}
2011-06-11 02:50:32 +03:00
int CClient : : getLocalPlayer ( ) const
{
if ( LOCPLINT )
return LOCPLINT - > playerID ;
return getCurrentPlayer ( ) ;
}
2011-06-25 17:22:19 +03:00
void CClient : : calculatePaths ( const CGHeroInstance * h )
{
assert ( h ) ;
boost : : unique_lock < boost : : mutex > pathLock ( pathMx ) ;
gs - > calculatePaths ( h , * pathInfo ) ;
}
2011-08-25 18:24:37 +03:00
void CClient : : commenceTacticPhaseForInt ( CBattleGameInterface * battleInt )
{
setThreadName ( - 1 , " CClient::commenceTacticPhaseForInt " ) ;
try
{
battleInt - > yourTacticPhase ( gs - > curB - > tacticDistance ) ;
2011-08-26 00:08:53 +03:00
if ( gs & & ! ! gs - > curB & & gs - > curB - > tacticDistance ) //while awaiting for end of tactics phase, many things can happen (end of battle... or game)
{
MakeAction ma ( BattleAction : : makeEndOFTacticPhase ( battleInt - > playerID ) ) ;
serv - > sendPack ( ma ) ;
}
2011-08-25 18:24:37 +03:00
} HANDLE_EXCEPTION
}
2011-09-03 05:54:33 +03:00
void CClient : : invalidatePaths ( const CGHeroInstance * h /*= NULL*/ )
{
if ( ! h | | pathInfo - > hero = = h )
pathInfo - > isValid = false ;
}
2009-03-28 20:46:20 +02:00
template void CClient : : serialize ( CISer < CLoadFile > & h , const int version ) ;
2009-06-06 18:17:07 +03:00
template void CClient : : serialize ( COSer < CSaveFile > & h , const int version ) ;
2010-09-03 21:42:54 +03:00
void CServerHandler : : startServer ( )
{
th . update ( ) ;
2011-06-03 06:23:50 +03:00
serverThread = new boost : : thread ( & CServerHandler : : callServer , this ) ; //runs server executable;
2010-09-03 21:42:54 +03:00
if ( verbose )
tlog0 < < " Setting up thread calling server: " < < th . getDif ( ) < < std : : endl ;
}
void CServerHandler : : waitForServer ( )
{
if ( ! serverThread )
startServer ( ) ;
th . update ( ) ;
intpr : : scoped_lock < intpr : : interprocess_mutex > slock ( shared - > sr - > mutex ) ;
while ( ! shared - > sr - > ready )
{
shared - > sr - > cond . wait ( slock ) ;
}
if ( verbose )
tlog0 < < " Waiting for server: " < < th . getDif ( ) < < std : : endl ;
}
CConnection * CServerHandler : : connectToServer ( )
{
if ( ! shared - > sr - > ready )
waitForServer ( ) ;
th . update ( ) ;
2010-10-24 14:35:14 +03:00
CConnection * ret = justConnectToServer ( conf . cc . server , port ) ;
2010-09-03 21:42:54 +03:00
if ( verbose )
tlog0 < < " \t Connecting to the server: " < < th . getDif ( ) < < std : : endl ;
return ret ;
}
2010-10-24 14:35:14 +03:00
CServerHandler : : CServerHandler ( bool runServer /*= false*/ )
2010-09-03 21:42:54 +03:00
{
serverThread = NULL ;
shared = NULL ;
port = boost : : lexical_cast < std : : string > ( conf . cc . port ) ;
2011-06-03 06:23:50 +03:00
verbose = false ;
2010-09-03 21:42:54 +03:00
boost : : interprocess : : shared_memory_object : : remove ( " vcmi_memory " ) ; //if the application has previously crashed, the memory may not have been removed. to avoid problems - try to destroy it
try
{
shared = new SharedMem ( ) ;
} HANDLE_EXCEPTIONC ( tlog1 < < " Cannot open interprocess memory: " ; )
}
CServerHandler : : ~ CServerHandler ( )
{
delete shared ;
delete serverThread ; //detaches, not kills thread
}
void CServerHandler : : callServer ( )
{
2011-02-24 15:57:47 +02:00
setThreadName ( - 1 , " CServerHandler::callServer " ) ;
2010-09-03 21:42:54 +03:00
std : : string comm = std : : string ( BIN_DIR PATH_SEPARATOR SERVER_NAME " " ) + port + " > server_log.txt " ;
std : : system ( comm . c_str ( ) ) ;
tlog0 < < " Server finished \n " ;
}
2010-10-24 14:35:14 +03:00
CConnection * CServerHandler : : justConnectToServer ( const std : : string & host , const std : : string & port )
{
CConnection * ret = NULL ;
while ( ! ret )
{
try
{
tlog0 < < " Establishing connection... \n " ;
ret = new CConnection ( host . size ( ) ? host : conf . cc . server ,
port . size ( ) ? port : boost : : lexical_cast < std : : string > ( conf . cc . port ) ,
NAME ) ;
}
catch ( . . . )
{
tlog1 < < " \n Cannot establish connection! Retrying within 2 seconds " < < std : : endl ;
SDL_Delay ( 2000 ) ;
}
}
return ret ;
2010-10-31 00:53:41 +03:00
}