ソースを参照

* Server will strictly require answering the queries before taking any actions. Let me know, if this causes any freezes.
* Fixed crash on new week after we lost battle with neutral monster but killed the top stack (merging failed then).
* minor changes

Michał W. Urbańczyk 14 年 前
コミット
8b7a2f179c

+ 2 - 0
CCallback.cpp

@@ -58,6 +58,8 @@ bool CCallback::moveHero(const CGHeroInstance *h, int3 dst)
 void CCallback::selectionMade(int selection, int asker)
 {
 	QueryReply pack(asker,selection);
+	pack.player = player;
+
 	boost::unique_lock<boost::mutex> lock(*cl->serv->wmx);
 	*cl->serv << &pack;
 }

+ 4 - 7
client/Client.cpp

@@ -214,10 +214,7 @@ void CClient::endGame( bool closeConnection /*= true*/ )
 		delete pint;
 	}
 
-	BOOST_FOREACH(CCallback *cb, callbacks)
-	{
-		delete cb;
-	}
+	callbacks.clear();
 	tlog0 << "Deleted playerInts." << std::endl;
 
 	tlog0 << "Client stopped." << std::endl;
@@ -379,6 +376,7 @@ void CClient::newGame( CConnection *con, StartInfo *si )
 			battleints[color] = playerint[color];
 
 			playerint[color]->init(cb);
+			callbacks[color] = std::auto_ptr<CCallback>(cb);
 		}
 		else
 		{
@@ -465,10 +463,9 @@ void CClient::serialize( Handler &h, const int version )
 			else
 				nInt = new CPlayerInterface(pid);
 
-			CCallback *callback = new CCallback(gs,pid,this);
-			callbacks.insert(callback);
+			callbacks[pid] = std::auto_ptr<CCallback>(new CCallback(gs,pid,this));
 			battleints[pid] = playerint[pid] = nInt;
-			nInt->init(callback);
+			nInt->init(callbacks[pid].get());
 			nInt->serialize(h, version);
 		}
 

+ 1 - 1
client/Client.h

@@ -64,7 +64,7 @@ class CClient : public IGameCallback
 {
 public:
 	CCallback *cb;
-	std::set<CCallback*> callbacks; //callbacks given to player interfaces
+	std::map<ui8,std::auto_ptr<CCallback> > callbacks; //callbacks given to player interfaces
 	std::vector<IGameEventsReceiver*> privilagedGameEventReceivers; //scripting modules, spectator interfaces
 	std::vector<IBattleEventsReceiver*> privilagedBattleEventReceivers; //scripting modules, spectator interfaces
 	std::map<ui8,CGameInterface *> playerint;

+ 1 - 1
client/NetPacksClient.cpp

@@ -528,7 +528,7 @@ void HeroLevelUp::applyCl( CClient *cl )
 	CGHeroInstance *h = GS(cl)->getHero(heroid);
 	if(vstd::contains(cl->playerint,h->tempOwner))
 	{
-		boost::function<void(ui32)> callback = boost::function<void(ui32)>(boost::bind(&CCallback::selectionMade,LOCPLINT->cb,_1,id));
+		boost::function<void(ui32)> callback = boost::function<void(ui32)>(boost::bind(&CCallback::selectionMade,cl->callbacks[h->tempOwner].get(),_1,id));
 		cl->playerint[h->tempOwner]->heroGotLevel(const_cast<const CGHeroInstance*>(h),static_cast<int>(primskill),skills, callback);
 	}
 }

+ 8 - 2
lib/CObjectHandler.cpp

@@ -2941,8 +2941,14 @@ void CGCreature::endBattle( BattleResult *result ) const
 				cb->changeStackType (StackLocation(this, i->first), cre); //un-upgrade creatures
 			}
 		}
+
+		//first stack has to be at slot 0 -> if original one got killed, move there first remaining stack
+		if(!hasStackAtSlot(0))
+			cb->moveStack(StackLocation(this, stacks.begin()->first), StackLocation(this, 0), stacks.begin()->second->count);
+
 		while (stacks.size() > 1) //hopefully that's enough
 		{
+			// TODO it's either overcomplicated (if we assume there'll be only one stack) or buggy (if we allow multiple stacks... but that'll also cause troubles elsewhere)
 			i = stacks.end();
 			i--;
 			TSlot slot = getSlotFor(i->second->type);
@@ -3013,7 +3019,7 @@ void CGCreature::setPropertyDer(ui8 what, ui32 val)
 		case ObjProperty::MONSTER_EXP:
 			giveStackExp(val);
 			break;
-		case 13:
+		case ObjProperty::MONSTER_RESTORE_TYPE:
 			restore.basicType = val;
 			break;
 	}
