From fa71bbc1b2541fee78326826ae5eae80b3bf35d7 Mon Sep 17 00:00:00 2001 From: LordOfLunacy <64547205+LordOfLunacy@users.noreply.github.com> Date: Sat, 14 May 2022 15:28:24 -0400 Subject: [PATCH] Implement requested changes - Change the GuestPathfinder object to a smart pointer - Improved function signatures - Added javadoc comments to the abstract base class - Converted pointers to references in pathfinding function calls --- src/openrct2/GameState.cpp | 3 - src/openrct2/entity/Peep.cpp | 4 +- src/openrct2/entity/Peep.h | 2 +- src/openrct2/entity/Staff.cpp | 8 +- src/openrct2/peep/GuestPathfinding.cpp | 206 +++++++++++++------------ src/openrct2/peep/GuestPathfinding.h | 51 +++--- test/tests/Pathfinding.cpp | 2 +- 7 files changed, 145 insertions(+), 131 deletions(-) diff --git a/src/openrct2/GameState.cpp b/src/openrct2/GameState.cpp index 70ec004eda..11b4740a42 100644 --- a/src/openrct2/GameState.cpp +++ b/src/openrct2/GameState.cpp @@ -89,9 +89,6 @@ void GameState::InitAll(const TileCoordsXY& mapSize) CheatsReset(); ClearRestrictedScenery(); - // TODO: find a better place for this - gGuestPathfinder = new OriginalPathfinding(); - #ifdef ENABLE_SCRIPTING auto& scriptEngine = GetContext()->GetScriptEngine(); scriptEngine.ClearParkStorage(); diff --git a/src/openrct2/entity/Peep.cpp b/src/openrct2/entity/Peep.cpp index bdf0fd01b2..3e2e6b28a7 100644 --- a/src/openrct2/entity/Peep.cpp +++ b/src/openrct2/entity/Peep.cpp @@ -73,6 +73,8 @@ uint32_t gNextGuestNumber; uint8_t gPeepWarningThrottle[16]; +std::unique_ptr gGuestPathfinder = std::make_unique(); + static uint8_t _unk_F1AEF0; static TileElement* _peepRideEntranceExitElement; @@ -2357,7 +2359,7 @@ void Peep::PerformNextAction(uint8_t& pathing_result, TileElement*& tile_result) if (guest != nullptr) { - result = gGuestPathfinder->guest_path_finding(guest); + result = gGuestPathfinder->CalculateNextDestination(*guest); } else { diff --git a/src/openrct2/entity/Peep.h b/src/openrct2/entity/Peep.h index 9ba98efbbb..cedab9a448 100644 --- a/src/openrct2/entity/Peep.h +++ b/src/openrct2/entity/Peep.h @@ -399,7 +399,7 @@ public: // Peep bool IsActionInterruptable() const; // Reset the peep's stored goal, which means they will forget any stored pathfinding history - // on the next GuestPathfinding::peep_pathfind_choose_direction call. + // on the next GuestPathfinding::ChooseDirection call. void ResetPathfindGoal(); void SetDestination(const CoordsXY& coords); diff --git a/src/openrct2/entity/Staff.cpp b/src/openrct2/entity/Staff.cpp index ae9a54904c..7d34236353 100644 --- a/src/openrct2/entity/Staff.cpp +++ b/src/openrct2/entity/Staff.cpp @@ -66,8 +66,6 @@ colour_t gStaffHandymanColour; colour_t gStaffMechanicColour; colour_t gStaffSecurityColour; -GuestPathfinding* gGuestPathfinder; - // Maximum manhattan distance that litter can be for a handyman to seek to it const uint16_t MAX_LITTER_DISTANCE = 3 * COORDS_XY_STEP; @@ -721,10 +719,10 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat gPeepPathFindQueueRideIndex = RideId::GetNull(); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - PathfindLoggingEnable(this); + PathfindLoggingEnable(*this); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - Direction pathfindDirection = gGuestPathfinder->peep_pathfind_choose_direction(TileCoordsXYZ{ NextLoc }, this); + Direction pathfindDirection = gGuestPathfinder->ChooseDirection(TileCoordsXYZ{ NextLoc }, *this); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 PathfindLoggingDisable(); @@ -734,7 +732,7 @@ Direction Staff::MechanicDirectionPath(uint8_t validDirections, PathElement* pat { /* Heuristic search failed for all directions. * Reset the PathfindGoal - this means that the PathfindHistory - * will be reset in the next call to GuestPathfinding::peep_pathfind_choose_direction(). + * will be reset in the next call to GuestPathfinding::ChooseDirection(). * This lets the heuristic search "try again" in case the player has * edited the path layout or the mechanic was already stuck in the * save game (e.g. with a worse version of the pathfinding). */ diff --git a/src/openrct2/peep/GuestPathfinding.cpp b/src/openrct2/peep/GuestPathfinding.cpp index 2739153716..71a964d935 100644 --- a/src/openrct2/peep/GuestPathfinding.cpp +++ b/src/openrct2/peep/GuestPathfinding.cpp @@ -43,7 +43,7 @@ static bool _pathFindDebug = false; static utf8 _pathFindDebugPeepName[256]; #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 -static int32_t guest_surface_path_finding(Peep* peep); +static int32_t guest_surface_path_finding(Peep& peep); /* A junction history for the peep pathfinding heuristic search * The magic number 16 is the largest value returned by @@ -124,10 +124,10 @@ static int32_t path_get_permitted_edges(PathElement* pathElement) * * rct2: 0x0069524E */ -static int32_t peep_move_one_tile(Direction direction, Peep* peep) +static int32_t peep_move_one_tile(Direction direction, Peep& peep) { assert(direction_valid(direction)); - auto newTile = CoordsXY{ CoordsXY{ peep->NextLoc } + CoordsDirectionDelta[direction] }.ToTileCentre(); + auto newTile = CoordsXY{ CoordsXY{ peep.NextLoc } + CoordsDirectionDelta[direction] }.ToTileCentre(); if (newTile.x >= MAXIMUM_MAP_SIZE_BIG || newTile.y >= MAXIMUM_MAP_SIZE_BIG) { @@ -135,8 +135,8 @@ static int32_t peep_move_one_tile(Direction direction, Peep* peep) return guest_surface_path_finding(peep); } - peep->PeepDirection = direction; - if (peep->State != PeepState::Queuing) + peep.PeepDirection = direction; + if (peep.State != PeepState::Queuing) { // When peeps are walking along a path, we would like them to be spread out across the width of the path, // instead of all walking along the exact centre line of the path. @@ -159,19 +159,19 @@ static int32_t peep_move_one_tile(Direction direction, Peep* peep) if (direction == 0 || direction == 2) { // Peep is moving along X, so apply the offset to the X position of the destination and clamp their current Y - const int32_t centreLine = (peep->y & 0xFFE0) + COORDS_XY_HALF_TILE; + const int32_t centreLine = (peep.y & 0xFFE0) + COORDS_XY_HALF_TILE; newTile.x += offset; - newTile.y = std::clamp(peep->y, centreLine - 3, centreLine + 3); + newTile.y = std::clamp(peep.y, centreLine - 3, centreLine + 3); } else { // Peep is moving along Y, so apply the offset to the Y position of the destination and clamp their current X - const int32_t centreLine = (peep->x & 0xFFE0) + COORDS_XY_HALF_TILE; - newTile.x = std::clamp(peep->x, centreLine - 3, centreLine + 3); + const int32_t centreLine = (peep.x & 0xFFE0) + COORDS_XY_HALF_TILE; + newTile.x = std::clamp(peep.x, centreLine - 3, centreLine + 3); newTile.y += offset; } } - peep->SetDestination(newTile, 2); + peep.SetDestination(newTile, 2); return 0; } @@ -180,9 +180,9 @@ static int32_t peep_move_one_tile(Direction direction, Peep* peep) * * rct2: 0x00694C41 */ -static int32_t guest_surface_path_finding(Peep* peep) +static int32_t guest_surface_path_finding(Peep& peep) { - auto pathPos = CoordsXYRangedZ{ peep->NextLoc, peep->NextLoc.z, peep->NextLoc.z + PATH_CLEARANCE }; + auto pathPos = CoordsXYRangedZ{ peep.NextLoc, peep.NextLoc.z, peep.NextLoc.z + PATH_CLEARANCE }; Direction randDirection = scenario_rand() & 3; if (!fence_in_the_way(pathPos, randDirection)) @@ -208,8 +208,8 @@ static int32_t guest_surface_path_finding(Peep* peep) } randDirection &= 3; - pathPos.x = peep->NextLoc.x; - pathPos.y = peep->NextLoc.y; + pathPos.x = peep.NextLoc.x; + pathPos.y = peep.NextLoc.y; if (!fence_in_the_way(pathPos, randDirection)) { pathPos.x += CoordsDirectionDelta[randDirection].x; @@ -228,8 +228,8 @@ static int32_t guest_surface_path_finding(Peep* peep) randDirection -= 2; randDirection &= 3; - pathPos.x = peep->NextLoc.x; - pathPos.y = peep->NextLoc.y; + pathPos.x = peep.NextLoc.x; + pathPos.y = peep.NextLoc.y; if (!fence_in_the_way(pathPos, randDirection)) { pathPos.x += CoordsDirectionDelta[randDirection].x; @@ -460,14 +460,14 @@ static uint8_t footpath_element_destination_in_direction( * * rct2: 0x00695225 */ -static int32_t guest_path_find_aimless(Peep* peep, uint8_t edges) +static int32_t guest_path_find_aimless(Peep& peep, uint8_t edges) { if (scenario_rand() & 1) { // If possible go straight - if (edges & (1 << peep->PeepDirection)) + if (edges & (1 << peep.PeepDirection)) { - return peep_move_one_tile(peep->PeepDirection, peep); + return peep_move_one_tile(peep.PeepDirection, peep); } } @@ -486,21 +486,21 @@ static int32_t guest_path_find_aimless(Peep* peep, uint8_t edges) * * rct2: 0x0069A60A */ -static uint8_t peep_pathfind_get_max_number_junctions(Peep* peep) +static uint8_t peep_pathfind_get_max_number_junctions(Peep& peep) { - if (peep->Is()) + if (peep.Is()) return 8; // PEEP_FLAGS_2? It's cleared here but not set anywhere! - if ((peep->PeepFlags & PEEP_FLAGS_2)) + if ((peep.PeepFlags & PEEP_FLAGS_2)) { if ((scenario_rand() & 0xFFFF) <= 7281) - peep->PeepFlags &= ~PEEP_FLAGS_2; + peep.PeepFlags &= ~PEEP_FLAGS_2; return 8; } - auto* guest = peep->As(); + auto* guest = peep.As(); if (guest == nullptr) return 8; @@ -687,7 +687,7 @@ static constexpr const char* pathSearchToString(uint8_t pathFindSearchResult) * rct2: 0x0069A997 */ static void peep_pathfind_heuristic_search( - TileCoordsXYZ loc, Peep* peep, TileElement* currentTileElement, bool inPatrolArea, uint8_t counter, uint16_t* endScore, + TileCoordsXYZ loc, Peep& peep, TileElement* currentTileElement, bool inPatrolArea, uint8_t counter, uint16_t* endScore, Direction test_edge, uint8_t* endJunctions, TileCoordsXYZ junctionList[16], uint8_t directionList[16], TileCoordsXYZ* endXYZ, uint8_t* endSteps) { @@ -696,7 +696,7 @@ static void peep_pathfind_heuristic_search( bool currentElementIsWide = currentTileElement->AsPath()->IsWide(); if (currentElementIsWide) { - const Staff* staff = peep->As(); + const Staff* staff = peep.As(); if (staff != nullptr && staff->CanIgnoreWideFlag(loc.ToCoordsXYZ(), currentTileElement)) currentElementIsWide = false; } @@ -721,7 +721,7 @@ static void peep_pathfind_heuristic_search( } bool nextInPatrolArea = inPatrolArea; - auto* staff = peep->As(); + auto* staff = peep.As(); if (staff != nullptr && staff->IsMechanic()) { nextInPatrolArea = staff->IsLocationInPatrol(loc.ToCoordsXY()); @@ -1075,14 +1075,14 @@ static void peep_pathfind_heuristic_search( /* First check if going through the junction would be * a loop. If so, the current search path ends here. * Path finding loop detection can take advantage of both the - * peep->PathfindHistory - loops through remembered junctions + * peep.PathfindHistory - loops through remembered junctions * the peep has already passed through getting to its * current position while on the way to its current goal; * _peepPathFindHistory - loops in the current search path. */ bool pathLoop = false; - /* Check the peep->PathfindHistory to see if this junction has + /* Check the peep.PathfindHistory to see if this junction has * already been visited by the peep while heading for this goal. */ - for (auto& pathfindHistory : peep->PathfindHistory) + for (auto& pathfindHistory : peep.PathfindHistory) { if (pathfindHistory == loc) { @@ -1261,7 +1261,7 @@ static void peep_pathfind_heuristic_search( * * rct2: 0x0069A5F0 */ -Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) +Direction OriginalPathfinding::ChooseDirection(const TileCoordsXYZ& loc, Peep& peep) { PROFILED_FUNCTION(); @@ -1270,9 +1270,9 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY /* The max number of tiles to check - a whole-search limit. * Mainly to limit the performance impact of the path finding. */ - int32_t maxTilesChecked = (peep->Is()) ? 50000 : 15000; + int32_t maxTilesChecked = (peep.Is()) ? 50000 : 15000; // Used to allow walking through no entry banners - _peepPathFindIsStaff = peep->Is(); + _peepPathFindIsStaff = peep.Is(); TileCoordsXYZ goal = gPeepPathFindGoalPosition; @@ -1322,7 +1322,7 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY } /* Check if this path element is a thin junction. - * Only 'thin' junctions are remembered in peep->PathfindHistory. + * Only 'thin' junctions are remembered in peep.PathfindHistory. * NO attempt is made to merge the overlaid path elements and * check if the combination is 'thin'! * The junction is considered 'thin' simply if any of the @@ -1338,9 +1338,9 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY permitted_edges &= 0xF; uint8_t edges = permitted_edges; - if (isThin && peep->PathfindGoal == goal) + if (isThin && peep.PathfindGoal == goal) { - /* Use of peep->PathfindHistory[]: + /* Use of peep.PathfindHistory[]: * When walking to a goal, the peep PathfindHistory stores * the last 4 thin junctions that the peep walked through. * For each of these 4 thin junctions the peep remembers @@ -1355,7 +1355,7 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY /* If the peep remembers walking through this junction * previously while heading for its goal, retrieve the * directions it has not yet tried. */ - for (auto& pathfindHistory : peep->PathfindHistory) + for (auto& pathfindHistory : peep.PathfindHistory) { if (pathfindHistory == loc) { @@ -1405,15 +1405,15 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY /* If this is a new goal for the peep. Store it and reset the peep's * PathfindHistory. */ - if (!direction_valid(peep->PathfindGoal.direction) || peep->PathfindGoal != goal) + if (!direction_valid(peep.PathfindGoal.direction) || peep.PathfindGoal != goal) { - peep->PathfindGoal = { goal, 0 }; + peep.PathfindGoal = { goal, 0 }; // Clear pathfinding history TileCoordsXYZD nullPos; nullPos.SetNull(); - std::fill(std::begin(peep->PathfindHistory), std::end(peep->PathfindHistory), nullPos); + std::fill(std::begin(peep.PathfindHistory), std::end(peep.PathfindHistory), nullPos); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { @@ -1504,13 +1504,13 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY uint8_t endDirectionList[16] = { 0 }; bool inPatrolArea = false; - auto* staff = peep->As(); + auto* staff = peep.As(); if (staff != nullptr && staff->IsMechanic()) { /* Mechanics are the only staff type that * pathfind to a destination. Determine if the * mechanic is in their patrol area. */ - inPatrolArea = staff->IsLocationInPatrol(peep->NextLoc); + inPatrolArea = staff->IsLocationInPatrol(peep.NextLoc); } #if defined(DEBUG_LEVEL_2) && DEBUG_LEVEL_2 @@ -1592,20 +1592,20 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY { for (int32_t i = 0; i < 4; ++i) { - if (peep->PathfindHistory[i] == loc) + if (peep.PathfindHistory[i] == loc) { /* Peep remembers this junction, so remove the * chosen_edge from those left to try. */ - peep->PathfindHistory[i].direction &= ~(1 << chosen_edge); + peep.PathfindHistory[i].direction &= ~(1 << chosen_edge); /* Also remove the edge through which the peep * entered the junction from those left to try. */ - peep->PathfindHistory[i].direction &= ~(1 << direction_reverse(peep->PeepDirection)); + peep.PathfindHistory[i].direction &= ~(1 << direction_reverse(peep.PeepDirection)); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { log_verbose( "Updating existing pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i, - loc.x, loc.y, loc.z, direction_reverse(peep->PeepDirection), chosen_edge); + loc.x, loc.y, loc.z, direction_reverse(peep.PeepDirection), chosen_edge); } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 return chosen_edge; @@ -1614,20 +1614,20 @@ Direction OriginalPathfinding::peep_pathfind_choose_direction(const TileCoordsXY /* Peep does not remember this junction, so forget a junction * and remember this junction. */ - int32_t i = peep->PathfindGoal.direction++; - peep->PathfindGoal.direction &= 3; - peep->PathfindHistory[i] = { loc, permitted_edges }; + int32_t i = peep.PathfindGoal.direction++; + peep.PathfindGoal.direction &= 3; + peep.PathfindHistory[i] = { loc, permitted_edges }; /* Remove the chosen_edge from those left to try. */ - peep->PathfindHistory[i].direction &= ~(1 << chosen_edge); + peep.PathfindHistory[i].direction &= ~(1 << chosen_edge); /* Also remove the edge through which the peep * entered the junction from those left to try. */ - peep->PathfindHistory[i].direction &= ~(1 << direction_reverse(peep->PeepDirection)); + peep.PathfindHistory[i].direction &= ~(1 << direction_reverse(peep.PeepDirection)); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { log_verbose( "Storing new pf_history (in index: %d) for %d,%d,%d without entry edge %d & exit edge %d.", i, loc.x, loc.y, - loc.z, direction_reverse(peep->PeepDirection), chosen_edge); + loc.z, direction_reverse(peep.PeepDirection), chosen_edge); } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 } @@ -1661,10 +1661,10 @@ static std::optional GetNearestParkEntrance(const CoordsXY& loc) * * rct2: 0x006952C0 */ -int32_t OriginalPathfinding::GuestPathFindParkEntranceEntering(Peep* peep, uint8_t edges) +int32_t OriginalPathfinding::GuestPathFindParkEntranceEntering(Peep& peep, uint8_t edges) { // Send peeps to the nearest park entrance. - auto chosenEntrance = GetNearestParkEntrance(peep->NextLoc); + auto chosenEntrance = GetNearestParkEntrance(peep.NextLoc); // If no defined park entrances are found, walk aimlessly. if (!chosenEntrance.has_value()) @@ -1674,7 +1674,7 @@ int32_t OriginalPathfinding::GuestPathFindParkEntranceEntering(Peep* peep, uint8 gPeepPathFindIgnoreForeignQueues = true; gPeepPathFindQueueRideIndex = RideId::GetNull(); - Direction chosenDirection = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); + Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep); if (chosenDirection == INVALID_DIRECTION) return guest_path_find_aimless(peep, edges); @@ -1710,10 +1710,10 @@ static uint8_t get_nearest_peep_spawn_index(uint16_t x, uint16_t y) * * rct2: 0x0069536C */ -int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep* peep, uint8_t edges) +int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep& peep, uint8_t edges) { // Send peeps to the nearest spawn point. - uint8_t chosenSpawn = get_nearest_peep_spawn_index(peep->NextLoc.x, peep->NextLoc.y); + uint8_t chosenSpawn = get_nearest_peep_spawn_index(peep.NextLoc.x, peep.NextLoc.y); // If no defined spawns were found, walk aimlessly. if (chosenSpawn == 0xFF) @@ -1723,14 +1723,14 @@ int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep* peep, uint8_t edges) Direction direction = peepSpawnLoc.direction; gPeepPathFindGoalPosition = TileCoordsXYZ(peepSpawnLoc); - if (peepSpawnLoc.x == peep->NextLoc.x && peepSpawnLoc.y == peep->NextLoc.y) + if (peepSpawnLoc.x == peep.NextLoc.x && peepSpawnLoc.y == peep.NextLoc.y) { return peep_move_one_tile(direction, peep); } gPeepPathFindIgnoreForeignQueues = true; gPeepPathFindQueueRideIndex = RideId::GetNull(); - direction = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); + direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep); if (direction == INVALID_DIRECTION) return guest_path_find_aimless(peep, edges); @@ -1741,28 +1741,28 @@ int32_t OriginalPathfinding::GuestPathFindPeepSpawn(Peep* peep, uint8_t edges) * * rct2: 0x00695161 */ -int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep* peep, uint8_t edges) +int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep& peep, uint8_t edges) { TileCoordsXYZ entranceGoal{}; - if (peep->PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN) + if (peep.PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN) { - entranceGoal = peep->PathfindGoal; + entranceGoal = peep.PathfindGoal; auto* entranceElement = map_get_park_entrance_element_at(entranceGoal.ToCoordsXYZ(), false); // If entrance no longer exists, choose a new one if (entranceElement == nullptr) { - peep->PeepFlags &= ~(PEEP_FLAGS_PARK_ENTRANCE_CHOSEN); + peep.PeepFlags &= ~(PEEP_FLAGS_PARK_ENTRANCE_CHOSEN); } } - if (!(peep->PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN)) + if (!(peep.PeepFlags & PEEP_FLAGS_PARK_ENTRANCE_CHOSEN)) { - auto chosenEntrance = GetNearestParkEntrance(peep->NextLoc); + auto chosenEntrance = GetNearestParkEntrance(peep.NextLoc); if (!chosenEntrance.has_value()) return guest_path_find_aimless(peep, edges); - peep->PeepFlags |= PEEP_FLAGS_PARK_ENTRANCE_CHOSEN; + peep.PeepFlags |= PEEP_FLAGS_PARK_ENTRANCE_CHOSEN; entranceGoal = TileCoordsXYZ(*chosenEntrance); } @@ -1774,7 +1774,7 @@ int32_t OriginalPathfinding::GuestPathFindParkEntranceLeaving(Peep* peep, uint8_ PathfindLoggingEnable(peep); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - Direction chosenDirection = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); + Direction chosenDirection = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 PathfindLoggingDisable(); @@ -1942,9 +1942,9 @@ static void get_ride_queue_end(TileCoordsXYZ& loc) * appropriate. */ static StationIndex guest_pathfinding_select_random_station( - const Guest* guest, int32_t numEntranceStations, BitSet& entranceStations) + const Guest& guest, int32_t numEntranceStations, BitSet& entranceStations) { - int32_t select = guest->GuestNumRides % numEntranceStations; + int32_t select = guest.GuestNumRides % numEntranceStations; while (select > 0) { for (StationIndex::UnderlyingType i = 0; i < OpenRCT2::Limits::MaxStationsPerRide; i++) @@ -1971,22 +1971,22 @@ static StationIndex guest_pathfinding_select_random_station( * * rct2: 0x00694C35 */ -int32_t OriginalPathfinding::guest_path_finding(Guest* peep) +int32_t OriginalPathfinding::CalculateNextDestination(Guest& peep) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 PathfindLoggingEnable(peep); if (_pathFindDebug) { - log_info("Starting guest_path_finding for %s", _pathFindDebugPeepName); + log_info("Starting CalculateNextDestination for %s", _pathFindDebugPeepName); } #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - if (peep->GetNextIsSurface()) + if (peep.GetNextIsSurface()) { return guest_surface_path_finding(peep); } - TileCoordsXYZ loc{ peep->NextLoc }; + TileCoordsXYZ loc{ peep.NextLoc }; auto* pathElement = map_get_path_element_at(loc); if (pathElement == nullptr) @@ -2002,7 +2002,7 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) return guest_surface_path_finding(peep); } - if (!peep->OutsideOfPark && peep->HeadingForRideOrParkExit()) + if (!peep.OutsideOfPark && peep.HeadingForRideOrParkExit()) { /* If this tileElement is adjacent to any non-wide paths, * remove all of the edges to wide paths. */ @@ -2024,14 +2024,14 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) edges = adjustedEdges; } - int32_t direction = direction_reverse(peep->PeepDirection); + int32_t direction = direction_reverse(peep.PeepDirection); // Check if in a dead end (i.e. only edge is where the peep came from) if (!(edges & ~(1 << direction))) { // In a dead end. Check if peep is lost, etc. - peep->CheckIfLost(); - peep->CheckCantFindRide(); - peep->CheckCantFindExit(); + peep.CheckIfLost(); + peep.CheckCantFindRide(); + peep.CheckCantFindExit(); } else { @@ -2048,7 +2048,7 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) if (_pathFindDebug) { log_info( - "Completed guest_path_finding for %s - taking only direction available: %d.", _pathFindDebugPeepName, + "Completed CalculateNextDestination for %s - taking only direction available: %d.", _pathFindDebugPeepName, direction); } PathfindLoggingDisable(); @@ -2060,16 +2060,16 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) // Peep is outside the park. // loc_694F19: - if (peep->OutsideOfPark) + if (peep.OutsideOfPark) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - peep is outside the park.", _pathFindDebugPeepName); + log_info("Completed CalculateNextDestination for %s - peep is outside the park.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 - switch (peep->State) + switch (peep.State) { case PeepState::EnteringPark: return GuestPathFindParkEntranceEntering(peep, edges); @@ -2086,7 +2086,7 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) * In principle, peeps with food are not paying as much attention to * where they are going and are consequently more like to walk up * dead end paths, paths to ride exits, etc. */ - if (!peep->HasFoodOrDrink() && (scenario_rand() & 0xFFFF) >= 2184) + if (!peep.HasFoodOrDrink() && (scenario_rand() & 0xFFFF) >= 2184) { uint8_t adjustedEdges = edges; for (Direction chosenDirection : ALL_DIRECTIONS) @@ -2113,41 +2113,41 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) /* If there are still multiple directions to choose from, * peeps with maps will randomly read the map: probability of doing so * is much higher when heading for a ride or the park exit. */ - if (peep->HasItem(ShopItem::Map)) + if (peep.HasItem(ShopItem::Map)) { // If at least 2 directions consult map if (bitcount(edges) >= 2) { uint16_t probability = 1638; - if (peep->HeadingForRideOrParkExit()) + if (peep.HeadingForRideOrParkExit()) { probability = 9362; } if ((scenario_rand() & 0xFFFF) < probability) { - peep->ReadMap(); + peep.ReadMap(); } } } - if (peep->PeepFlags & PEEP_FLAGS_LEAVING_PARK) + if (peep.PeepFlags & PEEP_FLAGS_LEAVING_PARK) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - peep is leaving the park.", _pathFindDebugPeepName); + log_info("Completed CalculateNextDestination for %s - peep is leaving the park.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 return GuestPathFindParkEntranceLeaving(peep, edges); } - if (peep->GuestHeadingToRideId.IsNull()) + if (peep.GuestHeadingToRideId.IsNull()) { #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - peep is aimless.", _pathFindDebugPeepName); + log_info("Completed CalculateNextDestination for %s - peep is aimless.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2155,7 +2155,7 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) } // Peep is heading for a ride. - RideId rideIndex = peep->GuestHeadingToRideId; + RideId rideIndex = peep.GuestHeadingToRideId; auto ride = get_ride(rideIndex); if (ride == nullptr || ride->status != RideStatus::Open) { @@ -2163,7 +2163,8 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) if (_pathFindDebug) { log_info( - "Completed guest_path_finding for %s - peep is heading to closed ride == aimless.", _pathFindDebugPeepName); + "Completed CalculateNextDestination for %s - peep is heading to closed ride == aimless.", + _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2194,7 +2195,7 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) entranceStations[stationIndex.ToUnderlying()] = true; TileCoordsXYZD entranceLocation = station.Entrance; - auto score = CalculateHeuristicPathingScore(entranceLocation, TileCoordsXYZ{ peep->NextLoc }); + auto score = CalculateHeuristicPathingScore(entranceLocation, TileCoordsXYZ{ peep.NextLoc }); if (score < bestScore) { bestScore = score; @@ -2234,22 +2235,23 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) gPeepPathFindGoalPosition = loc; gPeepPathFindIgnoreForeignQueues = true; - direction = peep_pathfind_choose_direction(TileCoordsXYZ{ peep->NextLoc }, peep); + direction = ChooseDirection(TileCoordsXYZ{ peep.NextLoc }, peep); if (direction == INVALID_DIRECTION) { /* Heuristic search failed for all directions. * Reset the PathfindGoal - this means that the PathfindHistory - * will be reset in the next call to peep_pathfind_choose_direction(). + * will be reset in the next call to ChooseDirection(). * This lets the heuristic search "try again" in case the player has * edited the path layout or the mechanic was already stuck in the * save game (e.g. with a worse version of the pathfinding). */ - peep->ResetPathfindGoal(); + peep.ResetPathfindGoal(); #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - failed to choose a direction == aimless.", _pathFindDebugPeepName); + log_info( + "Completed CalculateNextDestination for %s - failed to choose a direction == aimless.", _pathFindDebugPeepName); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2259,7 +2261,7 @@ int32_t OriginalPathfinding::guest_path_finding(Guest* peep) #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 if (_pathFindDebug) { - log_info("Completed guest_path_finding for %s - direction chosen: %d.", _pathFindDebugPeepName, direction); + log_info("Completed CalculateNextDestination for %s - direction chosen: %d.", _pathFindDebugPeepName, direction); } PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 @@ -2311,18 +2313,18 @@ void Peep::ResetPathfindGoal() } #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 -void PathfindLoggingEnable([[maybe_unused]] Peep* peep) +void PathfindLoggingEnable([[maybe_unused]] Peep& peep) { # if defined(PATHFIND_DEBUG) && PATHFIND_DEBUG /* Determine if the pathfinding debugging is wanted for this peep. */ - format_string(gPathFindDebugPeepName, sizeof(gPathFindDebugPeepName), peep->name_string_idx, &(peep->Id)); + format_string(gPathFindDebugPeepName, sizeof(gPathFindDebugPeepName), peep.name_string_idx, &(peep.Id)); /* For guests, use the existing PEEP_FLAGS_TRACKING flag to * determine for which guest(s) the pathfinding debugging will * be output for. */ - if (peep->type == PEEP_TYPE_GUEST) + if (peep.type == PEEP_TYPE_GUEST) { - gPathFindDebug = peep->PeepFlags & PEEP_FLAGS_TRACKING; + gPathFindDebug = peep.PeepFlags & PEEP_FLAGS_TRACKING; } /* For staff, there is no tracking button (any other similar * suitable existing mechanism?), so fall back to a crude diff --git a/src/openrct2/peep/GuestPathfinding.h b/src/openrct2/peep/GuestPathfinding.h index bb6d08b60e..e9eb4a5ad8 100644 --- a/src/openrct2/peep/GuestPathfinding.h +++ b/src/openrct2/peep/GuestPathfinding.h @@ -42,38 +42,53 @@ class GuestPathfinding public: virtual ~GuestPathfinding() = default; - // Given a peep 'peep' at tile 'loc', who is trying to get to 'gPeepPathFindGoalPosition', decide - // the direction the peep should walk in from the current tile. - virtual Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) = 0; + /** + * Given a peep 'peep' at tile 'loc', who is trying to get to 'gPeepPathFindGoalPosition', decide the direction the peep + * should walk in from the current tile. + * + * @param loc Reference to the peep's current tile location + * @param peep Reference to the current peep struct + * @return The direction the peep should walk in + */ + virtual Direction ChooseDirection(const TileCoordsXYZ& loc, Peep& peep) = 0; - // Test whether the given tile can be walked onto, if the peep is currently at height currentZ and - // moving in direction currentDirection. + /** + * Test whether the given tile can be walked onto, if the peep is currently at height currentZ and + * moving in direction currentDirection + * + * @param tileElement A pointer to the tile that is being tested + * @param currentZ The height coord the peep is at + * @param currentDirection The direction the peep is facing in + * @return True if the given tile can be walked onto, false otherwise + */ static bool IsValidPathZAndDirection(TileElement* tileElement, int32_t currentZ, int32_t currentDirection); - // Overall guest pathfinding AI. Sets up Peep::DestinationX/DestinationY (which they move to in a - // straight line, no pathfinding). Called whenever the guest has arrived at their previously set destination. - // - // Returns 0 if the guest has successfully had a new destination set up, nonzero otherwise. - virtual int32_t guest_path_finding(Guest* peep) = 0; + /** + * Overall guest pathfinding AI. Sets up Peep::DestinationX/DestinationY (which they move to in a + * straight line, no pathfinding). Called whenever the guest has arrived at their previously set destination. + * + * @param peep A reference to a guest struct + * @returns 0 if the guest has successfully had a new destination set up, nonzero otherwise. + */ + virtual int32_t CalculateNextDestination(Guest& peep) = 0; }; class OriginalPathfinding : public GuestPathfinding { public: - Direction peep_pathfind_choose_direction(const TileCoordsXYZ& loc, Peep* peep) final override; + Direction ChooseDirection(const TileCoordsXYZ& loc, Peep& peep) final override; - int32_t guest_path_finding(Guest* peep) final override; + int32_t CalculateNextDestination(Guest& peep) final override; private: - int32_t GuestPathFindParkEntranceEntering(Peep* peep, uint8_t edges); + int32_t GuestPathFindParkEntranceEntering(Peep& peep, uint8_t edges); - int32_t GuestPathFindPeepSpawn(Peep* peep, uint8_t edges); + int32_t GuestPathFindPeepSpawn(Peep& peep, uint8_t edges); - int32_t GuestPathFindParkEntranceLeaving(Peep* peep, uint8_t edges); + int32_t GuestPathFindParkEntranceLeaving(Peep& peep, uint8_t edges); }; -// TODO: Implement a better solution than a global variable for the utilized pathfinder -extern GuestPathfinding* gGuestPathfinder; +extern std::unique_ptr gGuestPathfinder; #if defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 # define PATHFIND_DEBUG \ @@ -84,6 +99,6 @@ extern GuestPathfinding* gGuestPathfinder; // The following calls configure debug logging for the given peep // If they're a guest, pathfinding will be logged if they have PEEP_FLAGS_TRACKING set // If they're staff, pathfinding will be logged if their name is "Mechanic Debug" -void PathfindLoggingEnable(Peep* peep); +void PathfindLoggingEnable(Peep& peep); void PathfindLoggingDisable(); #endif // defined(DEBUG_LEVEL_1) && DEBUG_LEVEL_1 diff --git a/test/tests/Pathfinding.cpp b/test/tests/Pathfinding.cpp index faf1c35503..cac06cb984 100644 --- a/test/tests/Pathfinding.cpp +++ b/test/tests/Pathfinding.cpp @@ -84,7 +84,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. gPeepPathFindGoalPosition = goal; - const Direction moveDir = gGuestPathfinder->peep_pathfind_choose_direction(*pos, peep); + const Direction moveDir = gGuestPathfinder->ChooseDirection(*pos, *peep); if (moveDir == INVALID_DIRECTION) { // Couldn't determine a direction to move off in