Переглянути джерело

replaced references to SectorMap with shared_ptr to avoid data races in AI code

Ivan Savenko 10 роки тому
батько
коміт
2e56b547ee
5 змінених файлів з 24 додано та 24 видалено
  1. 2 2
      AI/VCAI/AIUtility.cpp
  2. 1 1
      AI/VCAI/Fuzzy.cpp
  3. 8 8
      AI/VCAI/Goals.cpp
  4. 11 11
      AI/VCAI/VCAI.cpp
  5. 2 2
      AI/VCAI/VCAI.h

+ 2 - 2
AI/VCAI/AIUtility.cpp

@@ -363,7 +363,7 @@ int3 whereToExplore(HeroPtr h)
 	int radius = h->getSightRadious();
 	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
 	const int DIST_LIMIT = 3;
@@ -378,7 +378,7 @@ int3 whereToExplore(HeroPtr h)
 				CGPath p;
 				ai->myCb->getPathsInfo(h.get())->getPath(p, op);
 				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);
 			}
 		}

+ 1 - 1
AI/VCAI/Fuzzy.cpp

@@ -484,7 +484,7 @@ float FuzzyHelper::evaluate (Goals::ClearWayTo & g)
 	if (!g.hero.h)
 		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())
 	{

+ 8 - 8
AI/VCAI/Goals.cpp

@@ -484,9 +484,9 @@ TGoalVec ClearWayTo::getAllPossibleSubgoals()
 
 		//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())
 			continue;
 
@@ -634,11 +634,11 @@ TGoalVec Explore::getAllPossibleSubgoals()
 
 	for (auto h : heroes)
 	{
-		SectorMap &sm = ai->getCachedSectorMap(h);
+		auto sm = ai->getCachedSectorMap(h);
 
 		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))
 				ret.push_back (sptr(Goals::ClearWayTo(obj->visitablePos(), h).setisAbstract(true)));
 		}
@@ -964,7 +964,7 @@ TGoalVec Conquer::getAllPossibleSubgoals()
 
 	for (auto h : cb->getHeroesInfo())
 	{
-		SectorMap &sm = ai->getCachedSectorMap(h);
+		auto sm = ai->getCachedSectorMap(h);
 		std::vector<const CGObjectInstance *> ourObjs(objs); //copy common objects
 
 		for (auto obj : ai->reservedHeroesMap[h]) //add objects reserved by this hero
@@ -975,7 +975,7 @@ TGoalVec Conquer::getAllPossibleSubgoals()
 		for (auto obj : ourObjs)
 		{
 			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 (ai->isTileNotReserved(h, t)) //no other hero wants to conquer that tile
@@ -1094,11 +1094,11 @@ TGoalVec GatherArmy::getAllPossibleSubgoals()
 	}
 	for(auto h : cb->getHeroesInfo())
 	{
-		SectorMap &sm = ai->getCachedSectorMap(h);
+		auto sm = ai->getCachedSectorMap(h);
 		for (auto obj : objs)
 		{ //find safe dwelling
 			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)));
 		}
 	}

+ 11 - 11
AI/VCAI/VCAI.cpp

@@ -845,9 +845,9 @@ void VCAI::makeTurnInternal()
 bool VCAI::goVisitObj(const CGObjectInstance * obj, HeroPtr h)
 {
 	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);
-	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
 		return false;
 	return moveHeroToTile(pos, h);
@@ -1383,10 +1383,10 @@ std::vector<const CGObjectInstance *> VCAI::getPossibleDestinations(HeroPtr h)
 {
 	validateVisitableObjs();
 	std::vector<const CGObjectInstance *> possibleDestinations;
-	SectorMap &sm = getCachedSectorMap(h);
+	auto sm = getCachedSectorMap(h);
 	for(const CGObjectInstance *obj : visitableObjs)
 	{
-		if (isGoodForVisit(obj, h, sm))
+		if (isGoodForVisit(obj, h, *sm))
 		{
 			possibleDestinations.push_back(obj);
 		}
@@ -1441,12 +1441,12 @@ void VCAI::wander(HeroPtr h)
 		validateVisitableObjs();
 		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
 		for (auto obj : tmp)
 		{
-			int3 pos = sm.firstTileToGet(h, obj->visitablePos());
+			int3 pos = sm->firstTileToGet(h, obj->visitablePos());
 			if (pos.valid())
 				if (isAccessibleForHero (pos, h)) //even nearby objects could be blocked by other heroes :(
 					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));
 		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())
@@ -2541,7 +2541,7 @@ int3 VCAI::explorationNewPoint(HeroPtr h)
 
 int3 VCAI::explorationDesperate(HeroPtr h)
 {
-	SectorMap &sm = getCachedSectorMap(h);
+	auto sm = getCachedSectorMap(h);
 	int radius = h->getSightRadious();
 	
 	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
 				continue;
 
-			auto t = sm.firstTileToGet(h, tile);
+			auto t = sm->firstTileToGet(h, tile);
 			if (t.valid())
 			{
 				ui64 ourDanger = evaluateDanger(t, h.h);
@@ -2759,14 +2759,14 @@ TResources VCAI::freeResources() const
 	return myRes;
 }
 
-SectorMap& VCAI::getCachedSectorMap(HeroPtr h)
+std::shared_ptr<SectorMap> VCAI::getCachedSectorMap(HeroPtr h)
 {
 	auto it = cachedSectorMaps.find(h);
 	if (it != cachedSectorMaps.end())
 		return it->second;
 	else
 	{
-		cachedSectorMaps.insert(std::make_pair(h, SectorMap(h)));
+		cachedSectorMaps[h] = std::make_shared<SectorMap>(h);
 		return cachedSectorMaps[h];
 	}
 }

+ 2 - 2
AI/VCAI/VCAI.h

@@ -159,7 +159,7 @@ public:
 	std::set<const CGObjectInstance *> alreadyVisited;
 	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;
 
@@ -312,7 +312,7 @@ public:
 	const CGObjectInstance *getUnvisitedObj(const std::function<bool(const CGObjectInstance *)> &predicate);
 	bool isAccessibleForHero(const int3 & pos, HeroPtr h, bool includeAllies = false) const;
 	//optimization - use one SM for every hero call
-	SectorMap& getCachedSectorMap(HeroPtr h);
+	std::shared_ptr<SectorMap> getCachedSectorMap(HeroPtr h);
 
 	const CGTownInstance *findTownWithTavern() const;
 	bool canRecruitAnyHero(const CGTownInstance * t = NULL) const;