Selaa lähdekoodia

Battle Info uses ObjectInstanceID's instead of pointers

Ivan Savenko 8 kuukautta sitten
vanhempi
sitoutus
f03cc06176

+ 3 - 3
client/Client.cpp

@@ -388,7 +388,7 @@ void CClient::battleStarted(const BattleInfo * info)
 	auto callBattleStart = [&](PlayerColor color, BattleSide side)
 	{
 		if(vstd::contains(battleints, color))
-			battleints[color]->battleStart(info->battleID, leftSide.armyObject, rightSide.armyObject, info->tile, leftSide.hero, rightSide.hero, side, info->replayAllowed);
+			battleints[color]->battleStart(info->battleID, leftSide.getArmy(), rightSide.getArmy(), info->tile, leftSide.getHero(), rightSide.getHero(), side, info->replayAllowed);
 	};
 	
 	callBattleStart(leftSide.color, BattleSide::LEFT_SIDE);
@@ -433,14 +433,14 @@ void CClient::battleStarted(const BattleInfo * info)
 	{
 		if(att || def)
 		{
-			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def);
+			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.getArmy(), rightSide.getArmy(), leftSide.getHero(), rightSide.getHero(), att, def);
 		}
 		else if(settings["session"]["spectate"].Bool() && !settings["session"]["spectate-skip-battle"].Bool())
 		{
 			//TODO: This certainly need improvement
 			auto spectratorInt = std::dynamic_pointer_cast<CPlayerInterface>(playerint[PlayerColor::SPECTATOR]);
 			spectratorInt->cb->onBattleStarted(info);
-			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.armyObject, rightSide.armyObject, leftSide.hero, rightSide.hero, att, def, spectratorInt);
+			CPlayerInterface::battleInt = std::make_shared<BattleInterface>(info->getBattleID(), leftSide.getArmy(), rightSide.getArmy(), leftSide.getHero(), rightSide.getHero(), att, def, spectratorInt);
 		}
 	}
 

+ 3 - 3
client/NetPacksClient.cpp

@@ -745,11 +745,11 @@ void ApplyFirstClientNetPackVisitor::visitBattleStart(BattleStart & pack)
 {
 	// Cannot use the usual code because curB is not set yet
 	callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::ATTACKER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSideArmy(BattleSide::ATTACKER), pack.info->getSideArmy(BattleSide::DEFENDER),
-		pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSideHero(BattleSide::DEFENDER));
+		pack.info->tile, pack.info->getSideHero(BattleSide::ATTACKER), pack.info->getSideHero(BattleSide::DEFENDER));
 	callOnlyThatBattleInterface(cl, pack.info->getSide(BattleSide::DEFENDER).color, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSideArmy(BattleSide::ATTACKER), pack.info->getSideArmy(BattleSide::DEFENDER),
-		pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSideHero(BattleSide::DEFENDER));
+		pack.info->tile, pack.info->getSideHero(BattleSide::ATTACKER), pack.info->getSideHero(BattleSide::DEFENDER));
 	callOnlyThatBattleInterface(cl, PlayerColor::SPECTATOR, &IBattleEventsReceiver::battleStartBefore, pack.battleID, pack.info->getSideArmy(BattleSide::ATTACKER), pack.info->getSideArmy(BattleSide::DEFENDER),
-		pack.info->tile, pack.info->getSide(BattleSide::ATTACKER).hero, pack.info->getSideHero(BattleSide::DEFENDER));
+		pack.info->tile, pack.info->getSideHero(BattleSide::ATTACKER), pack.info->getSideHero(BattleSide::DEFENDER));
 }
 
 void ApplyClientNetPackVisitor::visitBattleStart(BattleStart & pack)

+ 26 - 15
lib/battle/BattleInfo.cpp

@@ -157,10 +157,10 @@ struct RangeGenerator
 	std::function<int()> myRand;
 };
 
