1
0
mirror of https://github.com/vcmi/vcmi.git synced 2024-12-24 22:14:36 +02:00

NKAI: fix potential concurrency and town treat calculation

This commit is contained in:
Andrii Danylchenko 2023-08-06 08:57:14 +03:00
parent b9e804954d
commit a4297ebdf6
2 changed files with 48 additions and 29 deletions

View File

@ -53,6 +53,13 @@ void DangerHitMapAnalyzer::updateHitMap()
}
}
auto ourTowns = cb->getTownsInfo();
for(auto town : ourTowns)
{
townTreats[town->id]; // insert empty list
}
foreach_tile_pos([&](const int3 & pos){
hitMap[pos.x][pos.y][pos.z].reset();
});
@ -95,33 +102,33 @@ void DangerHitMapAnalyzer::updateHitMap()
node.fastestDanger = newTreat;
}
if(newTreat.turn == 0)
auto objects = cb->getVisitableObjs(pos, false);
for(auto obj : objects)
{
auto objects = cb->getVisitableObjs(pos, false);
for(auto obj : objects)
if(obj->ID == Obj::TOWN && obj->getOwner() == ai->playerID)
{
if(cb->getPlayerRelations(obj->tempOwner, ai->playerID) != PlayerRelations::ENEMIES)
enemyHeroAccessibleObjects[path.targetHero].insert(obj);
auto & treats = townTreats[obj->id];
auto treat = std::find_if(treats.begin(), treats.end(), [&](const HitMapInfo & i) -> bool
{
return i.hero.hid == path.targetHero->id;
});
if(obj->ID == Obj::TOWN && obj->getOwner() == ai->playerID)
if(treat == treats.end())
{
auto & treats = townTreats[obj->id];
auto treat = std::find_if(treats.begin(), treats.end(), [&](const HitMapInfo & i) -> bool
{
return i.hero.hid == path.targetHero->id;
});
treats.emplace_back();
treat = std::prev(treats.end(), 1);
}
if(treat == treats.end())
{
treats.emplace_back();
treat = std::prev(treats.end(), 1);
}
if(newTreat.value() > treat->value())
{
*treat = newTreat;
}
if(newTreat.value() > treat->value())
{
*treat = newTreat;
}
if(newTreat.turn == 0)
{
if(cb->getPlayerRelations(obj->tempOwner, ai->playerID) != PlayerRelations::ENEMIES)
enemyHeroAccessibleObjects.emplace_back(path.targetHero, obj);
}
}
}
@ -274,16 +281,17 @@ const HitMapNode & DangerHitMapAnalyzer::getTileTreat(const int3 & tile) const
const std::set<const CGObjectInstance *> empty = {};
const std::set<const CGObjectInstance *> & DangerHitMapAnalyzer::getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const
std::set<const CGObjectInstance *> DangerHitMapAnalyzer::getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const
{
auto result = enemyHeroAccessibleObjects.find(enemy);
if(result == enemyHeroAccessibleObjects.end())
std::set<const CGObjectInstance *> result;
for(auto & obj : enemyHeroAccessibleObjects)
{
return empty;
if(obj.hero == enemy)
result.insert(obj.obj);
}
return result->second;
return result;
}
void DangerHitMapAnalyzer::reset()

View File

@ -55,11 +55,22 @@ struct HitMapNode
}
};
struct EnemyHeroAccessibleObject
{
const CGHeroInstance * hero;
const CGObjectInstance * obj;
EnemyHeroAccessibleObject(const CGHeroInstance * hero, const CGObjectInstance * obj)
:hero(hero), obj(obj)
{
}
};
class DangerHitMapAnalyzer
{
private:
boost::multi_array<HitMapNode, 3> hitMap;
std::map<const CGHeroInstance *, std::set<const CGObjectInstance *>> enemyHeroAccessibleObjects;
tbb::concurrent_vector<EnemyHeroAccessibleObject> enemyHeroAccessibleObjects;
bool hitMapUpToDate = false;
bool tileOwnersUpToDate = false;
const Nullkiller * ai;
@ -73,7 +84,7 @@ public:
uint64_t enemyCanKillOurHeroesAlongThePath(const AIPath & path) const;
const HitMapNode & getObjectTreat(const CGObjectInstance * obj) const;
const HitMapNode & getTileTreat(const int3 & tile) const;
const std::set<const CGObjectInstance *> & getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const;
std::set<const CGObjectInstance *> getOneTurnAccessibleObjects(const CGHeroInstance * enemy) const;
void reset();
void resetTileOwners() { tileOwnersUpToDate = false; }
PlayerColor getTileOwner(const int3 & tile) const;