The Battle for Wesnoth  1.13.11+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
savegame.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by Jörg Hinrichs, refactored from various
3  places formerly created by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include <boost/iostreams/filter/gzip.hpp>
17 
18 #include "savegame.hpp"
19 
20 #include "save_index.hpp"
21 #include "carryover.hpp"
22 #include "format_time_summary.hpp"
23 #include "formatter.hpp"
24 #include "formula/string_utils.hpp"
25 #include "game_end_exceptions.hpp"
26 #include "game_errors.hpp"
27 #include "preferences/game.hpp"
28 #include "gettext.hpp"
31 #include "gui/dialogs/message.hpp"
34 #include "gui/widgets/settings.hpp"
35 #include "gui/widgets/window.hpp"
36 #include "log.hpp"
37 #include "persist_manager.hpp"
38 #include "resources.hpp"
39 #include "save_index.hpp"
40 #include "saved_game.hpp"
42 #include "serialization/parser.hpp"
43 #include "statistics.hpp"
44 #include "version.hpp"
45 #include "video.hpp"
46 
47 #include <algorithm>
48 
49 static lg::log_domain log_engine("engine");
50 #define LOG_SAVE LOG_STREAM(info, log_engine)
51 #define ERR_SAVE LOG_STREAM(err, log_engine)
52 
53 static lg::log_domain log_enginerefac("enginerefac");
54 #define LOG_RG LOG_STREAM(info, log_enginerefac)
55 
56 
57 namespace savegame {
58 
60 {
61  name += compression::format_extension(compressed);
63 }
64 
65 void clean_saves(const std::string& label)
66 {
67  std::vector<save_info> games = get_saves_list();
68  std::string prefix = label + "-" + _("Auto-Save");
69  LOG_SAVE << "Cleaning saves with prefix '" << prefix << "'\n";
70  for (std::vector<save_info>::iterator i = games.begin(); i != games.end(); ++i) {
71  if (i->name().compare(0, prefix.length(), prefix) == 0) {
72  LOG_SAVE << "Deleting savegame '" << i->name() << "'\n";
73  delete_game(i->name());
74  }
75  }
76 }
77 
79  : game_config_(game_config)
80  , gamestate_(gamestate)
81  , load_data_()
82 {}
83 
85 {
86  if(load_data_.summary["corrupt"].to_bool()) {
87  return false;
88  }
89 
90  std::string campaign_id = load_data_.summary["campaign"];
91 
92  for(const config &campaign : game_config_.child_range("campaign"))
93  {
94  if(campaign["id"] != campaign_id) {
95  continue;
96  }
97 
98  gui2::dialogs::campaign_difficulty difficulty_dlg(campaign);
99  difficulty_dlg.show();
100 
101  // Return if canceled, since otherwise load_data_.difficulty will be set to 'CANCEL'
102  if (difficulty_dlg.get_retval() != gui2::window::OK) {
103  return false;
104  }
105 
106  load_data_.difficulty = difficulty_dlg.selected_difficulty();
107 
108  // Exit loop
109  break;
110  }
111 
112  return true;
113 }
114 
115 // Called only by play_controller to handle in-game attempts to load. Instead of returning true,
116 // throws a "load_game_exception" to signal a resulting load game request.
118 {
119  if(CVideo::get_singleton().faked()) {
120  return false;
121  }
122 
124  return false;
125  }
126 
127  if(load_data_.filename.empty()) {
128  return false;
129  }
130 
132  if(!show_difficulty_dialog()) {
133  return false;
134  }
135  }
136 
138 
139  // Confirm the integrity of the file before throwing the exception.
140  // Use the summary in the save_index for this.
141  const config & summary = save_index_manager.get(load_data_.filename);
142 
143  if (summary["corrupt"].to_bool(false)) {
145  _("The file you have tried to load is corrupt: '"));
146  return false;
147  }
148 
149  if (!loadgame::check_version_compatibility(summary["version"].str())) {
150  return false;
151  }
152 
153  throw load_game_exception(std::move(load_data_));
154 }
155 
157 {
158  bool skip_version_check = true;
159 
160  if(load_data_.filename.empty()){
162  return false;
163  }
164  skip_version_check = false;
166  }
167 
168  if(load_data_.filename.empty()) {
169  return false;
170  }
171 
173  if(!show_difficulty_dialog()) {
174  return false;
175  }
176  }
177 
178  std::string error_log;
180 
182 
183  for (config& side : load_data_.load_config.child_range("side")) {
184  side.remove_attribute("is_local");
185  }
186 
187  if(!error_log.empty()) {
188  try {
190  _("Warning: The file you have tried to load is corrupt. Loading anyway.\n") +
191  error_log);
192  } catch (utf8::invalid_utf8_exception&) {
194  _("Warning: The file you have tried to load is corrupt. Loading anyway.\n") +
195  std::string("(UTF-8 ERROR)"));
196  }
197  }
198 
199  if (!load_data_.difficulty.empty()){
201  }
202  // read classification to for loading the game_config config object.
204 
205  if (skip_version_check) {
206  return true;
207  }
208 
210 }
211 
213 {
215 }
216 
218 {
219  if (save_version == game_config::version) {
220  return true;
221  }
222 
224 
225  // Even minor version numbers indicate stable releases which are
226  // compatible with each other.
227  if (wesnoth_version.minor_version() % 2 == 0 &&
228  wesnoth_version.major_version() == save_version.major_version() &&
229  wesnoth_version.minor_version() == save_version.minor_version())
230  {
231  return true;
232  }
233 
234  // Do not load if too old. If either the savegame or the current
235  // game has the version 'test', load. This 'test' version is never
236  // supposed to occur, except when Soliton is testing MP servers.
237  if (save_version < game_config::min_savegame_version &&
238  save_version != game_config::test_version &&
239  wesnoth_version != game_config::test_version)
240  {
241  const std::string message = _("This save is from an old, unsupported version ($version_number|) and cannot be loaded.");
242  utils::string_map symbols;
243  symbols["version_number"] = save_version.str();
245  return false;
246  }
247 
249  const std::string message = _("This save is from a different version of the game ($version_number|). Do you wish to try to load it?");
250  utils::string_map symbols;
251  symbols["version_number"] = save_version.str();
252  const int res = gui2::show_message(_("Load Game"), utils::interpolate_variables_into_string(message, &symbols),
254  return res == gui2::window::OK;
255  }
256 
257  return true;
258 }
259 
261 {
263 }
264 
266 {
268  return false;
269  }
270 
271 
273  if(load_data_.filename.empty()) {
274  return false;
275  }
276 
277  // read_save_file needs to be called before we can verify the classification so the data has
278  // been populated. Since we do that, we report any errors in that process first.
279  std::string error_log;
280  {
282  log_scope("load_game");
283 
286  }
287 
288  if(!error_log.empty()) {
290  _("The file you have tried to load is corrupt: '") +
291  error_log);
292  return false;
293  }
294 
296  gui2::show_transient_message(_("Load Game"), _("Replays are not supported in multiplayer mode."));
297  return false;
298  }
299 
300  // We want to verify the game classification before setting the data, so we don't check on
301  // gamestate_.classification() and instead construct a game_classification object manually.
302  if(game_classification(load_data_.load_config).campaign_type != game_classification::CAMPAIGN_TYPE::MULTIPLAYER) {
303  gui2::show_transient_error_message(_("This is not a multiplayer save."));
304  return false;
305  }
306 
307  set_gamestate();
308 
310 }
311 
313 {
314  const config &replay_start = cfg.child("replay_start");
315  if (!replay_start) return;
316 
317  const config &era = replay_start.child("era");
318  if (!era) return;
319 
320  config &snapshot = cfg.child("snapshot");
321  if (!snapshot) return;
322 
323  snapshot.add_child("era", era);
324 }
325 
326 savegame::savegame(saved_game& gamestate, const compression::format compress_saves, const std::string& title)
327  : filename_()
328  , gamestate_(gamestate)
329  , title_(title)
330  , error_message_(_("The game could not be saved: "))
331  , show_confirmation_(false)
332  , compress_saves_(compress_saves)
333 {}
334 
335 bool savegame::save_game_automatic(bool ask_for_overwrite, const std::string& filename)
336 {
337  if (filename.empty())
338  filename_ = create_filename();
339  else
340  filename_ = filename;
341 
342  if (ask_for_overwrite){
343  if (!check_overwrite()) {
344  return save_game_interactive("", savegame::OK_CANCEL);
345  }
346  }
347 
348  return save_game();
349 }
350 
351 bool savegame::save_game_interactive(const std::string& message, DIALOG_TYPE dialog_type)
352 {
353  show_confirmation_ = true;
354  filename_ = create_filename();
355 
356  const int res = show_save_dialog(message, dialog_type);
357 
358  if (res == 2) {
359  throw_quit_game_exception(); //Quit game
360  }
361 
362  if (res == gui2::window::OK && check_overwrite()) {
363  return save_game();
364  }
365 
366  return false;
367 }
368 
369 int savegame::show_save_dialog(const std::string& message, DIALOG_TYPE dialog_type)
370 {
371  int res = 0;
372 
373  if (dialog_type == OK_CANCEL){
374  gui2::dialogs::game_save dlg(filename_, title_);
375  dlg.show();
376  res = dlg.get_retval();
377  }
378  else if (dialog_type == YES_NO){
379  gui2::dialogs::game_save_message dlg(filename_, title_, message);
380  dlg.show();
381  res = dlg.get_retval();
382  }
383 
384  if (!check_filename(filename_)) {
385  res = gui2::window::CANCEL;
386  }
387 
388  return res;
389 }
390 
391 bool savegame::check_overwrite()
392 {
393  if(!save_game_exists(filename_, compress_saves_)) {
394  return true;
395  }
396 
397  std::ostringstream message;
398  message << _("Save already exists. Do you want to overwrite it?") << "\n" << _("Name: ") << filename_;
399  const int res = gui2::show_message(_("Overwrite?"), message.str(), gui2::dialogs::message::yes_no_buttons);
400  return res == gui2::window::OK;
401 
402 }
403 
404 bool savegame::check_filename(const std::string& filename)
405 {
406  if (filesystem::is_compressed_file(filename)) {
407  gui2::show_error_message(_("Save names should not end on '.gz' or '.bz2'. "
408  "Please remove the extension."));
409  return false;
410  }
411 
412  return true;
413 }
414 
415 bool savegame::is_illegal_file_char(char c)
416 {
417  return c == '/' || c == '\\' || c == ':' || (c >= 0x00 && c < 0x20)
418 #ifdef _WIN32
419  || c == '?' || c == '|' || c == '<' || c == '>' || c == '*' || c == '"'
420 #endif
421  ;
422 }
423 
424 std::string savegame::create_filename(unsigned int turn_number) const
425 {
426  std::string filename = create_initial_filename(turn_number);
427  filename.erase(std::remove_if(filename.begin(), filename.end(),
428  is_illegal_file_char), filename.end());
429  std::replace(filename.begin(), filename.end(), '_', ' ');
430  return filename;
431 }
432 
433 void savegame::before_save()
434 {
435 }
436 
437 bool savegame::save_game(const std::string& filename)
438 {
439 
440  try {
441  uint32_t start, end;
442  start = SDL_GetTicks();
443 
444  if (filename_.empty())
445  filename_ = filename;
446 
447  before_save();
448 
449  write_game_to_disk(filename_);
450  if (resources::persist != nullptr) {
453  }
454 
455  // Create an entry in the save_index. Doing this here ensures all leader image paths
456  // sre expanded in a context-independent fashion and can appear in the Load Game dialog
457  // even if a campaign-specific sprite is used. This is because the image's full path is
458  // only available if the binary-path context its a part of is loaded. Without this, if
459  // a player saves a game and exits the game or reloads the cache, the leader image will
460  // only be available within that specific binary context (when playing another game from
461  // the came campaign, for example).
463 
464  end = SDL_GetTicks();
465  LOG_SAVE << "Milliseconds to save " << filename_ << ": " << end - start << std::endl;
466 
467  if (show_confirmation_)
468  gui2::show_transient_message(_("Saved"), _("The game has been saved."));
469  return true;
470  } catch(game::save_game_failed& e) {
471  ERR_SAVE << error_message_ << e.message << std::endl;
472 
473  gui2::show_error_message(error_message_ + e.message);
474  //do not bother retrying, since the user can just try to save the game again
475  //maybe show a yes-no dialog for "disable autosaves now"?
476 
477  return false;
478  };
479 }
480 
481 void savegame::write_game_to_disk(const std::string& filename)
482 {
483  LOG_SAVE << "savegame::save_game" << std::endl;
484 
485  filename_ = filename;
486  filename_ += compression::format_extension(compress_saves_);
487 
488  std::stringstream ss;
489  {
490  config_writer out(ss, compress_saves_);
491  write_game(out);
492  finish_save_game(out);
493  }
494  filesystem::scoped_ostream os(open_save_game(filename_));
495  (*os) << ss.str();
496 
497  if (!os->good()) {
498  throw game::save_game_failed(_("Could not write to file"));
499  }
500 }
501 
502 void savegame::write_game(config_writer &out)
503 {
504  log_scope("write_game");
505 
506  out.write_key_val("version", game_config::version);
507 
508  gamestate_.write_general_info(out);
509  out.open_child("statistics");
511  out.close_child("statistics");
512 }
513 
514 void savegame::finish_save_game(const config_writer &out)
515 {
516  try {
517  if(!out.good()) {
518  throw game::save_game_failed(_("Could not write to file"));
519  }
520  save_index_manager.remove(gamestate_.classification().label);
521  } catch(filesystem::io_exception& e) {
522  throw game::save_game_failed(e.what());
523  }
524 }
525 
526 // Throws game::save_game_failed
527 filesystem::scoped_ostream savegame::open_save_game(const std::string &label)
528 {
529  try {
530  return filesystem::ostream_file(filesystem::get_saves_dir() + "/" + label);
531  } catch(filesystem::io_exception& e) {
532  throw game::save_game_failed(e.what());
533  }
534 }
535 
537  : savegame(gamestate, compress_saves)
538 {
540 }
541 
543 {
544  return gamestate().classification().label;
545 }
546 
549  gamestate().write_carryover(out);
550 }
551 
553  : savegame(gamestate, compress_saves, _("Save Replay"))
554 {}
555 
557 {
558  return formatter() << gamestate().classification().label << " " << _("replay");
559 }
560 
563 
564  gamestate().write_carryover(out);
565  out.write_child("replay_start", gamestate().replay_start());
566 
567  out.open_child("replay");
568  gamestate().get_replay().write(out);
569  out.close_child("replay");
570 
571 }
572 
574  : ingame_savegame(gamestate, compress_saves)
575 {
576  set_error_message(_("Could not auto save the game. Please save the game manually."));
577 }
578 
579 void autosave_savegame::autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
580 {
581  if(disable_autosave)
582  return;
583 
585 
586  remove_old_auto_saves(autosave_max, infinite_autosaves);
587 }
588 
590 {
592  if(gamestate().classification().label.empty())
593  filename = _("Auto-Save");
594  else
595  filename = gamestate().classification().label + "-" + _("Auto-Save") + std::to_string(turn_number);
596 
597  return filename;
598 }
599 
600 oos_savegame::oos_savegame(saved_game& gamestate, bool& ignore)
602  , ignore_(ignore)
603 {}
604 
605 int oos_savegame::show_save_dialog(const std::string& message, DIALOG_TYPE /*dialog_type*/)
606 {
607  int res = 0;
608 
609  if (!ignore_){
611  dlg.show();
612  res = dlg.get_retval();
613  }
614 
615  if (!check_filename(filename_)) {
616  res = gui2::window::CANCEL;
617  }
618 
619  return res;
620 }
621 
623  : savegame(gamestate, compress_saves, _("Save Game"))
624 {
625 }
626 
628 {
629  return formatter() << gamestate().classification().label
630  << " " << _("Turn") << " " << turn_number;
631 }
632 
634  log_scope("write_game");
635 
636  if(!gamestate().get_starting_pos().validate_wml()) {
637  throw game::save_game_failed(_("Game state is corrupted"));
638  }
639 
641 
642  gamestate().write_carryover(out);
643  out.write_child("snapshot",gamestate().get_starting_pos());
644  out.write_child("replay_start", gamestate().replay_start());
645  out.open_child("replay");
646  gamestate().get_replay().write(out);
647  out.close_child("replay");
648 }
649 
650 //changes done during 1.11.0-dev
652 {
653  if(!cfg.has_child("snapshot")){
654  return;
655  }
656 
657  const config& snapshot = cfg.child("snapshot");
658  const config& replay_start = cfg.child("replay_start");
659  const config& replay = cfg.child("replay");
660 
661  if(!cfg.has_child("carryover_sides") && !cfg.has_child("carryover_sides_start")){
663  //copy rng and menu items from toplevel to new carryover_sides
664  carryover["random_seed"] = cfg["random_seed"];
665  carryover["random_calls"] = cfg["random_calls"];
666  for(const config& menu_item : cfg.child_range("menu_item")) {
667  carryover.add_child("menu_item", menu_item);
668  }
669  carryover["difficulty"] = cfg["difficulty"];
670  carryover["random_mode"] = cfg["random_mode"];
671  //the scenario to be played is always stored as next_scenario in carryover_sides_start
672  carryover["next_scenario"] = cfg["scenario"];
673 
674  config carryover_start = carryover;
675 
676  //copy sides from either snapshot or replay_start to new carryover_sides
677  if(!snapshot.empty()){
678  for(const config& side : snapshot.child_range("side")) {
679  carryover.add_child("side", side);
680  }
681  //for compatibility with old savegames that use player instead of side
682  for(const config& side : snapshot.child_range("player")) {
683  carryover.add_child("side", side);
684  }
685  //save the sides from replay_start in carryover_sides_start
686  for(const config& side : replay_start.child_range("side")) {
687  carryover_start.add_child("side", side);
688  }
689  //for compatibility with old savegames that use player instead of side
690  for(const config& side : replay_start.child_range("player")) {
691  carryover_start.add_child("side", side);
692  }
693  } else if (!replay_start.empty()){
694  for(const config& side : replay_start.child_range("side")) {
695  carryover.add_child("side", side);
696  carryover_start.add_child("side", side);
697  }
698  //for compatibility with old savegames that use player instead of side
699  for(const config& side : replay_start.child_range("player")) {
700  carryover.add_child("side", side);
701  carryover_start.add_child("side", side);
702  }
703  }
704 
705  //get variables according to old hierarchy and copy them to new carryover_sides
706  if(!snapshot.empty()){
707  if(const config& variables_from_snapshot = snapshot.child("variables")){
708  carryover.add_child("variables", variables_from_snapshot);
709  carryover_start.add_child("variables", replay_start.child_or_empty("variables"));
710  } else if (const config& variables_from_cfg = cfg.child("variables")){
711  carryover.add_child("variables", variables_from_cfg);
712  carryover_start.add_child("variables", variables_from_cfg);
713  }
714  } else if (!replay_start.empty()){
715  if(const config& variables = replay_start.child("variables")){
716  carryover.add_child("variables", variables);
717  carryover_start.add_child("variables", variables);
718  }
719  } else {
720  carryover.add_child("variables", cfg.child("variables"));
721  carryover_start.add_child("variables", cfg.child("variables"));
722  }
723 
724  cfg.add_child("carryover_sides", carryover);
725  cfg.add_child("carryover_sides_start", carryover_start);
726  }
727 
728  //if replay and snapshot are empty we've got a start of scenario save and don't want replay_start either
729  if(replay.empty() && snapshot.empty()){
730  LOG_RG<<"removing replay_start \n";
731  cfg.clear_children("replay_start");
732  }
733 
734  //remove empty replay or snapshot so type of save can be detected more easily
735  if(replay.empty()){
736  LOG_RG<<"removing replay \n";
737  cfg.clear_children("replay");
738  }
739 
740  if(snapshot.empty()){
741  LOG_RG<<"removing snapshot \n";
742  cfg.clear_children("snapshot");
743  }
744 }
745 //changes done during 1.13.0-dev
747 {
748  if(config& carryover_sides_start = cfg.child("carryover_sides_start"))
749  {
750  if(!carryover_sides_start.has_attribute("next_underlying_unit_id"))
751  {
752  carryover_sides_start["next_underlying_unit_id"] = cfg["next_underlying_unit_id"];
753  }
754  }
755  if(cfg.child_or_empty("snapshot").empty())
756  {
757  cfg.clear_children("snapshot");
758  }
759  if(cfg.child_or_empty("replay_start").empty())
760  {
761  cfg.clear_children("replay_start");
762  }
763  if(config& snapshot = cfg.child("snapshot"))
764  {
765  //make [end_level] -> [end_level_data] since its alo called [end_level_data] in the carryover.
766  if(config& end_level = cfg.child("end_level") )
767  {
768  snapshot.add_child("end_level_data", end_level);
769  snapshot.clear_children("end_level");
770  }
771  //if we have a snapshot then we already applied carryover so there is no reason to keep this data.
772  if(cfg.has_child("carryover_sides_start"))
773  {
774  cfg.clear_children("carryover_sides_start");
775  }
776  }
777  if(!cfg.has_child("snapshot") && !cfg.has_child("replay_start"))
778  {
779  cfg.clear_children("carryover_sides");
780  }
781  //This code is needed because for example otherwise it won't find the (empty) era
782  if(!cfg.has_child("multiplayer")) {
783  cfg.add_child("multiplayer", config {
784  "mp_era", "era_blank",
785  "mp_use_map_settings", true,
786  });
787  }
788 }
789 
790 
791 //changes done during 1.13.0+dev
793 {
794  if(config& multiplayer = cfg.child("multiplayer")) {
795  if(multiplayer["mp_era"] == "era_blank") {
796  multiplayer["mp_era"] = "era_default";
797  }
798  }
799  //This currently only fixes start-of-scenario saves.
800  if(config& carryover_sides_start = cfg.child("carryover_sides_start"))
801  {
802  for(config& side : carryover_sides_start.child_range("side"))
803  {
804  for(config& unit : side.child_range("unit"))
805  {
806  if(config& modifications = unit.child("modifications"))
807  {
808  for(config& advancement : modifications.child_range("advance"))
809  {
810  modifications.add_child("advancement", advancement);
811  }
812  modifications.clear_children("advance");
813  }
814  }
815  }
816  }
817  for(config& snapshot : cfg.child_range("snapshot")) {
818  if (snapshot.has_attribute("used_items")) {
819  config used_items;
820  for(const std::string& item : utils::split(snapshot["used_items"])) {
821  used_items[item] = true;
822  }
823  snapshot.remove_attribute("used_items");
824  snapshot.add_child("used_items", used_items);
825  }
826  }
827 }
828 
830 {
831  version_info loaded_version(cfg["version"]);
832  if(loaded_version < version_info("1.12.0"))
833  {
835  }
836  // '<= version_info("1.13.0")' doesn't work
837  //because version_info cannot handle 1.13.0-dev versions correctly.
838  if(loaded_version < version_info("1.13.1"))
839  {
841  }
842  if(loaded_version <= version_info("1.13.1"))
843  {
845  }
846  LOG_RG<<"cfg after conversion "<<cfg<<"\n";
847 }
848 
849 }
850 
oos_savegame(saved_game &gamestate, bool &ignore)
Definition: savegame.cpp:600
void remove_old_auto_saves(const int autosavemax, const int infinite_auto_saves)
Remove autosaves that are no longer needed (according to the autosave policy in the preferences)...
Definition: save_index.cpp:309
void show_message(const std::string &title, const std::string &msg, const std::string &button_caption, const bool auto_close, const bool message_use_markup, const bool title_use_markup)
Shows a message to the user.
Definition: message.cpp:152
bool load_game()
Load a game with pre-setting information for the load-game dialog.
Definition: savegame.cpp:156
bool good() const
Dialog is closed with ok button.
Definition: window.hpp:101
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:419
const char * what() const NOEXCEPT
Definition: exceptions.hpp:37
std::vector< char_t > string
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
Function which will interpolate variables, starting with '$' in the string 'str' with the equivalent ...
static void convert_old_saves_1_13_1(config &cfg)
Definition: savegame.cpp:792
void rebuild(const std::string &name)
Definition: save_index.cpp:45
void read_save_file(const std::string &name, config &cfg, std::string *error_log)
Read the complete config information out of a savefile.
Definition: save_index.cpp:268
std::map< std::string, t_string > string_map
std::string label
Name of the game (e.g.
std::string era()
Definition: game.cpp:700
This class represents a single unit of a specific type.
Definition: unit.hpp:100
std::string filename
Name of the savefile to be loaded.
Definition: savegame.hpp:40
game_classification * classification
Definition: resources.cpp:34
virtual void write_game(config_writer &out)
Writing the savegame config to a file.
Definition: savegame.cpp:502
static void convert_old_saves_1_13_0(config &cfg)
Definition: savegame.cpp:746
void set_gamestate()
Generate the gamestate out of the loaded game config.
Definition: savegame.cpp:260
replay_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:552
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:547
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:589
replay_recorder_base & get_replay()
Definition: saved_game.hpp:117
void remove(const std::string &name)
Definition: save_index.cpp:71
#define ERR_SAVE
Definition: savegame.cpp:51
This file contains the window object, this object is a top level container which has the event manage...
child_itors child_range(config_key_type key)
Definition: config.cpp:362
ingame_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:622
std::vector< save_info > get_saves_list(const std::string *dir, const std::string *filter)
Get a list of available saves.
Definition: save_index.cpp:188
void show_transient_message(const std::string &title, const std::string &message, const std::string &image, const bool message_use_markup, const bool title_use_markup, const bool restore_background)
Shows a transient message to the user.
Error used when game saving fails.
Definition: game_errors.hpp:38
autosave_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:573
load_game_metadata load_data_
Primary output information.
Definition: savegame.hpp:140
static CVideo & get_singleton()
Definition: video.hpp:43
Class for "normal" midgame saves.
Definition: savegame.hpp:241
persist_manager * persist
Definition: resources.cpp:26
bool confirm_load_save_from_different_version()
Definition: general.cpp:1039
Contains the exception interfaces used to signal completion of a scenario, campaign or turn...
static bool execute(const config &cache_config, savegame::load_game_metadata &data)
Definition: game_load.hpp:38
bool empty() const
Definition: config.cpp:830
bool show(const unsigned auto_close_time=0)
Shows the window.
std::string get_saves_dir()
void remove_attribute(config_key_type key)
Definition: config.cpp:235
-file util.hpp
scenariostart_savegame(saved_game &gamestate, const compression::format compress_saves)
Definition: savegame.cpp:536
std::vector< std::string > split(const std::string &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
std::string filename_
Definition: action_wml.cpp:546
The base class for all savegame stuff.
Definition: savegame.hpp:147
void write_child(const std::string &key, const config &cfg)
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:89
loadgame(const config &game_config, saved_game &gamestate)
Definition: savegame.cpp:78
std::string selected_difficulty() const
Returns the selected difficulty define after displaying.
void throw_quit_game_exception()
void write_key_val(const std::string &key, const T &value)
This template function will work with any type that can be assigned to an attribute_value.
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:556
void close_child(const std::string &key)
This file contains the settings handling of the widget library.
void clear_children(T...keys)
Definition: config.hpp:510
std::ostringstream wrapper.
Definition: formatter.hpp:38
Class for writing a config out to a file in pieces.
bool disable_autosave
const version_info test_version("test")
void open_child(const std::string &key)
saved_game & gamestate_
Definition: savegame.hpp:138
void delete_game(const std::string &name)
Delete a savegame.
Definition: save_index.cpp:327
static bool is_replay_save(const config &cfg)
Definition: savegame.hpp:123
void write(config_writer &out) const
save_index_class save_index_manager
Definition: save_index.cpp:168
Modify, read and display user preferences.
Shows a yes and no button.
Definition: message.hpp:79
bool load_game_ingame()
Load a game without providing any information.
Definition: savegame.cpp:117
virtual int show_save_dialog(const std::string &message, DIALOG_TYPE dialog_type) override
Display the save game dialog.
Definition: savegame.cpp:605
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:627
void set_data(config &cfg)
destroys the passed config.
Definition: saved_game.cpp:645
const config & game_config_
Definition: savegame.hpp:136
#define LOG_SAVE
Definition: savegame.cpp:50
const std::string & title() const
Definition: savegame.hpp:195
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:633
void write_game(config_writer &out) override
Writing the savegame config to a file.
Definition: savegame.cpp:561
std::string str() const
Serializes the version number into string form.
Definition: version.cpp:93
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
Definition: config.cpp:412
void convert_old_saves(config &cfg)
converts saves from older versions of wesnoth
Definition: savegame.cpp:829
std::unique_ptr< std::ostream > scoped_ostream
Definition: filesystem.hpp:38
std::string format_extension(format compression_format)
Definition: compression.hpp:26
Exception used to signal that the user has decided to abortt a game, and to load another game instead...
Definition: savegame.hpp:74
filesystem::scoped_ostream ostream_file(const std::string &fname, bool create_directory=true)
config & get(const std::string &name)
Definition: save_index.cpp:83
Thrown by operations encountering invalid UTF-8 data.
void clean_saves(const std::string &label)
Delete all autosaves of a certain scenario.
Definition: savegame.cpp:65
Game configuration data as global variables.
Definition: build_info.cpp:53
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:452
EXIT_STATUS start(const config &game_conf, const std::string &filename, bool take_screenshot, const std::string &screenshot_filename)
Main interface for launching the editor from the title screen.
Definition: editor_main.cpp:28
An exception object used when an IO error occurs.
Definition: filesystem.hpp:46
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
Definition: version.cpp:133
bool check_filename(const std::string &filename)
Check, if the filename contains illegal constructs like ".gz".
Definition: savegame.cpp:404
unsigned int major_version() const
Retrieves the major version number (x1 in "x1.x2.x3").
Definition: version.cpp:129
std::string difficulty
The difficulty the save is meant to be loaded with.
Definition: savegame.hpp:43
bool is_compressed_file(const std::string &filename)
Definition: filesystem.hpp:154
#define log_scope(description)
Definition: log.hpp:186
size_t i
Definition: function.cpp:933
#define LOG_RG
Definition: savegame.cpp:54
config summary
Summary config of the save selected in the load game dialog.
Definition: savegame.hpp:55
const version_info wesnoth_version(VERSION)
bool load_multiplayer_game()
Loading a game from within the multiplayer-create dialog.
Definition: savegame.cpp:265
Represents version numbers.
Definition: version.hpp:43
config & add_child(config_key_type key)
Definition: config.cpp:475
void copy_era(config &cfg)
Copy era information into the snapshot.
Definition: savegame.cpp:312
void set_error_message(const std::string &error_message)
Customize the standard error message.
Definition: savegame.hpp:193
compression::format save_compression_format()
Definition: game.cpp:873
static lg::log_domain log_enginerefac("enginerefac")
void show_transient_error_message(const std::string &message, const std::string &image, const bool message_use_markup)
Shows a transient error message to the user.
bool show_replay
State of the "show_replay" checkbox in the load-game dialog.
Definition: savegame.hpp:46
const std::vector< std::string > & modifications(bool mp)
Definition: game.cpp:730
game_classification & classification()
Definition: saved_game.hpp:55
static void convert_old_saves_1_11_0(config &cfg)
Definition: savegame.cpp:651
config write_stats()
Definition: statistics.cpp:607
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
Definition: savegame.cpp:579
std::string message
Definition: exceptions.hpp:31
bool select_difficulty
State of the "change_difficulty" checkbox in the load-game dialog.
Definition: savegame.hpp:52
bool show_difficulty_dialog()
Display the difficulty dialog.
Definition: savegame.cpp:84
static const char * name(const std::vector< SDL_Joystick * > &joysticks, const size_t index)
Definition: joystick.cpp:48
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
Definition: message.cpp:205
std::string filename_
Filename of the savegame file on disk.
Definition: savegame.hpp:205
#define e
const saved_game & gamestate() const
Definition: savegame.hpp:196
bool save_game_exists(std::string name, compression::format compressed)
Returns true if there is already a savegame with that name.
Definition: savegame.cpp:59
const std::string & filename() const
Definition: savegame.hpp:171
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:93
void write_carryover(config_writer &out) const
Definition: saved_game.cpp:166
mock_char c
const version_info min_savegame_version(MIN_SAVEGAME_VERSION)
bool check_version_compatibility()
Call check_version_compatibility above, using the version of this savefile.
Definition: savegame.cpp:212
Interfaces for manipulating version numbers of engine, add-ons, etc.
bool file_exists(const std::string &name)
Returns true if a file or directory with such name already exists.
std::string create_filename() const
Build the filename according to the specific savegame's needs.
Definition: savegame.hpp:174
const std::string version
Definition: game_config.cpp:39
static lg::log_domain log_engine("engine")
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
Definition: savegame.cpp:542
Dialog is closed with the cancel button.
Definition: window.hpp:102
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
bool save_game_automatic(bool ask_for_overwrite=false, const std::string &filename="")
Saves a game without user interaction, unless the file exists and it should be asked to overwrite it...
Definition: savegame.cpp:335
config load_config
Config information of the savefile to be loaded.
Definition: savegame.hpp:58
std::string version
Version game was created with.