Add other versions of Wesnoth to the Load Game dialog
If a save directory from another version is found, a drop-down list of directories is added below the filter box in the Load Game dialog. Refactor save_index_class to allow instances for other directories. Design idea: all new saves go in to the main save directory. Games can be loaded from other directories, but those directories are treated as read-only. When building an index for other directories, the index is kept in memory and not written to disk - this results in some noticeable lag in the UI when opening the other versions' directories, but not the usual save dir.
This commit is contained in:
parent
22acd36155
commit
b66bdb8a16
16 changed files with 402 additions and 128 deletions
|
@ -19,6 +19,7 @@
|
|||
* Add mushroom defense cap to mounted and some flying units
|
||||
* Dwarvish Lord and Steelclad: reduce hitpoints by 3 and reduce impact and pierce resistance to 20%
|
||||
### User interface
|
||||
* The load-game dialog can now see the directories used by Wesnoth 1.14, 1.12, etc.
|
||||
### Lua API
|
||||
### WML engine
|
||||
### Packaging
|
||||
|
|
|
@ -412,15 +412,42 @@
|
|||
grow_factor = 0
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[text_box]
|
||||
id = "txtFilter"
|
||||
definition = "default"
|
||||
{FILTER_TEXT_BOX_HINT}
|
||||
[/text_box]
|
||||
[grid]
|
||||
|
||||
[row]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[text_box]
|
||||
id = "txtFilter"
|
||||
definition = "default"
|
||||
{FILTER_TEXT_BOX_HINT}
|
||||
[/text_box]
|
||||
|
||||
[/column]
|
||||
|
||||
[column]
|
||||
border = "all"
|
||||
border_size = 5
|
||||
horizontal_alignment = "left"
|
||||
|
||||
[menu_button]
|
||||
id = "dirList"
|
||||
definition = "default"
|
||||
tooltip = _ "Show saves from a different version of Wesnoth"
|
||||
[/menu_button]
|
||||
|
||||
[/column]
|
||||
|
||||
[/row]
|
||||
|
||||
[/grid]
|
||||
|
||||
[/column]
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
#include "config.hpp"
|
||||
#include "deprecation.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "game_version.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "log.hpp"
|
||||
#include "serialization/unicode.hpp"
|
||||
#include "serialization/unicode_cast.hpp"
|
||||
#include "game_version.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
@ -513,6 +513,13 @@ std::string get_next_filename(const std::string& name, const std::string& extens
|
|||
|
||||
static bfs::path user_data_dir, user_config_dir, cache_dir;
|
||||
|
||||
static const std::string get_version_path_suffix(const version_info& version)
|
||||
{
|
||||
std::ostringstream s;
|
||||
s << version.major_version() << '.' << version.minor_version();
|
||||
return s.str();
|
||||
}
|
||||
|
||||
static const std::string& get_version_path_suffix()
|
||||
{
|
||||
static std::string suffix;
|
||||
|
@ -521,9 +528,7 @@ static const std::string& get_version_path_suffix()
|
|||
// the version number cannot change during runtime.
|
||||
|
||||
if(suffix.empty()) {
|
||||
std::ostringstream s;
|
||||
s << game_config::wesnoth_version.major_version() << '.' << game_config::wesnoth_version.minor_version();
|
||||
suffix = s.str();
|
||||
suffix = get_version_path_suffix(game_config::wesnoth_version);
|
||||
}
|
||||
|
||||
return suffix;
|
||||
|
@ -817,6 +822,36 @@ std::string get_cache_dir()
|
|||
return cache_dir.string();
|
||||
}
|
||||
|
||||
std::vector<other_version_dir> find_other_version_saves_dirs()
|
||||
{
|
||||
const auto& w_ver = game_config::wesnoth_version;
|
||||
const auto& ms_ver = game_config::min_savegame_version;
|
||||
|
||||
if(w_ver.major_version() != 1 || ms_ver.major_version() != 1) {
|
||||
// Unimplemented, assuming that version 2 won't use WML-based saves
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<other_version_dir> result;
|
||||
|
||||
// For 1.16, check for saves from all versions up to 1.20.
|
||||
for(auto minor = ms_ver.minor_version(); minor <= w_ver.minor_version() + 4; ++minor) {
|
||||
if(minor == w_ver.minor_version())
|
||||
continue;
|
||||
|
||||
auto version = version_info{};
|
||||
version.set_major_version(w_ver.major_version());
|
||||
version.set_minor_version(minor);
|
||||
auto suffix = get_version_path_suffix(version);
|
||||
auto path = get_user_data_path().parent_path() / suffix / "saves";
|
||||
if(bfs::exists(path)) {
|
||||
result.emplace_back(suffix, path.generic_string());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string get_cwd()
|
||||
{
|
||||
error_code ec;
|
||||
|
|
|
@ -23,9 +23,9 @@
|
|||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <iosfwd>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "exceptions.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
|
@ -172,19 +172,46 @@ std::string get_user_config_dir();
|
|||
std::string get_user_data_dir();
|
||||
std::string get_cache_dir();
|
||||
|
||||
struct other_version_dir
|
||||
{
|
||||
/**
|
||||
* Here the version is given as a string instead of a version_info, because the
|
||||
* logic of how many components are significant ("1.16" rather than
|
||||
* "1.16.0") is encapsulated in find_other_version_saves_dirs().
|
||||
*/
|
||||
std::string version;
|
||||
std::string path;
|
||||
|
||||
// constructor because emplace_back() doesn't use aggregate initialization
|
||||
other_version_dir(const std::string& v, const std::string& p)
|
||||
: version(v)
|
||||
, path(p)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Searches for directories containing saves created by other versions of Wesnoth.
|
||||
*
|
||||
* The directories returned will exist, but might not contain any saves. Changes to
|
||||
* the filesystem (by running other versions or by deleting old directories) may
|
||||
* change the results returned by the function.
|
||||
*/
|
||||
std::vector<other_version_dir> find_other_version_saves_dirs();
|
||||
|
||||
std::string get_cwd();
|
||||
std::string get_exe_dir();
|
||||
|
||||
bool make_directory(const std::string& dirname);
|
||||
bool delete_directory(const std::string& dirname, const bool keep_pbl = false);
|
||||
bool delete_file(const std::string &filename);
|
||||
bool delete_file(const std::string& filename);
|
||||
|
||||
bool looks_like_pbl(const std::string& file);
|
||||
|
||||
// Basic disk I/O:
|
||||
|
||||
/** Basic disk I/O - read file. */
|
||||
std::string read_file(const std::string &fname);
|
||||
std::string read_file(const std::string& fname);
|
||||
filesystem::scoped_istream istream_file(const std::string& fname, bool treat_failure_as_error = true);
|
||||
filesystem::scoped_ostream ostream_file(const std::string& fname, bool create_directory = true);
|
||||
/** Throws io_exception if an error occurs. */
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "preferences/general.hpp" // for disable_preferences_save, etc
|
||||
#include "preferences/display.hpp"
|
||||
#include "savegame.hpp" // for clean_saves, etc
|
||||
#include "save_index.hpp"
|
||||
#include "scripting/application_lua_kernel.hpp"
|
||||
#include "sdl/surface.hpp" // for surface
|
||||
#include "serialization/compression.hpp" // for format::NONE
|
||||
|
@ -185,14 +186,14 @@ game_launcher::game_launcher(const commandline_options& cmdline_opts, const char
|
|||
{
|
||||
jump_to_editor_ = true;
|
||||
if (!cmdline_opts_.editor->empty())
|
||||
load_data_.reset(new savegame::load_game_metadata{ *cmdline_opts_.editor });
|
||||
load_data_.reset(new savegame::load_game_metadata{ savegame::save_index_class::default_saves_dir(), *cmdline_opts_.editor });
|
||||
}
|
||||
if (cmdline_opts_.fps)
|
||||
preferences::set_show_fps(true);
|
||||
if (cmdline_opts_.fullscreen)
|
||||
video().set_fullscreen(true);
|
||||
if (cmdline_opts_.load)
|
||||
load_data_.reset(new savegame::load_game_metadata{ *cmdline_opts_.load });
|
||||
load_data_.reset(new savegame::load_game_metadata{ savegame::save_index_class::default_saves_dir(), *cmdline_opts_.load });
|
||||
if (cmdline_opts_.max_fps) {
|
||||
int fps = utils::clamp(*cmdline_opts_.max_fps, 1, 1000);
|
||||
fps = 1000 / fps;
|
||||
|
@ -522,7 +523,7 @@ int game_launcher::unit_test()
|
|||
savegame::replay_savegame save(state_, compression::NONE);
|
||||
save.save_game_automatic(false, "unit_test_replay"); //false means don't check for overwrite
|
||||
|
||||
load_data_.reset(new savegame::load_game_metadata{ "unit_test_replay" , "", true, true, false });
|
||||
load_data_.reset(new savegame::load_game_metadata{ savegame::save_index_class::default_saves_dir(), "unit_test_replay" , "", true, true, false });
|
||||
|
||||
if (!load_game()) {
|
||||
std::cerr << "Failed to load the replay!" << std::endl;
|
||||
|
@ -601,7 +602,7 @@ bool game_launcher::load_game()
|
|||
|
||||
DBG_GENERAL << "Current campaign type: " << state_.classification().campaign_type << std::endl;
|
||||
|
||||
savegame::loadgame load(game_config_manager::get()->game_config(), state_);
|
||||
savegame::loadgame load(savegame::save_index_class::default_saves_dir(), game_config_manager::get()->game_config(), state_);
|
||||
if (load_data_) {
|
||||
std::unique_ptr<savegame::load_game_metadata> load_data = std::move(load_data_);
|
||||
load.data() = std::move(*load_data);
|
||||
|
|
|
@ -20,10 +20,9 @@
|
|||
#include "filesystem.hpp"
|
||||
#include "formatter.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "preferences/game.hpp"
|
||||
#include "game_classification.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "gui/auxiliary/field.hpp"
|
||||
#include "gui/core/log.hpp"
|
||||
#include "gui/dialogs/game_delete.hpp"
|
||||
|
@ -32,18 +31,19 @@
|
|||
#include "gui/widgets/label.hpp"
|
||||
#include "gui/widgets/listbox.hpp"
|
||||
#include "gui/widgets/minimap.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/scroll_label.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/text_box.hpp"
|
||||
#include "gui/widgets/toggle_button.hpp"
|
||||
#include "gui/widgets/window.hpp"
|
||||
#include "picture.hpp"
|
||||
#include "language.hpp"
|
||||
#include "picture.hpp"
|
||||
#include "preferences/game.hpp"
|
||||
#include "serialization/string_utils.hpp"
|
||||
#include "utils/general.hpp"
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
#include <cctype>
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
static lg::log_domain log_gameloaddlg{"gui/dialogs/game_load_dialog"};
|
||||
#define ERR_GAMELOADDLG LOG_STREAM(err, log_gameloaddlg)
|
||||
|
@ -69,6 +69,9 @@ namespace dialogs
|
|||
* txtFilter & & text & m &
|
||||
* The filter for the listbox items. $
|
||||
*
|
||||
* dirList & & menu_button & m &
|
||||
* Allows changing directory to the directories for old versions of Wesnoth. $
|
||||
*
|
||||
* savegame_list & & listbox & m &
|
||||
* List of savegames. $
|
||||
*
|
||||
|
@ -90,6 +93,9 @@ namespace dialogs
|
|||
* -lblSummary & & label & m &
|
||||
* Summary of the selected savegame. $
|
||||
*
|
||||
* delete & & button & m &
|
||||
* Delete the selected savegame. $
|
||||
*
|
||||
* @end{table}
|
||||
*/
|
||||
|
||||
|
@ -97,11 +103,12 @@ REGISTER_DIALOG(game_load)
|
|||
|
||||
game_load::game_load(const config& cache_config, savegame::load_game_metadata& data)
|
||||
: filename_(data.filename)
|
||||
, save_index_manager_(data.manager)
|
||||
, change_difficulty_(register_bool("change_difficulty", true, data.select_difficulty))
|
||||
, show_replay_(register_bool("show_replay", true, data.show_replay))
|
||||
, cancel_orders_(register_bool("cancel_orders", true, data.cancel_orders))
|
||||
, summary_(data.summary)
|
||||
, games_({savegame::get_saves_list()})
|
||||
, games_()
|
||||
, cache_config_(cache_config)
|
||||
, last_words_()
|
||||
{
|
||||
|
@ -116,19 +123,76 @@ void game_load::pre_show(window& window)
|
|||
|
||||
text_box* filter = find_widget<text_box>(&window, "txtFilter", false, true);
|
||||
|
||||
filter->set_text_changed_callback(
|
||||
std::bind(&game_load::filter_text_changed, this, _1, _2));
|
||||
filter->set_text_changed_callback(std::bind(&game_load::filter_text_changed, this, _1, _2));
|
||||
|
||||
listbox& list = find_widget<listbox>(&window, "savegame_list", false);
|
||||
|
||||
connect_signal_notify_modified(list,
|
||||
std::bind(&game_load::display_savegame, this, std::ref(window)));
|
||||
connect_signal_notify_modified(list, std::bind(&game_load::display_savegame, this, std::ref(window)));
|
||||
|
||||
window.keyboard_capture(filter);
|
||||
window.add_to_keyboard_chain(&list);
|
||||
|
||||
list.register_sorting_option(0, [this](const int i) { return games_[i].name(); });
|
||||
list.register_sorting_option(1, [this](const int i) { return games_[i].modified(); });
|
||||
|
||||
populate_game_list(window);
|
||||
|
||||
connect_signal_mouse_left_click(find_widget<button>(&window, "delete", false),
|
||||
std::bind(&game_load::delete_button_callback, this, std::ref(window)));
|
||||
|
||||
connect_signal_mouse_left_click(find_widget<button>(&window, "browse_saves_folder", false),
|
||||
std::bind(&game_load::browse_button_callback, this));
|
||||
|
||||
menu_button& dir_list = find_widget<menu_button>(&window, "dirList", false);
|
||||
dir_list.set_use_markup(true);
|
||||
dir_list.set_active(true);
|
||||
|
||||
set_save_dir_list(dir_list);
|
||||
|
||||
connect_signal_notify_modified(dir_list, std::bind(&game_load::handle_dir_select, this, std::ref(window)));
|
||||
|
||||
display_savegame(window);
|
||||
}
|
||||
|
||||
void game_load::set_save_dir_list(menu_button& dir_list)
|
||||
{
|
||||
const auto other_dirs = filesystem::find_other_version_saves_dirs();
|
||||
if(other_dirs.empty()) {
|
||||
dir_list.set_visible(widget::visibility::invisible);
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<config> options;
|
||||
// The first option in the list is the current version's save dir
|
||||
{
|
||||
config option;
|
||||
option["label"] = _("Normal saves directory");
|
||||
option["path"] = "";
|
||||
options.push_back(std::move(option));
|
||||
}
|
||||
|
||||
for(const auto& known_dir : filesystem::find_other_version_saves_dirs()) {
|
||||
if(!known_dir.path.empty()) {
|
||||
config option;
|
||||
option["label"] = known_dir.version;
|
||||
option["path"] = known_dir.path;
|
||||
option["details"] = formatter() << "<span color='#777777'>(" << known_dir.path << ")</span>";
|
||||
options.push_back(std::move(option));
|
||||
}
|
||||
}
|
||||
|
||||
dir_list.set_values(options, 0);
|
||||
dir_list.set_visible(widget::visibility::visible);
|
||||
}
|
||||
|
||||
void game_load::populate_game_list(window& window)
|
||||
{
|
||||
listbox& list = find_widget<listbox>(&window, "savegame_list", false);
|
||||
|
||||
list.clear();
|
||||
|
||||
games_ = save_index_manager_->get_saves_list();
|
||||
|
||||
for(const auto& game : games_) {
|
||||
std::map<std::string, string_map> data;
|
||||
string_map item;
|
||||
|
@ -144,19 +208,7 @@ void game_load::pre_show(window& window)
|
|||
list.add_row(data);
|
||||
}
|
||||
|
||||
list.register_sorting_option(0, [this](const int i) { return games_[i].name(); });
|
||||
list.register_sorting_option(1, [this](const int i) { return games_[i].modified(); });
|
||||
|
||||
connect_signal_mouse_left_click(
|
||||
find_widget<button>(&window, "delete", false),
|
||||
std::bind(&game_load::delete_button_callback,
|
||||
this, std::ref(window)));
|
||||
|
||||
connect_signal_mouse_left_click(
|
||||
find_widget<button>(&window, "browse_saves_folder", false),
|
||||
std::bind(&desktop::open_object, filesystem::get_saves_dir()));
|
||||
|
||||
display_savegame(window);
|
||||
find_widget<button>(&window, "delete", false).set_active(!save_index_manager_->read_only());
|
||||
}
|
||||
|
||||
void game_load::display_savegame_internal(window& window)
|
||||
|
@ -432,6 +484,10 @@ void game_load::evaluate_summary_string(std::stringstream& str, const config& cf
|
|||
}
|
||||
}
|
||||
}
|
||||
void game_load::browse_button_callback()
|
||||
{
|
||||
desktop::open_object(save_index_manager_->dir());
|
||||
}
|
||||
|
||||
void game_load::delete_button_callback(window& window)
|
||||
{
|
||||
|
@ -448,7 +504,7 @@ void game_load::delete_button_callback(window& window)
|
|||
}
|
||||
|
||||
// Delete the file
|
||||
savegame::delete_game(games_[index].name());
|
||||
save_index_manager_->delete_game(games_[index].name());
|
||||
|
||||
// Remove it from the list of saves
|
||||
games_.erase(games_.begin() + index);
|
||||
|
@ -484,5 +540,20 @@ void game_load::key_press_callback(window& window, const SDL_Keycode key)
|
|||
}
|
||||
}
|
||||
|
||||
void game_load::handle_dir_select(window& window)
|
||||
{
|
||||
menu_button& dir_list = find_widget<menu_button>(&window, "dirList", false);
|
||||
|
||||
const auto& path = dir_list.get_value_config()["path"].str();
|
||||
if(path.empty()) {
|
||||
save_index_manager_ = savegame::save_index_class::default_saves_dir();
|
||||
} else {
|
||||
save_index_manager_ = std::make_shared<savegame::save_index_class>(path);
|
||||
}
|
||||
|
||||
populate_game_list(window);
|
||||
display_savegame(window);
|
||||
}
|
||||
|
||||
} // namespace dialogs
|
||||
} // namespace gui2
|
||||
|
|
|
@ -14,11 +14,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "gettext.hpp"
|
||||
#include "gui/dialogs/modal_dialog.hpp"
|
||||
#include "gui/dialogs/transient_message.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "gui/widgets/menu_button.hpp"
|
||||
#include "save_index.hpp"
|
||||
#include "gettext.hpp"
|
||||
#include "savegame.hpp"
|
||||
|
||||
#include <SDL2/SDL_keycode.h>
|
||||
|
||||
|
@ -28,7 +29,6 @@ class text_box_base;
|
|||
|
||||
namespace dialogs
|
||||
{
|
||||
|
||||
class game_load : public modal_dialog
|
||||
{
|
||||
public:
|
||||
|
@ -36,11 +36,6 @@ public:
|
|||
|
||||
static bool execute(const config& cache_config, savegame::load_game_metadata& data)
|
||||
{
|
||||
if(savegame::get_saves_list().empty()) {
|
||||
gui2::show_transient_message(_("No Saved Games"), _("There are no save files to load"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return game_load(cache_config, data).show();
|
||||
}
|
||||
|
||||
|
@ -51,8 +46,15 @@ private:
|
|||
/** Inherited from modal_dialog, implemented by REGISTER_DIALOG. */
|
||||
virtual const std::string& window_id() const override;
|
||||
|
||||
void set_save_dir_list(menu_button& dir_list);
|
||||
|
||||
/** Update (both internally and visually) the list of games. */
|
||||
void populate_game_list(window& window);
|
||||
|
||||
void filter_text_changed(text_box_base* textbox, const std::string& text);
|
||||
void browse_button_callback();
|
||||
void delete_button_callback(window& window);
|
||||
void handle_dir_select(window& window);
|
||||
|
||||
void display_savegame_internal(window& window);
|
||||
void display_savegame(window& window);
|
||||
|
@ -61,6 +63,7 @@ private:
|
|||
void key_press_callback(window& window, const SDL_Keycode key);
|
||||
|
||||
std::string& filename_;
|
||||
std::shared_ptr<savegame::save_index_class>& save_index_manager_;
|
||||
|
||||
field_bool* change_difficulty_;
|
||||
field_bool* show_replay_;
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
#include "gui/dialogs/multiplayer/mp_create_game.hpp"
|
||||
|
||||
#include "filesystem.hpp"
|
||||
#include "formatter.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "game_config_manager.hpp"
|
||||
#include "game_initialization/lobby_data.hpp"
|
||||
#include "gettext.hpp"
|
||||
|
@ -27,12 +30,8 @@
|
|||
#include "gui/widgets/button.hpp"
|
||||
#include "gui/widgets/image.hpp"
|
||||
#include "gui/widgets/integer_selector.hpp"
|
||||
#include "gui/widgets/menu_button.hpp"
|
||||
#include "preferences/game.hpp"
|
||||
#include "gui/widgets/listbox.hpp"
|
||||
#include "formatter.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "gui/widgets/menu_button.hpp"
|
||||
#include "gui/widgets/minimap.hpp"
|
||||
#include "gui/widgets/settings.hpp"
|
||||
#include "gui/widgets/slider.hpp"
|
||||
|
@ -42,8 +41,10 @@
|
|||
#include "gui/widgets/toggle_button.hpp"
|
||||
#include "gui/widgets/toggle_panel.hpp"
|
||||
#include "log.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "map_settings.hpp"
|
||||
#include "preferences/game.hpp"
|
||||
#include "save_index.hpp"
|
||||
#include "savegame.hpp"
|
||||
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
|
@ -789,7 +790,7 @@ void mp_create_game::update_map_settings()
|
|||
|
||||
void mp_create_game::load_game_callback(window& window)
|
||||
{
|
||||
savegame::loadgame load(cfg_, create_engine_.get_state());
|
||||
savegame::loadgame load(savegame::save_index_class::default_saves_dir(), cfg_, create_engine_.get_state());
|
||||
|
||||
if(!load.load_multiplayer_game()) {
|
||||
return;
|
||||
|
|
|
@ -549,5 +549,6 @@ hotkey::ACTION_STATE play_controller::hotkey_handler::get_action_state(hotkey::H
|
|||
|
||||
void play_controller::hotkey_handler::load_autosave(const std::string& filename)
|
||||
{
|
||||
throw savegame::load_game_exception(filename);
|
||||
throw savegame::load_game_exception(
|
||||
savegame::load_game_metadata{savegame::save_index_class::default_saves_dir(), filename});
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include "hotkey/hotkey_handler_sp.hpp"
|
||||
|
||||
#include "filesystem.hpp" // for get_saves_dir()
|
||||
#include "font/standard_colors.hpp"
|
||||
#include "formula/string_utils.hpp"
|
||||
#include "hotkey/hotkey_command.hpp"
|
||||
|
@ -308,7 +309,7 @@ void playsingle_controller::hotkey_handler::load_autosave(const std::string& fil
|
|||
{
|
||||
config savegame;
|
||||
std::string error_log;
|
||||
savegame::read_save_file(filename, savegame, &error_log);
|
||||
savegame::read_save_file(filesystem::get_saves_dir(), filename, savegame, &error_log);
|
||||
|
||||
if(!error_log.empty() || savegame.child_or_empty("snapshot")["replay_pos"].to_int(-1) < 0 ) {
|
||||
gui2::show_error_message(_("The file you have tried to load is corrupt: '") + error_log);
|
||||
|
|
|
@ -47,9 +47,10 @@
|
|||
#include "replay.hpp"
|
||||
#include "reports.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "save_blocker.hpp"
|
||||
#include "save_index.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "savegame.hpp"
|
||||
#include "scripting/game_lua_kernel.hpp"
|
||||
#include "scripting/plugins/context.hpp"
|
||||
#include "sound.hpp"
|
||||
|
@ -909,7 +910,7 @@ void play_controller::save_map()
|
|||
|
||||
void play_controller::load_game()
|
||||
{
|
||||
savegame::loadgame load(game_config_, saved_game_);
|
||||
savegame::loadgame load(savegame::save_index_class::default_saves_dir(), game_config_, saved_game_);
|
||||
load.load_game_ingame();
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ void extract_summary_from_config(config&, config&);
|
|||
|
||||
void save_index_class::rebuild(const std::string& name)
|
||||
{
|
||||
std::time_t modified = filesystem::file_modified_time(filesystem::get_saves_dir() + "/" + name);
|
||||
std::time_t modified = filesystem::file_modified_time(dir_ + "/" + name);
|
||||
rebuild(name, modified);
|
||||
}
|
||||
|
||||
|
@ -56,7 +56,7 @@ void save_index_class::rebuild(const std::string& name, const std::time_t& modif
|
|||
try {
|
||||
config full;
|
||||
std::string dummy;
|
||||
read_save_file(name, full, &dummy);
|
||||
read_save_file(dir_, name, full, &dummy);
|
||||
|
||||
extract_summary_from_config(full, summary);
|
||||
} catch(const game::load_game_failed&) {
|
||||
|
@ -92,10 +92,20 @@ config& save_index_class::get(const std::string& name)
|
|||
return result;
|
||||
}
|
||||
|
||||
const std::string& save_index_class::dir() const
|
||||
{
|
||||
return dir_;
|
||||
}
|
||||
|
||||
void save_index_class::write_save_index()
|
||||
{
|
||||
log_scope("write_save_index()");
|
||||
|
||||
if(read_only_) {
|
||||
LOG_SAVE << "no-op: read_only instance";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
filesystem::scoped_ostream stream = filesystem::ostream_file(filesystem::get_save_index_file());
|
||||
|
||||
|
@ -110,13 +120,21 @@ void save_index_class::write_save_index()
|
|||
}
|
||||
}
|
||||
|
||||
save_index_class::save_index_class()
|
||||
save_index_class::save_index_class(const std::string& dir)
|
||||
: loaded_(false)
|
||||
, data_()
|
||||
, modified_()
|
||||
, dir_(dir)
|
||||
, read_only_(true)
|
||||
{
|
||||
}
|
||||
|
||||
save_index_class::save_index_class(create_for_default_saves_dir)
|
||||
: save_index_class(filesystem::get_saves_dir())
|
||||
{
|
||||
read_only_ = false;
|
||||
}
|
||||
|
||||
config& save_index_class::data(const std::string& name)
|
||||
{
|
||||
config& cfg = data();
|
||||
|
@ -167,7 +185,11 @@ void save_index_class::fix_leader_image_path(config& data)
|
|||
}
|
||||
}
|
||||
|
||||
save_index_class save_index_manager;
|
||||
std::shared_ptr<save_index_class> save_index_class::default_saves_dir()
|
||||
{
|
||||
static auto instance = std::make_shared<save_index_class>(create_for_default_saves_dir::yes);
|
||||
return instance;
|
||||
}
|
||||
|
||||
class filename_filter
|
||||
{
|
||||
|
@ -187,12 +209,12 @@ private:
|
|||
};
|
||||
|
||||
/** Get a list of available saves. */
|
||||
std::vector<save_info> get_saves_list(const std::string* dir, const std::string* filter)
|
||||
std::vector<save_info> save_index_class::get_saves_list(const std::string* filter)
|
||||
{
|
||||
create_save_info creator(dir);
|
||||
create_save_info creator(shared_from_this());
|
||||
|
||||
std::vector<std::string> filenames;
|
||||
filesystem::get_files_in_dir(creator.dir, &filenames);
|
||||
filesystem::get_files_in_dir(dir(), &filenames);
|
||||
|
||||
if(filter) {
|
||||
filenames.erase(
|
||||
|
@ -208,7 +230,7 @@ std::vector<save_info> get_saves_list(const std::string* dir, const std::string*
|
|||
|
||||
const config& save_info::summary() const
|
||||
{
|
||||
return save_index_manager.get(name());
|
||||
return save_index_->get(name());
|
||||
}
|
||||
|
||||
std::string save_info::format_time_local() const
|
||||
|
@ -255,12 +277,12 @@ bool save_info_less_time::operator()(const save_info& a, const save_info& b) con
|
|||
}
|
||||
}
|
||||
|
||||
static filesystem::scoped_istream find_save_file(
|
||||
static filesystem::scoped_istream find_save_file(const std::string& dir,
|
||||
const std::string& name, const std::vector<std::string>& suffixes)
|
||||
{
|
||||
for(const std::string& suf : suffixes) {
|
||||
filesystem::scoped_istream file_stream =
|
||||
filesystem::istream_file(filesystem::get_saves_dir() + "/" + name + suf);
|
||||
filesystem::istream_file(dir + "/" + name + suf);
|
||||
|
||||
if(!file_stream->fail()) {
|
||||
return file_stream;
|
||||
|
@ -271,10 +293,10 @@ static filesystem::scoped_istream find_save_file(
|
|||
throw game::load_game_failed();
|
||||
}
|
||||
|
||||
void read_save_file(const std::string& name, config& cfg, std::string* error_log)
|
||||
void read_save_file(const std::string& dir, const std::string& name, config& cfg, std::string* error_log)
|
||||
{
|
||||
static const std::vector<std::string> suffixes{"", ".gz", ".bz2"};
|
||||
filesystem::scoped_istream file_stream = find_save_file(name, suffixes);
|
||||
filesystem::scoped_istream file_stream = find_save_file(dir, name, suffixes);
|
||||
|
||||
cfg.clear();
|
||||
try {
|
||||
|
@ -312,8 +334,14 @@ void read_save_file(const std::string& name, config& cfg, std::string* error_log
|
|||
}
|
||||
}
|
||||
|
||||
void remove_old_auto_saves(const int autosavemax, const int infinite_auto_saves)
|
||||
void save_index_class::delete_old_auto_saves(const int autosavemax, const int infinite_auto_saves)
|
||||
{
|
||||
log_scope("delete_old_auto_saves()");
|
||||
if(read_only_) {
|
||||
LOG_SAVE << "no-op: read_only instance";
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string auto_save = _("Auto-Save");
|
||||
|
||||
int countdown = autosavemax;
|
||||
|
@ -321,7 +349,7 @@ void remove_old_auto_saves(const int autosavemax, const int infinite_auto_saves)
|
|||
return;
|
||||
}
|
||||
|
||||
std::vector<save_info> games = get_saves_list(nullptr, &auto_save);
|
||||
std::vector<save_info> games = get_saves_list(&auto_save);
|
||||
for(std::vector<save_info>::iterator i = games.begin(); i != games.end(); ++i) {
|
||||
if(countdown-- <= 0) {
|
||||
LOG_SAVE << "Deleting savegame '" << i->name() << "'\n";
|
||||
|
@ -330,23 +358,28 @@ void remove_old_auto_saves(const int autosavemax, const int infinite_auto_saves)
|
|||
}
|
||||
}
|
||||
|
||||
void delete_game(const std::string& name)
|
||||
void save_index_class::delete_game(const std::string& name)
|
||||
{
|
||||
filesystem::delete_file(filesystem::get_saves_dir() + "/" + name);
|
||||
if(read_only_) {
|
||||
log_scope("delete_game()");
|
||||
LOG_SAVE << "no-op: read_only instance";
|
||||
return;
|
||||
}
|
||||
|
||||
save_index_manager.remove(name);
|
||||
filesystem::delete_file(dir() + "/" + name);
|
||||
remove(name);
|
||||
}
|
||||
|
||||
create_save_info::create_save_info(const std::string* d)
|
||||
: dir(d ? *d : filesystem::get_saves_dir())
|
||||
create_save_info::create_save_info(const std::shared_ptr<save_index_class>& manager)
|
||||
: manager_(manager)
|
||||
{
|
||||
}
|
||||
|
||||
save_info create_save_info::operator()(const std::string& filename) const
|
||||
{
|
||||
std::time_t modified = filesystem::file_modified_time(dir + "/" + filename);
|
||||
save_index_manager.set_modified(filename, modified);
|
||||
return save_info(filename, modified);
|
||||
std::time_t modified = filesystem::file_modified_time(manager_->dir() + "/" + filename);
|
||||
manager_->set_modified(filename, modified);
|
||||
return save_info(filename, manager_, modified);
|
||||
}
|
||||
|
||||
void extract_summary_from_config(config& cfg_save, config& cfg_summary)
|
||||
|
|
|
@ -20,14 +20,17 @@
|
|||
|
||||
namespace savegame
|
||||
{
|
||||
class save_index_class;
|
||||
|
||||
/** Filename and modification date for a file list */
|
||||
class save_info
|
||||
{
|
||||
private:
|
||||
friend class create_save_info;
|
||||
|
||||
save_info(const std::string& name, const std::time_t& modified)
|
||||
save_info(const std::string& name, const std::shared_ptr<save_index_class>& index, const std::time_t& modified)
|
||||
: name_(name)
|
||||
, save_index_(index)
|
||||
, modified_(modified)
|
||||
{
|
||||
}
|
||||
|
@ -49,6 +52,7 @@ public:
|
|||
|
||||
private:
|
||||
std::string name_;
|
||||
std::shared_ptr<save_index_class> save_index_;
|
||||
std::time_t modified_;
|
||||
};
|
||||
|
||||
|
@ -61,40 +65,60 @@ struct save_info_less_time
|
|||
bool operator()(const save_info& a, const save_info& b) const;
|
||||
};
|
||||
|
||||
std::vector<save_info> get_saves_list(const std::string* dir = nullptr, const std::string* filter = nullptr);
|
||||
|
||||
/** Read the complete config information out of a savefile. */
|
||||
void read_save_file(const std::string& name, config& cfg, std::string* error_log);
|
||||
|
||||
/** Remove autosaves that are no longer needed (according to the autosave policy in the preferences). */
|
||||
void remove_old_auto_saves(const int autosavemax, const int infinite_auto_saves);
|
||||
|
||||
/** Delete a savegame. */
|
||||
void delete_game(const std::string& name);
|
||||
void read_save_file(const std::string& dir, const std::string& name, config& cfg, std::string* error_log);
|
||||
|
||||
class create_save_info
|
||||
{
|
||||
public:
|
||||
create_save_info(const std::string* d = nullptr);
|
||||
explicit create_save_info(const std::shared_ptr<save_index_class>&);
|
||||
save_info operator()(const std::string& filename) const;
|
||||
const std::string dir;
|
||||
std::shared_ptr<save_index_class> manager_;
|
||||
};
|
||||
|
||||
class save_index_class
|
||||
class save_index_class : public std::enable_shared_from_this<save_index_class>
|
||||
{
|
||||
public:
|
||||
save_index_class();
|
||||
/**
|
||||
* Constructor for a read-only instance. To get a writable instance, call default_saves_dir().
|
||||
*/
|
||||
explicit save_index_class(const std::string& dir);
|
||||
/** Syntatic sugar for choosing which constructor to use. */
|
||||
enum class create_for_default_saves_dir { yes };
|
||||
explicit save_index_class(create_for_default_saves_dir);
|
||||
|
||||
/** Returns an instance for managing saves in filesystem::get_saves_dir() */
|
||||
static std::shared_ptr<save_index_class> default_saves_dir();
|
||||
|
||||
std::vector<save_info> get_saves_list(const std::string* filter=nullptr);
|
||||
|
||||
/** Delete a savegame, including deleting the underlying file. */
|
||||
void delete_game(const std::string& name);
|
||||
|
||||
void rebuild(const std::string& name);
|
||||
void rebuild(const std::string& name, const std::time_t& modified);
|
||||
|
||||
/** Delete a savegame from the index, without deleting the underlying file. */
|
||||
void remove(const std::string& name);
|
||||
void set_modified(const std::string& name, const std::time_t& modified);
|
||||
|
||||
config& get(const std::string& name);
|
||||
const std::string& dir() const;
|
||||
|
||||
/** Delete autosaves that are no longer needed (according to the autosave policy in the preferences). */
|
||||
void delete_old_auto_saves(const int autosavemax, const int infinite_auto_saves);
|
||||
|
||||
/** Sync to disk, no-op if read_only_ is set */
|
||||
void write_save_index();
|
||||
|
||||
/**
|
||||
* If true, all of delete_game, delete_old_auto_saves and write_save_index will be no-ops.
|
||||
*/
|
||||
bool read_only()
|
||||
{
|
||||
return read_only_;
|
||||
}
|
||||
|
||||
private:
|
||||
config& data(const std::string& name);
|
||||
config& data();
|
||||
|
@ -104,7 +128,11 @@ private:
|
|||
bool loaded_;
|
||||
config data_;
|
||||
std::map<std::string, std::time_t> modified_;
|
||||
const std::string dir_;
|
||||
/**
|
||||
* The instance for default_saves_dir() writes a cache file. For other instances,
|
||||
* write_save_index() and delete() are no-ops.
|
||||
*/
|
||||
bool read_only_;
|
||||
};
|
||||
|
||||
extern save_index_class save_index_manager;
|
||||
} // end of namespace savegame
|
||||
|
|
|
@ -61,7 +61,8 @@ namespace savegame {
|
|||
bool save_game_exists(std::string name, compression::format compressed)
|
||||
{
|
||||
name += compression::format_extension(compressed);
|
||||
return filesystem::file_exists(filesystem::get_saves_dir() + "/" + name);
|
||||
auto manager = save_index_class::default_saves_dir();
|
||||
return filesystem::file_exists(manager->dir() + "/" + name);
|
||||
}
|
||||
|
||||
void clean_saves(const std::string& label)
|
||||
|
@ -69,18 +70,19 @@ void clean_saves(const std::string& label)
|
|||
const std::string prefix = label + "-" + _("Auto-Save");
|
||||
LOG_SAVE << "Cleaning saves with prefix '" << prefix << "'\n";
|
||||
|
||||
for(const auto& save : get_saves_list()) {
|
||||
auto manager = save_index_class::default_saves_dir();
|
||||
for(const auto& save : manager->get_saves_list()) {
|
||||
if(save.name().compare(0, prefix.length(), prefix) == 0) {
|
||||
LOG_SAVE << "Deleting savegame '" << save.name() << "'\n";
|
||||
delete_game(save.name());
|
||||
manager->delete_game(save.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadgame::loadgame(const config& game_config, saved_game& gamestate)
|
||||
loadgame::loadgame(const std::shared_ptr<save_index_class>& index, const config& game_config, saved_game& gamestate)
|
||||
: game_config_(game_config)
|
||||
, gamestate_(gamestate)
|
||||
, load_data_()
|
||||
, load_data_(index)
|
||||
{}
|
||||
|
||||
bool loadgame::show_difficulty_dialog()
|
||||
|
@ -136,11 +138,16 @@ bool loadgame::load_game_ingame()
|
|||
}
|
||||
}
|
||||
|
||||
if(!load_data_.manager) {
|
||||
ERR_SAVE << "Null pointer in save index" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
load_data_.show_replay |= is_replay_save(load_data_.summary);
|
||||
|
||||
// Confirm the integrity of the file before throwing the exception.
|
||||
// Use the summary in the save_index for this.
|
||||
const config & summary = save_index_manager.get(load_data_.filename);
|
||||
const config & summary = load_data_.manager->get(load_data_.filename);
|
||||
|
||||
if (summary["corrupt"].to_bool(false)) {
|
||||
gui2::show_error_message(
|
||||
|
@ -177,8 +184,13 @@ bool loadgame::load_game()
|
|||
}
|
||||
}
|
||||
|
||||
if(!load_data_.manager) {
|
||||
ERR_SAVE << "Null pointer in save index" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string error_log;
|
||||
read_save_file(load_data_.filename, load_data_.load_config, &error_log);
|
||||
read_save_file(load_data_.manager->dir(), load_data_.filename, load_data_.load_config, &error_log);
|
||||
|
||||
convert_old_saves(load_data_.load_config);
|
||||
|
||||
|
@ -276,6 +288,11 @@ bool loadgame::load_multiplayer_game()
|
|||
return false;
|
||||
}
|
||||
|
||||
if(!load_data_.manager) {
|
||||
ERR_SAVE << "Null pointer in save index" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// read_save_file needs to be called before we can verify the classification so the data has
|
||||
// been populated. Since we do that, we report any errors in that process first.
|
||||
std::string error_log;
|
||||
|
@ -283,7 +300,7 @@ bool loadgame::load_multiplayer_game()
|
|||
cursor::setter cur(cursor::WAIT);
|
||||
log_scope("load_game");
|
||||
|
||||
read_save_file(load_data_.filename, load_data_.load_config, &error_log);
|
||||
read_save_file(load_data_.manager->dir(), load_data_.filename, load_data_.load_config, &error_log);
|
||||
copy_era(load_data_.load_config);
|
||||
}
|
||||
|
||||
|
@ -328,6 +345,7 @@ void loadgame::copy_era(config &cfg)
|
|||
savegame::savegame(saved_game& gamestate, const compression::format compress_saves, const std::string& title)
|
||||
: filename_()
|
||||
, title_(title)
|
||||
, save_index_manager_(save_index_class::default_saves_dir())
|
||||
, gamestate_(gamestate)
|
||||
, error_message_(_("The game could not be saved: "))
|
||||
, show_confirmation_(false)
|
||||
|
@ -448,7 +466,7 @@ bool savegame::save_game(const std::string& filename)
|
|||
// a player saves a game and exits the game or reloads the cache, the leader image will
|
||||
// only be available within that specific binary context (when playing another game from
|
||||
// the came campaign, for example).
|
||||
save_index_manager.rebuild(filename_);
|
||||
save_index_manager_->rebuild(filename_);
|
||||
|
||||
end = SDL_GetTicks();
|
||||
LOG_SAVE << "Milliseconds to save " << filename_ << ": " << end - start << std::endl;
|
||||
|
@ -506,7 +524,7 @@ void savegame::finish_save_game(const config_writer &out)
|
|||
if(!out.good()) {
|
||||
throw game::save_game_failed(_("Could not write to file"));
|
||||
}
|
||||
save_index_manager.remove(gamestate_.classification().label);
|
||||
save_index_manager_->remove(gamestate_.classification().label);
|
||||
} catch(const filesystem::io_exception& e) {
|
||||
throw game::save_game_failed(e.what());
|
||||
}
|
||||
|
@ -516,7 +534,7 @@ void savegame::finish_save_game(const config_writer &out)
|
|||
filesystem::scoped_ostream savegame::open_save_game(const std::string &label)
|
||||
{
|
||||
try {
|
||||
return filesystem::ostream_file(filesystem::get_saves_dir() + "/" + label);
|
||||
return filesystem::ostream_file(save_index_manager_->dir() + "/" + label);
|
||||
} catch(const filesystem::io_exception& e) {
|
||||
throw game::save_game_failed(e.what());
|
||||
}
|
||||
|
@ -573,7 +591,8 @@ void autosave_savegame::autosave(const bool disable_autosave, const int autosave
|
|||
|
||||
save_game_automatic();
|
||||
|
||||
remove_old_auto_saves(autosave_max, infinite_autosaves);
|
||||
auto manager = save_index_class::default_saves_dir();
|
||||
manager->delete_old_auto_saves(autosave_max, infinite_autosaves);
|
||||
}
|
||||
|
||||
std::string autosave_savegame::create_initial_filename(unsigned int turn_number) const
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "config.hpp"
|
||||
#include "filesystem.hpp"
|
||||
#include "lua_jailbreak_exception.hpp"
|
||||
#include "save_index.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "serialization/compression.hpp"
|
||||
|
||||
|
@ -26,17 +27,33 @@
|
|||
class config_writer;
|
||||
class version_info;
|
||||
|
||||
namespace savegame {
|
||||
namespace savegame
|
||||
{
|
||||
/** converts saves from older versions of wesnoth*/
|
||||
void convert_old_saves(config& cfg);
|
||||
/** Returns true if there is already a savegame with that name. */
|
||||
|
||||
/**
|
||||
* Returns true if there is already a savegame with this name, looking only in the default save
|
||||
* directory. Only expected to be used to check whether a subsequent save would overwrite an
|
||||
* existing file, therefore only expected to be used for the default save dir.
|
||||
*/
|
||||
bool save_game_exists(std::string name, compression::format compressed);
|
||||
|
||||
/** Delete all autosaves of a certain scenario. */
|
||||
/**
|
||||
* Delete all autosaves of a certain scenario from the default save directory.
|
||||
*
|
||||
* This is only expected to be called when the player starts the next scenario (or finishes the
|
||||
* campaign, in the case of the last scenario), so it's expected to correspond to the next scenario
|
||||
* being written to the default save directory.
|
||||
*/
|
||||
void clean_saves(const std::string& label);
|
||||
|
||||
struct load_game_metadata {
|
||||
/** Name of the savefile to be loaded. */
|
||||
struct load_game_metadata
|
||||
{
|
||||
/** There may be different instances of the index for different directories */
|
||||
std::shared_ptr<save_index_class> manager;
|
||||
|
||||
/** Name of the savefile to be loaded (not including the directory). */
|
||||
std::string filename;
|
||||
|
||||
/** The difficulty the save is meant to be loaded with. */
|
||||
|
@ -57,10 +74,11 @@ struct load_game_metadata {
|
|||
/** Config information of the savefile to be loaded. */
|
||||
config load_config;
|
||||
|
||||
explicit load_game_metadata(const std::string& fname = "", const std::string& hard = "",
|
||||
explicit load_game_metadata(std::shared_ptr<save_index_class> index,
|
||||
const std::string& fname = "", const std::string& hard = "",
|
||||
bool replay = false, bool stop = false, bool change = false,
|
||||
const config& summary = config(), const config& info = config())
|
||||
: filename(fname), difficulty(hard)
|
||||
: manager(index), filename(fname), difficulty(hard)
|
||||
, show_replay(replay), cancel_orders(stop), select_difficulty(change)
|
||||
, summary(summary), load_config(info)
|
||||
{
|
||||
|
@ -75,13 +93,7 @@ class load_game_exception
|
|||
: public lua_jailbreak_exception, public std::exception
|
||||
{
|
||||
public:
|
||||
load_game_exception(const std::string& fname)
|
||||
: lua_jailbreak_exception()
|
||||
, data_(fname)
|
||||
{
|
||||
}
|
||||
|
||||
load_game_exception(load_game_metadata&& data)
|
||||
explicit load_game_exception(load_game_metadata&& data)
|
||||
: lua_jailbreak_exception()
|
||||
, data_(data)
|
||||
{
|
||||
|
@ -96,7 +108,7 @@ private:
|
|||
class loadgame
|
||||
{
|
||||
public:
|
||||
loadgame(const config& game_config, saved_game& gamestate);
|
||||
loadgame(const std::shared_ptr<save_index_class>& index, const config& game_config, saved_game& gamestate);
|
||||
virtual ~loadgame() {}
|
||||
|
||||
/* In any of the following three function, a bool value of false indicates
|
||||
|
@ -143,6 +155,9 @@ private:
|
|||
* The base class for all savegame stuff.
|
||||
* This should not be used directly, as it does not directly produce usable saves.
|
||||
* Instead, use one of the derived classes.
|
||||
*
|
||||
* Saves are only created in filesystem::get_saves_dir() - files can be loaded
|
||||
* from elsewhere, but writes are only to that directory.
|
||||
*/
|
||||
class savegame
|
||||
{
|
||||
|
@ -207,6 +222,13 @@ protected:
|
|||
/** Title of the savegame dialog */
|
||||
std::string title_;
|
||||
|
||||
/** Will (at the time of writing) be save_index_class::default_saves_dir().
|
||||
There may be different instances the index for different directories, however
|
||||
writing is only expected to happen in the default save directory.
|
||||
|
||||
Making this a class member anyway, while I'm refactoring. */
|
||||
std::shared_ptr<save_index_class> save_index_manager_;
|
||||
|
||||
private:
|
||||
/** Subclass-specific part of filename building. */
|
||||
virtual std::string create_initial_filename(unsigned int turn_number) const = 0;
|
||||
|
|
|
@ -111,6 +111,7 @@
|
|||
#include "language.hpp"
|
||||
#include "map/map.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "save_index.hpp"
|
||||
#include "saved_game.hpp"
|
||||
#include "terrain/type_data.hpp"
|
||||
#include "tests/utils/fake_display.hpp"
|
||||
|
@ -740,7 +741,9 @@ template<>
|
|||
struct dialog_tester<game_load>
|
||||
{
|
||||
config cfg;
|
||||
savegame::load_game_metadata data;
|
||||
// It would be good to have a test directory instead of using the same directory as the player,
|
||||
// however this code will support that - default_saves_dir() will respect --userdata-dir.
|
||||
savegame::load_game_metadata data{savegame::save_index_class::default_saves_dir()};
|
||||
dialog_tester()
|
||||
{
|
||||
/** @todo Would be nice to add real data to the config. */
|
||||
|
|
Loading…
Add table
Reference in a new issue