Browse Source

Optimize Unit::getHexes method

Ivan Savenko 9 months ago
parent
commit
3b35c679ce
5 changed files with 59 additions and 34 deletions
  1. 28 0
      lib/CStack.cpp
  2. 7 22
      lib/CStack.h
  3. 1 1
      lib/battle/CUnitState.h
  4. 21 11
      lib/battle/Unit.cpp
  5. 2 0
      lib/battle/Unit.h

+ 28 - 0
lib/CStack.cpp

@@ -35,6 +35,7 @@ CStack::CStack(const CStackInstance * Base, const PlayerColor & O, int I, Battle
 	side(Side)
 {
 	health.init(); //???
+	doubleWideCached = battle::CUnitState::doubleWide();
 }
 
 CStack::CStack():
@@ -55,6 +56,7 @@ CStack::CStack(const CStackBasicDescriptor * stack, const PlayerColor & O, int I
 	side(Side)
 {
 	health.init(); //???
+	doubleWideCached = battle::CUnitState::doubleWide();
 }
 
 void CStack::localInit(BattleInfo * battleInfo)
@@ -404,4 +406,30 @@ void CStack::spendMana(ServerCallback * server, const int spellCost) const
 	server->apply(ssp);
 }
 
+void CStack::postDeserialize(const CArmedInstance * army, const SlotID & extSlot)
+{
+	if(extSlot == SlotID::COMMANDER_SLOT_PLACEHOLDER)
+	{
+		const auto * hero = dynamic_cast<const CGHeroInstance *>(army);
+		assert(hero);
+		base = hero->commander;
+	}
+	else if(slot == SlotID::SUMMONED_SLOT_PLACEHOLDER || slot == SlotID::ARROW_TOWERS_SLOT || slot == SlotID::WAR_MACHINES_SLOT)
+	{
+		//no external slot possible, so no base stack
+		base = nullptr;
+	}
+	else if(!army || extSlot == SlotID() || !army->hasStackAtSlot(extSlot))
+	{
+		base = nullptr;
+		logGlobal->warn("%s doesn't have a base stack!", typeID.toEntity(VLC)->getNameSingularTranslated());
+	}
+	else
+	{
+		base = &army->getStack(extSlot);
+	}
+
+	doubleWideCached = battle::CUnitState::doubleWide();
+}
+
 VCMI_LIB_NAMESPACE_END

+ 7 - 22
lib/CStack.h

@@ -23,7 +23,7 @@ struct BattleStackAttacked;
 class BattleInfo;
 
 //Represents STACK_BATTLE nodes
-class DLL_LINKAGE CStack : public CBonusSystemNode, public battle::CUnitState, public battle::IUnitEnvironment
+class DLL_LINKAGE CStack final : public CBonusSystemNode, public battle::CUnitState, public battle::IUnitEnvironment
 {
 private:
 	ui32 ID = -1; //unique ID of stack
@@ -36,6 +36,9 @@ private:
 
 	SlotID slot;  //slot - position in garrison (may be 255 for neutrals/called creatures)
 
+	bool doubleWideCached = false;
+
+	void postDeserialize(const CArmedInstance * army, const SlotID & extSlot);
 public:
 	const CStackInstance * base = nullptr; //garrison slot from which stack originates (nullptr for war machines, summoned cres, etc)
 	
@@ -77,6 +80,7 @@ public:
 	BattleSide unitSide() const override;
 	PlayerColor unitOwner() const override;
 	SlotID unitSlot() const override;
+	bool doubleWide() const override { return doubleWideCached;};
 
 	std::string getDescription() const override;
 
@@ -119,26 +123,7 @@ public:
 			h & army;
 			h & extSlot;
 
-			if(extSlot == SlotID::COMMANDER_SLOT_PLACEHOLDER)
-			{
-				const auto * hero = dynamic_cast<const CGHeroInstance *>(army);
-				assert(hero);
-				base = hero->commander;
-			}
-			else if(slot == SlotID::SUMMONED_SLOT_PLACEHOLDER || slot == SlotID::ARROW_TOWERS_SLOT || slot == SlotID::WAR_MACHINES_SLOT)
-			{
-				//no external slot possible, so no base stack
-				base = nullptr;
-			}
-			else if(!army || extSlot == SlotID() || !army->hasStackAtSlot(extSlot))
-			{
-				base = nullptr;
-				logGlobal->warn("%s doesn't have a base stack!", typeID.toEntity(VLC)->getNameSingularTranslated());
-			}
-			else
-			{
-				base = &army->getStack(extSlot);
-			}
+			postDeserialize(army, extSlot);
 		}
 	}
 
