2
0
Эх сурвалжийг харах

#928 and #931 should be fixed.
Ignoring savegames from newer versions of VCMI.

Michał W. Urbańczyk 13 жил өмнө
parent
commit
cd4c93318d
3 өөрчлөгдсөн 78 нэмэгдсэн , 9 устгасан
  1. 51 8
      AI/VCAI/VCAI.cpp
  2. 21 0
      AI/VCAI/VCAI.h
  3. 6 1
      lib/Connection.cpp

+ 51 - 8
AI/VCAI/VCAI.cpp

@@ -59,6 +59,7 @@ typename Container::value_type frontOrNull(const Container &c) //returns first e
 		return NULL;
 }
 
+
 #define SET_GLOBAL_STATE(ai) SetGlobalState _hlpSetState(ai);
 
 #define NET_EVENT_HANDLER SET_GLOBAL_STATE(this)
@@ -658,6 +659,12 @@ void VCAI::objectRemoved(const CGObjectInstance *obj)
 	LOG_ENTRY;
 	if(remove_if_present(visitableObjs, obj))
 		assert(obj->isVisitable());
+
+	BOOST_FOREACH(auto &p, reservedHeroesMap)
+		remove_if_present(p.second, obj);
+
+	//TODO
+	//there are other places where CGObjectinstance ptrs are stored...
 }
 
 void VCAI::showHillFortWindow(const CGObjectInstance *object, const CGHeroInstance *visitor)
@@ -1145,9 +1152,11 @@ void VCAI::wander(const CGHeroInstance * h)
 {
 	while(1)
 	{
-		std::vector <const CGObjectInstance *> dests (reservedHeroesMap[h].begin(), reservedHeroesMap[h].end()); //copy constructor
+		std::vector <ObjectIdRef> dests;
+		range::copy(reservedHeroesMap[h], std::back_inserter(dests));
 		if (!dests.size())
-			dests = getPossibleDestinations(h);
+			range::copy(getPossibleDestinations(h), std::back_inserter(dests));
+
 		if(!dests.size())
 		{
 			auto compareReinforcements = [h](const CGTownInstance *lhs, const CGTownInstance *rhs) -> bool
@@ -1170,7 +1179,7 @@ void VCAI::wander(const CGHeroInstance * h)
             if(townsReachable.size())
             {
 				boost::sort(townsReachable, compareReinforcements);
-				dests.push_back(townsReachable.back());
+				dests.emplace_back(townsReachable.back());
 			}
 			else if(townsNotReachable.size())
 			{
@@ -1208,12 +1217,19 @@ void VCAI::wander(const CGHeroInstance * h)
 				break;
 			}
 		}
-		const CGObjectInstance * obj = dests.front();
-		if(!goVisitObj(obj, h))
+		const ObjectIdRef&dest = dests.front();
+		if(!goVisitObj(dest, h))
 		{
-			BNLOG("Hero %s apparently used all MPs (%d left)\n", h->name % h->movement);
-			reserveObject(h, obj); //reserve that object - we predict it will be reached soon
-			setGoal(h, CGoal(VISIT_TILE).sethero(h).settile(obj->visitablePos()));
+			if(!dest)
+			{
+				BNLOG("Visit attempt made the object (id=%d) gone...", dest.id);
+			}
+			else
+			{
+				BNLOG("Hero %s apparently used all MPs (%d left)\n", h->name % h->movement);
+				reserveObject(h, dest); //reserve that object - we predict it will be reached soon
+				setGoal(h, CGoal(VISIT_TILE).sethero(h).settile(dest->visitablePos()));
+			}
 			break;
 		}
 
@@ -1238,6 +1254,7 @@ void VCAI::setGoal (const CGHeroInstance *h, EGoals goalType)
 
 void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int3 tile, const CGHeroInstance *hero1, const CGHeroInstance *hero2, bool side)
 {
+	NET_EVENT_HANDLER;
 	assert(playerID > GameConstants::PLAYER_LIMIT || status.getBattle() == UPCOMING_BATTLE);
 	status.setBattle(ONGOING_BATTLE);
 	const CGObjectInstance *presumedEnemy = backOrNull(cb->getVisitableObjs(tile)); //may be NULL in some very are cases -> eg. visited monolith and fighting with an enemy at the FoW covered exit
@@ -1247,6 +1264,7 @@ void VCAI::battleStart(const CCreatureSet *army1, const CCreatureSet *army2, int
 
 void VCAI::battleEnd(const BattleResult *br)
 {
+	NET_EVENT_HANDLER;
 	assert(status.getBattle() == ONGOING_BATTLE);
 	status.setBattle(ENDING_BATTLE);
 	bool won = br->winner == myCb->battleGetMySide();
@@ -2852,3 +2870,28 @@ unsigned char & SectorMap::retreiveTile(crint3 pos)
 {
 	return retreiveTileN(sector, pos);
 }
+
+const CGObjectInstance * ObjectIdRef::operator->() const
+{
+	return cb->getObj(id, false);
+}
+
+ObjectIdRef::operator const CGObjectInstance*() const
+{
+	return cb->getObj(id, false);
+}
+
+ObjectIdRef::ObjectIdRef(int _id) : id(_id)
+{
+
+}
+
+ObjectIdRef::ObjectIdRef(const CGObjectInstance *obj) : id(obj->id)
+{
+
+}
+
+bool ObjectIdRef::operator<(const ObjectIdRef &rhs) const
+{
+	return id < rhs.id;
+}

+ 21 - 0
AI/VCAI/VCAI.h

@@ -148,6 +148,27 @@ struct CIssueCommand : CGoal
 	CIssueCommand(boost::function<bool()> _command): CGoal(ISSUE_COMMAND), command(_command) {}
 };
 
+
+// AI lives in a dangerous world. CGObjectInstances under pointer may got deleted/hidden.
+// This class stores object id, so we can detect when we lose access to the underlying object.
+struct ObjectIdRef
+{
+	int id;
+
+	const CGObjectInstance *operator->() const;
+	operator const CGObjectInstance *() const;
+
+	ObjectIdRef(int _id);
+	ObjectIdRef(const CGObjectInstance *obj);
+
+	bool operator<(const ObjectIdRef &rhs) const;
+};
+
+class ObjsVector : public std::vector<ObjectIdRef>
+{
+private:
+};
+
 class VCAI : public CAdventureAI
 {
 public:

+ 6 - 1
lib/Connection.cpp

@@ -330,7 +330,12 @@ void CLoadFile::openNextFile(const std::string &fname, int minimalVersion)
 		*this >> myVersion;	
 		if(myVersion < minimalVersion)
 		{
-			tlog1 << "Error: Old file format! (file " << fname << " )\n";
+			tlog1 << "Error: Too old file format! (file " << fname << " )\n";
+			sfile.release();
+		}
+		if(myVersion > version)
+		{
+			tlog1 << "Error: Too new file format! (file " << fname << " )\n";
 			sfile.release();
 		}
 	}