Browse Source

Battle is run and result is stored.

Michał W. Urbańczyk 14 years ago
parent
commit
131b9d6e1a

+ 125 - 0
VCMI_BattleAiHost/Client.cpp

@@ -1,3 +1,128 @@
 #include "Client.h"
+#include "../lib/Connection.h"
+#include "../CThreadHelper.h"
+#include "../lib/CGameState.h"
+#include "../lib/BattleAction.h"
+#include "../lib/CGameInterface.h"
+#include "CheckTime.h"
 
+#define NOT_LIB
+#include "../lib/RegisterTypes.cpp"
 
+template <typename T> class CApplyOnCL;
+
+class CBaseForCLApply
+{
+public:
+	virtual void applyOnClAfter(CClient *cl, void *pack) const =0; 
+	virtual void applyOnClBefore(CClient *cl, void *pack) const =0; 
+	virtual ~CBaseForCLApply(){}
+
+	template<typename U> static CBaseForCLApply *getApplier(const U * t=NULL)
+	{
+		return new CApplyOnCL<U>;
+	}
+};
+
+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);
+	}
+};
+
+static CApplier<CBaseForCLApply> *applier = NULL;
+
+void CClient::run()
+{
+	setThreadName(-1, "CClient::run");
+	try
+	{
+		CPack *pack = NULL;
+		while(!terminate)
+		{
+			pack = serv->retreivePack(); //get the package from the server
+
+			if (terminate) 
+			{
+				delete pack;
+				pack = NULL;
+				break;
+			}
+
+			handlePack(pack);
+			pack = NULL;
+		}
+	} 
+	catch (const std::exception& e)
+	{	
+		tlog3 << "Lost connection to server, ending listening thread!\n";
+		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;
+		}
+	}
+}
+
+void CClient::handlePack( CPack * pack )
+{			
+	CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
+	if(apply)
+	{
+		apply->applyOnClBefore(this,pack);
+		tlog5 << "\tMade first apply on cl\n";
+		gs->apply(pack);
+		tlog5 << "\tApplied on gs\n";
+		apply->applyOnClAfter(this,pack);
+		tlog5 << "\tMade second apply on cl\n";
+	}
+	else
+	{
+		tlog1 << "Message cannot be applied, cannot find applier! TypeID " << typeList.getTypeID(pack) << std::endl;
+	}
+	delete pack;
+}
+
+void CClient::requestMoveFromAI(const CStack *s)
+{
+	boost::thread(&CClient::requestMoveFromAIWorker, this, s);
+}
+
+void CClient::requestMoveFromAIWorker(const CStack *s)
+{
+	BattleAction ba;
+
+	try
+	{
+		CheckTime timer("AI was thinking for ");
+		ba = ai->activeStack(s);
+		MakeAction temp_action(ba);
+		*serv << &temp_action;
+	}
+	catch(...)
+	{
+		tlog0 << "AI thrown an exception!\n";
+	}
+}
+
+CClient::CClient()
+{
+	gs = NULL;
+	serv = NULL;
+	ai = NULL;
+	curbaction = NULL;
+	terminate = false;
+
+	applier = new CApplier<CBaseForCLApply>;
+	registerTypes2(*applier);
+}

+ 13 - 5
VCMI_BattleAiHost/Client.h

@@ -1,17 +1,25 @@
 #pragma once
-
+#include "../global.h"
 class CGameState;
 class CConnection;
+struct CPack;
+class CBattleGameInterface;
+struct BattleAction;
+class CStack;
 
 class CClient/* : public IGameCallback*/
 {
 public:
+	bool terminate;
+	BattleAction *curbaction;
 	CGameState *gs;
 	CConnection *serv;
-	CClient()
-	{
+	CBattleGameInterface *ai;
 
-	}
+	CClient();
 
-	//void commitPackage(CPackForClient *) OVERRIDE {};
+	void run();
+	void handlePack( CPack * pack ); //applies the given pack and deletes it
+	void requestMoveFromAI(const CStack *s);
+	void requestMoveFromAIWorker(const CStack *s);
 };

+ 2 - 0
VCMI_BattleAiHost/VCMI_BattleAiHost.vcxproj

