1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Merge pull request #1721 from vcmi/fix_rmg_infinite_loop

Fix rmg infinite loop
This commit is contained in:
Andrii Danylchenko
2023-03-19 19:46:28 +02:00
committed by GitHub
3 changed files with 65 additions and 17 deletions

View File

@@ -672,28 +672,64 @@ void CRmgTemplate::serializeJson(JsonSerializeFormat & handler)
afterLoad();
}
std::set<TerrainId> CRmgTemplate::inheritTerrainType(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
{
if (iteration >= 50)
{
logGlobal->error("Infinite recursion for terrain types detected in template %s", name);
return std::set<TerrainId>();
}
if (zone->getTerrainTypeLikeZone() != ZoneOptions::NO_ZONE)
{
iteration++;
const auto otherZone = zones.at(zone->getTerrainTypeLikeZone());
zone->setTerrainTypes(inheritTerrainType(otherZone, iteration));
}
return zone->getTerrainTypes();
}
std::map<TResource, ui16> CRmgTemplate::inheritMineTypes(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
{
if (iteration >= 50)
{
logGlobal->error("Infinite recursion for mine types detected in template %s", name);
return std::map<TResource, ui16>();
}
if (zone->getMinesLikeZone() != ZoneOptions::NO_ZONE)
{
iteration++;
const auto otherZone = zones.at(zone->getMinesLikeZone());
zone->setMinesInfo(inheritMineTypes(otherZone, iteration));
}
return zone->getMinesInfo();
}
std::vector<CTreasureInfo> CRmgTemplate::inheritTreasureInfo(std::shared_ptr<ZoneOptions> zone, uint32_t iteration /* = 0 */)
{
if (iteration >= 50)
{
logGlobal->error("Infinite recursion for treasures detected in template %s", name);
return std::vector<CTreasureInfo>();
}
if (zone->getTreasureLikeZone() != ZoneOptions::NO_ZONE)
{
iteration++;
const auto otherZone = zones.at(zone->getTreasureLikeZone());
zone->setTreasureInfo(inheritTreasureInfo(otherZone, iteration));
}
return zone->getTreasureInfo();
}
void CRmgTemplate::afterLoad()
{
for(auto & idAndZone : zones)
{
auto zone = idAndZone.second;
if(zone->getMinesLikeZone() != ZoneOptions::NO_ZONE)
{
const auto otherZone = zones.at(zone->getMinesLikeZone());
zone->setMinesInfo(otherZone->getMinesInfo());
}
if(zone->getTerrainTypeLikeZone() != ZoneOptions::NO_ZONE)
{
const auto otherZone = zones.at(zone->getTerrainTypeLikeZone());
zone->setTerrainTypes(otherZone->getTerrainTypes());
}
if(zone->getTreasureLikeZone() != ZoneOptions::NO_ZONE)
{
const auto otherZone = zones.at(zone->getTreasureLikeZone());
zone->setTreasureInfo(otherZone->getTreasureInfo());
}
//Inherit properties recursively.
inheritTerrainType(zone);
inheritMineTypes(zone);
inheritTreasureInfo(zone);
}
for(const auto & connection : connections)

View File

@@ -238,6 +238,9 @@ private:
std::set<EWaterContent::EWaterContent> allowedWaterContent;
void afterLoad();
std::set<TerrainId> inheritTerrainType(std::shared_ptr<rmg::ZoneOptions> zone, uint32_t iteration = 0);
std::map<TResource, ui16> inheritMineTypes(std::shared_ptr<rmg::ZoneOptions> zone, uint32_t iteration = 0);
std::vector<CTreasureInfo> inheritTreasureInfo(std::shared_ptr<rmg::ZoneOptions> zone, uint32_t iteration = 0);
void serializeSize(JsonSerializeFormat & handler, int3 & value, const std::string & fieldName);
void serializePlayers(JsonSerializeFormat & handler, CPlayerCountRange & value, const std::string & fieldName);
};

View File

@@ -134,7 +134,16 @@ void initTerrainType(Zone & zone, CMapGenerator & gen)
}
else
{
zone.setTerrainType(*RandomGeneratorUtil::nextItem(zone.getTerrainTypes(), gen.rand));
auto terrainTypes = zone.getTerrainTypes();
if (terrainTypes.empty())
{
logGlobal->warn("No terrain types found, falling back to DIRT");
zone.setTerrainType(ETerrainId::DIRT);
}
else
{
zone.setTerrainType(*RandomGeneratorUtil::nextItem(terrainTypes, gen.rand));
}
}
//Now, replace disallowed terrains on surface and in the underground