Răsfoiți Sursa

Properly pass battleID in all battle netpack's

Ivan Savenko 2 ani în urmă
părinte
comite
9fa7a93fb0

+ 5 - 0
AI/BattleAI/StackWithBonuses.cpp

@@ -320,6 +320,11 @@ battle::Units HypotheticBattle::getUnitsIf(battle::UnitFilter predicate) const
 	return ret;
 }
 
+BattleID HypotheticBattle::getBattleID() const
+{
+	return subject->getBattle()->getBattleID();
+}
+
 int32_t HypotheticBattle::getActiveStackID() const
 {
 	return activeUnitId;

+ 3 - 0
CCallback.cpp

@@ -207,6 +207,7 @@ void CBattleCallback::battleMakeSpellAction(const BattleID & battleID, const Bat
 {
 	assert(action.actionType == EActionType::HERO_SPELL);
 	MakeAction mca(action);
+	mca.battleID = battleID;
 	sendRequest(&mca);
 }
 
@@ -376,6 +377,7 @@ void CBattleCallback::battleMakeUnitAction(const BattleID & battleID, const Batt
 	assert(!cl->gs->getBattle(battleID)->tacticDistance);
 	MakeAction ma;
 	ma.ba = action;
+	ma.battleID = battleID;
 	sendRequest(&ma);
 }
 
@@ -384,6 +386,7 @@ void CBattleCallback::battleMakeTacticAction(const BattleID & battleID, const Ba
 	assert(cl->gs->getBattle(battleID)->tacticDistance);
 	MakeAction ma;
 	ma.ba = action;
+	ma.battleID = battleID;
 	sendRequest(&ma);
 }
 

+ 2 - 2
client/Client.cpp

@@ -615,7 +615,7 @@ void CClient::battleStarted(const BattleInfo * info)
 		if(att || def)
 		{
 			boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
-			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def);
+			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def);
 		}
 		else if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
 		{
@@ -623,7 +623,7 @@ void CClient::battleStarted(const BattleInfo * info)
 			auto spectratorInt = std::dynamic_pointer_cast<CPlayerInterface>(playerint[PlayerColor::SPECTATOR]);
 			spectratorInt->cb->onBattleStarted(info);
 			boost::unique_lock<boost::recursive_mutex> un(*CPlayerInterface::pim);
-			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def, spectratorInt);
+			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def, spectratorInt);
 		}
 	}
 

+ 2 - 1
client/battle/BattleInterface.cpp

@@ -45,7 +45,7 @@
 #include "../../lib/TerrainHandler.h"
 #include "../../lib/CThreadHelper.h"
 
-BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *army2,
+BattleInterface::BattleInterface(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2,
 		const CGHeroInstance *hero1, const CGHeroInstance *hero2,
 		std::shared_ptr<CPlayerInterface> att,
 		std::shared_ptr<CPlayerInterface> defen,
@@ -55,6 +55,7 @@ BattleInterface::BattleInterface(const CCreatureSet *army1, const CCreatureSet *
 	, attackerInt(att)
 	, defenderInt(defen)
 	, curInt(att)
+	, battleID(battleID)
 	, battleOpeningDelayActive(true)
 {
 	if(spectatorInt)

+ 1 - 1
client/battle/BattleInterface.h

@@ -156,7 +156,7 @@ public:
 	BattleID getBattleID() const;
 	std::shared_ptr<CPlayerBattleCallback> getBattle() const;
 
-	BattleInterface(const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);
+	BattleInterface(const BattleID & battleID, const CCreatureSet *army1, const CCreatureSet *army2, const CGHeroInstance *hero1, const CGHeroInstance *hero2, std::shared_ptr<CPlayerInterface> att, std::shared_ptr<CPlayerInterface> defen, std::shared_ptr<CPlayerInterface> spectatorInt = nullptr);
 	~BattleInterface();
 
 	void trySetActivePlayer( PlayerColor player ); // if in hotseat, will activate interface of chosen player

+ 20 - 0
lib/NetPacks.h

@@ -1492,6 +1492,7 @@ struct DLL_LINKAGE BattleStart : public CPackForClient
 	{
 		h & battleID;
 		h & info;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1506,6 +1507,7 @@ struct DLL_LINKAGE BattleNextRound : public CPackForClient
 	template <typename Handler> void serialize(Handler & h, const int version)
 	{
 		h & battleID;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1524,6 +1526,7 @@ struct DLL_LINKAGE BattleSetActiveStack : public CPackForClient
 		h & battleID;
 		h & stack;
 		h & askPlayerInterface;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1557,6 +1560,7 @@ struct DLL_LINKAGE BattleResultAccepted : public CPackForClient
 		h & battleID;
 		h & heroResult;
 		h & winnerSide;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1583,6 +1587,7 @@ struct DLL_LINKAGE BattleResult : public Query
 		h & casualties[1];
 		h & exp;
 		h & artifacts;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1600,6 +1605,7 @@ struct DLL_LINKAGE BattleLogMessage : public CPackForClient
 	{
 		h & battleID;
 		h & lines;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1623,6 +1629,7 @@ struct DLL_LINKAGE BattleStackMoved : public CPackForClient
 		h & tilesToMove;
 		h & distance;
 		h & teleporting;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1640,6 +1647,7 @@ struct DLL_LINKAGE BattleUnitsChanged : public CPackForClient
 	{
 		h & battleID;
 		h & changedStacks;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1693,6 +1701,7 @@ struct BattleStackAttacked
 		h & killedAmount;
 		h & damageAmount;
 		h & spellID;
+		assert(battleID != BattleID::NONE);
 	}
 	bool operator<(const BattleStackAttacked & b) const
 	{
@@ -1758,6 +1767,7 @@ struct DLL_LINKAGE BattleAttack : public CPackForClient
 		h & tile;
 		h & spellID;
 		h & attackerChanges;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1780,6 +1790,7 @@ struct DLL_LINKAGE StartAction : public CPackForClient
 	{
 		h & battleID;
 		h & ba;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1826,6 +1837,7 @@ struct DLL_LINKAGE BattleSpellCast : public CPackForClient
 		h & casterStack;
 		h & castByHero;
 		h & activeCast;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1847,6 +1859,7 @@ struct DLL_LINKAGE SetStackEffect : public CPackForClient
 		h & toAdd;
 		h & toUpdate;
 		h & toRemove;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1864,6 +1877,7 @@ struct DLL_LINKAGE StacksInjured : public CPackForClient
 	{
 		h & battleID;
 		h & stacks;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1878,6 +1892,7 @@ struct DLL_LINKAGE BattleResultsApplied : public CPackForClient
 		h & battleID;
 		h & player1;
 		h & player2;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1895,6 +1910,7 @@ struct DLL_LINKAGE BattleObstaclesChanged : public CPackForClient
 	{
 		h & battleID;
 		h & changes;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1931,6 +1947,7 @@ struct DLL_LINKAGE CatapultAttack : public CPackForClient
 		h & battleID;
 		h & attackedParts;
 		h & attacker;
+		assert(battleID != BattleID::NONE);
 	}
 };
 
@@ -1953,6 +1970,7 @@ struct DLL_LINKAGE BattleSetStackProperty : public CPackForClient
 		h & which;
 		h & val;
 		h & absolute;
+		assert(battleID != BattleID::NONE);
 	}
 
 protected:
@@ -1977,6 +1995,7 @@ struct DLL_LINKAGE BattleTriggerEffect : public CPackForClient
 		h & effect;
 		h & val;
 		h & additionalInfo;
+		assert(battleID != BattleID::NONE);
 	}
 
 protected:
@@ -1993,6 +2012,7 @@ struct DLL_LINKAGE BattleUpdateGateState : public CPackForClient
 	{
 		h & battleID;
 		h & state;
+		assert(battleID != BattleID::NONE);
 	}
 
 protected:

+ 2 - 2
lib/constants/EntityIdentifiers.h

@@ -180,10 +180,10 @@ public:
 	DLL_LINKAGE static const QueryID NONE;
 };
 
-class BattleID : public Identifier<QueryID>
+class BattleID : public Identifier<BattleID>
 {
 public:
-	using Identifier<QueryID>::Identifier;
+	using Identifier<BattleID>::Identifier;
 	DLL_LINKAGE static const BattleID NONE;
 };
 class ObjectInstanceID : public Identifier<ObjectInstanceID>

+ 6 - 2
lib/spells/BattleSpellMechanics.cpp

@@ -252,6 +252,7 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target)
 
 	sc.side = casterSide;
 	sc.spellID = getSpellId();
+	sc.battleID = battle()->getBattle()->getBattleID();
 	sc.tile = target.at(0).hexValue;
 
 	sc.castByHero = mode == Mode::HERO;
@@ -299,6 +300,7 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target)
 	beforeCast(sc, *server->getRNG(), target);
 
 	BattleLogMessage castDescription;
+	castDescription.battleID = battle()->getBattle()->getBattleID();
 
 	switch (mode)
 	{
@@ -344,8 +346,9 @@ void BattleSpellMechanics::cast(ServerCallback * server, const Target & target)
 
 	// send empty event to client
 	// temporary(?) workaround to force animations to trigger
-	StacksInjured fake_event;
-	server->apply(&fake_event);
+	StacksInjured fakeEvent;
+	fakeEvent.battleID = battle()->getBattle()->getBattleID();
+	server->apply(&fakeEvent);
 }
 
 void BattleSpellMechanics::beforeCast(BattleSpellCast & sc, vstd::RNG & rng, const Target & target)
@@ -448,6 +451,7 @@ std::set<const battle::Unit *> BattleSpellMechanics::collectTargets() const
 void BattleSpellMechanics::doRemoveEffects(ServerCallback * server, const std::vector<const battle::Unit *> & targets, const CSelector & selector)
 {
 	SetStackEffect sse;
+	sse.battleID = battle()->getBattle()->getBattleID();
 
 	for(const auto * unit : targets)
 	{

+ 1 - 1
lib/spells/BattleSpellMechanics.h

@@ -73,7 +73,7 @@ private:
 
 	std::set<const battle::Unit *> collectTargets() const;
 
-	static void doRemoveEffects(ServerCallback * server, const std::vector<const battle::Unit *> & targets, const CSelector & selector);
+	void doRemoveEffects(ServerCallback * server, const std::vector<const battle::Unit *> & targets, const CSelector & selector);
 
 	std::set<BattleHex> spellRangeInHexes(BattleHex centralHex) const;
 

+ 1 - 0
lib/spells/effects/Catapult.cpp

@@ -188,6 +188,7 @@ int Catapult::getRandomDamage (ServerCallback * server) const
 void Catapult::removeTowerShooters(ServerCallback * server, const Mechanics * m) const
 {
 	BattleUnitsChanged removeUnits;
+	removeUnits.battleID = m->battle()->getBattle()->getBattleID();
 
 	for (auto const wallPart : { EWallPart::KEEP, EWallPart::BOTTOM_TOWER, EWallPart::UPPER_TOWER })
 	{

+ 5 - 0
lib/spells/effects/Clone.cpp

@@ -14,6 +14,7 @@
 #include "../ISpellMechanics.h"
 #include "../../NetPacks.h"
 #include "../../battle/CBattleInfoCallback.h"
+#include "../../battle/IBattleState.h"
 #include "../../battle/CUnitState.h"
 #include "../../serializer/JsonSerializeFormat.h"
 
@@ -60,6 +61,7 @@ void Clone::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
 		info.summoned = true;
 
 		BattleUnitsChanged pack;
+		pack.battleID = m->battle()->getBattle()->getBattleID();
 		pack.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
 		info.save(pack.changedStacks.back().data);
 		server->apply(&pack);
@@ -67,6 +69,7 @@ void Clone::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
 		//TODO: use BattleUnitsChanged with UPDATE operation
 
 		BattleUnitsChanged cloneFlags;
+		cloneFlags.battleID = m->battle()->getBattle()->getBattleID();
 
 		const auto *cloneUnit = m->battle()->battleGetUnitByID(unitId);
 
@@ -89,6 +92,8 @@ void Clone::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
 		server->apply(&cloneFlags);
 
 		SetStackEffect sse;
+		sse.battleID = m->battle()->getBattle()->getBattleID();
+
 		Bonus lifeTimeMarker(BonusDuration::N_TURNS, BonusType::NONE, BonusSource::SPELL_EFFECT, 0, SpellID::CLONE); //TODO: use special bonus type
 		lifeTimeMarker.turnsRemain = m->getEffectDuration();
 		std::vector<Bonus> buffer;

+ 4 - 0
lib/spells/effects/Damage.cpp

@@ -34,6 +34,9 @@ void Damage::apply(ServerCallback * server, const Mechanics * m, const EffectTar
 {
 	StacksInjured stacksInjured;
 	BattleLogMessage blm;
+	stacksInjured.battleID = m->battle()->getBattle()->getBattleID();
+	blm.battleID = m->battle()->getBattle()->getBattleID();
+
 	size_t targetIndex = 0;
 	const battle::Unit * firstTarget = nullptr;
 	const bool describe = server->describeChanges();
@@ -48,6 +51,7 @@ void Damage::apply(ServerCallback * server, const Mechanics * m, const EffectTar
 		if(unit && unit->alive())
 		{
 			BattleStackAttacked bsa;
+			bsa.battleID = m->battle()->getBattle()->getBattleID();
 			bsa.damageAmount = damageForTarget(targetIndex, m, unit);
 			bsa.stackAttacked = unit->unitId();
 			bsa.attackerID = -1;

+ 2 - 0
lib/spells/effects/DemonSummon.cpp

@@ -14,6 +14,7 @@
 #include "../ISpellMechanics.h"
 #include "../../NetPacks.h"
 #include "../../battle/CBattleInfoCallback.h"
+#include "../../battle/BattleInfo.h"
 #include "../../battle/CUnitState.h"
 #include "../../serializer/JsonSerializeFormat.h"
 
@@ -27,6 +28,7 @@ namespace effects
 void DemonSummon::apply(ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
 {
 	BattleUnitsChanged pack;
+	pack.battleID = m->battle()->getBattle()->getBattleID();
 
 	for(const Destination & dest : target)
 	{

+ 3 - 0
lib/spells/effects/Dispel.cpp

@@ -18,6 +18,7 @@
 
 #include "../../NetPacks.h"
 #include "../../battle/IBattleState.h"
+#include "../../battle/CBattleInfoCallback.h"
 #include "../../battle/Unit.h"
 #include "../../serializer/JsonSerializeFormat.h"
 
@@ -33,6 +34,8 @@ void Dispel::apply(ServerCallback * server, const Mechanics * m, const EffectTar
 	const bool describe = server->describeChanges();
 	SetStackEffect sse;
 	BattleLogMessage blm;
+	blm.battleID = m->battle()->getBattle()->getBattleID();
+	sse.battleID = m->battle()->getBattle()->getBattleID();
 
 	for(const auto & t : target)
 	{

+ 4 - 0
lib/spells/effects/Heal.cpp

@@ -35,7 +35,11 @@ void Heal::apply(ServerCallback * server, const Mechanics * m, const EffectTarge
 void Heal::apply(int64_t value, ServerCallback * server, const Mechanics * m, const EffectTarget & target) const
 {
 	BattleLogMessage logMessage;
+	logMessage.battleID = m->battle()->getBattle()->getBattleID();
+
 	BattleUnitsChanged pack;
+	pack.battleID = m->battle()->getBattle()->getBattleID();
+
 	prepareHealEffect(value, pack, logMessage, *server->getRNG(), m, target);
 	if(!pack.changedStacks.empty())
 		server->apply(&pack);

+ 1 - 0
lib/spells/effects/Sacrifice.cpp

@@ -123,6 +123,7 @@ void Sacrifice::apply(ServerCallback * server, const Mechanics * m, const Effect
 	Heal::apply(calculateHealEffectValue(m, victim), server, m, healTarget);
 
 	BattleUnitsChanged removeUnits;
+	removeUnits.battleID = m->battle()->getBattle()->getBattleID();
 	removeUnits.changedStacks.emplace_back(victim->unitId(), UnitChanges::EOperation::REMOVE);
 	server->apply(&removeUnits);
 }

+ 2 - 0
lib/spells/effects/Summon.cpp

@@ -14,6 +14,7 @@
 
 #include "../ISpellMechanics.h"
 #include "../../battle/CBattleInfoCallback.h"
+#include "../../battle/BattleInfo.h"
 #include "../../battle/Unit.h"
 #include "../../NetPacks.h"
 #include "../../serializer/JsonSerializeFormat.h"
@@ -87,6 +88,7 @@ void Summon::apply(ServerCallback * server, const Mechanics * m, const EffectTar
 	auto valueWithBonus = m->applySpecificSpellBonus(m->calculateRawEffectValue(0, m->getEffectPower()));//TODO: consider use base power too
 
 	BattleUnitsChanged pack;
+	pack.battleID = m->battle()->getBattle()->getBattleID();
 
 	for(const auto & dest : target)
 	{

+ 3 - 0
lib/spells/effects/Timed.cpp

@@ -15,6 +15,7 @@
 
 #include "../../NetPacks.h"
 #include "../../battle/IBattleState.h"
+#include "../../battle/CBattleInfoCallback.h"
 #include "../../battle/Unit.h"
 #include "../../serializer/JsonSerializeFormat.h"
 
@@ -116,6 +117,8 @@ void Timed::apply(ServerCallback * server, const Mechanics * m, const EffectTarg
 
 	SetStackEffect sse;
 	BattleLogMessage blm;
+	blm.battleID = m->battle()->getBattle()->getBattleID();
+	sse.battleID = m->battle()->getBattle()->getBattleID();
 
 	for(const auto & t : target)
 	{

+ 23 - 2
server/battles/BattleActionProcessor.cpp

@@ -160,6 +160,8 @@ bool BattleActionProcessor::doDefendAction(const CBattleInfoCallback & battle, c
 
 	//defensive stance, TODO: filter out spell boosts from bonus (stone skin etc.)
 	SetStackEffect sse;
+	sse.battleID = battle.getBattle()->getBattleID();
+
 	Bonus defenseBonusToAdd(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 20, -1, static_cast<int32_t>(PrimarySkill::DEFENSE), BonusValueType::PERCENT_TO_ALL);
 	Bonus bonus2(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, stack->valOfBonuses(BonusType::DEFENSIVE_STANCE), -1, static_cast<int32_t>(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
 	Bonus alternativeWeakCreatureBonus(BonusDuration::STACK_GETS_TURN, BonusType::PRIMARY_SKILL, BonusSource::OTHER, 1, -1, static_cast<int32_t>(PrimarySkill::DEFENSE), BonusValueType::ADDITIVE_VALUE);
@@ -188,6 +190,7 @@ bool BattleActionProcessor::doDefendAction(const CBattleInfoCallback & battle, c
 	gameHandler->sendAndApply(&sse);
 
 	BattleLogMessage message;
+	message.battleID = battle.getBattle()->getBattleID();
 
 	MetaString text;
 	stack->addText(text, EMetaText::GENERAL_TXT, 120);
@@ -541,6 +544,7 @@ bool BattleActionProcessor::makeBattleActionImpl(const CBattleInfoCallback & bat
 	if (!ba.isBattleEndAction())
 	{
 		StartAction startAction(ba);
+		startAction.battleID = battle.getBattle()->getBattleID();
 		gameHandler->sendAndApply(&startAction);
 	}
 
@@ -549,6 +553,7 @@ bool BattleActionProcessor::makeBattleActionImpl(const CBattleInfoCallback & bat
 	if (!ba.isBattleEndAction())
 	{
 		EndAction endAction;
+		endAction.battleID = battle.getBattle()->getBattleID();
 		gameHandler->sendAndApply(&endAction);
 	}
 
@@ -658,12 +663,14 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
 				occupyGateDrawbridgeHex(dest))
 			{
 				BattleUpdateGateState db;
+				db.battleID = battle.getBattle()->getBattleID();
 				db.state = EGateState::OPENED;
 				gameHandler->sendAndApply(&db);
 			}
 
 			//inform clients about move
 			BattleStackMoved sm;
+			sm.battleID = battle.getBattle()->getBattleID();
 			sm.stack = curStack->unitId();
 			std::vector<BattleHex> tiles;
 			tiles.push_back(path.first[0]);
@@ -793,6 +800,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
 			{
 				//commit movement
 				BattleStackMoved sm;
+				sm.battleID = battle.getBattle()->getBattleID();
 				sm.stack = curStack->unitId();
 				sm.distance = path.second;
 				sm.teleporting = false;
@@ -820,6 +828,7 @@ int BattleActionProcessor::moveStack(const CBattleInfoCallback & battle, int sta
 						if (curStack->alive())
 						{
 							BattleUpdateGateState db;
+							db.battleID = battle.getBattle()->getBattleID();
 							db.state = EGateState::OPENED;
 							gameHandler->sendAndApply(&db);
 						}
@@ -857,6 +866,9 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 	FireShieldInfo fireShield;
 	BattleAttack bat;
 	BattleLogMessage blm;
+	blm.battleID = battle.getBattle()->getBattleID();
+	bat.battleID = battle.getBattle()->getBattleID();
+	bat.attackerChanges.battleID = battle.getBattle()->getBattleID();
 	bat.stackAttacking = attacker->unitId();
 	bat.tile = targetHex;
 
@@ -966,6 +978,9 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 	if (drainedLife > 0)
 		bat.flags |= BattleAttack::LIFE_DRAIN;
 
+	for (BattleStackAttacked & bsa : bat.bsa)
+		bsa.battleID = battle.getBattle()->getBattleID();
+
 	gameHandler->sendAndApply(&bat);
 
 	{
@@ -1032,6 +1047,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 		{
 			BattleStackAttacked bsa;
 
+			bsa.battleID = battle.getBattle()->getBattleID();
 			bsa.flags |= BattleStackAttacked::FIRE_SHIELD;
 			bsa.stackAttacked = attacker->unitId(); //invert
 			bsa.attackerID = defender->unitId();
@@ -1039,6 +1055,7 @@ void BattleActionProcessor::makeAttack(const CBattleInfoCallback & battle, const
 			attacker->prepareAttacked(bsa, gameHandler->getRandomGenerator());
 
 			StacksInjured pack;
+			pack.battleID = battle.getBattle()->getBattleID();
 			pack.stacks.push_back(bsa);
 			gameHandler->sendAndApply(&pack);
 
@@ -1240,10 +1257,12 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 			return; //wrong subtype
 
 		BattleUnitsChanged addUnits;
+		addUnits.battleID = battle.getBattle()->getBattleID();
 		addUnits.changedStacks.emplace_back(resurrectInfo.id, UnitChanges::EOperation::ADD);
 		resurrectInfo.save(addUnits.changedStacks.back().data);
 
 		BattleUnitsChanged removeUnits;
+		removeUnits.battleID = battle.getBattle()->getBattleID();
 		removeUnits.changedStacks.emplace_back(defender->unitId(), UnitChanges::EOperation::REMOVE);
 		gameHandler->sendAndApply(&removeUnits);
 		gameHandler->sendAndApply(&addUnits);
@@ -1280,10 +1299,11 @@ void BattleActionProcessor::handleAfterAttackCasting(const CBattleInfoCallback &
 		defender->prepareAttacked(bsa, gameHandler->getRandomGenerator());
 
 		StacksInjured si;
+		si.battleID = battle.getBattle()->getBattleID();
 		si.stacks.push_back(bsa);
 
 		gameHandler->sendAndApply(&si);
-		sendGenericKilledLog(defender, bsa.killedAmount, false);
+		sendGenericKilledLog(battle, defender, bsa.killedAmount, false);
 	}
 }
 
@@ -1354,11 +1374,12 @@ int64_t BattleActionProcessor::applyBattleEffects(const CBattleInfoCallback & ba
 	return drainedLife;
 }
 
-void BattleActionProcessor::sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple)
+void BattleActionProcessor::sendGenericKilledLog(const CBattleInfoCallback & battle, const CStack * defender, int32_t killed, bool multiple)
 {
 	if(killed > 0)
 	{
 		BattleLogMessage blm;
+		blm.battleID = battle.getBattle()->getBattleID();
 		addGenericKilledLog(blm, defender, killed, multiple);
 		gameHandler->sendAndApply(&blm);
 	}

+ 1 - 1
server/battles/BattleActionProcessor.h

@@ -49,7 +49,7 @@ class BattleActionProcessor : boost::noncopyable
 	// damage, drain life & fire shield; returns amount of drained life
 	int64_t applyBattleEffects(const CBattleInfoCallback & battle, BattleAttack & bat, std::shared_ptr<battle::CUnitState> attackerState, FireShieldInfo & fireShield, const CStack * def, int distance, bool secondary);
 
-	void sendGenericKilledLog(const CStack * defender, int32_t killed, bool multiple);
+	void sendGenericKilledLog(const CBattleInfoCallback & battle, const CStack * defender, int32_t killed, bool multiple);
 	void addGenericKilledLog(BattleLogMessage & blm, const CStack * defender, int32_t killed, bool multiple);
 
 	bool canStackAct(const CBattleInfoCallback & battle, const CStack * stack);

+ 11 - 0
server/battles/BattleFlowProcessor.cpp

@@ -171,6 +171,7 @@ void BattleFlowProcessor::trySummonGuardians(const CBattleInfoCallback & battle,
 			info.summoned = true;
 
 			BattleUnitsChanged pack;
+			pack.battleID = battle.getBattle()->getBattleID();
 			pack.changedStacks.emplace_back(info.id, UnitChanges::EOperation::ADD);
 			info.save(pack.changedStacks.back().data);
 			gameHandler->sendAndApply(&pack);
@@ -227,6 +228,7 @@ void BattleFlowProcessor::onTacticsEnded(const CBattleInfoCallback & battle)
 void BattleFlowProcessor::startNextRound(const CBattleInfoCallback & battle, bool isFirstRound)
 {
 	BattleNextRound bnr;
+	bnr.battleID = battle.getBattle()->getBattleID();
 	logGlobal->debug("Next round starts");
 	gameHandler->sendAndApply(&bnr);
 
@@ -265,6 +267,7 @@ const CStack * BattleFlowProcessor::getNextStack(const CBattleInfoCallback & bat
 	if(stack && stack->alive() && !stack->waiting)
 	{
 		BattleTriggerEffect bte;
+		bte.battleID = battle.getBattle()->getBattleID();
 		bte.stackID = stack->unitId();
 		bte.effect = vstd::to_underlying(BonusType::HP_REGENERATION);
 
@@ -303,6 +306,7 @@ void BattleFlowProcessor::activateNextStack(const CBattleInfoCallback & battle)
 		}
 
 		BattleUnitsChanged removeGhosts;
+		removeGhosts.battleID = battle.getBattle()->getBattleID();
 
 		auto pendingGhosts = battle.battleGetStacksIf([](const CStack * stack){
 			return stack->ghostPending;
@@ -487,6 +491,7 @@ bool BattleFlowProcessor::rollGoodMorale(const CBattleInfoCallback & battle, con
 		if(diceSize.size() > 0 && gameHandler->getRandomGenerator().nextInt(1, diceSize[diceIndex]) == 1)
 		{
 			BattleTriggerEffect bte;
+			bte.battleID = battle.getBattle()->getBattleID();
 			bte.stackID = next->unitId();
 			bte.effect = vstd::to_underlying(BonusType::MORALE);
 			bte.val = 1;
@@ -558,6 +563,7 @@ void BattleFlowProcessor::makeStackDoNothing(const CBattleInfoCallback & battle,
 bool BattleFlowProcessor::makeAutomaticAction(const CBattleInfoCallback & battle, const CStack *stack, BattleAction &ba)
 {
 	BattleSetActiveStack bsa;
+	bsa.battleID = battle.getBattle()->getBattleID();
 	bsa.stack = stack->unitId();
 	bsa.askPlayerInterface = false;
 	gameHandler->sendAndApply(&bsa);
@@ -601,6 +607,7 @@ void BattleFlowProcessor::stackEnchantedTrigger(const CBattleInfoCallback & batt
 void BattleFlowProcessor::removeObstacle(const CBattleInfoCallback & battle, const CObstacleInstance & obstacle)
 {
 	BattleObstaclesChanged obsRem;
+	obsRem.battleID = battle.getBattle()->getBattleID();
 	obsRem.changes.emplace_back(obstacle.uniqueID, ObstacleChanges::EOperation::REMOVE);
 	gameHandler->sendAndApply(&obsRem);
 }
@@ -608,6 +615,7 @@ void BattleFlowProcessor::removeObstacle(const CBattleInfoCallback & battle, con
 void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, const CStack *st)
 {
 	BattleTriggerEffect bte;
+	bte.battleID = battle.getBattle()->getBattleID();
 	bte.stackID = st->unitId();
 	bte.effect = -1;
 	bte.val = 0;
@@ -640,6 +648,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
 			if (unbind)
 			{
 				BattleSetStackProperty ssp;
+				ssp.battleID = battle.getBattle()->getBattleID();
 				ssp.which = BattleSetStackProperty::UNBIND;
 				ssp.stackID = st->unitId();
 				gameHandler->sendAndApply(&ssp);
@@ -721,6 +730,7 @@ void BattleFlowProcessor::stackTurnTrigger(const CBattleInfoCallback & battle, c
 
 					int cooldown = bonus->additionalInfo[0];
 					BattleSetStackProperty ssp;
+					ssp.battleID = battle.getBattle()->getBattleID();
 					ssp.which = BattleSetStackProperty::ENCHANTER_COUNTER;
 					ssp.absolute = false;
 					ssp.val = cooldown;
@@ -737,6 +747,7 @@ void BattleFlowProcessor::setActiveStack(const CBattleInfoCallback & battle, con
 	assert(stack);
 
 	BattleSetActiveStack sas;
+	sas.battleID = battle.getBattle()->getBattleID();
 	sas.stack = stack->unitId();
 	gameHandler->sendAndApply(&sas);
 }

+ 2 - 8
server/battles/BattleProcessor.cpp

@@ -89,7 +89,7 @@ void BattleProcessor::startBattlePrimary(const CArmedInstance *army1, const CArm
 			}
 		}
 
-		lastBattleQuery->bi = battle;
+		lastBattleQuery->battleID = battle->getBattleID();
 		lastBattleQuery->result = std::nullopt;
 		lastBattleQuery->belligerents[0] = battle->sides[0].armyObject;
 		lastBattleQuery->belligerents[1] = battle->sides[1].armyObject;
@@ -261,13 +261,7 @@ void BattleProcessor::endBattleConfirm(const BattleID & battleID)
 
 void BattleProcessor::battleAfterLevelUp(const BattleID & battleID, const BattleResult &result)
 {
-	auto battle = gameHandler->gameState()->getBattle(battleID);
-	assert(battle);
-
-	if (!battle)
-		return;
-
-	resultProcessor->battleAfterLevelUp(*battle, result);
+	resultProcessor->battleAfterLevelUp(battleID, result);
 }
 
 void BattleProcessor::setGameHandler(CGameHandler * newGameHandler)

+ 25 - 27
server/battles/BattleResultProcessor.cpp

@@ -180,26 +180,21 @@ void CasualtiesAfterBattle::updateArmy(CGameHandler *gh)
 	}
 }
 
-FinishingBattleHelper::FinishingBattleHelper(std::shared_ptr<const CBattleQuery> Query, int remainingBattleQueriesCount)
+FinishingBattleHelper::FinishingBattleHelper(const CBattleInfoCallback & info, const BattleResult & result, int remainingBattleQueriesCount)
 {
-	assert(Query->result);
-	assert(Query->bi);
-	auto &result = *Query->result;
-	auto &info = *Query->bi;
-
 	if (result.winner == BattleSide::ATTACKER)
 	{
-		winnerHero = info.getSideHero(BattleSide::ATTACKER);
-		loserHero = info.getSideHero(BattleSide::DEFENDER);
-		victor = info.getSidePlayer(BattleSide::ATTACKER);
-		loser = info.getSidePlayer(BattleSide::DEFENDER);
+		winnerHero = info.getBattle()->getSideHero(BattleSide::ATTACKER);
+		loserHero = info.getBattle()->getSideHero(BattleSide::DEFENDER);
+		victor = info.getBattle()->getSidePlayer(BattleSide::ATTACKER);
+		loser = info.getBattle()->getSidePlayer(BattleSide::DEFENDER);
 	}
 	else
 	{
-		winnerHero = info.getSideHero(BattleSide::DEFENDER);
-		loserHero = info.getSideHero(BattleSide::ATTACKER);
-		victor = info.getSidePlayer(BattleSide::DEFENDER);
-		loser = info.getSidePlayer(BattleSide::ATTACKER);
+		winnerHero = info.getBattle()->getSideHero(BattleSide::DEFENDER);
+		loserHero = info.getBattle()->getSideHero(BattleSide::ATTACKER);
+		victor = info.getBattle()->getSidePlayer(BattleSide::DEFENDER);
+		loser = info.getBattle()->getSidePlayer(BattleSide::ATTACKER);
 	}
 
 	winnerSide = result.winner;
@@ -207,12 +202,12 @@ FinishingBattleHelper::FinishingBattleHelper(std::shared_ptr<const CBattleQuery>
 	this->remainingBattleQueriesCount = remainingBattleQueriesCount;
 }
 
-FinishingBattleHelper::FinishingBattleHelper()
-{
-	winnerHero = loserHero = nullptr;
-	winnerSide = 0;
-	remainingBattleQueriesCount = 0;
-}
+//FinishingBattleHelper::FinishingBattleHelper()
+//{
+//	winnerHero = loserHero = nullptr;
+//	winnerSide = 0;
+//	remainingBattleQueriesCount = 0;
+//}
 
 void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
 {
@@ -267,7 +262,7 @@ void BattleResultProcessor::endBattle(const CBattleInfoCallback & battle)
 	const int queriedPlayers = battleQuery ? (int)boost::count(gameHandler->queries->allQueries(), battleQuery) : 0;
 
 	assert(finishingBattles.count(battle.getBattle()->getBattleID()) == 0);
-	finishingBattles[battle.getBattle()->getBattleID()] = std::make_unique<FinishingBattleHelper>(battleQuery, queriedPlayers);
+	finishingBattles[battle.getBattle()->getBattleID()] = std::make_unique<FinishingBattleHelper>(battle, *battleResult, queriedPlayers);
 
 	// in battles against neutrals, 1st player can ask to replay battle manually
 	if (!battle.sideToPlayer(1).isValidPlayer())
@@ -490,6 +485,7 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 		gameHandler->changePrimSkill(finishingBattle->winnerHero, PrimarySkill::EXPERIENCE, battleResult->exp[finishingBattle->winnerSide]);
 
 	BattleResultAccepted raccepted;
+	raccepted.battleID = battle.getBattle()->getBattleID();
 	raccepted.heroResult[0].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(0));
 	raccepted.heroResult[1].army = const_cast<CArmedInstance*>(battle.battleGetArmyObject(1));
 	raccepted.heroResult[0].hero = const_cast<CGHeroInstance*>(battle.battleGetFightingHero(0));
@@ -503,15 +499,15 @@ void BattleResultProcessor::endBattleConfirm(const CBattleInfoCallback & battle)
 	//--> continuation (battleAfterLevelUp) occurs after level-up gameHandler->queries are handled or on removing query
 }
 
-void BattleResultProcessor::battleAfterLevelUp(const CBattleInfoCallback & battle, const BattleResult & result)
+void BattleResultProcessor::battleAfterLevelUp(const BattleID & battleID, const BattleResult & result)
 {
 	LOG_TRACE(logGlobal);
 
-	assert(finishingBattles.count(battle.getBattle()->getBattleID()) != 0);
-	if(finishingBattles.count(battle.getBattle()->getBattleID()) == 0)
+	assert(finishingBattles.count(battleID) != 0);
+	if(finishingBattles.count(battleID) == 0)
 		return;
 
-	auto & finishingBattle = finishingBattles[battle.getBattle()->getBattleID()];
+	auto & finishingBattle = finishingBattles[battleID];
 
 	finishingBattle->remainingBattleQueriesCount--;
 	logGlobal->trace("Decremented gameHandler->queries count to %d", finishingBattle->remainingBattleQueriesCount);
@@ -537,6 +533,7 @@ void BattleResultProcessor::battleAfterLevelUp(const CBattleInfoCallback & battl
 	}
 
 	BattleResultsApplied resultsApplied;
+	resultsApplied.battleID = battleID;
 	resultsApplied.player1 = finishingBattle->victor;
 	resultsApplied.player2 = finishingBattle->loser;
 	gameHandler->sendAndApply(&resultsApplied);
@@ -561,8 +558,8 @@ void BattleResultProcessor::battleAfterLevelUp(const CBattleInfoCallback & battl
 			gameHandler->heroPool->onHeroEscaped(finishingBattle->victor, finishingBattle->winnerHero);
 	}
 
-	finishingBattles.erase(battle.getBattle()->getBattleID());
-	battleResults.erase(battle.getBattle()->getBattleID());
+	finishingBattles.erase(battleID);
+	battleResults.erase(battleID);
 }
 
 void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide)
@@ -572,6 +569,7 @@ void BattleResultProcessor::setBattleResult(const CBattleInfoCallback & battle,
 	battleResults[battle.getBattle()->getBattleID()] = std::make_unique<BattleResult>();
 
 	auto & battleResult = battleResults[battle.getBattle()->getBattleID()];
+	battleResult->battleID = battle.getBattle()->getBattleID();
 	battleResult->result = resultType;
 	battleResult->winner = victoriusSide; //surrendering side loses
 

+ 3 - 3
server/battles/BattleResultProcessor.h

@@ -37,8 +37,8 @@ struct CasualtiesAfterBattle
 
 struct FinishingBattleHelper
 {
-	FinishingBattleHelper();
-	FinishingBattleHelper(std::shared_ptr<const CBattleQuery> Query, int RemainingBattleQueriesCount);
+//	FinishingBattleHelper();
+	FinishingBattleHelper(const CBattleInfoCallback & battle, const BattleResult & result, int RemainingBattleQueriesCount);
 
 	inline bool isDraw() const {return winnerSide == 2;}
 
@@ -76,5 +76,5 @@ public:
 	void setBattleResult(const CBattleInfoCallback & battle, EBattleResult resultType, int victoriusSide);
 	void endBattle(const CBattleInfoCallback & battle); //ends battle
 	void endBattleConfirm(const CBattleInfoCallback & battle);
-	void battleAfterLevelUp(const CBattleInfoCallback & battle, const BattleResult & result);
+	void battleAfterLevelUp(const BattleID & battleID, const BattleResult & result);
 };

+ 3 - 3
server/queries/BattleQueries.cpp

@@ -24,7 +24,7 @@ void CBattleQuery::notifyObjectAboutRemoval(const CObjectVisitQuery & objectVisi
 
 CBattleQuery::CBattleQuery(CGameHandler * owner, const IBattleInfo * bi):
 	CGhQuery(owner),
-	bi(bi)
+	battleID(bi->getBattleID())
 {
 	belligerents[0] = bi->getSideArmy(0);
 	belligerents[1] = bi->getSideArmy(1);
@@ -34,7 +34,7 @@ CBattleQuery::CBattleQuery(CGameHandler * owner, const IBattleInfo * bi):
 }
 
 CBattleQuery::CBattleQuery(CGameHandler * owner):
-	CGhQuery(owner), bi(nullptr)
+	CGhQuery(owner)
 {
 	belligerents[0] = belligerents[1] = nullptr;
 }
@@ -48,7 +48,7 @@ bool CBattleQuery::blocksPack(const CPack * pack) const
 void CBattleQuery::onRemoval(PlayerColor color)
 {
 	if(result)
-		gh->battles->battleAfterLevelUp(bi->getBattleID(), *result);
+		gh->battles->battleAfterLevelUp(battleID, *result);
 }
 
 CBattleDialogQuery::CBattleDialogQuery(CGameHandler * owner, const IBattleInfo * bi):

+ 1 - 1
server/queries/BattleQueries.h

@@ -23,7 +23,7 @@ public:
 	std::array<const CArmedInstance *,2> belligerents;
 	std::array<int, 2> initialHeroMana;
 
-	const IBattleInfo *bi;
+	BattleID battleID;
 	std::optional<BattleResult> result;
 
 	CBattleQuery(CGameHandler * owner);