Added persist_manager class to handle saving,

...loading, caching and (not yet implemented) atomic transactions of
data.
This commit is contained in:
Jody Northup 2010-06-23 05:01:24 +00:00
parent bd60de7140
commit 55f1280b07
14 changed files with 179 additions and 75 deletions

View file

@ -553,7 +553,7 @@
>
</File>
<File
RelativePath="..\..\src\persist_manager.hpp"
RelativePath="..\..\src\persist_manager.cpp"
>
</File>
<File
@ -6735,6 +6735,10 @@
RelativePath="..\..\src\persist_context.hpp"
>
</File>
<File
RelativePath="..\..\src\persist_manager.hpp"
>
</File>
<File
RelativePath="..\..\src\persist_var.hpp"
>

View file

@ -425,6 +425,7 @@ set(wesnoth-main_SRC
multiplayer_create.cpp
${network_implementation_files} # network.cpp and network_worker.cpp are included by default (without USE_ANA_NETWORK)
persist_context.cpp
persist_manager.cpp
persist_var.cpp
playcampaign.cpp
play_controller.cpp

View file

@ -241,6 +241,7 @@ wesnoth_source = \
$(network_core) \
pathfind/pathfind.cpp \
persist_context.cpp \
persist_manager.cpp \
persist_var.cpp \
playcampaign.cpp \
play_controller.cpp \

View file

@ -225,6 +225,7 @@ wesnoth_sources = Split("""
multiplayer_connect.cpp
pathfind/pathfind.cpp
persist_context.cpp
persist_manager.cpp
persist_var.cpp
playcampaign.cpp
play_controller.cpp

View file

@ -1,6 +1,6 @@
/* $Id$ */
/*
Copyright (C) 2003 - 2010 by David White <dave@whitevine.net>
Copyright (C) 2010 by Jody Northup
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
@ -14,68 +14,11 @@
#include "global.hpp"
#include "filesystem.hpp"
#include "util.hpp"
#include "log.hpp"
#include "persist_context.hpp"
#include "persist_manager.hpp"
#include "resources.hpp"
#include "serialization/binary_or_text.hpp"
static std::string get_persist_cfg_name(const std::string &name_space) {
return (get_dir(get_user_data_dir() + "/persist/") + name_space + ".cfg");
}
static bool load_persist_data(const std::string &name_space, config &cfg, const bool create_if_missing = true)
{
bool success = false;
std::string cfg_dir = get_dir(get_user_data_dir() + "/persist");
create_directory_if_missing(cfg_dir);
std::string cfg_name = get_persist_cfg_name(name_space);
if (!cfg_name.empty()) {
scoped_istream file_stream = istream_file(cfg_name);
if (file_stream->fail()) {
if (create_if_missing) {
success = true;
}
} else {
try {
detect_format_and_read(cfg,*file_stream);
success = true;
} catch (config::error &err) {
LOG_SAVE << err.message;
success = false;
}
}
}
return success;
}
static bool save_persist_data(const std::string &name_space, config &cfg)
{
bool success = false;
std::string cfg_name = get_persist_cfg_name(name_space);
if (!cfg_name.empty()) {
if (cfg.empty()) {
success = delete_directory(cfg_name);
} else {
scoped_ostream out = ostream_file(cfg_name);
if (!out->fail())
{
config_writer writer(*out,false);
try {
writer.write(cfg);
success = true;
} catch(config::error &err) {
LOG_SAVE << err.message;
success = false;
}
}
}
}
return success;
}
#include "util.hpp"
config pack_scalar(const std::string &name, const t_string &val)
{
@ -89,12 +32,12 @@ persist_context &persist_context::add_child(const std::string& /*key*/) {
return *this;//(children_[key]);
}
void persist_context::load() {
load_persist_data(namespace_.root_,cfg_,false);
resources::persist->load_data(namespace_.root_,cfg_,false);
}
persist_context::persist_context(const std::string &name_space)
: cfg_()
, namespace_(name_space)
, namespace_(name_space,true)
, root_node_(namespace_.root_,this,cfg_)
, active_(&root_node_)
, valid_(namespace_.valid())
@ -142,7 +85,6 @@ bool persist_context::clear_var(std::string &global)
active_->cfg_.clear_children("variables");
active_->cfg_.remove_attribute("variables");
}
namespace_ = namespace_.prev();
}
}
// dirty_ = true;
@ -174,7 +116,7 @@ config persist_context::get_var(const std::string &global) const
return ret;
}
bool persist_context::save_context() {
return save_persist_data(namespace_.root_,cfg_);
return resources::persist->save_data(namespace_.root_,cfg_);
}
bool persist_context::set_var(const std::string &global,const config &val)
{
@ -191,3 +133,20 @@ bool persist_context::set_var(const std::string &global,const config &val)
// dirty_ = true;
return save_context();
}
void persist_context::set_node(const std::string &name) {
active_ = &(root_node_.child(name));
}
std::string persist_context::get_node() {
std::vector<std::string> layers;
node *ptr = active_;
while (ptr != NULL) {
layers.push_back(ptr->name_);
ptr = ptr->parent_;
}
std::string ret;
for (int i = layers.size() - 1; i >= 0; i--) {
ret += layers[i];
if (i != 0) ret += ".";
}
return ret;
}

View file

@ -1,6 +1,6 @@
/* $Id$ */
/*
Copyright (C) 2003 - 2010 by David White <dave@whitevine.net>
Copyright (C) 2010 by Jody Northup
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
@ -22,7 +22,7 @@ static lg::log_domain log_persist("engine/persistence");
#define ERR_SAVE LOG_STREAM(err, log_persist)
config pack_scalar(const std::string &,const t_string &);
class persist_context {
private:
public:
struct name_space {
std::string namespace_;
std::string root_;
@ -76,7 +76,7 @@ private:
{
}
name_space(const std::string &ns)
name_space(const std::string &ns, bool doParse = false)
: namespace_(ns)
, root_()
, node_()
@ -84,7 +84,8 @@ private:
, descendants_()
, valid_(false)
{
parse();
if (doParse)
parse();
valid_ = ((namespace_.find_first_not_of("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.") > namespace_.length()) && !namespace_.empty());
root_ = namespace_.substr(0,namespace_.find_first_of("."));
node_ = namespace_.substr(namespace_.find_last_of(".") + 1);
@ -94,6 +95,7 @@ private:
descendants_ = namespace_.substr(namespace_.find_first_of(".") + 1);
}
};
private:
struct node {
typedef std::map<std::string,node*> child_map;
@ -166,6 +168,8 @@ public:
bool clear_var(std::string &);
config get_var(const std::string &) const;
bool set_var(const std::string &, const config &);
std::string get_node();
void set_node(const std::string &);
bool valid() const { return valid_; };
bool dirty() const {
return true;

85
src/persist_manager.cpp Normal file
View file

@ -0,0 +1,85 @@
/* $Id: persist_manager.cpp 43488 2010-06-16 13:47:53Z upthorn $ */
/*
Copyright (C) 2010 by Jody Northup
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "filesystem.hpp"
#include "persist_context.hpp"
#include "persist_manager.hpp"
#include "serialization/binary_or_text.hpp"
static std::string get_persist_cfg_name(const std::string &name_space) {
return (get_dir(get_user_data_dir() + "/persist/") + name_space + ".cfg");
}
bool persist_manager::save_data(const std::string &name_space, config &cfg) {
bool success = false;
std::string cfg_name = get_persist_cfg_name(name_space);
if (!cfg_name.empty()) {
if (cfg.empty()) {
success = delete_directory(cfg_name);
} else {
scoped_ostream out = ostream_file(cfg_name);
if (!out->fail())
{
config_writer writer(*out,false);
try {
writer.write(cfg);
success = true;
} catch(config::error &err) {
LOG_SAVE << err.message;
success = false;
}
}
}
}
return success;
}
bool persist_manager::load_data(const std::string &name_space, config &cfg, const bool create_if_missing) {
bool success = false;
std::string cfg_dir = get_dir(get_user_data_dir() + "/persist");
create_directory_if_missing(cfg_dir);
std::string cfg_name = get_persist_cfg_name(name_space);
if (!cfg_name.empty()) {
scoped_istream file_stream = istream_file(cfg_name);
if (file_stream->fail()) {
if (create_if_missing) {
success = true;
}
} else {
try {
detect_format_and_read(cfg,*file_stream);
success = true;
} catch (config::error &err) {
LOG_SAVE << err.message;
success = false;
}
}
}
return success;
}
persist_context &persist_manager::get_context(const std::string &ns)
{
persist_context::name_space name(ns,true);
std::string key(name.root_);
context_map::iterator i = contexts_.find(key);
if (i == contexts_.end()) {
contexts_[key] = new persist_context(key);
}
persist_context *ret = contexts_[key];
if (ret->get_node() != ns)
ret->set_node(name.descendants_);
return *ret;
};

40
src/persist_manager.hpp Normal file
View file

@ -0,0 +1,40 @@
/* $Id$ */
/*
Copyright (C) 2010 by Jody Northup
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
or at your option any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#include "config.hpp"
#include "persist_context.hpp"
class persist_manager {
protected:
typedef std::map<std::string,persist_context *> context_map;
bool in_transaction_;
context_map contexts_;
public:
persist_manager() : in_transaction_(false),contexts_() {}
~persist_manager() {
for (context_map::iterator i = contexts_.begin(); i != contexts_.end(); i++)
delete (i->second);
}
persist_context &get_context(const std::string &ns);
//Allow for derived types to save/load from other types of storage
virtual bool save_data(const std::string &name_space, config &cfg);
virtual bool load_data(const std::string &name_space, config &cfg, const bool create_if_missing = true);
//TODO - Transactions
bool start_transaction();
bool end_transaction();
bool cancel_transaction();
};

View file

@ -1,6 +1,6 @@
/* $Id$ */
/*
Copyright (C) 2003 - 2010 by David White <dave@whitevine.net>
Copyright (C) 2010 by Jody Northup
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
@ -17,6 +17,7 @@
#include "gamestatus.hpp"
#include "log.hpp"
#include "persist_context.hpp"
#include "persist_manager.hpp"
#include "persist_var.hpp"
#include "resources.hpp"
@ -78,7 +79,7 @@ void verify_and_get_global_variable(const vconfig &pcfg)
// TODO: determine single or multiplayer and check for side=, depending.
if (valid)
{
persist_context ctx(pcfg["namespace"]);
persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
if (ctx.valid()) {
get_global_variable(ctx,pcfg);
} else {
@ -104,7 +105,7 @@ void verify_and_set_global_variable(const vconfig &pcfg)
// TODO: determine single or multiplayer and check for side=, depending.
if (valid)
{
persist_context ctx(pcfg["namespace"]);
persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
if (ctx.valid()) {
set_global_variable(ctx,pcfg);
} else {
@ -126,7 +127,7 @@ void verify_and_clear_global_variable(const vconfig &pcfg)
// TODO: determine single or multiplayer and check for side=, depending.
if (valid)
{
persist_context ctx(pcfg["namespace"]);
persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
if (ctx.valid()) {
clear_global_variable(ctx,pcfg);
} else {

View file

@ -1,6 +1,6 @@
/* $Id$ */
/*
Copyright (C) 2003 - 2010 by David White <dave@whitevine.net>
Copyright (C) 2010 by Jody Northup
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify

View file

@ -62,7 +62,8 @@ playsingle_controller::playsingle_controller(const config& level,
replaying_(false),
turn_over_(false),
skip_next_turn_(false),
level_result_(NONE)
level_result_(NONE),
persist_()
{
// game may need to start in linger mode
if (state_of_game.classification().completion == "victory" || state_of_game.classification().completion == "defeat")
@ -74,12 +75,14 @@ playsingle_controller::playsingle_controller(const config& level,
ai::game_info ai_info;
ai::manager::set_ai_info(ai_info);
ai::manager::add_observer(this) ;
resources::persist = &persist_;
}
playsingle_controller::~playsingle_controller()
{
ai::manager::remove_observer(this) ;
ai::manager::clear_ais() ;
resources::persist = NULL;
}
void playsingle_controller::init_gui(){

View file

@ -19,6 +19,7 @@
#include "global.hpp"
#include "cursor.hpp"
#include "persist_manager.hpp"
#include "play_controller.hpp"
#include "replay.hpp"
@ -96,6 +97,7 @@ protected:
bool turn_over_;
bool skip_next_turn_;
LEVEL_RESULT level_result_;
persist_manager persist_;
private:
void report_victory(std::ostringstream &report, int player_gold,
int remaining_gold, int finishing_bonus_per_turn,

View file

@ -28,4 +28,5 @@ namespace resources
wb::manager *whiteboard;
std::vector<undo_action> *undo_stack;
std::vector<undo_action> *redo_stack;
persist_manager *persist;
}

View file

@ -28,6 +28,7 @@ class play_controller;
class team;
class tod_manager;
class unit_map;
class persist_manager;
struct undo_action;
namespace soundsource { class manager; }
@ -48,6 +49,7 @@ namespace resources
extern wb::manager *whiteboard;
extern std::vector<undo_action> *undo_stack;
extern std::vector<undo_action> *redo_stack;
extern persist_manager *persist;
}
#endif