瀏覽代碼

Chenges (networking for PG, minor fixes)

mateuszb 15 年之前
父節點
當前提交
4ba3c68ced
共有 12 個文件被更改,包括 379 次插入165 次删除
  1. 1 0
      client/AdventureMapButton.cpp
  2. 2 2
      client/CPlayerInterface.cpp
  3. 137 13
      client/CPreGame.cpp
  4. 30 4
      client/CPreGame.h
  5. 102 97
      client/Client.cpp
  6. 21 5
      client/Client.h
  7. 8 24
      lib/CGameState.cpp
  8. 11 0
      lib/Connection.cpp
  9. 24 0
      lib/Connection.h
  10. 18 0
      lib/NetPacks.h
  11. 16 3
      lib/RegisterTypes.cpp
  12. 9 17
      server/CGameHandler.cpp

+ 1 - 0
client/AdventureMapButton.cpp

@@ -72,6 +72,7 @@ void CButtonBase::showAll( SDL_Surface * to )
 
 void CButtonBase::addTextOverlay( const std::string Text, EFonts font, SDL_Color color)
 {
+	delete text;
 	text = new TextOverlay;
 	text->text = Text;
 

+ 2 - 2
client/CPlayerInterface.cpp

@@ -1824,11 +1824,11 @@ void CPlayerInterface::gameOver(ui8 player, bool victory )
 	}
 	else
 	{
-		if(!victory) //enemy has lost
+		if(!victory && cb->getPlayerStatus(playerID) == PlayerState::INGAME) //enemy has lost
 		{
 			std::string txt = CGI->generaltexth->allTexts[5]; //%s has been vanquished!
 			boost::algorithm::replace_first(txt, "%s", CGI->generaltexth->capColors[player]);
-			//showInfoDialog(txt,std::vector<SComponent*>(1, new SComponent(SComponent::flag, player, 0)));
+			showInfoDialog(txt,std::vector<SComponent*>(1, new SComponent(SComponent::flag, player, 0)));
 		}
 	}
 }

+ 137 - 13
client/CPreGame.cpp

@@ -39,6 +39,11 @@
 #include "../hch/CArtHandler.h" /*for campaign bonuses*/
 #include "../hch/CBuildingHandler.h" /*for campaign bonuses*/
 #include "CBitmapHandler.h"
+#include "Client.h"
+#include "../lib/NetPacks.h"
+
+#define NOT_LIB
+#include "../lib/RegisterTypes.cpp"
 
 /*
  * CPreGame.cpp, part of VCMI engine
@@ -97,6 +102,29 @@ static void clearInfo()
 	playerNames.clear();
 }
 
+class CBaseForPGApply
+{
+public:
+	virtual void applyOnPG(CSelectionScreen *selScr, void *pack) const =0; 
+	virtual ~CBaseForPGApply(){};
+	template<typename U> static CBaseForPGApply *getApplier(const U * t=NULL)
+	{
+		return new CApplyOnPG<U>;
+	}
+};
+
+template <typename T> class CApplyOnPG : public CBaseForPGApply
+{
+public:
+	void applyOnPG(CSelectionScreen *selScr, void *pack) const
+	{
+		T *ptr = static_cast<T*>(pack);
+		ptr->apply(selScr);
+	}
+};
+
+CApplier<CBaseForPGApply> *applier = NULL;
+
 void CMapInfo::countPlayers()
 {
 	actualHumanPlayers = playerAmnt = humenPlayers = 0;
@@ -186,7 +214,7 @@ CMenuScreen::CMenuScreen( EState which )
 	case newGame:
 		{
 			bgAd = new CPicture(BitmapHandler::loadBitmap("ZNEWGAM.bmp"), 114, 312, true);
-			buttons[0] = new AdventureMapButton("", CGI->generaltexth->zelp[10].second, bind(&CGPreGame::openSel, CGP, newGame, false), 545, 4, "ZTSINGL.DEF", SDLK_s);
+			buttons[0] = new AdventureMapButton("", CGI->generaltexth->zelp[10].second, bind(&CGPreGame::openSel, CGP, newGame, SINGLE_PLAYER), 545, 4, "ZTSINGL.DEF", SDLK_s);
 			buttons[1] = new AdventureMapButton("", CGI->generaltexth->zelp[11].second, &pushIntT<CMultiMode>, 568, 120, "ZTMULTI.DEF", SDLK_m);
 			buttons[2] = new AdventureMapButton("", CGI->generaltexth->zelp[12].second, bind(&CMenuScreen::moveTo, this, ref(CGP->scrs[campaignMain])), 541, 233, "ZTCAMPN.DEF", SDLK_c);
 			buttons[3] = new AdventureMapButton("", CGI->generaltexth->zelp[13].second, 0 /*cb*/, 545, 358, "ZTTUTOR.DEF", SDLK_t);
