From 195de3b25830b7ce21fdf243ada9da88307f9d07 Mon Sep 17 00:00:00 2001 From: mix Date: Mon, 3 Nov 2025 01:05:23 +0000 Subject: [PATCH 1/3] Fix #6228: Track design queue connections not preserved when built --- distribution/changelog.txt | 1 + src/openrct2/ride/Ride.h | 3 ++- src/openrct2/ride/TrackDesign.cpp | 18 +++++++------ src/openrct2/world/Footpath.cpp | 45 +++++++++++++++++++++++++++++++ src/openrct2/world/Footpath.h | 1 + 5 files changed, 59 insertions(+), 9 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index cde2c4bf64..4571da31ab 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,6 +1,7 @@ 0.4.29 (in development) ------------------------------------------------------------------------ - Improved: [#25426] Building the track designs index is now quicker. +- Fix: [#6228] The saved queue line path connections are not preserved when placing track designs (original bug). - Fix: [#14365] Track designs with scenery below the lowest track piece do not preview correctly. - Fix: [#25451] Dropdown item tooltips stay open if the mouse is moved over an empty space. - Fix: [#25461] Path connections in raised track designs are sometimes broken when placed. diff --git a/src/openrct2/ride/Ride.h b/src/openrct2/ride/Ride.h index 3bcef56b5e..d544932ce6 100644 --- a/src/openrct2/ride/Ride.h +++ b/src/openrct2/ride/Ride.h @@ -327,13 +327,14 @@ public: // in the station array. e.g. if only slot 0 and 2 are in use, index 2 returns 2 instead of 3. StationIndex::UnderlyingType getStationNumber(StationIndex in) const; + void chainQueues() const; + private: void update(); void updateQueueLength(StationIndex stationIndex); ResultWithMessage createVehicles(const CoordsXYE& element, bool isApplying, bool isSimulating); void moveTrainsToBlockBrakes(const CoordsXYZ& firstBlockPosition, OpenRCT2::TrackElement& firstBlock); money64 calculateIncomePerHour() const; - void chainQueues() const; void constructMissingEntranceOrExit() const; ResultWithMessage changeStatusDoStationChecks(StationIndex& stationIndex); diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index bb07e65998..3c010d5719 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -1229,12 +1229,6 @@ static GameActions::Result TrackDesignPlaceSceneryElement( return GameActions::Result(); } - if (tds.placeOperation == TrackPlaceOperation::place) - { - FootpathQueueChainReset(); - FootpathRemoveEdgesAt(mapCoord, reinterpret_cast(pathElement)); - } - flags = GAME_COMMAND_FLAG_APPLY; if (tds.placeOperation == TrackPlaceOperation::placeTrackPreview) { @@ -1252,8 +1246,11 @@ static GameActions::Result TrackDesignPlaceSceneryElement( if (tds.placeOperation == TrackPlaceOperation::place) { - FootpathConnectEdges(mapCoord, reinterpret_cast(pathElement), flags); - FootpathUpdateQueueChains(); + if (!pathElement->IsQueue() || FootpathQueueCountConnections(mapCoord, *pathElement) < 2) + { + FootpathRemoveEdgesAt(mapCoord, reinterpret_cast(pathElement)); + FootpathConnectEdges(mapCoord, reinterpret_cast(pathElement), flags); + } } return GameActions::Result(); @@ -1807,6 +1804,11 @@ static GameActions::Result TrackDesignPlaceVirtual( return sceneryPlaceRes; } + if (tds.placeOperation == TrackPlaceOperation::place || tds.placeOperation == TrackPlaceOperation::placeTrackPreview) + { + ride.chainQueues(); + } + // 0x6D0FE6 if (tds.placeOperation == TrackPlaceOperation::drawOutlines) { diff --git a/src/openrct2/world/Footpath.cpp b/src/openrct2/world/Footpath.cpp index 43f754812d..57a5bdf1e3 100644 --- a/src/openrct2/world/Footpath.cpp +++ b/src/openrct2/world/Footpath.cpp @@ -955,6 +955,51 @@ void FootpathUpdateQueueChains() } } +int32_t FootpathQueueCountConnections(const CoordsXY& position, const PathElement& pathElement) +{ + int32_t connectionCount = 0; + for (const Direction direction : kAllDirections) + { + const uint8_t edge = 1 << direction; + if (pathElement.GetEdges() & edge) + { + const CoordsXY adjacentPathPosition = position + CoordsDirectionDelta[direction]; + const int32_t z = pathElement.GetBaseZ(); + const TileElement* tileElement = FootpathGetElement({ adjacentPathPosition, z, z + kLandHeightStep }, direction); + + if (tileElement == nullptr) + { + tileElement = FootpathGetElement({ adjacentPathPosition, z - kLandHeightStep, z }, direction); + + if (tileElement == nullptr) + { + const EntranceElement* entrance = MapGetRideEntranceElementAt(CoordsXYZ{ adjacentPathPosition, z }, true); + if (entrance == nullptr) + { + entrance = MapGetRideEntranceElementAt(CoordsXYZ{ adjacentPathPosition, z + kLandHeightStep }, true); + if (entrance == nullptr) + continue; + } + + if (entrance_has_direction(*entrance, direction + entrance->GetDirection())) + { + connectionCount++; + } + continue; + } + } + + const PathElement& adjacentPath = *tileElement->AsPath(); + + if (adjacentPath.GetEdges() & Numerics::rol4(edge, 2)) + { + connectionCount++; + } + } + } + return connectionCount; +} + /** * * rct2: 0x0069ADBD diff --git a/src/openrct2/world/Footpath.h b/src/openrct2/world/Footpath.h index 9690d468f8..9fa7c8e188 100644 --- a/src/openrct2/world/Footpath.h +++ b/src/openrct2/world/Footpath.h @@ -189,6 +189,7 @@ const OpenRCT2::FootpathRailingsObject* GetPathRailingsEntry(OpenRCT2::ObjectEnt void FootpathQueueChainReset(); void FootpathQueueChainPush(RideId rideIndex); +int32_t FootpathQueueCountConnections(const CoordsXY& position, const OpenRCT2::PathElement& pathElement); bool FootpathIsZAndDirectionValid(const OpenRCT2::PathElement& tileElement, int32_t currentZ, int32_t currentDirection); FootpathPlacementResult FootpathGetOnTerrainPlacement(const TileCoordsXY& location); From 61e73a5535569fcabfcc0ff4e01441c8bbd426dd Mon Sep 17 00:00:00 2001 From: mix Date: Thu, 6 Nov 2025 00:20:37 +0000 Subject: [PATCH 2/3] Bump network version --- src/openrct2/network/NetworkBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openrct2/network/NetworkBase.cpp b/src/openrct2/network/NetworkBase.cpp index 4b4b963c2d..cad46ba29e 100644 --- a/src/openrct2/network/NetworkBase.cpp +++ b/src/openrct2/network/NetworkBase.cpp @@ -47,7 +47,7 @@ // It is used for making sure only compatible builds get connected, even within // single OpenRCT2 version. -constexpr uint8_t kStreamVersion = 1; +constexpr uint8_t kStreamVersion = 2; const std::string kStreamID = std::string(kOpenRCT2Version) + "-" + std::to_string(kStreamVersion); From 462f2941846c3a298e794b379f1b752f39a67188 Mon Sep 17 00:00:00 2001 From: mix Date: Mon, 3 Nov 2025 01:06:41 +0000 Subject: [PATCH 3/3] Fix paths in track design previews not being connected correctly --- distribution/changelog.txt | 1 + src/openrct2/ride/TrackDesign.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 4571da31ab..a8c39e1d83 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -5,6 +5,7 @@ - Fix: [#14365] Track designs with scenery below the lowest track piece do not preview correctly. - Fix: [#25451] Dropdown item tooltips stay open if the mouse is moved over an empty space. - Fix: [#25461] Path connections in raised track designs are sometimes broken when placed. +- Fix: [#25467] Paths are not connected together correctly in track design previews. - Fix: [#25476] When both RCT2 and RCT1 are present, autodetection fails. 0.4.28 (2025-11-01) diff --git a/src/openrct2/ride/TrackDesign.cpp b/src/openrct2/ride/TrackDesign.cpp index 3c010d5719..a4efaadd5e 100644 --- a/src/openrct2/ride/TrackDesign.cpp +++ b/src/openrct2/ride/TrackDesign.cpp @@ -1244,7 +1244,8 @@ static GameActions::Result TrackDesignPlaceSceneryElement( flags |= GAME_COMMAND_FLAG_REPLAY; } - if (tds.placeOperation == TrackPlaceOperation::place) + if (tds.placeOperation == TrackPlaceOperation::placeTrackPreview + || tds.placeOperation == TrackPlaceOperation::place) { if (!pathElement->IsQueue() || FootpathQueueCountConnections(mapCoord, *pathElement) < 2) {