Browse Source

Do not use StackLocation in netpacks

AlexVinS 7 years ago
parent
commit
03cfd2cb78

+ 1 - 32
AI/VCAI/VCAI.cpp

@@ -148,12 +148,6 @@ void VCAI::heroMoved(const TryMoveHero & details)
 	}
 }
 
-void VCAI::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute)
-{
-	LOG_TRACE_PARAMS(logAi, "isAbsolute '%i'", isAbsolute);
-	NET_EVENT_HANDLER;
-}
-
 void VCAI::heroInGarrisonChange(const CGTownInstance *town)
 {
 	LOG_TRACE(logAi);
@@ -246,19 +240,12 @@ void VCAI::artifactRemoved(const ArtifactLocation &al)
 	NET_EVENT_HANDLER;
 }
 
-void VCAI::stacksErased(const StackLocation &location)
-{
-	LOG_TRACE(logAi);
-	NET_EVENT_HANDLER;
-}
-
 void VCAI::artifactDisassembled(const ArtifactLocation &al)
 {
 	LOG_TRACE(logAi);
 	NET_EVENT_HANDLER;
 }
 
-
 void VCAI::heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start)
 {
 	LOG_TRACE_PARAMS(logAi, "start '%i'; obj '%s'", start % (visitedObj ? visitedObj->getObjectName() : std::string("n/a")));
@@ -377,13 +364,7 @@ void VCAI::heroMovePointsChanged(const CGHeroInstance * hero)
 	NET_EVENT_HANDLER;
 }
 
-void VCAI::stackChangedType(const StackLocation &location, const CCreature &newType)
-{
-	LOG_TRACE(logAi);
-	NET_EVENT_HANDLER;
-}
-
-void VCAI::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count)
+void VCAI::garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2)
 {
 	LOG_TRACE(logAi);
 	NET_EVENT_HANDLER;
@@ -452,12 +433,6 @@ void VCAI::playerBonusChanged(const Bonus &bonus, bool gain)
 	NET_EVENT_HANDLER;
 }
 
-void VCAI::newStackInserted(const StackLocation &location, const CStackInstance &stack)
-{
-	LOG_TRACE(logAi);
-	NET_EVENT_HANDLER;
-}
-
 void VCAI::heroCreated(const CGHeroInstance* h)
 {
 	LOG_TRACE(logAi);
@@ -501,12 +476,6 @@ void VCAI::receivedResource()
 	NET_EVENT_HANDLER;
 }
 
-void VCAI::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2)
-{
-	LOG_TRACE(logAi);
-	NET_EVENT_HANDLER;
-}
-
 void VCAI::showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor)
 {
 	LOG_TRACE(logAi);

+ 1 - 6
AI/VCAI/VCAI.h

@@ -203,7 +203,6 @@ public:
 
 	virtual void availableCreaturesChanged(const CGDwelling *town) override;
 	virtual void heroMoved(const TryMoveHero & details) override;
-	virtual void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) override;
 	virtual void heroInGarrisonChange(const CGTownInstance *town) override;
 	virtual void centerView(int3 pos, int focusTime) override;
 	virtual void tileHidden(const std::unordered_set<int3, ShashInt3> &pos) override;
@@ -217,7 +216,6 @@ public:
 	virtual void gameOver(PlayerColor player, const EVictoryLossCheckResult & victoryLossCheckResult) override;
 	virtual void artifactPut(const ArtifactLocation &al) override;
 	virtual void artifactRemoved(const ArtifactLocation &al) override;
-	virtual void stacksErased(const StackLocation &location) override;
 	virtual void artifactDisassembled(const ArtifactLocation &al) override;
 	virtual void heroVisit(const CGHeroInstance *visitor, const CGObjectInstance *visitedObj, bool start) override;
 	virtual void availableArtifactsChanged(const CGBlackMarket *bm = nullptr) override;
@@ -227,18 +225,15 @@ public:
 	virtual void heroPrimarySkillChanged(const CGHeroInstance * hero, int which, si64 val) override;
 	virtual void showRecruitmentDialog(const CGDwelling *dwelling, const CArmedInstance *dst, int level) override;
 	virtual void heroMovePointsChanged(const CGHeroInstance * hero) override;
