30 #include <boost/algorithm/string/replace.hpp> 31 #include <boost/iostreams/filter/gzip.hpp> 34 #define LOG_SAVE LOG_STREAM(info, log_engine) 35 #define ERR_SAVE LOG_STREAM(err, log_engine) 38 #define LOG_RG LOG_STREAM(info, log_enginerefac) 63 summary[
"corrupt"] =
true;
66 summary[
"mod_time"] = std::to_string(static_cast<int>(modified));
109 ERR_SAVE <<
"error writing to save index file: '" << e.
what() <<
"'" << std::endl;
143 }
catch(
const boost::iostreams::gzip_error&) {
148 ERR_SAVE <<
"error reading save index: '" << e.
what() <<
"'" << std::endl;
150 ERR_SAVE <<
"error parsing save index config file:\n" << e.
message << std::endl;
163 std::string leader_image = leader[
"leader_image"];
164 boost::algorithm::replace_all(leader_image,
"\\",
"/");
166 leader[
"leader_image"] = leader_image;
182 return filename.end() == std::search(filename.begin(), filename.end(), filter_.begin(), filter_.end());
190 std::vector<save_info>
get_saves_list(
const std::string* dir,
const std::string* filter)
194 std::vector<std::string> filenames;
199 std::remove_if(filenames.begin(), filenames.end(),
filename_filter(*filter)), filenames.end());
202 std::vector<save_info> result;
203 std::transform(filenames.begin(), filenames.end(), std::back_inserter(result), creator);
211 return save_index_manager.
get(
name());
216 if(std::tm* tm_l = std::localtime(&modified())) {
218 ?
_(
"%a %b %d %I:%M %p %Y")
219 :
_(
"%a %b %d %H:%M %Y");
224 LOG_SAVE <<
"localtime() returned null for time " << this->modified() <<
", save " <<
name();
230 std::time_t
t = modified();
240 }
else if(a.
name().find(
_(
" replay")) == std::string::npos && b.
name().find(
_(
" replay")) != std::string::npos) {
247 }
else if(a.
name().find(
_(
" replay")) != std::string::npos && b.
name().find(
_(
" replay")) == std::string::npos) {
255 const std::string&
name,
const std::vector<std::string>& suffixes)
257 for(
const std::string& suf : suffixes) {
261 if(!file_stream->fail()) {
266 LOG_SAVE <<
"Could not open supplied filename '" << name <<
"'\n";
272 static const std::vector<std::string> suffixes{
"",
".gz",
".bz2"};
286 read(cfg, *file_stream);
288 }
catch(
const std::ios_base::failure&
e) {
292 *error_log += e.what();
306 LOG_SAVE <<
"Could not parse file data into config\n";
313 const std::string auto_save =
_(
"Auto-Save");
316 if(countdown == infinite_auto_saves) {
320 std::vector<save_info> games =
get_saves_list(
nullptr, &auto_save);
322 if(countdown-- <= 0) {
323 LOG_SAVE <<
"Deleting savegame '" <<
i->name() <<
"'\n";
333 save_index_manager.
remove(name);
350 const config& cfg_snapshot = cfg_save.
child(
"snapshot");
353 const config& cfg_replay_start = cfg_save.
child(
"replay_start")
354 ? cfg_save.
child(
"replay_start")
355 : cfg_save.
child(
"scenario");
357 const config& cfg_replay = cfg_save.
child(
"replay");
358 const bool has_replay = cfg_replay && !cfg_replay.
empty();
359 const bool has_snapshot = cfg_snapshot && cfg_snapshot.
has_child(
"side");
361 cfg_summary[
"replay"] = has_replay;
362 cfg_summary[
"snapshot"] = has_snapshot;
364 cfg_summary[
"label"] = cfg_save[
"label"];
365 cfg_summary[
"campaign_type"] = cfg_save[
"campaign_type"];
367 if(cfg_save.
has_child(
"carryover_sides_start")) {
368 cfg_summary[
"scenario"] = cfg_save.
child(
"carryover_sides_start")[
"next_scenario"];
370 cfg_summary[
"scenario"] = cfg_save[
"scenario"];
373 cfg_summary[
"difficulty"] = cfg_save[
"difficulty"];
374 cfg_summary[
"random_mode"] = cfg_save[
"random_mode"];
376 cfg_summary[
"active_mods"] = cfg_save.
child_or_empty(
"multiplayer")[
"active_mods"];
377 cfg_summary[
"campaign"] = cfg_save[
"campaign"];
378 cfg_summary[
"version"] = cfg_save[
"version"];
379 cfg_summary[
"corrupt"] =
"";
382 cfg_summary[
"turn"] = cfg_snapshot[
"turn_at"];
383 if(cfg_snapshot[
"turns"] !=
"-1") {
384 cfg_summary[
"turn"] = cfg_summary[
"turn"].str() +
"/" + cfg_snapshot[
"turns"].str();
394 bool shrouded =
false;
396 if(
const config& snapshot = *(has_snapshot ? &cfg_snapshot : &cfg_replay_start)) {
399 std::string leader_image;
400 std::string leader_image_tc_modifier;
401 std::string leader_name;
402 int gold = side[
"gold"];
403 int units = 0, recall_units = 0;
405 if(side[
"controller"] != team::CONTROLLER::enum_to_string(team::CONTROLLER::HUMAN)) {
409 if(side[
"shroud"].to_bool()) {
414 if(u.has_attribute(
"x") && u.has_attribute(
"y")) {
421 if(!leader.empty() || !u[
"canrecruit"].to_bool()) {
429 leader = u[
"id"].str();
430 leader_name = u[
"name"].str();
431 leader_image = u[
"image"].str();
432 leader_image_tc_modifier =
"~RC(" + u[
"flag_rgb"].str() +
">" + tc_color +
")";
443 if(!leader_image_path.empty()) {
444 leader_image_path += leader_image_tc_modifier;
446 leader_image = leader_image_path;
449 leader_config[
"leader"] = leader;
450 leader_config[
"leader_name"] = leader_name;
451 leader_config[
"leader_image"] = leader_image;
452 leader_config[
"leader_image_tc_modifier"] = leader_image_tc_modifier;
453 leader_config[
"gold"] = gold;
454 leader_config[
"units"] = units;
455 leader_config[
"recall_units"] = recall_units;
457 cfg_summary.
add_child(
"leader", leader_config);
464 cfg_summary[
"map_data"] = cfg_snapshot[
"map_data"].str();
466 ERR_SAVE <<
"Not saving map because there is shroud" << std::endl;
468 }
else if(has_replay) {
469 if(!cfg_replay_start.find_child(
"side",
"shroud",
"yes") && cfg_replay_start.has_attribute(
"map_data")) {
470 cfg_summary[
"map_data"] = cfg_replay_start[
"map_data"];
472 ERR_SAVE <<
"Not saving map because there is shroud" << std::endl;
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)...
bool empty() const
Tests for an attribute that either was never set or was set to "".
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...
void rebuild(const std::string &name)
void read_save_file(const std::string &name, config &cfg, std::string *error_log)
Read the complete config information out of a savefile.
void clear_children(T... keys)
bool delete_file(const std::string &filename)
static std::string get_side_color_id_from_config(const config &cfg)
config & find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Variant for storing WML attributes.
bool operator()(const save_info &a, const save_info &b) const
void extract_summary_from_config(config &, config &)
void read_bz2(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially bzip2_error.
Error used when game loading fails.
bool has_attribute(config_key_type key) const
bool has_child(config_key_type key) const
Determine whether a config has a child or not.
void remove(const std::string &name)
static bool file_exists(const bfs::path &fpath)
child_itors child_range(config_key_type key)
std::vector< save_info > get_saves_list(const std::string *dir, const std::string *filter)
Get a list of available saves.
static lg::log_domain log_engine("engine")
filesystem::scoped_istream istream_file(const std::string &fname, bool treat_failure_as_error)
void set_modified(const std::string &name, const std::time_t &modified)
Contains the exception interfaces used to signal completion of a scenario, campaign or turn...
void read_gz(config &cfg, std::istream &file, abstract_validator *validator)
Might throw a std::ios_base::failure especially a gzip_error.
std::string get_saves_dir()
void remove_attribute(config_key_type key)
Definitions for the interface to Wesnoth Markup Language (WML).
const config & summary() const
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
std::string strftime(const std::string &format, const std::tm *time)
std::string format_time_local() const
void write(std::ostream &out, const configr_of &cfg, unsigned int level)
bool operator()(const std::string &filename) const
static UNUSEDNOWARN std::string _(const char *str)
static filesystem::scoped_istream find_save_file(const std::string &name, const std::vector< std::string > &suffixes)
void write_gz(std::ostream &out, const configr_of &cfg)
void read(config &cfg, std::istream &in, abstract_validator *validator)
void delete_game(const std::string &name)
Delete a savegame.
std::unique_ptr< std::istream > scoped_istream
save_index_class save_index_manager
std::string get_independent_image_path(const std::string &filename)
Returns an image path to filename for binary path-independent use in saved games. ...
std::time_t to_time_t(std::time_t def=0) const
const char * what() const noexcept
const std::string & name() const
const std::time_t & modified() const
std::unique_ptr< std::ostream > scoped_ostream
bool is_gzip_file(const std::string &filename)
Returns true if the file ends with '.gz'.
config & get(const std::string &name)
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, file_name_option mode, file_filter_option filter, file_reorder_option reorder, file_tree_checksum *checksum)
Populates 'files' with all the files and 'dirs' with all the directories in dir.
An exception object used when an IO error occurs.
#define log_scope(description)
static void fix_leader_image_path(config &data)
Declarations for File-IO.
static int sort(lua_State *L)
save_info operator()(const std::string &filename) const
config & add_child(config_key_type key)
compression::format save_compression_format()
bool is_bzip2_file(const std::string &filename)
Returns true if the file ends with '.bz2'.
Filename and modification date for a file list.
create_save_info(const std::string *d=nullptr)
std::time_t file_modified_time(const std::string &fname)
Get the modification time of a file.
std::map< std::string, std::time_t > modified_
std::string format_time_summary() const
filename_filter(const std::string &filter)
Standard logging facilities (interface).
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.
A config object defines a single node in a WML file, with access to child nodes.
static lg::log_domain log_enginerefac("enginerefac")
std::string get_save_index_file()
A structure for comparing to save_info objects based on their modified time.
std::string format_time_summary(std::time_t t)
bool use_twelve_hour_clock_format()
std::string::const_iterator iterator
filesystem::scoped_ostream ostream_file(const std::string &fname, bool create_directory)