Codechange: Store custom station layouts in a map instead of nested vectors. (#12898)

The map key is the platforms and length combined. This simplifies allocation and searching for layouts.

(cherry picked from commit ff972ec4ff)

# Conflicts:
#	src/newgrf.cpp
#	src/newgrf_station.h
This commit is contained in:
Peter Nelson 2024-08-14 19:58:56 +01:00 committed by Jonathan G Rennison
parent 839ec6f1e8
commit fe14fe6d3c
3 changed files with 26 additions and 21 deletions

View File

@ -2029,14 +2029,14 @@ static ChangeInfoResult StationChangeInfo(uint stid, int numinfo, int prop, cons
if (length == 0 || number == 0) break; if (length == 0 || number == 0) break;
if (statspec->layouts.size() < length) statspec->layouts.resize(length); const uint8_t *buf_layout = buf->ReadBytes(length * number);
if (statspec->layouts[length - 1].size() < number) statspec->layouts[length - 1].resize(number);
const uint8_t *layout = buf->ReadBytes(length * number); /* Create entry in layouts and assign the layout to it. */
statspec->layouts[length - 1][number - 1].assign(layout, layout + length * number); 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. */ /* 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) { if ((tile & ~1U) != tile) {
GrfMsg(1, "StationChangeInfo: Invalid tile {} in layout {}x{}", tile, length, number); GrfMsg(1, "StationChangeInfo: Invalid tile {} in layout {}x{}", tile, length, number);
tile &= ~1U; tile &= ~1U;

View File

@ -21,6 +21,7 @@
#include "newgrf_spritegroup.h" #include "newgrf_spritegroup.h"
#include "newgrf_town.h" #include "newgrf_town.h"
#include <vector> #include <vector>
#include <unordered_map>
/** Scope resolver for stations. */ /** Scope resolver for stations. */
struct StationScopeResolver : public ScopeResolver { struct StationScopeResolver : public ScopeResolver {
@ -191,15 +192,8 @@ struct StationSpec : NewGRFSpecBase<StationClassID> {
uint8_t internal_flags; ///< Bitmask of internal spec flags (StationSpecIntlFlags) uint8_t internal_flags; ///< Bitmask of internal spec flags (StationSpecIntlFlags)
/** /** Custom platform layouts, keyed by platform and length combined. */
* Custom platform layouts. std::unordered_map<uint16_t, std::vector<uint8_t>> 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<std::vector<std::vector<uint8_t>>> layouts;
}; };
DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags); DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags);
@ -208,6 +202,17 @@ using StationClass = NewGRFClass<StationSpec, StationClassID, STAT_CLASS_MAX>;
const StationSpec *GetStationSpec(TileIndex t); 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. * Test if a StationClass is the waypoint class.
* @param cls StationClass to test. * @param cls StationClass to test.

View File

@ -1325,14 +1325,14 @@ 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) void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec)
{ {
if (statspec != nullptr && statspec->layouts.size() >= plat_len && if (statspec != nullptr) {
statspec->layouts[plat_len - 1].size() >= numtracks && auto found = statspec->layouts.find(GetStationLayoutKey(numtracks, plat_len));
!statspec->layouts[plat_len - 1][numtracks - 1].empty()) { if (found != std::end(statspec->layouts)) {
/* Custom layout defined, follow it. */ /* Custom layout defined, copy to buffer. */
memcpy(layout, statspec->layouts[plat_len - 1][numtracks - 1].data(), std::copy(std::begin(found->second), std::end(found->second), layout);
static_cast<size_t>(plat_len) * numtracks);
return; return;
} }
}
if (plat_len == 1) { if (plat_len == 1) {
CreateSingle(layout, numtracks); CreateSingle(layout, numtracks);