mirror of
https://github.com/vcmi/vcmi.git
synced 2025-09-16 09:26:28 +02:00
replaced references to SectorMap with shared_ptr to avoid data races in AI code
This commit is contained in:
@@ -363,7 +363,7 @@ int3 whereToExplore(HeroPtr h)
|
|||||||
int radius = h->getSightRadious();
|
int radius = h->getSightRadious();
|
||||||
int3 hpos = h->visitablePos();
|
int3 hpos = h->visitablePos();
|
||||||
|
|
||||||
SectorMap &sm = ai->getCachedSectorMap(h);
|
auto sm = ai->getCachedSectorMap(h);
|
||||||
|
|
||||||
//look for nearby objs -> visit them if they're close enouh
|
//look for nearby objs -> visit them if they're close enouh
|
||||||
const int DIST_LIMIT = 3;
|
const int DIST_LIMIT = 3;
|
||||||
@@ -378,7 +378,7 @@ int3 whereToExplore(HeroPtr h)
|
|||||||
CGPath p;
|
CGPath p;
|
||||||
ai->myCb->getPathsInfo(h.get())->getPath(p, op);
|
ai->myCb->getPathsInfo(h.get())->getPath(p, op);
|
||||||
if (p.nodes.size() && p.endPos() == op && p.nodes.size() <= DIST_LIMIT)
|
if (p.nodes.size() && p.endPos() == op && p.nodes.size() <= DIST_LIMIT)
|
||||||
if (ai->isGoodForVisit(obj, h, sm))
|
if (ai->isGoodForVisit(obj, h, *sm))
|
||||||
nearbyVisitableObjs.push_back(obj);
|
nearbyVisitableObjs.push_back(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -484,7 +484,7 @@ float FuzzyHelper::evaluate (Goals::ClearWayTo & g)
|
|||||||
if (!g.hero.h)
|
if (!g.hero.h)
|
||||||
throw cannotFulfillGoalException("ClearWayTo called without hero!");
|
throw cannotFulfillGoalException("ClearWayTo called without hero!");
|
||||||
|
|
||||||
int3 t = ai->getCachedSectorMap(g.hero).firstTileToGet(g.hero, g.tile);
|
int3 t = ai->getCachedSectorMap(g.hero)->firstTileToGet(g.hero, g.tile);
|
||||||
|
|
||||||
if (t.valid())
|
if (t.valid())
|
||||||
{
|
{
|
||||||
|
@@ -484,9 +484,9 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
|
|||||||
|
|
||||||
//if our hero is trapped, make sure we request clearing the way from OUR perspective
|
//if our hero is trapped, make sure we request clearing the way from OUR perspective
|
||||||
|
|
||||||
SectorMap &sm = ai->getCachedSectorMap(h);
|
auto sm = ai->getCachedSectorMap(h);
|
||||||
|
|
||||||
int3 tileToHit = sm.firstTileToGet(h, tile);
|
int3 tileToHit = sm->firstTileToGet(h, tile);
|
||||||
if (!tileToHit.valid())
|
if (!tileToHit.valid())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -634,11 +634,11 @@ TGoalVec Explore::getAllPossibleSubgoals()
|
|||||||
|
|
||||||
for (auto h : heroes)
|
for (auto h : heroes)
|
||||||
{
|
{
|
||||||
SectorMap &sm = ai->getCachedSectorMap(h);
|
auto sm = ai->getCachedSectorMap(h);
|
||||||
|
|
||||||
for (auto obj : objs) //double loop, performance risk?
|
for (auto obj : objs) //double loop, performance risk?
|
||||||
{
|
{
|
||||||
auto t = sm.firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
|
auto t = sm->firstTileToGet(h, obj->visitablePos()); //we assume that no more than one tile on the way is guarded
|
||||||
if (ai->isTileNotReserved(h, t))
|
if (ai->isTileNotReserved(h, t))
|
||||||
ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
|
ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
|
||||||
}
|
}
|
||||||
@@ -964,7 +964,7 @@ TGoalVec Conquer::getAllPossibleSubgoals()
|
|||||||
|
|
||||||
for (auto h : cb->getHeroesInfo())
|
for (auto h : cb->getHeroesInfo())
|
||||||
{
|
{
|
||||||
SectorMap &sm = ai->getCachedSectorMap(h);
|
auto sm = ai->getCachedSectorMap(h);
|
||||||
std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
|
std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
|
||||||
|
|
||||||
for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
|
for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
|
||||||
@@ -975,7 +975,7 @@ TGoalVec Conquer::getAllPossibleSubgoals()
|
|||||||
for (auto obj : ourObjs)
|
for (auto obj : ourObjs)
|
||||||
{
|
{
|
||||||
int3 dest = obj->visitablePos();
|
int3 dest = obj->visitablePos();
|
||||||
auto t = sm.firstTileToGet(h, dest); //we assume that no more than one tile on the way is guarded
|
auto t = sm->firstTileToGet(h, dest); //we assume that no more than one tile on the way is guarded
|
||||||
if (t.valid()) //we know any path at all
|
if (t.valid()) //we know any path at all
|
||||||
{
|
{
|
||||||
if (ai->isTileNotReserved(h, t)) //no other hero wants to conquer that tile
|
if (ai->isTileNotReserved(h, t)) //no other hero wants to conquer that tile
|
||||||
@@ -1094,11 +1094,11 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
|
|||||||
}
|
}
|
||||||
for(auto h : cb->getHeroesInfo())
|
for(auto h : cb->getHeroesInfo())
|
||||||
{
|
{
|
||||||
SectorMap &sm = ai->getCachedSectorMap(h);
|
auto sm = ai->getCachedSectorMap(h);
|
||||||
for (auto obj : objs)
|
for (auto obj : objs)
|
||||||
{ //find safe dwelling
|
{ //find safe dwelling
|
||||||
auto pos = obj->visitablePos();
|
auto pos = obj->visitablePos();
|
||||||
if (ai->isGoodForVisit(obj, h, sm))
|
if (ai->isGoodForVisit(obj, h, *sm))
|
||||||
ret.push_back (sptr (Goals::VisitTile(pos).sethero(h)));
|
ret.push_back (sptr (Goals::VisitTile(pos).sethero(h)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -845,9 +845,9 @@ void VCAI::makeTurnInternal()
|
|||||||
bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
|
bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
|
||||||
{
|
{
|
||||||
int3 dst = obj->visitablePos();
|
int3 dst = obj->visitablePos();
|
||||||
SectorMap &sm = getCachedSectorMap(h);
|
auto sm = getCachedSectorMap(h);
|
||||||
logAi->debugStream() << boost::format("%s will try to visit %s at (%s)") % h->name % obj->getObjectName() % strFromInt3(dst);
|
logAi->debugStream() << boost::format("%s will try to visit %s at (%s)") % h->name % obj->getObjectName() % strFromInt3(dst);
|
||||||
int3 pos = sm.firstTileToGet(h, dst);
|
int3 pos = sm->firstTileToGet(h, dst);
|
||||||
if (!pos.valid()) //rare case when we are already standing on one of potential objects
|
if (!pos.valid()) //rare case when we are already standing on one of potential objects
|
||||||
return false;
|
return false;
|
||||||
return moveHeroToTile(pos, h);
|
return moveHeroToTile(pos, h);
|
||||||
@@ -1383,10 +1383,10 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(HeroPtr h)
|
|||||||
{
|
{
|
||||||
validateVisitableObjs();
|
validateVisitableObjs();
|
||||||
std::vector<const CGObjectInstance *> possibleDestinations;
|
std::vector<const CGObjectInstance *> possibleDestinations;
|
||||||
SectorMap &sm = getCachedSectorMap(h);
|
auto sm = getCachedSectorMap(h);
|
||||||
for(const CGObjectInstance *obj : visitableObjs)
|
for(const CGObjectInstance *obj : visitableObjs)
|
||||||
{
|
{
|
||||||
if (isGoodForVisit(obj, h, sm))
|
if (isGoodForVisit(obj, h, *sm))
|
||||||
{
|
{
|
||||||
possibleDestinations.push_back(obj);
|
possibleDestinations.push_back(obj);
|
||||||
}
|
}
|
||||||
@@ -1441,12 +1441,12 @@ void VCAI::wander(HeroPtr h)
|
|||||||
validateVisitableObjs();
|
validateVisitableObjs();
|
||||||
std::vector <ObjectIdRef> dests, tmp;
|
std::vector <ObjectIdRef> dests, tmp;
|
||||||
|
|
||||||
SectorMap &sm = getCachedSectorMap(h);
|
auto sm = getCachedSectorMap(h);
|
||||||
|
|
||||||
range::copy(reservedHeroesMap[h], std::back_inserter(tmp)); //also visit our reserved objects - but they are not prioritized to avoid running back and forth
|
range::copy(reservedHeroesMap[h], std::back_inserter(tmp)); //also visit our reserved objects - but they are not prioritized to avoid running back and forth
|
||||||
for (auto obj : tmp)
|
for (auto obj : tmp)
|
||||||
{
|
{
|
||||||
int3 pos = sm.firstTileToGet(h, obj->visitablePos());
|
int3 pos = sm->firstTileToGet(h, obj->visitablePos());
|
||||||
if (pos.valid())
|
if (pos.valid())
|
||||||
if (isAccessibleForHero (pos, h)) //even nearby objects could be blocked by other heroes :(
|
if (isAccessibleForHero (pos, h)) //even nearby objects could be blocked by other heroes :(
|
||||||
dests.push_back(obj); //can't use lambda for member function :(
|
dests.push_back(obj); //can't use lambda for member function :(
|
||||||
@@ -1455,7 +1455,7 @@ void VCAI::wander(HeroPtr h)
|
|||||||
range::copy(getPossibleDestinations(h), std::back_inserter(dests));
|
range::copy(getPossibleDestinations(h), std::back_inserter(dests));
|
||||||
erase_if(dests, [&](ObjectIdRef obj) -> bool
|
erase_if(dests, [&](ObjectIdRef obj) -> bool
|
||||||
{
|
{
|
||||||
return !isSafeToVisit(h, sm.firstTileToGet(h, obj->visitablePos()));
|
return !isSafeToVisit(h, sm->firstTileToGet(h, obj->visitablePos()));
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!dests.size())
|
if(!dests.size())
|
||||||
@@ -2541,7 +2541,7 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
|
|||||||
|
|
||||||
int3 VCAI::explorationDesperate(HeroPtr h)
|
int3 VCAI::explorationDesperate(HeroPtr h)
|
||||||
{
|
{
|
||||||
SectorMap &sm = getCachedSectorMap(h);
|
auto sm = getCachedSectorMap(h);
|
||||||
int radius = h->getSightRadious();
|
int radius = h->getSightRadious();
|
||||||
|
|
||||||
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
|
std::vector<std::vector<int3> > tiles; //tiles[distance_to_fow]
|
||||||
@@ -2570,7 +2570,7 @@ int3 VCAI::explorationDesperate(HeroPtr h)
|
|||||||
if (!howManyTilesWillBeDiscovered(tile, radius, cbp)) //avoid costly checks of tiles that don't reveal much
|
if (!howManyTilesWillBeDiscovered(tile, radius, cbp)) //avoid costly checks of tiles that don't reveal much
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto t = sm.firstTileToGet(h, tile);
|
auto t = sm->firstTileToGet(h, tile);
|
||||||
if (t.valid())
|
if (t.valid())
|
||||||
{
|
{
|
||||||
ui64 ourDanger = evaluateDanger(t, h.h);
|
ui64 ourDanger = evaluateDanger(t, h.h);
|
||||||
@@ -2759,14 +2759,14 @@ TResources VCAI::freeResources() const
|
|||||||
return myRes;
|
return myRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
SectorMap& VCAI::getCachedSectorMap(HeroPtr h)
|
std::shared_ptr<SectorMap> VCAI::getCachedSectorMap(HeroPtr h)
|
||||||
{
|
{
|
||||||
auto it = cachedSectorMaps.find(h);
|
auto it = cachedSectorMaps.find(h);
|
||||||
if (it != cachedSectorMaps.end())
|
if (it != cachedSectorMaps.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
cachedSectorMaps.insert(std::make_pair(h, SectorMap(h)));
|
cachedSectorMaps[h] = std::make_shared<SectorMap>(h);
|
||||||
return cachedSectorMaps[h];
|
return cachedSectorMaps[h];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -159,7 +159,7 @@ public:
|
|||||||
std::set<const CGObjectInstance *> alreadyVisited;
|
std::set<const CGObjectInstance *> alreadyVisited;
|
||||||
std::set<const CGObjectInstance *> reservedObjs; //to be visited by specific hero
|
std::set<const CGObjectInstance *> reservedObjs; //to be visited by specific hero
|
||||||
|
|
||||||
std::map <HeroPtr, SectorMap> cachedSectorMaps; //TODO: serialize? not necessary
|
std::map <HeroPtr, std::shared_ptr<SectorMap>> cachedSectorMaps; //TODO: serialize? not necessary
|
||||||
|
|
||||||
TResources saving;
|
TResources saving;
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ public:
|
|||||||
const CGObjectInstance *getUnvisitedObj(const std::function<bool(const CGObjectInstance *)> &predicate);
|
const CGObjectInstance *getUnvisitedObj(const std::function<bool(const CGObjectInstance *)> &predicate);
|
||||||
bool isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies = false) const;
|
bool isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies = false) const;
|
||||||
//optimization - use one SM for every hero call
|
//optimization - use one SM for every hero call
|
||||||
SectorMap& getCachedSectorMap(HeroPtr h);
|
std::shared_ptr<SectorMap> getCachedSectorMap(HeroPtr h);
|
||||||
|
|
||||||
const CGTownInstance *findTownWithTavern() const;
|
const CGTownInstance *findTownWithTavern() const;
|
||||||
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;
|
bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;
|
||||||
|
Reference in New Issue
Block a user