From 96b6d3412fba98161d1118b2fdc5cfbff6c821cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Sun, 29 Sep 2024 15:25:50 +0300 Subject: [PATCH 1/5] Eliminate global variables, pass state to PeepPathfindHeuristicSearch --- src/openrct2/peep/GuestPathfinding.cpp | 125 +++++++++++++------------ 1 file changed, 65 insertions(+), 60 deletions(-) diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 14e0cb4b77..97cd396544 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -33,22 +33,25 @@ RideId gPeepPathFindQueueRideIndex; namespace OpenRCT2::PathFinding { - static int8_t _peepPathFindNumJunctions; - static int8_t _peepPathFindMaxJunctions; - static int32_t _peepPathFindTilesChecked; + struct PathFindingState + { + int8_t junctionCount; + int8_t maxJunctions; + int32_t countTilesChecked; + + /* A junction history for the peep pathfinding heuristic search + * The magic number 16 is the largest value returned by + * PeepPathfindGetMaxNumberJunctions() which should eventually + * be declared properly. */ + struct + { + TileCoordsXYZ location; + Direction direction; + } history[16]; + }; static int32_t GuestSurfacePathFinding(Peep& peep); - /* A junction history for the peep pathfinding heuristic search - * The magic number 16 is the largest value returned by - * PeepPathfindGetMaxNumberJunctions() which should eventually - * be declared properly. */ - static struct - { - TileCoordsXYZ location; - Direction direction; - } _peepPathFindHistory[16]; - enum class PathSearchResult { DeadEnd, // Path is a dead end, i.e. < 2 edges. @@ -704,9 +707,10 @@ namespace OpenRCT2::PathFinding * rct2: 0x0069A997 */ static void PeepPathfindHeuristicSearch( - TileCoordsXYZ loc, const TileCoordsXYZ& goal, const Peep& peep, TileElement* currentTileElement, - const bool inPatrolArea, uint8_t numSteps, uint16_t* endScore, Direction testEdge, uint8_t* endJunctions, - TileCoordsXYZ junctionList[16], uint8_t directionList[16], TileCoordsXYZ* endXYZ, uint8_t* endSteps) + PathFindingState& state, TileCoordsXYZ loc, const TileCoordsXYZ& goal, const Peep& peep, + TileElement* currentTileElement, const bool inPatrolArea, uint8_t numSteps, uint16_t* endScore, Direction testEdge, + uint8_t* endJunctions, TileCoordsXYZ junctionList[16], uint8_t directionList[16], TileCoordsXYZ* endXYZ, + uint8_t* endSteps) { PathSearchResult searchResult = PathSearchResult::Failed; @@ -721,12 +725,12 @@ namespace OpenRCT2::PathFinding loc += TileDirectionDelta[testEdge]; ++numSteps; - _peepPathFindTilesChecked--; + state.countTilesChecked--; /* If this is where the search started this is a search loop and the * current search path ends here. * Return without updating the parameters (best result so far). */ - if (_peepPathFindHistory[0].location == loc) + if (state.history[0].location == loc) { LogPathfinding(&peep, "Return from %d,%d,%d; Steps: %u; At start", loc.x >> 5, loc.y >> 5, loc.z, numSteps); return; @@ -910,14 +914,14 @@ namespace OpenRCT2::PathFinding // Update the end x,y,z *endXYZ = loc; // Update the telemetry - *endJunctions = _peepPathFindMaxJunctions - _peepPathFindNumJunctions; + *endJunctions = state.maxJunctions - state.junctionCount; for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++) { - uint8_t histIdx = _peepPathFindMaxJunctions - junctInd; - junctionList[junctInd].x = _peepPathFindHistory[histIdx].location.x; - junctionList[junctInd].y = _peepPathFindHistory[histIdx].location.y; - junctionList[junctInd].z = _peepPathFindHistory[histIdx].location.z; - directionList[junctInd] = _peepPathFindHistory[histIdx].direction; + uint8_t histIdx = state.maxJunctions - junctInd; + junctionList[junctInd].x = state.history[histIdx].location.x; + junctionList[junctInd].y = state.history[histIdx].location.y; + junctionList[junctInd].z = state.history[histIdx].location.z; + directionList[junctInd] = state.history[histIdx].direction; } } LogPathfinding( @@ -961,14 +965,14 @@ namespace OpenRCT2::PathFinding // Update the end x,y,z *endXYZ = loc; // Update the telemetry - *endJunctions = _peepPathFindMaxJunctions - _peepPathFindNumJunctions; + *endJunctions = state.maxJunctions - state.junctionCount; for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++) { - uint8_t histIdx = _peepPathFindMaxJunctions - junctInd; - junctionList[junctInd].x = _peepPathFindHistory[histIdx].location.x; - junctionList[junctInd].y = _peepPathFindHistory[histIdx].location.y; - junctionList[junctInd].z = _peepPathFindHistory[histIdx].location.z; - directionList[junctInd] = _peepPathFindHistory[histIdx].direction; + uint8_t histIdx = state.maxJunctions - junctInd; + junctionList[junctInd].x = state.history[histIdx].location.x; + junctionList[junctInd].y = state.history[histIdx].location.y; + junctionList[junctInd].z = state.history[histIdx].location.z; + directionList[junctInd] = state.history[histIdx].direction; } } LogPathfinding( @@ -1004,7 +1008,7 @@ namespace OpenRCT2::PathFinding /* Check if either of the search limits has been reached: * - max number of steps or max tiles checked. */ - if (numSteps >= 200 || _peepPathFindTilesChecked <= 0) + if (numSteps >= 200 || state.countTilesChecked <= 0) { /* The current search ends here. * The path continues, so the goal could still be reachable from here. @@ -1018,14 +1022,14 @@ namespace OpenRCT2::PathFinding // Update the end x,y,z *endXYZ = loc; // Update the telemetry - *endJunctions = _peepPathFindMaxJunctions - _peepPathFindNumJunctions; + *endJunctions = state.maxJunctions - state.junctionCount; for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++) { - uint8_t histIdx = _peepPathFindMaxJunctions - junctInd; - junctionList[junctInd].x = _peepPathFindHistory[histIdx].location.x; - junctionList[junctInd].y = _peepPathFindHistory[histIdx].location.y; - junctionList[junctInd].z = _peepPathFindHistory[histIdx].location.z; - directionList[junctInd] = _peepPathFindHistory[histIdx].direction; + uint8_t histIdx = state.maxJunctions - junctInd; + junctionList[junctInd].x = state.history[histIdx].location.x; + junctionList[junctInd].y = state.history[histIdx].location.y; + junctionList[junctInd].z = state.history[histIdx].location.z; + directionList[junctInd] = state.history[histIdx].direction; } } LogPathfinding( @@ -1083,10 +1087,9 @@ namespace OpenRCT2::PathFinding /* Check the _peepPathFindHistory to see if this junction has been * previously passed through in the current search path. * i.e. this is a loop in the current search path. */ - for (int32_t junctionNum = _peepPathFindNumJunctions + 1; junctionNum <= _peepPathFindMaxJunctions; - junctionNum++) + for (int32_t junctionNum = state.junctionCount + 1; junctionNum <= state.maxJunctions; junctionNum++) { - if (_peepPathFindHistory[junctionNum].location == loc) + if (state.history[junctionNum].location == loc) { pathLoop = true; break; @@ -1107,7 +1110,7 @@ namespace OpenRCT2::PathFinding * be reachable from here. * If the search result is better than the best so far (in the parameters), * then update the parameters with this search before continuing to the next map element. */ - if (_peepPathFindNumJunctions <= 0) + if (state.junctionCount <= 0) { if (newScore < *endScore || (newScore == *endScore && numSteps < *endSteps)) { @@ -1117,12 +1120,12 @@ namespace OpenRCT2::PathFinding // Update the end x,y,z *endXYZ = loc; // Update the telemetry - *endJunctions = _peepPathFindMaxJunctions; // - _peepPathFindNumJunctions; + *endJunctions = state.maxJunctions; // - _peepPathFindNumJunctions; for (uint8_t junctInd = 0; junctInd < *endJunctions; junctInd++) { - uint8_t histIdx = _peepPathFindMaxJunctions - junctInd; - junctionList[junctInd] = _peepPathFindHistory[histIdx].location; - directionList[junctInd] = _peepPathFindHistory[histIdx].direction; + uint8_t histIdx = state.maxJunctions - junctInd; + junctionList[junctInd] = state.history[histIdx].location; + directionList[junctInd] = state.history[histIdx].direction; } } LogPathfinding( @@ -1133,10 +1136,10 @@ namespace OpenRCT2::PathFinding /* This junction was NOT previously visited in the current * search path, so add the junction to the history. */ - _peepPathFindHistory[_peepPathFindNumJunctions].location = loc; + state.history[state.junctionCount].location = loc; // .direction take is added below. - _peepPathFindNumJunctions--; + state.junctionCount--; } } @@ -1145,7 +1148,7 @@ namespace OpenRCT2::PathFinding do { edges &= ~(1 << nextTestEdge); - uint8_t savedNumJunctions = _peepPathFindNumJunctions; + uint8_t savedNumJunctions = state.junctionCount; uint8_t height = loc.z; if (tileElement->AsPath()->IsSloped() && tileElement->AsPath()->GetSlopeDirection() == nextTestEdge) @@ -1177,13 +1180,13 @@ namespace OpenRCT2::PathFinding if (isThinJunction) { /* Add the current test_edge to the history. */ - _peepPathFindHistory[_peepPathFindNumJunctions + 1].direction = nextTestEdge; + state.history[state.junctionCount + 1].direction = nextTestEdge; } PeepPathfindHeuristicSearch( - { loc.x, loc.y, height }, goal, peep, tileElement, nextInPatrolArea, numSteps, endScore, nextTestEdge, - endJunctions, junctionList, directionList, endXYZ, endSteps); - _peepPathFindNumJunctions = savedNumJunctions; + state, { loc.x, loc.y, height }, goal, peep, tileElement, nextInPatrolArea, numSteps, endScore, + nextTestEdge, endJunctions, junctionList, directionList, endXYZ, endSteps); + state.junctionCount = savedNumJunctions; LogPathfinding( &peep, "Returned to %d,%d,%d; Steps: %u; edge: %d; Score: %d", loc.x >> 5, loc.y >> 5, loc.z, numSteps, @@ -1218,8 +1221,10 @@ namespace OpenRCT2::PathFinding { PROFILED_FUNCTION(); + PathFindingState state{}; + // The max number of thin junctions searched - a per-search-path limit. - _peepPathFindMaxJunctions = PeepPathfindGetMaxNumberJunctions(peep); + state.maxJunctions = PeepPathfindGetMaxNumberJunctions(peep); /* The max number of tiles to check - a whole-search limit. * Mainly to limit the performance impact of the path finding. */ @@ -1388,12 +1393,12 @@ namespace OpenRCT2::PathFinding /* Divide the maxTilesChecked global search limit * between the remaining edges to ensure the search * covers all of the remaining edges. */ - _peepPathFindTilesChecked = maxTilesChecked / numEdges; - _peepPathFindNumJunctions = _peepPathFindMaxJunctions; + state.countTilesChecked = maxTilesChecked / numEdges; + state.junctionCount = state.maxJunctions; // Initialise _peepPathFindHistory. - for (auto& entry : _peepPathFindHistory) + for (auto& entry : state.history) { entry.location.SetNull(); entry.direction = INVALID_DIRECTION; @@ -1402,8 +1407,8 @@ namespace OpenRCT2::PathFinding /* The pathfinding will only use elements * 1.._peepPathFindMaxJunctions, so the starting point * is placed in element 0 */ - _peepPathFindHistory[0].location = loc; - _peepPathFindHistory[0].direction = 0xF; + state.history[0].location = loc; + state.history[0].direction = 0xF; uint16_t score = 0xFFFF; /* Variable endXYZ contains the end location of the @@ -1440,8 +1445,8 @@ namespace OpenRCT2::PathFinding &peep, "Pathfind searching in direction: %d from %d,%d,%d", testEdge, loc.x >> 5, loc.y >> 5, loc.z); PeepPathfindHeuristicSearch( - { loc.x, loc.y, height }, goal, peep, firstTileElement, inPatrolArea, 0, &score, testEdge, &endJunctions, - endJunctionList, endDirectionList, &endXYZ, &endSteps); + state, { loc.x, loc.y, height }, goal, peep, firstTileElement, inPatrolArea, 0, &score, testEdge, + &endJunctions, endJunctionList, endDirectionList, &endXYZ, &endSteps); if constexpr (kLogPathfinding) { From fdff60552b9aba7c765efe8a091c787a316f5e71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:36:01 +0300 Subject: [PATCH 2/5] Reduce memory footprint for history, cleanup code --- src/openrct2/peep/GuestPathfinding.cpp | 37 ++++++++++++++++---------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 97cd396544..193c7f8401 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -33,21 +33,29 @@ RideId gPeepPathFindQueueRideIndex; namespace OpenRCT2::PathFinding { + // The search limits the maximum junctions by certain conditions. + static constexpr uint8_t kMaxJunctionsStaff = 8; + static constexpr uint8_t kMaxJunctionsGuest = 5; + static constexpr uint8_t kMaxJunctionsGuestWithMap = 7; + static constexpr uint8_t kMaxJunctionsGuestLeavingPark = 7; + static constexpr uint8_t kMaxJunctionsGuestLeavingParkLost = 8; + + // Maximum amount of junctions. + static constexpr uint8_t kMaxJunctions = std::max({ kMaxJunctionsStaff, kMaxJunctionsGuest, kMaxJunctionsGuestWithMap, + kMaxJunctionsGuestLeavingPark, kMaxJunctionsGuestLeavingParkLost }); + struct PathFindingState { int8_t junctionCount; int8_t maxJunctions; int32_t countTilesChecked; - /* A junction history for the peep pathfinding heuristic search - * The magic number 16 is the largest value returned by - * PeepPathfindGetMaxNumberJunctions() which should eventually - * be declared properly. */ + // A junction history for the peep path finding heuristic search. struct { TileCoordsXYZ location; Direction direction; - } history[16]; + } history[kMaxJunctions + 1]; }; static int32_t GuestSurfacePathFinding(Peep& peep); @@ -553,24 +561,25 @@ namespace OpenRCT2::PathFinding static uint8_t PeepPathfindGetMaxNumberJunctions(Peep& peep) { if (peep.Is()) - return 8; + return kMaxJunctionsStaff; auto* guest = peep.As(); if (guest == nullptr) - return 8; + return kMaxJunctionsStaff; - if (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK && guest->GuestIsLostCountdown < 90) + bool isLeavingPark = (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK) != 0; + if (isLeavingPark && guest->GuestIsLostCountdown < 90) { - return 8; + return kMaxJunctionsGuestLeavingParkLost; } + if (isLeavingPark) + return kMaxJunctionsGuestLeavingPark; + if (guest->HasItem(ShopItem::Map)) - return 7; + return kMaxJunctionsGuestWithMap; - if (guest->PeepFlags & PEEP_FLAGS_LEAVING_PARK) - return 7; - - return 5; + return kMaxJunctionsGuest; } /** From bc1f2f62cfdee270d5912ff44d1861013601e943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Mon, 30 Sep 2024 12:53:12 +0300 Subject: [PATCH 3/5] Rename IsValidPathZAndDirection and move to more appropriate place --- src/openrct2/entity/Staff.cpp | 2 +- src/openrct2/peep/GuestPathfinding.cpp | 33 +++----------------------- src/openrct2/peep/GuestPathfinding.h | 2 -- src/openrct2/world/Footpath.cpp | 27 +++++++++++++++++++++ src/openrct2/world/Footpath.h | 1 + 5 files changed, 32 insertions(+), 33 deletions(-) diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index 4cdbb2daa9..d6467c1eba 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -183,7 +183,7 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons } /* test_element is a path */ - if (!PathFinding::IsValidPathZAndDirection(test_element, adjacPos.z / kCoordsZStep, adjac_dir)) + if (!FootpathIsZAndDirectionValid(test_element, adjacPos.z / kCoordsZStep, adjac_dir)) continue; /* test_element is a connected path */ diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 193c7f8401..18cb488b92 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -359,7 +359,7 @@ namespace OpenRCT2::PathFinding continue; if (nextTileElement->GetType() != TileElementType::Path) continue; - if (!IsValidPathZAndDirection(nextTileElement, loc.z, chosenDirection)) + if (!FootpathIsZAndDirectionValid(nextTileElement, loc.z, chosenDirection)) continue; if (nextTileElement->AsPath()->IsWide()) return PathSearchResult::Wide; @@ -453,7 +453,7 @@ namespace OpenRCT2::PathFinding break; case TileElementType::Path: { - if (!IsValidPathZAndDirection(tileElement, loc.z, chosenDirection)) + if (!FootpathIsZAndDirectionValid(tileElement, loc.z, chosenDirection)) continue; if (tileElement->AsPath()->IsWide()) return PathSearchResult::Wide; @@ -845,7 +845,7 @@ namespace OpenRCT2::PathFinding * queue path. * Otherwise, peeps walk on path tiles to get to the goal. */ - if (!IsValidPathZAndDirection(tileElement, loc.z, testEdge)) + if (!FootpathIsZAndDirectionValid(tileElement, loc.z, testEdge)) continue; // Path may be sloped, so set z to path base height. @@ -2134,31 +2134,4 @@ namespace OpenRCT2::PathFinding return PeepMoveOneTile(direction, peep); } - bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection) - { - if (tileElement->AsPath()->IsSloped()) - { - int32_t slopeDirection = tileElement->AsPath()->GetSlopeDirection(); - if (slopeDirection == currentDirection) - { - if (currentZ != tileElement->BaseHeight) - return false; - } - else - { - slopeDirection = DirectionReverse(slopeDirection); - if (slopeDirection != currentDirection) - return false; - if (currentZ != tileElement->BaseHeight + 2) - return false; - } - } - else - { - if (currentZ != tileElement->BaseHeight) - return false; - } - return true; - } - } // namespace OpenRCT2::PathFinding diff --git a/src/openrct2/peep/GuestPathfinding.h b/src/openrct2/peep/GuestPathfinding.h index 7b691ee384..d098dc6df5 100644 --- a/src/openrct2/peep/GuestPathfinding.h +++ b/src/openrct2/peep/GuestPathfinding.h @@ -43,6 +43,4 @@ namespace OpenRCT2::PathFinding int32_t GuestPathFindParkEntranceLeaving(Peep& peep, uint8_t edges); - bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection); - }; // namespace OpenRCT2::PathFinding diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 7a1d796c56..ab04c066f1 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -2328,3 +2328,30 @@ bool PathElement::IsLevelCrossing(const CoordsXY& coords) const return ride->GetRideTypeDescriptor().HasFlag(RtdFlag::supportsLevelCrossings); } + +bool FootpathIsZAndDirectionValid(TileElement* tileElement, int32_t currentZ, int32_t currentDirection) +{ + if (tileElement->AsPath()->IsSloped()) + { + int32_t slopeDirection = tileElement->AsPath()->GetSlopeDirection(); + if (slopeDirection == currentDirection) + { + if (currentZ != tileElement->BaseHeight) + return false; + } + else + { + slopeDirection = DirectionReverse(slopeDirection); + if (slopeDirection != currentDirection) + return false; + if (currentZ != tileElement->BaseHeight + 2) + return false; + } + } + else + { + if (currentZ != tileElement->BaseHeight) + return false; + } + return true; +} diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 7096449aff..a0430b323e 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -186,3 +186,4 @@ const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex); void FootpathQueueChainReset(); void FootpathQueueChainPush(RideId rideIndex); +bool FootpathIsZAndDirectionValid(TileElement* tileElement, int32_t currentZ, int32_t currentDirection); From 3755f3a6d1f1ff8393289137c6f9683835290609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:10:14 +0300 Subject: [PATCH 4/5] Remove two more globals, pass them as arguments --- src/openrct2/entity/Staff.cpp | 5 +--- src/openrct2/peep/GuestPathfinding.cpp | 39 +++++++++----------------- src/openrct2/peep/GuestPathfinding.h | 16 ++--------- test/tests/Pathfinding.cpp | 2 +- 4 files changed, 18 insertions(+), 44 deletions(-) diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index d6467c1eba..8e959f9ae0 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -713,11 +713,8 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat } } - gPeepPathFindIgnoreForeignQueues = false; - gPeepPathFindQueueRideIndex = RideId::GetNull(); - const auto goalPos = TileCoordsXYZ{ location }; - Direction pathfindDirection = PathFinding::ChooseDirection(TileCoordsXYZ{ NextLoc }, goalPos, *this); + Direction pathfindDirection = PathFinding::ChooseDirection(TileCoordsXYZ{ NextLoc }, goalPos, *this, false, RideId::GetNull()); if (pathfindDirection == INVALID_DIRECTION) { /* Heuristic search failed for all directions. diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 18cb488b92..0b2b111f4d 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -28,9 +28,6 @@ #include #include -bool gPeepPathFindIgnoreForeignQueues; -RideId gPeepPathFindQueueRideIndex; - namespace OpenRCT2::PathFinding { // The search limits the maximum junctions by certain conditions. @@ -49,7 +46,9 @@ namespace OpenRCT2::PathFinding int8_t junctionCount; int8_t maxJunctions; int32_t countTilesChecked; - + // TODO: Move them, those are query parameters not really state, but for now its easier to pass it down. + bool ignoreForeignQueues; + RideId queueRideIndex; // A junction history for the peep path finding heuristic search. struct { @@ -877,9 +876,9 @@ namespace OpenRCT2::PathFinding else { // numEdges == 2 if (tileElement->AsPath()->IsQueue() - && tileElement->AsPath()->GetRideIndex() != gPeepPathFindQueueRideIndex) + && tileElement->AsPath()->GetRideIndex() != state.queueRideIndex) { - if (gPeepPathFindIgnoreForeignQueues && !tileElement->AsPath()->GetRideIndex().IsNull()) + if (state.ignoreForeignQueues && !tileElement->AsPath()->GetRideIndex().IsNull()) { // Path is a queue we aren't interested in /* The rideIndex will be useful for @@ -1226,12 +1225,16 @@ namespace OpenRCT2::PathFinding * * rct2: 0x0069A5F0 */ - Direction ChooseDirection(const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep) + Direction ChooseDirection( + const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep, bool ignoreForeignQueues, RideId queueRideIndex) { PROFILED_FUNCTION(); PathFindingState state{}; + state.ignoreForeignQueues = ignoreForeignQueues; + state.queueRideIndex = queueRideIndex; + // The max number of thin junctions searched - a per-search-path limit. state.maxJunctions = PeepPathfindGetMaxNumberJunctions(peep); @@ -1590,11 +1593,8 @@ namespace OpenRCT2::PathFinding if (!chosenEntrance.has_value()) return GuestPathfindAimless(peep, edges); - gPeepPathFindIgnoreForeignQueues = true; - gPeepPathFindQueueRideIndex = RideId::GetNull(); - const auto goalPos = TileCoordsXYZ(chosenEntrance.value()); - Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep); + Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep, true, RideId::GetNull()); if (chosenDirection == INVALID_DIRECTION) return GuestPathfindAimless(peep, edges); @@ -1647,11 +1647,8 @@ namespace OpenRCT2::PathFinding return PeepMoveOneTile(direction, peep); } - gPeepPathFindIgnoreForeignQueues = true; - gPeepPathFindQueueRideIndex = RideId::GetNull(); - const auto goalPos = TileCoordsXYZ(peepSpawnLoc); - direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep); + direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, goalPos, peep, true, RideId::GetNull()); if (direction == INVALID_DIRECTION) return GuestPathfindAimless(peep, edges); @@ -1687,10 +1684,7 @@ namespace OpenRCT2::PathFinding entranceGoal = TileCoordsXYZ(*chosenEntrance); } - gPeepPathFindIgnoreForeignQueues = true; - gPeepPathFindQueueRideIndex = RideId::GetNull(); - - Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, entranceGoal, peep); + Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, entranceGoal, peep, true, RideId::GetNull()); if (chosenDirection == INVALID_DIRECTION) return GuestPathfindAimless(peep, edges); @@ -2049,9 +2043,6 @@ namespace OpenRCT2::PathFinding return GuestPathfindAimless(peep, edges); } - // The ride is open. - gPeepPathFindQueueRideIndex = rideIndex; - /* Find the ride's closest entrance station to the peep. * At the same time, count how many entrance stations there are and * which stations are entrance stations. */ @@ -2110,9 +2101,7 @@ namespace OpenRCT2::PathFinding GetRideQueueEnd(loc); - gPeepPathFindIgnoreForeignQueues = true; - - direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, loc, peep); + direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, loc, peep, true, rideIndex); if (direction == INVALID_DIRECTION) { diff --git a/src/openrct2/peep/GuestPathfinding.h b/src/openrct2/peep/GuestPathfinding.h index d098dc6df5..11a986e2ed 100644 --- a/src/openrct2/peep/GuestPathfinding.h +++ b/src/openrct2/peep/GuestPathfinding.h @@ -18,22 +18,10 @@ struct Peep; struct Guest; struct TileElement; -// When the heuristic pathfinder is examining neighboring tiles, one possibility is that it finds a -// queue tile; furthermore, this queue tile may or may not be for the ride that the peep is trying -// to get to, if any. This first var is used to store the ride that the peep is currently headed to. -extern RideId gPeepPathFindQueueRideIndex; - -// Furthermore, staff members don't care about this stuff; even if they are e.g. a mechanic headed -// to a particular ride, they have no issues with walking over queues for other rides to get there. -// This bool controls that behaviour - if true, the peep will not path over queues for rides other -// than their target ride, and if false, they will treat it like a regular path. -// -// In practice, if this is false, gPeepPathFindQueueRideIndex is always RIDE_ID_NULL. -extern bool gPeepPathFindIgnoreForeignQueues; - namespace OpenRCT2::PathFinding { - Direction ChooseDirection(const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep); + Direction ChooseDirection( + const TileCoordsXYZ& loc, const TileCoordsXYZ& goal, Peep& peep, bool ignoreForeignQueues, RideId queueRideIndex); int32_t CalculateNextDestination(Guest& peep); diff --git a/test/tests/Pathfinding.cpp b/test/tests/Pathfinding.cpp index 6efaec4f6a..a9d84a5407 100644 --- a/test/tests/Pathfinding.cpp +++ b/test/tests/Pathfinding.cpp @@ -85,7 +85,7 @@ protected: // Pick the direction the peep should initially move in, given the goal position. // This will also store the goal position and initialize pathfinding data for the peep. - const Direction moveDir = PathFinding::ChooseDirection(*pos, goal, *peep); + const Direction moveDir = PathFinding::ChooseDirection(*pos, goal, *peep, false, RideId::GetNull()); if (moveDir == INVALID_DIRECTION) { // Couldn't determine a direction to move off in From 763e9968cf11aff6f36f9f61404cfe8f674ef85a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Mon, 30 Sep 2024 13:24:04 +0300 Subject: [PATCH 5/5] Refactor FootpathIsZAndDirectionValid and its uses, more constness --- src/openrct2/entity/Staff.cpp | 8 +++--- src/openrct2/peep/GuestPathfinding.cpp | 37 +++++++++++++------------- src/openrct2/world/Footpath.cpp | 12 ++++----- src/openrct2/world/Footpath.h | 2 +- 4 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index 8e959f9ae0..fb88e5f494 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -183,7 +183,8 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons } /* test_element is a path */ - if (!FootpathIsZAndDirectionValid(test_element, adjacPos.z / kCoordsZStep, adjac_dir)) + const auto* adjacentPathElement = test_element->AsPath(); + if (!FootpathIsZAndDirectionValid(*adjacentPathElement, adjacPos.z / kCoordsZStep, adjac_dir)) continue; /* test_element is a connected path */ @@ -193,7 +194,7 @@ bool Staff::CanIgnoreWideFlag(const CoordsXYZ& staffPos, TileElement* path) cons pathcount++; } - if (test_element->AsPath()->IsWide()) + if (adjacentPathElement->IsWide()) { if (!widefound) { @@ -714,7 +715,8 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat } const auto goalPos = TileCoordsXYZ{ location }; - Direction pathfindDirection = PathFinding::ChooseDirection(TileCoordsXYZ{ NextLoc }, goalPos, *this, false, RideId::GetNull()); + Direction pathfindDirection = PathFinding::ChooseDirection( + TileCoordsXYZ{ NextLoc }, goalPos, *this, false, RideId::GetNull()); if (pathfindDirection == INVALID_DIRECTION) { /* Heuristic search failed for all directions. diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 0b2b111f4d..d0cec670cc 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -140,14 +140,14 @@ namespace OpenRCT2::PathFinding } #pragma endregion - static TileElement* GetBannerOnPath(TileElement* pathElement) + static const TileElement* GetBannerOnPath(const TileElement* pathElement) { // This is an improved version of original. // That only checked for one fence in the way. if (pathElement->IsLastForTile()) return nullptr; - TileElement* bannerElement = pathElement + 1; + const TileElement* bannerElement = pathElement + 1; do { // Path on top, so no banners @@ -165,11 +165,11 @@ namespace OpenRCT2::PathFinding return nullptr; } - static int32_t BannerClearPathEdges(bool ignoreBanners, PathElement* pathElement, int32_t edges) + static int32_t BannerClearPathEdges(bool ignoreBanners, const PathElement* pathElement, int32_t edges) { if (ignoreBanners) return edges; - TileElement* bannerElement = GetBannerOnPath(reinterpret_cast(pathElement)); + const TileElement* bannerElement = GetBannerOnPath(reinterpret_cast(pathElement)); if (bannerElement != nullptr) { do @@ -183,7 +183,7 @@ namespace OpenRCT2::PathFinding /** * Gets the connected edges of a path that are permitted (i.e. no 'no entry' signs) */ - static int32_t PathGetPermittedEdges(bool ignoreBanners, PathElement* pathElement) + static int32_t PathGetPermittedEdges(bool ignoreBanners, const PathElement* pathElement) { return BannerClearPathEdges(ignoreBanners, pathElement, pathElement->GetEdgesAndCorners()) & 0x0F; } @@ -358,12 +358,13 @@ namespace OpenRCT2::PathFinding continue; if (nextTileElement->GetType() != TileElementType::Path) continue; - if (!FootpathIsZAndDirectionValid(nextTileElement, loc.z, chosenDirection)) + const auto* nextPathElement = nextTileElement->AsPath(); + if (!FootpathIsZAndDirectionValid(*nextPathElement, loc.z, chosenDirection)) continue; - if (nextTileElement->AsPath()->IsWide()) + if (nextPathElement->IsWide()) return PathSearchResult::Wide; // Only queue tiles that are connected to a ride are returned as ride queues. - if (nextTileElement->AsPath()->IsQueue() && !nextTileElement->AsPath()->GetRideIndex().IsNull()) + if (nextPathElement->IsQueue() && !nextPathElement->GetRideIndex().IsNull()) return PathSearchResult::RideQueue; return PathSearchResult::Other; @@ -452,12 +453,13 @@ namespace OpenRCT2::PathFinding break; case TileElementType::Path: { - if (!FootpathIsZAndDirectionValid(tileElement, loc.z, chosenDirection)) + const auto* pathElement = tileElement->AsPath(); + if (!FootpathIsZAndDirectionValid(*pathElement, loc.z, chosenDirection)) continue; if (tileElement->AsPath()->IsWide()) return PathSearchResult::Wide; - uint8_t edges = PathGetPermittedEdges(ignoreBanners, tileElement->AsPath()); + uint8_t edges = PathGetPermittedEdges(ignoreBanners, pathElement); edges &= ~(1 << DirectionReverse(chosenDirection)); loc.z = tileElement->BaseHeight; @@ -840,17 +842,17 @@ namespace OpenRCT2::PathFinding break; case TileElementType::Path: { + const auto* pathElement = tileElement->AsPath(); /* For peeps heading for a ride with a queue, the goal is the last * queue path. * Otherwise, peeps walk on path tiles to get to the goal. */ - - if (!FootpathIsZAndDirectionValid(tileElement, loc.z, testEdge)) + if (!FootpathIsZAndDirectionValid(*pathElement, loc.z, testEdge)) continue; // Path may be sloped, so set z to path base height. loc.z = tileElement->BaseHeight; - if (tileElement->AsPath()->IsWide()) + if (pathElement->IsWide()) { /* Check if staff can ignore this wide flag. */ if (staff == nullptr || !staff->CanIgnoreWideFlag(loc.ToCoordsXYZ(), tileElement)) @@ -863,7 +865,7 @@ namespace OpenRCT2::PathFinding searchResult = PathSearchResult::Thin; - uint8_t numEdges = std::popcount(tileElement->AsPath()->GetEdges()); + uint8_t numEdges = std::popcount(pathElement->GetEdges()); if (numEdges < 2) { @@ -875,15 +877,14 @@ namespace OpenRCT2::PathFinding } else { // numEdges == 2 - if (tileElement->AsPath()->IsQueue() - && tileElement->AsPath()->GetRideIndex() != state.queueRideIndex) + if (pathElement->IsQueue() && pathElement->GetRideIndex() != state.queueRideIndex) { - if (state.ignoreForeignQueues && !tileElement->AsPath()->GetRideIndex().IsNull()) + if (state.ignoreForeignQueues && !pathElement->GetRideIndex().IsNull()) { // Path is a queue we aren't interested in /* The rideIndex will be useful for * adding transport rides later. */ - rideIndex = tileElement->AsPath()->GetRideIndex(); + rideIndex = pathElement->GetRideIndex(); searchResult = PathSearchResult::RideQueue; } } diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index ab04c066f1..9a74e0d680 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -2329,14 +2329,14 @@ bool PathElement::IsLevelCrossing(const CoordsXY& coords) const return ride->GetRideTypeDescriptor().HasFlag(RtdFlag::supportsLevelCrossings); } -bool FootpathIsZAndDirectionValid(TileElement* tileElement, int32_t currentZ, int32_t currentDirection) +bool FootpathIsZAndDirectionValid(const PathElement& pathElement, int32_t currentZ, int32_t currentDirection) { - if (tileElement->AsPath()->IsSloped()) + if (pathElement.IsSloped()) { - int32_t slopeDirection = tileElement->AsPath()->GetSlopeDirection(); + int32_t slopeDirection = pathElement.GetSlopeDirection(); if (slopeDirection == currentDirection) { - if (currentZ != tileElement->BaseHeight) + if (currentZ != pathElement.BaseHeight) return false; } else @@ -2344,13 +2344,13 @@ bool FootpathIsZAndDirectionValid(TileElement* tileElement, int32_t currentZ, in slopeDirection = DirectionReverse(slopeDirection); if (slopeDirection != currentDirection) return false; - if (currentZ != tileElement->BaseHeight + 2) + if (currentZ != pathElement.BaseHeight + 2) return false; } } else { - if (currentZ != tileElement->BaseHeight) + if (currentZ != pathElement.BaseHeight) return false; } return true; diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index a0430b323e..9db7eedced 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -186,4 +186,4 @@ const FootpathRailingsObject* GetPathRailingsEntry(ObjectEntryIndex entryIndex); void FootpathQueueChainReset(); void FootpathQueueChainPush(RideId rideIndex); -bool FootpathIsZAndDirectionValid(TileElement* tileElement, int32_t currentZ, int32_t currentDirection); +bool FootpathIsZAndDirectionValid(const PathElement& tileElement, int32_t currentZ, int32_t currentDirection);