diff --git a/src/newgrf.cpp b/src/newgrf.cpp index c656e15d3e..2b6f1ad255 100644 --- a/src/newgrf.cpp +++ b/src/newgrf.cpp @@ -2029,14 +2029,14 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, cons if (length == 0 || number == 0) break; - if (statspec->layouts.size() < length) statspec->layouts.resize(length); - if (statspec->layouts[length - 1].size() < number) statspec->layouts[length - 1].resize(number); + const uint8_t *buf_layout = buf->ReadBytes(length * number); - const uint8_t *layout = buf->ReadBytes(length * number); - statspec->layouts[length - 1][number - 1].assign(layout, layout + length * number); + /* Create entry in layouts and assign the layout to it. */ + auto &layout = statspec->layouts[GetStationLayoutKey(number, length)]; + layout.assign(buf_layout, buf_layout + length * number); /* Ensure the first bit, axis, is zero. The rest of the value is validated during rendering, as we don't know the range yet. */ - for (auto &tile : statspec->layouts[length - 1][number - 1]) { + for (auto &tile : layout) { if ((tile & ~1U) != tile) { GrfMsg(1, "StationChangeInfo: Invalid tile {} in layout {}x{}", tile, length, number); tile &= ~1U; diff --git a/src/newgrf_station.h b/src/newgrf_station.h index 2d17152fff..80382ac8ab 100644 --- a/src/newgrf_station.h +++ b/src/newgrf_station.h @@ -21,6 +21,7 @@ #include "newgrf_spritegroup.h" #include "newgrf_town.h" #include +#include /** Scope resolver for stations. */ struct StationScopeResolver : public ScopeResolver { @@ -191,15 +192,8 @@ struct StationSpec : NewGRFSpecBase { uint8_t internal_flags; ///< Bitmask of internal spec flags (StationSpecIntlFlags) - /** - * Custom platform layouts. - * This is a 2D array containing an array of tiles. - * 1st layer is platform lengths. - * 2nd layer is tracks (width). - * These can be sparsely populated, and the upper limit is not defined but - * limited to 255. - */ - std::vector>> layouts; + /** Custom platform layouts, keyed by platform and length combined. */ + std::unordered_map> layouts; }; DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags); @@ -208,6 +202,17 @@ using StationClass = NewGRFClass; const StationSpec *GetStationSpec(TileIndex t); +/** + * Get the station layout key for a given station layout size. + * @param platforms Number of platforms. + * @param length Length of platforms. + * @returns Key of station layout. + */ +inline uint16_t GetStationLayoutKey(uint8_t platforms, uint8_t length) +{ + return (length << 8U) | platforms; +} + /** * Test if a StationClass is the waypoint class. * @param cls StationClass to test. diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp index b009434d5b..660d3ad66e 100644 --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -1325,13 +1325,13 @@ static inline uint8_t *CreateMulti(uint8_t *layout, int n, uint8_t b) */ void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec) { - if (statspec != nullptr && statspec->layouts.size() >= plat_len && - statspec->layouts[plat_len - 1].size() >= numtracks && - !statspec->layouts[plat_len - 1][numtracks - 1].empty()) { - /* Custom layout defined, follow it. */ - memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1].data(), - static_cast(plat_len) * numtracks); - return; + if (statspec != nullptr) { + auto found = statspec->layouts.find(GetStationLayoutKey(numtracks, plat_len)); + if (found != std::end(statspec->layouts)) { + /* Custom layout defined, copy to buffer. */ + std::copy(std::begin(found->second), std::end(found->second), layout); + return; + } } if (plat_len == 1) {