@@ -196,8 +224,8 @@ CMenuScreen::CMenuScreen( EState which )
 	case loadGame:
 		{
 			bgAd = new CPicture(BitmapHandler::loadBitmap("ZLOADGAM.bmp"), 114, 312, true);
-			buttons[0] = new AdventureMapButton("", CGI->generaltexth->zelp[10].second, bind(&CGPreGame::openSel, CGP, loadGame, false), 545, 4, "ZTSINGL.DEF", SDLK_s);
-			buttons[1] = new AdventureMapButton("", CGI->generaltexth->zelp[11].second, bind(&CGPreGame::openSel, CGP, loadGame, true), 568, 120, "ZTMULTI.DEF", SDLK_m);
+			buttons[0] = new AdventureMapButton("", CGI->generaltexth->zelp[10].second, bind(&CGPreGame::openSel, CGP, loadGame, SINGLE_PLAYER), 545, 4, "ZTSINGL.DEF", SDLK_s);
+			buttons[1] = new AdventureMapButton("", CGI->generaltexth->zelp[11].second, bind(&CGPreGame::openSel, CGP, loadGame, HOT_SEAT), 568, 120, "ZTMULTI.DEF", SDLK_m);
 			buttons[2] = new AdventureMapButton("", CGI->generaltexth->zelp[12].second, 0 /*cb*/, 541, 233, "ZTCAMPN.DEF", SDLK_c);
 			buttons[3] = new AdventureMapButton("", CGI->generaltexth->zelp[13].second, 0 /*cb*/, 545, 358, "ZTTUTOR.DEF", SDLK_t);
 			buttons[4] = new AdventureMapButton("", CGI->generaltexth->zelp[14].second, bind(&CMenuScreen::moveTo, this, CGP->scrs[mainMenu]), 582, 464, "ZTBACK.DEF", SDLK_ESCAPE);
@@ -208,7 +236,7 @@ CMenuScreen::CMenuScreen( EState which )
 			buttons[0] = new AdventureMapButton("", "", 0 /*cb*/, 535, 8, "ZSSSOD.DEF", SDLK_s);
 			buttons[1] = new AdventureMapButton("", "", 0 /*cb*/, 494, 117, "ZSSROE.DEF", SDLK_m);
 			buttons[2] = new AdventureMapButton("", "", 0 /*cb*/, 486, 241, "ZSSARM.DEF", SDLK_c);
-			buttons[3] = new AdventureMapButton("", "", bind(&CGPreGame::openSel, CGP, campaignList, false), 550, 358, "ZSSCUS.DEF", SDLK_t);
+			buttons[3] = new AdventureMapButton("", "", bind(&CGPreGame::openSel, CGP, campaignList, SINGLE_PLAYER), 550, 358, "ZSSCUS.DEF", SDLK_t);
 			buttons[4] = new AdventureMapButton("", "", bind(&CMenuScreen::moveTo, this, CGP->scrs[newGame]), 582, 464, "ZSSEXIT.DEF", SDLK_ESCAPE);
 
 		}
@@ -259,10 +287,9 @@ CGPreGame::~CGPreGame()
 		delete scrs[i];
 }
 
-void CGPreGame::openSel( CMenuScreen::EState type, bool multi )
+void CGPreGame::openSel(CMenuScreen::EState type, CMenuScreen::EMultiMode multi /*= CMenuScreen::SINGLE_PLAYER*/)
 {
 	resetPlayerNames();
-
 	GH.pushInt(new CSelectionScreen(type, multi));
 }
 
@@ -314,10 +341,19 @@ void CGPreGame::resetPlayerNames()
 	playerNames.push_back(CGI->generaltexth->allTexts[434]); //we have only one player and his name is "Player"
 }
 
-CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, bool MultiPlayer)
-	:multiPlayer(MultiPlayer)
+CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMultiMode MultiPlayer /*= CMenuScreen::SINGLE_PLAYER*/)
+	:multiPlayer(MultiPlayer), serv(NULL)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
+	applier = new CApplier<CBaseForPGApply>;
+
+	CServerHandler *sh = NULL;
+	if(multiPlayer == CMenuScreen::MULTI_PLAYER)
+	{
+		sh = new CServerHandler;
+		sh->startServer();
+	}
+
 	IShowActivable::type = BLOCK_ADV_HOTKEYS;
 	pos.w = 762;
 	pos.h = 584;
