16 #include <boost/iostreams/filter/gzip.hpp> 54 #define LOG_SAVE LOG_STREAM(info, log_engine) 55 #define ERR_SAVE LOG_STREAM(err, log_engine) 58 #define LOG_RG LOG_STREAM(info, log_enginerefac) 71 const std::string prefix = label +
"-" +
_(
"Auto-Save");
72 LOG_SAVE <<
"Cleaning saves with prefix '" << prefix <<
"'";
75 for(
const auto& save : manager->get_saves_list()) {
76 if(save.name().compare(0, prefix.length(), prefix) == 0) {
77 LOG_SAVE <<
"Deleting savegame '" << save.name() <<
"'";
78 manager->delete_game(save.name());
85 , gamestate_(gamestate)
99 if(campaign[
"id"] != campaign_id) {
106 if(!difficulty_dlg.
show()) {
143 ERR_SAVE <<
"Null pointer in save index";
153 if(summary[
"corrupt"].to_bool(
false)) {
167 bool skip_version_check =
true;
174 skip_version_check =
false;
189 ERR_SAVE <<
"Null pointer in save index";
193 std::string error_log;
199 side.remove_attribute(
"is_local");
202 if(!error_log.empty()) {
205 _(
"Warning: The file you have tried to load is corrupt. Loading anyway.\n") + error_log);
208 + std::string(
"(UTF-8 ERROR)"));
218 if(skip_version_check) {
250 const std::string message
251 =
_(
"This save is from an old, unsupported version ($version_number|) and cannot be loaded.");
253 symbols[
"version_number"] = save_version.
str();
259 const std::string message
260 =
_(
"This save is from a different version of the game ($version_number|), and might not work with this " 263 "<b>Warning:</b> saves in the middle of campaigns are especially likely to fail, and you should either " 264 "use the old version or restart the campaign. Even when a saved game seems to load successfully, " 265 "subtler aspects like gameplay balance and story progression could be impacted. The difficulty, the " 266 "challenge, the <i>fun</i> may be missing.\n" 268 "For example, the campaign may have been rebalanced with fewer enemies in the early scenarios, but " 269 "expecting your recall list to have correspondingly less experience in the late scenarios.\n" 271 "Do you wish to continue?");
273 symbols[
"version_number"] = save_version.
str();
299 ERR_SAVE <<
"Null pointer in save index";
305 std::string error_log;
314 if(!error_log.empty()) {
338 const config& replay_start = cfg.
child(
"replay_start");
361 , error_message_(
_(
"The game could not be saved: "))
362 , show_confirmation_(false)
363 , compress_saves_(compress_saves)
367 bool savegame::save_game_automatic(
bool ask_for_overwrite,
const std::string& filename)
369 if(filename.empty()) {
375 if(ask_for_overwrite) {
376 if(!check_overwrite()) {
377 return save_game_interactive(
"", savegame::OK_CANCEL);
384 bool savegame::save_game_interactive(
const std::string& message,
DIALOG_TYPE dialog_type)
386 show_confirmation_ =
true;
389 const int res = show_save_dialog(message, dialog_type);
402 int savegame::show_save_dialog(
const std::string& message,
DIALOG_TYPE dialog_type)
406 if(dialog_type == OK_CANCEL) {
410 }
else if(dialog_type == YES_NO) {
423 bool savegame::check_overwrite()
429 std::ostringstream message;
430 message <<
_(
"Save already exists. Do you want to overwrite it?") <<
"\n" <<
_(
"Name: ") <<
filename_;
435 bool savegame::check_filename(
const std::string& filename)
443 gui2::show_error_message(
_(
"Save names may not end with a dot, or contain two dots or any of the following characters:\n \" * / : < > ? \\ | ~"));
450 std::string savegame::create_filename(
unsigned int turn_number)
const 452 return create_initial_filename(turn_number);
455 void savegame::before_save()
459 bool savegame::save_game(
const std::string& filename)
463 start = SDL_GetTicks();
486 end = SDL_GetTicks();
489 if(show_confirmation_) {
504 void savegame::write_game_to_disk(
const std::string& filename)
511 std::stringstream ss;
515 finish_save_game(out);
532 gamestate_.write_general_info(out);
560 :
savegame(gamestate, compress_saves)
577 :
savegame(gamestate, compress_saves,
_(
"Save Replay"))
583 time_t
t = std::time(
nullptr);
584 tm tm = *std::localtime(&t);
585 auto time = std::put_time(&tm,
"%Y%m%d-%H%M%S");
617 manager->delete_old_auto_saves(autosave_max, infinite_autosaves);
624 filename =
_(
"Auto-Save");
656 :
savegame(gamestate, compress_saves,
_(
"Save Game"))
669 if(!
gamestate().get_starting_point().validate_wml()) {
691 const config& replay_start = cfg.
child(
"replay_start");
697 carryover[
"random_seed"] = cfg[
"random_seed"];
698 carryover[
"random_calls"] = cfg[
"random_calls"];
701 carryover.
add_child(
"menu_item", menu_item);
704 carryover[
"difficulty"] = cfg[
"difficulty"];
705 carryover[
"random_mode"] = cfg[
"random_mode"];
707 carryover[
"next_scenario"] = cfg[
"scenario"];
709 config carryover_start = carryover;
712 if(!snapshot.
empty()) {
728 }
else if(!replay_start.
empty()) {
741 if(!snapshot.
empty()) {
742 if(
const config& variables_from_snapshot = snapshot.
child(
"variables")) {
743 carryover.
add_child(
"variables", variables_from_snapshot);
745 }
else if(
const config& variables_from_cfg = cfg.
child(
"variables")) {
746 carryover.
add_child(
"variables", variables_from_cfg);
747 carryover_start.
add_child(
"variables", variables_from_cfg);
749 }
else if(!replay_start.
empty()) {
750 if(
const config& variables = replay_start.
child(
"variables")) {
751 carryover.
add_child(
"variables", variables);
752 carryover_start.
add_child(
"variables", variables);
759 cfg.
add_child(
"carryover_sides", carryover);
760 cfg.
add_child(
"carryover_sides_start", carryover_start);
765 LOG_RG <<
"removing replay_start";
771 LOG_RG <<
"removing replay";
775 if(snapshot.
empty()) {
776 LOG_RG <<
"removing snapshot";
783 if(
config& carryover_sides_start = cfg.
child(
"carryover_sides_start")) {
784 if(!carryover_sides_start.has_attribute(
"next_underlying_unit_id")) {
785 carryover_sides_start[
"next_underlying_unit_id"] = cfg[
"next_underlying_unit_id"];
800 snapshot.add_child(
"end_level_data", end_level);
801 snapshot.clear_children(
"end_level");
804 if(cfg.
has_child(
"carryover_sides_start")) {
819 "mp_use_map_settings",
828 if(
config& multiplayer = cfg.
child(
"multiplayer")) {
829 if(multiplayer[
"mp_era"] ==
"era_blank") {
830 multiplayer[
"mp_era"] =
"era_default";
835 if(
config& carryover_sides_start = cfg.
child(
"carryover_sides_start")) {
837 for(
config&
unit : side.child_range(
"unit")) {
849 if(snapshot.has_attribute(
"used_items")) {
852 used_items[
item] =
true;
856 snapshot.add_child(
"used_items", used_items);
864 if(cfg[
"era_id"].empty()) {
868 if(cfg[
"active_mods"].empty()) {
869 cfg[
"active_mods"] = cfg.
child_or_empty(
"multiplayer")[
"active_mods"];
894 LOG_RG <<
"cfg after conversion " << cfg;
oos_savegame(saved_game &gamestate, bool &ignore)
Dialog was closed with the CANCEL button.
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.
bool load_game()
Load a game with pre-setting information for the load-game dialog.
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...
bool is_legal_user_file_name(const std::string &name, bool allow_whitespace=true)
Returns whether the given filename is a legal name for a user-created file.
std::string interpolate_variables_into_string(const std::string &str, const string_map *const symbols)
static void convert_old_saves_1_13_1(config &cfg)
std::map< std::string, t_string > string_map
void clear_children(T... keys)
std::string label
Name of the game (e.g.
This class represents a single unit of a specific type.
Interfaces for manipulating version numbers of engine, add-ons, etc.
const game_config_view & game_config_
game_classification * classification
loadgame(const std::shared_ptr< save_index_class > &index, saved_game &gamestate)
virtual void write_game(config_writer &out)
Writing the savegame config to a file.
static void convert_old_saves_1_13_0(config &cfg)
void set_gamestate()
Generate the gamestate out of the loaded game config.
replay_savegame(saved_game &gamestate, const compression::format compress_saves)
void write_game(config_writer &out) override
Writing the savegame config to a file.
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
const std::string & filename() const
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()
replay_recorder_base & get_replay()
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
void write_carryover(config_writer &out) const
static bool file_exists(const bfs::path &fpath)
child_itors child_range(config_key_type key)
ingame_savegame(saved_game &gamestate, const compression::format compress_saves)
Error used when game saving fails.
autosave_savegame(saved_game &gamestate, const compression::format compress_saves)
static void convert_old_saves_1_15_3(config &cfg)
load_game_metadata load_data_
Primary output information.
Class for "normal" midgame saves.
persist_manager * persist
bool confirm_load_save_from_different_version()
Contains the exception interfaces used to signal completion of a scenario, campaign or turn...
static std::string _(const char *str)
bool show(const unsigned auto_close_time=0)
Shows the window.
static bool execute(const game_config_view &cache_config, savegame::load_game_metadata &data)
void remove_attribute(config_key_type key)
scenariostart_savegame(saved_game &gamestate, const compression::format compress_saves)
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.
filesystem::scoped_ostream ostream_file(const std::string &fname, std::ios_base::openmode mode, bool create_directory)
void write_child(const std::string &key, const config &cfg)
const saved_game & gamestate() const
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.
void close_child(const std::string &key)
std::string label
What to show in the filter's drop-down list.
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").
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.
Class for writing a config out to a file in pieces.
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)
std::string create_filename() const
Build the filename according to the specific savegame's needs.
unsigned int minor_version() const
Retrieves the minor version number (x2 in "x1.x2.x3").
static bool is_replay_save(const config &cfg)
bool headless()
The game is running headless.
Modify, read and display user preferences.
void write(config_writer &out) const
Shows a yes and no button.
bool load_game_ingame()
Load a game without providing any information.
virtual int show_save_dialog(const std::string &message, DIALOG_TYPE dialog_type) override
Display the save game dialog.
virtual std::string create_initial_filename(unsigned int turn_number) const override
Create a filename for automatic saves.
std::string selected_difficulty() const
Returns the selected difficulty define after displaying.
const char * what() const noexcept
void set_data(config &cfg)
destroys the passed config.
void write_game(config_writer &out) override
Writing the savegame config to a file.
void write_game(config_writer &out) override
Writing the savegame config to a file.
void convert_old_saves(config &cfg)
converts saves from older versions of wesnoth
std::unique_ptr< std::ostream > scoped_ostream
std::string format_extension(format compression_format)
Exception used to signal that the user has decided to abortt a game, and to load another game instead...
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.
Game configuration data as global variables.
An exception object used when an IO error occurs.
bool check_filename(const std::string &filename)
Check, if the filename contains illegal constructs like ".gz".
bool is_compressed_file(const std::string &filename)
#define log_scope(description)
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.
const version_info wesnoth_version(VERSION)
The campaign mode difficulty menu.
bool load_multiplayer_game()
Loading a game from within the multiplayer-create dialog.
This shows the dialog to create a savegame file.
Represents version numbers.
config & add_child(config_key_type key)
void copy_era(config &cfg)
Copy era information into the snapshot.
void set_error_message(const std::string &error_message)
Customize the standard error message.
compression::format save_compression_format()
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.
int get_retval() const
Returns the cached window exit code.
const std::vector< std::string > & modifications(bool mp)
std::vector< std::string > split(const config_attribute_value &val)
game_classification & classification()
static void convert_old_saves_1_11_0(config &cfg)
Standard logging facilities (interface).
void autosave(const bool disable_autosave, const int autosave_max, const int infinite_autosaves)
std::string str() const
Serializes the version number into string form.
bool show_difficulty_dialog()
Display the difficulty dialog.
const std::string & title() const
void show_error_message(const std::string &msg, bool message_use_markup)
Shows an error message to the user.
std::string filename_
Filename of the savegame file on disk.
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.
Dialog was closed with the OK button.
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...
A config object defines a single node in a WML file, with access to child nodes.
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.
bool check_version_compatibility()
Call check_version_compatibility above, using the version of this savefile.
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.
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...
std::pair< std::string, unsigned > item
std::string version
Version game was created with.