@@ -146,4 +131,4 @@ private:
 	const BattleInfo * battle; //do not serialize
 };
 
-VCMI_LIB_NAMESPACE_END
+VCMI_LIB_NAMESPACE_END

+ 1 - 1
lib/battle/CUnitState.h

@@ -269,7 +269,7 @@ private:
 	void reset();
 };
 
-class DLL_LINKAGE CUnitStateDetached : public CUnitState
+class DLL_LINKAGE CUnitStateDetached final : public CUnitState
 {
 public:
 	explicit CUnitStateDetached(const IUnitInfo * unit_, const IBonusBearer * bonus_);

+ 21 - 11
lib/battle/Unit.cpp

@@ -107,24 +107,34 @@ const BattleHexArray & Unit::getHexes(BattleHex assumedPos) const
 	return getHexes(assumedPos, doubleWide(), unitSide());
 }
 
-const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side)
+BattleHexArray::ArrayOfBattleHexArrays Unit::precomputeUnitHexes(BattleSide side, bool twoHex)
 {
-	static BattleHexArray::ArrayOfBattleHexArrays precomputed[4];
-	int index = side == BattleSide::ATTACKER ? 0 : 2;
+	BattleHexArray::ArrayOfBattleHexArrays result;
 
-	if(!precomputed[index + twoHex][assumedPos.toInt()].empty())
-		return precomputed[index + twoHex][assumedPos.toInt()];
+	for (BattleHex assumedPos = 0; assumedPos < GameConstants::BFIELD_SIZE; ++assumedPos)
+	{
+		BattleHexArray hexes;
+		hexes.insert(assumedPos);
 
-	// first run, compute
+		if(twoHex)
+			hexes.insert(occupiedHex(assumedPos, twoHex, side));
 
-	BattleHexArray hexes;
-	hexes.insert(assumedPos);
+		result[assumedPos.toInt()] = std::move(hexes);
+	}
 
-	if(twoHex)
-		hexes.insert(occupiedHex(assumedPos, twoHex, side));
+	return result;
+}
 
-	precomputed[index + twoHex][assumedPos.toInt()] = std::move(hexes);
+const BattleHexArray & Unit::getHexes(BattleHex assumedPos, bool twoHex, BattleSide side)
+{
+	static const std::array<BattleHexArray::ArrayOfBattleHexArrays, 4> precomputed = {
+		precomputeUnitHexes(BattleSide::ATTACKER, false),
+		precomputeUnitHexes(BattleSide::ATTACKER, true),
+		precomputeUnitHexes(BattleSide::DEFENDER, false),
+		precomputeUnitHexes(BattleSide::DEFENDER, true),
+	};
 
+	int index = side == BattleSide::ATTACKER ? 0 : 2;
 	return precomputed[index + twoHex][assumedPos.toInt()];
 }
 

+ 2 - 0
lib/battle/Unit.h

@@ -64,6 +64,8 @@ class CUnitState;
 
 class DLL_LINKAGE Unit : public IUnitInfo, public spells::Caster, public virtual IBonusBearer, public ACreature
 {
+	static BattleHexArray::ArrayOfBattleHexArrays precomputeUnitHexes(BattleSide side, bool twoHex);
+
 public:
 	virtual ~Unit();