Browse Source

New file for VCMI_Server - NetPacksServer.cpp
Redone client -> server protocol.

Michał W. Urbańczyk 16 years ago
parent
commit
4653ca6b29
18 changed files with 674 additions and 1217 deletions
  1. 0 2
      CBattleInterface.cpp
  2. 26 28
      CCallback.cpp
  3. 19 5
      CGameState.cpp
  4. 3 2
      CGameState.h
  5. 2 1
      CMT.cpp
  6. 8 1
      ChangeLog
  7. 2 2
      client/Client.cpp
  8. 1 1
      client/Client.h
  9. 1 1
      int3.h
  10. 23 5
      lib/IGameCallback.cpp
  11. 2 1
      lib/IGameCallback.h
  12. 318 43
      lib/NetPacks.h
  13. 12 12
      lib/NetPacksLib.cpp
  14. 31 2
      lib/RegisterTypes.h
  15. 52 1062
      server/CGameHandler.cpp
  16. 30 49
      server/CGameHandler.h
  17. 140 0
      server/NetPacksServer.cpp
  18. 4 0
      server/VCMI_server.vcproj

+ 0 - 2
CBattleInterface.cpp

@@ -1708,8 +1708,6 @@ void CBattleInterface::spellCasted(SpellCasted * sc)
 				SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			}
 			SDL_SetClipRect(screen, &buf); //restoring previous clip rect
-
-			int b=0; //TODO use me
 			break; //for 15 and 16 cases
 		}
 	case 17: //lightning bolt

+ 26 - 28
CCallback.cpp

@@ -97,11 +97,7 @@ bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType)
 	if (pathType==0)
 		CPathfinder::convertPath(path,pathType);
 	if (pathType>1)
-#ifndef __GNUC__
-		throw std::exception("Unknown path format");
-#else
-		throw std::exception();
-#endif
+		throw std::string("Unknown path format");
 
 	CPath * ourPath = path; 
 	if(!ourPath)
@@ -111,13 +107,14 @@ bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType)
 		int3 stpos(ourPath->nodes[i].coord.x, ourPath->nodes[i].coord.y, hero->pos.z), 
 			endpos(ourPath->nodes[i-1].coord.x, ourPath->nodes[i-1].coord.y, hero->pos.z);
 		HeroMoveDetails curd(stpos,endpos,hero);