-	virtual void stackChangedType(const StackLocation &location, const CCreature &newType) override;
-	virtual void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) override;
+	virtual void garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) override;
 	virtual void newObject(const CGObjectInstance * obj) override;
 	virtual void showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor) override;
 	virtual void playerBonusChanged(const Bonus &bonus, bool gain) override;
-	virtual void newStackInserted(const StackLocation &location, const CStackInstance &stack) override;
 	virtual void heroCreated(const CGHeroInstance*) override;
 	virtual void advmapSpellCast(const CGHeroInstance * caster, int spellID) override;
 	virtual void showInfoDialog(const std::string &text, const std::vector<Component*> &components, int soundID) override;
 	virtual void requestRealized(PackageApplied *pa) override;
 	virtual void receivedResource() override;
-	virtual void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) override;
 	virtual void objectRemoved(const CGObjectInstance *obj) override;
 	virtual void showUniversityWindow(const IMarket *market, const CGHeroInstance *visitor) override;
 	virtual void heroManaPointsChanged(const CGHeroInstance * hero) override;

+ 18 - 48
client/CPlayerInterface.cpp

@@ -609,6 +609,24 @@ void CPlayerInterface::heroVisitsTown(const CGHeroInstance* hero, const CGTownIn
 	waitWhileDialog();
 	openTownWindow(town);
 }
+
+void CPlayerInterface::garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2)
+{
+	std::vector<const CGObjectInstance *> instances;
+
+	if(auto obj = cb->getObj(id1))
+		instances.push_back(obj);
+
+
+	if(id2 != ObjectInstanceID() && id2 != id1)
+	{
+		if(auto obj = cb->getObj(id2))
+			instances.push_back(obj);
+	}
+
+	garrisonsChanged(instances);
+}
+
 void CPlayerInterface::garrisonsChanged(std::vector<const CGObjectInstance *> objs)
 {
 	boost::unique_lock<boost::recursive_mutex> un(*pim);
@@ -2567,54 +2585,6 @@ void CPlayerInterface::sendCustomEvent( int code )
 	CGuiHandler::pushSDLEvent(SDL_USEREVENT, code);
 }
 
-void CPlayerInterface::stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute)
-{
-	EVENT_HANDLER_CALLED_BY_CLIENT;
-	garrisonChanged(location.army);
-}
-
-void CPlayerInterface::stackChangedType(const StackLocation &location, const CCreature &newType)
-{
-	EVENT_HANDLER_CALLED_BY_CLIENT;
-	garrisonChanged(location.army);
-}
-
-void CPlayerInterface::stacksErased(const StackLocation &location)
-{
-	EVENT_HANDLER_CALLED_BY_CLIENT;
-	garrisonChanged(location.army);
-}
-
-void CPlayerInterface::stacksSwapped(const StackLocation &loc1, const StackLocation &loc2)
-{
-	EVENT_HANDLER_CALLED_BY_CLIENT;
-
-	std::vector<const CGObjectInstance *> objects;
-	objects.push_back(loc1.army);
-	if (loc2.army != loc1.army)
-		objects.push_back(loc2.army);
-
-	garrisonsChanged(objects);
-}
-
-void CPlayerInterface::newStackInserted(const StackLocation &location, const CStackInstance &stack)
-{
-	EVENT_HANDLER_CALLED_BY_CLIENT;
-	garrisonChanged(location.army);
-}
-
-void CPlayerInterface::stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count)
-{
-	EVENT_HANDLER_CALLED_BY_CLIENT;
-
-	std::vector<const CGObjectInstance *> objects;
-	objects.push_back(src.army);
-	if (src.army != dst.army)
-		objects.push_back(dst.army);
-
-	garrisonsChanged(objects);
-}
-
 void CPlayerInterface::askToAssembleArtifact(const ArtifactLocation &al)
 {
 	auto hero = boost::apply_visitor(HeroObjectRetriever(), al.artHolder);

+ 2 - 6
client/CPlayerInterface.h

@@ -131,13 +131,9 @@ public:
 	int getLastIndex(std::string namePrefix);
 
 	//overridden funcs from CGameInterface
+	void garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2) override;
+
 	void buildChanged(const CGTownInstance *town, BuildingID buildingID, int what) override; //what: 1 - built, 2 - demolished
