1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +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
committed by Ivan Savenko
parent 04fe78d31c
commit 1eb58bcc32
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){ foreach_tile_pos([&](const int3 & pos){
hitMap[pos.x][pos.y][pos.z].reset(); hitMap[pos.x][pos.y][pos.z].reset();
}); });
@@ -95,15 +102,10 @@ void DangerHitMapAnalyzer::updateHitMap()
node.fastestDanger = newTreat; node.fastestDanger = newTreat;
} }
if(newTreat.turn == 0)
{
auto objects = cb->getVisitableObjs(pos, false); auto objects = cb->getVisitableObjs(pos, false);
for(auto obj : objects) for(auto obj : objects)
{ {
if(cb->getPlayerRelations(obj->tempOwner, ai->playerID) != PlayerRelations::ENEMIES)
enemyHeroAccessibleObjects[path.targetHero].insert(obj);
if(obj->ID == Obj::TOWN && obj->getOwner() == ai->playerID) if(obj->ID == Obj::TOWN && obj->getOwner() == ai->playerID)
{ {
auto & treats = townTreats[obj->id]; auto & treats = townTreats[obj->id];
@@ -122,6 +124,11 @@ void DangerHitMapAnalyzer::updateHitMap()
{ {
*treat = newTreat; *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 *> 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); std::set<const CGObjectInstance *> result;
if(result == enemyHeroAccessibleObjects.end()) for(auto & obj : enemyHeroAccessibleObjects)
{ {
return empty; if(obj.hero == enemy)
result.insert(obj.obj);
} }
return result->second; return result;
} }
void DangerHitMapAnalyzer::reset() 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 class DangerHitMapAnalyzer
{ {
private: private:
boost::multi_array<HitMapNode, 3> hitMap; boost::multi_array<HitMapNode, 3> hitMap;
std::map<const CGHeroInstance *, std::set<const CGObjectInstance *>> enemyHeroAccessibleObjects; tbb::concurrent_vector<EnemyHeroAccessibleObject> enemyHeroAccessibleObjects;
bool hitMapUpToDate = false; bool hitMapUpToDate = false;
bool tileOwnersUpToDate = false; bool tileOwnersUpToDate = false;
const Nullkiller * ai; const Nullkiller * ai;
@@ -73,7 +84,7 @@ public:
uint64_t enemyCanKillOurHeroesAlongThePath(const AIPath & path) const; uint64_t enemyCanKillOurHeroesAlongThePath(const AIPath & path) const;
const HitMapNode & getObjectTreat(const CGObjectInstance * obj) const; const HitMapNode & getObjectTreat(const CGObjectInstance * obj) const;
const HitMapNode & getTileTreat(const int3 & tile) 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 reset();
void resetTileOwners() { tileOwnersUpToDate = false; } void resetTileOwners() { tileOwnersUpToDate = false; }
PlayerColor getTileOwner(const int3 & tile) const; PlayerColor getTileOwner(const int3 & tile) const;