-		*cl->serv << ui16(501) << hero->id << stpos << endpos;
+		*cl->serv << &MoveHero(endpos,hero->id);
+
 		{//wait till there is server answer
 			boost::unique_lock<boost::mutex> lock(*mess.mx);
 			while(std::find_if(mess.res->begin(),mess.res->end(),&isType<501>) == mess.res->end())
 				mess.cv->wait(lock);
 			std::set<CPack*>::iterator itr = std::find_if(mess.res->begin(),mess.res->end(),&isType<501>);
-			TryMoveHero *tmh = static_cast<TryMoveHero*>(*itr);
+			TryMoveHero *tmh = dynamic_cast<TryMoveHero*>(*itr);
 			mess.res->erase(itr);
 			if(!tmh->result)
 			{
@@ -132,12 +129,12 @@ bool CCallback::moveHero(int ID, CPath * path, int idtype, int pathType)
 
 void CCallback::selectionMade(int selection, int asker)
 {
-	*cl->serv << ui16(2001) << ui32(asker) << ui32(selection);
+	*cl->serv << &QueryReply(asker,selection);
 }
 void CCallback::recruitCreatures(const CGObjectInstance *obj, ui32 ID, ui32 amount)
 {
 	if(player!=obj->tempOwner) return;
-	*cl->serv << ui16(506) << obj->id << ID << amount;
+	*cl->serv << &RecruitCreatures(obj->id,ID,amount);
 }
 
 
@@ -145,20 +142,18 @@ bool CCallback::dismissCreature(const CArmedInstance *obj, int stackPos)
 {
 	if(((player>=0)  &&  obj->tempOwner != player) || obj->army.slots.size()<2)
 		return false;
-	*cl->serv << ui16(503) << obj->id <<  ui8(stackPos);
+	*cl->serv << &DisbandCreature(stackPos,obj->id);
 	return true;
 }
 bool CCallback::upgradeCreature(const CArmedInstance *obj, int stackPos, int newID)
 {
-	*cl->serv << ui16(507) << obj->id <<  ui8(stackPos) << ui32(newID);
+	*cl->serv << &UpgradeCreature(stackPos,obj->id,newID);
 	return false;
 }
 void CCallback::endTurn()
 {
 	tlog5 << "Player "<<(unsigned)player<<" end his turn."<<std::endl;
-	cl->serv->wmx->lock();
-	*cl->serv << ui16(100); //report that we ended turn
-	cl->serv->wmx->unlock();
+	*cl->serv << &EndTurn(); //report that we ended turn
 }
 UpgradeInfo CCallback::getUpgradeInfo(const CArmedInstance *obj, int stackPos) const
 {
@@ -388,7 +383,7 @@ int CCallback::swapCreatures(const CGObjectInstance *s1, const CGObjectInstance
 {
 	if(s1->tempOwner != player   ||   s2->tempOwner != player)
 		return -1;
-	*cl->serv << ui16(502) << ui8(1) << s1->id << ui8(p1) << s2->id << ui8(p2);
+	*cl->serv << &ArrangeStacks(1,p1,p2,s1->id,s2->id,0);
 	return 0;
 }
 
@@ -398,7 +393,7 @@ int CCallback::mergeStacks(const CGObjectInstance *s1, const CGObjectInstance *s
 	{
 		return -1;
 	}
-	*cl->serv << ui16(502) << ui8(2) << s1->id << ui8(p1) << s2->id << ui8(p2);
+	*cl->serv << &ArrangeStacks(2,p1,p2,s1->id,s2->id,0);
 	return 0;
 }
 int CCallback::splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2, int p1, int p2, int val)
@@ -407,14 +402,14 @@ int CCallback::splitStack(const CGObjectInstance *s1, const CGObjectInstance *s2
 	{
 		return -1;
 	}
-	*cl->serv << ui16(502) << ui8(3) << s1->id << ui8(p1) << s2->id << ui8(p2) << si32(val);
+	*cl->serv << &ArrangeStacks(3,p1,p2,s1->id,s2->id,val);
 	return 0;
 }
 
 bool CCallback::dismissHero(const CGHeroInstance *hero)
 {
 	if(player!=hero->tempOwner) return false;
-	*cl->serv << ui16(500) << hero->id;
+	*cl->serv << &DismissHero(hero->id);
 	return true;
 }
 
@@ -443,7 +438,7 @@ bool CCallback::buildBuilding(const CGTownInstance *town, si32 buildingID)
 		if(b->resources[i] > gs->players[player].resources[i])
 			return false; //lack of resources
 
-	*cl->serv << ui16(504) << town->id << buildingID;
+	*cl->serv << &BuildStructure(town->id,buildingID);
 	return true;
 }
 
@@ -483,7 +478,7 @@ CStack* CCallback::battleGetStackByID(int ID)
 
 int CCallback::battleMakeAction(BattleAction* action)
 {
-	*cl->serv << ui16(3003) << *action;
+	*cl->serv << &MakeAction(*action);
 	return 0;
 }
 
@@ -612,7 +607,7 @@ void CCallback::swapGarrisonHero( const CGTownInstance *town )
 void CCallback::buyArtifact(const CGHeroInstance *hero, int aid)
 {
 	if(hero->tempOwner != player) return;
-	*cl->serv << ui16(510) << hero->id << ui32(aid);
+	*cl->serv << &BuyArtifact(hero->id,aid);
 }
 
 std::vector < const CGObjectInstance * > CCallback::getBlockingObjs( int3 pos ) const
@@ -681,13 +676,13 @@ void CCallback::trade( int mode, int id1, int id2, int val1 )
 {
 	int p1, p2;
 	getMarketOffer(id1,id2,p1,p2,mode);
-	*cl->serv << ui16(511) << ui8(player) << ui32(mode)  << ui32(id1) << ui32(id2) << ui32(val1);
+	*cl->serv << &TradeOnMarketplace(player,mode,id1,id2,val1);
 }
 
 void CCallback::setFormation(const CGHeroInstance * hero, bool tight)
 {
 	const_cast<CGHeroInstance*>(hero)->army.formation = tight;
-	*cl->serv << ui16(512) << hero->id << ui8(tight);
+	*cl->serv << &SetFormation(hero->id,tight);
 }
 
 void CCallback::setSelection(const CArmedInstance * obj)
@@ -695,17 +690,20 @@ void CCallback::setSelection(const CArmedInstance * obj)
 	SetSelection ss;
 	ss.player = player;
 	ss.id = obj->id;
-	*cl->serv << ui16(514) << ss;
+	*cl->serv << &ss;
 }
 
 void CCallback::recruitHero(const CGTownInstance *town, const CGHeroInstance *hero)
 {
 	ui8 i=0;
-	for(;i<gs->players[player].availableHeroes.size();i++)
+	for(; i<gs->players[player].availableHeroes.size(); i++)
+	{
 		if(gs->players[player].availableHeroes[i] == hero)
-			break;
-	if(i>1) return;
-	*cl->serv << ui16(515) << town->id << i;
+		{
+			*cl->serv << &HireHero(town->id,i);
+			return;
+		}
+	}
 }
 
 std::vector<const CGHeroInstance *> CCallback::getAvailableHeroes(const CGTownInstance * town) const

+ 19 - 5
CGameState.cpp

@@ -1116,7 +1116,8 @@ void CGameState::init(StartInfo * si, Mapa * map, int Seed)
 					j->second.first = vti->town->upgradedCreatures[ (j->second.first-197) / 2 ];
 			}
 		}
-		players[vti->getOwner()].towns.push_back(vti);
+		if(vti->getOwner() != 255)
+			getPlayer(vti->getOwner())->towns.push_back(vti);
 	}
 
 	for(std::map<ui8, PlayerState>::iterator k=players.begin(); k!=players.end(); ++k)
@@ -1297,8 +1298,8 @@ float CGameState::getMarketEfficiency( int player, int mode/*=0*/ )
 	boost::shared_lock<boost::shared_mutex> lock(*mx);
 	if(mode) return -1; //todo - support other modes
 	int mcount = 0;
-	for(int i=0;i<players[player].towns.size();i++)
-		if(vstd::contains(players[player].towns[i]->builtBuildings,14))
+	for(int i=0;i<getPlayer(player)->towns.size();i++)
+		if(vstd::contains(getPlayer(player)->towns[i]->builtBuildings,14))
 			mcount++;
 	float ret = std::min(((float)mcount+1.0f)/20.0f,0.5f);
 	return ret;
@@ -1453,7 +1454,7 @@ int CGameState::canBuildStructure( const CGTownInstance *t, int ID )
 	CBuilding * pom = VLC->buildh->buildings[t->subID][ID];
 	for(int res=0;res<7;res++) //TODO: support custom amount of resources
 	{
-		if(pom->resources[res] > players[t->tempOwner].resources[res])
+		if(pom->resources[res] > getPlayer(t->tempOwner)->resources[res])
 			ret = 6; //lack of res
 	}
 
@@ -1491,6 +1492,19 @@ void CGameState::apply(CPack *pack)
 	applier->apps[typeList.getTypeID(pack)]->applyOnGS(this,pack);
 }
 
