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