mirror of
https://github.com/vcmi/vcmi.git
synced 2025-01-26 03:52:01 +02:00
Nullkiller: async hero chain calculation
This commit is contained in:
parent
0265de77fa
commit
66843b22d3
@ -401,11 +401,12 @@ private:
|
||||
int heroChainTurn;
|
||||
std::vector<CGPathNode *> heroChain;
|
||||
const std::vector<int3> & tiles;
|
||||
std::vector<DelayedWork> delayedWork;
|
||||
|
||||
public:
|
||||
HeroChainCalculationTask(
|
||||
AINodeStorage & storage, AISharedStorage & nodes, const std::vector<int3> & tiles, uint64_t chainMask, int heroChainTurn)
|
||||
:existingChains(), newChains(), nodes(nodes), storage(storage), chainMask(chainMask), heroChainTurn(heroChainTurn), heroChain(), tiles(tiles)
|
||||
:existingChains(), newChains(), delayedWork(), nodes(nodes), storage(storage), chainMask(chainMask), heroChainTurn(heroChainTurn), heroChain(), tiles(tiles)
|
||||
{
|
||||
existingChains.reserve(NUM_CHAINS);
|
||||
newChains.reserve(NUM_CHAINS);
|
||||
@ -444,6 +445,22 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
for(auto delayed = delayedWork.begin(); delayed != delayedWork.end();)
|
||||
{
|
||||
auto newActor = delayed->carrier->actor->tryExchangeNoLock(delayed->other->actor);
|
||||
|
||||
if(!newActor.lockAcquired) continue;
|
||||
|
||||
if(newActor.actor)
|
||||
{
|
||||
newChains.push_back(calculateExchange(newActor.actor, delayed->carrier, delayed->other));
|
||||
}
|
||||
|
||||
delayed++;
|
||||
}
|
||||
|
||||
delayedWork.clear();
|
||||
|
||||
cleanupInefectiveChains(newChains);
|
||||
addHeroChain(newChains);
|
||||
}
|
||||
@ -483,11 +500,34 @@ bool AINodeStorage::calculateHeroChain()
|
||||
|
||||
CCreature::DisableChildLinkage = true;
|
||||
|
||||
auto r = blocked_range<size_t>(0, data.size());
|
||||
HeroChainCalculationTask task(*this, nodes, data, chainMask, heroChainTurn);
|
||||
if(data.size() > 100)
|
||||
{
|
||||
std::mutex resultMutex;
|
||||
|
||||
task.execute(r);
|
||||
task.flushResult(heroChain);
|
||||
std::random_shuffle(data.begin(), data.end());
|
||||
|
||||
parallel_for(blocked_range<size_t>(0, data.size()), [&](const blocked_range<size_t>& r)
|
||||
{
|
||||
//auto r = blocked_range<size_t>(0, data.size());
|
||||
HeroChainCalculationTask task(*this, nodes, data, chainMask, heroChainTurn);
|
||||
|
||||
task.execute(r);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> resultLock(resultMutex);
|
||||
|
||||
task.flushResult(heroChain);
|
||||
}
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
auto r = blocked_range<size_t>(0, data.size());
|
||||
HeroChainCalculationTask task(*this, nodes, data, chainMask, heroChainTurn);
|
||||
|
||||
task.execute(r);
|
||||
task.flushResult(heroChain);\
|
||||
}
|
||||
|
||||
CCreature::DisableChildLinkage = false;
|
||||
|
||||
@ -666,9 +706,10 @@ void HeroChainCalculationTask::calculateHeroChain(
|
||||
}
|
||||
}
|
||||
|
||||
auto newActor = carrier->actor->tryExchange(other->actor);
|
||||
auto newActor = carrier->actor->tryExchangeNoLock(other->actor);
|
||||
|
||||
if(newActor) result.push_back(calculateExchange(newActor, carrier, other));
|
||||
if(!newActor.lockAcquired) delayedWork.push_back(DelayedWork(carrier, other));
|
||||
if(newActor.actor) result.push_back(calculateExchange(newActor.actor, carrier, other));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,11 +145,11 @@ void HeroActor::setupSpecialActors()
|
||||
}
|
||||
}
|
||||
|
||||
ChainActor * ChainActor::tryExchange(const ChainActor * specialActor, const ChainActor * other) const
|
||||
ExchangeResult ChainActor::tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const
|
||||
{
|
||||
if(!isMovable) return nullptr;
|
||||
if(!isMovable) return ExchangeResult();
|
||||
|
||||
return baseActor->tryExchange(specialActor, other);
|
||||
return baseActor->tryExchangeNoLock(specialActor, other);
|
||||
}
|
||||
|
||||
namespace vstd
|
||||
@ -169,12 +169,12 @@ namespace vstd
|
||||
}
|
||||
}
|
||||
|
||||
ChainActor * HeroActor::tryExchange(const ChainActor * specialActor, const ChainActor * other) const
|
||||
ExchangeResult HeroActor::tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const
|
||||
{
|
||||
const ChainActor * otherBase = other->baseActor;
|
||||
HeroActor * result = exchangeMap->tryExchange(otherBase);
|
||||
ExchangeResult result = exchangeMap->tryExchangeNoLock(otherBase);
|
||||
|
||||
if(!result) return nullptr;
|
||||
if(!result.actor || !result.lockAcquired) return result;
|
||||
|
||||
if(specialActor == this)
|
||||
return result;
|
||||
@ -184,7 +184,9 @@ ChainActor * HeroActor::tryExchange(const ChainActor * specialActor, const Chain
|
||||
return &actor == specialActor;
|
||||
});
|
||||
|
||||
return &result->specialActors[index];
|
||||
result.actor = &(dynamic_cast<HeroActor *>(result.actor)->specialActors[index]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HeroExchangeMap::HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai)
|
||||
@ -205,40 +207,67 @@ HeroExchangeMap::~HeroExchangeMap()
|
||||
exchangeMap.clear();
|
||||
}
|
||||
|
||||
HeroActor * HeroExchangeMap::tryExchange(const ChainActor * other)
|
||||
ExchangeResult HeroExchangeMap::tryExchangeNoLock(const ChainActor * other)
|
||||
{
|
||||
auto position = exchangeMap.find(other);
|
||||
ExchangeResult result;
|
||||
|
||||
if(position != exchangeMap.end())
|
||||
{
|
||||
return position->second;
|
||||
boost::shared_lock<boost::shared_mutex> lock(sync, boost::try_to_lock);
|
||||
|
||||
if(!lock.owns_lock())
|
||||
{
|
||||
result.lockAcquired = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto position = exchangeMap.find(other);
|
||||
|
||||
if(position != exchangeMap.end())
|
||||
{
|
||||
result.actor = position->second;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
auto inserted = exchangeMap.insert(std::pair<const ChainActor *, HeroActor *>(other, nullptr));
|
||||
|
||||
if(!inserted.second)
|
||||
{
|
||||
return inserted.first->second; // already inserted
|
||||
}
|
||||
boost::unique_lock<boost::shared_mutex> uniqueLock(sync, boost::try_to_lock);
|
||||
|
||||
position = inserted.first;
|
||||
if(!uniqueLock.owns_lock())
|
||||
{
|
||||
result.lockAcquired = false;
|
||||
|
||||
auto differentMasks = (actor->chainMask & other->chainMask) == 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
if(!differentMasks) return nullptr;
|
||||
auto inserted = exchangeMap.insert(std::pair<const ChainActor *, HeroActor *>(other, nullptr));
|
||||
|
||||
TResources resources = ai->cb->getResourceAmount();
|
||||
if(!inserted.second)
|
||||
{
|
||||
result.actor = inserted.first->second;
|
||||
|
||||
if(!resources.canAfford(actor->armyCost + other->armyCost))
|
||||
{
|
||||
return result; // already inserted
|
||||
}
|
||||
|
||||
auto position = inserted.first;
|
||||
|
||||
auto differentMasks = (actor->chainMask & other->chainMask) == 0;
|
||||
|
||||
if(!differentMasks) return result;
|
||||
|
||||
TResources resources = ai->cb->getResourceAmount();
|
||||
|
||||
if(!resources.canAfford(actor->armyCost + other->armyCost))
|
||||
{
|
||||
#if PATHFINDER_TRACE_LEVEL >= 2
|
||||
logAi->trace(
|
||||
"Can not afford exchange because of total cost %s but we have %s",
|
||||
(actor->armyCost + other->armyCost).toString(),
|
||||
resources.toString());
|
||||
logAi->trace(
|
||||
"Can not afford exchange because of total cost %s but we have %s",
|
||||
(actor->armyCost + other->armyCost).toString(),
|
||||
resources.toString());
|
||||
#endif
|
||||
return nullptr;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if(other->isMovable && other->armyValue <= actor->armyValue / 10 && other->armyValue < MIN_ARMY_STRENGTH_FOR_CHAIN)
|
||||
return nullptr;
|
||||
@ -247,52 +276,54 @@ HeroActor * HeroExchangeMap::tryExchange(const ChainActor * other)
|
||||
HeroExchangeArmy * upgradedInitialArmy = tryUpgrade(actor->creatureSet, other->getActorObject(), availableResources);
|
||||
HeroExchangeArmy * newArmy;
|
||||
|
||||
if(other->creatureSet->Slots().size())
|
||||
{
|
||||
if(upgradedInitialArmy)
|
||||
if(other->creatureSet->Slots().size())
|
||||
{
|
||||
newArmy = pickBestCreatures(upgradedInitialArmy, other->creatureSet);
|
||||
newArmy->armyCost = upgradedInitialArmy->armyCost;
|
||||
newArmy->requireBuyArmy = upgradedInitialArmy->requireBuyArmy;
|
||||
if(upgradedInitialArmy)
|
||||
{
|
||||
newArmy = pickBestCreatures(upgradedInitialArmy, other->creatureSet);
|
||||
newArmy->armyCost = upgradedInitialArmy->armyCost;
|
||||
newArmy->requireBuyArmy = upgradedInitialArmy->requireBuyArmy;
|
||||
|
||||
delete upgradedInitialArmy;
|
||||
delete upgradedInitialArmy;
|
||||
}
|
||||
else
|
||||
{
|
||||
newArmy = pickBestCreatures(actor->creatureSet, other->creatureSet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newArmy = pickBestCreatures(actor->creatureSet, other->creatureSet);
|
||||
newArmy = upgradedInitialArmy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newArmy = upgradedInitialArmy;
|
||||
}
|
||||
|
||||
if(!newArmy) return nullptr;
|
||||
if(!newArmy) return result;
|
||||
|
||||
auto reinforcement = newArmy->getArmyStrength() - actor->creatureSet->getArmyStrength();
|
||||
auto reinforcement = newArmy->getArmyStrength() - actor->creatureSet->getArmyStrength();
|
||||
|
||||
#if PATHFINDER_TRACE_LEVEL >= 2
|
||||
logAi->trace(
|
||||
"Exchange %s->%s reinforcement: %d, %f%%",
|
||||
actor->toString(),
|
||||
other->toString(),
|
||||
reinforcement,
|
||||
100.0f * reinforcement / actor->armyValue);
|
||||
logAi->trace(
|
||||
"Exchange %s->%s reinforcement: %d, %f%%",
|
||||
actor->toString(),
|
||||
other->toString(),
|
||||
reinforcement,
|
||||
100.0f * reinforcement / actor->armyValue);
|
||||
#endif
|
||||
|
||||
if(reinforcement <= actor->armyValue / 10 && reinforcement < MIN_ARMY_STRENGTH_FOR_CHAIN)
|
||||
{
|
||||
delete newArmy;
|
||||
|
||||
return nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
HeroActor * exchanged = new HeroActor(actor, other, newArmy, ai);
|
||||
|
||||
exchanged->armyCost += newArmy->armyCost;
|
||||
result.actor = exchanged;
|
||||
exchangeMap[other] = exchanged;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
HeroActor * exchanged = new HeroActor(actor, other, newArmy, ai);
|
||||
|
||||
exchanged->armyCost += newArmy->armyCost;
|
||||
position->second = exchanged;
|
||||
|
||||
return exchanged;
|
||||
}
|
||||
|
||||
HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
extern const uint64_t MIN_ARMY_STRENGTH_FOR_CHAIN;
|
||||
|
||||
class ChainActor;
|
||||
class HeroActor;
|
||||
class Nullkiller;
|
||||
|
||||
@ -33,6 +34,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct ExchangeResult
|
||||
{
|
||||
bool lockAcquired;
|
||||
ChainActor * actor;
|
||||
|
||||
ExchangeResult() : lockAcquired(true), actor(nullptr) {}
|
||||
};
|
||||
|
||||
class ChainActor
|
||||
{
|
||||
protected:
|
||||
@ -68,12 +77,12 @@ public:
|
||||
ChainActor(){}
|
||||
|
||||
virtual std::string toString() const;
|
||||
ChainActor * tryExchange(const ChainActor * other) const { return tryExchange(this, other); }
|
||||
ExchangeResult tryExchangeNoLock(const ChainActor * other) const { return tryExchangeNoLock(this, other); }
|
||||
void setBaseActor(HeroActor * base);
|
||||
virtual const CGObjectInstance * getActorObject() const { return hero; }
|
||||
|
||||
protected:
|
||||
virtual ChainActor * tryExchange(const ChainActor * specialActor, const ChainActor * other) const;
|
||||
virtual ExchangeResult tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const;
|
||||
};
|
||||
|
||||
class HeroExchangeMap
|
||||
@ -88,7 +97,7 @@ public:
|
||||
HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai);
|
||||
~HeroExchangeMap();
|
||||
|
||||
HeroActor * tryExchange(const ChainActor * other);
|
||||
ExchangeResult tryExchangeNoLock(const ChainActor * other);
|
||||
|
||||
private:
|
||||
HeroExchangeArmy * pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const;
|
||||
@ -114,7 +123,7 @@ public:
|
||||
HeroActor(const ChainActor * carrier, const ChainActor * other, const HeroExchangeArmy * army, const Nullkiller * ai);
|
||||
|
||||
protected:
|
||||
virtual ChainActor * tryExchange(const ChainActor * specialActor, const ChainActor * other) const override;
|
||||
virtual ExchangeResult tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const override;
|
||||
};
|
||||
|
||||
class ObjectActor : public ChainActor
|
||||
|
Loading…
x
Reference in New Issue
Block a user