+PlayerState * CGameState::getPlayer( ui8 color )
+{
+	if(vstd::contains(players,color))
+	{
+		return &players[color];
+	}
+	else 
+	{
+		tlog2 << "Warning: Cannot find info for player " << int(color) << std::endl;
+		return NULL;
+	}
+}
+
 int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, const CGHeroInstance * attackerHero, const CGHeroInstance * defendingHero, bool shooting)
 {
 	int attackerAttackBonus = attacker->creature->attack + (attackerHero ? attackerHero->getPrimSkillLevel(0) : 0);
@@ -1637,7 +1651,7 @@ int BattleInfo::calculateDmg(const CStack* attacker, const CStack* defender, con
 			dmgBonusMultiplier *= 0.8f;
 	}
 
-	return (float)damageBase * (float)attacker->amount * dmgBonusMultiplier;
+	return int(  (float)damageBase * (float)attacker->amount * dmgBonusMultiplier  );
 }
 
 void BattleInfo::calculateCasualties( std::set<std::pair<ui32,si32> > *casualties )

+ 3 - 2
CGameState.h

@@ -224,6 +224,7 @@ public:
 
 	boost::shared_mutex *mx;
 
+	PlayerState *getPlayer(ui8 color);
 	void init(StartInfo * si, Mapa * map, int Seed);
 	void loadTownDInfos();
 	void randomizeObject(CGObjectInstance *cur);
@@ -257,10 +258,10 @@ public:
 			//recreating towns/heroes vectors in players entries
 			for(int i=0; i<map->towns.size(); i++)
 				if(map->towns[i]->tempOwner < PLAYER_LIMIT)
-					players[map->towns[i]->tempOwner].towns.push_back(map->towns[i]);
+					getPlayer(map->towns[i]->tempOwner)->towns.push_back(map->towns[i]);
 			for(int i=0; i<map->heroes.size(); i++)
 				if(map->heroes[i]->tempOwner < PLAYER_LIMIT)
-					players[map->heroes[i]->tempOwner].heroes.push_back(map->heroes[i]);
+					getPlayer(map->heroes[i]->tempOwner)->heroes.push_back(map->heroes[i]);
 			//recreating available heroes
 			for(std::map<ui8,PlayerState>::iterator i=players.begin(); i!=players.end(); i++)
 			{

+ 2 - 1
CMT.cpp

@@ -41,6 +41,7 @@
 #include "lib/Connection.h"
 #include "lib/VCMI_Lib.h"
 #include <cstdlib>
+#include "lib/NetPacks.h"
 
 #if __MINGW32__
 #undef main
@@ -328,6 +329,6 @@ void processCommand(const std::string &message, CClient *&client)
 	}
 	else if(client && client->serv && client->serv->connected) //send to server
 	{
-		*client->serv << ui16(513) << message;
+		*client->serv << &PlayerMessage(255,message);
 	}
 }

+ 8 - 1
ChangeLog

@@ -1,4 +1,4 @@
-0.7 -> 0.71 (as for r726)
+0.7 -> 0.71 (as for r751)
 GENERAL:
 * fixed scrolling behind window problem (now it's possible to scroll with CTRL + arrows) 
 * morale/luck system and corresponding sec. skills supported 
@@ -30,7 +30,14 @@ BATTLES:
 * spells not known by hero can't be casted 
 * spell books won't be placed in War Machine slots after battle
 * attack is now possible when hex under cursor is not displayed 
+* glowing effect of yellow border around creatures
+* blue glowing border around hovered creature
+* made animation on battlefield more smooth
+* standing stacks have more static animation
 * fixes for two-hex creatures actions
+* fixed hero casting spell animation
+* corrected stack death animation
+* correct handling of flying creatures in battles
 * a few tweaks in battle path/available hexes calculation (more of them is needed)
 * fixed positions of stack queue and battle result window when resolution is != 800x600 
 * corrected duration of frenzy spell which was incorrect in certain cases 

+ 2 - 2
client/Client.cpp

@@ -137,7 +137,7 @@ void CClient::close()
 
 	tlog3 << "Connection has been requested to be closed.\n";
 	boost::unique_lock<boost::mutex>(*serv->wmx);
-	*serv << ui16(99);
+	*serv << &CloseServer();
 	tlog3 << "Sent closing signal to the server\n";
 	serv->close();
 	tlog3 << "Our socket has been closed.\n";
@@ -151,7 +151,7 @@ void CClient::save(const std::string & fname)
 		return;
 	}
 
-	*serv << ui16(98) << fname;
+	*serv << &SaveGame(fname);
 }
 
 void CClient::load( const std::string & fname )

+ 1 - 1
client/Client.h

@@ -85,7 +85,7 @@ public:
 	void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb){}; //use hero=NULL for no hero
 	void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb){}; //for hero<=>neutral army
 	void setAmount(int objid, ui32 val){};
-	void moveHero(int hid, int3 pos, bool instant){};
+	void moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255){};
 	void giveHeroBonus(GiveBonus * bonus){};
 	void setMovePoints(SetMovePoints * smp){};
 	void setManaPoints(int hid, int val){};

+ 1 - 1
int3.h

@@ -35,7 +35,7 @@ public:
 	}
 	operator bool() const
 	{
-		return slots.size();
+		return slots.size()>0;
 	}
 };
 

+ 23 - 5
lib/IGameCallback.cpp

@@ -7,15 +7,33 @@
 
 const CGObjectInstance* IGameCallback::getObj(int objid)
 {
+	if(objid < 0  ||  objid >= gs->map->objects.size())
+	{
+		tlog1 << "Cannot get object with id " << objid << std::endl;
+		return NULL;
+	}
+	else if (!gs->map->objects[objid])
+	{
+		tlog1 << "Cannot get object with id " << objid << ". Object was removed.\n";
+		return NULL;
+	}
 	return gs->map->objects[objid];
 }
 const CGHeroInstance* IGameCallback::getHero(int objid)
 {
-	return dynamic_cast<const CGHeroInstance*>(gs->map->objects[objid]);
+	const CGObjectInstance *obj = getObj(objid);
+	if(obj)
+		return dynamic_cast<const CGHeroInstance*>(obj);
+	else
+		return NULL;
 }
 const CGTownInstance* IGameCallback::getTown(int objid)
 {
-	return dynamic_cast<const CGTownInstance*>(gs->map->objects[objid]);
+	const CGObjectInstance *obj = getObj(objid);
+	if(obj)
+		return dynamic_cast<const CGTownInstance*>(gs->map->objects[objid]);
+	else
+		return NULL;
 }
 
 int IGameCallback::getOwner(int heroID)
