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