mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-10 22:31:40 +02:00
Replace global bonus tree change counter with per-node counter
This commit is contained in:
@@ -170,7 +170,7 @@ TConstBonusListPtr StackWithBonuses::getAllBonuses(const CSelector & selector, c
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t StackWithBonuses::getTreeVersion() const
|
int32_t StackWithBonuses::getTreeVersion() const
|
||||||
{
|
{
|
||||||
auto result = owner->getTreeVersion();
|
auto result = owner->getTreeVersion();
|
||||||
|
|
||||||
@@ -485,7 +485,7 @@ BattleLayout HypotheticBattle::getLayout() const
|
|||||||
return subject->getBattle()->getLayout();
|
return subject->getBattle()->getLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t HypotheticBattle::getTreeVersion() const
|
int32_t HypotheticBattle::getTreeVersion() const
|
||||||
{
|
{
|
||||||
return getBonusBearer()->getTreeVersion() + bonusTreeVersion;
|
return getBonusBearer()->getTreeVersion() + bonusTreeVersion;
|
||||||
}
|
}
|
||||||
|
@@ -93,7 +93,7 @@ public:
|
|||||||
TConstBonusListPtr getAllBonuses(const CSelector & selector, const CSelector & limit,
|
TConstBonusListPtr getAllBonuses(const CSelector & selector, const CSelector & limit,
|
||||||
const std::string & cachingStr = "") const override;
|
const std::string & cachingStr = "") const override;
|
||||||
|
|
||||||
int64_t getTreeVersion() const override;
|
int32_t getTreeVersion() const override;
|
||||||
|
|
||||||
void addUnitBonus(const std::vector<Bonus> & bonus);
|
void addUnitBonus(const std::vector<Bonus> & bonus);
|
||||||
void updateUnitBonus(const std::vector<Bonus> & bonus);
|
void updateUnitBonus(const std::vector<Bonus> & bonus);
|
||||||
@@ -162,7 +162,7 @@ public:
|
|||||||
int3 getLocation() const override;
|
int3 getLocation() const override;
|
||||||
BattleLayout getLayout() const override;
|
BattleLayout getLayout() const override;
|
||||||
|
|
||||||
int64_t getTreeVersion() const;
|
int32_t getTreeVersion() const;
|
||||||
|
|
||||||
void makeWait(const battle::Unit * activeStack);
|
void makeWait(const battle::Unit * activeStack);
|
||||||
|
|
||||||
|
@@ -703,8 +703,9 @@ void CArtHandler::afterLoadFinalization()
|
|||||||
assert(bonus->source == BonusSource::ARTIFACT);
|
assert(bonus->source == BonusSource::ARTIFACT);
|
||||||
bonus->sid = BonusSourceID(art->id);
|
bonus->sid = BonusSourceID(art->id);
|
||||||
}
|
}
|
||||||
|
art->nodeHasChanged();
|
||||||
}
|
}
|
||||||
CBonusSystemNode::treeHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
|
CArtifactInstance * CArtifactSet::getArt(const ArtifactPosition & pos, bool excludeLocked) const
|
||||||
|
@@ -693,7 +693,7 @@ void BattleInfo::moveUnit(uint32_t id, BattleHex destination)
|
|||||||
sta->position = destination;
|
sta->position = destination;
|
||||||
//Bonuses can be limited by unit placement, so, change tree version
|
//Bonuses can be limited by unit placement, so, change tree version
|
||||||
//to force updating a bonus. TODO: update version only when such bonuses are present
|
//to force updating a bonus. TODO: update version only when such bonuses are present
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BattleInfo::setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta)
|
void BattleInfo::setUnitState(uint32_t id, const JsonNode & data, int64_t healthDelta)
|
||||||
@@ -890,7 +890,7 @@ void BattleInfo::addOrUpdateUnitBonus(CStack * sta, const Bonus & value, bool fo
|
|||||||
stackBonus->turnsRemain = std::max(stackBonus->turnsRemain, value.turnsRemain);
|
stackBonus->turnsRemain = std::max(stackBonus->turnsRemain, value.turnsRemain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CBonusSystemNode::treeHasChanged();
|
sta->nodeHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -953,7 +953,7 @@ TConstBonusListPtr CUnitStateDetached::getAllBonuses(const CSelector & selector,
|
|||||||
return bonus->getAllBonuses(selector, limit, cachingStr);
|
return bonus->getAllBonuses(selector, limit, cachingStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t CUnitStateDetached::getTreeVersion() const
|
int32_t CUnitStateDetached::getTreeVersion() const
|
||||||
{
|
{
|
||||||
return bonus->getTreeVersion();
|
return bonus->getTreeVersion();
|
||||||
}
|
}
|
||||||
|
@@ -279,7 +279,7 @@ public:
|
|||||||
|
|
||||||
TConstBonusListPtr getAllBonuses(const CSelector & selector, const CSelector & limit, const std::string & cachingStr = "") const override;
|
TConstBonusListPtr getAllBonuses(const CSelector & selector, const CSelector & limit, const std::string & cachingStr = "") const override;
|
||||||
|
|
||||||
int64_t getTreeVersion() const override;
|
int32_t getTreeVersion() const override;
|
||||||
|
|
||||||
uint32_t unitId() const override;
|
uint32_t unitId() const override;
|
||||||
BattleSide unitSide() const override;
|
BattleSide unitSide() const override;
|
||||||
|
@@ -32,8 +32,8 @@ protected:
|
|||||||
|
|
||||||
struct BonusCacheEntry
|
struct BonusCacheEntry
|
||||||
{
|
{
|
||||||
std::atomic<int64_t> version = 0;
|
std::atomic<int32_t> version = 0;
|
||||||
std::atomic<int64_t> value = 0;
|
std::atomic<int32_t> value = 0;
|
||||||
|
|
||||||
BonusCacheEntry() = default;
|
BonusCacheEntry() = default;
|
||||||
BonusCacheEntry(const BonusCacheEntry & other)
|
BonusCacheEntry(const BonusCacheEntry & other)
|
||||||
@@ -152,7 +152,7 @@ private:
|
|||||||
class PrimarySkillsCache
|
class PrimarySkillsCache
|
||||||
{
|
{
|
||||||
const IBonusBearer * target;
|
const IBonusBearer * target;
|
||||||
mutable std::atomic<int64_t> version = 0;
|
mutable std::atomic<int32_t> version = 0;
|
||||||
mutable std::array<std::atomic<int32_t>, 4> skills;
|
mutable std::array<std::atomic<int32_t>, 4> skills;
|
||||||
|
|
||||||
void update() const;
|
void update() const;
|
||||||
@@ -166,7 +166,7 @@ public:
|
|||||||
class MagicSchoolMasteryCache
|
class MagicSchoolMasteryCache
|
||||||
{
|
{
|
||||||
const IBonusBearer * target;
|
const IBonusBearer * target;
|
||||||
mutable std::atomic<int64_t> version = 0;
|
mutable std::atomic<int32_t> version = 0;
|
||||||
mutable std::array<std::atomic<int32_t>, 4+1> schools;
|
mutable std::array<std::atomic<int32_t>, 4+1> schools;
|
||||||
|
|
||||||
void update() const;
|
void update() const;
|
||||||
@@ -184,7 +184,7 @@ class BonusCachePerTurn : public BonusCacheBase
|
|||||||
const CSelector selector;
|
const CSelector selector;
|
||||||
mutable TConstBonusListPtr bonusList;
|
mutable TConstBonusListPtr bonusList;
|
||||||
mutable std::mutex bonusListMutex;
|
mutable std::mutex bonusListMutex;
|
||||||
mutable std::atomic<int64_t> bonusListVersion = 0;
|
mutable std::atomic<int32_t> bonusListVersion = 0;
|
||||||
mutable std::array<BonusCacheEntry, cachedTurns> cache;
|
mutable std::array<BonusCacheEntry, cachedTurns> cache;
|
||||||
const BonusCacheMode mode;
|
const BonusCacheMode mode;
|
||||||
|
|
||||||
|
@@ -14,36 +14,6 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
BonusList::BonusList(bool BelongsToTree) : belongsToTree(BelongsToTree)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
BonusList::BonusList(const BonusList & bonusList): belongsToTree(false)
|
|
||||||
{
|
|
||||||
bonuses.resize(bonusList.size());
|
|
||||||
std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
|
|
||||||
}
|
|
||||||
|
|
||||||
BonusList::BonusList(BonusList && other) noexcept: belongsToTree(false)
|
|
||||||
{
|
|
||||||
std::swap(belongsToTree, other.belongsToTree);
|
|
||||||
std::swap(bonuses, other.bonuses);
|
|
||||||
}
|
|
||||||
|
|
||||||
BonusList& BonusList::operator=(const BonusList &bonusList)
|
|
||||||
{
|
|
||||||
bonuses.resize(bonusList.size());
|
|
||||||
std::copy(bonusList.begin(), bonusList.end(), bonuses.begin());
|
|
||||||
belongsToTree = false;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonusList::changed() const
|
|
||||||
{
|
|
||||||
if(belongsToTree)
|
|
||||||
CBonusSystemNode::treeHasChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void BonusList::stackBonuses()
|
void BonusList::stackBonuses()
|
||||||
{
|
{
|
||||||
boost::sort(bonuses, [](const std::shared_ptr<Bonus> & b1, const std::shared_ptr<Bonus> & b2) -> bool
|
boost::sort(bonuses, [](const std::shared_ptr<Bonus> & b1, const std::shared_ptr<Bonus> & b2) -> bool
|
||||||
@@ -228,19 +198,16 @@ JsonNode BonusList::toJsonNode() const
|
|||||||
void BonusList::push_back(const std::shared_ptr<Bonus> & x)
|
void BonusList::push_back(const std::shared_ptr<Bonus> & x)
|
||||||
{
|
{
|
||||||
bonuses.push_back(x);
|
bonuses.push_back(x);
|
||||||
changed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BonusList::TInternalContainer::iterator BonusList::erase(const int position)
|
BonusList::TInternalContainer::iterator BonusList::erase(const int position)
|
||||||
{
|
{
|
||||||
changed();
|
|
||||||
return bonuses.erase(bonuses.begin() + position);
|
return bonuses.erase(bonuses.begin() + position);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BonusList::clear()
|
void BonusList::clear()
|
||||||
{
|
{
|
||||||
bonuses.clear();
|
bonuses.clear();
|
||||||
changed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<BonusList *>::size_type BonusList::operator-=(const std::shared_ptr<Bonus> & i)
|
std::vector<BonusList *>::size_type BonusList::operator-=(const std::shared_ptr<Bonus> & i)
|
||||||
@@ -249,20 +216,17 @@ std::vector<BonusList *>::size_type BonusList::operator-=(const std::shared_ptr<
|
|||||||
if(itr == bonuses.end())
|
if(itr == bonuses.end())
|
||||||
return false;
|
return false;
|
||||||
bonuses.erase(itr);
|
bonuses.erase(itr);
|
||||||
changed();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BonusList::resize(BonusList::TInternalContainer::size_type sz, const std::shared_ptr<Bonus> & c)
|
void BonusList::resize(BonusList::TInternalContainer::size_type sz, const std::shared_ptr<Bonus> & c)
|
||||||
{
|
{
|
||||||
bonuses.resize(sz, c);
|
bonuses.resize(sz, c);
|
||||||
changed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusList::TInternalContainer::size_type n, const std::shared_ptr<Bonus> & x)
|
void BonusList::insert(BonusList::TInternalContainer::iterator position, BonusList::TInternalContainer::size_type n, const std::shared_ptr<Bonus> & x)
|
||||||
{
|
{
|
||||||
bonuses.insert(position, n, x);
|
bonuses.insert(position, n, x);
|
||||||
changed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
|
DLL_LINKAGE std::ostream & operator<<(std::ostream &out, const BonusList &bonusList)
|
||||||
|
@@ -21,8 +21,6 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
TInternalContainer bonuses;
|
TInternalContainer bonuses;
|
||||||
bool belongsToTree;
|
|
||||||
void changed() const;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using const_reference = TInternalContainer::const_reference;
|
using const_reference = TInternalContainer::const_reference;
|
||||||
@@ -31,10 +29,7 @@ public:
|
|||||||
using const_iterator = TInternalContainer::const_iterator;
|
using const_iterator = TInternalContainer::const_iterator;
|
||||||
using iterator = TInternalContainer::iterator;
|
using iterator = TInternalContainer::iterator;
|
||||||
|
|
||||||
BonusList(bool BelongsToTree = false);
|
BonusList() = default;
|
||||||
BonusList(const BonusList &bonusList);
|
|
||||||
BonusList(BonusList && other) noexcept;
|
|
||||||
BonusList& operator=(const BonusList &bonusList);
|
|
||||||
|
|
||||||
// wrapper functions of the STL vector container
|
// wrapper functions of the STL vector container
|
||||||
TInternalContainer::size_type size() const { return bonuses.size(); }
|
TInternalContainer::size_type size() const { return bonuses.size(); }
|
||||||
|
@@ -17,8 +17,7 @@
|
|||||||
|
|
||||||
VCMI_LIB_NAMESPACE_BEGIN
|
VCMI_LIB_NAMESPACE_BEGIN
|
||||||
|
|
||||||
std::atomic<int64_t> CBonusSystemNode::treeChanged(1);
|
constexpr bool cachingEnabled = true;
|
||||||
constexpr bool CBonusSystemNode::cachingEnabled = true;
|
|
||||||
|
|
||||||
std::shared_ptr<Bonus> CBonusSystemNode::getLocalBonus(const CSelector & selector)
|
std::shared_ptr<Bonus> CBonusSystemNode::getLocalBonus(const CSelector & selector)
|
||||||
{
|
{
|
||||||
@@ -97,11 +96,11 @@ void CBonusSystemNode::getAllBonusesRec(BonusList &out, const CSelector & select
|
|||||||
|
|
||||||
TConstBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr) const
|
TConstBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, const CSelector &limit, const std::string &cachingStr) const
|
||||||
{
|
{
|
||||||
if (CBonusSystemNode::cachingEnabled)
|
if (cachingEnabled)
|
||||||
{
|
{
|
||||||
// If a bonus system request comes with a caching string then look up in the map if there are any
|
// If a bonus system request comes with a caching string then look up in the map if there are any
|
||||||
// pre-calculated bonus results. Limiters can't be cached so they have to be calculated.
|
// pre-calculated bonus results. Limiters can't be cached so they have to be calculated.
|
||||||
if (cachedLast == treeChanged && !cachingStr.empty())
|
if (cachedLast == nodeChanged && !cachingStr.empty())
|
||||||
{
|
{
|
||||||
RequestsMap::const_accessor accessor;
|
RequestsMap::const_accessor accessor;
|
||||||
|
|
||||||
@@ -114,7 +113,7 @@ TConstBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, co
|
|||||||
//Perform bonus selection
|
//Perform bonus selection
|
||||||
auto ret = std::make_shared<BonusList>();
|
auto ret = std::make_shared<BonusList>();
|
||||||
|
|
||||||
if (cachedLast == treeChanged)
|
if (cachedLast == nodeChanged)
|
||||||
{
|
{
|
||||||
// Cached bonuses are up-to-date - use shared/read access and compute results
|
// Cached bonuses are up-to-date - use shared/read access and compute results
|
||||||
std::shared_lock lock(sync);
|
std::shared_lock lock(sync);
|
||||||
@@ -125,7 +124,7 @@ TConstBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, co
|
|||||||
// If the bonus system tree changes(state of a single node or the relations to each other) then
|
// If the bonus system tree changes(state of a single node or the relations to each other) then
|
||||||
// cache all bonus objects. Selector objects doesn't matter.
|
// cache all bonus objects. Selector objects doesn't matter.
|
||||||
std::lock_guard lock(sync);
|
std::lock_guard lock(sync);
|
||||||
if (cachedLast == treeChanged)
|
if (cachedLast == nodeChanged)
|
||||||
{
|
{
|
||||||
// While our thread was waiting, another one have updated bonus tree. Use cached bonuses.
|
// While our thread was waiting, another one have updated bonus tree. Use cached bonuses.
|
||||||
cachedBonuses.getBonuses(*ret, selector, limit);
|
cachedBonuses.getBonuses(*ret, selector, limit);
|
||||||
@@ -140,7 +139,7 @@ TConstBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, co
|
|||||||
getAllBonusesRec(allBonuses, Selector::all);
|
getAllBonusesRec(allBonuses, Selector::all);
|
||||||
limitBonuses(allBonuses, cachedBonuses);
|
limitBonuses(allBonuses, cachedBonuses);
|
||||||
cachedBonuses.stackBonuses();
|
cachedBonuses.stackBonuses();
|
||||||
cachedLast = treeChanged;
|
cachedLast = nodeChanged;
|
||||||
cachedBonuses.getBonuses(*ret, selector, limit);
|
cachedBonuses.getBonuses(*ret, selector, limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,7 +154,7 @@ TConstBonusListPtr CBonusSystemNode::getAllBonuses(const CSelector &selector, co
|
|||||||
accessor->second.first = cachedLast;
|
accessor->second.first = cachedLast;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cachedRequests.emplace(cachingStr, std::pair<int64_t, TBonusListPtr>{ cachedLast, ret });
|
cachedRequests.emplace(cachingStr, std::pair<int32_t, TBonusListPtr>{ cachedLast, ret });
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -187,8 +186,6 @@ std::shared_ptr<Bonus> CBonusSystemNode::getUpdatedBonus(const std::shared_ptr<B
|
|||||||
}
|
}
|
||||||
|
|
||||||
CBonusSystemNode::CBonusSystemNode(bool isHypotetic):
|
CBonusSystemNode::CBonusSystemNode(bool isHypotetic):
|
||||||
bonuses(true),
|
|
||||||
exportedBonuses(true),
|
|
||||||
nodeType(UNKNOWN),
|
nodeType(UNKNOWN),
|
||||||
cachedLast(0),
|
cachedLast(0),
|
||||||
isHypotheticNode(isHypotetic)
|
isHypotheticNode(isHypotetic)
|
||||||
@@ -196,8 +193,6 @@ CBonusSystemNode::CBonusSystemNode(bool isHypotetic):
|
|||||||
}
|
}
|
||||||
|
|
||||||
CBonusSystemNode::CBonusSystemNode(ENodeTypes NodeType):
|
CBonusSystemNode::CBonusSystemNode(ENodeTypes NodeType):
|
||||||
bonuses(true),
|
|
||||||
exportedBonuses(true),
|
|
||||||
nodeType(NodeType),
|
nodeType(NodeType),
|
||||||
cachedLast(0),
|
cachedLast(0),
|
||||||
isHypotheticNode(false)
|
isHypotheticNode(false)
|
||||||
@@ -227,10 +222,11 @@ void CBonusSystemNode::attachTo(CBonusSystemNode & parent)
|
|||||||
if(!parent.actsAsBonusSourceOnly())
|
if(!parent.actsAsBonusSourceOnly())
|
||||||
newRedDescendant(parent);
|
newRedDescendant(parent);
|
||||||
|
|
||||||
parent.newChildAttached(*this);
|
assert(!vstd::contains(parent.children, this));
|
||||||
|
parent.children.push_back(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::attachToSource(const CBonusSystemNode & parent)
|
void CBonusSystemNode::attachToSource(const CBonusSystemNode & parent)
|
||||||
@@ -244,7 +240,7 @@ void CBonusSystemNode::attachToSource(const CBonusSystemNode & parent)
|
|||||||
parent.newRedDescendant(*this);
|
parent.newRedDescendant(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
|
void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
|
||||||
@@ -271,9 +267,15 @@ void CBonusSystemNode::detachFrom(CBonusSystemNode & parent)
|
|||||||
|
|
||||||
if(!isHypothetic())
|
if(!isHypothetic())
|
||||||
{
|
{
|
||||||
parent.childDetached(*this);
|
if(vstd::contains(parent.children, this))
|
||||||
|
parent.children -= this;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logBonus->error("Error on Detach. Node %s (nodeType=%d) is not a child of %s (nodeType=%d)"
|
||||||
|
, nodeShortInfo(), nodeType, parent.nodeShortInfo(), parent.nodeType);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -297,7 +299,7 @@ void CBonusSystemNode::detachFromSource(const CBonusSystemNode & parent)
|
|||||||
, nodeShortInfo(), nodeType, parent.nodeShortInfo(), parent.nodeType);
|
, nodeShortInfo(), nodeType, parent.nodeShortInfo(), parent.nodeType);
|
||||||
}
|
}
|
||||||
|
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::removeBonusesRecursive(const CSelector & s)
|
void CBonusSystemNode::removeBonusesRecursive(const CSelector & s)
|
||||||
@@ -333,7 +335,6 @@ void CBonusSystemNode::addNewBonus(const std::shared_ptr<Bonus>& b)
|
|||||||
assert(!vstd::contains(exportedBonuses, b));
|
assert(!vstd::contains(exportedBonuses, b));
|
||||||
exportedBonuses.push_back(b);
|
exportedBonuses.push_back(b);
|
||||||
exportBonus(b);
|
exportBonus(b);
|
||||||
CBonusSystemNode::treeHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::accumulateBonus(const std::shared_ptr<Bonus>& b)
|
void CBonusSystemNode::accumulateBonus(const std::shared_ptr<Bonus>& b)
|
||||||
@@ -349,10 +350,14 @@ void CBonusSystemNode::removeBonus(const std::shared_ptr<Bonus>& b)
|
|||||||
{
|
{
|
||||||
exportedBonuses -= b;
|
exportedBonuses -= b;
|
||||||
if(b->propagator)
|
if(b->propagator)
|
||||||
|
{
|
||||||
unpropagateBonus(b);
|
unpropagateBonus(b);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
bonuses -= b;
|
bonuses -= b;
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::removeBonuses(const CSelector & selector)
|
void CBonusSystemNode::removeBonuses(const CSelector & selector)
|
||||||
@@ -385,6 +390,7 @@ void CBonusSystemNode::propagateBonus(const std::shared_ptr<Bonus> & b, const CB
|
|||||||
: b;
|
: b;
|
||||||
bonuses.push_back(propagated);
|
bonuses.push_back(propagated);
|
||||||
logBonus->trace("#$# %s #propagated to# %s", propagated->Description(nullptr), nodeName());
|
logBonus->trace("#$# %s #propagated to# %s", propagated->Description(nullptr), nodeName());
|
||||||
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
TNodes lchildren;
|
TNodes lchildren;
|
||||||
@@ -402,11 +408,11 @@ void CBonusSystemNode::unpropagateBonus(const std::shared_ptr<Bonus> & b)
|
|||||||
else
|
else
|
||||||
logBonus->warn("Attempt to remove #$# %s, which is not propagated to %s", b->Description(nullptr), nodeName());
|
logBonus->warn("Attempt to remove #$# %s, which is not propagated to %s", b->Description(nullptr), nodeName());
|
||||||
|
|
||||||
bonuses.remove_if([b](const auto & bonus)
|
bonuses.remove_if([this, b](const auto & bonus)
|
||||||
{
|
{
|
||||||
if (bonus->propagationUpdater && bonus->propagationUpdater == b->propagationUpdater)
|
if (bonus->propagationUpdater && bonus->propagationUpdater == b->propagationUpdater)
|
||||||
{
|
{
|
||||||
treeHasChanged();
|
nodeHasChanged();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -419,23 +425,6 @@ void CBonusSystemNode::unpropagateBonus(const std::shared_ptr<Bonus> & b)
|
|||||||
pname->unpropagateBonus(b);
|
pname->unpropagateBonus(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::newChildAttached(CBonusSystemNode & child)
|
|
||||||
{
|
|
||||||
assert(!vstd::contains(children, &child));
|
|
||||||
children.push_back(&child);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBonusSystemNode::childDetached(CBonusSystemNode & child)
|
|
||||||
{
|
|
||||||
if(vstd::contains(children, &child))
|
|
||||||
children -= &child;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
logBonus->error("Error on Detach. Node %s (nodeType=%d) is not a child of %s (nodeType=%d)"
|
|
||||||
, child.nodeShortInfo(), child.nodeType, nodeShortInfo(), nodeType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void CBonusSystemNode::detachFromAll()
|
void CBonusSystemNode::detachFromAll()
|
||||||
{
|
{
|
||||||
while(!parentsToPropagate.empty())
|
while(!parentsToPropagate.empty())
|
||||||
@@ -558,11 +547,14 @@ void CBonusSystemNode::getRedAncestors(TCNodes &out) const
|
|||||||
void CBonusSystemNode::exportBonus(const std::shared_ptr<Bonus> & b)
|
void CBonusSystemNode::exportBonus(const std::shared_ptr<Bonus> & b)
|
||||||
{
|
{
|
||||||
if(b->propagator)
|
if(b->propagator)
|
||||||
|
{
|
||||||
propagateBonus(b, *this);
|
propagateBonus(b, *this);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
bonuses.push_back(b);
|
bonuses.push_back(b);
|
||||||
|
nodeHasChanged();
|
||||||
CBonusSystemNode::treeHasChanged();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::exportBonuses()
|
void CBonusSystemNode::exportBonuses()
|
||||||
@@ -631,14 +623,27 @@ void CBonusSystemNode::limitBonuses(const BonusList &allBonuses, BonusList &out)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CBonusSystemNode::treeHasChanged()
|
void CBonusSystemNode::nodeHasChanged()
|
||||||
{
|
{
|
||||||
treeChanged++;
|
static std::atomic<int32_t> globalCounter = 1;
|
||||||
|
|
||||||
|
invalidateChildrenNodes(++globalCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t CBonusSystemNode::getTreeVersion() const
|
void CBonusSystemNode::invalidateChildrenNodes(int32_t changeCounter)
|
||||||
{
|
{
|
||||||
return treeChanged;
|
if (nodeChanged == changeCounter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
nodeChanged = changeCounter;
|
||||||
|
|
||||||
|
for(CBonusSystemNode * child : children)
|
||||||
|
child->invalidateChildrenNodes(changeCounter);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CBonusSystemNode::getTreeVersion() const
|
||||||
|
{
|
||||||
|
return nodeChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@@ -56,15 +56,16 @@ private:
|
|||||||
ENodeTypes nodeType;
|
ENodeTypes nodeType;
|
||||||
bool isHypotheticNode;
|
bool isHypotheticNode;
|
||||||
|
|
||||||
static const bool cachingEnabled;
|
|
||||||
mutable BonusList cachedBonuses;
|
mutable BonusList cachedBonuses;
|
||||||
mutable int64_t cachedLast;
|
mutable int32_t cachedLast;
|
||||||
static std::atomic<int64_t> treeChanged;
|
std::atomic<int32_t> nodeChanged;
|
||||||
|
|
||||||
|
void invalidateChildrenNodes(int32_t changeCounter);
|
||||||
|
|
||||||
// Setting a value to cachingStr before getting any bonuses caches the result for later requests.
|
// Setting a value to cachingStr before getting any bonuses caches the result for later requests.
|
||||||
// This string needs to be unique, that's why it has to be set in the following manner:
|
// This string needs to be unique, that's why it has to be set in the following manner:
|
||||||
// [property key]_[value] => only for selector
|
// [property key]_[value] => only for selector
|
||||||
using RequestsMap = tbb::concurrent_hash_map<std::string, std::pair<int64_t, TBonusListPtr>, HashStringCompare>;
|
using RequestsMap = tbb::concurrent_hash_map<std::string, std::pair<int32_t, TBonusListPtr>, HashStringCompare>;
|
||||||
mutable RequestsMap cachedRequests;
|
mutable RequestsMap cachedRequests;
|
||||||
mutable std::shared_mutex sync;
|
mutable std::shared_mutex sync;
|
||||||
|
|
||||||
@@ -79,8 +80,6 @@ private:
|
|||||||
|
|
||||||
void getAllParents(TCNodes & out) const;
|
void getAllParents(TCNodes & out) const;
|
||||||
|
|
||||||
void newChildAttached(CBonusSystemNode & child);
|
|
||||||
void childDetached(CBonusSystemNode & child);
|
|
||||||
void propagateBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & source);
|
void propagateBonus(const std::shared_ptr<Bonus> & b, const CBonusSystemNode & source);
|
||||||
void unpropagateBonus(const std::shared_ptr<Bonus> & b);
|
void unpropagateBonus(const std::shared_ptr<Bonus> & b);
|
||||||
bool actsAsBonusSourceOnly() const;
|
bool actsAsBonusSourceOnly() const;
|
||||||
@@ -136,9 +135,9 @@ public:
|
|||||||
void setNodeType(CBonusSystemNode::ENodeTypes type);
|
void setNodeType(CBonusSystemNode::ENodeTypes type);
|
||||||
const TCNodesVector & getParentNodes() const;
|
const TCNodesVector & getParentNodes() const;
|
||||||
|
|
||||||
static void treeHasChanged();
|
void nodeHasChanged();
|
||||||
|
|
||||||
int64_t getTreeVersion() const override;
|
int32_t getTreeVersion() const override;
|
||||||
|
|
||||||
virtual PlayerColor getOwner() const
|
virtual PlayerColor getOwner() const
|
||||||
{
|
{
|
||||||
|
@@ -41,7 +41,7 @@ public:
|
|||||||
TConstBonusListPtr getBonusesOfType(BonusType type) const;
|
TConstBonusListPtr getBonusesOfType(BonusType type) const;
|
||||||
TConstBonusListPtr getBonusesOfType(BonusType type, BonusSubtypeID subtype) const;
|
TConstBonusListPtr getBonusesOfType(BonusType type, BonusSubtypeID subtype) const;
|
||||||
|
|
||||||
virtual int64_t getTreeVersion() const = 0;
|
virtual int32_t getTreeVersion() const = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
VCMI_LIB_NAMESPACE_END
|
VCMI_LIB_NAMESPACE_END
|
||||||
|
@@ -115,7 +115,7 @@ void CArmedInstance::updateMoraleBonusFromArmy()
|
|||||||
|
|
||||||
b->description = bonusDescription;
|
b->description = bonusDescription;
|
||||||
|
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
|
|
||||||
//-1 modifier for any Undead unit in army
|
//-1 modifier for any Undead unit in army
|
||||||
auto undeadModifier = getExportedBonusList().getFirst(Selector::source(BonusSource::ARMY, BonusCustomSource::undeadMoraleDebuff));
|
auto undeadModifier = getExportedBonusList().getFirst(Selector::source(BonusSource::ARMY, BonusCustomSource::undeadMoraleDebuff));
|
||||||
|
@@ -1513,7 +1513,7 @@ void CGHeroInstance::setPrimarySkill(PrimarySkill primarySkill, si64 value, ui8
|
|||||||
{
|
{
|
||||||
skill->val += static_cast<si32>(value);
|
skill->val += static_cast<si32>(value);
|
||||||
}
|
}
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
else if(primarySkill == PrimarySkill::EXPERIENCE)
|
else if(primarySkill == PrimarySkill::EXPERIENCE)
|
||||||
{
|
{
|
||||||
@@ -1550,7 +1550,7 @@ void CGHeroInstance::levelUp(const std::vector<SecondarySkill> & skills)
|
|||||||
}
|
}
|
||||||
|
|
||||||
//update specialty and other bonuses that scale with level
|
//update specialty and other bonuses that scale with level
|
||||||
treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CGHeroInstance::levelUpAutomatically(vstd::RNG & rand)
|
void CGHeroInstance::levelUpAutomatically(vstd::RNG & rand)
|
||||||
|
@@ -730,7 +730,7 @@ void CGTownInstance::updateMoraleBonusFromArmy()
|
|||||||
if (garrisonHero)
|
if (garrisonHero)
|
||||||
{
|
{
|
||||||
b->val = 0;
|
b->val = 0;
|
||||||
CBonusSystemNode::treeHasChanged();
|
nodeHasChanged();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
CArmedInstance::updateMoraleBonusFromArmy();
|
CArmedInstance::updateMoraleBonusFromArmy();
|
||||||
|
@@ -901,6 +901,7 @@ void SetCommanderProperty::applyGs(CGameState *gs)
|
|||||||
break;
|
break;
|
||||||
case EXPERIENCE:
|
case EXPERIENCE:
|
||||||
commander->giveStackExp(amount); //TODO: allow setting exp for stacks via netpacks
|
commander->giveStackExp(amount); //TODO: allow setting exp for stacks via netpacks
|
||||||
|
commander->nodeHasChanged();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1708,7 +1709,9 @@ void RebalanceStacks::applyGs(CGameState *gs)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CBonusSystemNode::treeHasChanged();
|
srcObj->nodeHasChanged();
|
||||||
|
if (srcObj != dstObj)
|
||||||
|
dstObj->nodeHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void BulkRebalanceStacks::applyGs(CGameState *gs)
|
void BulkRebalanceStacks::applyGs(CGameState *gs)
|
||||||
@@ -2147,10 +2150,16 @@ void BattleResultAccepted::applyGs(CGameState *gs)
|
|||||||
if(gs->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
|
if(gs->getSettings().getBoolean(EGameSettings::MODULE_STACK_EXPERIENCE))
|
||||||
{
|
{
|
||||||
if(heroResult[BattleSide::ATTACKER].army)
|
if(heroResult[BattleSide::ATTACKER].army)
|
||||||
|
{
|
||||||
heroResult[BattleSide::ATTACKER].army->giveStackExp(heroResult[BattleSide::ATTACKER].exp);
|
heroResult[BattleSide::ATTACKER].army->giveStackExp(heroResult[BattleSide::ATTACKER].exp);
|
||||||
|
heroResult[BattleSide::ATTACKER].army->nodeHasChanged();
|
||||||
|
}
|
||||||
if(heroResult[BattleSide::DEFENDER].army)
|
if(heroResult[BattleSide::DEFENDER].army)
|
||||||
|
{
|
||||||
heroResult[BattleSide::DEFENDER].army->giveStackExp(heroResult[BattleSide::DEFENDER].exp);
|
heroResult[BattleSide::DEFENDER].army->giveStackExp(heroResult[BattleSide::DEFENDER].exp);
|
||||||
CBonusSystemNode::treeHasChanged();
|
heroResult[BattleSide::DEFENDER].army->nodeHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto currentBattle = boost::range::find_if(gs->currentBattles, [&](const auto & battle)
|
auto currentBattle = boost::range::find_if(gs->currentBattles, [&](const auto & battle)
|
||||||
|
@@ -378,7 +378,6 @@ void CGameHandler::giveExperience(const CGHeroInstance * hero, TExpType amountTo
|
|||||||
scp.which = SetCommanderProperty::EXPERIENCE;
|
scp.which = SetCommanderProperty::EXPERIENCE;
|
||||||
scp.amount = amountToGain;
|
scp.amount = amountToGain;
|
||||||
sendAndApply(scp);
|
sendAndApply(scp);
|
||||||
CBonusSystemNode::treeHasChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
expGiven(hero);
|
expGiven(hero);
|
||||||
|
@@ -38,7 +38,7 @@ TConstBonusListPtr BonusBearerMock::getAllBonuses(const CSelector & selector, co
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t BonusBearerMock::getTreeVersion() const
|
int32_t BonusBearerMock::getTreeVersion() const
|
||||||
{
|
{
|
||||||
return treeVersion;
|
return treeVersion;
|
||||||
}
|
}
|
||||||
|
@@ -25,10 +25,10 @@ public:
|
|||||||
|
|
||||||
TConstBonusListPtr getAllBonuses(const CSelector & selector, const CSelector & limit, const std::string & cachingStr = "") const override;
|
TConstBonusListPtr getAllBonuses(const CSelector & selector, const CSelector & limit, const std::string & cachingStr = "") const override;
|
||||||
|
|
||||||
int64_t getTreeVersion() const override;
|
int32_t getTreeVersion() const override;
|
||||||
private:
|
private:
|
||||||
mutable BonusList bonuses;
|
mutable BonusList bonuses;
|
||||||
|
|
||||||
mutable int64_t cachedLast;
|
mutable int32_t cachedLast;
|
||||||
int32_t treeVersion;
|
int32_t treeVersion;
|
||||||
};
|
};
|
||||||
|
@@ -16,7 +16,7 @@ class UnitMock : public battle::Unit
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
MOCK_CONST_METHOD3(getAllBonuses, TConstBonusListPtr(const CSelector &, const CSelector &, const std::string &));
|
MOCK_CONST_METHOD3(getAllBonuses, TConstBonusListPtr(const CSelector &, const CSelector &, const std::string &));
|
||||||
MOCK_CONST_METHOD0(getTreeVersion, int64_t());
|
MOCK_CONST_METHOD0(getTreeVersion, int32_t());
|
||||||
|
|
||||||
MOCK_CONST_METHOD0(getCasterUnitId, int32_t());
|
MOCK_CONST_METHOD0(getCasterUnitId, int32_t());
|
||||||
MOCK_CONST_METHOD2(getSpellSchoolLevel, int32_t(const spells::Spell *, SpellSchool *));
|
MOCK_CONST_METHOD2(getSpellSchoolLevel, int32_t(const spells::Spell *, SpellSchool *));
|
||||||
|
Reference in New Issue
Block a user