-std::unique_ptr<BattleInfo> BattleInfo::setupBattle(const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town)
+std::unique_ptr<BattleInfo> BattleInfo::setupBattle(IGameCallback *cb, const int3 & tile, TerrainId terrain, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town)
 {
 	CMP_stack cmpst;
-	auto currentBattle = std::make_unique<BattleInfo>(layout);
+	auto currentBattle = std::make_unique<BattleInfo>(cb, layout);
 
 	for(auto i : { BattleSide::LEFT_SIDE, BattleSide::RIGHT_SIDE})
 		currentBattle->sides[i].init(heroes[i], armies[i]);
@@ -171,7 +171,8 @@ std::unique_ptr<BattleInfo> BattleInfo::setupBattle(const int3 & tile, TerrainId
 	currentBattle->round = -2;
 	currentBattle->activeStack = -1;
 	currentBattle->replayAllowed = false;
-	currentBattle->town = town;
+	if (town)
+		currentBattle->townID = town->id;
 
 	//setting up siege obstacles
 	if (town && town->fortificationsLevel().wallsHealth != 0)
@@ -354,15 +355,15 @@ std::unique_ptr<BattleInfo> BattleInfo::setupBattle(const int3 & tile, TerrainId
 		}
 	}
 
-	if (currentBattle->town)
+	if (currentBattle->townID.hasValue())
 	{
-		if (currentBattle->town->fortificationsLevel().citadelHealth != 0)
+		if (currentBattle->getTown()->fortificationsLevel().citadelHealth != 0)
 			currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_CENTRAL_TOWER);
 
-		if (currentBattle->town->fortificationsLevel().upperTowerHealth != 0)
+		if (currentBattle->getTown()->fortificationsLevel().upperTowerHealth != 0)
 			currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_UPPER_TOWER);
 
-		if (currentBattle->town->fortificationsLevel().lowerTowerHealth != 0)
+		if (currentBattle->getTown()->fortificationsLevel().lowerTowerHealth != 0)
 			currentBattle->generateNewStack(currentBattle->nextUnitId(), CStackBasicDescriptor(CreatureID::ARROW_TOWERS, 1), BattleSide::DEFENDER, SlotID::ARROW_TOWERS_SLOT, BattleHex::CASTLE_BOTTOM_TOWER);
 
 		//Moat generating is done on server
@@ -437,7 +438,7 @@ const CGHeroInstance * BattleInfo::getHero(const PlayerColor & player) const
 {
 	for(const auto & side : sides)
 		if(side.color == player)
-			return side.hero;
+			return side.getHero();
 
 	logGlobal->error("Player %s is not in battle!", player.toString());
 	return nullptr;
@@ -458,17 +459,18 @@ CStack * BattleInfo::getStack(int stackID, bool onlyAlive)
 	return const_cast<CStack *>(battleGetStackByID(stackID, onlyAlive));
 }
 
-BattleInfo::BattleInfo(const BattleLayout & layout):
-	BattleInfo()
+BattleInfo::BattleInfo(IGameCallback *cb, const BattleLayout & layout):
+	BattleInfo(cb)
 {
 	*this->layout = layout;
 }
 
-BattleInfo::BattleInfo():
+BattleInfo::BattleInfo(IGameCallback *cb)
+	:GameCallbackHolder(cb),
+	sides({SideInBattle(cb), SideInBattle(cb)}),
 	layout(std::make_unique<BattleLayout>()),
 	round(-1),
 	activeStack(-1),
-	town(nullptr),
 	tile(-1,-1,-1),
 	battlefieldType(BattleField::NONE),
 	tacticsSide(BattleSide::NONE),
@@ -557,12 +559,19 @@ PlayerColor BattleInfo::getSidePlayer(BattleSide side) const
 
 const CArmedInstance * BattleInfo::getSideArmy(BattleSide side) const
 {
-	return getSide(side).armyObject;
+	return getSide(side).getArmy();
 }
 
 const CGHeroInstance * BattleInfo::getSideHero(BattleSide side) const
 {
-	return getSide(side).hero;
+	return getSide(side).getHero();
+}
+
+const CGTownInstance * BattleInfo::getTown() const
+{
+	if (townID.hasValue())
+		return cb->getTown(townID);
+	return nullptr;
 }
 
 uint8_t BattleInfo::getTacticDist() const
