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;
|
int heroChainTurn;
|
||||||
std::vector<CGPathNode *> heroChain;
|
std::vector<CGPathNode *> heroChain;
|
||||||
const std::vector<int3> & tiles;
|
const std::vector<int3> & tiles;
|
||||||
|
std::vector<DelayedWork> delayedWork;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
HeroChainCalculationTask(
|
HeroChainCalculationTask(
|
||||||
AINodeStorage & storage, AISharedStorage & nodes, const std::vector<int3> & tiles, uint64_t chainMask, int heroChainTurn)
|
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);
|
existingChains.reserve(NUM_CHAINS);
|
||||||
newChains.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);
|
cleanupInefectiveChains(newChains);
|
||||||
addHeroChain(newChains);
|
addHeroChain(newChains);
|
||||||
}
|
}
|
||||||
@ -483,11 +500,34 @@ bool AINodeStorage::calculateHeroChain()
|
|||||||
|
|
||||||
CCreature::DisableChildLinkage = true;
|
CCreature::DisableChildLinkage = true;
|
||||||
|
|
||||||
auto r = blocked_range<size_t>(0, data.size());
|
if(data.size() > 100)
|
||||||
HeroChainCalculationTask task(*this, nodes, data, chainMask, heroChainTurn);
|
{
|
||||||
|
std::mutex resultMutex;
|
||||||
|
|
||||||
task.execute(r);
|
std::random_shuffle(data.begin(), data.end());
|
||||||
task.flushResult(heroChain);
|
|
||||||
|
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;
|
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
|
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;
|
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)
|
if(specialActor == this)
|
||||||
return result;
|
return result;
|
||||||
@ -184,7 +184,9 @@ ChainActor * HeroActor::tryExchange(const ChainActor * specialActor, const Chain
|
|||||||
return &actor == specialActor;
|
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)
|
HeroExchangeMap::HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai)
|
||||||
@ -205,40 +207,67 @@ HeroExchangeMap::~HeroExchangeMap()
|
|||||||
exchangeMap.clear();
|
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
|
#if PATHFINDER_TRACE_LEVEL >= 2
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"Can not afford exchange because of total cost %s but we have %s",
|
"Can not afford exchange because of total cost %s but we have %s",
|
||||||
(actor->armyCost + other->armyCost).toString(),
|
(actor->armyCost + other->armyCost).toString(),
|
||||||
resources.toString());
|
resources.toString());
|
||||||
#endif
|
#endif
|
||||||
return nullptr;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(other->isMovable && other->armyValue <= actor->armyValue / 10 && other->armyValue < MIN_ARMY_STRENGTH_FOR_CHAIN)
|
if(other->isMovable && other->armyValue <= actor->armyValue / 10 && other->armyValue < MIN_ARMY_STRENGTH_FOR_CHAIN)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -247,52 +276,54 @@ HeroActor * HeroExchangeMap::tryExchange(const ChainActor * other)
|
|||||||
HeroExchangeArmy * upgradedInitialArmy = tryUpgrade(actor->creatureSet, other->getActorObject(), availableResources);
|
HeroExchangeArmy * upgradedInitialArmy = tryUpgrade(actor->creatureSet, other->getActorObject(), availableResources);
|
||||||
HeroExchangeArmy * newArmy;
|
HeroExchangeArmy * newArmy;
|
||||||
|
|
||||||
if(other->creatureSet->Slots().size())
|
if(other->creatureSet->Slots().size())
|
||||||
{
|
|
||||||
if(upgradedInitialArmy)
|
|
||||||
{
|
{
|
||||||
newArmy = pickBestCreatures(upgradedInitialArmy, other->creatureSet);
|
if(upgradedInitialArmy)
|
||||||
newArmy->armyCost = upgradedInitialArmy->armyCost;
|
{
|
||||||
newArmy->requireBuyArmy = upgradedInitialArmy->requireBuyArmy;
|
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
|
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
|
#if PATHFINDER_TRACE_LEVEL >= 2
|
||||||
logAi->trace(
|
logAi->trace(
|
||||||
"Exchange %s->%s reinforcement: %d, %f%%",
|
"Exchange %s->%s reinforcement: %d, %f%%",
|
||||||
actor->toString(),
|
actor->toString(),
|
||||||
other->toString(),
|
other->toString(),
|
||||||
reinforcement,
|
reinforcement,
|
||||||
100.0f * reinforcement / actor->armyValue);
|
100.0f * reinforcement / actor->armyValue);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(reinforcement <= actor->armyValue / 10 && reinforcement < MIN_ARMY_STRENGTH_FOR_CHAIN)
|
if(reinforcement <= actor->armyValue / 10 && reinforcement < MIN_ARMY_STRENGTH_FOR_CHAIN)
|
||||||
{
|
{
|
||||||
delete newArmy;
|
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(
|
HeroExchangeArmy * HeroExchangeMap::tryUpgrade(
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
extern const uint64_t MIN_ARMY_STRENGTH_FOR_CHAIN;
|
extern const uint64_t MIN_ARMY_STRENGTH_FOR_CHAIN;
|
||||||
|
|
||||||
|
class ChainActor;
|
||||||
class HeroActor;
|
class HeroActor;
|
||||||
class Nullkiller;
|
class Nullkiller;
|
||||||
|
|
||||||
@ -33,6 +34,14 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ExchangeResult
|
||||||
|
{
|
||||||
|
bool lockAcquired;
|
||||||
|
ChainActor * actor;
|
||||||
|
|
||||||
|
ExchangeResult() : lockAcquired(true), actor(nullptr) {}
|
||||||
|
};
|
||||||
|
|
||||||
class ChainActor
|
class ChainActor
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
@ -68,12 +77,12 @@ public:
|
|||||||
ChainActor(){}
|
ChainActor(){}
|
||||||
|
|
||||||
virtual std::string toString() const;
|
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);
|
void setBaseActor(HeroActor * base);
|
||||||
virtual const CGObjectInstance * getActorObject() const { return hero; }
|
virtual const CGObjectInstance * getActorObject() const { return hero; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ChainActor * tryExchange(const ChainActor * specialActor, const ChainActor * other) const;
|
virtual ExchangeResult tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
class HeroExchangeMap
|
class HeroExchangeMap
|
||||||
@ -88,7 +97,7 @@ public:
|
|||||||
HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai);
|
HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai);
|
||||||
~HeroExchangeMap();
|
~HeroExchangeMap();
|
||||||
|
|
||||||
HeroActor * tryExchange(const ChainActor * other);
|
ExchangeResult tryExchangeNoLock(const ChainActor * other);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HeroExchangeArmy * pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const;
|
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);
|
HeroActor(const ChainActor * carrier, const ChainActor * other, const HeroExchangeArmy * army, const Nullkiller * ai);
|
||||||
|
|
||||||
protected:
|
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
|
class ObjectActor : public ChainActor
|
||||||
|
Loading…
x
Reference in New Issue
Block a user