2011-12-14 00:23:17 +03:00
# include "StdInc.h"
2014-07-15 10:14:49 +03:00
# include "Client.h"
# include <SDL.h>
2011-12-14 00:23:17 +03:00
2010-12-20 23:22:53 +02:00
# include "CMusicHandler.h"
2013-04-07 13:48:07 +03:00
# include "../lib/mapping/CCampaignHandler.h"
2008-07-25 20:28:28 +03:00
# include "../CCallback.h"
2011-12-14 00:23:17 +03:00
# include "../lib/CConsoleHandler.h"
2009-05-20 13:08:56 +03:00
# include "CGameInfo.h"
# include "../lib/CGameState.h"
# include "CPlayerInterface.h"
2011-12-14 00:23:17 +03:00
# include "../lib/StartInfo.h"
2010-12-25 21:23:30 +02:00
# include "../lib/BattleState.h"
2012-08-10 16:07:53 +03:00
# include "../lib/CModHandler.h"
2010-12-20 23:22:53 +02:00
# include "../lib/CArtHandler.h"
# include "../lib/CGeneralTextHandler.h"
# include "../lib/CHeroHandler.h"
# include "../lib/CTownHandler.h"
# include "../lib/CBuildingHandler.h"
2015-02-02 10:25:26 +02:00
# include "../lib/spells/CSpellHandler.h"
2008-11-09 00:29:19 +02:00
# include "../lib/Connection.h"
2014-08-26 13:19:04 +03:00
# ifndef VCMI_ANDROID
2009-01-11 00:08:18 +02:00
# include "../lib/Interprocess.h"
2014-02-20 21:53:18 +03:00
# endif
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"
2011-11-01 15:58:01 +03:00
# include "../lib/VCMIDirs.h"
2013-04-07 13:48:07 +03:00
# include "../lib/mapping/CMap.h"
2011-09-01 04:40:46 +03:00
# include "../lib/JsonNode.h"
2010-04-06 16:19:54 +03:00
# include "mapHandler.h"
2012-09-29 13:59:43 +03:00
# include "../lib/CConfigHandler.h"
2008-11-09 00:29:19 +02:00
# include "Client.h"
2010-08-20 16:34:39 +03:00
# include "CPreGame.h"
2013-04-07 14:52:07 +03:00
# include "battle/CBattleInterface.h"
2011-12-14 00:23:17 +03:00
# include "../lib/CThreadHelper.h"
2011-06-20 14:41:04 +03:00
# include "../lib/CScriptingModule.h"
2014-02-24 22:57:33 +03:00
# include "../lib/registerTypes/RegisterTypes.h"
2013-04-07 14:52:07 +03:00
# include "gui/CGuiHandler.h"
2013-06-17 18:45:55 +03:00
# include "CMT.h"
2011-05-10 01:20:47 +03:00
2009-01-11 00:08:18 +02:00
extern std : : string NAME ;
2014-08-26 13:19:04 +03:00
# ifndef VCMI_ANDROID
2009-01-11 00:08:18 +02:00
namespace intpr = boost : : interprocess ;
2014-02-20 21:53:18 +03:00
# endif
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
2013-06-26 14:18:27 +03:00
template < typename U > static CBaseForCLApply * getApplier ( const U * t = nullptr )
2010-09-03 21:42:54 +03:00
{
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 ) ;
}
} ;
2014-02-19 04:04:27 +03:00
template < > class CApplyOnCL < CPack > : public CBaseForCLApply
{
public :
void applyOnClAfter ( CClient * cl , void * pack ) const
{
logGlobal - > errorStream ( ) < < " Cannot apply on CL plain CPack! " ;
assert ( 0 ) ;
}
void applyOnClBefore ( CClient * cl , void * pack ) const
{
logGlobal - > errorStream ( ) < < " Cannot apply on CL plain CPack! " ;
assert ( 0 ) ;
}
} ;
2013-05-09 14:09:23 +03:00
static CApplier < CBaseForCLApply > * applier = nullptr ;
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 ;
2013-05-09 14:09:23 +03:00
connectionHandler = nullptr ;
pathInfo = nullptr ;
2010-09-03 21:42:54 +03:00
applier = new CApplier < CBaseForCLApply > ;
2014-02-24 22:57:33 +03:00
registerTypesClientPacks1 ( * applier ) ;
registerTypesClientPacks2 ( * applier ) ;
2009-02-01 16:11:41 +02:00
IObjectInterface : : cb = this ;
2013-05-09 14:09:23 +03:00
serv = nullptr ;
gs = nullptr ;
erm = nullptr ;
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-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
2013-03-03 20:06:03 +03:00
void CClient : : waitForMoveAndSend ( PlayerColor color )
2008-08-04 18:56:36 +03:00
{
2008-08-30 00:41:32 +03:00
try
{
2012-09-24 02:10:56 +03:00
setThreadName ( " CClient::waitForMoveAndSend " ) ;
2010-12-25 03:43:40 +02:00
assert ( vstd : : contains ( battleints , color ) ) ;
2012-08-26 12:07:48 +03:00
BattleAction ba = battleints [ color ] - > activeStack ( gs - > curB - > battleGetStackByID ( gs - > curB - > activeStack , false ) ) ;
2013-11-09 19:25:20 +03:00
logNetwork - > traceStream ( ) < < " Send battle action to server: " < < ba ;
2011-06-11 07:54:41 +03:00
MakeAction temp_action ( ba ) ;
2012-03-26 01:46:14 +03:00
sendRequest ( & temp_action , color ) ;
2008-08-30 00:41:32 +03:00
return ;
2012-02-20 00:03:43 +03:00
}
catch ( boost : : thread_interrupted & )
{
2013-04-09 17:31:36 +03:00
logNetwork - > debugStream ( ) < < " Wait for move thread was interrupted and no action will be send. Was a battle ended by spell? " ;
2012-02-20 00:03:43 +03:00
return ;
}
2015-02-14 21:42:47 +02:00
catch ( . . . )
{
handleException ( ) ;
return ;
}
2013-04-09 17:31:36 +03:00
logNetwork - > errorStream ( ) < < " We should not be here! " ;
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 ( )
{
2012-06-27 23:44:01 +03:00
setThreadName ( " CClient::run " ) ;
2009-04-11 04:32:50 +03:00
try
2008-07-25 20:28:28 +03:00
{
2009-12-28 06:08:24 +02:00
while ( ! terminate )
2009-03-07 17:54:12 +02:00
{
2013-11-07 15:48:41 +03:00
CPack * 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 )
{
2013-11-07 15:48:41 +03:00
vstd : : clear_pointer ( pack ) ;
2009-11-01 03:15:16 +02:00
break ;
}
2010-01-02 03:48:44 +02:00
handlePack ( pack ) ;
2009-03-07 17:54:12 +02:00
}
2010-01-29 22:52:45 +02:00
}
2012-06-16 20:12:58 +03:00
//catch only asio exceptions
catch ( const boost : : system : : system_error & e )
2010-01-29 22:52:45 +02:00
{
2013-04-09 17:31:36 +03:00
logNetwork - > errorStream ( ) < < " Lost connection to server, ending listening thread! " ;
logNetwork - > errorStream ( ) < < e . what ( ) ;
2010-01-29 22:52:45 +02:00
if ( ! terminate ) //rethrow (-> boom!) only if closing connection was unexpected
{
2013-04-09 17:31:36 +03:00
logNetwork - > errorStream ( ) < < " Something wrong, lost connection while game is still ongoing... " ;
2010-01-29 22:52:45 +02:00
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 )
{
2013-04-09 17:31:36 +03:00
logNetwork - > errorStream ( ) < < " Game cannot be saved during battle! " ;
2009-02-11 19:03:30 +02:00
return ;
}
2011-06-11 07:54:41 +03:00
SaveGame save_game ( fname ) ;
2013-03-03 20:06:03 +03:00
sendRequest ( ( CPackForClient * ) & save_game , PlayerColor : : NEUTRAL ) ;
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
{
2012-02-22 16:41:27 +03:00
//suggest interfaces to finish their stuff (AI should interrupt any bg working threads)
2013-06-29 16:05:48 +03:00
for ( auto i : playerint )
2012-02-22 16:41:27 +03:00
i . second - > finish ( ) ;
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 ( ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Closed connection. " ;
2011-05-30 02:49:25 +03:00
2013-06-26 14:18:27 +03:00
GH . curInt = nullptr ;
2012-02-20 00:03:43 +03:00
{
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Ending current game! " ;
2012-02-20 00:03:43 +03:00
if ( GH . topInt ( ) )
GH . topInt ( ) - > deactivate ( ) ;
GH . listInt . clear ( ) ;
GH . objsToBlit . clear ( ) ;
2013-06-26 14:18:27 +03:00
GH . statusbar = nullptr ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Removed GUI. " ;
2012-02-20 00:03:43 +03:00
2013-05-09 14:09:23 +03:00
vstd : : clear_pointer ( const_cast < CGameInfo * > ( CGI ) - > mh ) ;
vstd : : clear_pointer ( gs ) ;
2012-02-20 00:03:43 +03:00
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Deleted mapHandler and gameState. " ;
2013-06-26 14:18:27 +03:00
LOCPLINT = nullptr ;
2012-02-20 00:03:43 +03:00
}
2009-06-23 11:14:49 +03:00
2013-06-23 00:47:51 +03:00
playerint . clear ( ) ;
2013-12-06 22:44:11 +03:00
battleints . clear ( ) ;
2011-09-06 09:00:32 +03:00
callbacks . clear ( ) ;
2013-06-22 17:47:20 +03:00
battleCallbacks . clear ( ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Deleted playerInts. " ;
2009-11-01 03:15:16 +02:00
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Client stopped. " ;
2009-11-01 03:15:16 +02:00
}
2014-10-21 15:11:54 +03:00
# if 1
void CClient : : loadGame ( const std : : string & fname , const bool server , const std : : vector < int > & humanplayerindices , const int loadNumPlayers , int player_ , const std : : string & ipaddr , const std : : string & port )
{
2014-10-24 06:15:41 +03:00
PlayerColor player ( player_ ) ; //intentional shadowing
2014-10-21 15:11:54 +03:00
logNetwork - > infoStream ( ) < < " Loading procedure started! " ;
CServerHandler sh ;
2014-10-20 05:13:10 +03:00
if ( server )
2014-10-21 15:11:54 +03:00
sh . startServer ( ) ;
else
serv = sh . justConnectToServer ( ipaddr , port = = " " ? " 3030 " : port ) ;
CStopWatch tmh ;
unique_ptr < CLoadFile > loader ;
try
{
std : : string clientSaveName = * CResourceHandler : : get ( " local " ) - > getResourceName ( ResourceID ( fname , EResType : : CLIENT_SAVEGAME ) ) ;
std : : string controlServerSaveName ;
if ( CResourceHandler : : get ( " local " ) - > existsResource ( ResourceID ( fname , EResType : : SERVER_SAVEGAME ) ) )
{
controlServerSaveName = * CResourceHandler : : get ( " local " ) - > getResourceName ( ResourceID ( fname , EResType : : SERVER_SAVEGAME ) ) ;
}
else // create entry for server savegame. Triggered if save was made after launch and not yet present in res handler
{
controlServerSaveName = clientSaveName . substr ( 0 , clientSaveName . find_last_of ( " . " ) ) + " .vsgm1 " ;
CResourceHandler : : get ( " local " ) - > createResource ( controlServerSaveName , true ) ;
}
if ( clientSaveName . empty ( ) )
throw std : : runtime_error ( " Cannot open client part of " + fname ) ;
if ( controlServerSaveName . empty ( ) )
throw std : : runtime_error ( " Cannot open server part of " + fname ) ;
{
CLoadIntegrityValidator checkingLoader ( clientSaveName , controlServerSaveName , minSupportedVersion ) ;
loadCommonState ( checkingLoader ) ;
loader = checkingLoader . decay ( ) ;
}
logNetwork - > infoStream ( ) < < " Loaded common part of save " < < tmh . getDiff ( ) ;
const_cast < CGameInfo * > ( CGI ) - > mh = new CMapHandler ( ) ;
const_cast < CGameInfo * > ( CGI ) - > mh - > map = gs - > map ;
pathInfo = make_unique < CPathsInfo > ( getMapSize ( ) ) ;
CGI - > mh - > init ( ) ;
logNetwork - > infoStream ( ) < < " Initing maphandler: " < < tmh . getDiff ( ) ;
}
catch ( std : : exception & e )
{
logGlobal - > errorStream ( ) < < " Cannot load game " < < fname < < " . Error: " < < e . what ( ) ;
throw ; //obviously we cannot continue here
}
2014-10-19 14:47:09 +03:00
2014-10-24 06:15:41 +03:00
/*
if ( ! server )
player = PlayerColor ( player_ ) ;
*/
2014-10-21 15:11:54 +03:00
std : : set < PlayerColor > clientPlayers ;
if ( server )
serv = sh . connectToServer ( ) ;
//*loader >> *this;
2014-10-19 14:47:09 +03:00
if ( server )
{
tmh . update ( ) ;
ui8 pom8 ;
* serv < < ui8 ( 3 ) < < ui8 ( loadNumPlayers ) ; //load game; one client if single-player
* serv < < fname ;
* serv > > pom8 ;
if ( pom8 )
throw std : : runtime_error ( " Server cannot open the savegame! " ) ;
else
logNetwork - > infoStream ( ) < < " Server opened savegame properly. " ;
}
if ( server )
{
2014-10-20 05:13:10 +03:00
for ( auto & elem : gs - > scenarioOps - > playerInfos )
if ( ! std : : count ( humanplayerindices . begin ( ) , humanplayerindices . end ( ) , elem . first . getNum ( ) ) | | elem . first = = player )
{
2014-10-21 15:11:54 +03:00
clientPlayers . insert ( elem . first ) ;
2014-10-20 05:13:10 +03:00
}
2014-10-21 15:11:54 +03:00
clientPlayers . insert ( PlayerColor : : NEUTRAL ) ;
2014-10-19 14:47:09 +03:00
}
else
{
2014-10-24 06:15:41 +03:00
clientPlayers . insert ( player ) ;
2014-10-19 14:47:09 +03:00
}
2009-01-11 00:08:18 +02:00
2014-10-24 06:15:41 +03:00
std : : cout < < " CLIENTPLAYERS: \n " ;
for ( auto x : clientPlayers )
std : : cout < < x < < std : : endl ;
std : : cout < < " ENDCLIENTPLAYERS \n " ;
2014-12-21 16:27:50 +02:00
serialize ( loader - > serializer , 0 , clientPlayers ) ;
2014-10-21 15:11:54 +03:00
* serv < < ui32 ( clientPlayers . size ( ) ) ;
for ( auto & elem : clientPlayers )
* serv < < ui8 ( elem . getNum ( ) ) ;
serv - > addStdVecItems ( gs ) ; /*why is this here?*/
//*loader >> *this;
logNetwork - > infoStream ( ) < < " Loaded client part of save " < < tmh . getDiff ( ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Sent info to server: " < < tmh . getDiff ( ) ;
2012-09-28 12:11:18 +03:00
2014-10-21 15:11:54 +03:00
//*serv << clientPlayers;
2014-10-20 05:13:10 +03:00
serv - > enableStackSendingByID ( ) ;
serv - > disableSmartPointerSerialization ( ) ;
2012-09-28 12:11:18 +03:00
2013-08-18 18:46:28 +03:00
// logGlobal->traceStream() << "Objects:";
// for(int i = 0; i < gs->map->objects.size(); i++)
// {
// auto o = gs->map->objects[i];
// if(o)
// logGlobal->traceStream() << boost::format("\tindex=%5d, id=%5d; address=%5d, pos=%s, name=%s") % i % o->id % (int)o.get() % o->pos % o->getHoverText();
// else
// logGlobal->traceStream() << boost::format("\tindex=%5d --- nullptr") % i;
// }
2009-01-11 00:08:18 +02:00
}
2014-10-21 15:11:54 +03:00
# endif
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 ;
2013-06-26 14:18:27 +03:00
if ( con = = nullptr )
2009-12-20 19:14:14 +02:00
{
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
}
2013-05-09 14:09:23 +03:00
CConnection & c = * serv ;
2009-01-11 00:08:18 +02:00
////////////////////////////////////////////////////
2010-10-24 14:35:14 +03:00
2013-05-09 14:09:23 +03:00
logNetwork - > infoStream ( ) < < " \t Will send info to server... " ;
CStopWatch tmh ;
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 ;
2014-01-30 21:56:31 +03:00
if ( pom8 ) throw std : : runtime_error ( " Server cannot open the map! " ) ;
2009-01-11 00:08:18 +02:00
}
2010-10-24 14:35:14 +03:00
2012-04-14 05:20:22 +03:00
c > > si ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " \t Sending/Getting info to/from the server: " < < tmh . getDiff ( ) ;
2012-09-25 21:00:55 +03:00
c . enableStackSendingByID ( ) ;
c . disableSmartPointerSerialization ( ) ;
2009-01-11 00:08:18 +02:00
2013-01-21 23:49:19 +03:00
// Initialize game state
2013-05-09 14:09:23 +03:00
gs = new CGameState ( ) ;
logNetwork - > infoStream ( ) < < " \t Creating gamestate: " < < tmh . getDiff ( ) ;
2009-01-11 00:08:18 +02:00
gs - > scenarioOps = si ;
2012-04-14 05:20:22 +03:00
gs - > init ( si ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Initializing GameState (together): " < < tmh . getDiff ( ) ;
2010-12-22 22:14:40 +02:00
2013-01-21 23:49:19 +03:00
// Now after possible random map gen, we know exact player count.
// Inform server about how many players client handles
2013-03-03 20:06:03 +03:00
std : : set < PlayerColor > myPlayers ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : gs - > scenarioOps - > playerInfos )
2013-01-21 23:49:19 +03:00
{
if ( ( networkMode = = SINGLE ) //single - one client has all player
2013-06-29 16:05:48 +03:00
| | ( networkMode ! = SINGLE & & serv - > connectionID = = elem . second . playerID ) //multi - client has only "its players"
| | ( networkMode = = HOST & & elem . second . playerID = = PlayerSettings : : PLAYER_AI ) ) //multi - host has all AI players
2013-01-21 23:49:19 +03:00
{
2013-06-29 16:05:48 +03:00
myPlayers . insert ( elem . first ) ; //add player
2013-01-21 23:49:19 +03:00
}
}
if ( networkMode ! = GUEST )
2013-03-03 20:06:03 +03:00
myPlayers . insert ( PlayerColor : : NEUTRAL ) ;
2013-01-21 23:49:19 +03:00
c < < myPlayers ;
// Init map handler
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 ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Creating mapHandler: " < < tmh . getDiff ( ) ;
2011-09-03 06:04:06 +03:00
CGI - > mh - > init ( ) ;
2013-05-09 14:09:23 +03:00
pathInfo = make_unique < CPathsInfo > ( getMapSize ( ) ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Initializing mapHandler (together): " < < tmh . getDiff ( ) ;
2010-12-22 22:14:40 +02:00
}
2009-01-11 00:08:18 +02:00
2010-02-20 15:24:38 +02:00
int humanPlayers = 0 ;
2013-06-29 16:05:48 +03:00
for ( auto & elem : gs - > scenarioOps - > playerInfos ) //initializing interfaces for players
2013-02-19 02:10:46 +03:00
{
2013-06-29 16:05:48 +03:00
PlayerColor color = elem . 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 ;
2013-04-09 17:31:36 +03:00
logNetwork - > traceStream ( ) < < " Preparing interface for player " < < color ;
2010-12-22 22:14:40 +02:00
if ( si - > mode ! = StartInfo : : DUEL )
2010-02-20 15:24:38 +02:00
{
2013-06-29 16:05:48 +03:00
if ( elem . second . playerID = = PlayerSettings : : PLAYER_AI )
2010-12-22 22:14:40 +02:00
{
2013-06-29 16:05:48 +03:00
auto AiToGive = aiNameForPlayer ( elem . second , false ) ;
2013-06-22 17:47:20 +03:00
logNetwork - > infoStream ( ) < < boost : : format ( " Player %s will be lead by %s " ) % color % AiToGive ;
installNewPlayerInterface ( CDynLibHandler : : getNewAI ( AiToGive ) , color ) ;
2010-12-22 22:14:40 +02:00
}
else
{
2013-06-23 00:47:51 +03:00
installNewPlayerInterface ( make_shared < CPlayerInterface > ( color ) , color ) ;
2010-12-22 22:14:40 +02:00
humanPlayers + + ;
}
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
{
2013-06-29 16:05:48 +03:00
std : : string AItoGive = aiNameForPlayer ( elem . second , true ) ;
2013-06-22 17:47:20 +03:00
installNewBattleInterface ( CDynLibHandler : : getNewBattleAI ( AItoGive ) , color ) ;
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 )
{
2013-06-17 18:45:55 +03:00
if ( ! gNoGUI )
{
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
2013-06-23 00:47:51 +03:00
auto p = make_shared < CPlayerInterface > ( PlayerColor : : NEUTRAL ) ;
2013-06-17 18:45:55 +03:00
p - > observerInDuelMode = true ;
2013-06-22 17:47:20 +03:00
installNewPlayerInterface ( p , boost : : none ) ;
2013-06-23 00:47:51 +03:00
GH . curInt = p . get ( ) ;
2013-06-17 18:45:55 +03:00
}
2010-12-23 02:33:48 +02:00
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
2013-05-09 14:09:23 +03:00
serv - > addStdVecItems ( gs ) ;
2010-02-20 15:24:38 +02:00
hotSeat = ( humanPlayers > 1 ) ;
2011-07-17 21:49:05 +03:00
// std::vector<FileInfo> scriptModules;
2013-04-13 14:07:32 +03:00
// CFileUtility::getFilesWithExt(scriptModules, LIB_DIR "/scripting", "." LIB_EXT);
2013-06-29 16:05:48 +03:00
// for(FileInfo &m : scriptModules)
2011-07-17 21:49:05 +03:00
// {
// 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
}
2014-12-21 21:33:20 +02:00
void CClient : : serialize ( COSer & h , const int version )
2009-03-28 20:46:20 +02:00
{
2014-12-21 21:33:20 +02:00
assert ( h . saving ) ;
h & hotSeat ;
2009-03-28 20:46:20 +02:00
{
ui8 players = playerint . size ( ) ;
h & players ;
2013-03-03 20:06:03 +03:00
for ( auto i = playerint . begin ( ) ; i ! = playerint . end ( ) ; i + + )
2009-03-28 20:46:20 +02:00
{
2013-05-09 14:09:23 +03:00
LOG_TRACE_PARAMS ( logGlobal , " Saving player %s interface " , i - > first ) ;
assert ( i - > first = = i - > second - > playerID ) ;
h & i - > first & i - > second - > dllName & i - > second - > human ;
2014-12-21 21:33:20 +02:00
i - > second - > saveGame ( h , version ) ;
2009-03-28 20:46:20 +02:00
}
}
2014-12-21 21:33:20 +02:00
}
void CClient : : serialize ( CISer & h , const int version )
{
assert ( ! h . saving ) ;
h & hotSeat ;
2009-03-28 20:46:20 +02:00
{
2013-01-21 01:49:34 +03:00
ui8 players = 0 ; //fix for uninitialized warning
2009-03-28 20:46:20 +02:00
h & players ;
for ( int i = 0 ; i < players ; i + + )
{
std : : string dllname ;
2013-05-09 14:09:23 +03:00
PlayerColor pid ;
bool isHuman = false ;
2009-03-28 20:46:20 +02:00
2013-05-09 14:09:23 +03:00
h & pid & dllname & isHuman ;
LOG_TRACE_PARAMS ( logGlobal , " Loading player %s interface " , pid ) ;
2009-07-18 06:13:13 +03:00
2013-06-23 22:35:54 +03:00
shared_ptr < CGameInterface > nInt ;
2009-03-28 20:46:20 +02:00
if ( dllname . length ( ) )
2011-02-23 05:57:45 +02:00
{
2013-03-03 20:06:03 +03:00
if ( pid = = PlayerColor : : NEUTRAL )
2011-02-23 05:57:45 +02:00
{
2013-06-22 17:47:20 +03:00
installNewBattleInterface ( CDynLibHandler : : getNewBattleAI ( dllname ) , pid ) ;
2011-02-23 05:57:45 +02:00
//TODO? consider serialization
continue ;
}
else
2013-05-09 14:09:23 +03:00
{
assert ( ! isHuman ) ;
2011-06-20 14:41:04 +03:00
nInt = CDynLibHandler : : getNewAI ( dllname ) ;
2013-05-09 14:09:23 +03:00
}
2011-02-23 05:57:45 +02:00
}
2009-07-18 06:13:13 +03:00
else
2013-05-09 14:09:23 +03:00
{
assert ( isHuman ) ;
2013-06-23 00:47:51 +03:00
nInt = make_shared < CPlayerInterface > ( pid ) ;
2013-05-09 14:09:23 +03:00
}
nInt - > dllName = dllname ;
nInt - > human = isHuman ;
nInt - > playerID = pid ;
2009-07-18 06:13:13 +03:00
2013-06-22 17:47:20 +03:00
installNewPlayerInterface ( nInt , pid ) ;
2014-12-21 21:33:20 +02:00
nInt - > loadGame ( h , version ) ; //another evil cast, check above
2009-03-28 20:46:20 +02:00
}
2011-02-27 21:58:14 +02:00
2013-03-03 20:06:03 +03:00
if ( ! vstd : : contains ( battleints , PlayerColor : : NEUTRAL ) )
2011-02-27 21:58:14 +02:00
loadNeutralBattleAI ( ) ;
2009-03-28 20:46:20 +02:00
}
}
2014-12-21 21:33:20 +02:00
void CClient : : serialize ( COSer & h , const int version , const std : : set < PlayerColor > & playerIDs )
2014-10-21 15:11:54 +03:00
{
2014-12-21 21:33:20 +02:00
assert ( h . saving ) ;
2014-10-21 15:11:54 +03:00
h & hotSeat ;
{
ui8 players = playerint . size ( ) ;
h & players ;
for ( auto i = playerint . begin ( ) ; i ! = playerint . end ( ) ; i + + )
{
LOG_TRACE_PARAMS ( logGlobal , " Saving player %s interface " , i - > first ) ;
assert ( i - > first = = i - > second - > playerID ) ;
h & i - > first & i - > second - > dllName & i - > second - > human ;
2014-12-21 21:33:20 +02:00
i - > second - > saveGame ( h , version ) ;
2014-10-21 15:11:54 +03:00
}
}
2014-12-21 21:33:20 +02:00
}
void CClient : : serialize ( CISer & h , const int version , const std : : set < PlayerColor > & playerIDs )
{
assert ( ! h . saving ) ;
h & hotSeat ;
2014-10-21 15:11:54 +03:00
{
ui8 players = 0 ; //fix for uninitialized warning
h & players ;
for ( int i = 0 ; i < players ; i + + )
{
std : : string dllname ;
PlayerColor pid ;
bool isHuman = false ;
h & pid & dllname & isHuman ;
LOG_TRACE_PARAMS ( logGlobal , " Loading player %s interface " , pid ) ;
shared_ptr < CGameInterface > nInt ;
if ( dllname . length ( ) )
{
if ( pid = = PlayerColor : : NEUTRAL )
{
2014-10-24 05:18:42 +03:00
if ( playerIDs . count ( pid ) )
installNewBattleInterface ( CDynLibHandler : : getNewBattleAI ( dllname ) , pid ) ;
2014-10-21 15:11:54 +03:00
//TODO? consider serialization
continue ;
}
2014-10-24 05:18:42 +03:00
else
2014-10-21 15:11:54 +03:00
{
assert ( ! isHuman ) ;
nInt = CDynLibHandler : : getNewAI ( dllname ) ;
}
}
else
{
assert ( isHuman ) ;
nInt = make_shared < CPlayerInterface > ( pid ) ;
}
nInt - > dllName = dllname ;
nInt - > human = isHuman ;
nInt - > playerID = pid ;
if ( playerIDs . count ( pid ) )
2014-10-25 12:04:08 +03:00
installNewPlayerInterface ( nInt , pid ) ;
2014-12-21 21:33:20 +02:00
nInt - > loadGame ( h , version ) ;
2014-10-21 15:11:54 +03:00
}
2014-10-25 12:39:12 +03:00
if ( playerIDs . count ( PlayerColor : : NEUTRAL ) )
loadNeutralBattleAI ( ) ;
2014-10-21 15:11:54 +03:00
}
}
2010-01-02 03:48:44 +02:00
void CClient : : handlePack ( CPack * pack )
2014-10-25 12:04:08 +03:00
{
2010-01-02 03:48:44 +02:00
CBaseForCLApply * apply = applier - > apps [ typeList . getTypeID ( pack ) ] ; //find the applier
if ( apply )
{
2012-04-06 18:02:15 +03:00
boost : : unique_lock < boost : : recursive_mutex > guiLock ( * LOCPLINT - > pim ) ;
2010-01-02 03:48:44 +02:00
apply - > applyOnClBefore ( this , pack ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > traceStream ( ) < < " \t Made first apply on cl " ;
2010-01-02 03:48:44 +02:00
gs - > apply ( pack ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > traceStream ( ) < < " \t Applied on gs " ;
2010-01-02 03:48:44 +02:00
apply - > applyOnClAfter ( this , pack ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > traceStream ( ) < < " \t Made second apply on cl " ;
2010-01-02 03:48:44 +02:00
}
else
{
2013-04-09 17:31:36 +03:00
logNetwork - > errorStream ( ) < < " Message cannot be applied, cannot find applier! TypeID " < < typeList . getTypeID ( pack ) ;
2010-01-02 03:48:44 +02:00
}
delete pack ;
}
2009-08-04 02:53:18 +03:00
2012-09-21 20:59:54 +03:00
void CClient : : finishCampaign ( shared_ptr < CCampaignState > camp )
2010-08-20 16:34:39 +03:00
{
}
2012-09-21 20:59:54 +03:00
void CClient : : proposeNextMission ( shared_ptr < CCampaignState > camp )
2010-08-20 16:34:39 +03:00
{
GH . pushInt ( new CBonusSelection ( camp ) ) ;
}
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
{
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Connection has been requested to be closed. " ;
2010-08-20 16:34:39 +03:00
boost : : unique_lock < boost : : mutex > ( * serv - > wmx ) ;
2011-06-11 07:54:41 +03:00
CloseServer close_server ;
2013-03-03 20:06:03 +03:00
sendRequest ( & close_server , PlayerColor : : NEUTRAL ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Sent closing signal to the server " ;
2010-08-20 16:34:39 +03:00
}
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 ( ) ;
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Connection handler thread joined " ;
2010-08-20 16:34:39 +03:00
delete connectionHandler ;
2013-06-26 14:18:27 +03:00
connectionHandler = nullptr ;
2010-08-20 16:34:39 +03:00
}
2011-01-17 18:07:08 +02:00
if ( serv ) //and delete connection
{
serv - > close ( ) ;
delete serv ;
2013-06-26 14:18:27 +03:00
serv = nullptr ;
2013-04-09 17:31:36 +03:00
logNetwork - > warnStream ( ) < < " Our socket has been closed. " ;
2011-01-17 18:07:08 +02:00
}
2010-08-20 16:34:39 +03:00
}
2010-12-23 02:33:48 +02:00
void CClient : : battleStarted ( const BattleInfo * info )
{
2013-06-29 16:05:48 +03:00
for ( auto & battleCb : battleCallbacks )
2012-08-26 12:07:48 +03:00
{
2013-07-22 01:01:29 +03:00
if ( vstd : : contains_if ( info - > sides , [ & ] ( const SideInBattle & side ) { return side . color = = battleCb . first ; } )
| | battleCb . first > = PlayerColor : : PLAYER_LIMIT )
{
2012-08-26 12:07:48 +03:00
battleCb . second - > setBattle ( info ) ;
2013-07-22 01:01:29 +03:00
}
2012-08-26 12:07:48 +03:00
}
2013-06-29 16:05:48 +03:00
// for(ui8 side : info->sides)
2012-08-26 12:07:48 +03:00
// if(battleCallbacks.count(side))
// battleCallbacks[side]->setBattle(info);
2013-06-23 22:35:54 +03:00
shared_ptr < CPlayerInterface > att , def ;
2013-07-22 01:01:29 +03:00
auto & leftSide = info - > sides [ 0 ] , & rightSide = info - > sides [ 1 ] ;
2010-12-23 02:33:48 +02:00
2013-06-23 14:25:48 +03:00
//If quick combat is not, do not prepare interfaces for battleint
if ( ! settings [ " adventure " ] [ " quickCombat " ] . Bool ( ) )
{
2013-07-22 01:01:29 +03:00
if ( vstd : : contains ( playerint , leftSide . color ) & & playerint [ leftSide . color ] - > human )
att = std : : dynamic_pointer_cast < CPlayerInterface > ( playerint [ leftSide . color ] ) ;
2013-06-23 14:25:48 +03:00
2013-07-22 01:01:29 +03:00
if ( vstd : : contains ( playerint , rightSide . color ) & & playerint [ rightSide . color ] - > human )
def = std : : dynamic_pointer_cast < CPlayerInterface > ( playerint [ rightSide . color ] ) ;
2013-06-23 14:25:48 +03:00
}
2010-12-23 02:33:48 +02:00
2013-06-23 00:47:51 +03:00
if ( ! gNoGUI & & ( ! ! att | | ! ! def | | gs - > scenarioOps - > mode = = StartInfo : : DUEL ) )
2012-02-20 00:03:43 +03:00
{
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
2013-09-02 01:55:57 +03:00
auto bi = new CBattleInterface ( leftSide . armyObject , rightSide . armyObject , leftSide . hero , rightSide . hero ,
2012-04-20 00:21:11 +03:00
Rect ( ( screen - > w - 800 ) / 2 ,
( screen - > h - 600 ) / 2 , 800 , 600 ) , att , def ) ;
2013-09-02 01:55:57 +03:00
GH . pushInt ( bi ) ;
2012-02-20 00:03:43 +03:00
}
2010-12-23 02:33:48 +02:00
2013-07-22 01:01:29 +03:00
auto callBattleStart = [ & ] ( PlayerColor color , ui8 side ) {
if ( vstd : : contains ( battleints , color ) )
battleints [ color ] - > battleStart ( leftSide . armyObject , rightSide . armyObject , info - > tile , leftSide . hero , rightSide . hero , side ) ;
} ;
callBattleStart ( leftSide . color , 0 ) ;
2013-07-22 19:23:23 +03:00
callBattleStart ( rightSide . color , 1 ) ;
2013-07-22 01:01:29 +03:00
callBattleStart ( PlayerColor : : UNFLAGGABLE , 1 ) ;
2011-08-25 18:24:37 +03:00
2013-07-22 01:01:29 +03:00
if ( info - > tacticDistance & & vstd : : contains ( battleints , info - > sides [ info - > tacticsSide ] . color ) )
2011-08-25 18:24:37 +03:00
{
2013-07-22 01:01:29 +03:00
boost : : thread ( & CClient : : commenceTacticPhaseForInt , this , battleints [ info - > sides [ info - > tacticsSide ] . color ] ) ;
2011-08-25 18:24:37 +03:00
}
2010-12-23 02:33:48 +02:00
}
2012-08-26 12:07:48 +03:00
void CClient : : battleFinished ( )
{
2013-07-22 01:01:29 +03:00
for ( auto & side : gs - > curB - > sides )
if ( battleCallbacks . count ( side . color ) )
battleCallbacks [ side . color ] - > setBattle ( nullptr ) ;
2012-08-26 12:07:48 +03:00
}
2011-02-27 21:58:14 +02:00
void CClient : : loadNeutralBattleAI ( )
{
2013-06-22 17:47:20 +03:00
installNewBattleInterface ( CDynLibHandler : : getNewBattleAI ( settings [ " server " ] [ " neutralAI " ] . String ( ) ) , PlayerColor : : NEUTRAL ) ;
2011-02-27 21:58:14 +02:00
}
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 ;
2013-03-03 20:06:03 +03:00
sendRequest ( & cp , PlayerColor : : NEUTRAL ) ;
2011-05-22 21:46:52 +03:00
}
2013-03-03 20:06:03 +03:00
PlayerColor CClient : : getLocalPlayer ( ) const
2011-06-11 02:50:32 +03:00
{
if ( LOCPLINT )
return LOCPLINT - > playerID ;
return getCurrentPlayer ( ) ;
}
2013-06-23 00:47:51 +03:00
void CClient : : commenceTacticPhaseForInt ( shared_ptr < CBattleGameInterface > battleInt )
2011-08-25 18:24:37 +03:00
{
2012-06-27 23:44:01 +03:00
setThreadName ( " CClient::commenceTacticPhaseForInt " ) ;
2011-08-25 18:24:37 +03:00
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)
{
2013-03-03 20:06:03 +03:00
MakeAction ma ( BattleAction : : makeEndOFTacticPhase ( gs - > curB - > playerToSide ( battleInt - > playerID ) ) ) ;
2012-03-26 01:46:14 +03:00
sendRequest ( & ma , battleInt - > playerID ) ;
2011-08-26 00:08:53 +03:00
}
2015-02-14 21:42:47 +02:00
}
catch ( . . . )
{
handleException ( ) ;
}
2011-08-25 18:24:37 +03:00
}
2014-09-21 16:42:08 +03:00
void CClient : : invalidatePaths ( )
{
// turn pathfinding info into invalid. It will be regenerated later
boost : : unique_lock < boost : : mutex > pathLock ( pathInfo - > pathMx ) ;
pathInfo - > hero = nullptr ;
}
const CPathsInfo * CClient : : getPathsInfo ( const CGHeroInstance * h )
2011-09-03 05:54:33 +03:00
{
2014-09-21 16:42:08 +03:00
assert ( h ) ;
boost : : unique_lock < boost : : mutex > pathLock ( pathInfo - > pathMx ) ;
if ( pathInfo - > hero ! = h )
{
gs - > calculatePaths ( h , * pathInfo . get ( ) ) ;
}
return pathInfo . get ( ) ;
2011-09-03 05:54:33 +03:00
}
2013-03-03 20:06:03 +03:00
int CClient : : sendRequest ( const CPack * request , PlayerColor player )
2012-03-26 01:46:14 +03:00
{
static ui32 requestCounter = 0 ;
ui32 requestID = requestCounter + + ;
2013-04-09 17:31:36 +03:00
logNetwork - > traceStream ( ) < < boost : : format ( " Sending a request \" %s \" . It'll have an ID=%d. " )
2012-03-26 01:46:14 +03:00
% typeid ( * request ) . name ( ) % requestID ;
waitingRequest . pushBack ( requestID ) ;
serv - > sendPackToServer ( * request , player , requestID ) ;
2012-07-15 18:34:00 +03:00
if ( vstd : : contains ( playerint , player ) )
playerint [ player ] - > requestSent ( dynamic_cast < const CPackForServer * > ( request ) , requestID ) ;
2012-03-26 01:46:14 +03:00
return requestID ;
}
2013-02-23 22:16:14 +03:00
void CClient : : campaignMapFinished ( shared_ptr < CCampaignState > camp )
{
endGame ( false ) ;
GH . curInt = CGPreGame : : create ( ) ;
auto & epilogue = camp - > camp - > scenarios [ camp - > mapsConquered . back ( ) ] . epilog ;
2013-11-10 18:04:29 +03:00
auto finisher = [ = ] ( )
2013-02-23 22:16:14 +03:00
{
if ( camp - > mapsRemaining . size ( ) )
proposeNextMission ( camp ) ;
else
finishCampaign ( camp ) ;
} ;
if ( epilogue . hasPrologEpilog )
{
GH . pushInt ( new CPrologEpilogVideo ( epilogue , finisher ) ) ;
}
else
{
finisher ( ) ;
}
}
2013-06-23 00:47:51 +03:00
void CClient : : installNewPlayerInterface ( shared_ptr < CGameInterface > gameInterface , boost : : optional < PlayerColor > color )
2013-06-22 17:47:20 +03:00
{
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
PlayerColor colorUsed = color . get_value_or ( PlayerColor : : UNFLAGGABLE ) ;
2014-10-24 05:18:42 +03:00
if ( ! color )
2013-06-22 17:47:20 +03:00
privilagedGameEventReceivers . push_back ( gameInterface ) ;
playerint [ colorUsed ] = gameInterface ;
logGlobal - > traceStream ( ) < < boost : : format ( " \t Initializing the interface for player %s " ) % colorUsed ;
auto cb = make_shared < CCallback > ( gs , color , this ) ;
callbacks [ colorUsed ] = cb ;
battleCallbacks [ colorUsed ] = cb ;
gameInterface - > init ( cb ) ;
installNewBattleInterface ( gameInterface , color , false ) ;
}
2013-06-23 00:47:51 +03:00
void CClient : : installNewBattleInterface ( shared_ptr < CBattleGameInterface > battleInterface , boost : : optional < PlayerColor > color , bool needCallback /*= true*/ )
2013-06-22 17:47:20 +03:00
{
boost : : unique_lock < boost : : recursive_mutex > un ( * LOCPLINT - > pim ) ;
PlayerColor colorUsed = color . get_value_or ( PlayerColor : : UNFLAGGABLE ) ;
if ( ! color )
privilagedBattleEventReceivers . push_back ( battleInterface ) ;
battleints [ colorUsed ] = battleInterface ;
if ( needCallback )
{
logGlobal - > traceStream ( ) < < boost : : format ( " \t Initializing the battle interface for player %s " ) % * color ;
auto cbc = make_shared < CBattleCallback > ( gs , color , this ) ;
battleCallbacks [ colorUsed ] = cbc ;
battleInterface - > init ( cbc ) ;
}
}
std : : string CClient : : aiNameForPlayer ( const PlayerSettings & ps , bool battleAI )
{
if ( ps . name . size ( ) )
{
2014-08-27 13:31:58 +03:00
const boost : : filesystem : : path aiPath =
VCMIDirs : : get ( ) . libraryPath ( ) / " AI " / VCMIDirs : : get ( ) . libraryName ( ps . name ) ;
if ( boost : : filesystem : : exists ( aiPath ) )
2013-06-22 17:47:20 +03:00
return ps . name ;
}
const int sensibleAILimit = settings [ " session " ] [ " oneGoodAI " ] . Bool ( ) ? 1 : PlayerColor : : PLAYER_LIMIT_I ;
std : : string goodAI = battleAI ? settings [ " server " ] [ " neutralAI " ] . String ( ) : settings [ " server " ] [ " playerAI " ] . String ( ) ;
std : : string badAI = battleAI ? " StupidAI " : " EmptyAI " ;
//TODO what about human players
if ( battleints . size ( ) > = sensibleAILimit )
return badAI ;
return goodAI ;
}
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 )
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Setting up thread calling server: " < < th . getDiff ( ) ;
2010-09-03 21:42:54 +03:00
}
void CServerHandler : : waitForServer ( )
{
if ( ! serverThread )
startServer ( ) ;
th . update ( ) ;
2014-08-26 13:19:04 +03:00
# ifndef VCMI_ANDROID
2010-09-03 21:42:54 +03:00
intpr : : scoped_lock < intpr : : interprocess_mutex > slock ( shared - > sr - > mutex ) ;
while ( ! shared - > sr - > ready )
{
shared - > sr - > cond . wait ( slock ) ;
}
2014-02-20 21:53:18 +03:00
# endif
2010-09-03 21:42:54 +03:00
if ( verbose )
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Waiting for server: " < < th . getDiff ( ) ;
2010-09-03 21:42:54 +03:00
}
CConnection * CServerHandler : : connectToServer ( )
{
2014-08-26 13:19:04 +03:00
# ifndef VCMI_ANDROID
2010-09-03 21:42:54 +03:00
if ( ! shared - > sr - > ready )
waitForServer ( ) ;
2014-02-20 21:53:18 +03:00
# else
waitForServer ( ) ;
# endif
2010-09-03 21:42:54 +03:00
2012-09-22 18:16:45 +03:00
th . update ( ) ; //put breakpoint here to attach to server before it does something stupid
2014-10-19 14:47:09 +03:00
2012-01-12 18:23:00 +03:00
CConnection * ret = justConnectToServer ( settings [ " server " ] [ " server " ] . String ( ) , port ) ;
2010-10-24 14:35:14 +03:00
2010-09-03 21:42:54 +03:00
if ( verbose )
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " \t Connecting to the server: " < < th . getDiff ( ) ;
2010-09-03 21:42:54 +03:00
return ret ;
}
2010-10-24 14:35:14 +03:00
CServerHandler : : CServerHandler ( bool runServer /*= false*/ )
2010-09-03 21:42:54 +03:00
{
2013-06-26 14:18:27 +03:00
serverThread = nullptr ;
shared = nullptr ;
2012-01-12 18:23:00 +03:00
port = boost : : lexical_cast < std : : string > ( settings [ " server " ] [ " port " ] . Float ( ) ) ;
2013-02-19 02:10:46 +03:00
verbose = true ;
2010-09-03 21:42:54 +03:00
2014-08-26 13:19:04 +03:00
# ifndef VCMI_ANDROID
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 ( ) ;
2015-02-14 21:42:47 +02:00
}
catch ( . . . )
{
logNetwork - > error ( " Cannot open interprocess memory. " ) ;
handleException ( ) ;
throw ;
}
2014-02-20 21:53:18 +03:00
# endif
2010-09-03 21:42:54 +03:00
}
CServerHandler : : ~ CServerHandler ( )
{
delete shared ;
delete serverThread ; //detaches, not kills thread
}
void CServerHandler : : callServer ( )
{
2012-06-27 23:44:01 +03:00
setThreadName ( " CServerHandler::callServer " ) ;
2014-08-11 00:42:39 +03:00
const std : : string logName = ( VCMIDirs : : get ( ) . userCachePath ( ) / " server_log.txt " ) . string ( ) ;
2014-08-27 13:31:58 +03:00
const std : : string comm = VCMIDirs : : get ( ) . serverPath ( ) . string ( ) + " --port= " + port + " > \" " + logName + ' \" ' ;
2012-06-02 18:16:54 +03:00
int result = std : : system ( comm . c_str ( ) ) ;
if ( result = = 0 )
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Server closed correctly " ;
2012-06-02 18:16:54 +03:00
else
2012-11-16 00:29:22 +03:00
{
2013-04-09 17:31:36 +03:00
logNetwork - > errorStream ( ) < < " Error: server failed to close correctly or crashed! " ;
logNetwork - > errorStream ( ) < < " Check " < < logName < < " for more info " ;
2012-11-16 00:29:22 +03:00
exit ( 1 ) ; // exit in case of error. Othervice without working server VCMI will hang
}
2010-09-03 21:42:54 +03:00
}
2010-10-24 14:35:14 +03:00
CConnection * CServerHandler : : justConnectToServer ( const std : : string & host , const std : : string & port )
{
2013-06-26 14:18:27 +03:00
CConnection * ret = nullptr ;
2010-10-24 14:35:14 +03:00
while ( ! ret )
{
try
{
2013-04-09 17:31:36 +03:00
logNetwork - > infoStream ( ) < < " Establishing connection... " ;
2012-01-12 18:23:00 +03:00
ret = new CConnection ( host . size ( ) ? host : settings [ " server " ] [ " server " ] . String ( ) ,
port . size ( ) ? port : boost : : lexical_cast < std : : string > ( settings [ " server " ] [ " port " ] . Float ( ) ) ,
2010-10-24 14:35:14 +03:00
NAME ) ;
}
catch ( . . . )
{
2013-04-09 17:31:36 +03:00
logNetwork - > errorStream ( ) < < " \n Cannot establish connection! Retrying within 2 seconds " ;
2010-10-24 14:35:14 +03:00
SDL_Delay ( 2000 ) ;
}
}
return ret ;
2010-10-31 00:53:41 +03:00
}