@@ -45,10 +63,10 @@ int IGameCallback::getHeroCount( int player, bool includeGarrisoned )
 {
 	int ret = 0;
 	if(includeGarrisoned)
-		return gs->players[player].heroes.size();
+		return gs->getPlayer(player)->heroes.size();
 	else
-		for(int i=0; i < gs->players[player].heroes.size(); i++)
-			if(!gs->players[player].heroes[i]->inTownGarrison)
+		for(int i=0; i < gs->getPlayer(player)->heroes.size(); i++)
+			if(!gs->getPlayer(player)->heroes[i]->inTownGarrison)
 				ret++;
 	return ret;
 }

+ 2 - 1
lib/IGameCallback.h

@@ -59,7 +59,7 @@ public:
 	virtual void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb)=0; //use hero=NULL for no hero
 	virtual void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb)=0; //for hero<=>neutral army
 	virtual void setAmount(int objid, ui32 val)=0;
-	virtual void moveHero(int hid, int3 pos, bool instant)=0;
+	virtual void moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255)=0;
 	virtual void giveHeroBonus(GiveBonus * bonus)=0;
 	virtual void setMovePoints(SetMovePoints * smp)=0;
 	virtual void setManaPoints(int hid, int val)=0;
@@ -67,5 +67,6 @@ public:
 	virtual void changeObjPos(int objid, int3 newPos, ui8 flags)=0;
 
 	friend struct CPackForClient;
+	friend struct CPackForServer;
 };
 #endif // __IGAMECALLBACK_H__

+ 318 - 43
lib/NetPacks.h

@@ -8,6 +8,8 @@
 
 class CClient;
 class CGameState;
+class CGameHandler;
+class CConnection;
 
 struct CPack
 {
@@ -20,27 +22,36 @@ struct CPack
 	{
 		tlog1 << "CPack serialized... this should not happen!\n";
 	}
+	DLL_EXPORT void applyGs(CGameState *gs)
+	{};
 };
 
 struct CPackForClient : public CPack
 {
-	CGameState* GS(CClient *cl);
-	CPackForClient(){type = 0;};
+	CPackForClient(){type = 1;};
 
+	CGameState* GS(CClient *cl);
 	void applyFirstCl(CClient *cl)//called before applying to gs
-	{
-		//tlog1 << "CPackForClient::applyFirstCl - We should not be here!\n";
-	};
-	DLL_EXPORT void applyGs(CGameState *gs)
-	{
-		//tlog1 << "CPackForClient::applyGs - We should not be here!\n";
-	};
+	{};
 	void applyCl(CClient *cl)//called after applying to gs
+	{}; 
+};
+
+struct CPackForServer : public CPack
+{
+	CConnection *c;
+	CGameState* GS(CGameHandler *gh);
+	CPackForServer()
 	{
-		//tlog1 << "CPackForClient::applyCl - We should not be here!\n";
-	}; 
+		type = 2; 
+		c = NULL;
+	};
+
+	void applyGh(CGameHandler *gh)//called after applying to gs
+	{}; 
 };
 
+
 struct Query : public CPackForClient
 {
 	ui32 id;
@@ -80,8 +91,11 @@ struct MetaString : public CPack //2001 helper for object scrips
 	MetaString(){type = 2001;};
 }; 
 
+/***********************************************************************************************************/
+
 struct SystemMessage : public CPackForClient //95
 {
+	SystemMessage(const std::string Text) : text(Text){type = 95;};
 	SystemMessage(){type = 95;};
 	void applyCl(CClient *cl);
 
@@ -394,38 +408,7 @@ struct SetHeroArtifacts : public CPackForClient //509
 	{
 		h & hid & artifacts & artifWorn;
 	}
-};  
-
-struct PlayerMessage : public CPackForClient //513
-{
-	PlayerMessage(){type = 513;};
-	PlayerMessage(ui8 Player, const std::string &Text)
-		:player(Player),text(Text)
-	{type = 513;};
-	void applyCl(CClient *cl);
-
-	ui8 player;
-	std::string text;
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & text & player;
-	}
-};  
-
-struct SetSelection : public CPackForClient //514
-{
-	SetSelection(){type = 514;};
-	DLL_EXPORT void applyGs(CGameState *gs);
-
-	ui8 player;
-	ui32 id;
-
-	template <typename Handler> void serialize(Handler &h, const int version)
-	{
-		h & id & player;
-	}
-};  
+};   
 
 struct HeroRecruited : public CPackForClient //515
 {
@@ -793,4 +776,296 @@ struct ShowInInfobox : public CPackForClient //107
 		h & player & c & text;
 	}
 };