@@ -349,7 +385,7 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, bool MultiPlayer)
 	sInfo.turnTime = 0;
 	curTab = NULL;
 
-	card = new InfoCard(type); //right info card
+	card = new InfoCard(type, multiPlayer == CMenuScreen::MULTI_PLAYER); //right info card
 	if (type == CMenuScreen::campaignList)
 	{
 		opt = NULL;
@@ -378,6 +414,12 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, bool MultiPlayer)
 			random->addTextOverlay(CGI->generaltexth->allTexts[740], FONT_SMALL);
 
 			start  = new AdventureMapButton(CGI->generaltexth->zelp[103], bind(&CSelectionScreen::startGame, this), 411, 529, "SCNRBEG.DEF", SDLK_b);
+
+			if(multiPlayer == CMenuScreen::MULTI_PLAYER)
+			{
+				AdventureMapButton *hideChat = new AdventureMapButton(CGI->generaltexth->zelp[48], 0, 619, 75, "GSPBUT2.DEF", SDLK_h);
+				hideChat->addTextOverlay(CGI->generaltexth->allTexts[531], FONT_SMALL);
+			}
 		}
 		break;
 	case CMenuScreen::loadGame:
@@ -408,6 +450,13 @@ CSelectionScreen::CSelectionScreen(CMenuScreen::EState Type, bool MultiPlayer)
 	}
 
 	back = new AdventureMapButton("", CGI->generaltexth->zelp[105].second, bind(&CGuiHandler::popIntTotally, &GH, this), 581, 529, backName, SDLK_ESCAPE);
+
+
+	if(multiPlayer == CMenuScreen::MULTI_PLAYER)
+	{
+		serv = sh->connectToServer();
+	}
+	delete sh;
 }
 
 CSelectionScreen::~CSelectionScreen()
@@ -416,6 +465,7 @@ CSelectionScreen::~CSelectionScreen()
 	curOpts = NULL;
 	playerColor = -1;
 	playerNames.clear();
+	delete applier;
 }
 
 void CSelectionScreen::toggleTab(CIntObject *tab)
@@ -598,6 +648,19 @@ void CSelectionScreen::difficultyChange( int to )
 	GH.totalRedraw();
 }
 
+void CSelectionScreen::handleConnection()
+{
+	while(serv)
+	{
+		
+	}
+}
+
+void CSelectionScreen::toggleChat()
+{
+
+}
+
 // A new size filter (Small, Medium, ...) has been selected. Populate
 // selMaps with the relevant data.
 void SelectionTab::filter( int size, bool selectFirst )
@@ -1167,8 +1230,14 @@ void SelectionTab::selectFName( const std::string &fname )
 
 
 
-InfoCard::InfoCard( CMenuScreen::EState Type )
-: difficulty(NULL), sizes(NULL), sFlags(NULL), bg(NULL)
+CChatBox::CChatBox(const Rect &rect)
+{
+	const int height = 10;
+	//inputBox = new CTextInput(Rect(rect.x, rect.y + rect.h - height, rect.w, height));
+}
+
+InfoCard::InfoCard( CMenuScreen::EState Type, bool network )
+: difficulty(NULL), sizes(NULL), sFlags(NULL), bg(NULL), chatOn(false), chat(NULL)
 {
 	OBJ_CONSTRUCTION;
 	pos.x += 393;
@@ -1209,6 +1278,12 @@ InfoCard::InfoCard( CMenuScreen::EState Type )
 
 		//description needs bg
 		moveChild(new CPicture(*bg, descriptionRect), this, mapDescription, true); //move subpicture bg to our description control (by default it's our (Infocard) child)
+
+		if(network)
+		{
+			new CPicture("CHATPLUG.bmp", 17, 276);
+			chat = new CChatBox(descriptionRect);
+		}
 	}
 
 }
@@ -1413,6 +1488,36 @@ void InfoCard::showTeamsPopup()
 	GH.pushInt(new CInfoPopup(bmp, true));
 }
 