-	void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute) override; //if absolute, change is the new count; otherwise count was modified by adding change
-	void stackChangedType(const StackLocation &location, const CCreature &newType) override; //used eg. when upgrading creatures
-	void stacksErased(const StackLocation &location) override; //stack removed from previously filled slot
-	void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2) override;
-	void newStackInserted(const StackLocation &location, const CStackInstance &stack) override; //new stack inserted at given (previously empty position)
-	void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count) override; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
 
 	void artifactPut(const ArtifactLocation &al) override;
 	void artifactRemoved(const ArtifactLocation &al) override;

+ 37 - 16
client/NetPacksClient.cpp

@@ -199,38 +199,59 @@ void SetAvailableHeroes::applyCl(CClient *cl)
 	//TODO: inform interface?
 }
 
-void ChangeStackCount::applyCl(CClient *cl)
+static void dispatchGarrisonChange(CClient * cl, ObjectInstanceID army1, ObjectInstanceID army2)
 {
-	callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::stackChagedCount, sl, count, absoluteValue);
+	auto obj1 = cl->getObj(army1);
+	if(!obj1)
+	{
+		logNetwork->error("Cannot find army with ID %d", army1.getNum());
+		return;
+	}
+
+	callInterfaceIfPresent(cl, obj1->tempOwner, &IGameEventsReceiver::garrisonsChanged, army1, army2);
+
+	if(army2 != ObjectInstanceID() && army2 != army1)
+	{
+		auto obj2 = cl->getObj(army2);
+		if(!obj2)
+		{
+			logNetwork->error("Cannot find army with ID %d", army2.getNum());
+			return;
+		}
+
+		if(obj1->tempOwner != obj2->tempOwner)
+			callInterfaceIfPresent(cl, obj2->tempOwner, &IGameEventsReceiver::garrisonsChanged, army1, army2);
+	}
+}
+
+void ChangeStackCount::applyCl(CClient * cl)
+{
+	dispatchGarrisonChange(cl, army, ObjectInstanceID());
 }
 
-void SetStackType::applyCl(CClient *cl)
+void SetStackType::applyCl(CClient * cl)
 {
-	callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::stackChangedType, sl, *type);
+	dispatchGarrisonChange(cl, army, ObjectInstanceID());
 }
 
-void EraseStack::applyCl(CClient *cl)
+void EraseStack::applyCl(CClient * cl)
 {
-	callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::stacksErased, sl);
+	dispatchGarrisonChange(cl, army, ObjectInstanceID());
 }
 
-void SwapStacks::applyCl(CClient *cl)
+void SwapStacks::applyCl(CClient * cl)
 {
-	callInterfaceIfPresent(cl, sl1.army->tempOwner, &IGameEventsReceiver::stacksSwapped, sl1, sl2);
-	if(sl1.army->tempOwner != sl2.army->tempOwner)
-		callInterfaceIfPresent(cl, sl2.army->tempOwner, &IGameEventsReceiver::stacksSwapped, sl1, sl2);
+	dispatchGarrisonChange(cl, srcArmy, dstArmy);
 }
 
-void InsertNewStack::applyCl(CClient *cl)
+void InsertNewStack::applyCl(CClient * cl)
 {
-	callInterfaceIfPresent(cl, sl.army->tempOwner, &IGameEventsReceiver::newStackInserted, sl, *sl.getStack());
+	dispatchGarrisonChange(cl, army, ObjectInstanceID());
 }
 
-void RebalanceStacks::applyCl(CClient *cl)
+void RebalanceStacks::applyCl(CClient * cl)
 {
-	callInterfaceIfPresent(cl, src.army->tempOwner, &IGameEventsReceiver::stacksRebalanced, src, dst, count);
-	if(src.army->tempOwner != dst.army->tempOwner)
-		callInterfaceIfPresent(cl, dst.army->tempOwner, &IGameEventsReceiver::stacksRebalanced, src, dst, count);
+	dispatchGarrisonChange(cl, srcArmy, dstArmy);
 }
 
 void PutArtifact::applyCl(CClient *cl)

+ 2 - 2
lib/CCreatureSet.cpp

@@ -424,11 +424,11 @@ CStackInstance * CCreatureSet::detachStack(SlotID slot)
 	return ret;
 }
 
-void CCreatureSet::setStackType(SlotID slot, const CCreature *type)
+void CCreatureSet::setStackType(SlotID slot, CreatureID type)
 {
 	assert(hasStackAtSlot(slot));
 	CStackInstance *s = stacks[slot];
-	s->setType(type->idNumber);
+	s->setType(type);
 	armyChanged();
 }
 

