4 * This file is part of OpenTTD.
5 * 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.
6 * 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.
7 * 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/>.
10 /** @file linkgraph_sl.cpp Code handling saving and loading of link graphs */
12 #include "../stdafx.h"
13 #include "../linkgraph/linkgraph.h"
14 #include "../linkgraph/linkgraphjob.h"
15 #include "../linkgraph/linkgraphschedule.h"
16 #include "../settings_internal.h"
19 #include "../safeguards.h"
21 typedef LinkGraph::BaseNode Node
;
22 typedef LinkGraph::BaseEdge Edge
;
24 const SettingDesc
*GetSettingDescription(uint index
);
26 static uint16 _num_nodes
;
29 * Get a SaveLoad array for a link graph.
30 * @return SaveLoad array for link graph.
32 const SaveLoad
*GetLinkGraphDesc()
34 static const SaveLoad link_graph_desc
[] = {
35 SLE_VAR(LinkGraph
, last_compression
, SLE_INT32
),
36 SLEG_VAR(_num_nodes
, SLE_UINT16
),
37 SLE_VAR(LinkGraph
, cargo
, SLE_UINT8
),
40 return link_graph_desc
;
43 void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob
*lgj
)
45 lgj
->join_date_ticks
*= DAY_TICKS
;
46 lgj
->join_date_ticks
+= LinkGraphSchedule::SPAWN_JOIN_TICK
;
47 lgj
->start_date_ticks
= lgj
->join_date_ticks
- (lgj
->Settings().recalc_time
* DAY_TICKS
);
51 * Get a SaveLoad array for a link graph job. The settings struct is derived from
52 * the global settings saveload array. The exact entries are calculated when the function
53 * is called the first time.
54 * It's necessary to keep a copy of the settings for each link graph job so that you can
55 * change the settings while in-game and still not mess with current link graph runs.
56 * Of course the settings have to be saved and loaded, too, to avoid desyncs.
57 * @return Array of SaveLoad structs.
59 const SaveLoad
*GetLinkGraphJobDesc()
61 static SmallVector
<SaveLoad
, 16> saveloads
;
62 static const char *prefix
= "linkgraph.";
64 /* Build the SaveLoad array on first call and don't touch it later on */
65 if (saveloads
.Length() == 0) {
66 size_t offset_gamesettings
= cpp_offsetof(GameSettings
, linkgraph
);
67 size_t offset_component
= cpp_offsetof(LinkGraphJob
, settings
);
69 size_t prefixlen
= strlen(prefix
);
72 const SettingDesc
*desc
= GetSettingDescription(setting
);
73 while (desc
->save
.cmd
!= SL_END
) {
74 if (desc
->desc
.name
!= NULL
&& strncmp(desc
->desc
.name
, prefix
, prefixlen
) == 0) {
75 SaveLoad sl
= desc
->save
;
76 char *&address
= reinterpret_cast<char *&>(sl
.address
);
77 address
-= offset_gamesettings
;
78 address
+= offset_component
;
79 *(saveloads
.Append()) = sl
;
81 desc
= GetSettingDescription(++setting
);
84 const SaveLoad job_desc
[] = {
85 SLE_VAR(LinkGraphJob
, join_date_ticks
, SLE_INT32
),
86 SLE_CONDVAR(LinkGraphJob
, start_date_ticks
, SLE_INT32
, SL_PATCH_PACK_1_21
, SL_MAX_VERSION
),
87 SLE_VAR(LinkGraphJob
, link_graph
.index
, SLE_UINT16
),
93 *(saveloads
.Append()) = job_desc
[i
++];
94 } while (saveloads
[saveloads
.Length() - 1].cmd
!= SL_END
);
101 * Get a SaveLoad array for the link graph schedule.
102 * @return SaveLoad array for the link graph schedule.
104 const SaveLoad
*GetLinkGraphScheduleDesc()
106 static const SaveLoad schedule_desc
[] = {
107 SLE_LST(LinkGraphSchedule
, schedule
, REF_LINK_GRAPH
),
108 SLE_LST(LinkGraphSchedule
, running
, REF_LINK_GRAPH_JOB
),
111 return schedule_desc
;
114 /* Edges and nodes are saved in the correct order, so we don't need to save their IDs. */
117 * SaveLoad desc for a link graph node.
119 static const SaveLoad _node_desc
[] = {
120 SLE_CONDVAR(Node
, xy
, SLE_UINT32
, 191, SL_PATCH_PACK
- 1),
121 SLE_CONDVAR(Node
, xy
, SLE_UINT32
, SL_PATCH_PACK_1_8
, SL_MAX_VERSION
),
122 SLE_VAR(Node
, supply
, SLE_UINT32
),
123 SLE_VAR(Node
, demand
, SLE_UINT32
),
124 SLE_VAR(Node
, station
, SLE_UINT16
),
125 SLE_VAR(Node
, last_update
, SLE_INT32
),
130 * SaveLoad desc for a link graph edge.
132 static const SaveLoad _edge_desc
[] = {
133 SLE_CONDNULL(4, 0, 190), // distance
134 SLE_CONDNULL(4, SL_PATCH_PACK
, SL_PATCH_PACK_1_7
), // distance
135 SLE_VAR(Edge
, capacity
, SLE_UINT32
),
136 SLE_VAR(Edge
, usage
, SLE_UINT32
),
137 SLE_VAR(Edge
, last_unrestricted_update
, SLE_INT32
),
138 SLE_CONDVAR(Edge
, last_restricted_update
, SLE_INT32
, 187, SL_MAX_VERSION
),
139 SLE_VAR(Edge
, next_edge
, SLE_UINT16
),
144 * Save/load a link graph.
145 * @param comp Link graph to be saved or loaded.
147 void SaveLoad_LinkGraph(LinkGraph
&lg
)
149 uint size
= lg
.Size();
150 for (NodeID from
= 0; from
< size
; ++from
) {
151 Node
*node
= &lg
.nodes
[from
];
152 SlObject(node
, _node_desc
);
153 if (IsSavegameVersionBefore(191) || IsPatchPackSavegameVersionBefore(SL_PATCH_PACK_1_8
)) {
154 /* We used to save the full matrix ... */
155 for (NodeID to
= 0; to
< size
; ++to
) {
156 SlObject(&lg
.edges
[from
][to
], _edge_desc
);
160 /* ... but as that wasted a lot of space we save a sparse matrix now. */
161 for (NodeID to
= from
; to
!= INVALID_NODE
; to
= lg
.edges
[from
][to
].next_edge
) {
162 SlObject(&lg
.edges
[from
][to
], _edge_desc
);
169 * Save a link graph job.
170 * @param lgj LinkGraphJob to be saved.
172 static void DoSave_LGRJ(LinkGraphJob
*lgj
)
174 SlObject(lgj
, GetLinkGraphJobDesc());
175 _num_nodes
= lgj
->Size();
176 SlObject(const_cast<LinkGraph
*>(&lgj
->Graph()), GetLinkGraphDesc());
177 SaveLoad_LinkGraph(const_cast<LinkGraph
&>(lgj
->Graph()));
182 * @param lg LinkGraph to be saved.
184 static void DoSave_LGRP(LinkGraph
*lg
)
186 _num_nodes
= lg
->Size();
187 SlObject(lg
, GetLinkGraphDesc());
188 SaveLoad_LinkGraph(*lg
);
192 * Load all link graphs.
194 static void Load_LGRP()
197 while ((index
= SlIterateArray()) != -1) {
198 if (!LinkGraph::CanAllocateItem()) {
199 /* Impossible as they have been present in previous game. */
202 LinkGraph
*lg
= new (index
) LinkGraph();
203 SlObject(lg
, GetLinkGraphDesc());
204 lg
->Init(_num_nodes
);
205 SaveLoad_LinkGraph(*lg
);
210 * Load all link graph jobs.
212 static void Load_LGRJ()
215 while ((index
= SlIterateArray()) != -1) {
216 if (!LinkGraphJob::CanAllocateItem()) {
217 /* Impossible as they have been present in previous game. */
220 LinkGraphJob
*lgj
= new (index
) LinkGraphJob();
221 SlObject(lgj
, GetLinkGraphJobDesc());
222 if (IsSavegameVersionBefore(SL_PATCH_PACK_1_21
)) {
223 GetLinkGraphJobDayLengthScaleAfterLoad(lgj
);
225 LinkGraph
&lg
= const_cast<LinkGraph
&>(lgj
->Graph());
226 SlObject(&lg
, GetLinkGraphDesc());
228 SaveLoad_LinkGraph(lg
);
233 * Load the link graph schedule.
235 static void Load_LGRS()
237 SlObject(&LinkGraphSchedule::instance
, GetLinkGraphScheduleDesc());
241 * Spawn the threads for running link graph calculations.
242 * Has to be done after loading as the cargo classes might have changed.
244 void AfterLoadLinkGraphs()
246 if (IsSavegameVersionBefore(191) || IsPatchPackSavegameVersionBefore(SL_PATCH_PACK_1_8
)) {
248 FOR_ALL_LINK_GRAPHS(lg
) {
249 for (NodeID node_id
= 0; node_id
< lg
->Size(); ++node_id
) {
250 (*lg
)[node_id
].UpdateLocation(Station::Get((*lg
)[node_id
].Station())->xy
);
255 FOR_ALL_LINK_GRAPH_JOBS(lgj
) {
256 lg
= &(const_cast<LinkGraph
&>(lgj
->Graph()));
257 for (NodeID node_id
= 0; node_id
< lg
->Size(); ++node_id
) {
258 (*lg
)[node_id
].UpdateLocation(Station::Get((*lg
)[node_id
].Station())->xy
);
263 LinkGraphSchedule::instance
.SpawnAll();
267 * Save all link graphs.
269 static void Save_LGRP()
272 FOR_ALL_LINK_GRAPHS(lg
) {
273 SlSetArrayIndex(lg
->index
);
274 SlAutolength((AutolengthProc
*)DoSave_LGRP
, lg
);
279 * Save all link graph jobs.
281 static void Save_LGRJ()
284 FOR_ALL_LINK_GRAPH_JOBS(lgj
) {
285 SlSetArrayIndex(lgj
->index
);
286 SlAutolength((AutolengthProc
*)DoSave_LGRJ
, lgj
);
291 * Save the link graph schedule.
293 static void Save_LGRS()
295 SlObject(&LinkGraphSchedule::instance
, GetLinkGraphScheduleDesc());
299 * Substitute pointers in link graph schedule.
301 static void Ptrs_LGRS()
303 SlObject(&LinkGraphSchedule::instance
, GetLinkGraphScheduleDesc());
306 extern const ChunkHandler _linkgraph_chunk_handlers
[] = {
307 { 'LGRP', Save_LGRP
, Load_LGRP
, NULL
, NULL
, CH_ARRAY
},
308 { 'LGRJ', Save_LGRJ
, Load_LGRJ
, NULL
, NULL
, CH_ARRAY
},
309 { 'LGRS', Save_LGRS
, Load_LGRS
, Ptrs_LGRS
, NULL
, CH_LAST
}