+void InfoCard::toggleChat()
+{
+	setChat(!chatOn);
+}
+
+void InfoCard::setChat(bool activateChat)
+{
+	if(chatOn == activateChat)
+		return;
+
+	assert(active);
+
+	if(activateChat)
+	{
+		mapDescription->recActions = 0;
+		mapDescription->deactivate();
+		chat->recActions = 255;
+		chat->activate();
+	}
+	else
+	{
+		mapDescription->recActions = 255;
+		mapDescription->activate();
+		chat->recActions = 0;
+		chat->deactivate();
+	}
+
+	chatOn = activateChat;
+}
+
 OptionsTab::OptionsTab( CMenuScreen::EState Type)
 :type(Type)
 {
@@ -2172,6 +2277,8 @@ CMultiMode::CMultiMode()
 	txt->setText(CGI->generaltexth->allTexts[434]); //Player
 
 	btns[0] = new AdventureMapButton(CGI->generaltexth->zelp[266], bind(&CMultiMode::openHotseat, this), 373, 78, "MUBHOT.DEF");
+	btns[1] = new AdventureMapButton("Host TCP/IP game", "", bind(&CMultiMode::hostTCP, this), 373, 78 + 57*1, "MUBHOST.DEF");
+	btns[2] = new AdventureMapButton("Join TCP/IP game", "", bind(&CMultiMode::joinTCP, this), 373, 78 + 57*2, "MUBJOIN.DEF");
 	btns[6] = new AdventureMapButton(CGI->generaltexth->zelp[288], bind(&CGuiHandler::popIntTotally, ref(GH), this), 373, 424, "MUBCANC.DEF", SDLK_ESCAPE);
 }
 
@@ -2180,6 +2287,19 @@ void CMultiMode::openHotseat()
 	GH.pushInt(new CHotSeatPlayers(txt->text));
 }
 
+void CMultiMode::hostTCP()
+{
+	playerNames.clear();
+	playerNames.push_back(txt->text);
+	GH.popIntTotally(this);
+	GH.pushInt(new CSelectionScreen(CMenuScreen::newGame, CMenuScreen::MULTI_PLAYER));
+}
+
+void CMultiMode::joinTCP()
+{
+
+}
+
 CHotSeatPlayers::CHotSeatPlayers(const std::string &firstPlayer)
 {
 	OBJ_CONSTRUCTION;
@@ -2206,7 +2326,7 @@ void CHotSeatPlayers::enterSelectionScreen()
 		if(txt[i]->text.length())
 			playerNames.push_back(txt[i]->text);
 
-	GH.popInts(2);
+	GH.popInts(2); //pop MP mode window and this
 	GH.pushInt(new CSelectionScreen(CMenuScreen::newGame));
 }
 
@@ -2779,7 +2899,7 @@ void CBonusSelection::CRegion::show( SDL_Surface * to )
 }
 
 CSavingScreen::CSavingScreen(bool hotseat)
- : CSelectionScreen(CMenuScreen::saveGame, hotseat)
+ : CSelectionScreen(CMenuScreen::saveGame, hotseat ? CMenuScreen::HOT_SEAT : CMenuScreen::SINGLE_PLAYER)
 {
 	ourGame = mapInfoFromGame();
 	sInfo = *LOCPLINT->cb->getStartInfo();
@@ -2791,3 +2911,7 @@ CSavingScreen::~CSavingScreen()
 
 }
 
+void ChatMessage::apply(CSelectionScreen *selScreen)
+{
+
+}

+ 30 - 4
client/CPreGame.h

@@ -25,6 +25,7 @@ class CCampaign;
 class CGStatusBar;
 class CTextBox;
 class CCampaignState;
+class CConnection;
 
 class CMapInfo
 {
@@ -64,6 +65,10 @@ public:
 		mainMenu, newGame, loadGame, campaignMain, saveGame, scenarioInfo, campaignList
 	};
 
+	enum EMultiMode {
+		SINGLE_PLAYER = 0, HOT_SEAT, MULTI_PLAYER
+	};
+
 	CPicture *bgAd;
 	AdventureMapButton *buttons[5];
 
@@ -82,13 +87,25 @@ struct FileInfo
 	bool inLod; //tells if this file is located in Lod
 };
 
+class CChatBox : public CIntObject
+{
+public:
+	CTextBox *chatHistory;
+	CTextInput *inputBox;
+
+	CChatBox(const Rect &rect);
+};
+
 class InfoCard : public CIntObject
 {
 	CPicture *bg; 
 public:
 	CMenuScreen::EState type;
 
+	bool chatOn;  //if chat is shown, then description is hidden
 	CTextBox *mapDescription;
+	CChatBox *chat;
+
 	CHighlightableButtonsGroup *difficulty;
 	CDefHandler *sizes, *sFlags;;
 
@@ -96,7 +113,9 @@ public:
 	void showAll(SDL_Surface * to);
 	void clickRight(tribool down, bool previousState);
 	void showTeamsPopup();
-	InfoCard(CMenuScreen::EState Type);
+	void toggleChat();
+	void setChat(bool activateChat);
+	InfoCard(CMenuScreen::EState Type, bool network = false);
 	~InfoCard();
 };
 
@@ -214,9 +233,11 @@ public:
 	const CMapInfo *current;
 	StartInfo sInfo;
 	CIntObject *curTab;