+
+/***********************************************************************************************************/
+
+struct SaveGame : public CPackForServer
+{
+	SaveGame(){};
+	SaveGame(const std::string &Fname) :fname(Fname){};
+	std::string fname;
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & fname;
+	}
+};
+
+struct CloseServer : public CPackForServer
+{
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{}
+};
+
+struct EndTurn : public CPackForServer
+{
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{}
+};
+
+struct DismissHero : public CPackForServer
+{
+	DismissHero(){};
+	DismissHero(si32 HID) : hid(hid) {};
+	si32 hid;
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & hid;
+	}
+};
+
+struct MoveHero : public CPackForServer
+{
+	MoveHero(){};
+	MoveHero(const int3 &Dest, si32 HID) : dest(Dest), hid(HID){};
+	int3 dest;
+	si32 hid;
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & dest & hid;
+	}
+};
+
+struct ArrangeStacks : public CPackForServer
+{
+	ArrangeStacks(){};
+	ArrangeStacks(ui8 W, ui8 P1, ui8 P2, si32 ID1, si32 ID2, si32 VAL)
+		:what(W),p1(P1),p2(P2),id1(ID1),id2(ID2),val(VAL) {};
+
+	ui8 what; //1 - swap; 2 - merge; 3 - split
+	ui8 p1, p2; //positions of first and second stack
+	si32 id1, id2; //ids of objects with garrison
+	si32 val;
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & what & p1 & p2 & id1 & id2 & val;
+	}
+};
+
+struct DisbandCreature : public CPackForServer
+{
+	DisbandCreature(){};
+	DisbandCreature(ui8 Pos, si32 ID):pos(Pos),id(ID){};
+	ui8 pos; //stack pos
+	si32 id; //object id
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & pos & id;
+	}
+};
+
+struct BuildStructure : public CPackForServer
+{
+	BuildStructure(){};
+	BuildStructure(si32 TID, si32 BID):tid(TID),bid(BID){};
+	si32 bid, tid; //structure and town ids
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & tid & bid;
+	}
+};
+
+struct RecruitCreatures : public CPackForServer
+{
+	RecruitCreatures(){};
+	RecruitCreatures(si32 TID, si32 CRID, si32 Amount):tid(TID),crid(CRID),amount(Amount){};
+	si32 tid; //town id
+	ui32 crid, amount;//creature ID and amount
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & tid & crid & amount;
+	}
+};
+
+struct UpgradeCreature : public CPackForServer
+{
+	UpgradeCreature(){};
+	UpgradeCreature(ui8 Pos, si32 ID, si32 CRID):pos(Pos),id(ID), cid(CRID){};
+	ui8 pos; //stack pos
+	si32 id; //object id
+	si32 cid; //id of type to which we want make upgrade
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & pos & id & cid;
+	}
+};
+
+struct GarrisonHeroSwap : public CPackForServer
+{
+	GarrisonHeroSwap(){};
+	GarrisonHeroSwap(si32 TID):tid(TID){};
+	si32 tid; 
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & tid;
+	}
+};
+
+struct ExchangeArtifacts : public CPackForServer
+{
+	ExchangeArtifacts(){};
+	ExchangeArtifacts(si32 H1, si32 H2, ui16 S1, ui16 S2)
+		:hid1(H1),hid2(H2),slot1(S1),slot2(S2){};
+	si32 hid1, hid2;
+	ui16 slot1, slot2;
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & hid1 & hid2 & slot1 & slot2;
+	}
+};
+
+struct BuyArtifact : public CPackForServer
+{
+	BuyArtifact(){};
+	BuyArtifact(si32 HID, si32 AID):hid(HID),aid(AID){};
+	si32 hid, aid; //hero and artifact id
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & hid & aid;
+	}
+};
+
+struct TradeOnMarketplace : public CPackForServer
+{
+	TradeOnMarketplace(){};
+	TradeOnMarketplace(ui8 Player, ui8 Mode, /*si32 ID, */ui32 R1, ui32 R2, ui32 Val)
+		:player(Player),mode(Mode),/*id(ID),*/r1(R1),r2(R2),val(Val){};
+	ui8 player;
+	ui8 mode;//0 - res<->res; 
+	//si32 id; //object id
+	ui32 r1, r2; //mode 0: r1 - sold resource, r2 - bought res
+	ui32 val; //units of sold resource
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & player & mode & /*id & */r1 & r2 & val;
+	}
+};
+
+struct SetFormation : public CPackForServer
+{
+	SetFormation(){};
+	SetFormation(si32 HID, ui8 Formation):hid(HID),formation(Formation){};
+	si32 hid;
+	ui8 formation;
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & hid & formation;
+	}
+};
+
+struct HireHero : public CPackForServer
+{
+	HireHero(){};
+	HireHero(si32 HID, si32 TID):hid(HID),tid(TID){};
+	si32 hid, tid; //available hero serial and town id
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & hid & tid;
+	}
+};
+
+struct QueryReply : public CPackForServer
+{
+	QueryReply(){};
+	QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){};
+	ui32 qid, answer; //hero and artifact id
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & qid & answer;
+	}
+};
+
+struct MakeAction : public CPackForServer
+{
+	MakeAction(){};
+	MakeAction(const BattleAction &BA):ba(ba){};
+	BattleAction ba;
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & ba;
+	}
+};
+
+struct MakeCustomAction : public CPackForServer
+{
+	MakeCustomAction(){};
+	MakeCustomAction(const BattleAction &BA):ba(ba){};
+	BattleAction ba;
+
+	void applyGh(CGameHandler *gh);
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & ba;
+	}
+};
+
+/***********************************************************************************************************/
+
+struct PlayerMessage : public CPackForClient, public CPackForServer //513
+{
+	PlayerMessage(){CPackForClient::type = 513;};
+	PlayerMessage(ui8 Player, const std::string &Text)
+		:player(Player),text(Text)
+	{CPackForClient::type = 513;};
+	void applyCl(CClient *cl);
+	void applyGs(CGameState *gs){};
+	void applyGh(CGameHandler *gh);
+
+	ui8 player;
+	std::string text;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & text & player;
+	}
+}; 
+
+
+struct SetSelection : public CPackForClient, public CPackForServer //514
+{
+	SetSelection(){CPackForClient::type = 514;};
+	DLL_EXPORT void applyGs(CGameState *gs);
+	void applyGh(CGameHandler *gh);
+
+	ui8 player;
+	ui32 id;
+
+	template <typename Handler> void serialize(Handler &h, const int version)
+	{
+		h & id & player;
+	}
+};  
+
 #endif //__NETPACKS_H__

