1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-26 22:57:00 +02:00

hacks to optimize a few bonus requests

This commit is contained in:
Andrii Danylchenko 2020-06-28 16:19:27 +03:00
parent cc75b859d4
commit d782ee39df
6 changed files with 200 additions and 141 deletions

View File

@ -152,6 +152,120 @@ const BonusList * CBonusProxy::operator->() const
return get().get(); return get().get();
} }
CTotalsProxy::CTotalsProxy(const IBonusBearer * Target, CSelector Selector, int InitialValue)
: target(Target),
selector(Selector),
initialValue(InitialValue),
meleeCachedLast(0),
meleeValue(0),
rangedCachedLast(0),
rangedValue(0),
value(0),
cachedLast(0)
{
}
CTotalsProxy::CTotalsProxy(const CTotalsProxy & other)
: target(other.target),
selector(other.selector),
initialValue(other.initialValue),
meleeCachedLast(other.meleeCachedLast),
meleeValue(other.meleeValue),
rangedCachedLast(other.rangedCachedLast),
rangedValue(other.rangedValue)
{
}
CTotalsProxy & CTotalsProxy::operator=(const CTotalsProxy & other)
{
initialValue = other.initialValue;
meleeCachedLast = other.meleeCachedLast;
meleeValue = other.meleeValue;
rangedCachedLast = other.rangedCachedLast;
rangedValue = other.rangedValue;
value = other.value;
cachedLast = other.cachedLast;
return *this;
}
int CTotalsProxy::getValue() const
{
const auto treeVersion = target->getTreeVersion();
if(treeVersion != cachedLast)
{
auto bonuses = target->getBonuses(selector);
value = initialValue + bonuses->totalValue();
cachedLast = treeVersion;
}
return value;
}
int CTotalsProxy::getMeleeValue() const
{
static const auto limit = Selector::effectRange(Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_MELEE_FIGHT));
const auto treeVersion = target->getTreeVersion();
if(treeVersion != meleeCachedLast)
{
auto bonuses = target->getBonuses(selector, limit);
meleeValue = initialValue + bonuses->totalValue();
meleeCachedLast = treeVersion;
}
return meleeValue;
}
int CTotalsProxy::getRangedValue() const
{
static const auto limit = Selector::effectRange(Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT));
const auto treeVersion = target->getTreeVersion();
if(treeVersion != rangedCachedLast)
{
auto bonuses = target->getBonuses(selector, limit);
rangedValue = initialValue + bonuses->totalValue();
rangedCachedLast = treeVersion;
}
return rangedValue;
}
///CCheckProxy
CCheckProxy::CCheckProxy(const IBonusBearer * Target, CSelector Selector)
: target(Target),
selector(Selector),
cachedLast(0),
hasBonus(false)
{
}
CCheckProxy::CCheckProxy(const CCheckProxy & other)
: target(other.target),
selector(other.selector),
cachedLast(other.cachedLast),
hasBonus(other.hasBonus)
{
}
bool CCheckProxy::getHasBonus() const
{
const auto treeVersion = target->getTreeVersion();
if(treeVersion != cachedLast)
{
hasBonus = target->hasBonus(selector);
cachedLast = treeVersion;
}
return hasBonus;
}
CAddInfo::CAddInfo() CAddInfo::CAddInfo()
{ {
} }
@ -467,6 +581,22 @@ void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusLi
changed(); changed();
} }
CSelector IBonusBearer::anaffectedByMoraleSelector
= Selector::type(Bonus::NON_LIVING)
.Or(Selector::type(Bonus::UNDEAD))
.Or(Selector::type(Bonus::NO_MORALE))
.Or(Selector::type(Bonus::SIEGE_WEAPON));
CSelector IBonusBearer::moraleSelector = Selector::type(Bonus::MORALE);
CSelector IBonusBearer::selfMoraleSelector = Selector::type(Bonus::SELF_MORALE);
IBonusBearer::IBonusBearer()
:anaffectedByMorale(this, anaffectedByMoraleSelector),
moraleValue(this, moraleSelector, 0),
selfMorale(this, selfMoraleSelector)
{
}
int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const int IBonusBearer::valOfBonuses(Bonus::BonusType type, const CSelector &selector) const
{ {
return valOfBonuses(Selector::type(type).And(selector)); return valOfBonuses(Selector::type(type).And(selector));
@ -532,13 +662,12 @@ bool IBonusBearer::hasBonusFrom(Bonus::BonusSource source, ui32 sourceID) const
int IBonusBearer::MoraleVal() const int IBonusBearer::MoraleVal() const
{ {
if(hasBonusOfType(Bonus::NON_LIVING) || hasBonusOfType(Bonus::UNDEAD) || if(anaffectedByMorale.getHasBonus())
hasBonusOfType(Bonus::NO_MORALE) || hasBonusOfType(Bonus::SIEGE_WEAPON))
return 0; return 0;
int ret = valOfBonuses(Bonus::MORALE); int ret = moraleValue.getValue();
if(hasBonusOfType(Bonus::SELF_MORALE)) //eg. minotaur if(selfMorale.getHasBonus()) //eg. minotaur
vstd::amax(ret, +1); vstd::amax(ret, +1);
return vstd::abetween(ret, -3, +3); return vstd::abetween(ret, -3, +3);

View File

@ -87,6 +87,51 @@ private:
mutable TBonusListPtr data; mutable TBonusListPtr data;
}; };
class DLL_LINKAGE CTotalsProxy
{
public:
CTotalsProxy(const IBonusBearer * Target, CSelector Selector, int InitialValue);
CTotalsProxy(const CTotalsProxy & other);
CTotalsProxy(CTotalsProxy && other) = delete;
CTotalsProxy & operator=(const CTotalsProxy & other);
CTotalsProxy & operator=(CTotalsProxy && other) = delete;
int getMeleeValue() const;
int getRangedValue() const;
int getValue() const;
private:
const IBonusBearer * target;
CSelector selector;
int initialValue;
mutable int64_t cachedLast;
mutable int value;
mutable int64_t meleeCachedLast;
mutable int meleeValue;
mutable int64_t rangedCachedLast;
mutable int rangedValue;
};
class DLL_LINKAGE CCheckProxy
{
public:
CCheckProxy(const IBonusBearer * Target, CSelector Selector);
CCheckProxy(const CCheckProxy & other);
bool getHasBonus() const;
private:
const IBonusBearer * target;
CSelector selector;
mutable int64_t cachedLast;
mutable bool hasBonus;
};
class DLL_LINKAGE CAddInfo : public std::vector<si32> class DLL_LINKAGE CAddInfo : public std::vector<si32>
{ {
public: public:
@ -641,11 +686,20 @@ public:
class DLL_LINKAGE IBonusBearer class DLL_LINKAGE IBonusBearer
{ {
private:
static CSelector anaffectedByMoraleSelector;
CCheckProxy anaffectedByMorale;
static CSelector moraleSelector;
CTotalsProxy moraleValue;
static CSelector selfMoraleSelector;
CCheckProxy selfMorale;
public: public:
//new bonusing node interface //new bonusing node interface
// * selector is predicate that tests if HeroBonus matches our criteria // * selector is predicate that tests if HeroBonus matches our criteria
// * root is node on which call was made (nullptr will be replaced with this) // * root is node on which call was made (nullptr will be replaced with this)
//interface //interface
IBonusBearer();
virtual const TBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr, const std::string &cachingStr = "") const = 0; virtual const TBonusListPtr getAllBonuses(const CSelector &selector, const CSelector &limit, const CBonusSystemNode *root = nullptr, const std::string &cachingStr = "") const = 0;
int valOfBonuses(const CSelector &selector, const std::string &cachingStr = "") const; int valOfBonuses(const CSelector &selector, const std::string &cachingStr = "") const;
bool hasBonus(const CSelector &selector, const std::string &cachingStr = "") const; bool hasBonus(const CSelector &selector, const std::string &cachingStr = "") const;

View File

@ -19,99 +19,6 @@
namespace battle namespace battle
{ {
CTotalsProxy::CTotalsProxy(const IBonusBearer * Target, CSelector Selector, int InitialValue)
: target(Target),
selector(Selector),
initialValue(InitialValue),
meleeCachedLast(0),
meleeValue(0),
rangedCachedLast(0),
rangedValue(0)
{
}
CTotalsProxy::CTotalsProxy(const CTotalsProxy & other)
: target(other.target),
selector(other.selector),
initialValue(other.initialValue),
meleeCachedLast(other.meleeCachedLast),
meleeValue(other.meleeValue),
rangedCachedLast(other.rangedCachedLast),
rangedValue(other.rangedValue)
{
}
CTotalsProxy & CTotalsProxy::operator=(const CTotalsProxy & other)
{
initialValue = other.initialValue;
meleeCachedLast = other.meleeCachedLast;
meleeValue = other.meleeValue;
rangedCachedLast = other.rangedCachedLast;
rangedValue = other.rangedValue;
return *this;
}
int CTotalsProxy::getMeleeValue() const
{
static const auto limit = Selector::effectRange(Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_MELEE_FIGHT));
const auto treeVersion = target->getTreeVersion();
if(treeVersion != meleeCachedLast)
{
auto bonuses = target->getBonuses(selector, limit);
meleeValue = initialValue + bonuses->totalValue();
meleeCachedLast = treeVersion;
}
return meleeValue;
}
int CTotalsProxy::getRangedValue() const
{
static const auto limit = Selector::effectRange(Bonus::NO_LIMIT).Or(Selector::effectRange(Bonus::ONLY_DISTANCE_FIGHT));
const auto treeVersion = target->getTreeVersion();
if(treeVersion != rangedCachedLast)
{
auto bonuses = target->getBonuses(selector, limit);
rangedValue = initialValue + bonuses->totalValue();
rangedCachedLast = treeVersion;
}
return rangedValue;
}
///CCheckProxy
CCheckProxy::CCheckProxy(const IBonusBearer * Target, CSelector Selector)
: target(Target),
selector(Selector),
cachedLast(0),
hasBonus(false)
{
}
CCheckProxy::CCheckProxy(const CCheckProxy & other)
: target(other.target),
selector(other.selector),
cachedLast(other.cachedLast),
hasBonus(other.hasBonus)
{
}
bool CCheckProxy::getHasBonus() const
{
const auto treeVersion = target->getTreeVersion();
if(treeVersion != cachedLast)
{
hasBonus = target->hasBonus(selector);
cachedLast = treeVersion;
}
return hasBonus;
}
///CAmmo ///CAmmo
CAmmo::CAmmo(const battle::Unit * Owner, CSelector totalSelector) CAmmo::CAmmo(const battle::Unit * Owner, CSelector totalSelector)
: used(0), : used(0),

View File

@ -24,47 +24,6 @@ namespace battle
{ {
class CUnitState; class CUnitState;
class DLL_LINKAGE CTotalsProxy
{
public:
CTotalsProxy(const IBonusBearer * Target, CSelector Selector, int InitialValue);
CTotalsProxy(const CTotalsProxy & other);
CTotalsProxy(CTotalsProxy && other) = delete;
CTotalsProxy & operator=(const CTotalsProxy & other);
CTotalsProxy & operator=(CTotalsProxy && other) = delete;
int getMeleeValue() const;
int getRangedValue() const;
private:
const IBonusBearer * target;
CSelector selector;
int initialValue;
mutable int64_t meleeCachedLast;
mutable int meleeValue;
mutable int64_t rangedCachedLast;
mutable int rangedValue;
};
class DLL_LINKAGE CCheckProxy
{
public:
CCheckProxy(const IBonusBearer * Target, CSelector Selector);
CCheckProxy(const CCheckProxy & other);
bool getHasBonus() const;
private:
const IBonusBearer * target;
CSelector selector;
mutable int64_t cachedLast;
mutable bool hasBonus;
};
class DLL_LINKAGE CAmmo class DLL_LINKAGE CAmmo
{ {
public: public:

View File

@ -36,7 +36,11 @@ void CArmedInstance::randomizeArmy(int type)
return; return;
} }
// Take Angelic Alliance troop-mixing freedom of non-evil units into account.
CSelector CArmedInstance::nonEvilAlignmentMixSelector = Selector::type(Bonus::NONEVIL_ALIGNMENT_MIX);
CArmedInstance::CArmedInstance() CArmedInstance::CArmedInstance()
:nonEvilAlignmentMix(this, nonEvilAlignmentMixSelector)
{ {
battle = nullptr; battle = nullptr;
} }
@ -57,6 +61,9 @@ void CArmedInstance::updateMoraleBonusFromArmy()
std::set<TFaction> factions; std::set<TFaction> factions;
bool hasUndead = false; bool hasUndead = false;
const std::string undeadCacheKey = "type_UNDEAD";
static const CSelector undeadSelector = Selector::type(Bonus::UNDEAD);
for(auto slot : Slots()) for(auto slot : Slots())
{ {
const CStackInstance * inst = slot.second; const CStackInstance * inst = slot.second;
@ -64,13 +71,12 @@ void CArmedInstance::updateMoraleBonusFromArmy()
factions.insert(creature->faction); factions.insert(creature->faction);
// Check for undead flag instead of faction (undead mummies are neutral) // Check for undead flag instead of faction (undead mummies are neutral)
hasUndead |= inst->hasBonusOfType(Bonus::UNDEAD); hasUndead |= inst->hasBonus(undeadSelector, undeadCacheKey);
} }
size_t factionsInArmy = factions.size(); //town garrison seems to take both sets into account size_t factionsInArmy = factions.size(); //town garrison seems to take both sets into account
// Take Angelic Alliance troop-mixing freedom of non-evil units into account. if (nonEvilAlignmentMix.getHasBonus())
if (hasBonusOfType(Bonus::NONEVIL_ALIGNMENT_MIX))
{ {
size_t mixableFactions = 0; size_t mixableFactions = 0;

View File

@ -17,6 +17,10 @@ class CGameState;
class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet class DLL_LINKAGE CArmedInstance: public CGObjectInstance, public CBonusSystemNode, public CCreatureSet
{ {
private:
CCheckProxy nonEvilAlignmentMix;
static CSelector nonEvilAlignmentMixSelector;
public: public:
BattleInfo *battle; //set to the current battle, if engaged BattleInfo *battle; //set to the current battle, if engaged