-	bool multiPlayer;
+	CMenuScreen::EMultiMode multiPlayer;
 
-	CSelectionScreen(CMenuScreen::EState Type, bool MultiPlayer = false);
+	CConnection *serv; //connection to server, used in MP mode
+
+	CSelectionScreen(CMenuScreen::EState Type, CMenuScreen::EMultiMode MultiPlayer = CMenuScreen::SINGLE_PLAYER);
 	~CSelectionScreen();
 	void toggleTab(CIntObject *tab);
 	void changeSelection(const CMapInfo *to);
@@ -224,6 +245,9 @@ public:
 	void startCampaign();
 	void startGame();
 	void difficultyChange(int to);
+
+	void toggleChat();
+	void handleConnection();
 };
 
 class CSavingScreen : public CSelectionScreen
@@ -257,6 +281,8 @@ public:
 
 	CMultiMode();
 	void openHotseat();
+	void hostTCP();
+	void joinTCP();
 };
 
 class CHotSeatPlayers : public CIntObject
@@ -359,7 +385,7 @@ public:
 	~CGPreGame();
 	void update();
 	void run();
-	void openSel(CMenuScreen::EState type, bool multi = false);
+	void openSel(CMenuScreen::EState type, CMenuScreen::EMultiMode multi = CMenuScreen::SINGLE_PLAYER);
 
 	void resetPlayerNames();
 	void loadGraphics();

+ 102 - 97
client/Client.cpp

@@ -26,11 +26,11 @@
 #include <boost/foreach.hpp>
 #include <boost/thread.hpp>
 #include <boost/thread/shared_mutex.hpp>
+#include <boost/lexical_cast.hpp>
 #include <sstream>
 #include "CPreGame.h"
 
-#undef DLL_EXPORT
-#define DLL_EXPORT
+#define NOT_LIB
 #include "../lib/RegisterTypes.cpp"
 extern std::string NAME;
 namespace intpr = boost::interprocess;
@@ -45,13 +45,21 @@ namespace intpr = boost::interprocess;
  *
  */
 
+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:
@@ -67,46 +75,20 @@ public:
 	}
 };
 
-class CCLApplier
-{
-public:
-	std::map<ui16,CBaseForCLApply*> apps; 
-
-	CCLApplier()
-	{
-		registerTypes2(*this);
-	}
-	~CCLApplier()
-	{
-		std::map<ui16,CBaseForCLApply*>::iterator iter;
-
-		for(iter = apps.begin(); iter != apps.end(); iter++)
-			delete iter->second;
-	}
-	template<typename T> void registerType(const T * t=NULL)
-	{
-		ui16 ID = typeList.registerType(t);
-		apps[ID] = new CApplyOnCL<T>;
-	}
-
-} *applier = NULL;
+CApplier<CBaseForCLApply> *applier = NULL;
 
 void CClient::init()
 {
 	hotSeat = false;
 	connectionHandler = NULL;
 	pathInfo = NULL;
-	applier = new CCLApplier;
+	applier = new CApplier<CBaseForCLApply>;
+	registerTypes2(*applier);
 	IObjectInterface::cb = this;
 	serv = NULL;
 	gs = NULL;
 	cb = NULL;
 	terminate = false;
-	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: ";)
 }
 
 CClient::CClient(void)
@@ -114,18 +96,20 @@ CClient::CClient(void)
 {
 	init();
 }
+
 CClient::CClient(CConnection *con, StartInfo *si)
 :waitingRequest(false)
 {
 	init();
 	newGame(con,si);
 }
+
 CClient::~CClient(void)
 {
 	delete pathInfo;
 	delete applier;
-	delete shared;
 }