+ 12 - 12
lib/NetPacksLib.cpp

@@ -14,13 +14,13 @@
 
 DLL_EXPORT void SetResource::applyGs( CGameState *gs )
 {
-	gs->players[player].resources[resid] = val;
+	gs->getPlayer(player)->resources[resid] = val;
 }
 
 DLL_EXPORT void SetResources::applyGs( CGameState *gs )
 {
 	for(int i=0;i<res.size();i++)
-		gs->players[player].resources[i] = res[i];
+		gs->getPlayer(player)->resources[i] = res[i];
 }
 
 DLL_EXPORT void SetPrimSkill::applyGs( CGameState *gs )
@@ -127,15 +127,15 @@ DLL_EXPORT void SetMovePoints::applyGs( CGameState *gs )
 DLL_EXPORT void FoWChange::applyGs( CGameState *gs )
 {
 	BOOST_FOREACH(int3 t, tiles)
-		gs->players[player].fogOfWarMap[t.x][t.y][t.z] = mode;
+		gs->getPlayer(player)->fogOfWarMap[t.x][t.y][t.z] = mode;
 }
 
 DLL_EXPORT void SetAvailableHeroes::applyGs( CGameState *gs )
 {
-	gs->players[player].availableHeroes.clear();
+	gs->getPlayer(player)->availableHeroes.clear();
 
 	CGHeroInstance *h = (hid1>=0 ?  gs->hpool.heroesPool[hid1] : NULL);
-	gs->players[player].availableHeroes.push_back(h);
+	gs->getPlayer(player)->availableHeroes.push_back(h);
 	if(h  &&  flags & 1)
 	{
 		h->army.slots.clear();
@@ -143,7 +143,7 @@ DLL_EXPORT void SetAvailableHeroes::applyGs( CGameState *gs )
 	}
 
 	h = (hid2>=0 ?  gs->hpool.heroesPool[hid2] : NULL);
-	gs->players[player].availableHeroes.push_back(h);
+	gs->getPlayer(player)->availableHeroes.push_back(h);
 	if(flags & 2)
 	{
 		h->army.slots.clear();
@@ -180,8 +180,8 @@ DLL_EXPORT void RemoveObject::applyGs( CGameState *gs )
 		std::vector<CGHeroInstance*>::iterator nitr = std::find(gs->map->heroes.begin(), gs->map->heroes.end(),h);
 		gs->map->heroes.erase(nitr);
 		int player = h->tempOwner;
-		nitr = std::find(gs->players[player].heroes.begin(), gs->players[player].heroes.end(), h);
-		gs->players[player].heroes.erase(nitr);
+		nitr = std::find(gs->getPlayer(player)->heroes.begin(), gs->getPlayer(player)->heroes.end(), h);
+		gs->getPlayer(player)->heroes.erase(nitr);
 		if(h->visitedTown)
 		{
 			if(h->inTownGarrison)
@@ -213,7 +213,7 @@ void TryMoveHero::applyGs( CGameState *gs )
 		gs->map->addBlockVisTiles(h);
 	}
 	BOOST_FOREACH(int3 t, fowRevealed)
-		gs->players[h->getOwner()].fogOfWarMap[t.x][t.y][t.z] = 1;
+		gs->getPlayer(h->getOwner())->fogOfWarMap[t.x][t.y][t.z] = 1;
 }
 
 DLL_EXPORT void SetGarrisons::applyGs( CGameState *gs )
@@ -295,7 +295,7 @@ DLL_EXPORT void HeroRecruited::applyGs( CGameState *gs )
 
 	h->initHeroDefInfo();
 	gs->map->heroes.push_back(h);
-	gs->players[h->tempOwner].heroes.push_back(h);
+	gs->getPlayer(h->getOwner())->heroes.push_back(h);
 	gs->map->addBlockVisTiles(h);
 	t->visitingHero = h;
 	h->visitedTown = t;
@@ -310,7 +310,7 @@ DLL_EXPORT void GiveHero::applyGs( CGameState *gs )
 	h->movement =  h->maxMovePoints(true);
 	h->initHeroDefInfo();
 	gs->map->heroes.push_back(h);
-	gs->players[h->tempOwner].heroes.push_back(h);
+	gs->getPlayer(h->getOwner())->heroes.push_back(h);
 	gs->map->addBlockVisTiles(h);
 	h->inTownGarrison = false;
 }
@@ -476,5 +476,5 @@ DLL_EXPORT void YourTurn::applyGs( CGameState *gs )
 
 DLL_EXPORT void SetSelection::applyGs( CGameState *gs )
 {
-	gs->players[player].currentSelection = id;
+	gs->getPlayer(player)->currentSelection = id;
 }

+ 31 - 2
lib/RegisterTypes.h

@@ -29,7 +29,7 @@ template<typename Serializer> DLL_EXPORT void registerTypes1(Serializer &s)
 }
 
 
