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