Browse Source

Merge pull request #530 from dydzio0614/objRemovalFix

Extend objectRemoved callback to check parent goals and resource manager
DjWarmonger 6 năm trước cách đây
mục cha
commit
efc53e8f8b
5 tập tin đã thay đổi với 53 bổ sung36 xóa
  1. 5 0
      AI/VCAI/AIhelper.cpp
  2. 1 0
      AI/VCAI/AIhelper.h
  3. 27 16
      AI/VCAI/ResourceManager.cpp
  4. 2 1
      AI/VCAI/ResourceManager.h
  5. 18 19
      AI/VCAI/VCAI.cpp

+ 5 - 0
AI/VCAI/AIhelper.cpp

@@ -88,6 +88,11 @@ bool AIhelper::hasTasksLeft() const
 	return resourceManager->hasTasksLeft();
 }
 
+bool AIhelper::removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal&)> predicate)
+{
+	return resourceManager->removeOutdatedObjectives(predicate);
+}
+
 bool AIhelper::canAfford(const TResources & cost) const
 {
 	return resourceManager->canAfford(cost);

+ 1 - 0
AI/VCAI/AIhelper.h

@@ -47,6 +47,7 @@ public:
 	Goals::TSubgoal whatToDo() const override;
 	bool containsObjective(Goals::TSubgoal goal) const;
 	bool hasTasksLeft() const override;
+	bool removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate) override;
 
 	bool getBuildingOptions(const CGTownInstance * t) override;
 	BuildingID getMaxPossibleGoldBuilding(const CGTownInstance * t);

+ 27 - 16
AI/VCAI/ResourceManager.cpp

@@ -232,22 +232,12 @@ bool ResourceManager::notifyGoalCompleted(Goals::TSubgoal goal)
 	if (goal->invalid())
 		logAi->warn("Attempt to complete Invalid goal");
 
-	bool removedGoal = false;
-	while (true)
-	{ //unfortunatelly we can't use remove_if on heap
-		auto it = boost::find_if(queue, [goal](const ResourceObjective & ro) -> bool
-		{
-			return ro.goal == goal || ro.goal->fulfillsMe (goal);
-		});
-		if(it != queue.end()) //removed at least one
-		{
-			logAi->debug("Removing goal %s from ResourceManager.", it->goal->name());
-			queue.erase(queue.s_handle_from_iterator(it));
-			removedGoal = true;
-		}
-		else //found nothing more to remove
-			break;
-	}
+	std::function<bool(const Goals::TSubgoal &)> equivalentGoalsCheck = [goal](const Goals::TSubgoal & x) -> bool
+	{
+		return x == goal || x->fulfillsMe(goal);
+	};
+
+	bool removedGoal = removeOutdatedObjectives(equivalentGoalsCheck);
 
 	dumpToLog();
 
@@ -315,6 +305,27 @@ bool ResourceManager::hasTasksLeft() const
 	return !queue.empty();
 }
 
+bool ResourceManager::removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate)
+{
+	bool removedAnything = false;
+	while(true)
+	{ //unfortunately we can't use remove_if on heap
+		auto it = boost::find_if(queue, [&](const ResourceObjective & ro) -> bool
+		{
+			predicate(ro.goal);
+		});
+		if(it != queue.end()) //removed at least one
+		{
+			logAi->debug("Removing goal %s from ResourceManager.", it->goal->name());
+			queue.erase(queue.s_handle_from_iterator(it));
+			removedAnything = true;
+		}
+		else //found nothing more to remove
+			break;
+	}
+	return removedAnything;
+}
+
 TResources ResourceManager::reservedResources() const
 {
 	TResources res;

+ 2 - 1
AI/VCAI/ResourceManager.h

@@ -52,7 +52,7 @@ public:
 	virtual Goals::TSubgoal whatToDo(TResources &res, Goals::TSubgoal goal) = 0;
 	virtual bool containsObjective(Goals::TSubgoal goal) const = 0;
 	virtual bool hasTasksLeft() const = 0;
-private:
+	virtual bool removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate) = 0; //remove ResourceObjectives from queue if ResourceObjective->goal meets specific criteria
 	virtual bool notifyGoalCompleted(Goals::TSubgoal goal) = 0;
 };
 
@@ -82,6 +82,7 @@ public:
 	Goals::TSubgoal whatToDo(TResources & res, Goals::TSubgoal goal); //can we afford this goal or need to CollectRes?
 	bool containsObjective(Goals::TSubgoal goal) const;
 	bool hasTasksLeft() const override;
+	bool removeOutdatedObjectives(std::function<bool(const Goals::TSubgoal &)> predicate) override;
 
 protected: //not-const actions only for AI
 	virtual void reserveResoures(const TResources & res, Goals::TSubgoal goal = Goals::TSubgoal());

+ 18 - 19
AI/VCAI/VCAI.cpp

@@ -418,37 +418,36 @@ void VCAI::objectRemoved(const CGObjectInstance * obj)
 	for(auto h : cb->getHeroesInfo())
 		unreserveObject(h, obj);
 
-
-	vstd::erase_if(lockedHeroes, [&](const std::pair<HeroPtr, Goals::TSubgoal> & x) -> bool
+	std::function<bool(const Goals::TSubgoal &)> checkRemovalValidity = [&](const Goals::TSubgoal & x) -> bool
 	{
-		if((x.second->goalType == Goals::VISIT_OBJ) && (x.second->objid == obj->id.getNum()))
+		if((x->goalType == Goals::VISIT_OBJ) && (x->objid == obj->id.getNum()))
+			return true;
+		else if(x->parent && checkRemovalValidity(x->parent)) //repeat this lambda check recursively on parent goal
 			return true;
 		else
 			return false;
-	});
+	};
 
-	vstd::erase_if(ultimateGoalsFromBasic, [&](const std::pair<Goals::TSubgoal, Goals::TGoalVec> & x) -> bool
+	//clear VCAI / main loop caches
+	vstd::erase_if(lockedHeroes, [&](const std::pair<HeroPtr, Goals::TSubgoal> & x) -> bool
 	{
-		if((x.first->goalType == Goals::VISIT_OBJ) && (x.first->objid == obj->id.getNum()))
-			return true;
-		else
-			return false;
+		return checkRemovalValidity(x.second);
 	});
 
-	auto goalErasePredicate = [&](const Goals::TSubgoal & x) ->bool
+	vstd::erase_if(ultimateGoalsFromBasic, [&](const std::pair<Goals::TSubgoal, Goals::TGoalVec> & x) -> bool
 	{
-		if((x->goalType == Goals::VISIT_OBJ) && (x->objid == obj->id.getNum()))
-			return true;
-		else
-			return false;
-	};
+		return checkRemovalValidity(x.first);
+	});
 
-	vstd::erase_if(basicGoals, goalErasePredicate);
-	vstd::erase_if(goalsToAdd, goalErasePredicate);
-	vstd::erase_if(goalsToRemove, goalErasePredicate);
+	vstd::erase_if(basicGoals, checkRemovalValidity);
+	vstd::erase_if(goalsToAdd, checkRemovalValidity);
+	vstd::erase_if(goalsToRemove, checkRemovalValidity);
 
 	for(auto goal : ultimateGoalsFromBasic)
-		vstd::erase_if(goal.second, goalErasePredicate);
+		vstd::erase_if(goal.second, checkRemovalValidity);
+
+	//clear resource manager goal cache
+	ah->removeOutdatedObjectives(checkRemovalValidity);
 
 	//TODO: Find better way to handle hero boat removal
 	if(auto hero = dynamic_cast<const CGHeroInstance *>(obj))