OpenTTD Source 20241224-master-gf74b0cf984
linkgraph_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
12#include "saveload.h"
14
15#include "../linkgraph/linkgraph.h"
16#include "../linkgraph/linkgraphjob.h"
17#include "../linkgraph/linkgraphschedule.h"
18#include "../network/network.h"
19#include "../settings_internal.h"
20#include "../settings_table.h"
21
22#include "../safeguards.h"
23
26
27static uint16_t _num_nodes;
29static NodeID _linkgraph_from;
30
31class SlLinkgraphEdge : public DefaultSaveLoadHandler<SlLinkgraphEdge, Node> {
32public:
33 inline static const SaveLoad description[] = {
34 SLE_VAR(Edge, capacity, SLE_UINT32),
35 SLE_VAR(Edge, usage, SLE_UINT32),
36 SLE_CONDVAR(Edge, travel_time_sum, SLE_UINT64, SLV_LINKGRAPH_TRAVEL_TIME, SL_MAX_VERSION),
37 SLE_VAR(Edge, last_unrestricted_update, SLE_INT32),
38 SLE_CONDVAR(Edge, last_restricted_update, SLE_INT32, SLV_187, SL_MAX_VERSION),
39 SLE_VAR(Edge, dest_node, SLE_UINT16),
40 SLE_CONDVARNAME(Edge, dest_node, "next_edge", SLE_UINT16, SL_MIN_VERSION, SLV_LINKGRAPH_EDGES),
41 };
42 inline const static SaveLoadCompatTable compat_description = _linkgraph_edge_sl_compat;
43
44 void Save(Node *bn) const override
45 {
46 SlSetStructListLength(bn->edges.size());
47 for (Edge &e : bn->edges) {
48 SlObject(&e, this->GetDescription());
49 }
50 }
51
52 void Load(Node *bn) const override
53 {
55 uint16_t max_size = _linkgraph->Size();
56 std::vector<Edge> edges(max_size);
57
59 /* We used to save the full matrix ... */
60 for (NodeID to = 0; to < max_size; ++to) {
61 SlObject(&edges[to], this->GetLoadDescription());
62 }
63 } else {
64 size_t used_size = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? max_size : SlGetStructListLength(UINT16_MAX);
65
66 /* ... but as that wasted a lot of space we save a sparse matrix now. */
67 for (NodeID to = _linkgraph_from; to != INVALID_NODE; to = edges[to].dest_node) {
68 if (used_size == 0) SlErrorCorrupt("Link graph structure overflow");
69 used_size--;
70
71 if (to >= max_size) SlErrorCorrupt("Link graph structure overflow");
72 SlObject(&edges[to], this->GetLoadDescription());
73 }
74
75 if (!IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) && used_size > 0) SlErrorCorrupt("Corrupted link graph");
76 }
77
78 /* Build edge list from edge matrix. */
79 for (NodeID to = edges[_linkgraph_from].dest_node; to != INVALID_NODE; to = edges[to].dest_node) {
80 auto &edge = bn->edges.emplace_back(edges[to]);
81 edge.dest_node = to;
82 }
83 /* Sort by destination. */
84 std::sort(bn->edges.begin(), bn->edges.end());
85 } else {
86 /* Edge data is now a simple vector and not any kind of matrix. */
87 size_t size = SlGetStructListLength(UINT16_MAX);
88 for (size_t i = 0; i < size; i++) {
89 bn->edges.emplace_back();
90 SlObject(&bn->edges.back(), this->GetLoadDescription());
91 }
92 }
93 }
94};
95
96class SlLinkgraphNode : public DefaultSaveLoadHandler<SlLinkgraphNode, LinkGraph> {
97public:
98 inline static const SaveLoad description[] = {
99 SLE_CONDVAR(Node, xy, SLE_UINT32, SLV_191, SL_MAX_VERSION),
100 SLE_VAR(Node, supply, SLE_UINT32),
101 SLE_VAR(Node, demand, SLE_UINT32),
102 SLE_VAR(Node, station, SLE_UINT16),
103 SLE_VAR(Node, last_update, SLE_INT32),
105 };
106 inline const static SaveLoadCompatTable compat_description = _linkgraph_node_sl_compat;
107
108 void Save(LinkGraph *lg) const override
109 {
110 _linkgraph = lg;
111
113 for (NodeID from = 0; from < lg->Size(); ++from) {
114 _linkgraph_from = from;
115 SlObject(&lg->nodes[from], this->GetDescription());
116 }
117 }
118
119 void Load(LinkGraph *lg) const override
120 {
121 _linkgraph = lg;
122
123 uint16_t length = IsSavegameVersionBefore(SLV_SAVELOAD_LIST_LENGTH) ? _num_nodes : (uint16_t)SlGetStructListLength(UINT16_MAX);
124 lg->Init(length);
125 for (NodeID from = 0; from < length; ++from) {
126 _linkgraph_from = from;
127 SlObject(&lg->nodes[from], this->GetLoadDescription());
128 }
129 }
130};
131
137{
138 static const SaveLoad link_graph_desc[] = {
139 SLE_VAR(LinkGraph, last_compression, SLE_INT32),
140 SLEG_CONDVAR("num_nodes", _num_nodes, SLE_UINT16, SL_MIN_VERSION, SLV_SAVELOAD_LIST_LENGTH),
141 SLE_VAR(LinkGraph, cargo, SLE_UINT8),
143 };
144 return link_graph_desc;
145}
146
154class SlLinkgraphJobProxy : public DefaultSaveLoadHandler<SlLinkgraphJobProxy, LinkGraphJob> {
155public:
156 inline static const SaveLoad description[] = {{}}; // Needed to keep DefaultSaveLoadHandler happy.
157 SaveLoadTable GetDescription() const override { return GetLinkGraphDesc(); }
158 inline const static SaveLoadCompatTable compat_description = _linkgraph_sl_compat;
159
160 void Save(LinkGraphJob *lgj) const override
161 {
162 SlObject(const_cast<LinkGraph *>(&lgj->Graph()), this->GetDescription());
163 }
164
165 void Load(LinkGraphJob *lgj) const override
166 {
167 SlObject(const_cast<LinkGraph *>(&lgj->Graph()), this->GetLoadDescription());
168 }
169};
170
181{
182 static std::vector<SaveLoad> saveloads;
183
184 static const SaveLoad job_desc[] = {
185 SLE_VAR(LinkGraphJob, join_date, SLE_INT32),
186 SLE_VAR(LinkGraphJob, link_graph.index, SLE_UINT16),
187 SLEG_STRUCT("linkgraph", SlLinkgraphJobProxy),
188 };
189
190 /* The member offset arithmetic below is only valid if the types in question
191 * are standard layout types. Otherwise, it would be undefined behaviour. */
192 static_assert(std::is_standard_layout<LinkGraphSettings>::value, "LinkGraphSettings needs to be a standard layout type");
193
194 /* We store the offset of each member of the #LinkGraphSettings in the
195 * extra data of the saveload struct. Use it together with the address
196 * of the settings struct inside the job to find the final memory address. */
197 static SaveLoadAddrProc * const proc = [](void *b, size_t extra) -> void * { return const_cast<void *>(static_cast<const void *>(reinterpret_cast<const char *>(std::addressof(static_cast<LinkGraphJob *>(b)->settings)) + extra)); };
198
199 /* Build the SaveLoad array on first call and don't touch it later on */
200 if (saveloads.empty()) {
201 GetSaveLoadFromSettingTable(_linkgraph_settings, saveloads);
202
203 for (auto &sl : saveloads) {
204 sl.address_proc = proc;
205 }
206
207 for (auto &sld : job_desc) {
208 saveloads.push_back(sld);
209 }
210 }
211
212 return saveloads;
213}
214
220{
221 static const SaveLoad schedule_desc[] = {
224 };
225 return schedule_desc;
226}
227
233{
235 for (LinkGraph *lg : LinkGraph::Iterate()) {
236 for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) {
237 const Station *st = Station::GetIfValid((*lg)[node_id].station);
238 if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy);
239 }
240 }
241
242 for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
243 LinkGraph *lg = &(const_cast<LinkGraph &>(lgj->Graph()));
244 for (NodeID node_id = 0; node_id < lg->Size(); ++node_id) {
245 const Station *st = Station::GetIfValid((*lg)[node_id].station);
246 if (st != nullptr) (*lg)[node_id].UpdateLocation(st->xy);
247 }
248 }
249 }
250
252
255 }
256}
257
262 LGRPChunkHandler() : ChunkHandler('LGRP', CH_TABLE) {}
263
264 void Save() const override
265 {
267
268 for (LinkGraph *lg : LinkGraph::Iterate()) {
269 SlSetArrayIndex(lg->index);
271 }
272 }
273
274 void Load() const override
275 {
276 const std::vector<SaveLoad> slt = SlCompatTableHeader(GetLinkGraphDesc(), _linkgraph_sl_compat);
277
278 int index;
279 while ((index = SlIterateArray()) != -1) {
280 LinkGraph *lg = new (index) LinkGraph();
281 SlObject(lg, slt);
282 }
283 }
284};
285
290 LGRJChunkHandler() : ChunkHandler('LGRJ', CH_TABLE) {}
291
292 void Save() const override
293 {
295
296 for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
297 SlSetArrayIndex(lgj->index);
299 }
300 }
301
302 void Load() const override
303 {
304 const std::vector<SaveLoad> slt = SlCompatTableHeader(GetLinkGraphJobDesc(), _linkgraph_job_sl_compat);
305
306 int index;
307 while ((index = SlIterateArray()) != -1) {
308 LinkGraphJob *lgj = new (index) LinkGraphJob();
309 SlObject(lgj, slt);
310 }
311 }
312};
313
318 LGRSChunkHandler() : ChunkHandler('LGRS', CH_TABLE) {}
319
320 void Save() const override
321 {
323
324 SlSetArrayIndex(0);
326 }
327
328 void Load() const override
329 {
331
334 if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many LGRS entries");
335 }
336
341};
342
343static const LGRPChunkHandler LGRP;
344static const LGRJChunkHandler LGRJ;
345static const LGRSChunkHandler LGRS;
346static const ChunkHandlerRef linkgraph_chunk_handlers[] = {
347 LGRP,
348 LGRJ,
349 LGRS,
350};
351
352extern const ChunkHandlerTable _linkgraph_chunk_handlers(linkgraph_chunk_handlers);
Default handler for saving/loading an object to/from disk.
Definition saveload.h:581
SaveLoadTable GetDescription() const override
Definition saveload.h:583
Class for calculation jobs to be run on link graphs.
const LinkGraph & Graph() const
Get a reference to the underlying link graph.
static LinkGraphSchedule instance
Static instance of LinkGraphSchedule.
void SpawnAll()
Start all threads in the running list.
A connected component of a link graph.
Definition linkgraph.h:37
void Init(uint size)
Resize the component and fill it with empty nodes and edges.
NodeVector nodes
Nodes in the component.
Definition linkgraph.h:266
NodeID Size() const
Get the current size of the component.
Definition linkgraph.h:230
SaveLoadTable GetLoadDescription() const
Get the description for how to load the chunk.
Proxy to reuse LinkGraph to save/load a LinkGraphJob.
SaveLoadTable GetDescription() const override
Get the description of the fields in the savegame.
fluid_settings_t * settings
FluidSynth settings handle.
SaveLoadTable GetLinkGraphDesc()
Get a SaveLoad array for a link graph.
SaveLoadTable GetLinkGraphScheduleDesc()
Get a SaveLoad array for the link graph schedule.
static LinkGraph * _linkgraph
Contains the current linkgraph being saved/loaded.
void AfterLoadLinkGraphs()
Spawn the threads for running link graph calculations.
SaveLoadTable GetLinkGraphJobDesc()
Get a SaveLoad array for a link graph job.
static NodeID _linkgraph_from
Contains the current "from" node being saved/loaded.
Loading of linkgraph chunks before table headers were added.
const SaveLoadCompat _linkgraph_node_sl_compat[]
Original field order for SlLinkgraphNode.
const SaveLoadCompat _linkgraph_edge_sl_compat[]
Original field order for SlLinkgraphEdge.
const SaveLoadCompat _linkgraph_schedule_sl_compat[]
Original field order for schedule_desc.
const SaveLoadCompat _linkgraph_job_sl_compat[]
Original field order for job_desc.
const SaveLoadCompat _linkgraph_sl_compat[]
Original field order for link_graph_desc.
void AfterLoad_LinkGraphPauseControl()
Pause the game on load if we would do a join with the next link graph job, but it is still running,...
bool _networking
are we in networking mode?
Definition network.cpp:65
bool _network_server
network-server is active
Definition network.cpp:66
std::vector< SaveLoad > SlCompatTableHeader(const SaveLoadTable &slt, const SaveLoadCompatTable &slct)
Load a table header in a savegame compatible way.
size_t SlGetStructListLength(size_t limit)
Get the length of this list; if it exceeds the limit, error out.
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.
std::vector< SaveLoad > SlTableHeader(const SaveLoadTable &slt)
Save or Load a table header.
void SlSetStructListLength(size_t length)
Set the length of this list.
Functions/types related to saving and loading games.
#define SLEG_STRUCTLIST(name, handler)
Storage of a list of structs in every savegame version.
Definition saveload.h:1241
#define SLEG_CONDVAR(name, variable, type, from, to)
Storage of a global variable in some savegame versions.
Definition saveload.h:1109
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_REFLIST(base, variable, type)
Storage of a list of SL_REF elements in every savegame version.
Definition saveload.h:1063
std::span< const struct SaveLoadCompat > SaveLoadCompatTable
A table of SaveLoadCompat entries.
Definition saveload.h:518
#define SLEG_STRUCT(name, handler)
Storage of a structs in every savegame version.
Definition saveload.h:1218
#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_SAVELOAD_LIST_LENGTH
293 PR#9374 Consistency in list length with SL_STRUCT / SL_STRUCTLIST / SL_DEQUE / SL_REFLIST.
Definition saveload.h:331
@ SLV_191
191 26636 FS#6026 Fix disaster vehicle storage (No bump) 191 26646 FS#6041 Linkgraph - store location...
Definition saveload.h:272
@ SLV_RIFF_TO_ARRAY
294 PR#9375 Changed many CH_RIFF chunks to CH_ARRAY chunks.
Definition saveload.h:332
@ SLV_LINKGRAPH_EDGES
304 PR#10314 Explicitly store link graph edges destination, PR#10471 int64_t instead of uint64_t leag...
Definition saveload.h:344
@ SL_MAX_VERSION
Highest possible saveload version.
Definition saveload.h:399
@ SL_MIN_VERSION
First savegame version.
Definition saveload.h:31
@ SLV_187
187 25899 Linkgraph - restricted flows
Definition saveload.h:267
@ SLV_LINKGRAPH_TRAVEL_TIME
297 PR#9457 v12.0-RC1 Store travel time in the linkgraph.
Definition saveload.h:336
@ REF_LINK_GRAPH_JOB
Load/save a reference to a link graph job.
Definition saveload.h:612
@ REF_LINK_GRAPH
Load/save a reference to a link graph.
Definition saveload.h:611
std::span< const struct SaveLoad > SaveLoadTable
A table of SaveLoad entries.
Definition saveload.h:515
#define SLE_VAR(base, variable, type)
Storage of a variable in every version of a savegame.
Definition saveload.h:1002
#define SLE_CONDVARNAME(base, variable, name, type, from, to)
Storage of a variable in some savegame versions.
Definition saveload.h:879
void GetSaveLoadFromSettingTable(SettingTable settings, std::vector< SaveLoad > &saveloads)
Get the SaveLoad for all settings in the settings table.
TileIndex xy
Base tile of the station.
Handlers and description of chunk.
Definition saveload.h:463
All link graph jobs.
void Save() const override
Save the chunk.
void Load() const override
Load the chunk.
All link graphs.
void Load() const override
Load the chunk.
void Save() const override
Save the chunk.
Link graph schedule.
void FixPointers() const override
Fix the pointers.
void Load() const override
Load the chunk.
void Save() const override
Save the chunk.
An edge in the link graph.
Definition linkgraph.h:42
Node of the link graph.
Definition linkgraph.h:90
std::vector< BaseEdge > edges
Sorted list of outgoing edges from this node.
Definition linkgraph.h:97
Tindex index
Index of this pool item.
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
SaveLoad type struct.
Definition saveload.h:717
static Station * GetIfValid(size_t index)
Returns station if the index is a valid index for this station type.
Station data structure.