@@ -577,7 +586,9 @@ BattleSide BattleInfo::getTacticsSide() const
 
 const CGTownInstance * BattleInfo::getDefendedTown() const
 {
-	return town;
+	if (townID.hasValue())
+		return cb->getTown(townID);
+	return nullptr;
 }
 
 EWallState BattleInfo::getWallState(EWallPart partOfWall) const

+ 15 - 10
lib/battle/BattleInfo.h

@@ -8,13 +8,16 @@
  *
  */
 #pragma once
-#include "../int3.h"
-#include "../bonuses/Bonus.h"
-#include "../bonuses/CBonusSystemNode.h"
+
 #include "CBattleInfoCallback.h"
 #include "IBattleState.h"
-#include "SiegeInfo.h"
 #include "SideInBattle.h"
+#include "SiegeInfo.h"
+
+#include "../GameCallbackHolder.h"
+#include "../bonuses/Bonus.h"
+#include "../bonuses/CBonusSystemNode.h"
+#include "../int3.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
@@ -24,7 +27,7 @@ class CStackBasicDescriptor;
 class BattleField;
 struct BattleLayout;
 
-class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState
+class DLL_LINKAGE BattleInfo : public CBonusSystemNode, public CBattleInfoCallback, public IBattleState, public GameCallbackHolder
 {
 	BattleSideArray<SideInBattle> sides; //sides[0] - attacker, sides[1] - defender
 	std::unique_ptr<BattleLayout> layout;
@@ -33,7 +36,7 @@ public:
 
 	si32 round;
 	si32 activeStack;
-	const CGTownInstance * town; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
+	ObjectInstanceID townID; //used during town siege, nullptr if this is not a siege (note that fortless town IS also a siege)
 	int3 tile; //for background and bonuses
 	bool replayAllowed;
 	std::vector<std::unique_ptr<CStack>> stacks;
@@ -52,7 +55,7 @@ public:
 		h & sides;
 		h & round;
 		h & activeStack;
-		h & town;
+		h & townID;
 		h & tile;
 		h & stacks;
 		h & obstacles;
@@ -66,8 +69,8 @@ public:
 	}
 
 	//////////////////////////////////////////////////////////////////////////
-	BattleInfo(const BattleLayout & layout);
-	BattleInfo();
+	BattleInfo(IGameCallback *cb, const BattleLayout & layout);
+	BattleInfo(IGameCallback *cb);
 	virtual ~BattleInfo();
 
 	const IBattleInfo * getBattle() const override;
@@ -93,6 +96,8 @@ public:
 	const CArmedInstance * getSideArmy(BattleSide side) const override;
 	const CGHeroInstance * getSideHero(BattleSide side) const override;
 
+	const CGTownInstance * getTown() const;
+
 	ui8 getTacticDist() const override;
 	BattleSide getTacticsSide() const override;
 
@@ -154,7 +159,7 @@ public:
 	const CGHeroInstance * getHero(const PlayerColor & player) const; //returns fighting hero that belongs to given player
 
 	void localInit();
-	static std::unique_ptr<BattleInfo> setupBattle(const int3 & tile, TerrainId, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town);
+	static std::unique_ptr<BattleInfo> setupBattle(IGameCallback *cb, const int3 & tile, TerrainId, const BattleField & battlefieldType, BattleSideArray<const CArmedInstance *> armies, BattleSideArray<const CGHeroInstance *> heroes, const BattleLayout & layout, const CGTownInstance * town);
 
 	BattleSide whatSide(const PlayerColor & player) const;
 

+ 22 - 5
lib/battle/SideInBattle.cpp

@@ -9,16 +9,19 @@
  */
 #include "StdInc.h"
 #include "SideInBattle.h"