+ 1 - 1
lib/CCreatureSet.h

@@ -185,7 +185,7 @@ public:
 	void putStack(SlotID slot, CStackInstance *stack); //adds new stack to the army, slot must be empty
 	void setStackCount(SlotID slot, TQuantity count); //stack must exist!
 	CStackInstance *detachStack(SlotID slot); //removes stack from army but doesn't destroy it (so it can be moved somewhere else or safely deleted)
-	void setStackType(SlotID slot, const CCreature *type);
+	void setStackType(SlotID slot, CreatureID type);
 	void giveStackExp(TExpType exp);
 	void setStackExp(SlotID slot, TExpType exp);
 

+ 1 - 0
lib/CGameInfoCallback.h

@@ -78,6 +78,7 @@ public:
 	int64_t estimateSpellDamage(const CSpell * sp, const CGHeroInstance * hero) const; //estimates damage of given spell; returns 0 if spell causes no dmg
 	const CArtifactInstance * getArtInstance(ArtifactInstanceID aid) const;
 	const CGObjectInstance * getObjInstance(ObjectInstanceID oid) const;
+	const CGObjectInstance * getArmyInstance(ObjectInstanceID oid) const;
 
 	//objects
 	const CGObjectInstance* getObj(ObjectInstanceID objid, bool verbose = true) const;

+ 7 - 2
lib/IGameCallback.cpp

@@ -224,12 +224,17 @@ PlayerState * CNonConstInfoCallback::getPlayer( PlayerColor color, bool verbose
 
 CArtifactInstance * CNonConstInfoCallback::getArtInstance( ArtifactInstanceID aid )
 {
-	return gs->map->artInstances[aid.num];
+	return gs->map->artInstances.at(aid.num);
 }
 
 CGObjectInstance * CNonConstInfoCallback::getObjInstance( ObjectInstanceID oid )
 {
-	return gs->map->objects[oid.num];
+	return gs->map->objects.at(oid.num);
+}
+
+CArmedInstance * CNonConstInfoCallback::getArmyInstance(ObjectInstanceID oid)
+{
+	return dynamic_cast<CArmedInstance *>(getObjInstance(oid));
 }
 
 const CGObjectInstance * IGameCallback::putNewObject(Obj ID, int subID, int3 pos)

+ 1 - 0
lib/IGameCallback.h

@@ -108,6 +108,7 @@ public:
 	TerrainTile * getTile(int3 pos);
 	CArtifactInstance * getArtInstance(ArtifactInstanceID aid);
 	CGObjectInstance * getObjInstance(ObjectInstanceID oid);
+	CArmedInstance * getArmyInstance(ObjectInstanceID oid);
 };
 
 /// Interface class for handling general game logic and actions

+ 1 - 8
lib/IGameEventsReceiver.h

@@ -80,14 +80,7 @@ public:
 
 	virtual void battleResultsApplied(){}; //called when all effects of last battle are applied
 
-	//garrison operations
-	virtual void stackChagedCount(const StackLocation &location, const TQuantity &change, bool isAbsolute){}; //if absolute, change is the new count; otherwise count was modified by adding change
-	virtual void stackChangedType(const StackLocation &location, const CCreature &newType){}; //used eg. when upgrading creatures
-	virtual void stacksErased(const StackLocation &location){}; //stack removed from previously filled slot
-	virtual void stacksSwapped(const StackLocation &loc1, const StackLocation &loc2){};
-	virtual void newStackInserted(const StackLocation &location, const CStackInstance &stack){}; //new stack inserted at given (previously empty position)
-	virtual void stacksRebalanced(const StackLocation &src, const StackLocation &dst, TQuantity count){}; //moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
-	//virtual void garrisonChanged(const CGObjectInstance * obj){};
+	virtual void garrisonsChanged(ObjectInstanceID id1, ObjectInstanceID id2){};
 
 	//artifacts operations
 	virtual void artifactPut(const ArtifactLocation &al){};

+ 53 - 27
lib/NetPacks.h

