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 (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;

View File

@ -21,6 +21,7 @@
#include "newgrf_spritegroup.h"
#include "newgrf_town.h"
#include <vector>
#include <unordered_map>
/** Scope resolver for stations. */
struct StationScopeResolver : public ScopeResolver {
@ -191,15 +192,8 @@ struct StationSpec : NewGRFSpecBase<StationClassID> {
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<std::vector<std::vector<uint8_t>>> layouts;
/** Custom platform layouts, keyed by platform and length combined. */
std::unordered_map<uint16_t, std::vector<uint8_t>> layouts;
};
DECLARE_ENUM_AS_BIT_SET(StationSpec::TileFlags);
@ -208,6 +202,17 @@ using StationClass = NewGRFClass<StationSpec, StationClassID, STAT_CLASS_MAX>;
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.

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)
{
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<size_t>(plat_len) * numtracks);
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) {
CreateSingle(layout, numtracks);