| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 | /* * BonusCache.h, part of VCMI engine * * Authors: listed in file AUTHORS in main folder * * License: GNU General Public License v2.0 or later * Full text of license available in license.txt file, in main folder * */#pragma once#include "BonusSelector.h"VCMI_LIB_NAMESPACE_BEGINenum class BonusCacheMode : int8_t{	VALUE, // total value of bonus will be cached	PRESENCE, // presence of bonus will be cached};/// Internal base class with no own cacheclass BonusCacheBase{protected:	const IBonusBearer * target;	explicit BonusCacheBase(const IBonusBearer * target):		target(target)	{}	struct BonusCacheEntry	{		std::atomic<int32_t> version = 0;		std::atomic<int32_t> value = 0;		BonusCacheEntry() = default;		BonusCacheEntry(const BonusCacheEntry & other)			: version(other.version.load())			, value(other.value.load())		{		}		BonusCacheEntry & operator =(const BonusCacheEntry & other)		{			version = other.version.load();			value = other.value.load();			return *this;		}	};	int getBonusValueImpl(BonusCacheEntry & currentValue, const CSelector & selector, BonusCacheMode) const;};/// Cache that tracks a single query to bonus systemclass BonusValueCache : public BonusCacheBase{	CSelector selector;	mutable BonusCacheEntry value;public:	BonusValueCache(const IBonusBearer * target, const CSelector & selector);	int getValue() const;	bool hasBonus() const;};/// Cache that can track a list of queries to bonus systemtemplate<size_t SIZE>class BonusValuesArrayCache : public BonusCacheBase{public:	using SelectorsArray = std::array<const CSelector, SIZE>;	BonusValuesArrayCache(const IBonusBearer * target, const SelectorsArray * selectors)		: BonusCacheBase(target)		, selectors(selectors)	{}	int getBonusValue(int index) const	{		return getBonusValueImpl(cache[index], (*selectors)[index], BonusCacheMode::VALUE);	}	int hasBonus(int index) const	{		return getBonusValueImpl(cache[index], (*selectors)[index], BonusCacheMode::PRESENCE);	}private:	using CacheArray = std::array<BonusCacheEntry, SIZE>;	const SelectorsArray * selectors;	mutable CacheArray cache;};class UnitBonusValuesProxy{public:	enum ECacheKeys : int8_t	{		TOTAL_ATTACKS_MELEE,		TOTAL_ATTACKS_RANGED,		MIN_DAMAGE_MELEE,		MIN_DAMAGE_RANGED,		MAX_DAMAGE_MELEE,		MAX_DAMAGE_RANGED,		ATTACK_MELEE,		ATTACK_RANGED,		DEFENCE_MELEE,		DEFENCE_RANGED,		IN_FRENZY,		HYPNOTIZED,		FORGETFULL,		HAS_FREE_SHOOTING,		STACK_HEALTH,		INVINCIBLE,		CLONE_MARKER,		TOTAL_KEYS,	};	static constexpr size_t KEYS_COUNT = static_cast<size_t>(ECacheKeys::TOTAL_KEYS);	using SelectorsArray = BonusValuesArrayCache<KEYS_COUNT>::SelectorsArray;	UnitBonusValuesProxy(const IBonusBearer * Target):		cache(Target, generateSelectors())	{}	int getBonusValue(ECacheKeys which) const	{		auto index = static_cast<size_t>(which);		return cache.getBonusValue(index);	}	int hasBonus(ECacheKeys which) const	{		auto index = static_cast<size_t>(which);		return cache.hasBonus(index);	}private:	const SelectorsArray * generateSelectors();	BonusValuesArrayCache<KEYS_COUNT> cache;};/// Cache that tracks values of primary skill values in bonus systemclass PrimarySkillsCache{	const IBonusBearer * target;	mutable std::atomic<int32_t> version = 0;	mutable std::array<std::atomic<int32_t>, 4> skills;	void update() const;public:	PrimarySkillsCache(const IBonusBearer * target);	const std::array<std::atomic<int32_t>, 4> & getSkills() const;	const std::atomic<int32_t> & getSkill(PrimarySkill id) const	{		return getSkills()[id.getNum()];	}};/// Cache that tracks values of spell school mastery in bonus systemclass MagicSchoolMasteryCache{	const IBonusBearer * target;	mutable std::atomic<int32_t> version = 0;	mutable std::vector<std::atomic<int32_t>> schools;	void update() const;public:	MagicSchoolMasteryCache(const IBonusBearer * target);	int32_t getMastery(const SpellSchool & school) const;};/// Cache that tracks values for different values of bonus durationclass BonusCachePerTurn : public BonusCacheBase{	static constexpr int cachedTurns = 8;	const CSelector selector;	mutable TConstBonusListPtr bonusList;	mutable std::mutex bonusListMutex;	mutable std::atomic<int32_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;};VCMI_LIB_NAMESPACE_END
 |