@@ -798,16 +798,18 @@ struct CArtifactOperationPack : CPackForClient
 
 struct ChangeStackCount : CGarrisonOperationPack
 {
-	StackLocation sl;
+	ObjectInstanceID army;
+	SlotID slot;
 	TQuantity count;
-	ui8 absoluteValue; //if not -> count will be added (or subtracted if negative)
+	bool absoluteValue; //if not -> count will be added (or subtracted if negative)
 
-	void applyCl(CClient *cl);
-	DLL_LINKAGE void applyGs(CGameState *gs);
+	void applyCl(CClient * cl);
+	DLL_LINKAGE void applyGs(CGameState * gs);
 
-	template <typename Handler> void serialize(Handler &h, const int version)
+	template <typename Handler> void serialize(Handler & h, const int version)
 	{
-		h & sl;
+		h & army;
+		h & slot;
 		h & count;
 		h & absoluteValue;
 	}
@@ -815,65 +817,87 @@ struct ChangeStackCount : CGarrisonOperationPack
 
 struct SetStackType : CGarrisonOperationPack
 {
-	StackLocation sl;
-	const CCreature *type;
+	ObjectInstanceID army;
+	SlotID slot;
+	CreatureID type;
 
 	void applyCl(CClient *cl);
 	DLL_LINKAGE void applyGs(CGameState *gs);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & sl;
+		h & army;
+		h & slot;
 		h & type;
 	}
 };
 
 struct EraseStack : CGarrisonOperationPack
 {
-	StackLocation sl;
+	ObjectInstanceID army;
+	SlotID slot;
 
 	void applyCl(CClient *cl);
 	DLL_LINKAGE void applyGs(CGameState *gs);
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & sl;
+		h & army;
+		h & slot;
 	}
 };
 
 struct SwapStacks : CGarrisonOperationPack
 {
-	StackLocation sl1, sl2;
+	ObjectInstanceID srcArmy;
+	ObjectInstanceID dstArmy;
+	SlotID srcSlot;
+	SlotID dstSlot;
 
-	void applyCl(CClient *cl);
-	DLL_LINKAGE void applyGs(CGameState *gs);
+	void applyCl(CClient * cl);
+	DLL_LINKAGE void applyGs(CGameState * gs);
 
-	template <typename Handler> void serialize(Handler &h, const int version)
+	template <typename Handler> void serialize(Handler & h, const int version)
 	{
-		h & sl1;
-		h & sl2;
+		h & srcArmy;
+		h & dstArmy;
+		h & srcSlot;
+		h & dstSlot;
 	}
 };
 
 struct InsertNewStack : CGarrisonOperationPack
 {
-	StackLocation sl;
-	CStackBasicDescriptor stack;
+	ObjectInstanceID army;
+	SlotID slot;
+	CreatureID type;
+	TQuantity count;
 
-	void applyCl(CClient *cl);
-	DLL_LINKAGE void applyGs(CGameState *gs);
+	InsertNewStack()
+		: count(0)
+	{
+	}
 
-	template <typename Handler> void serialize(Handler &h, const int version)
+	void applyCl(CClient * cl);
+	DLL_LINKAGE void applyGs(CGameState * gs);
+
+	template <typename Handler> void serialize(Handler & h, const int version)
 	{
-		h & sl;
-		h & stack;
+		h & army;
+		h & slot;
+		h & type;
+		h & count;
 	}
 };
 
 ///moves creatures from src stack to dst slot, may be used for merging/splittint/moving stacks
 struct RebalanceStacks : CGarrisonOperationPack
 {
-	StackLocation src, dst;
+	ObjectInstanceID srcArmy;
+	ObjectInstanceID dstArmy;
+	SlotID srcSlot;
+	SlotID dstSlot;
+
 	TQuantity count;
 
 	void applyCl(CClient *cl);
@@ -881,8 +905,10 @@ struct RebalanceStacks : CGarrisonOperationPack
 
 	template <typename Handler> void serialize(Handler &h, const int version)
 	{
-		h & src;
-		h & dst;
+		h & srcArmy;
+		h & dstArmy;
+		h & srcSlot;
+		h & dstSlot;
 		h & count;
 	}
 };

+ 51 - 16
lib/NetPacksLib.cpp

@@ -826,42 +826,77 @@ DLL_LINKAGE const ArtSlotInfo *ArtifactLocation::getSlot() const
 	return getHolderArtSet()->getSlot(slot);
 }
 