-#include "../mapObjects/CArmedInstance.h"
+
+#include "../IGameCallback.h"
+#include "../mapObjects/CGHeroInstance.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
 void SideInBattle::init(const CGHeroInstance * Hero, const CArmedInstance * Army)
 {
-	hero = Hero;
-	armyObject = Army;
+	armyObjectID = Army->id;
+	if (Hero)
+		heroID = Hero->id;
 
-	switch(armyObject->ID.toEnum())
+	switch(Army->ID.toEnum())
 	{
 		case Obj::CREATURE_GENERATOR1:
 		case Obj::CREATURE_GENERATOR2:
@@ -27,11 +30,25 @@ void SideInBattle::init(const CGHeroInstance * Hero, const CArmedInstance * Army
 			color = PlayerColor::NEUTRAL;
 			break;
 		default:
-			color = armyObject->getOwner();
+			color = Army->getOwner();
 	}
 
 	if(color == PlayerColor::UNFLAGGABLE)
 		color = PlayerColor::NEUTRAL;
 }
 
+const CArmedInstance * SideInBattle::getArmy() const
+{
+	if (armyObjectID.hasValue())
+		return dynamic_cast<const CArmedInstance*>(cb->getObjInstance(armyObjectID));
+	return nullptr;
+}
+
+const CGHeroInstance * SideInBattle::getHero() const
+{
+	if (heroID.hasValue())
+		return cb->getHero(heroID);
+	return nullptr;
+}
+
 VCMI_LIB_NAMESPACE_END

+ 11 - 6
lib/battle/SideInBattle.h

@@ -8,31 +8,36 @@
  *
  */
 #pragma once
+
 #include "../GameConstants.h"
+#include "../GameCallbackHolder.h"
 
 VCMI_LIB_NAMESPACE_BEGIN
 
 class CGHeroInstance;
 class CArmedInstance;
 
-struct DLL_LINKAGE SideInBattle
+struct DLL_LINKAGE SideInBattle : public GameCallbackHolder
 {
+	using GameCallbackHolder::GameCallbackHolder;
+
 	PlayerColor color = PlayerColor::CANNOT_DETERMINE;
-	const CGHeroInstance * hero = nullptr; //may be NULL if army is not commanded by hero
-	const CArmedInstance * armyObject = nullptr; //adv. map object with army that participates in battle; may be same as hero
+	ObjectInstanceID heroID; //may be empty if army is not commanded by hero
+	ObjectInstanceID armyObjectID; //adv. map object with army that participates in battle; may be same as hero
 
 	uint32_t castSpellsCount = 0; //how many spells each side has been cast this turn
 	std::vector<SpellID> usedSpellsHistory; //every time hero casts spell, it's inserted here -> eagle eye skill
 	int32_t enchanterCounter = 0; //tends to pass through 0, so sign is needed
 
 	void init(const CGHeroInstance * Hero, const CArmedInstance * Army);
-
+	const CArmedInstance * getArmy() const;
+	const CGHeroInstance * getHero() const;
 
 	template <typename Handler> void serialize(Handler &h)
 	{
 		h & color;
-		h & hero;
-		h & armyObject;
+		h & heroID;
+		h & armyObjectID;
 		h & castSpellsCount;
 		h & usedSpellsHistory;
 		h & enchanterCounter;

+ 1 - 1
server/battles/BattleProcessor.cpp

@@ -175,7 +175,7 @@ BattleID BattleProcessor::setupBattle(int3 tile, BattleSideArray<const CArmedIns
 
 	//send info about battles
 	BattleStart bs;
-	bs.info = BattleInfo::setupBattle(tile, terrain, battlefieldType, armies, heroes, layout, town);
+	bs.info = BattleInfo::setupBattle(gameHandler->gameState()->callback, tile, terrain, battlefieldType, armies, heroes, layout, town);
 	bs.battleID = gameHandler->gameState()->nextBattleID;
 
 	engageIntoBattle(bs.info->getSide(BattleSide::ATTACKER).color);

+ 1 - 1
test/game/CGameStateTest.cpp

@@ -200,7 +200,7 @@ public:
 
 		//send info about battles
 
-		auto battle = BattleInfo::setupBattle(tile, terrain, terType, armedInstancies, heroes, layout, nullptr);
+		auto battle = BattleInfo::setupBattle(gameState->callback, tile, terrain, terType, armedInstancies, heroes, layout, nullptr);
 
 		BattleStart bs;
 		bs.info = std::move(battle);