| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 | 
							- /*
 
-  * CBonusProxy.cpp, 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
 
-  *
 
-  */
 
- #include "StdInc.h"
 
- #include "BonusList.h"
 
- #include "CBonusProxy.h"
 
- #include "IBonusBearer.h"
 
- VCMI_LIB_NAMESPACE_BEGIN
 
- ///CBonusProxy
 
- CBonusProxy::CBonusProxy(const IBonusBearer * Target, CSelector Selector):
 
- 	bonusListCachedLast(0),
 
- 	target(Target),
 
- 	selector(std::move(Selector)),
 
- 	currentBonusListIndex(0)
 
- {
 
- }
 
- CBonusProxy::CBonusProxy(const CBonusProxy & other):
 
- 	bonusListCachedLast(other.bonusListCachedLast),
 
- 	target(other.target),
 
- 	selector(other.selector),
 
- 	currentBonusListIndex(other.currentBonusListIndex)
 
- {
 
- 	bonusList[currentBonusListIndex] = other.bonusList[currentBonusListIndex];
 
- }
 
- CBonusProxy::CBonusProxy(CBonusProxy && other) noexcept:
 
- 	bonusListCachedLast(0),
 
- 	target(other.target),
 
- 	currentBonusListIndex(0)
 
- {
 
- 	std::swap(bonusListCachedLast, other.bonusListCachedLast);
 
- 	std::swap(selector, other.selector);
 
- 	std::swap(bonusList, other.bonusList);
 
- 	std::swap(currentBonusListIndex, other.currentBonusListIndex);
 
- }
 
- CBonusProxy & CBonusProxy::operator=(const CBonusProxy & other)
 
- {
 
- 	boost::lock_guard<boost::mutex> lock(swapGuard);
 
- 	selector = other.selector;
 
- 	swapBonusList(other.bonusList[other.currentBonusListIndex]);
 
- 	bonusListCachedLast = other.bonusListCachedLast;
 
- 	return *this;
 
- }
 
- CBonusProxy & CBonusProxy::operator=(CBonusProxy && other) noexcept
 
- {
 
- 	std::swap(bonusListCachedLast, other.bonusListCachedLast);
 
- 	std::swap(selector, other.selector);
 
- 	std::swap(bonusList, other.bonusList);
 
- 	std::swap(currentBonusListIndex, other.currentBonusListIndex);
 
- 	return *this;
 
- }
 
- void CBonusProxy::swapBonusList(TConstBonusListPtr other) const
 
- {
 
- 	// The idea here is to avoid changing active bonusList while it can be read by a different thread.
 
- 	// Because such use of shared ptr is not thread safe
 
- 	// So to avoid this we change the second offline instance and swap active index
 
- 	auto newCurrent = 1 - currentBonusListIndex;
 
- 	bonusList[newCurrent] = std::move(other);
 
- 	currentBonusListIndex = newCurrent;
 
- }
 
- TConstBonusListPtr CBonusProxy::getBonusList() const
 
- {
 
- 	auto needUpdateBonusList = [&]() -> bool
 
- 	{
 
- 		return target->getTreeVersion() != bonusListCachedLast || !bonusList[currentBonusListIndex];
 
- 	};
 
- 	// avoid locking if everything is up-to-date
 
- 	if(needUpdateBonusList())
 
- 	{
 
- 		boost::lock_guard<boost::mutex>lock(swapGuard);
 
- 		if(needUpdateBonusList())
 
- 		{
 
- 			//TODO: support limiters
 
- 			swapBonusList(target->getAllBonuses(selector, Selector::all));
 
- 			bonusListCachedLast = target->getTreeVersion();
 
- 		}
 
- 	}
 
- 	return bonusList[currentBonusListIndex];
 
- }
 
- const BonusList * CBonusProxy::operator->() const
 
- {
 
- 	return getBonusList().get();
 
- }
 
- CTotalsProxy::CTotalsProxy(const IBonusBearer * Target, CSelector Selector, int InitialValue):
 
- 	CBonusProxy(Target, std::move(Selector)),
 
- 	initialValue(InitialValue),
 
- 	meleeCachedLast(0),
 
- 	meleeValue(0),
 
- 	rangedCachedLast(0),
 
- 	rangedValue(0)
 
- {
 
- }
 
- CTotalsProxy::CTotalsProxy(const CTotalsProxy & other)
 
- 	: CBonusProxy(other),
 
- 	initialValue(other.initialValue),
 
- 	meleeCachedLast(other.meleeCachedLast),
 
- 	meleeValue(other.meleeValue),
 
- 	rangedCachedLast(other.rangedCachedLast),
 
- 	rangedValue(other.rangedValue)
 
- {
 
- }
 
- int CTotalsProxy::getValue() const
 
- {
 
- 	const auto treeVersion = target->getTreeVersion();
 
- 	if(treeVersion != valueCachedLast)
 
- 	{
 
- 		auto bonuses = getBonusList();
 
- 		value = initialValue + bonuses->totalValue();
 
- 		valueCachedLast = treeVersion;
 
- 	}
 
- 	return value;
 
- }
 
- int CTotalsProxy::getValueAndList(TConstBonusListPtr & outBonusList) const
 
- {
 
- 	const auto treeVersion = target->getTreeVersion();
 
- 	outBonusList = getBonusList();
 
- 	if(treeVersion != valueCachedLast)
 
- 	{
 
- 		value = initialValue + outBonusList->totalValue();
 
- 		valueCachedLast = treeVersion;
 
- 	}
 
- 	return value;
 
- }
 
- int CTotalsProxy::getMeleeValue() const
 
- {
 
- 	static const auto limit = Selector::effectRange()(BonusLimitEffect::NO_LIMIT).Or(Selector::effectRange()(BonusLimitEffect::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()(BonusLimitEffect::NO_LIMIT).Or(Selector::effectRange()(BonusLimitEffect::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(std::move(Selector)),
 
- 	cachedLast(0),
 
- 	hasBonus(false)
 
- {
 
- }
 
- //This constructor should be placed here to avoid side effects
 
- CCheckProxy::CCheckProxy(const CCheckProxy & other) = default;
 
- bool CCheckProxy::getHasBonus() const
 
- {
 
- 	const auto treeVersion = target->getTreeVersion();
 
- 	if(treeVersion != cachedLast)
 
- 	{
 
- 		hasBonus = target->hasBonus(selector);
 
- 		cachedLast = treeVersion;
 
- 	}
 
- 	return hasBonus;
 
- }
 
- VCMI_LIB_NAMESPACE_END
 
 
  |