-DLL_LINKAGE void ChangeStackCount::applyGs(CGameState *gs)
+DLL_LINKAGE void ChangeStackCount::applyGs(CGameState * gs)
 {
+	auto srcObj = gs->getArmyInstance(army);
+	if(!srcObj)
+		logNetwork->error("[CRITICAL] ChangeStackCount: invalid army object %d, possible game state corruption.", army.getNum());
+
 	if(absoluteValue)
-		sl.army->setStackCount(sl.slot, count);
+		srcObj->setStackCount(slot, count);
 	else
-		sl.army->changeStackCount(sl.slot, count);
+		srcObj->changeStackCount(slot, count);
 }
 
-DLL_LINKAGE void SetStackType::applyGs(CGameState *gs)
+DLL_LINKAGE void SetStackType::applyGs(CGameState * gs)
 {
-	sl.army->setStackType(sl.slot, type);
+	auto srcObj = gs->getArmyInstance(army);
+	if(!srcObj)
+		logNetwork->error("[CRITICAL] SetStackType: invalid army object %d, possible game state corruption.", army.getNum());
+
+	srcObj->setStackType(slot, type);
 }
 
-DLL_LINKAGE void EraseStack::applyGs(CGameState *gs)
+DLL_LINKAGE void EraseStack::applyGs(CGameState * gs)
 {
-	sl.army->eraseStack(sl.slot);
+	auto srcObj = gs->getArmyInstance(army);
+	if(!srcObj)
+		logNetwork->error("[CRITICAL] EraseStack: invalid army object %d, possible game state corruption.", army.getNum());
+
+	srcObj->eraseStack(slot);
 }
 
-DLL_LINKAGE void SwapStacks::applyGs(CGameState *gs)
+DLL_LINKAGE void SwapStacks::applyGs(CGameState * gs)
 {
-	CStackInstance *s1 = sl1.army->detachStack(sl1.slot),
-		*s2 = sl2.army->detachStack(sl2.slot);
+	auto srcObj = gs->getArmyInstance(srcArmy);
+	if(!srcObj)
+		logNetwork->error("[CRITICAL] SwapStacks: invalid army object %d, possible game state corruption.", srcArmy.getNum());
+
+	auto dstObj = gs->getArmyInstance(dstArmy);
+	if(!dstObj)
+		logNetwork->error("[CRITICAL] SwapStacks: invalid army object %d, possible game state corruption.", dstArmy.getNum());
+
+	CStackInstance * s1 = srcObj->detachStack(srcSlot);
+	CStackInstance * s2 = dstObj->detachStack(dstSlot);
 
-	sl2.army->putStack(sl2.slot, s1);
-	sl1.army->putStack(sl1.slot, s2);
+	srcObj->putStack(srcSlot, s2);
+	dstObj->putStack(dstSlot, s1);
 }
 
 DLL_LINKAGE void InsertNewStack::applyGs(CGameState *gs)
 {
-	auto s = new CStackInstance(stack.type, stack.count);
-	sl.army->putStack(sl.slot, s);
+	auto s = new CStackInstance(type, count);
+	auto obj = gs->getArmyInstance(army);
+	if(obj)
+		obj->putStack(slot, s);
+	else
+		logNetwork->error("[CRITICAL] InsertNewStack: invalid army object %d, possible game state corruption.", army.getNum());
 }
 
