mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-09-03 22:59:30 +00:00
Codechange: Add RailStationTileLayout iterator. (#14510)
This allows iterating a predefined or calculated rail station layout without allocating extra memory and copying.
This commit is contained in:
@@ -462,6 +462,7 @@ add_files(
|
||||
station_gui.cpp
|
||||
station_gui.h
|
||||
station_kdtree.h
|
||||
station_layout_type.h
|
||||
station_map.h
|
||||
station_type.h
|
||||
statusbar_gui.cpp
|
||||
|
@@ -68,6 +68,7 @@
|
||||
#include "timer/timer_game_tick.h"
|
||||
#include "cheat_type.h"
|
||||
#include "road_func.h"
|
||||
#include "station_layout_type.h"
|
||||
|
||||
#include "widgets/station_widget.h"
|
||||
|
||||
@@ -1094,54 +1095,37 @@ CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta)
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
static inline uint8_t *CreateSingle(uint8_t *layout, int n)
|
||||
RailStationTileLayout::RailStationTileLayout(const StationSpec *spec, uint8_t platforms, uint8_t length) : platforms(platforms), length(length)
|
||||
{
|
||||
int i = n;
|
||||
do *layout++ = 0; while (--i);
|
||||
layout[((n - 1) >> 1) - n] = 2;
|
||||
return layout;
|
||||
if (spec == nullptr) return;
|
||||
|
||||
/* Look for a predefined layout for the required size. */
|
||||
auto found = spec->layouts.find(GetStationLayoutKey(platforms, length));
|
||||
if (found != std::end(spec->layouts)) this->layout = found->second;
|
||||
}
|
||||
|
||||
static inline uint8_t *CreateMulti(uint8_t *layout, int n, uint8_t b)
|
||||
StationGfx RailStationTileLayout::Iterator::operator*() const
|
||||
{
|
||||
int i = n;
|
||||
do *layout++ = b; while (--i);
|
||||
if (n > 4) {
|
||||
layout[0 - n] = 0;
|
||||
layout[n - 1 - n] = 0;
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
/* Use predefined layout if it exists. Mask bit zero which will indicate axis. */
|
||||
if (!stl.layout.empty()) return this->stl.layout[this->position] & ~1;
|
||||
|
||||
/**
|
||||
* Create the station layout for the given number of tracks and platform length.
|
||||
* @param layout The layout to write to.
|
||||
* @param numtracks The number of tracks to write.
|
||||
* @param plat_len The length of the platforms.
|
||||
* @param statspec The specification of the station to (possibly) get the layout from.
|
||||
*/
|
||||
void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec)
|
||||
{
|
||||
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 (this->stl.length == 1) {
|
||||
/* Special case for 1-long platforms, all bare platforms except one small building. */
|
||||
return this->position == ((this->stl.platforms - 1) / 2) ? 2 : 0;
|
||||
}
|
||||
|
||||
if (plat_len == 1) {
|
||||
CreateSingle(layout, numtracks);
|
||||
} else {
|
||||
if (numtracks & 1) layout = CreateSingle(layout, plat_len);
|
||||
int n = numtracks >> 1;
|
||||
|
||||
while (--n >= 0) {
|
||||
layout = CreateMulti(layout, plat_len, 4);
|
||||
layout = CreateMulti(layout, plat_len, 6);
|
||||
}
|
||||
if ((this->position < this->stl.length && (this->stl.platforms % 2 == 1))) {
|
||||
/* Number of tracks is odd, make the first platform bare with a small building. */
|
||||
return this->position == ((this->stl.length - 1) / 2) ? 2 : 0;
|
||||
}
|
||||
|
||||
if (this->stl.length > 4 && ((this->position % this->stl.length) == 0 || (this->position % this->stl.length) == this->stl.length - 1)) {
|
||||
/* Station is longer than 4 tiles, place bare platforms at either end. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* None of the above so must be north or south part of larger station. */
|
||||
return ((this->position / this->stl.length) & (this->stl.platforms % 2)) ? 4 : 6;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1427,19 +1411,17 @@ CommandCost CmdBuildRailStation(DoCommandFlags flags, TileIndex tile_org, RailTy
|
||||
TileIndexDiff track_delta = TileOffsByAxis(OtherAxis(axis)); // offset to go to the next track
|
||||
Track track = AxisToTrack(axis);
|
||||
|
||||
std::vector<uint8_t> layouts(numtracks * plat_len);
|
||||
GetStationLayout(layouts.data(), numtracks, plat_len, statspec);
|
||||
RailStationTileLayout stl{statspec, numtracks, plat_len};
|
||||
auto it = stl.begin();
|
||||
|
||||
uint8_t numtracks_orig = numtracks;
|
||||
|
||||
Company *c = Company::Get(st->owner);
|
||||
size_t layout_idx = 0;
|
||||
TileIndex tile_track = tile_org;
|
||||
do {
|
||||
TileIndex tile = tile_track;
|
||||
int w = plat_len;
|
||||
do {
|
||||
uint8_t layout = layouts[layout_idx++];
|
||||
if (IsRailStationTile(tile) && HasStationReservation(tile)) {
|
||||
/* Check for trains having a reservation for this tile. */
|
||||
Train *v = GetTrainForReservation(tile, AxisToTrack(GetRailStationAxis(tile)));
|
||||
@@ -1458,7 +1440,8 @@ CommandCost CmdBuildRailStation(DoCommandFlags flags, TileIndex tile_org, RailTy
|
||||
/* Remove animation if overbuilding */
|
||||
DeleteAnimatedTile(tile);
|
||||
uint8_t old_specindex = HasStationTileRail(tile) ? GetCustomStationSpecIndex(tile) : 0;
|
||||
MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, rt);
|
||||
|
||||
MakeRailStation(tile, st->owner, st->index, axis, *it++, rt);
|
||||
/* Free the spec if we overbuild something */
|
||||
DeallocateSpecFromStation(st, old_specindex);
|
||||
|
||||
|
59
src/station_layout_type.h
Normal file
59
src/station_layout_type.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* This file is part of OpenTTD.
|
||||
* OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
|
||||
* OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/** @file station_layout_type.h Functions related to station layouts. */
|
||||
|
||||
#ifndef STATION_LAYOUT_TYPE_H
|
||||
#define STATION_LAYOUT_TYPE_H
|
||||
|
||||
#include "newgrf_station.h"
|
||||
#include "station_map.h"
|
||||
|
||||
class RailStationTileLayout {
|
||||
private:
|
||||
std::span<const StationGfx> layout{}; ///< Predefined tile layout.
|
||||
uint platforms; ///< Number of platforms.
|
||||
uint length; ///< Length of platforms.
|
||||
public:
|
||||
RailStationTileLayout(const StationSpec *spec, uint8_t platforms, uint8_t length);
|
||||
|
||||
class Iterator {
|
||||
const RailStationTileLayout &stl; ///< Station tile layout being iterated.
|
||||
uint position = 0; ///< Position within iterator.
|
||||
public:
|
||||
using value_type = StationGfx;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using pointer = void;
|
||||
using reference = void;
|
||||
|
||||
Iterator(const RailStationTileLayout &stl) : stl(stl) {}
|
||||
|
||||
bool operator==(const Iterator &rhs) const { return this->position == rhs.position; }
|
||||
bool operator==(const std::default_sentinel_t &) const { return this->position == this->stl.platforms * this->stl.length; }
|
||||
|
||||
StationGfx operator*() const;
|
||||
|
||||
Iterator &operator++()
|
||||
{
|
||||
++this->position;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int)
|
||||
{
|
||||
Iterator result = *this;
|
||||
++*this;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Iterator begin() const { return Iterator(*this); }
|
||||
std::default_sentinel_t end() const { return std::default_sentinel_t(); }
|
||||
};
|
||||
|
||||
#endif /* STATION_LAYOUT_TYPE_H */
|
@@ -31,6 +31,7 @@
|
||||
#include "company_gui.h"
|
||||
#include "waypoint_cmd.h"
|
||||
#include "landscape_cmd.h"
|
||||
#include "station_layout_type.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
@@ -179,7 +180,6 @@ static CommandCost IsValidTileForWaypoint(TileIndex tile, Axis axis, StationID *
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
extern void GetStationLayout(uint8_t *layout, uint numtracks, uint plat_len, const StationSpec *statspec);
|
||||
extern CommandCost FindJoiningWaypoint(StationID existing_station, StationID station_to_join, bool adjacent, TileArea ta, Waypoint **wp, bool is_road);
|
||||
extern CommandCost CanExpandRailStation(const BaseStation *st, TileArea &new_ta);
|
||||
extern CommandCost CalculateRoadStopCost(TileArea tile_area, DoCommandFlags flags, bool is_drive_through, StationType station_type, Axis axis, DiagDirection ddir, StationID *est, RoadType rt, Money unit_cost);
|
||||
@@ -286,13 +286,11 @@ CommandCost CmdBuildRailWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
||||
wp->UpdateVirtCoord();
|
||||
|
||||
const StationSpec *spec = StationClass::Get(spec_class)->GetSpec(spec_index);
|
||||
std::vector<uint8_t> layout(count);
|
||||
if (spec != nullptr) {
|
||||
/* For NewGRF waypoints we like to have their style. */
|
||||
GetStationLayout(layout.data(), count, 1, spec);
|
||||
}
|
||||
uint8_t map_spec_index = AllocateSpecToStation(spec, wp, true);
|
||||
|
||||
RailStationTileLayout stl{spec, count, 1};
|
||||
auto it = stl.begin();
|
||||
|
||||
Company *c = Company::Get(wp->owner);
|
||||
for (int i = 0; i < count; i++) {
|
||||
TileIndex tile = start_tile + i * offset;
|
||||
@@ -301,7 +299,7 @@ CommandCost CmdBuildRailWaypoint(DoCommandFlags flags, TileIndex start_tile, Axi
|
||||
bool reserved = IsTileType(tile, MP_RAILWAY) ?
|
||||
HasBit(GetRailReservationTrackBits(tile), AxisToTrack(axis)) :
|
||||
HasStationReservation(tile);
|
||||
MakeRailWaypoint(tile, wp->owner, wp->index, axis, layout[i], GetRailType(tile));
|
||||
MakeRailWaypoint(tile, wp->owner, wp->index, axis, *it++, GetRailType(tile));
|
||||
SetCustomStationSpecIndex(tile, map_spec_index);
|
||||
|
||||
SetRailStationTileFlags(tile, spec);
|
||||
|
Reference in New Issue
Block a user