-//second set of types - derivatives of CPack (network VCMI packages)
+//second set of types - derivatives of CPack for client (network VCMI packages)
 template<typename Serializer> DLL_EXPORT void registerTypes2(Serializer &s)
 {
 	s.registerType<SystemMessage>();
@@ -53,7 +53,6 @@ template<typename Serializer> DLL_EXPORT void registerTypes2(Serializer &s)
 	s.registerType<SetAvailableCreatures>();
 	s.registerType<SetHeroesInTown>();
 	s.registerType<SetHeroArtifacts>();
-	s.registerType<SetSelection>();
 	s.registerType<HeroRecruited>();
 	s.registerType<GiveHero>();
 	s.registerType<NewTurn>();
@@ -75,6 +74,35 @@ template<typename Serializer> DLL_EXPORT void registerTypes2(Serializer &s)
 	s.registerType<SpellCasted>();
 	s.registerType<SetStackEffect>();
 	s.registerType<ShowInInfobox>();
+
+	s.registerType<SetSelection>();
+	s.registerType<PlayerMessage>();
+}
+
+template<typename Serializer> DLL_EXPORT void registerTypes3(Serializer &s)
+{
+	s.registerType<SaveGame>();
+	s.registerType<CloseServer>();
+	s.registerType<EndTurn>();
+	s.registerType<DismissHero>();
+	s.registerType<MoveHero>();
+	s.registerType<ArrangeStacks>();
+	s.registerType<DisbandCreature>();
+	s.registerType<BuildStructure>();
+	s.registerType<RecruitCreatures>();
+	s.registerType<UpgradeCreature>();
+	s.registerType<GarrisonHeroSwap>();
+	s.registerType<ExchangeArtifacts>();
+	s.registerType<BuyArtifact>();
+	s.registerType<TradeOnMarketplace>();
+	s.registerType<SetFormation>();
+	s.registerType<HireHero>();
+	s.registerType<QueryReply>();
+	s.registerType<MakeAction>();
+	s.registerType<MakeCustomAction>();
+
+	s.registerType<SetSelection>();
+	s.registerType<PlayerMessage>();
 }
 
 //register all
@@ -82,4 +110,5 @@ template<typename Serializer> DLL_EXPORT void registerTypes(Serializer &s)
 {
 	registerTypes1(s);
 	registerTypes2(s);
+	registerTypes3(s);
 }

File diff suppressed because it is too large
+ 52 - 1062
server/CGameHandler.cpp


+ 30 - 49
server/CGameHandler.h

@@ -7,6 +7,7 @@
 #include "../CGameState.h"
 #include "../lib/Connection.h"
 #include "../lib/IGameCallback.h"
+#include "../lib/BattleAction.h"
 #include <boost/function.hpp>
 #include <boost/thread.hpp>
 class CVCMIServer;
