From d8ad249b0a34149b77da5b2b47ab7cf4344cc76f Mon Sep 17 00:00:00 2001 From: Michael Steenbeek <1478678+Gymnasiast@users.noreply.github.com> Date: Tue, 23 Dec 2025 14:20:11 +0100 Subject: [PATCH] Only add invisible entrances to S4/S6 if they were actually used (#25682) --- distribution/changelog.txt | 1 + src/openrct2/rct1/S4Importer.cpp | 3 ++- src/openrct2/rct12/RCT12.cpp | 39 +++++++++++++++++--------------- src/openrct2/rct12/RCT12.h | 19 +++++++++++++++- src/openrct2/rct2/S6Importer.cpp | 28 +++++++++++++++++++---- 5 files changed, 66 insertions(+), 24 deletions(-) diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 8235900f34..52447bd4ba 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -23,6 +23,7 @@ - Fix: [#25571] Potential crash due to drawing a Crooked House ride. - Fix: [#25588] When the master server becomes unreachable the server would not register again until a restart. - Fix: [#25592] Log flume, river rapids, & splash boats can get control failure breakdown instead of brakes failure. +- Fix: [#25595] Invisible entrance is added to imported SV4 saves. - Fix: [#25628] Availability of AVX2 and SSE4.1 is not detected correctly. - Fix: [#25639] Scenery window crashes when a no longer present object is still selected. - Fix: [#25642] The selection marker for purchasing land rights is not drawn with the correct colours. diff --git a/src/openrct2/rct1/S4Importer.cpp b/src/openrct2/rct1/S4Importer.cpp index 6b44148d5f..3e598fbbf1 100644 --- a/src/openrct2/rct1/S4Importer.cpp +++ b/src/openrct2/rct1/S4Importer.cpp @@ -1561,7 +1561,8 @@ namespace OpenRCT2::RCT1 AppendRequiredObjects(result, ObjectType::footpathSurface, _footpathSurfaceEntries); AppendRequiredObjects(result, ObjectType::footpathRailings, _footpathRailingsEntries); AppendRequiredObjects(result, ObjectType::peepNames, std::vector({ "rct2.peep_names.original" })); - RCT12AddDefaultObjects(result); + AppendRequiredObjects(result, ObjectType::station, kDefaultStationStyles); + RCT12AddDefaultMusic(result); // Normalise the name to make the scenario as recognisable as possible auto normalisedName = ScenarioSources::NormaliseName(_s4.ScenarioName); diff --git a/src/openrct2/rct12/RCT12.cpp b/src/openrct2/rct12/RCT12.cpp index c69be1e1bd..ce1e330e19 100644 --- a/src/openrct2/rct12/RCT12.cpp +++ b/src/openrct2/rct12/RCT12.cpp @@ -719,11 +719,20 @@ OpenRCT2::RCT12::TrackElemType OpenRCT2FlatTrackTypeToRCT12(OpenRCT2::TrackElemT } } -static constexpr std::string_view _stationStyles[] = { - "rct2.station.plain", "rct2.station.wooden", "rct2.station.canvas_tent", "rct2.station.castle_grey", - "rct2.station.castle_brown", "rct2.station.jungle", "rct2.station.log", "rct2.station.classical", - "rct2.station.abstract", "rct2.station.snow", "rct2.station.pagoda", "rct2.station.space", - "openrct2.station.noentrance", +static constexpr std::string_view _stationStyleMap[] = { + "rct2.station.plain", // RCT12_STATION_STYLE_PLAIN + "rct2.station.wooden", // RCT12_STATION_STYLE_WOODEN + "rct2.station.canvas_tent", // RCT12_STATION_STYLE_CANVAS_TENT + "rct2.station.castle_grey", // RCT12_STATION_STYLE_CASTLE_GREY + "rct2.station.castle_brown", // RCT12_STATION_STYLE_CASTLE_BROWN + "rct2.station.jungle", // RCT12_STATION_STYLE_JUNGLE + "rct2.station.log", // RCT12_STATION_STYLE_LOG_CABIN + "rct2.station.classical", // RCT12_STATION_STYLE_CLASSICAL + "rct2.station.abstract", // RCT12_STATION_STYLE_ABSTRACT + "rct2.station.snow", // RCT12_STATION_STYLE_SNOW + "rct2.station.pagoda", // RCT12_STATION_STYLE_PAGODA + "rct2.station.space", // RCT12_STATION_STYLE_SPACE + "openrct2.station.noentrance", // RCT12_STATION_STYLE_INVISIBLE }; static constexpr std::string_view _musicStyles[] = { @@ -764,22 +773,22 @@ static constexpr std::string_view _musicStyles[] = { std::string_view GetStationIdentifierFromStyle(uint8_t style) { - if (style < std::size(_stationStyles)) + if (style < std::size(_stationStyleMap)) { - return _stationStyles[style]; + return _stationStyleMap[style]; } - return _stationStyles[RCT12_STATION_STYLE_INVISIBLE]; + return _stationStyleMap[RCT12_STATION_STYLE_INVISIBLE]; } uint8_t GetStationStyleFromIdentifier(u8string_view identifier) { // Not supported in TD6, closest match. - if (identifier == "openrct2.station.noplatformnoentrance") + if (identifier == kNoEntranceNoPlatformIdentifier) return RCT12_STATION_STYLE_INVISIBLE; - for (uint8_t i = RCT12_STATION_STYLE_PLAIN; i < std::size(_stationStyles); i++) + for (uint8_t i = RCT12_STATION_STYLE_PLAIN; i < std::size(_stationStyleMap); i++) { - if (_stationStyles[i] == identifier) + if (_stationStyleMap[i] == identifier) { return i; } @@ -798,14 +807,8 @@ std::optional GetStyleFromMusicIdentifier(std::string_view identifier) return std::nullopt; } -void RCT12AddDefaultObjects(ObjectList& objectList) +void RCT12AddDefaultMusic(ObjectList& objectList) { - // Stations - for (size_t i = 0; i < std::size(_stationStyles); i++) - { - objectList.SetObject(ObjectType::station, static_cast(i), _stationStyles[i]); - } - // Music for (size_t i = 0; i < std::size(_musicStyles); i++) { diff --git a/src/openrct2/rct12/RCT12.h b/src/openrct2/rct12/RCT12.h index 8fbe67ef82..538738d37e 100644 --- a/src/openrct2/rct12/RCT12.h +++ b/src/openrct2/rct12/RCT12.h @@ -478,6 +478,23 @@ enum : uint32_t TRACK_FLAGS2_SIX_FLAGS_RIDE_DEPRECATED = (1u << 31) // Not used anymore. }; +static constexpr std::string_view kNoEntranceNoPlatformIdentifier = "openrct2.station.noplatformnoentrance"; + +constexpr std::string_view kDefaultStationStyles[] = { + "rct2.station.plain", // RCT12_STATION_STYLE_PLAIN + "rct2.station.wooden", // RCT12_STATION_STYLE_WOODEN + "rct2.station.canvas_tent", // RCT12_STATION_STYLE_CANVAS_TENT + "rct2.station.castle_grey", // RCT12_STATION_STYLE_CASTLE_GREY + "rct2.station.castle_brown", // RCT12_STATION_STYLE_CASTLE_BROWN + "rct2.station.jungle", // RCT12_STATION_STYLE_JUNGLE + "rct2.station.log", // RCT12_STATION_STYLE_LOG_CABIN + "rct2.station.classical", // RCT12_STATION_STYLE_CLASSICAL + "rct2.station.abstract", // RCT12_STATION_STYLE_ABSTRACT + "rct2.station.snow", // RCT12_STATION_STYLE_SNOW + "rct2.station.pagoda", // RCT12_STATION_STYLE_PAGODA + "rct2.station.space", // RCT12_STATION_STYLE_SPACE +}; + #pragma pack(push, 1) struct RCT12xy8 @@ -1216,7 +1233,7 @@ OpenRCT2::RCT12::TrackElemType OpenRCT2FlatTrackTypeToRCT12(OpenRCT2::TrackElemT std::string_view GetStationIdentifierFromStyle(uint8_t style); uint8_t GetStationStyleFromIdentifier(u8string_view identifier); std::optional GetStyleFromMusicIdentifier(std::string_view identifier); -void RCT12AddDefaultObjects(OpenRCT2::ObjectList& objectList); +void RCT12AddDefaultMusic(OpenRCT2::ObjectList& objectList); void AppendRequiredObjects( OpenRCT2::ObjectList& objectList, OpenRCT2::ObjectType objectType, std::span objectNames); void AppendRequiredObjects( diff --git a/src/openrct2/rct2/S6Importer.cpp b/src/openrct2/rct2/S6Importer.cpp index 6ceb0c6ab2..c11889e587 100644 --- a/src/openrct2/rct2/S6Importer.cpp +++ b/src/openrct2/rct2/S6Importer.cpp @@ -90,6 +90,7 @@ namespace OpenRCT2::RCT2 ObjectEntryIndex _pathToRailingMap[16]; RCT12::EntryList _terrainSurfaceEntries; RCT12::EntryList _terrainEdgeEntries; + RCT12::EntryList _stationEntries; public: S6Importer(IObjectRepository& objectRepository) @@ -612,6 +613,8 @@ namespace OpenRCT2::RCT2 // Add default edges _terrainEdgeEntries.AddRange(DefaultTerrainEdges); + + _stationEntries.AddRange(kDefaultStationStyles); } void ConvertScenarioStringsToUTF8(GameState_t& gameState) @@ -971,11 +974,11 @@ namespace OpenRCT2::RCT2 } dst->music = musicStyle; + auto entranceStyle = src->entranceStyle; // In SV7, "plain" entrances are invisible. - auto entranceStyle = kObjectEntryIndexNull; - if (!_isSV7 && GetRideTypeDescriptor(dst->type).HasFlag(RtdFlag::hasEntranceAndExit)) + if (_isSV7) { - entranceStyle = src->entranceStyle; + entranceStyle = _stationEntries.GetOrAddEntry(kNoEntranceNoPlatformIdentifier); } dst->entranceStyle = entranceStyle; @@ -1920,9 +1923,26 @@ namespace OpenRCT2::RCT2 AppendRequiredObjects(objectList, ObjectType::terrainSurface, _terrainSurfaceEntries); AppendRequiredObjects(objectList, ObjectType::terrainEdge, _terrainEdgeEntries); + + const bool hasInvisibleEntrance = std::any_of(std::begin(_s6.Rides), std::end(_s6.Rides), [](Ride& ride) { + if (ride.type == kRideTypeNull) + return false; + + return ride.entranceStyle == RCT12_STATION_STYLE_INVISIBLE; + }); + if (hasInvisibleEntrance) + { + _stationEntries.GetOrAddEntry(GetStationIdentifierFromStyle(RCT12_STATION_STYLE_INVISIBLE)); + } + if (_isSV7) + { + _stationEntries.GetOrAddEntry(kNoEntranceNoPlatformIdentifier); + } + AppendRequiredObjects(objectList, ObjectType::station, _stationEntries); + AppendRequiredObjects( objectList, ObjectType::peepNames, std::vector({ "rct2.peep_names.original" })); - RCT12AddDefaultObjects(objectList); + RCT12AddDefaultMusic(objectList); // Normalise the name to make the scenario as recognisable as possible auto normalisedName = ScenarioSources::NormaliseName(_s6.Info.Name);