OpenTTD Source 20241224-master-gf74b0cf984
waypoint_sl.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
6 */
7
10#include "../stdafx.h"
11#include "../waypoint_base.h"
12#include "../debug.h"
13#include "../newgrf_station.h"
14#include "../vehicle_base.h"
15#include "../town.h"
16#include "../newgrf.h"
17#include "../timer/timer_game_calendar.h"
18
19#include "table/strings.h"
20
21#include "saveload_internal.h"
22
23#include "../safeguards.h"
24
27 size_t index;
28 TileIndex xy;
29 TownID town_index;
30 Town *town;
31 uint16_t town_cn;
32 StringID string_id;
33 std::string name;
34 uint8_t delete_ctr;
35 TimerGameCalendar::Date build_date;
36 uint8_t localidx;
37 uint32_t grfid;
38 const StationSpec *spec;
39 Owner owner;
40
41 size_t new_index;
42};
43
45static std::vector<OldWaypoint> _old_waypoints;
46
52{
53 if (!o->IsType(OT_GOTO_WAYPOINT)) return;
54
55 for (OldWaypoint &wp : _old_waypoints) {
56 if (wp.index != o->GetDestination()) continue;
57
58 o->SetDestination((DestinationID)wp.new_index);
59 return;
60 }
61}
62
68{
69 /* In version 17, ground type is moved from m2 to m4 for depots and
70 * waypoints to make way for storing the index in m2. The custom graphics
71 * id which was stored in m4 is now saved as a grf/id reference in the
72 * waypoint struct. */
74 for (OldWaypoint &wp : _old_waypoints) {
75 if (wp.delete_ctr != 0) continue; // The waypoint was deleted
76
77 /* Waypoint indices were not added to the map prior to this. */
78 Tile tile = wp.xy;
79 tile.m2() = (StationID)wp.index;
80
81 if (HasBit(tile.m3(), 4)) {
82 wp.spec = StationClass::Get(STAT_CLASS_WAYP)->GetSpec(tile.m4() + 1);
83 }
84 }
85 } else {
86 /* As of version 17, we recalculate the custom graphic ID of waypoints
87 * from the GRF ID / station index. */
88 for (OldWaypoint &wp : _old_waypoints) {
89 const auto specs = StationClass::Get(STAT_CLASS_WAYP)->Specs();
90 auto found = std::ranges::find_if(specs, [&wp](const StationSpec *spec) { return spec != nullptr && spec->grf_prop.grfid == wp.grfid && spec->grf_prop.local_id == wp.localidx; });
91 if (found != std::end(specs)) wp.spec = *found;
92 }
93 }
94
95 if (!Waypoint::CanAllocateItem(_old_waypoints.size())) SlError(STR_ERROR_TOO_MANY_STATIONS_LOADING);
96
97 /* All saveload conversions have been done. Create the new waypoints! */
98 for (OldWaypoint &wp : _old_waypoints) {
99 TileIndex t = wp.xy;
100 /* Sometimes waypoint (sign) locations became disconnected from their actual location in
101 * the map array. If this is the case, try to locate the actual location in the map array */
102 if (!IsTileType(t, MP_RAILWAY) || GetRailTileType(t) != 2 /* RAIL_TILE_WAYPOINT */ || Tile(t).m2() != wp.index) {
103 Debug(sl, 0, "Found waypoint tile {} with invalid position", t);
104 t = INVALID_TILE;
105 for (auto tile : Map::Iterate()) {
106 if (IsTileType(tile, MP_RAILWAY) && GetRailTileType(tile) == 2 /* RAIL_TILE_WAYPOINT */ && tile.m2() == wp.index) {
107 t = TileIndex(tile);
108 Debug(sl, 0, "Found actual waypoint position at {}", TileIndex(tile));
109 break;
110 }
111 }
112 }
113 if (t == INVALID_TILE) {
114 SlErrorCorrupt("Waypoint with invalid tile");
115 }
116
117 Waypoint *new_wp = new Waypoint(t);
118 new_wp->town = wp.town;
119 new_wp->town_cn = wp.town_cn;
120 new_wp->name = wp.name;
121 new_wp->delete_ctr = 0; // Just reset delete counter for once.
122 new_wp->build_date = wp.build_date;
123 new_wp->owner = wp.owner;
124 new_wp->string_id = STR_SV_STNAME_WAYPOINT;
125
126 /* The tile might've been reserved! */
127 Tile tile(t);
128 bool reserved = !IsSavegameVersionBefore(SLV_100) && HasBit(tile.m5(), 4);
129
130 /* The tile really has our waypoint, so reassign the map array */
131 MakeRailWaypoint(tile, GetTileOwner(tile), new_wp->index, (Axis)GB(tile.m5(), 0, 1), 0, GetRailType(tile));
132 new_wp->facilities |= FACIL_TRAIN;
133 new_wp->owner = GetTileOwner(tile);
134
135 SetRailStationReservation(tile, reserved);
136
137 if (wp.spec != nullptr) {
138 SetCustomStationSpecIndex(tile, AllocateSpecToStation(wp.spec, new_wp, true));
139 }
140 new_wp->rect.BeforeAddTile(tile, StationRect::ADD_FORCE);
141
142 wp.new_index = new_wp->index;
143 }
144
145 /* Update the orders of vehicles */
146 for (OrderList *ol : OrderList::Iterate()) {
147 if (ol->GetFirstSharedVehicle()->type != VEH_TRAIN) continue;
148
149 for (Order *o = ol->GetFirstOrder(); o != nullptr; o = o->next) UpdateWaypointOrder(o);
150 }
151
152 for (Vehicle *v : Vehicle::Iterate()) {
153 if (v->type != VEH_TRAIN) continue;
154
155 UpdateWaypointOrder(&v->current_order);
156 }
157
158 ResetOldWaypoints();
159}
160
161void ResetOldWaypoints()
162{
163 _old_waypoints.clear();
164 _old_waypoints.shrink_to_fit();
165}
166
167static const SaveLoad _old_waypoint_desc[] = {
168 SLE_CONDVAR(OldWaypoint, xy, SLE_FILE_U16 | SLE_VAR_U32, SL_MIN_VERSION, SLV_6),
169 SLE_CONDVAR(OldWaypoint, xy, SLE_UINT32, SLV_6, SL_MAX_VERSION),
170 SLE_CONDVAR(OldWaypoint, town_index, SLE_UINT16, SLV_12, SLV_122),
172 SLE_CONDVAR(OldWaypoint, town_cn, SLE_FILE_U8 | SLE_VAR_U16, SLV_12, SLV_89),
173 SLE_CONDVAR(OldWaypoint, town_cn, SLE_UINT16, SLV_89, SL_MAX_VERSION),
174 SLE_CONDVAR(OldWaypoint, string_id, SLE_STRINGID, SL_MIN_VERSION, SLV_84),
176 SLE_VAR(OldWaypoint, delete_ctr, SLE_UINT8),
177
178 SLE_CONDVAR(OldWaypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32, SLV_3, SLV_31),
179 SLE_CONDVAR(OldWaypoint, build_date, SLE_INT32, SLV_31, SL_MAX_VERSION),
180 SLE_CONDVAR(OldWaypoint, localidx, SLE_UINT8, SLV_3, SL_MAX_VERSION),
181 SLE_CONDVAR(OldWaypoint, grfid, SLE_UINT32, SLV_17, SL_MAX_VERSION),
182 SLE_CONDVAR(OldWaypoint, owner, SLE_UINT8, SLV_101, SL_MAX_VERSION),
183};
184
187
188 void Load() const override
189 {
190 /* Precaution for when loading failed and it didn't get cleared */
191 ResetOldWaypoints();
192
193 int index;
194
195 while ((index = SlIterateArray()) != -1) {
196 OldWaypoint *wp = &_old_waypoints.emplace_back();
197
198 wp->index = index;
199 SlObject(wp, _old_waypoint_desc);
200 }
201 }
202
203 void FixPointers() const override
204 {
205 for (OldWaypoint &wp : _old_waypoints) {
206 SlObject(&wp, _old_waypoint_desc);
207
209 wp.town_cn = (wp.string_id & 0xC000) == 0xC000 ? (wp.string_id >> 8) & 0x3F : 0;
210 wp.town = ClosestTownFromTile(wp.xy, UINT_MAX);
211 } else if (IsSavegameVersionBefore(SLV_122)) {
212 /* Only for versions 12 .. 122 */
213 if (!Town::IsValidID(wp.town_index)) {
214 /* Upon a corrupted waypoint we'll likely get here. The next step will be to
215 * loop over all Ptrs procs to nullptr the pointers. However, we don't know
216 * whether we're in the nullptr or "normal" Ptrs proc. So just clear the list
217 * of old waypoints we constructed and then this waypoint (and the other
218 * possibly corrupt ones) will not be queried in the nullptr Ptrs proc run. */
219 _old_waypoints.clear();
220 SlErrorCorrupt("Referencing invalid Town");
221 }
222 wp.town = Town::Get(wp.town_index);
223 }
225 wp.name = CopyFromOldName(wp.string_id);
226 }
227 }
228 }
229};
230
231static const CHKPChunkHandler CHKP;
232static const ChunkHandlerRef waypoint_chunk_handlers[] = {
233 CHKP,
234};
235
236extern const ChunkHandlerTable _waypoint_chunk_handlers(waypoint_chunk_handlers);
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
debug_inline static constexpr uint GB(const T x, const uint8_t s, const uint8_t n)
Fetch n bits from x, started at bit s.
std::span< Tspec *const > Specs() const
Get read-only span of specs of this class.
static NewGRFClass * Get(Tindex class_index)
Get a particular class.
const Tspec * GetSpec(uint index) const
Get a spec from the class at a given index.
Wrapper class to abstract away the way the tiles are stored.
Definition map_func.h:25
debug_inline uint16_t & m2()
Primarily used for indices to towns, industries and stations.
Definition map_func.h:125
debug_inline uint8_t & m4()
General purpose.
Definition map_func.h:149
debug_inline uint8_t & m3()
General purpose.
Definition map_func.h:137
debug_inline uint8_t & m5()
General purpose.
Definition map_func.h:161
Owner
Enum for all companies/owners.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
Axis
Allow incrementing of DiagDirDiff variables.
int AllocateSpecToStation(const StationSpec *statspec, BaseStation *st, bool exec)
Allocate a StationSpec to a Station.
@ STAT_CLASS_WAYP
Waypoint class.
RailType GetRailType(Tile t)
Gets the rail type of the given tile.
Definition rail_map.h:115
static debug_inline RailTileType GetRailTileType(Tile t)
Returns the RailTileType (normal with or without signals, waypoint or depot).
Definition rail_map.h:36
void SlError(StringID string, const std::string &extra_msg)
Error handler.
Definition saveload.cpp:321
int SlIterateArray()
Iterate through the elements of an array and read the whole thing.
Definition saveload.cpp:659
void SlErrorCorrupt(const std::string &msg)
Error handler for corrupt savegames.
Definition saveload.cpp:351
void SlObject(void *object, const SaveLoadTable &slt)
Main SaveLoad function.
@ CH_READONLY
Chunk is never saved.
Definition saveload.h:459
std::reference_wrapper< const ChunkHandler > ChunkHandlerRef
A reference to ChunkHandler.
Definition saveload.h:509
std::span< const ChunkHandlerRef > ChunkHandlerTable
A table of ChunkHandler entries.
Definition saveload.h:512
#define SLE_CONDSSTR(base, variable, type, from, to)
Storage of a std::string in some savegame versions.
Definition saveload.h:933
#define SLE_CONDVAR(base, variable, type, from, to)
Storage of a variable in some savegame versions.
Definition saveload.h:868
bool IsSavegameVersionBefore(SaveLoadVersion major, uint8_t minor=0)
Checks whether the savegame is below major.
Definition saveload.h:1263
@ SLV_89
89 12160
Definition saveload.h:149
@ SLV_84
84 11822
Definition saveload.h:143
@ SLV_17
17.0 3212 17.1 3218
Definition saveload.h:62
@ SLV_100
100 13952
Definition saveload.h:163
@ SLV_6
6.0 1721 6.1 1768
Definition saveload.h:46
@ SLV_122
122 16855
Definition saveload.h:189
@ SLV_12
12.1 2046
Definition saveload.h:55
@ SL_MAX_VERSION
Highest possible saveload version.
Definition saveload.h:399
@ SL_MIN_VERSION
First savegame version.
Definition saveload.h:31
@ SLV_3
3.x lost
Definition saveload.h:36
@ SLV_101
101 14233
Definition saveload.h:164
@ SLV_31
31 5999
Definition saveload.h:80
#define SLE_CONDREF(base, variable, type, from, to)
Storage of a reference in some savegame versions.
Definition saveload.h:889
@ REF_TOWN
Load/save a reference to a town.
Definition saveload.h:604
#define SLE_VAR(base, variable, type)
Storage of a variable in every version of a savegame.
Definition saveload.h:1002
Declaration of functions used in more save/load files.
std::string CopyFromOldName(StringID id)
Copy and convert old custom names to UTF-8.
void SetCustomStationSpecIndex(Tile t, uint8_t specindex)
Set the custom station spec for this tile.
void SetRailStationReservation(Tile t, bool b)
Set the reservation state of the rail station.
void MakeRailWaypoint(Tile t, Owner o, StationID sid, Axis a, uint8_t section, RailType rt)
Make the given tile a rail waypoint tile.
@ FACIL_TRAIN
Station with train station.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
StationFacility facilities
The facilities that this station has.
StringID string_id
Default name (town area) of station.
Owner owner
The owner of this station.
uint8_t delete_ctr
Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is ...
StationRect rect
NOSAVE: Station spread out rectangle maintained by StationRect::xxx() functions.
Town * town
The town this station is associated with.
TimerGameCalendar::Date build_date
Date of construction.
std::string name
Custom name.
void Load() const override
Load the chunk.
void FixPointers() const override
Fix the pointers.
Handlers and description of chunk.
Definition saveload.h:463
uint16_t local_id
id defined by the grf file for this entity
uint32_t grfid
grfid that introduced this entity.
static IterateWrapper Iterate()
Returns an iterable ensemble of all Tiles.
Definition map_func.h:363
Helper structure to convert from the old waypoint system.
Shared order list linking together the linked list of orders and the list of vehicles sharing this or...
Definition order_base.h:259
DestinationID GetDestination() const
Gets the destination of this order.
Definition order_base.h:103
bool IsType(OrderType type) const
Check whether this order is of the given type.
Definition order_base.h:70
Order * next
Pointer to next order. If nullptr, end of list.
Definition order_base.h:59
void SetDestination(DestinationID destination)
Sets the destination of this order.
Definition order_base.h:110
Tindex index
Index of this pool item.
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
static Titem * Get(size_t index)
Returns Titem with given index.
SaveLoad type struct.
Definition saveload.h:717
Station specification.
GRFFilePropsBase< NUM_CARGO+3 > grf_prop
Properties related the the grf file.
Town data structure.
Definition town.h:54
Vehicle data structure.
Representation of a waypoint.
uint16_t town_cn
The N-1th waypoint for this town (consecutive number)
Owner GetTileOwner(Tile tile)
Returns the owner of a tile.
Definition tile_map.h:178
static debug_inline bool IsTileType(Tile tile, TileType type)
Checks if a tile is a given tiletype.
Definition tile_map.h:150
constexpr TileIndex INVALID_TILE
The very nice invalid tile marker.
Definition tile_type.h:95
StrongType::Typedef< uint32_t, struct TileIndexTag, StrongType::Compare, StrongType::Integer, StrongType::Compatible< int32_t >, StrongType::Compatible< int64_t > > TileIndex
The index/ID of a Tile.
Definition tile_type.h:87
@ MP_RAILWAY
A railway.
Definition tile_type.h:49
Town * ClosestTownFromTile(TileIndex tile, uint threshold)
Return the town closest (in distance or ownership) to a given tile, within a given threshold.
@ VEH_TRAIN
Train vehicle type.
static void UpdateWaypointOrder(Order *o)
Update the waypoint orders to get the new waypoint ID.
static std::vector< OldWaypoint > _old_waypoints
Temporary array with old waypoints.
void MoveWaypointsToBaseStations()
Perform all steps to upgrade from the old waypoints to the new version that uses station.