Freeciv-3.3: /fast/freeciv/nightly/main/server/savegame/savemain.c Source File

Freeciv-3.3

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
28/* server */
29#include "console.h"
30#include "notify.h"
31
32/* server/savegame */
33#include "savegame2.h"
34#include "savegame3.h"
35
36#include "savemain.h"
37
38 static fc_thread *save_thread = nullptr;
39
40/************************************************************************/
43 void savegame_load(struct section_file *sfile)
44{
45 const char *savefile_options;
46
47 fc_assert_ret(sfile != nullptr);
48
49#ifdef DEBUG_TIMERS
50 struct timer *loadtimer = timer_new(TIMER_CPU, TIMER_DEBUG, "load");
51 timer_start(loadtimer);
52#endif // DEBUG_TIMERS
53
54 savefile_options = secfile_lookup_str(sfile, "savefile.options");
55
56 if (savefile_options == nullptr) {
57 log_error("Missing savefile options. Can not load the savegame.");
58 return;
59 }
60
61 if (has_capabilities("+version3", savefile_options)) {
62 /* Load new format (freeciv 3.0.x and newer) */
63 log_verbose("loading savefile in 3.0+ format ...");
64 savegame3_load(sfile);
65 } else if (has_capabilities("+version2", savefile_options)) {
66 /* Load old format (freeciv 2.3 - 2.6) */
67 log_verbose("loading savefile in 2.3 - 2.6 format ...");
68 savegame2_load(sfile);
69 } else {
70 log_error("Too old savegame. Format not supported any more.");
71 return;
72 }
73
74 players_iterate(pplayer) {
75 unit_list_iterate(pplayer->units, punit) {
76 CALL_FUNC_EACH_AI(unit_created, punit);
77 CALL_PLR_AI_FUNC(unit_got, pplayer, punit);
78 } unit_list_iterate_end;
79
80 city_list_iterate(pplayer->cities, pcity) {
81 CALL_FUNC_EACH_AI(city_created, pcity);
82 CALL_PLR_AI_FUNC(city_got, pplayer, pplayer, pcity);
83 } city_list_iterate_end;
84 } players_iterate_end;
85
86#ifdef DEBUG_TIMERS
87 timer_stop(loadtimer);
88 log_debug("Loading secfile in %.3f seconds.", timer_read_seconds(loadtimer));
89 timer_destroy(loadtimer);
90#endif // DEBUG_TIMERS
91}
92
93/************************************************************************/
96 void savegame_save(struct section_file *sfile, const char *save_reason,
97 bool scenario)
98{
99 savegame3_save(sfile, save_reason, scenario);
100}
101
102 struct save_thread_data
103{
104 struct section_file *sfile;
105 char filepath[600];
106 int save_compress_level;
107 enum fz_method save_compress_type;
108};
109
110/************************************************************************/
113 static void save_thread_data_free(struct save_thread_data *stdata)
114{
115 secfile_destroy(stdata->sfile);
116 free(stdata);
117}
118
119/************************************************************************/
122 static void save_thread_run(void *arg)
123{
124 struct save_thread_data *stdata = (struct save_thread_data *)arg;
125
126 if (!secfile_save(stdata->sfile, stdata->filepath, stdata->save_compress_level,
127 stdata->save_compress_type)) {
128 con_write(C_FAIL, _("Failed saving game as %s"), stdata->filepath);
129 log_error("Game saving failed: %s", secfile_error());
130 notify_conn(nullptr, nullptr, E_LOG_ERROR, ftc_warning,
131 _("Failed saving game."));
132 } else {
133 con_write(C_OK, _("Game saved as %s"), stdata->filepath);
134 }
135
136 save_thread_data_free(stdata);
137}
138
139/************************************************************************/
143 void save_game(const char *orig_filename, const char *save_reason,
144 bool scenario)
145{
146 char *dot, *filename;
147 struct timer *timer_cpu, *timer_user;
148 struct save_thread_data *stdata;
149
150 stdata = fc_malloc(sizeof(*stdata));
151
152 stdata->save_compress_type = game.server.save_compress_type;
153 stdata->save_compress_level = game.server.save_compress_level;
154
155 if (orig_filename == nullptr) {
156 stdata->filepath[0] = '\0';
157 filename = stdata->filepath;
158 } else {
159 sz_strlcpy(stdata->filepath, orig_filename);
160 if ((filename = strrchr(stdata->filepath, '/'))) {
161 filename++;
162 } else {
163 filename = stdata->filepath;
164 }
165
166 /* Ignores the dot at the start of the filename. */
167 for (dot = filename; '.' == *dot; dot++) {
168 /* Nothing. */
169 }
170 if ('\0' == *dot) {
171 /* Only dots in this file name, consider it as empty. */
172 filename[0] = '\0';
173 } else {
174 char *end_dot;
175 char *strip_extensions[] = {
176 ".sav", ".gz", ".bz2", ".xz", ".zst", nullptr };
177 bool stripped = TRUE;
178
179 while ((end_dot = strrchr(dot, '.')) && stripped) {
180 int i;
181
182 stripped = FALSE;
183
184 for (i = 0; strip_extensions[i] != nullptr && !stripped; i++) {
185 if (!strcmp(end_dot, strip_extensions[i])) {
186 *end_dot = '\0';
187 stripped = TRUE;
188 }
189 }
190 }
191 }
192 }
193
194 /* If orig_filename is nullptr or empty, use a generated default name. */
195 if (filename[0] == '\0') {
196 /* Manual save */
197 generate_save_name(game.server.save_name, filename,
198 sizeof(stdata->filepath) + stdata->filepath - filename, "manual");
199 }
200
201 timer_cpu = timer_new(TIMER_CPU, TIMER_ACTIVE, "save cpu");
202 timer_user = timer_new(TIMER_USER, TIMER_ACTIVE, "save user");
203 timer_start(timer_cpu);
204 timer_start(timer_user);
205
206 /* Allowing duplicates shouldn't be allowed. However, it takes very too
207 * long time for huge game saving... */
208 stdata->sfile = secfile_new(TRUE);
209 savegame_save(stdata->sfile, save_reason, scenario);
210
211 /* We have consistent game state in stdata->sfile now, so
212 * we could pass it to the saving thread already. We want to
213 * handle below notify_conn() and directory creation in
214 * main thread, though. */
215
216 /* Append ".sav" to filename. */
217 sz_strlcat(stdata->filepath, ".sav");
218
219 if (stdata->save_compress_level > 0) {
220 switch (stdata->save_compress_type) {
221#ifdef FREECIV_HAVE_LIBZ
222 case FZ_ZLIB:
223 /* Append ".gz" to filename. */
224 sz_strlcat(stdata->filepath, ".gz");
225 break;
226#endif
227#ifdef FREECIV_HAVE_LIBLZMA
228 case FZ_XZ:
229 /* Append ".xz" to filename. */
230 sz_strlcat(stdata->filepath, ".xz");
231 break;
232#endif
233#ifdef FREECIV_HAVE_LIBZSTD
234 case FZ_ZSTD:
235 /* Append ".zstd" to filename. */
236 sz_strlcat(stdata->filepath, ".zst");
237 break;
238#endif /* FREECIV_HAVE_LIBZSTD */
239 case FZ_PLAIN:
240 break;
241 default:
242 log_error(_("Unsupported compression type %d."),
243 stdata->save_compress_type);
244 notify_conn(nullptr, nullptr, E_SETTING, ftc_warning,
245 _("Unsupported compression type %d."),
246 stdata->save_compress_type);
247 break;
248 }
249 }
250
251 if (!path_is_absolute(stdata->filepath)) {
252 char tmpname[600];
253
254 if (!scenario) {
255 /* Ensure the saves directory exists. */
256 if (srvarg.saves_pathname[0] != '\0'
257 && !make_dir(srvarg.saves_pathname, DIRMODE_DEFAULT)) {
258 log_error(_("Can't create saves directory %s!"),
259 srvarg.saves_pathname);
260 /* Don't tell server paths to clients */
261 notify_conn(nullptr, nullptr, E_SETTING, ftc_warning,
262 _("Can't create saves directory!"));
263
264 save_thread_data_free(stdata);
265 timer_destroy(timer_cpu);
266 timer_destroy(timer_user);
267
268 return;
269 }
270
271 sz_strlcpy(tmpname, srvarg.saves_pathname);
272 } else {
273 /* Make sure scenario directory exist */
274 if (srvarg.scenarios_pathname[0] != '\0'
275 && !make_dir(srvarg.scenarios_pathname, DIRMODE_DEFAULT)) {
276 log_error(_("Can't create scenario saves directory %s!"),
277 srvarg.scenarios_pathname);
278 /* Don't tell server paths to clients */
279 notify_conn(nullptr, nullptr, E_SETTING, ftc_warning,
280 _("Can't create scenario saves directory!"));
281
282 save_thread_data_free(stdata);
283 timer_destroy(timer_cpu);
284 timer_destroy(timer_user);
285
286 return;
287 }
288
289 sz_strlcpy(tmpname, srvarg.scenarios_pathname);
290 }
291
292 if (tmpname[0] != '\0') {
293 sz_strlcat(tmpname, "/");
294 }
295 sz_strlcat(tmpname, stdata->filepath);
296 sz_strlcpy(stdata->filepath, tmpname);
297 }
298
299 if (save_thread != nullptr) {
300 /* Previously started thread */
301 fc_thread_wait(save_thread);
302 if (!game.server.threaded_save) {
303 /* Setting has changed since the last save */
304 free(save_thread);
305 save_thread = nullptr;
306 }
307 } else if (game.server.threaded_save) {
308 save_thread = fc_malloc(sizeof(save_thread));
309 }
310
311 if (save_thread != nullptr) {
312 fc_thread_start(save_thread, &save_thread_run, stdata);
313 } else {
314 save_thread_run(stdata);
315 }
316
317#ifdef LOG_TIMERS
318 log_verbose("Save time: %g seconds (%g apparent)",
319 timer_read_seconds(timer_cpu), timer_read_seconds(timer_user));
320#endif // LOG_TIMERS
321
322 timer_destroy(timer_cpu);
323 timer_destroy(timer_user);
324}
325
326/************************************************************************/
329 void save_system_close(void)
330{
331 if (save_thread != nullptr) {
332 fc_thread_wait(save_thread);
333 free(save_thread);
334 save_thread = nullptr;
335 }
336}
ai.h
CALL_FUNC_EACH_AI
#define CALL_FUNC_EACH_AI(_func,...)
Definition ai.h:387
CALL_PLR_AI_FUNC
#define CALL_PLR_AI_FUNC(_func, _player,...)
Definition ai.h:377
has_capabilities
bool has_capabilities(const char *us, const char *them)
Definition capability.c:88
capability.h
city_list_iterate
#define city_list_iterate(citylist, pcity)
Definition city.h:508
city_list_iterate_end
#define city_list_iterate_end
Definition city.h:510
incite_cost
char * incite_cost
Definition comments.c:74
con_write
void con_write(enum rfc_status rfc_status, const char *message,...)
Definition console.c:203
console.h
C_FAIL
@ C_FAIL
Definition console.h:45
C_OK
@ C_OK
Definition console.h:41
punit
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
_
#define _(String)
Definition fcintl.h:67
fc_thread_start
int fc_thread_start(fc_thread *thread, void(*function)(void *arg), void *arg)
fc_thread_wait
void fc_thread_wait(fc_thread *thread)
ftc_warning
const struct ft_color ftc_warning
Definition featured_text.c:75
game
struct civ_game game
Definition game.c:61
generate_save_name
int generate_save_name(const char *format, char *buf, int buflen, const char *reason)
Definition game.c:794
game.h
fz_method
fz_method
Definition ioz.h:36
FZ_PLAIN
@ FZ_PLAIN
Definition ioz.h:37
log.h
fc_assert_ret
#define fc_assert_ret(condition)
Definition log.h:191
log_verbose
#define log_verbose(message,...)
Definition log.h:109
log_debug
#define log_debug(message,...)
Definition log.h:115
log_error
#define log_error(message,...)
Definition log.h:103
mem.h
fc_malloc
#define fc_malloc(sz)
Definition mem.h:34
notify_conn
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:239
notify.h
players_iterate_end
#define players_iterate_end
Definition player.h:539
players_iterate
#define players_iterate(_pplayer)
Definition player.h:534
registry.h
secfile_new
struct section_file * secfile_new(bool allow_duplicates)
Definition section_file.c:73
secfile_error
const char * secfile_error(void)
Definition section_file.c:36
secfile_destroy
void secfile_destroy(struct section_file *secfile)
Definition section_file.c:95
secfile_lookup_str
const char * secfile_lookup_str(const struct section_file *secfile, const char *path,...)
Definition registry_ini.c:2180
secfile_save
bool secfile_save(const struct section_file *secfile, const char *filename, int compression_level, enum fz_method compression_method)
Definition registry_ini.c:644
savegame2_load
void savegame2_load(struct section_file *file)
Definition savegame2.c:402
savegame2.h
savegame3_save
void savegame3_save(struct section_file *sfile, const char *save_reason, bool scenario)
Definition savegame3.c:431
savegame3_load
void savegame3_load(struct section_file *file)
Definition savegame3.c:458
savegame3.h
savegame_load
void savegame_load(struct section_file *sfile)
Definition savemain.c:43
savegame_save
void savegame_save(struct section_file *sfile, const char *save_reason, bool scenario)
Definition savemain.c:96
save_system_close
void save_system_close(void)
Definition savemain.c:329
save_thread_run
static void save_thread_run(void *arg)
Definition savemain.c:122
save_thread_data_free
static void save_thread_data_free(struct save_thread_data *stdata)
Definition savemain.c:113
save_game
void save_game(const char *orig_filename, const char *save_reason, bool scenario)
Definition savemain.c:143
save_thread
static fc_thread * save_thread
Definition savemain.c:38
savemain.h
make_dir
bool make_dir(const char *pathname, int mode)
Definition shared.c:1776
path_is_absolute
bool path_is_absolute(const char *filename)
Definition shared.c:1881
DIRMODE_DEFAULT
#define DIRMODE_DEFAULT
Definition shared.h:258
srvarg
struct server_arguments srvarg
Definition srv_main.c:181
civ_game::threaded_save
bool threaded_save
Definition game.h:180
civ_game::save_compress_level
int save_compress_level
Definition game.h:181
civ_game::save_name
char save_name[MAX_LEN_NAME]
Definition game.h:220
civ_game::save_compress_type
enum fz_method save_compress_type
Definition game.h:182
civ_game::server
struct civ_game::@31::@35 server
save_thread_data
Definition savemain.c:103
save_thread_data::save_compress_level
int save_compress_level
Definition savemain.c:106
save_thread_data::save_compress_type
enum fz_method save_compress_type
Definition savemain.c:107
save_thread_data::sfile
struct section_file * sfile
Definition savemain.c:104
save_thread_data::filepath
char filepath[600]
Definition savemain.c:105
section_file
Definition section_file.h:36
server_arguments::scenarios_pathname
char * scenarios_pathname
Definition srv_main.h:47
server_arguments::saves_pathname
char * saves_pathname
Definition srv_main.h:46
timer
Definition timing.c:81
sz_strlcpy
#define sz_strlcpy(dest, src)
Definition support.h:189
TRUE
#define TRUE
Definition support.h:46
FALSE
#define FALSE
Definition support.h:47
sz_strlcat
#define sz_strlcat(dest, src)
Definition support.h:190
timer_destroy
void timer_destroy(struct timer *t)
Definition timing.c:208
timer_start
void timer_start(struct timer *t)
Definition timing.c:264
timer_stop
void timer_stop(struct timer *t)
Definition timing.c:308
timer_new
struct timer * timer_new(enum timer_timetype type, enum timer_use use, const char *name)
Definition timing.c:160
timer_read_seconds
double timer_read_seconds(struct timer *t)
Definition timing.c:384
TIMER_ACTIVE
@ TIMER_ACTIVE
Definition timing.h:46
TIMER_DEBUG
#define TIMER_DEBUG
Definition timing.h:61
TIMER_CPU
@ TIMER_CPU
Definition timing.h:41
TIMER_USER
@ TIMER_USER
Definition timing.h:42
unit_list_iterate
#define unit_list_iterate(unitlist, punit)
Definition unitlist.h:31
unit_list_iterate_end
#define unit_list_iterate_end
Definition unitlist.h:33