1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-02-03 13:01:33 +02:00

Merge pull request #2375 from vcmi/fix_roads

Fix RMG failing to place roads sometimes
This commit is contained in:
DjWarmonger 2023-07-22 15:56:25 +02:00 committed by GitHub
commit bf7b77600a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 12 deletions

View File

@ -464,6 +464,7 @@ void ObjectManager::placeObject(rmg::Object & object, bool guarded, bool updateD
objects.push_back(&instance->object()); objects.push_back(&instance->object());
if(auto * m = zone.getModificator<RoadPlacer>()) if(auto * m = zone.getModificator<RoadPlacer>())
{ {
//FIXME: Objects that can be removed, can be trespassed. Does not include Corpse
if(instance->object().appearance->isVisitableFromTop()) if(instance->object().appearance->isVisitableFromTop())
m->areaForRoads().add(instance->getVisitablePosition()); m->areaForRoads().add(instance->getVisitablePosition());
else else

View File

@ -31,7 +31,7 @@ void RoadPlacer::process()
void RoadPlacer::init() void RoadPlacer::init()
{ {
if (zone.isUnderground()) if(zone.isUnderground())
{ {
DEPENDENCY_ALL(RockFiller); DEPENDENCY_ALL(RockFiller);
} }
@ -54,22 +54,52 @@ const rmg::Area & RoadPlacer::getRoads() const
bool RoadPlacer::createRoad(const int3 & dst) bool RoadPlacer::createRoad(const int3 & dst)
{ {
auto searchArea = zone.areaPossible() + areaRoads + zone.freePaths() - isolated + roads; auto searchArea = zone.areaPossible() + zone.freePaths() + areaRoads + roads;
rmg::Path path(searchArea); rmg::Path path(searchArea);
path.connect(roads); path.connect(roads);
auto simpleRoutig = [this](const int3& src, const int3& dst)
{
if(areaIsolated().contains(dst))
{
return 1000.0f; //Do not route road behind objects that are not visitable from top
}
else
{
return 1.0f;
}
};
auto res = path.search(dst, true); auto res = path.search(dst, true, simpleRoutig);
if(!res.valid()) if(!res.valid())
{ {
res = path.search(dst, false, [](const int3 & src, const int3 & dst) auto desperateRoutig = [this](const int3& src, const int3& dst) -> float
{ {
//Do not allow connections straight up through object not visitable from top
if(std::abs((src - dst).y) == 1)
{
if(areaIsolated().contains(dst) || areaIsolated().contains(src))
{
return 1e30;
}
}
else
{
if(areaIsolated().contains(dst))
{
return 1e6;
}
}
float weight = dst.dist2dSQ(src); float weight = dst.dist2dSQ(src);
return weight * weight; return weight * weight;
}); };
res = path.search(dst, false, desperateRoutig);
if(!res.valid()) if(!res.valid())
{ {
logGlobal->warn("Failed to create road"); logGlobal->warn("Failed to create road to node %s", dst.toString());
return false; return false;
} }
} }
@ -88,7 +118,7 @@ void RoadPlacer::drawRoads(bool secondary)
zone.freePaths().unite(roads); zone.freePaths().unite(roads);
} }
if (!generator.getMapGenOptions().isRoadEnabled()) if(!generator.getMapGenOptions().isRoadEnabled())
{ {
return; return;
} }
@ -108,7 +138,7 @@ void RoadPlacer::drawRoads(bool secondary)
//If our road type is not enabled, choose highest below it //If our road type is not enabled, choose highest below it
for (int8_t bestRoad = roadType.getNum(); bestRoad > RoadId(Road::NO_ROAD).getNum(); bestRoad--) for (int8_t bestRoad = roadType.getNum(); bestRoad > RoadId(Road::NO_ROAD).getNum(); bestRoad--)
{ {
if (generator.getMapGenOptions().isRoadEnabled(RoadId(bestRoad))) if(generator.getMapGenOptions().isRoadEnabled(RoadId(bestRoad)))
{ {
mapProxy->drawRoads(zone.getRand(), tiles, RoadId(bestRoad)); mapProxy->drawRoads(zone.getRand(), tiles, RoadId(bestRoad));
return; return;
@ -126,11 +156,11 @@ void RoadPlacer::connectRoads()
{ {
bool noRoadNodes = false; bool noRoadNodes = false;
//Assumes objects are already placed //Assumes objects are already placed
if (roadNodes.size() < 2) if(roadNodes.size() < 2)
{ {
//If there are no nodes, draw roads to mines //If there are no nodes, draw roads to mines
noRoadNodes = true; noRoadNodes = true;
if (auto* m = zone.getModificator<ObjectManager>()) if(auto* m = zone.getModificator<ObjectManager>())
{ {
for(auto * object : m->getMines()) for(auto * object : m->getMines())
{ {
@ -149,7 +179,19 @@ void RoadPlacer::connectRoads()
for(const auto & node : roadNodes) for(const auto & node : roadNodes)
{ {
createRoad(node); try
{
createRoad(node);
}
catch (const rmgException& e)
{
logGlobal->warn("Handled exception while drawing road to node %s: %s", node.toString(), e.what());
}
catch (const std::exception & e)
{
logGlobal->error("Unhandled exception while drawing road to node %s: %s", node.toString(), e.what());
throw e;
}
} }
//Draw dirt roads if there are only mines //Draw dirt roads if there are only mines