mirror of
https://github.com/vcmi/vcmi.git
synced 2024-12-24 22:14:36 +02:00
#1409 should not crash anymore.
Fixed crash on serializing empty path. [How did it got there...?] operator<< for boost::optional.
This commit is contained in:
parent
2e92bfb617
commit
3b42cff3ec
@ -907,6 +907,7 @@ void VCAI::saveGame(COSer<CSaveFile> &h, const int version)
|
||||
{
|
||||
LOG_TRACE_PARAMS(logAi, "version '%i'", version);
|
||||
NET_EVENT_HANDLER;
|
||||
validateVisitableObjs();
|
||||
CAdventureAI::saveGame(h, version);
|
||||
serializeInternal(h, version);
|
||||
}
|
||||
@ -1018,6 +1019,11 @@ void VCAI::makeTurnInternal()
|
||||
boost::sort (hero.second, isCloser);
|
||||
for (auto obj : hero.second)
|
||||
{
|
||||
if(!obj || !obj->defInfo || !cb->getObj(obj->id))
|
||||
{
|
||||
logAi->errorStream() << "Error: there is wrong object on list for hero " << hero.first->name;
|
||||
continue;
|
||||
}
|
||||
striveToGoal (CGoal(VISIT_TILE).sethero(hero.first).settile(obj->visitablePos()));
|
||||
}
|
||||
}
|
||||
@ -1102,7 +1108,7 @@ void VCAI::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
||||
|
||||
void VCAI::moveCreaturesToHero(const CGTownInstance * t)
|
||||
{
|
||||
if(t->visitingHero && t->armedGarrison())
|
||||
if(t->visitingHero && t->armedGarrison() && t->visitingHero->tempOwner == t->tempOwner)
|
||||
{
|
||||
pickBestCreatures (t->visitingHero, t);
|
||||
}
|
||||
@ -1110,6 +1116,13 @@ void VCAI::moveCreaturesToHero(const CGTownInstance * t)
|
||||
|
||||
bool VCAI::canGetArmy (const CGHeroInstance * army, const CGHeroInstance * source)
|
||||
{ //TODO: merge with pickBestCreatures
|
||||
if(army->tempOwner != source->tempOwner)
|
||||
{
|
||||
logAi->errorStream() << "Why are we even considering exchange between heroes from different players?";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const CArmedInstance *armies[] = {army, source};
|
||||
int armySize = 0;
|
||||
//we calculate total strength for each creature type available in armies
|
||||
@ -1438,6 +1451,7 @@ void VCAI::wander(HeroPtr h)
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
validateVisitableObjs();
|
||||
std::vector <ObjectIdRef> dests;
|
||||
range::copy(reservedHeroesMap[h], std::back_inserter(dests));
|
||||
if (!dests.size())
|
||||
@ -1598,21 +1612,41 @@ void VCAI::reserveObject(HeroPtr h, const CGObjectInstance *obj)
|
||||
{
|
||||
reservedObjs.push_back(obj);
|
||||
reservedHeroesMap[h].push_back(obj);
|
||||
logAi->debugStream() << "reserved object id=" << obj->id << "; address=" << (int)obj << "; name=" << obj->getHoverText();
|
||||
}
|
||||
|
||||
void VCAI::validateVisitableObjs()
|
||||
{
|
||||
std::vector<const CGObjectInstance *> hlp;
|
||||
retreiveVisitableObjs(hlp, true);
|
||||
erase_if(visitableObjs, [&](const CGObjectInstance *obj) -> bool
|
||||
|
||||
std::string errorMsg;
|
||||
auto shouldBeErased = [&](const CGObjectInstance *obj) -> bool
|
||||
{
|
||||
if(!vstd::contains(hlp, obj))
|
||||
{
|
||||
logAi->errorStream() << helperObjInfo[obj].name << " at " << helperObjInfo[obj].pos << " shouldn't be on list!";
|
||||
logAi->errorStream() << helperObjInfo[obj].name << " at " << helperObjInfo[obj].pos << errorMsg;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
//errorMsg is captured by ref so lambda will take the new text
|
||||
errorMsg = " shouldn't be on the visitable objects list!";
|
||||
erase_if(visitableObjs, shouldBeErased);
|
||||
|
||||
for(auto &p : reservedHeroesMap)
|
||||
{
|
||||
errorMsg = " shouldn't be on list for hero " + p.first->name + "!";
|
||||
erase_if(p.second, shouldBeErased);
|
||||
}
|
||||
|
||||
errorMsg = " shouldn't be on the reserved objs list!";
|
||||
erase_if(reservedObjs, shouldBeErased);
|
||||
|
||||
//TODO overkill, hidden object should not be removed. However, we can't know if hidden object is erased from game.
|
||||
errorMsg = " shouldn't be on the already visited objs list!";
|
||||
erase_if(alreadyVisited, shouldBeErased);
|
||||
}
|
||||
|
||||
void VCAI::retreiveVisitableObjs(std::vector<const CGObjectInstance *> &out, bool includeOwned /*= false*/) const
|
||||
@ -2575,6 +2609,8 @@ void VCAI::validateObject(ObjectIdRef obj)
|
||||
|
||||
for(auto &p : reservedHeroesMap)
|
||||
erase_if(p.second, matchesId);
|
||||
|
||||
erase_if(reservedObjs, matchesId);
|
||||
}
|
||||
}
|
||||
|
||||
|
10
Global.h
10
Global.h
@ -268,6 +268,16 @@ public:
|
||||
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::ostream &operator<<(std::ostream &out, const boost::optional<T> &opt)
|
||||
{
|
||||
if(opt)
|
||||
return out << *opt;
|
||||
else
|
||||
return out<< "empty";
|
||||
}
|
||||
|
||||
|
||||
namespace vstd
|
||||
{
|
||||
|
||||
|
@ -1183,7 +1183,12 @@ template <typename Handler> void CPlayerInterface::serializeTempl( Handler &h, c
|
||||
if(h.saving)
|
||||
{
|
||||
for(auto &p : paths)
|
||||
pathsMap[p.first] = p.second.endPos();
|
||||
{
|
||||
if(p.second.nodes.size())
|
||||
pathsMap[p.first] = p.second.endPos();
|
||||
else
|
||||
logGlobal->errorStream() << p.first->name << " has assigned an empty path! Ignoring it...";
|
||||
}
|
||||
h & pathsMap;
|
||||
}
|
||||
else
|
||||
|
@ -290,6 +290,15 @@ void CClient::loadGame( const std::string & fname )
|
||||
serv->enableStackSendingByID();
|
||||
serv->disableSmartPointerSerialization();
|
||||
|
||||
// logGlobal->traceStream() << "Objects:";
|
||||
// for(int i = 0; i < gs->map->objects.size(); i++)
|
||||
// {
|
||||
// auto o = gs->map->objects[i];
|
||||
// if(o)
|
||||
// logGlobal->traceStream() << boost::format("\tindex=%5d, id=%5d; address=%5d, pos=%s, name=%s") % i % o->id % (int)o.get() % o->pos % o->getHoverText();
|
||||
// else
|
||||
// logGlobal->traceStream() << boost::format("\tindex=%5d --- nullptr") % i;
|
||||
// }
|
||||
}
|
||||
|
||||
void CClient::newGame( CConnection *con, StartInfo *si )
|
||||
|
@ -300,9 +300,9 @@ DLL_LINKAGE void RemoveBonus::applyGs( CGameState *gs )
|
||||
|
||||
DLL_LINKAGE void RemoveObject::applyGs( CGameState *gs )
|
||||
{
|
||||
logGlobal->debugStream() << "removing object oid=" << id;
|
||||
|
||||
CGObjectInstance *obj = gs->getObjInstance(id);
|
||||
logGlobal->debugStream() << "removing object id=" << id << "; address=" << (int)obj << "; name=" << obj->getHoverText();
|
||||
//unblock tiles
|
||||
if(obj->defInfo)
|
||||
{
|
||||
@ -594,7 +594,10 @@ DLL_LINKAGE void NewObject::applyGs( CGameState *gs )
|
||||
gs->map->addBlockVisTiles(o);
|
||||
o->initObj();
|
||||
assert(o->defInfo);
|
||||
|
||||
logGlobal->debugStream() << "added object id=" << id << "; address=" << (int)o << "; name=" << o->getHoverText();
|
||||
}
|
||||
|
||||
DLL_LINKAGE void NewArtifact::applyGs( CGameState *gs )
|
||||
{
|
||||
assert(!vstd::contains(gs->map->artInstances, art));
|
||||
|
Loading…
Reference in New Issue
Block a user