Freeciv-3.4
Loading...
Searching...
No Matches
savemain.c
Go to the documentation of this file.
1/***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12***********************************************************************/
13
14#ifdef HAVE_CONFIG_H
15#include <fc_config.h>
16#endif
17
18/* utility */
19#include "log.h"
20#include "mem.h"
21#include "registry.h"
22
23/* common */
24#include "ai.h"
25#include "capability.h"
26#include "game.h"
27#include "research.h"
28
29/* server */
30#include "console.h"
31#include "notify.h"
32
33/* server/ruleset */
34#include "ruleload.h"
35
36/* server/savegame */
37#include "savegame2.h"
38#include "savegame3.h"
39
40#include "savemain.h"
41
42static fc_thread *save_thread = nullptr;
43
44/************************************************************************/
47void savegame_load(struct section_file *sfile)
48{
49 const char *savefile_options;
50
51 fc_assert_ret(sfile != nullptr);
52
53#ifdef DEBUG_TIMERS
54 struct timer *loadtimer = timer_new(TIMER_CPU, TIMER_DEBUG, "load");
56#endif // DEBUG_TIMERS
57
58 savefile_options = secfile_lookup_str(sfile, "savefile.options");
59
60 if (savefile_options == nullptr) {
61 log_error("Missing savefile options. Can not load the savegame.");
63 return;
64 }
65
66 if (has_capabilities("+version3", savefile_options)) {
67 /* Load new format (freeciv 3.0.x and newer) */
68 log_verbose("loading savefile in 3.0+ format ...");
69 savegame3_load(sfile);
70 } else if (has_capabilities("+version2", savefile_options)) {
71 /* Load old format (freeciv 2.3 - 2.6) */
72 log_verbose("loading savefile in 2.3 - 2.6 format ...");
73 savegame2_load(sfile);
74 } else {
75 log_error("Too old savegame. Format not supported any more.");
77 return;
78 }
79
80 players_iterate(pplayer) {
81 unit_list_iterate(pplayer->units, punit) {
82 CALL_FUNC_EACH_AI(unit_created, punit);
83 CALL_PLR_AI_FUNC(unit_got, pplayer, punit);
85
86 city_list_iterate(pplayer->cities, pcity) {
87 CALL_FUNC_EACH_AI(city_created, pcity);
88 CALL_PLR_AI_FUNC(city_got, pplayer, pplayer, pcity);
91
92#ifdef DEBUG_TIMERS
94 log_debug("Loading secfile in %.3f seconds.", timer_read_seconds(loadtimer));
96#endif // DEBUG_TIMERS
97}
98
99/************************************************************************/
102void savegame_save(struct section_file *sfile, const char *save_reason,
103 bool scenario)
104{
105 savegame3_save(sfile, save_reason, scenario);
106}
107
115
116/************************************************************************/
120{
121 secfile_destroy(stdata->sfile);
122 free(stdata);
123}
124
125/************************************************************************/
128static void save_thread_run(void *arg)
129{
130 struct save_thread_data *stdata = (struct save_thread_data *)arg;
131
132 if (!secfile_save(stdata->sfile, stdata->filepath, stdata->save_compress_level,
133 stdata->save_compress_type)) {
134 con_write(C_FAIL, _("Failed saving game as %s"), stdata->filepath);
135 log_error("Game saving failed: %s", secfile_error());
136 notify_conn(nullptr, nullptr, E_LOG_ERROR, ftc_warning,
137 _("Failed saving game."));
138 } else {
139 con_write(C_OK, _("Game saved as %s"), stdata->filepath);
140 }
141
143}
144
145/************************************************************************/
149void save_game(const char *orig_filename, const char *save_reason,
150 bool scenario)
151{
152 char *dot, *filename;
153 struct timer *timer_cpu, *timer_user;
154 struct save_thread_data *stdata;
155
156 stdata = fc_malloc(sizeof(*stdata));
157
158 stdata->save_compress_type = game.server.save_compress_type;
159 stdata->save_compress_level = game.server.save_compress_level;
160
161 if (orig_filename == nullptr) {
162 stdata->filepath[0] = '\0';
163 filename = stdata->filepath;
164 } else {
165 sz_strlcpy(stdata->filepath, orig_filename);
166 if ((filename = strrchr(stdata->filepath, '/'))) {
167 filename++;
168 } else {
169 filename = stdata->filepath;
170 }
171
172 /* Ignores the dot at the start of the filename. */
173 for (dot = filename; '.' == *dot; dot++) {
174 /* Nothing. */
175 }
176 if ('\0' == *dot) {
177 /* Only dots in this file name, consider it as empty. */
178 filename[0] = '\0';
179 } else {
180 char *end_dot;
181 char *strip_extensions[] = {
182 ".sav", ".gz", ".bz2", ".xz", ".zst", nullptr };
183 bool stripped = TRUE;
184
185 while ((end_dot = strrchr(dot, '.')) && stripped) {
186 int i;
187
188 stripped = FALSE;
189
190 for (i = 0; strip_extensions[i] != nullptr && !stripped; i++) {
192 *end_dot = '\0';
193 stripped = TRUE;
194 }
195 }
196 }
197 }
198 }
199
200 /* If orig_filename is nullptr or empty, use a generated default name. */
201 if (filename[0] == '\0') {
202 /* Manual save */
204 sizeof(stdata->filepath) + stdata->filepath - filename, "manual");
205 }
206
211
212 /* Allowing duplicates shouldn't be allowed. However, it takes very too
213 * long time for huge game saving... */
214 stdata->sfile = secfile_new(TRUE);
215 savegame_save(stdata->sfile, save_reason, scenario);
216
217 /* We have consistent game state in stdata->sfile now, so
218 * we could pass it to the saving thread already. We want to
219 * handle below notify_conn() and directory creation in
220 * main thread, though. */
221
222 /* Append ".sav" to filename. */
223 sz_strlcat(stdata->filepath, ".sav");
224
225 if (stdata->save_compress_level > 0) {
226 switch (stdata->save_compress_type) {
227#ifdef FREECIV_HAVE_LIBZ
228 case FZ_ZLIB:
229 /* Append ".gz" to filename. */
230 sz_strlcat(stdata->filepath, ".gz");
231 break;
232#endif
233#ifdef FREECIV_HAVE_LIBLZMA
234 case FZ_XZ:
235 /* Append ".xz" to filename. */
236 sz_strlcat(stdata->filepath, ".xz");
237 break;
238#endif
239#ifdef FREECIV_HAVE_LIBZSTD
240 case FZ_ZSTD:
241 /* Append ".zstd" to filename. */
242 sz_strlcat(stdata->filepath, ".zst");
243 break;
244#endif /* FREECIV_HAVE_LIBZSTD */
245 case FZ_PLAIN:
246 break;
247 default:
248 log_error(_("Unsupported compression type %d."),
249 stdata->save_compress_type);
250 notify_conn(nullptr, nullptr, E_SETTING, ftc_warning,
251 _("Unsupported compression type %d."),
252 stdata->save_compress_type);
253 break;
254 }
255 }
256
257 if (!path_is_absolute(stdata->filepath)) {
258 char tmpname[600];
259
260 if (!scenario) {
261 /* Ensure the saves directory exists. */
262 if (srvarg.saves_pathname[0] != '\0'
264 log_error(_("Can't create saves directory %s!"),
266 /* Don't tell server paths to clients */
267 notify_conn(nullptr, nullptr, E_SETTING, ftc_warning,
268 _("Can't create saves directory!"));
269
273
274 return;
275 }
276
278 } else {
279 /* Make sure scenario directory exist */
280 if (srvarg.scenarios_pathname[0] != '\0'
282 log_error(_("Can't create scenario saves directory %s!"),
284 /* Don't tell server paths to clients */
285 notify_conn(nullptr, nullptr, E_SETTING, ftc_warning,
286 _("Can't create scenario saves directory!"));
287
291
292 return;
293 }
294
296 }
297
298 if (tmpname[0] != '\0') {
299 sz_strlcat(tmpname, "/");
300 }
301 sz_strlcat(tmpname, stdata->filepath);
302 sz_strlcpy(stdata->filepath, tmpname);
303 }
304
305 if (save_thread != nullptr) {
306 /* Previously started thread */
309 /* Setting has changed since the last save */
311 save_thread = nullptr;
312 }
313 } else if (game.server.threaded_save) {
315 }
316
317 if (save_thread != nullptr) {
319 } else {
321 }
322
323#ifdef LOG_TIMERS
324 log_verbose("Save time: %g seconds (%g apparent)",
326#endif // LOG_TIMERS
327
330}
331
332/************************************************************************/
336{
337 if (save_thread != nullptr) {
340 save_thread = nullptr;
341 }
342}
343
344/************************************************************************/
348{
349 /* Try to get the server back to a vaguely sane state */
353
357}
#define CALL_FUNC_EACH_AI(_func,...)
Definition ai.h:390
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:380
bool has_capabilities(const char *us, const char *them)
Definition capability.c:88
#define city_list_iterate(citylist, pcity)
Definition city.h:508
#define city_list_iterate_end
Definition city.h:510
char * incite_cost
Definition comments.c:77
void con_write(enum rfc_status rfc_status, const char *message,...)
Definition console.c:203
@ C_FAIL
Definition console.h:45
@ C_OK
Definition console.h:41
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit * punit
Definition dialogs_g.h:74
struct unit struct city struct unit struct tile struct extra_type const struct act_prob *act_probs int actor_unit_id struct unit struct unit int const struct action *paction struct unit struct city * pcity
Definition dialogs_g.h:78
#define _(String)
Definition fcintl.h:67
int fc_thread_start(fc_thread *thread, void(*function)(void *arg), void *arg)
Definition fcthread.c:83
void fc_thread_wait(fc_thread *thread)
Definition fcthread.c:102
const struct ft_color ftc_warning
struct civ_game game
Definition game.c:62
int generate_save_name(const char *format, char *buf, int buflen, const char *reason)
Definition game.c:801
fz_method
Definition ioz.h:37
@ FZ_PLAIN
Definition ioz.h:38
#define fc_assert_ret(condition)
Definition log.h:192
#define log_verbose(message,...)
Definition log.h:110
#define log_debug(message,...)
Definition log.h:116
#define log_error(message,...)
Definition log.h:104
#define fc_malloc(sz)
Definition mem.h:34
void notify_conn(struct conn_list *dest, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Definition notify.c:238
#define players_iterate_end
Definition player.h:552
#define players_iterate(_pplayer)
Definition player.h:547
struct section_file * secfile_new(bool allow_duplicates)
const char * secfile_error(void)
void secfile_destroy(struct section_file *secfile)
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
int recalculate_techs_researched(const struct research *presearch)
Definition research.c:1357
#define researches_iterate(_presearch)
Definition research.h:155
#define researches_iterate_end
Definition research.h:158
bool load_rulesets(const char *restore, const char *alt, bool compat_mode, rs_conversion_logger logger, bool act, bool buffer_script, bool load_luadata)
Definition ruleload.c:9437
void savegame2_load(struct section_file *file)
Definition savegame2.c:405
void savegame3_save(struct section_file *sfile, const char *save_reason, bool scenario)
Definition savegame3.c:434
void savegame3_load(struct section_file *file)
Definition savegame3.c:461
void savegame_load(struct section_file *sfile)
Definition savemain.c:47
void savegame_save(struct section_file *sfile, const char *save_reason, bool scenario)
Definition savemain.c:102
void save_system_close(void)
Definition savemain.c:335
static void save_thread_run(void *arg)
Definition savemain.c:128
static void save_thread_data_free(struct save_thread_data *stdata)
Definition savemain.c:119
void save_game(const char *orig_filename, const char *save_reason, bool scenario)
Definition savemain.c:149
void save_restore_sane_state(void)
Definition savemain.c:347
static fc_thread * save_thread
Definition savemain.c:42
bool make_dir(const char *pathname, int mode)
Definition shared.c:1779
bool path_is_absolute(const char *filename)
Definition shared.c:1884
#define DIRMODE_DEFAULT
Definition shared.h:258
void server_game_init(bool keep_ruleset_value)
Definition srv_main.c:3542
struct server_arguments srvarg
Definition srv_main.c:182
void server_game_free(void)
Definition srv_main.c:3566
bool threaded_save
Definition game.h:187
int save_compress_level
Definition game.h:188
char save_name[MAX_LEN_NAME]
Definition game.h:227
enum fz_method save_compress_type
Definition game.h:189
struct civ_game::@32::@36 server
int save_compress_level
Definition savemain.c:112
enum fz_method save_compress_type
Definition savemain.c:113
struct section_file * sfile
Definition savemain.c:110
char filepath[600]
Definition savemain.c:111
char * scenarios_pathname
Definition srv_main.h:47
char * saves_pathname
Definition srv_main.h:46
Definition timing.c:81
#define sz_strlcpy(dest, src)
Definition support.h:195
#define TRUE
Definition support.h:46
#define FALSE
Definition support.h:47
#define sz_strlcat(dest, src)
Definition support.h:196
void timer_destroy(struct timer *t)
Definition timing.c:208
void timer_start(struct timer *t)
Definition timing.c:263
void timer_stop(struct timer *t)
Definition timing.c:305
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
double timer_read_seconds(struct timer *t)
Definition timing.c:379
@ TIMER_ACTIVE
Definition timing.h:46
#define TIMER_DEBUG
Definition timing.h:61
@ TIMER_CPU
Definition timing.h:41
@ TIMER_USER
Definition timing.h:42
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
#define unit_list_iterate_end
Definition unitlist.h:33