From 5da7d0e4db84cd96f309d659884d5a069fbec216 Mon Sep 17 00:00:00 2001 From: Brendan Heinonen Date: Sun, 3 Nov 2024 20:05:03 -0500 Subject: [PATCH] Fix #22972: Missing flat footpath in scenarios Scenarios touched: - Alton Towers - Build your own Six Flags Magic Mountain - Mirage Madness - Six Flags Magic Mountain --- data/scenario_patches/2696a05.parkpatch | 17 +++- data/scenario_patches/5c95a4e.parkpatch | 9 +- data/scenario_patches/7f38f1b.parkpatch | 13 ++- data/scenario_patches/7ffdb44.parkpatch | 13 ++- data/scenario_patches/c1d4056.parkpatch | 13 ++- data/scenario_patches/c82272a.parkpatch | 13 ++- src/openrct2/rct12/ScenarioPatcher.cpp | 128 ++++++++++++++++++++++-- 7 files changed, 182 insertions(+), 24 deletions(-) diff --git a/data/scenario_patches/2696a05.parkpatch b/data/scenario_patches/2696a05.parkpatch index 391ddbd0f9..54c597985b 100644 --- a/data/scenario_patches/2696a05.parkpatch +++ b/data/scenario_patches/2696a05.parkpatch @@ -18,5 +18,20 @@ [ 140, 74 ], [ 141, 74 ], [ 142, 74 ], [ 143, 74 ], [ 144, 74 ], [ 145, 74 ], [ 146, 74 ], [ 147, 74 ] ] } - } + }, + "elements_to_delete": [ + { + "element_index": 1, + "coordinates": [ + [ 86, 75 ], [ 86, 77 ], [ 86, 78 ] + ] + } + ], + "paths": [ + { + "railings": "rct2.footpath_railings.bamboo_brown", + "surface": "rct2.footpath_surface.dirt", + "coordinates": [ [ 86, 74, 12 ], [ 86, 75, 12 ], [ 86, 76, 12 ], [ 86, 77, 12 ], [ 86, 78, 12 ] ] + } + ] } diff --git a/data/scenario_patches/5c95a4e.parkpatch b/data/scenario_patches/5c95a4e.parkpatch index 6c30ef46bf..0f7e0a0e03 100644 --- a/data/scenario_patches/5c95a4e.parkpatch +++ b/data/scenario_patches/5c95a4e.parkpatch @@ -7,5 +7,12 @@ [ 11, 31 ], [ 68, 112 ], [ 72, 118 ] ] } - } + }, + "paths": [ + { + "railings": "rct2.footpath_railings.wood", + "surface": "rct1.footpath_surface.crazy_paving", + "coordinates": [ [ 83, 81, 22 ] ] + } + ] } diff --git a/data/scenario_patches/7f38f1b.parkpatch b/data/scenario_patches/7f38f1b.parkpatch index a282000c56..5ab76eb98e 100644 --- a/data/scenario_patches/7f38f1b.parkpatch +++ b/data/scenario_patches/7f38f1b.parkpatch @@ -4,11 +4,11 @@ "land_ownership": { "available": { "coordinates": [ - [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], - [ 75, 167 ], + [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], + [ 75, 167 ], [ 61, 92 ], [ 61, 93 ], [ 61, 94 ], [ 61, 95 ], [ 62, 90 ], [ 62, 91 ], [ 62, 92 ], [ 62, 93 ], [ 62, 94 ], [ 92, 57 ], [ 93, 57 ], - [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], + [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], [ 168, 20 ], [ 169, 20 ], [ 46, 51 ], [ 58, 159 ], [ 71, 201 ], [ 126, 15 ], [ 190, 6 ] ] @@ -21,5 +21,12 @@ [ 103, 76 ], [ 104, 76 ] ] } + ], + "paths": [ + { + "railings": "rct2.footpath_railings.bamboo_brown", + "surface": "rct2.footpath_surface.dirt", + "coordinates": [ [ 144, 100, 34 ] ] + } ] } diff --git a/data/scenario_patches/7ffdb44.parkpatch b/data/scenario_patches/7ffdb44.parkpatch index db6206427e..6fd885f4b6 100644 --- a/data/scenario_patches/7ffdb44.parkpatch +++ b/data/scenario_patches/7ffdb44.parkpatch @@ -4,11 +4,11 @@ "land_ownership": { "available": { "coordinates": [ - [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], - [ 75, 167 ], + [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], + [ 75, 167 ], [ 61, 92 ], [ 61, 93 ], [ 61, 94 ], [ 61, 95 ], [ 62, 90 ], [ 62, 91 ], [ 62, 92 ], [ 62, 93 ], [ 62, 94 ], [ 92, 57 ], [ 93, 57 ], - [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], + [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], [ 168, 20 ], [ 169, 20 ], [ 46, 51 ], [ 58, 159 ], [ 71, 201 ], [ 126, 15 ], [ 190, 6 ] ] @@ -21,5 +21,12 @@ [ 103, 76 ], [ 104, 76 ] ] } + ], + "paths": [ + { + "railings": "rct2.footpath_railings.bamboo_brown", + "surface": "rct2.footpath_surface.dirt", + "coordinates": [ [ 144, 100, 34 ] ] + } ] } diff --git a/data/scenario_patches/c1d4056.parkpatch b/data/scenario_patches/c1d4056.parkpatch index 7f291735a1..96934e447d 100644 --- a/data/scenario_patches/c1d4056.parkpatch +++ b/data/scenario_patches/c1d4056.parkpatch @@ -4,11 +4,11 @@ "land_ownership": { "available": { "coordinates": [ - [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], - [ 75, 167 ], + [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], + [ 75, 167 ], [ 61, 92 ], [ 61, 93 ], [ 61, 94 ], [ 61, 95 ], [ 62, 90 ], [ 62, 91 ], [ 62, 92 ], [ 62, 93 ], [ 62, 94 ], [ 92, 57 ], [ 93, 57 ], - [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], + [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], [ 168, 20 ], [ 169, 20 ], [ 46, 51 ], [ 58, 159 ], [ 71, 201 ], [ 126, 15 ], [ 190, 6 ] ] @@ -21,5 +21,12 @@ [ 103, 76 ], [ 104, 76 ] ] } + ], + "paths": [ + { + "railings": "rct2.footpath_railings.bamboo_brown", + "surface": "rct2.footpath_surface.dirt", + "coordinates": [ [ 144, 100, 34 ] ] + } ] } diff --git a/data/scenario_patches/c82272a.parkpatch b/data/scenario_patches/c82272a.parkpatch index a75e9e8fef..e220c663c5 100644 --- a/data/scenario_patches/c82272a.parkpatch +++ b/data/scenario_patches/c82272a.parkpatch @@ -4,11 +4,11 @@ "land_ownership": { "available": { "coordinates": [ - [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], - [ 75, 167 ], + [ 104, 190 ], [ 105, 190 ], [ 108, 197 ], + [ 75, 167 ], [ 61, 92 ], [ 61, 93 ], [ 61, 94 ], [ 61, 95 ], [ 62, 90 ], [ 62, 91 ], [ 62, 92 ], [ 62, 93 ], [ 62, 94 ], [ 92, 57 ], [ 93, 57 ], - [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], + [ 89, 40 ], [ 89, 41 ], [ 89, 42 ], [ 88, 42 ], [ 168, 20 ], [ 169, 20 ], [ 46, 51 ], [ 58, 159 ], [ 71, 201 ], [ 126, 15 ], [ 190, 6 ] ] @@ -21,5 +21,12 @@ [ 103, 76 ], [ 104, 76 ] ] } + ], + "paths": [ + { + "railings": "rct2.footpath_railings.bamboo_brown", + "surface": "rct2.footpath_surface.dirt", + "coordinates": [ [ 144, 100, 34 ] ] + } ] } diff --git a/src/openrct2/rct12/ScenarioPatcher.cpp b/src/openrct2/rct12/ScenarioPatcher.cpp index 359d6eba8b..16dfb057d1 100644 --- a/src/openrct2/rct12/ScenarioPatcher.cpp +++ b/src/openrct2/rct12/ScenarioPatcher.cpp @@ -27,6 +27,7 @@ #include "../world/Location.hpp" #include "../world/Map.h" #include "../world/tile_element/EntranceElement.h" +#include "../world/tile_element/PathElement.h" #include "../world/tile_element/SurfaceElement.h" #include "../world/tile_element/TileElement.h" #include "../world/tile_element/TileElementType.h" @@ -74,6 +75,11 @@ static const std::string _ridesKey = "rides"; static const std::string _rideIdKey = "id"; static const std::string _operationKey = "operation"; +// Path fix keys +static const std::string _pathsKey = "paths"; +static const std::string _railingsKey = "railings"; +static const std::string _surfaceKey = "surface"; + static u8string ToOwnershipJsonKey(int ownershipType) { switch (ownershipType) @@ -93,7 +99,33 @@ static u8string ToOwnershipJsonKey(int ownershipType) return {}; } -static std::vector getCoordinates(const json_t& parameters) +static void readCoordinate(std::vector& out, const json_t& coordinatesArray) +{ + if (coordinatesArray.size() != 2) + { + OpenRCT2::Guard::Assert(0, "Fix coordinates sub array should have 2 elements"); + return; + } + + out.emplace_back( + OpenRCT2::Json::GetNumber(coordinatesArray[0]), OpenRCT2::Json::GetNumber(coordinatesArray[1])); +} + +static void readCoordinate(std::vector& out, const json_t& coordinatesArray) +{ + if (coordinatesArray.size() != 3) + { + OpenRCT2::Guard::Assert(0, "Fix coordinates sub array should have 3 elements"); + return; + } + + out.emplace_back( + OpenRCT2::Json::GetNumber(coordinatesArray[0]), OpenRCT2::Json::GetNumber(coordinatesArray[1]), + OpenRCT2::Json::GetNumber(coordinatesArray[2])); +} + +template +static std::vector getCoordinates(const json_t& parameters) { if (!parameters.contains(_coordinatesKey)) { @@ -113,7 +145,7 @@ static std::vector getCoordinates(const json_t& parameters) return {}; } - std::vector parsedCoordinates; + std::vector parsedCoordinates; parsedCoordinates.reserve(coords.size()); for (size_t i = 0; i < coords.size(); ++i) { @@ -123,14 +155,8 @@ static std::vector getCoordinates(const json_t& parameters) return {}; } - auto coordinatesPair = OpenRCT2::Json::AsArray(coords[i]); - if (coordinatesPair.size() != 2) - { - OpenRCT2::Guard::Assert(0, "Fix coordinates sub array should have 2 elements"); - return {}; - } - parsedCoordinates.emplace_back( - OpenRCT2::Json::GetNumber(coordinatesPair[0]), OpenRCT2::Json::GetNumber(coordinatesPair[1])); + auto coordinatesArray = OpenRCT2::Json::AsArray(coords[i]); + readCoordinate(parsedCoordinates, coordinatesArray); } return parsedCoordinates; } @@ -517,6 +543,87 @@ static void ApplyRideFixes(const json_t& scenarioPatch) } } +static void ApplyPathFixes(const json_t& scenarioPatch) +{ + if (!scenarioPatch.contains(_pathsKey)) + { + return; + } + + if (!scenarioPatch[_pathsKey].is_array()) + { + OpenRCT2::Guard::Assert(0, "Path fixes should be an array of arrays"); + return; + } + + auto pathFixes = OpenRCT2::Json::AsArray(scenarioPatch[_pathsKey]); + if (pathFixes.empty()) + { + OpenRCT2::Guard::Assert(0, "Path fixes should not be an empty array"); + return; + } + + for (size_t i = 0; i < pathFixes.size(); ++i) + { + auto pathFix = pathFixes[i]; + + if (!pathFix.contains(_railingsKey)) + { + OpenRCT2::Guard::Assert(0, "Path fixes should have railings"); + return; + } + + if (!pathFix.contains(_surfaceKey)) + { + OpenRCT2::Guard::Assert(0, "Path fixes should have a surface"); + return; + } + + auto railings = OpenRCT2::Json::GetString(pathFix[_railingsKey]); + auto surface = OpenRCT2::Json::GetString(pathFix[_surfaceKey]); + + if (_dryRun) + { + continue; + } + + auto& objectManager = OpenRCT2::GetContext()->GetObjectManager(); + auto railingsObjIndex = objectManager.GetLoadedObjectEntryIndex(railings); + auto surfaceObjIndex = objectManager.GetLoadedObjectEntryIndex(surface); + + if (railingsObjIndex == OBJECT_ENTRY_INDEX_NULL) + { + OpenRCT2::Guard::Assert(0, "Railings object not found"); + return; + } + + if (surfaceObjIndex == OBJECT_ENTRY_INDEX_NULL) + { + OpenRCT2::Guard::Assert(0, "Surface object not found"); + return; + } + + auto coordinates = getCoordinates(pathFix); + + for (auto coordinate : coordinates) + { + auto* pathElement = TileElementInsert(coordinate.ToCoordsXYZ(), 0b1111); + OpenRCT2::Guard::Assert(pathElement != nullptr); + + pathElement->SetSurfaceEntryIndex(surfaceObjIndex); + pathElement->SetRailingsEntryIndex(railingsObjIndex); + + FootpathQueueChainReset(); + FootpathConnectEdges( + coordinate.ToCoordsXY(), pathElement->as(), + GAME_COMMAND_FLAG_APPLY | GAME_COMMAND_FLAG_ALLOW_DURING_PAUSED); + FootpathUpdateQueueChains(); + + MapInvalidateTileFull(coordinate.ToCoordsXY()); + } + } +} + static u8string getScenarioSHA256(u8string_view scenarioPath) { auto env = OpenRCT2::GetContext()->GetPlatformEnvironment(); @@ -581,6 +688,7 @@ void OpenRCT2::RCT12::ApplyScenarioPatch(u8string_view scenarioPatchFile, u8stri ApplySurfaceFixes(scenarioPatch); RemoveTileElements(scenarioPatch); ApplyRideFixes(scenarioPatch); + ApplyPathFixes(scenarioPatch); } void OpenRCT2::RCT12::FetchAndApplyScenarioPatch(u8string_view scenarioPath)