1
0
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:
Michał W. Urbańczyk 2013-08-18 15:46:28 +00:00
parent 2e92bfb617
commit 3b42cff3ec
5 changed files with 69 additions and 6 deletions

View File

@ -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);
}
}

View File

@ -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
{

View File

@ -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

View File

@ -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 )

View File

@ -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));