From 93d0dc62bfd5e7c27b25bc83377ce5a9fba96bd4 Mon Sep 17 00:00:00 2001 From: Reinder Feenstra Date: Thu, 2 Nov 2023 23:09:37 +0100 Subject: [PATCH] blockpath: added check to prevent paths crossing/endless loops --- server/src/board/map/blockpath.cpp | 34 +++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/server/src/board/map/blockpath.cpp b/server/src/board/map/blockpath.cpp index 9a028762..1b8fb728 100644 --- a/server/src/board/map/blockpath.cpp +++ b/server/src/board/map/blockpath.cpp @@ -36,6 +36,17 @@ #include "../../core/objectproperty.tpp" #include "../../enum/bridgepath.hpp" +template +static bool contains(const std::vector, T2>>& values, const std::shared_ptr& value) +{ + const auto it = std::find_if(values.begin(), values.end(), + [&value](const auto& item) + { + return item.first.lock() == value; + }); + return it != values.end(); +} + std::vector> BlockPath::find(BlockRailTile& startBlock) { const auto& node = startBlock.node()->get(); @@ -111,7 +122,12 @@ std::vector> BlockPath::find(BlockRailTile& startBloc case TileId::RailTurnoutSingleSlip: case TileId::RailTurnoutDoubleSlip: { - auto* turnout = static_cast(&tile); + auto turnout = tile.shared_ptr(); + if(contains(current.path->m_turnouts, turnout)) + { + todo.pop(); // drop it, can't pass turnout twice + break; + } auto links = getTurnoutLinks(*turnout, *current.link); assert(!links.empty()); @@ -120,14 +136,14 @@ std::vector> BlockPath::find(BlockRailTile& startBloc for(size_t i = 1; i < links.size(); ++i) { auto path = std::make_shared(*current.path); // "fork" path - path->m_turnouts.emplace_back(turnout->shared_ptr(), links[i].turnoutPosition); + path->m_turnouts.emplace_back(turnout, links[i].turnoutPosition); todo.emplace(Position{std::move(path), &nextNode, nextNode.getLink(links[i].linkIndex).get()}); } } current.node = &nextNode; current.link = nextNode.getLink(links[0].linkIndex).get(); - current.path->m_turnouts.emplace_back(turnout->shared_ptr(), links[0].turnoutPosition); + current.path->m_turnouts.emplace_back(turnout, links[0].turnoutPosition); break; } case TileId::RailOneWay: @@ -183,23 +199,31 @@ std::vector> BlockPath::find(BlockRailTile& startBloc case TileId::RailCross45: case TileId::RailCross90: + { // 2 2 3 // | |/ // 1 --+-- 3 | // | /| // 0 1 0 + auto cross = tile.shared_ptr(); + if(contains(current.path->m_crossings, cross)) + { + todo.pop(); // drop it, can't pass crossing twice + break; + } + for(size_t i = 0; i < 4; i++) { if(nextNode.getLink(i).get() == current.link) { current.node = &nextNode; current.link = nextNode.getLink((i + 2) % 4).get(); // opposite - current.path->m_crossings.emplace_back(tile.shared_ptr(), i % 2 == 0 ? CrossState::AC : CrossState::BD); + current.path->m_crossings.emplace_back(cross, i % 2 == 0 ? CrossState::AC : CrossState::BD); break; } } break; - + } case TileId::RailLink: { auto& linkTile = static_cast(tile);