-DLL_LINKAGE void RebalanceStacks::applyGs(CGameState *gs)
+DLL_LINKAGE void RebalanceStacks::applyGs(CGameState * gs)
 {
-	const CCreature *srcType = src.army->getCreature(src.slot);
+	auto srcObj = gs->getArmyInstance(srcArmy);
+	if(!srcObj)
+		logNetwork->error("[CRITICAL] RebalanceStacks: invalid army object %d, possible game state corruption.", srcArmy.getNum());
+
+	auto dstObj = gs->getArmyInstance(dstArmy);
+	if(!dstObj)
+		logNetwork->error("[CRITICAL] RebalanceStacks: invalid army object %d, possible game state corruption.", dstArmy.getNum());
+
+	StackLocation src(srcObj, srcSlot);
+	StackLocation dst(dstObj, dstSlot);
+
+	const CCreature * srcType = src.army->getCreature(src.slot);
 	TQuantity srcCount = src.army->getStackCount(src.slot);
 	bool stackExp = VLC->modh->modules.STACK_EXP;
 

+ 7 - 5
lib/mapObjects/CGTownInstance.cpp

@@ -296,13 +296,13 @@ void CGDwelling::updateGuards() const
 		for (auto creatureEntry : creatures)
 		{
 			const CCreature * crea = VLC->creh->creatures[creatureEntry.second.at(0)];
-
 			SlotID slot = getSlotFor(crea->idNumber);
-			StackLocation stackLocation = StackLocation(this, slot);
+
 			if (hasStackAtSlot(slot)) //stack already exists, overwrite it
 			{
 				ChangeStackCount csc;
-				csc.sl = stackLocation;
+				csc.army = this->id;
+				csc.slot = slot;
 				csc.count = crea->growth * 3;
 				csc.absoluteValue = true;
 				cb->sendAndApply(&csc);
@@ -310,8 +310,10 @@ void CGDwelling::updateGuards() const
 			else //slot is empty, create whole new stack
 			{
 				InsertNewStack ns;
-				ns.sl = stackLocation;
-				ns.stack = CStackBasicDescriptor(crea->idNumber, crea->growth * 3);
+				ns.army = this->id;
+				ns.slot = slot;
+				ns.type = crea->idNumber;
+				ns.count = crea->growth * 3;
 				cb->sendAndApply(&ns);
 			}
 		}

+ 26 - 14
server/CGameHandler.cpp

@@ -3360,8 +3360,9 @@ bool CGameHandler::changeStackType(const StackLocation &sl, const CCreature *c)
 		COMPLAIN_RET("Cannot find a stack to change type");
 
 	SetStackType sst;
-	sst.sl = sl;
-	sst.type = c;
+	sst.army = sl.army->id;
+	sst.slot = sl.slot;
+	sst.type = c->idNumber;
 	sendAndApply(&sst);
 	return true;
 }
@@ -5799,8 +5800,10 @@ bool CGameHandler::insertNewStack(const StackLocation &sl, const CCreature *c, T
 		COMPLAIN_RET("Cannot insert stack to that slot!");
 
 	InsertNewStack ins;
-	ins.sl = sl;
-	ins.stack = CStackBasicDescriptor(c, count);
+	ins.army = sl.army->id;
+	ins.slot = sl.slot;
+	ins.type = c->idNumber;
+	ins.count = count;
 	sendAndApply(&ins);
 	return true;
 }
@@ -5818,7 +5821,8 @@ bool CGameHandler::eraseStack(const StackLocation &sl, bool forceRemoval)
 	}
 
 	EraseStack es;
-	es.sl = sl;
+	es.army = sl.army->id;
+	es.slot = sl.slot;
 	sendAndApply(&es);
 	return true;
 }
@@ -5840,7 +5844,8 @@ bool CGameHandler::changeStackCount(const StackLocation &sl, TQuantity count, bo
 	else
 	{
 		ChangeStackCount csc;
-		csc.sl = sl;
+		csc.army = sl.army->id;
+		csc.slot = sl.slot;
 		csc.count = count;
 		csc.absoluteValue = absoluteValue;
 		sendAndApply(&csc);
@@ -5920,25 +5925,32 @@ bool CGameHandler::moveStack(const StackLocation &src, const StackLocation &dst,
 	}
 
 	RebalanceStacks rs;
-	rs.src = src;
-	rs.dst = dst;
+	rs.srcArmy = src.army->id;
+	rs.dstArmy = dst.army->id;
+	rs.srcSlot = src.slot;
+	rs.dstSlot = dst.slot;
 	rs.count = count;
 	sendAndApply(&rs);
 	return true;
 }
 
-bool CGameHandler::swapStacks(const StackLocation &sl1, const StackLocation &sl2)
+bool CGameHandler::swapStacks(const StackLocation & sl1, const StackLocation & sl2)
 {
-
-	if (!sl1.army->hasStackAtSlot(sl1.slot))
+	if(!sl1.army->hasStackAtSlot(sl1.slot))
+	{
 		return moveStack(sl2, sl1);
-	else if (!sl2.army->hasStackAtSlot(sl2.slot))
+	}
+	else if(!sl2.army->hasStackAtSlot(sl2.slot))
+	{
 		return moveStack(sl1, sl2);
+	}
 	else
 	{
 		SwapStacks ss;
-		ss.sl1 = sl1;
-		ss.sl2 = sl2;
+		ss.srcArmy = sl1.army->id;
+		ss.dstArmy = sl2.army->id;
+		ss.srcSlot = sl1.slot;
+		ss.dstSlot = sl2.slot;
 		sendAndApply(&ss);
 		return true;
 	}