@@ -3145,7 +3151,7 @@ void CGCreature::fight( const CGHeroInstance *h ) const
 	//split stacks
 	int totalCount; //TODO: multiple creature types in a stack?
 	int basicType = stacks.begin()->second->type->idNumber;
-	cb->setObjProperty(id, 13, basicType); //store info about creature stack
+	cb->setObjProperty(id, ObjProperty::MONSTER_RESTORE_TYPE, basicType); //store info about creature stack
 
 	float relativePower = ((float)h->getTotalStrength() / getArmyStrength());
 	int stacksCount;

+ 3 - 2
lib/NetPacks.h

@@ -1029,7 +1029,7 @@ namespace ObjProperty
 {
 	//TODO: move non general properties out to the appropriate objs classes
 	enum {OWNER = 1, BLOCKVIS = 2, PRIMARY_STACK_COUNT = 3, VISITORS = 4, VISITED = 5, ID = 6, AVAILABLE_CREATURE = 7, SUBID = 8,
-		MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12};
+		MONSTER_COUNT = 10, MONSTER_POWER = 11, MONSTER_EXP = 12, MONSTER_RESTORE_TYPE = 13};
 }
 
 struct SetObjectProperty : public CPackForClient//1001
@@ -1791,11 +1791,12 @@ struct QueryReply : public CPackForServer
 	QueryReply(){type = 6000;};
 	QueryReply(ui32 QID, ui32 Answer):qid(QID),answer(Answer){type = 6000;};
 	ui32 qid, answer; //hero and artifact id
+	ui8 player;
 
 	bool applyGh(CGameHandler *gh);
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & qid & answer;
+		h & qid & answer & player;
 	}
 };
 

+ 14 - 2
server/CGameHandler.cpp

@@ -635,7 +635,18 @@ void CGameHandler::handleConnection(std::set<int> players, CConnection &c)
 			int packType = typeList.getTypeID(pack); //get the id of type
 			CBaseForGHApply *apply = applier->apps[packType]; //and appropriae applier object
 
-			if(apply)
+			if(packType != typeList.getTypeID<QueryReply>() && states[getCurrentPlayer()].queries.size())
+			{
+				complain("Answer the query before attempting any further actions!");
+				PackageApplied applied;
+				applied.result = false;
+				applied.packType = packType;
+				{
+					boost::unique_lock<boost::mutex> lock(*c.wmx);
+					c << &applied;
+				}
+			}
+			else if(apply)
 			{
 				bool result = apply->applyOnGH(this,&c,pack);
 				tlog5 << "Message successfully applied (result=" << result << ")!\n";
@@ -2911,9 +2922,10 @@ bool CGameHandler::hireHero(const CGObjectInstance *obj, ui8 hid, ui8 player)
 	return true;
 }
 
-bool CGameHandler::queryReply( ui32 qid, ui32 answer )
+bool CGameHandler::queryReply(ui32 qid, ui32 answer, ui8 player)
 {
 	boost::unique_lock<boost::recursive_mutex> lock(gsm);
+	states.removeQuery(player, qid);
 	if(vstd::contains(callbacks,qid))
 	{
 		CFunctionList<void(ui32)> callb = callbacks[qid];

+ 1 - 1
server/CGameHandler.h

@@ -197,7 +197,7 @@ public:
 	bool makeBattleAction(BattleAction &ba);
 	void handleSpellCasting(int spellID, int spellLvl, THex destination, ui8 casterSide, ui8 casterColor, const CGHeroInstance * caster, const CGHeroInstance * secHero, int usedSpellPower, SpellCasting::ECastingMode mode, const CStack * stack);
 	bool makeCustomAction(BattleAction &ba);
-	bool queryReply( ui32 qid, ui32 answer );
+	bool queryReply( ui32 qid, ui32 answer, ui8 player );
 	bool hireHero( const CGObjectInstance *obj, ui8 hid, ui8 player );
 	bool buildBoat( ui32 objid );
 	bool setFormation( si32 hid, ui8 formation );

+ 3 - 2
server/NetPacksServer.cpp

@@ -225,8 +225,9 @@ bool BuildBoat::applyGh( CGameHandler *gh )
 
 bool QueryReply::applyGh( CGameHandler *gh )
 {
-	//TODO - check if player matches the query
-	return gh->queryReply(qid,answer);
+	ERROR_IF_NOT(player);
+	assert(vstd::contains(gh->states.players, player));
+	return gh->queryReply(qid, answer, player);
 }
 
 bool MakeAction::applyGh( CGameHandler *gh )