@@ -135,9 +135,11 @@
     <ClCompile Include="BattleCallback.cpp" />
     <ClCompile Include="Client.cpp" />
     <ClCompile Include="main.cpp" />
+    <ClCompile Include="NetPacksRunner.cpp" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="BattleCallback.h" />
+    <ClInclude Include="CheckTime.h" />
     <ClInclude Include="Client.h" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />

+ 10 - 3
VCMI_BattleAiHost/main.cpp

@@ -81,10 +81,17 @@ int main(int argc, char** argv)
 		tlog0 << "Cl created\n";
 		CBattleCallback * cbc = new CBattleCallback(gs, color, &cl);
 		tlog0 << "Cbc created\n";
-		CBattleGameInterface *ai = CDynLibHandler::getNewBattleAI(battleAIName);
-		tlog0 << "AI created\n";
-		ai->init(cbc);
+		if(battleAIName.size())
+		{
+			cl.ai = CDynLibHandler::getNewBattleAI(battleAIName);
+			cl.ai->playerID = color;
+			tlog0 << "AI created\n";
+			cl.ai->init(cbc);
+		}
+		else
+			tlog0 << "Not loading AI, only simulation will be run\n";
 		tlog0 << cbc->battleGetAllStacks().size() << std::endl;
+		cl.run();
 	}
 	catch(std::exception &e)
 	{

+ 1 - 1
lib/Connection.cpp

@@ -240,7 +240,7 @@ CPack * CConnection::retreivePack()
 	boost::unique_lock<boost::mutex> lock(*rmx);
 	tlog5 << "Listening... ";
 	*this >> ret;
-	tlog5 << "\treceived server message of type " << typeid(*ret).name() << std::endl;
+	tlog5 << "\treceived message of type " << typeid(*ret).name() << std::endl;
 	return ret;
 }
 

+ 15 - 16
server/CGameHandler.cpp

