mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
Caching of bonuses that are requested with different durations
This commit is contained in:
@@ -23,8 +23,8 @@ class DLL_LINKAGE ACreature: public AFactionMember
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool isLiving() const; //non-undead, non-non living or alive
|
bool isLiving() const; //non-undead, non-non living or alive
|
||||||
ui32 getMovementRange(int turn) const; //get speed (in moving tiles) of creature with all modificators
|
virtual ui32 getMovementRange(int turn) const; //get speed (in moving tiles) of creature with all modificators
|
||||||
ui32 getMovementRange() const; //get speed (in moving tiles) of creature with all modificators
|
virtual ui32 getMovementRange() const; //get speed (in moving tiles) of creature with all modificators
|
||||||
virtual ui32 getMaxHealth() const; //get max HP of stack with all modifiers
|
virtual ui32 getMaxHealth() const; //get max HP of stack with all modifiers
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -333,6 +333,8 @@ CUnitState::CUnitState():
|
|||||||
counterAttacks(this),
|
counterAttacks(this),
|
||||||
health(this),
|
health(this),
|
||||||
shots(this),
|
shots(this),
|
||||||
|
stackSpeedPerTurn(this, Selector::type()(BonusType::STACKS_SPEED), BonusCacheMode::VALUE),
|
||||||
|
immobilizedPerTurn(this, Selector::type()(BonusType::SIEGE_WEAPON).Or(Selector::type()(BonusType::BIND_EFFECT)), BonusCacheMode::PRESENCE),
|
||||||
bonusCache(this, generateBonusSelectors()),
|
bonusCache(this, generateBonusSelectors()),
|
||||||
cloneLifetimeMarker(this, Selector::type()(BonusType::NONE).And(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(SpellID(SpellID::CLONE)))), "CUnitState::cloneLifetimeMarker"),
|
cloneLifetimeMarker(this, Selector::type()(BonusType::NONE).And(Selector::source(BonusSource::SPELL_EFFECT, BonusSourceID(SpellID(SpellID::CLONE)))), "CUnitState::cloneLifetimeMarker"),
|
||||||
cloneID(-1)
|
cloneID(-1)
|
||||||
@@ -573,11 +575,20 @@ void CUnitState::setPosition(BattleHex hex)
|
|||||||
|
|
||||||
int32_t CUnitState::getInitiative(int turn) const
|
int32_t CUnitState::getInitiative(int turn) const
|
||||||
{
|
{
|
||||||
if (turn == 0)
|
return stackSpeedPerTurn.getValue(turn);
|
||||||
return valOfBonuses(BonusType::STACKS_SPEED);
|
}
|
||||||
|
|
||||||
std::string cachingStr = "type_STACKS_SPEED_turns_" + std::to_string(turn);
|
ui32 CUnitState::getMovementRange(int turn) const
|
||||||
return valOfBonuses(Selector::type()(BonusType::STACKS_SPEED).And(Selector::turns(turn)), cachingStr);
|
{
|
||||||
|
if (immobilizedPerTurn.getValue(0) != 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return stackSpeedPerTurn.getValue(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui32 CUnitState::getMovementRange() const
|
||||||
|
{
|
||||||
|
return getMovementRange(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CUnitState::getRangedFullDamageDistance() const
|
uint8_t CUnitState::getRangedFullDamageDistance() const
|
||||||
|
@@ -248,6 +248,9 @@ public:
|
|||||||
uint8_t getRangedFullDamageDistance() const;
|
uint8_t getRangedFullDamageDistance() const;
|
||||||
uint8_t getShootingRangeDistance() const;
|
uint8_t getShootingRangeDistance() const;
|
||||||
|
|
||||||
|
ui32 getMovementRange(int turn) const override;
|
||||||
|
ui32 getMovementRange() const override;
|
||||||
|
|
||||||
bool canMove(int turn = 0) const override;
|
bool canMove(int turn = 0) const override;
|
||||||
bool defended(int turn = 0) const override;
|
bool defended(int turn = 0) const override;
|
||||||
bool moved(int turn = 0) const override;
|
bool moved(int turn = 0) const override;
|
||||||
@@ -293,6 +296,8 @@ private:
|
|||||||
|
|
||||||
const IUnitEnvironment * env;
|
const IUnitEnvironment * env;
|
||||||
|
|
||||||
|
BonusCachePerTurn immobilizedPerTurn;
|
||||||
|
BonusCachePerTurn stackSpeedPerTurn;
|
||||||
UnitBonusValuesProxy bonusCache;
|
UnitBonusValuesProxy bonusCache;
|
||||||
CCheckProxy cloneLifetimeMarker;
|
CCheckProxy cloneLifetimeMarker;
|
||||||
|
|
||||||
|
@@ -79,3 +79,59 @@ const std::array<std::atomic<int32_t>, 4> & PrimarySkillsCache::getSkills() cons
|
|||||||
update();
|
update();
|
||||||
return skills;
|
return skills;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int BonusCachePerTurn::getValueUncached(int turns) const
|
||||||
|
{
|
||||||
|
std::lock_guard lock(bonusListMutex);
|
||||||
|
|
||||||
|
int nodeTreeVersion = target->getTreeVersion();
|
||||||
|
|
||||||
|
if (bonusListVersion != nodeTreeVersion)
|
||||||
|
{
|
||||||
|
bonusList = target->getBonuses(selector);
|
||||||
|
bonusListVersion = nodeTreeVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode == BonusCacheMode::VALUE)
|
||||||
|
{
|
||||||
|
if (turns != 0)
|
||||||
|
return bonusList->valOfBonuses(Selector::turns(turns));
|
||||||
|
else
|
||||||
|
return bonusList->totalValue();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (turns != 0)
|
||||||
|
return bonusList->getFirst(Selector::turns(turns)) != nullptr;
|
||||||
|
else
|
||||||
|
return !bonusList->empty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int BonusCachePerTurn::getValue(int turns) const
|
||||||
|
{
|
||||||
|
int nodeTreeVersion = target->getTreeVersion();
|
||||||
|
|
||||||
|
if (turns < cachedTurns)
|
||||||
|
{
|
||||||
|
auto & entry = cache[turns];
|
||||||
|
if (entry.version == nodeTreeVersion)
|
||||||
|
{
|
||||||
|
// best case: value is in cache and up-to-date
|
||||||
|
return entry.value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// else - compute value and update it in the cache
|
||||||
|
int newValue = getValueUncached(turns);
|
||||||
|
entry.value = newValue;
|
||||||
|
entry.version = nodeTreeVersion;
|
||||||
|
return newValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// non-cacheable value - compute and return (should be 0 / close to 0 calls)
|
||||||
|
return getValueUncached(turns);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -12,12 +12,18 @@
|
|||||||
|
|
||||||
#include "BonusSelector.h"
|
#include "BonusSelector.h"
|
||||||
|
|
||||||
|
enum class BonusCacheMode
|
||||||
|
{
|
||||||
|
VALUE, // total value of bonus will be cached
|
||||||
|
PRESENCE, // presence of bonus will be cached
|
||||||
|
};
|
||||||
|
|
||||||
/// Internal base class with no own cache
|
/// Internal base class with no own cache
|
||||||
class BonusCacheBase
|
class BonusCacheBase
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
const IBonusBearer * target;
|
const IBonusBearer * target;
|
||||||
|
|
||||||
protected:
|
|
||||||
explicit BonusCacheBase(const IBonusBearer * target):
|
explicit BonusCacheBase(const IBonusBearer * target):
|
||||||
target(target)
|
target(target)
|
||||||
{}
|
{}
|
||||||
@@ -79,3 +85,26 @@ public:
|
|||||||
|
|
||||||
const std::array<std::atomic<int32_t>, 4> & getSkills() const;
|
const std::array<std::atomic<int32_t>, 4> & getSkills() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Cache that tracks values for different values of bonus duration
|
||||||
|
class BonusCachePerTurn : public BonusCacheBase
|
||||||
|
{
|
||||||
|
static constexpr int cachedTurns = 8;
|
||||||
|
|
||||||
|
const CSelector selector;
|
||||||
|
mutable TConstBonusListPtr bonusList;
|
||||||
|
mutable std::mutex bonusListMutex;
|
||||||
|
mutable std::atomic<int64_t> bonusListVersion = 0;
|
||||||
|
mutable std::array<BonusCacheEntry, cachedTurns> cache;
|
||||||
|
const BonusCacheMode mode;
|
||||||
|
|
||||||
|
int getValueUncached(int turns) const;
|
||||||
|
public:
|
||||||
|
BonusCachePerTurn(const IBonusBearer * target, const CSelector & selector, BonusCacheMode mode)
|
||||||
|
: BonusCacheBase(target)
|
||||||
|
, selector(selector)
|
||||||
|
, mode(mode)
|
||||||
|
{}
|
||||||
|
|
||||||
|
int getValue(int turns) const;
|
||||||
|
};
|
||||||
|
Reference in New Issue
Block a user