+
 void CClient::waitForMoveAndSend(int color)
 {
 	try
@@ -144,7 +128,7 @@ void CClient::run()
 		CPack *pack = NULL;
 		while(!terminate)
 		{
-			pack = retreivePack(); //get the package from the server
+			pack = serv->retreivePack(); //get the package from the server
 			
 			if (terminate) 
 			{
@@ -231,8 +215,9 @@ void CClient::endGame( bool closeConnection /*= true*/ )
 	LOCPLINT = NULL;
 	while (!playerint.empty())
 	{
-		delete playerint.begin()->second;
+		CGameInterface *pint = playerint.begin()->second;
 		playerint.erase(playerint.begin());
+		delete pint;
 	}
 
 	BOOST_FOREACH(CCallback *cb, callbacks)
@@ -251,13 +236,10 @@ void CClient::loadGame( const std::string & fname )
 {
 	tlog0 <<"\n\nLoading procedure started!\n\n";
 
-	timeHandler tmh;
-
-	char portc[10];
-	SDL_itoa(conf.cc.port,portc,10);
-	runServer(portc); //create new server
-	tlog0 <<"Restarting server: "<<tmh.getDif()<<std::endl;
+	CServerHandler sh;
+	sh.startServer();
 
+	timeHandler tmh;
 	{
 		ui32 ver;
 		char sig[8];
@@ -284,14 +266,10 @@ void CClient::loadGame( const std::string & fname )
 
 		tlog0 <<"Initing maphandler: "<<tmh.getDif()<<std::endl;
 	}
-
-	waitForServer();
-	tlog0 <<"Waiting for server: "<<tmh.getDif()<<std::endl;
-
-	serv = new CConnection(conf.cc.server,portc,NAME);
+	serv = sh.connectToServer();
 	serv->addStdVecItems(gs);
-	tlog0 <<"Setting up connection: "<<tmh.getDif()<<std::endl;
 
+	tmh.update();
 	ui8 pom8;
 	*serv << ui8(3) << ui8(1); //load game; one client
 	*serv << fname;
@@ -333,32 +311,8 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 {
 	if (con == NULL) 
 	{
-		timeHandler pomtime;
-		char portc[10];
-		SDL_itoa(conf.cc.port,portc,10);
-		CClient::runServer(portc);
-		tlog0<<"Preparing shared memory and starting server: "<<pomtime.getDif()<<std::endl;
-
-		pomtime.getDif();//reset timers
-
-		//wait until server is ready
-		tlog0<<"Waiting for server... ";
-		waitForServer();
-		tlog0 << pomtime.getDif()<<std::endl;
-		while(!con)
-		{
-			try
-			{
-				tlog0 << "Establishing connection...\n";
-				con = new CConnection(conf.cc.server,portc,NAME);
-			}
-			catch(...)
-			{
-				tlog1 << "\nCannot establish connection! Retrying within 2 seconds" <<std::endl;
-				SDL_Delay(2000);
-			}
-		}
-		THC tlog0<<"\tConnecting to the server: "<<pomtime.getDif()<<std::endl;
+		CServerHandler sh;
+		con = sh.connectToServer();
 	}
 
 	timeHandler tmh;
@@ -429,21 +383,6 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 	playerint[255]->init(new CCallback(gs,255,this));
 }
 
-void CClient::runServer(const char * portc)
-{
-	static std::string comm = std::string(BIN_DIR PATH_SEPARATOR 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()
-{
-	intpr::scoped_lock<intpr::interprocess_mutex> slock(shared->sr->mutex);
-	while(!shared->sr->ready)
-	{
-		shared->sr->cond.wait(slock);
-	}
-}
-
 template <typename Handler>
 void CClient::serialize( Handler &h, const int version )
 {
@@ -487,16 +426,6 @@ void CClient::serialize( Handler &h, const int version )
 	}
 }
 
-CPack * CClient::retreivePack()
-{
-	CPack *ret = NULL;
-	boost::unique_lock<boost::mutex> lock(*serv->rmx);
-	tlog5 << "Listening... ";
-	*serv >> ret;
-	tlog5 << "\treceived server message of type " << typeid(*ret).name() << std::endl;
-	return ret;
-}
-
 void CClient::handlePack( CPack * pack )
 {			
 	CBaseForCLApply *apply = applier->apps[typeList.getTypeID(pack)]; //find the applier
@@ -564,3 +493,79 @@ void CClient::stopConnection()
 
 template void CClient::serialize( CISer<CLoadFile> &h, const int version );
 template void CClient::serialize( COSer<CSaveFile> &h, const int version );
+
+void CServerHandler::startServer()
+{
+	th.update();
+	
+	serverThread = new boost::thread(&CServerHandler::callServer, this); //runs server executable; 	//TODO: will it work on non-windows platforms?
+	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();
+	CConnection *ret = NULL;
+	while(!ret)
+	{
+		try
+		{
+			tlog0 << "Establishing connection...\n";
+			ret = new CConnection(conf.cc.server, port, NAME);
+		}
+		catch(...)
+		{
+			tlog1 << "\nCannot establish connection! Retrying within 2 seconds" <<std::endl;
+			SDL_Delay(2000);
+		}
+	}
+	if(verbose)
+		tlog0<<"\tConnecting to the server: "<<th.getDif()<<std::endl;
+
+	return ret;
+}
+
+CServerHandler::CServerHandler()
+{
+	serverThread = NULL;
+	shared = NULL;
+	port = boost::lexical_cast<std::string>(conf.cc.port);
+
+	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()
+{
+	std::string comm = std::string(BIN_DIR PATH_SEPARATOR SERVER_NAME " ") + port + " > server_log.txt";
+	std::system(comm.c_str());
+	tlog0 << "Server finished\n";
+}

+ 21 - 5
client/Client.h

@@ -27,9 +27,30 @@ struct BattleAction;
 struct SharedMem;
 class CClient;
 struct CPathsInfo;
+namespace boost { class thread; }
 
 void processCommand(const std::string &message, CClient *&client);
 
+//structure to handle running server and connecting to it
+class CServerHandler
+{
+private:
+	void callServer(); //calls server via system(), should be called as thread
+public:
+	timeHandler th;
+	boost::thread *serverThread; //thread that called system to run server
+	SharedMem *shared; //interprocess memory (for waiting for server)
+	bool verbose; //whether to print log msgs
+	std::string port; //port number in text form
+
+	void startServer(); //creates a thread with callServer
+	void waitForServer(); //waits till server is ready
+	CConnection * connectToServer(); //connects to server
+
+	CServerHandler();
+	~CServerHandler();
+};
+
 class CClient : public IGameCallback
 {
 public:
@@ -38,7 +59,6 @@ public:
 	std::map<ui8,CGameInterface *> playerint;
 	bool hotSeat;
 	CConnection *serv;
-	SharedMem *shared;
 	BattleAction *curbaction;
 	CPathsInfo *pathInfo;
 
@@ -111,10 +131,6 @@ public:
 	friend class CCallback; //handling players actions
 	friend void processCommand(const std::string &message, CClient *&client); //handling console
 	
-	
-	static void runServer(const char * portc);
-	void waitForServer();
-	CPack * retreivePack(); //gets from server next pack (allocates it with new)
 	void handlePack( CPack * pack ); //applies the given pack and deletes it
 	void updatePaths();
 

+ 8 - 24
lib/CGameState.cpp

@@ -66,7 +66,12 @@ class CBaseForGSApply
 public:
 	virtual void applyOnGS(CGameState *gs, void *pack) const =0; 
 	virtual ~CBaseForGSApply(){};
+	template<typename U> static CBaseForGSApply *getApplier(const U * t=NULL)
+	{
+		return new CApplyOnGS<U>;
+	}
 };
+
 template <typename T> class CApplyOnGS : public CBaseForGSApply
 {
 public:
@@ -80,29 +85,7 @@ public:
 	}
 };
 
-class CGSApplier
-{
-public:
-	std::map<ui16,CBaseForGSApply*> apps; 
-
-	CGSApplier()
-	{
-		registerTypes2(*this);
-	}
-	~CGSApplier()
-	{
-		std::map<ui16,CBaseForGSApply*>::iterator iter;
-
-		for(iter = apps.begin(); iter != apps.end(); iter++)
-			delete iter->second;
-	}
-	template<typename T> void registerType(const T * t=NULL)
-	{
-		ui16 ID = typeList.registerType(t);
-		apps[ID] = new CApplyOnGS<T>;
-	}
-
-} *applierGs = NULL;
+CApplier<CBaseForGSApply> *applierGs = NULL;
 
 class IObjectCaller
 {
@@ -1373,7 +1356,8 @@ CGameState::CGameState()
 	map = NULL;
 	curB = NULL;
 	scenarioOps = NULL;
-	applierGs = new CGSApplier;
+	applierGs = new CApplier<CBaseForGSApply>;
+	registerTypes2(*applierGs);
 	objCaller = new CObjectCallersHandler;
 	campaign = NULL;
 }

+ 11 - 0
lib/Connection.cpp

@@ -20,6 +20,7 @@
 #include "../hch/CHeroHandler.h"
 #include "../hch/CTownHandler.h"
 #include "../hch/CCampaignHandler.h"
+#include "NetPacks.h"
 
 
 /*
@@ -219,6 +220,16 @@ void CConnection::reportState(CLogger &out)
 	}
 }
 
+CPack * CConnection::retreivePack()
+{
+	CPack *ret = NULL;
+	boost::unique_lock<boost::mutex> lock(*rmx);
+	tlog5 << "Listening... ";
+	*this >> ret;
+	tlog5 << "\treceived server message of type " << typeid(*ret).name() << std::endl;
+	return ret;
+}
+
 CSaveFile::CSaveFile( const std::string &fname )
 	:sfile(NULL)
 {

+ 24 - 0
lib/Connection.h

@@ -30,6 +30,7 @@ class CGameState;
 class CCreature;
 class LibClasses;
 class CHero;
+class CPack;
 extern DLL_EXPORT LibClasses * VLC;
 namespace mpl = boost::mpl;
 
@@ -863,6 +864,29 @@ public:
     template<class T>
     CConnection &operator&(const T&);
 	~CConnection(void);
+
+	CPack *retreivePack(); //gets from server next pack (allocates it with new)
+};
+
+template<typename T>
+class CApplier
+{
+public:
+	std::map<ui16,T*> apps; 
+
+	~CApplier()
+	{
+		std::map<ui16,T*>::iterator iter;
+
+		for(iter = apps.begin(); iter != apps.end(); iter++)
+			delete iter->second;
+	}
+	template<typename U> void registerType(const U * t=NULL)
+	{
+		ui16 ID = typeList.registerType(t);
+		apps[ID] = T::getApplier(t);
+	}
+
 };
 
 #endif // __CONNECTION_H__

+ 18 - 0
lib/NetPacks.h

@@ -23,6 +23,7 @@ class CGameHandler;
 class CConnection;
 class CCampaignState;
 class CArtifact;
+class CSelectionScreen;
 
 struct CPack
 {
@@ -1618,5 +1619,22 @@ struct CenterView : public CPackForClient//515
 	}
 };
 
+/***********************************************************************************************************/
+
+struct CPackForSelectionScreen : public CPack
+{
+	void apply(CSelectionScreen *selScreen){}; //that functions are implemented in CPreGame.cpp
+};
+
+struct ChatMessage : public CPackForSelectionScreen
+{
+	std::string playerName, message;
+
+	void apply(CSelectionScreen *selScreen);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & playerName & message;
+	}
+};
 
 #endif //__NETPACKS_H__

+ 16 - 3
lib/RegisterTypes.cpp

@@ -1,12 +1,11 @@
-#define VCMI_DLL
+
+
 #include "Connection.h"
 #include "NetPacks.h"
 #include "VCMI_Lib.h"
 #include "../hch/CObjectHandler.h"
 #include "../hch/CHeroHandler.h"
 #include "../hch/CTownHandler.h"
-#include "RegisterTypes.h"
-
 /*
  * RegisterTypes.cpp, part of VCMI engine
  *
@@ -17,6 +16,13 @@
  *
  */
 
+#ifndef VCMI_DLL
+	#undef DLL_EXPORT
+	#define DLL_EXPORT
+#endif
+
+#include "RegisterTypes.h"
+
 template<typename Serializer> DLL_EXPORT
 void registerTypes1(Serializer &s)
 {
@@ -171,10 +177,17 @@ void registerTypes3(Serializer &s)
 	s.template registerType<PlayerMessage>();
 }
 
+template<typename Serializer> DLL_EXPORT
+void registerTypes4(Serializer &s)
+{
+	s.template registerType<ChatMessage>();
+}
+
 template<typename Serializer> DLL_EXPORT
 void registerTypes(Serializer &s)
 {
 	registerTypes1(s);
 	registerTypes2(s);
 	registerTypes3(s);
+	registerTypes4(s);
 }

+ 9 - 17
server/CGameHandler.cpp

@@ -60,10 +60,16 @@ CondSh<BattleResult *> battleResult(NULL);
 std::ptrdiff_t randomizer (ptrdiff_t i) {return rand();}
 std::ptrdiff_t (*p_myrandom)(std::ptrdiff_t) = randomizer;
 
+
 class CBaseForGHApply
 {
 public:
 	virtual bool applyOnGH(CGameHandler *gh, CConnection *c, void *pack) const =0; 
+	virtual ~CBaseForGHApply(){}
+	template<typename U> static CBaseForGHApply *getApplier(const U * t=NULL)
+	{
+		return new CApplyOnGH<U>;
+	}
 };
 template <typename T> class CApplyOnGH : public CBaseForGHApply
 {
@@ -76,22 +82,7 @@ public:
 	}
 };
 
-class CGHApplier
-{
-public:
-	std::map<ui16,CBaseForGHApply*> apps; 
-
-	CGHApplier()
-	{
-		registerTypes3(*this);
-	}
-	template<typename T> void registerType(const T * t=NULL)
-	{
-		ui16 ID = typeList.registerType(t);
-		apps[ID] = new CApplyOnGH<T>;
-	}
-
-} *applier = NULL;
+CApplier<CBaseForGHApply> *applier = NULL;
 
 CMP_stack cmpst ;
 
@@ -938,7 +929,8 @@ CGameHandler::CGameHandler(void)
 	QID = 1;
 	gs = NULL;
 	IObjectInterface::cb = this;
-	applier = new CGHApplier;
+	applier = new CApplier<CBaseForGHApply>;
+	registerTypes3(*applier);
 	visitObjectAfterVictory = false; 
 }