@@ -462,6 +462,16 @@ void CGameHandler::endBattle(int3 tile, const CGHeroInstance *hero1, const CGHer
 	{
 		CSaveFile resultFile("result.vdrst");
 		resultFile << *battleResult.data;
+
+		int casualtiesPoints = 0;
+		tlog0 << boost::format("Winner side %d\nWinner casualties:\n") % battleResult.data->winner;
+		for(std::map<ui32,si32>::const_iterator i = battleResult.data->casualties[battleResult.data->winner].begin(); i != battleResult.data->casualties[battleResult.data->winner].end(); i++)
+		{
+			const CCreature *c = VLC->creh->creatures[i->first];
+			tlog0 << boost::format("\t* %d of %s\n") % i->second % c->namePl;
+			casualtiesPoints = c->AIValue * i->second;
+		}
+		tlog0 << boost::format("Total causalties points: %d\n") % casualtiesPoints;
 		return;
 	}
 
@@ -626,17 +636,12 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 	{
 		while(1)//server should never shut connection first //was: while(!end2)
 		{
-			{
-				boost::unique_lock<boost::mutex> lock(*c.rmx);
-				c >> pack; //get the package
-				tlog5 << "Received client message of type " << typeid(*pack).name() << std::endl;
-			}
-
+			pack = c.retreivePack();
 			int packType = typeList.getTypeID(pack); //get the id of type
 			CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object
-			if(packType != typeList.getTypeID<QueryReply>() &&
-			   (packType != typeList.getTypeID<ArrangeStacks>() || !isAllowedArrangePack((ArrangeStacks*)pack)) && // for dialogs like garrison
-			   states[getCurrentPlayer()].queries.size())
+			if(packType != typeList.getTypeID<QueryReply>() 
+				&&(packType != typeList.getTypeID<ArrangeStacks>() || !isAllowedArrangePack((ArrangeStacks*)pack)) // for dialogs like garrison
+				&& vstd::contains(states.players, getCurrentPlayer()) && states[getCurrentPlayer()].queries.size())
 			{
 				complain("Answer the query before attempting any further actions!");
 				PackageApplied applied;
@@ -1997,13 +2002,7 @@ void CGameHandler::save( const std::string &fname )
 
 void CGameHandler::close()
 {
-	tlog0 << "We have been requested to close.\n";	
-
-	if(gs->initialOpts->mode == StartInfo::DUEL)
-	{
-		exit(0);
-	}
-
+	tlog0 << "We have been requested to close.\n";
 	//BOOST_FOREACH(CConnection *cc, conns)
 	//	if(cc && cc->socket && cc->socket->is_open())
 	//		cc->socket->close();

+ 20 - 16
server/CVCMIServer.cpp

@@ -501,23 +501,14 @@ void CVCMIServer::loadGame()
 void CVCMIServer::startDuel(const std::string &battle, const std::string &leftAI, const std::string &rightAI)
 {
 	//we need three connections
-	CConnection *conns[1] = {0};
-	for (int i = 0; i < 1 ; i++)
+	CConnection *conns[3] = {0};
+	for (int i = 0; i < 3 ; i++)
 	{
 		boost::system::error_code error;
 
-
-		//boost::system::error_code error;
 		tlog0<<"Listening for connections at port " << acceptor->local_endpoint().port() << std::endl;
 		tcp::socket * s = new tcp::socket(acceptor->get_io_service());
-		boost::thread acc(boost::bind(vaccept,acceptor,s,&error));
-// 		sr->setToTrueAndNotify();
-// 		delete mr;
-
-		acc.join();
-
-		//tcp::socket * s = new tcp::socket(acceptor->get_io_service());
-		//acceptor->accept(*s, error);
+		acceptor->accept(*s, error);
 
 		if (error)
 		{
@@ -537,26 +528,39 @@ void CVCMIServer::startDuel(const std::string &battle, const std::string &leftAI
 	si.mode = StartInfo::DUEL;
 	si.mapname = battle;
 	
+
+	tlog0 << "Preparing gh!\n";
 	CGameHandler *gh = new CGameHandler();
 	gh->init(&si,std::time(NULL));
 
 	BOOST_FOREACH(CConnection *c, conns)
 	{
+		ui8 player = gh->conns.size();
+		tlog0 << boost::format("Preparing connection %d!\n") % (int)player;
 		c->addStdVecItems(gh->gs, VLC);
-		gh->connections[gh->conns.size()] = c;
+		gh->connections[player] = c;
 		gh->conns.insert(c);
+		gh->states.addPlayer(player);
 		*c << si;
+
+		std::set<int> pom;
+		pom.insert(player);
+		boost::thread(boost::bind(&CGameHandler::handleConnection,gh,pom,boost::ref(*c)));
 	}
 
+	tlog0 << boost::format("Sending start info to connections!\n");
 	*gh->connections[0] << leftAI << ui8(0);
-	//*gh->connections[1] << rightAI << ui8(1);
-	//*gh->connections[2] << std::string() << ui8(254);
+	*gh->connections[1] << rightAI << ui8(1);
+	*gh->connections[2] << std::string() << ui8(254);
 
 
+	tlog0 << "Starting battle!\n";
 	gh->runBattle();
-
+	tlog0 << "Battle over!\n";
 	delNull(gh);
+	tlog0 << "Removed gh!\n";
 	boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
+	tlog0 << "Dying...\n";
 	exit(0);
 }
 

+ 17 - 6
server/Makefile.am

@@ -1,6 +1,17 @@
-bin_PROGRAMS = odpalarka
-
-odpalarka_LDADD = $(top_builddir)/lib/libvcmi.la
-odpalarka_CXXFLAGS = @SDL_CXXFLAGS@
-odpalarka_LDFLAGS = -L$(top_builddir)/lib
-odpalarka_SOURCES = main.cpp
+bin_PROGRAMS = vcmiserver
+
+vcmiserver_LDADD = $(top_builddir)/lib/libvcmi.la
+vcmiserver_CXXFLAGS = @SDL_CXXFLAGS@
+vcmiserver_LDFLAGS = -L$(top_builddir)/lib
+vcmiserver_SOURCES = \
+	../CConsoleHandler.cpp \
+	../CConsoleHandler.h \
+	../CThreadHelper.cpp \
+	../CThreadHelper.h \
+	CGameHandler.cpp \
+	CGameHandler.h \
+	CVCMIServer.cpp \
+	CVCMIServer.h \
+	NetPacksServer.cpp \
+	stdafx.cpp \
+	stdafx.h