@@ -56,13 +57,13 @@ public:
 
 class CGameHandler : public IGameCallback
 {
+public:
 	static ui32 QID;
 	CVCMIServer *s;
 	std::map<int,CConnection*> connections; //player color -> connection to clinet with interface of that player
 	PlayerStatuses states; //player color -> player state
 	std::set<CConnection*> conns;
 
-	void sendMessageTo(CConnection &c, const std::string &message);
 	void giveSpells(const CGTownInstance *t, const CGHeroInstance *h);
 	void moveStack(int stack, int dest);
 	void startBattle(CCreatureSet army1, CCreatureSet army2, int3 tile, CGHeroInstance *hero1, CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
@@ -71,7 +72,7 @@ class CGameHandler : public IGameCallback
 	void checkForBattleEnd( std::vector<CStack*> &stacks );
 	void setupBattle( BattleInfo * curB, int3 tile, CCreatureSet &army1, CCreatureSet &army2, CGHeroInstance * hero1, CGHeroInstance * hero2 );
 
-public:
+
 	CGameHandler(void);
 	~CGameHandler(void);
 
@@ -102,7 +103,7 @@ public:
 	void startBattleI(const CCreatureSet * army1, const CCreatureSet * army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, boost::function<void(BattleResult*)> cb); //use hero=NULL for no hero
 	void startBattleI(int heroID, CCreatureSet army, int3 tile, boost::function<void(BattleResult*)> cb); //for hero<=>neutral army
 	void setAmount(int objid, ui32 val);
-	void moveHero(int hid, int3 pos, bool instant);
+	void moveHero(si32 hid, int3 dst, ui8 instant, ui8 asker = 255);
 	void giveHeroBonus(GiveBonus * bonus);
 	void setMovePoints(SetMovePoints * smp);
 	void setManaPoints(int hid, int val);
@@ -112,58 +113,38 @@ public:
 
 	void init(StartInfo *si, int Seed);
 	void handleConnection(std::set<int> players, CConnection &c);
+	int getPlayerAt(CConnection *c) const;
+
+	void playerMessage( ui8 player, const std::string &message);
+	void makeBattleAction(BattleAction &ba);
+	void makeCustomAction(BattleAction &ba);
+	void queryReply( ui32 qid, ui32 answer );
+	void hireHero( ui32 tid, ui8 hid );
+	void setFormation( si32 hid, ui8 formation );
+	void tradeResources( ui32 val, ui8 player, ui32 id1, ui32 id2 );
+	void buyArtifact( ui32 hid, si32 aid );
+	void swapArtifacts( si32 hid1, si32 hid2, ui16 slot1, ui16 slot2 );
+	void garrisonSwap(si32 tid);
+	void upgradeCreature( ui32 objid, ui8 pos, ui32 upgID );
+	void recruitCreatures(si32 objid, ui32 crid, ui32 cram);
+	void buildStructure(si32 tid, si32 bid);
+	void disbandCreature( si32 id, ui8 pos );
+	void arrangeStacks( si32 id1, si32 id2, ui8 what, ui8 p1, ui8 p2, si32 val );
+	void save(const std::string &fname);
+	void close();
+
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
 		h & QID & states;
 	}
-	//template <typename T> void applyAndAsk(Query<T> * sel, ui8 player, boost::function<void(ui32)> &callback)
-	//{
-	//	gsm.lock();
-	//	sel->id = QID;
-	//	callbacks[QID] = callback;
-	//	states.addQuery(player,QID);
-	//	QID++; 
-	//	sendAndApply(sel);
-	//	gsm.unlock();
-	//}
-	//template <typename T> void ask(Query<T> * sel, ui8 player, const CFunctionList<void(ui32)> &callback)
-	//{
-	//	gsm.lock();
-	//	sel->id = QID;
-	//	callbacks[QID] = callback;
-	//	states.addQuery(player,QID);
-	//	sendToAllClients(sel);
-	//	QID++; 
-	//	gsm.unlock();
-	//}
-
-	//template <typename T>void sendToAllClients(CPack<T> * info)
-	//{
-	//	for(std::set<CConnection*>::iterator i=conns.begin(); i!=conns.end();i++)
-	//	{
-	//		(*i)->wmx->lock();
-	//		**i << info->getType() << *info->This();
-	//		(*i)->wmx->unlock();
-	//	}
-	//}
-	//template <typename T>void sendAndApply(CPack<T> * info)
-	//{
-	//	gs->apply(info);
-	//	sendToAllClients(info);
-	//}
+
+	void sendMessageToAll(const std::string &message);
+	void sendMessageTo(CConnection &c, const std::string &message);
 	void applyAndAsk(Query * sel, ui8 player, boost::function<void(ui32)> &callback);
 	void ask(Query * sel, ui8 player, const CFunctionList<void(ui32)> &callback);
-	//template <typename T>void sendDataToClients(const T & data)
-	//{
-	//	for(std::set<CConnection*>::iterator i=conns.begin(); i!=conns.end();i++)
-	//	{
-	//		(*i)->wmx->lock();
-	//		**i << data;
-	//		(*i)->wmx->unlock();
-	//	}
-	//}
-	void sendToAllClients(CPack * info);
-	void sendAndApply(CPack * info);
+	void sendToAllClients(CPackForClient * info);
+	void sendAndApply(CPackForClient * info);
+
 	void run(bool resume);
 	void newTurn();
 

+ 140 - 0
server/NetPacksServer.cpp

@@ -0,0 +1,140 @@
+#include "../lib/NetPacks.h"
+#include "CGameHandler.h"
+
+
+#define PLAYER_OWNS(id) (gh->getPlayerAt(c)==gh->getOwner(id))
+#define ERROR_AND_RETURN	{if(c) *c << &SystemMessage("You don't own this object!");	\
+							tlog1<<"Player is not allowed to perform this action!\n";	\
+							return;}
+#define ERROR_IF_NOT_OWNS(id)	if(!PLAYER_OWNS(id)) ERROR_AND_RETURN
+
+CGameState* CPackForServer::GS(CGameHandler *gh)
+{
+	return gh->gs;
+}
+
+void SaveGame::applyGh( CGameHandler *gh )
+{
+	gh->sendMessageTo(*c,"Saving...");
+	gh->save(fname);
+	gh->sendMessageTo(*c,"Game has been succesfully saved!");
+}
+
+void CloseServer::applyGh( CGameHandler *gh )
+{
+	gh->close();
+}
+
+void EndTurn::applyGh( CGameHandler *gh )
+{
+	gh->states.setFlag(GS(gh)->currentPlayer,&PlayerStatus::makingTurn,false);
+}
+
+void DismissHero::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(hid);
+	gh->removeObject(hid);
+}
+
+void MoveHero::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(hid);
+	gh->moveHero(hid,dest,0,gh->getPlayerAt(c));
+}
+
+void ArrangeStacks::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(id1);
+	ERROR_IF_NOT_OWNS(id2);
+	gh->arrangeStacks(id1,id2,what,p1,p2,val);
+}
+
+void DisbandCreature::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(id);
+	gh->disbandCreature(id,pos);
+}
+
+void BuildStructure::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(tid);
+	gh->buildStructure(tid,bid);
+}
+
+void RecruitCreatures::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(tid);
+	gh->recruitCreatures(tid,crid,amount);
+}
+
+void UpgradeCreature::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(id);
+	gh->upgradeCreature(id,pos,cid);
+}
+
+void GarrisonHeroSwap::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(tid);
+	gh->garrisonSwap(tid);
+}
+
+void ExchangeArtifacts::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(hid1);
+	ERROR_IF_NOT_OWNS(hid2);
+	gh->swapArtifacts(hid1,hid2,slot1,slot2);
+}
+
+void BuyArtifact::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(hid);
+	gh->buyArtifact(hid,aid);
+}
+
+void TradeOnMarketplace::applyGh( CGameHandler *gh )
+{
+	if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN;
+	gh->tradeResources(val,player,r1,r2);
+}
+
+void SetFormation::applyGh( CGameHandler *gh )
+{	
+	ERROR_IF_NOT_OWNS(hid);
+	gh->setFormation(hid,formation);
+}
+
+void HireHero::applyGh( CGameHandler *gh )
+{
+	ERROR_IF_NOT_OWNS(tid);
+	gh->hireHero(tid,hid);
+}
+
+void QueryReply::applyGh( CGameHandler *gh )
+{
+	gh->queryReply(qid,answer);
+}
+
+void MakeAction::applyGh( CGameHandler *gh )
+{
+	if(gh->getPlayerAt(c) != GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner) ERROR_AND_RETURN;
+	gh->makeBattleAction(ba);
+}
+
+void MakeCustomAction::applyGh( CGameHandler *gh )
+{
+	if(gh->getPlayerAt(c) != GS(gh)->curB->getStack(GS(gh)->curB->activeStack)->owner) ERROR_AND_RETURN;
+	gh->makeCustomAction(ba);
+}
+
+void PlayerMessage::applyGh( CGameHandler *gh )
+{
+	if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN;
+	gh->playerMessage(player,text);
+}
+
+void SetSelection::applyGh( CGameHandler *gh )
+{
+	if(gh->getPlayerAt(c) != player) ERROR_AND_RETURN;
+	gh->sendToAllClients(this);
+}

+ 4 - 0
server/VCMI_server.vcproj

@@ -264,6 +264,10 @@
 				RelativePath=".\CVCMIServer.cpp"
 				>
 			</File>
+			<File
+				RelativePath=".\NetPacksServer.cpp"
+				>
+			</File>
 		</Filter>
 		<Filter
 			Name="Header Files"

Some files were not shown because too many files changed in this diff