move variable_info to own file
and also move game_data::temporarites_ to that file as a static variable. This fixes variable_info being dependent on game_data.
This commit is contained in:
parent
16938d397d
commit
5d3040c0b8
8 changed files with 266 additions and 209 deletions
|
@ -905,6 +905,7 @@ set(wesnoth-main_SRC
|
|||
unit_types.cpp
|
||||
utils/sha1.cpp
|
||||
variable.cpp
|
||||
variable_info.cpp
|
||||
variant.cpp
|
||||
whiteboard/action.cpp
|
||||
whiteboard/attack.cpp
|
||||
|
|
|
@ -537,6 +537,7 @@ wesnoth_sources = Split("""
|
|||
unit_types.cpp
|
||||
utils/sha1.cpp
|
||||
variable.cpp
|
||||
variable_info.cpp
|
||||
variant.cpp
|
||||
whiteboard/action.cpp
|
||||
whiteboard/attack.cpp
|
||||
|
|
|
@ -75,7 +75,6 @@ game_data::game_data()
|
|||
, wml_menu_items_()
|
||||
, rng_()
|
||||
, variables_()
|
||||
, temporaries_()
|
||||
, phase_(INITIAL)
|
||||
, can_end_turn_(true)
|
||||
, scenario_()
|
||||
|
@ -88,7 +87,6 @@ game_data::game_data(const config& level)
|
|||
, wml_menu_items_()
|
||||
, rng_(level)
|
||||
, variables_(level.child_or_empty("variables"))
|
||||
, temporaries_()
|
||||
, phase_(INITIAL)
|
||||
, can_end_turn_(level["can_end_turn"].to_bool(true))
|
||||
, scenario_(level["id"])
|
||||
|
@ -104,7 +102,6 @@ game_data::game_data(const game_data& data)
|
|||
, wml_menu_items_(data.wml_menu_items_)
|
||||
, rng_(data.rng_)
|
||||
, variables_(data.variables_)
|
||||
, temporaries_()
|
||||
, phase_(data.phase_)
|
||||
, can_end_turn_(data.can_end_turn_)
|
||||
, scenario_(data.scenario_)
|
||||
|
@ -121,7 +118,7 @@ config::attribute_value game_data::get_variable_const(const std::string &key) co
|
|||
variable_info to_get = get_variable_access(key, false, variable_info::TYPE_SCALAR);
|
||||
if (!to_get.is_valid)
|
||||
{
|
||||
config::attribute_value &to_return = temporaries_[key];
|
||||
config::attribute_value &to_return = variable_info::get_temporaries()[key];
|
||||
if (key.size() > 7 && key.substr(key.size() - 7) == ".length") {
|
||||
// length is a special attribute, so guarantee its correctness
|
||||
to_return = 0;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
#include "game_events/wmi_container.hpp"
|
||||
#include "map_location.hpp"
|
||||
#include "simple_rng.hpp"
|
||||
#include "variable.hpp"
|
||||
#include "variable_info.hpp"
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
@ -117,7 +117,6 @@ private:
|
|||
game_events::wmi_container wml_menu_items_;
|
||||
rand_rng::simple_rng rng_;
|
||||
config variables_;
|
||||
mutable config temporaries_; // lengths of arrays, etc.
|
||||
friend struct variable_info;
|
||||
PHASE phase_;
|
||||
bool can_end_turn_;
|
||||
|
|
171
src/variable.cpp
171
src/variable.cpp
|
@ -443,174 +443,3 @@ void scoped_recall_unit::activate()
|
|||
}
|
||||
|
||||
|
||||
variable_info::variable_info(config& source, const std::string& varname,
|
||||
bool force_valid, TYPE validation_type) :
|
||||
vartype(validation_type),
|
||||
is_valid(false),
|
||||
key(),
|
||||
explicit_index(false),
|
||||
index(0),
|
||||
vars(NULL)
|
||||
{
|
||||
|
||||
vars = &source;//&resources::gamedata->variables_;
|
||||
key = varname;
|
||||
std::string::const_iterator itor = std::find(key.begin(),key.end(),'.');
|
||||
int dot_index = key.find('.');
|
||||
|
||||
bool force_length = false;
|
||||
// example varname = "unit_store.modifications.trait[0]"
|
||||
while(itor != key.end()) { // subvar access
|
||||
std::string element=key.substr(0,dot_index);
|
||||
key = key.substr(dot_index+1);
|
||||
|
||||
size_t inner_index = 0;
|
||||
const std::string::iterator index_start = std::find(element.begin(),element.end(),'[');
|
||||
const bool inner_explicit_index = index_start != element.end();
|
||||
if(inner_explicit_index) {
|
||||
const std::string::iterator index_end = std::find(index_start,element.end(),']');
|
||||
const std::string index_str(index_start+1,index_end);
|
||||
inner_index = static_cast<size_t>(lexical_cast_default<int>(index_str));
|
||||
if(inner_index > game_config::max_loop) {
|
||||
ERR_NG << "variable_info: index greater than " << game_config::max_loop
|
||||
<< ", truncated\n";
|
||||
inner_index = game_config::max_loop;
|
||||
}
|
||||
element = std::string(element.begin(),index_start);
|
||||
}
|
||||
|
||||
size_t size = vars->child_count(element);
|
||||
if(size <= inner_index) {
|
||||
if(force_valid) {
|
||||
// Add elements to the array until the requested size is attained
|
||||
if(inner_explicit_index || key != "length") {
|
||||
for(; size <= inner_index; ++size) {
|
||||
vars->add_child(element);
|
||||
}
|
||||
}
|
||||
} else if(inner_explicit_index) {
|
||||
WRN_NG << "variable_info: invalid WML array index, "
|
||||
<< varname << std::endl;
|
||||
return;
|
||||
} else if(varname.length() >= 7 && varname.substr(varname.length()-7) == ".length") {
|
||||
// require '.' to avoid matching suffixes -> requires varname over key to always find length
|
||||
// return length 0 for non-existent WML array (handled below)
|
||||
force_length = true;
|
||||
} else {
|
||||
WRN_NG << "variable_info: retrieving member of non-existent WML container, "
|
||||
<< varname << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if((!inner_explicit_index && key == "length") || force_length) {
|
||||
switch(vartype) {
|
||||
case variable_info::TYPE_ARRAY:
|
||||
case variable_info::TYPE_CONTAINER:
|
||||
WRN_NG << "variable_info: using reserved WML variable as wrong type, "
|
||||
<< varname << std::endl;
|
||||
is_valid = force_valid || resources::gamedata->temporaries_.child(varname);
|
||||
break;
|
||||
case variable_info::TYPE_SCALAR:
|
||||
default:
|
||||
// Store the length of the array as a temporary variable
|
||||
resources::gamedata->temporaries_[varname] = int(size);
|
||||
is_valid = true;
|
||||
break;
|
||||
}
|
||||
key = varname;
|
||||
vars = &resources::gamedata->temporaries_;
|
||||
return;
|
||||
}
|
||||
|
||||
vars = &vars->child(element, inner_index);
|
||||
itor = std::find(key.begin(),key.end(),'.');
|
||||
dot_index = key.find('.');
|
||||
} // end subvar access
|
||||
|
||||
const std::string::iterator index_start = std::find(key.begin(),key.end(),'[');
|
||||
explicit_index = index_start != key.end();
|
||||
if(explicit_index) {
|
||||
const std::string::iterator index_end = std::find(index_start,key.end(),']');
|
||||
const std::string index_str(index_start+1,index_end);
|
||||
index = static_cast<size_t>(lexical_cast_default<int>(index_str));
|
||||
if(index > game_config::max_loop) {
|
||||
ERR_NG << "variable_info: index greater than " << game_config::max_loop
|
||||
<< ", truncated\n";
|
||||
index = game_config::max_loop;
|
||||
}
|
||||
key = std::string(key.begin(),index_start);
|
||||
size_t size = vars->child_count(key);
|
||||
if(size <= index) {
|
||||
if(!force_valid) {
|
||||
WRN_NG << "variable_info: invalid WML array index, " << varname << std::endl;
|
||||
return;
|
||||
}
|
||||
for(; size <= index; ++size) {
|
||||
vars->add_child(key);
|
||||
}
|
||||
}
|
||||
switch(vartype) {
|
||||
case variable_info::TYPE_ARRAY:
|
||||
vars = &vars->child(key, index);
|
||||
key = "__array";
|
||||
is_valid = force_valid || vars->child(key);
|
||||
break;
|
||||
case variable_info::TYPE_SCALAR:
|
||||
vars = &vars->child(key, index);
|
||||
key = "__value";
|
||||
is_valid = force_valid || vars->has_attribute(key);
|
||||
break;
|
||||
case variable_info::TYPE_CONTAINER:
|
||||
case variable_info::TYPE_UNSPECIFIED:
|
||||
default:
|
||||
is_valid = true;
|
||||
return;
|
||||
}
|
||||
if (force_valid) {
|
||||
WRN_NG << "variable_info: using explicitly indexed "
|
||||
"container as wrong WML type, " << varname << '\n';
|
||||
}
|
||||
explicit_index = false;
|
||||
index = 0;
|
||||
} else {
|
||||
// Final variable is not an explicit index [...]
|
||||
switch(vartype) {
|
||||
case variable_info::TYPE_ARRAY:
|
||||
case variable_info::TYPE_CONTAINER:
|
||||
is_valid = force_valid || vars->child(key);
|
||||
break;
|
||||
case variable_info::TYPE_SCALAR:
|
||||
is_valid = force_valid || vars->has_attribute(key);
|
||||
break;
|
||||
case variable_info::TYPE_UNSPECIFIED:
|
||||
default:
|
||||
is_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value &variable_info::as_scalar()
|
||||
{
|
||||
assert(is_valid);
|
||||
return (*vars)[key];
|
||||
}
|
||||
|
||||
config& variable_info::as_container() {
|
||||
assert(is_valid);
|
||||
if(explicit_index) {
|
||||
// Empty data for explicit index was already created if it was needed
|
||||
return vars->child(key, index);
|
||||
}
|
||||
if (config &temp = vars->child(key)) {
|
||||
// The container exists, index not specified, return index 0
|
||||
return temp;
|
||||
}
|
||||
// Add empty data for the new variable, since it does not exist yet
|
||||
return vars->add_child(key);
|
||||
}
|
||||
|
||||
variable_info::array_range variable_info::as_array() {
|
||||
assert(is_valid);
|
||||
return vars->child_range(key);
|
||||
}
|
||||
|
|
|
@ -209,36 +209,4 @@ private:
|
|||
unsigned int recall_index_;
|
||||
};
|
||||
|
||||
/** Information on a WML variable. */
|
||||
struct variable_info
|
||||
{
|
||||
typedef config::child_itors array_range;
|
||||
|
||||
/**
|
||||
* TYPE: the correct variable type should be decided by the user of the info structure
|
||||
* Note: an Array can also be considered a Container, since index 0 will be used by default
|
||||
*/
|
||||
enum TYPE { TYPE_SCALAR, //a Scalar variable resolves to a t_string attribute of *vars
|
||||
TYPE_ARRAY, //an Array variable is a series of Containers
|
||||
TYPE_CONTAINER, //a Container is a specific index of an Array (contains Scalars)
|
||||
TYPE_UNSPECIFIED };
|
||||
|
||||
variable_info(config& source, const std::string& varname, bool force_valid=true,
|
||||
TYPE validation_type=TYPE_UNSPECIFIED);
|
||||
|
||||
TYPE vartype; //default is TYPE_UNSPECIFIED
|
||||
bool is_valid;
|
||||
std::string key; //the name of the internal attribute or child
|
||||
bool explicit_index; //true if query ended in [...] specifier
|
||||
size_t index; //the index of the child
|
||||
config *vars; //the containing node in game_data s variables
|
||||
/**
|
||||
* Results: after deciding the desired type, these methods can retrieve the result
|
||||
* Note: first you should force_valid or check is_valid, otherwise these may fail
|
||||
*/
|
||||
config::attribute_value &as_scalar();
|
||||
config& as_container();
|
||||
array_range as_array(); //range may be empty
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
210
src/variable_info.cpp
Normal file
210
src/variable_info.cpp
Normal file
|
@ -0,0 +1,210 @@
|
|||
/*
|
||||
Copyright (C) 2003 by David White <dave@whitevine.net>
|
||||
Copyright (C) 2005 - 2014 by Philippe Plantier <ayin@anathas.org>
|
||||
|
||||
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 as published by
|
||||
the Free Software Foundation; either version 2 of the License, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Manage WML-variables.
|
||||
*/
|
||||
#include "global.hpp"
|
||||
#include "variable_info.hpp"
|
||||
|
||||
#include "log.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
static lg::log_domain log_engine("engine");
|
||||
#define LOG_NG LOG_STREAM(info, log_engine)
|
||||
#define WRN_NG LOG_STREAM(warn, log_engine)
|
||||
#define ERR_NG LOG_STREAM(err, log_engine)
|
||||
|
||||
namespace {
|
||||
config temporaries;// lengths of arrays, etc.
|
||||
}
|
||||
|
||||
|
||||
config& variable_info::get_temporaries() { return temporaries; }
|
||||
|
||||
variable_info::variable_info(config& source, const std::string& varname,
|
||||
bool force_valid, TYPE validation_type) :
|
||||
vartype(validation_type),
|
||||
is_valid(false),
|
||||
key(),
|
||||
explicit_index(false),
|
||||
index(0),
|
||||
vars(NULL)
|
||||
{
|
||||
|
||||
vars = &source;//&resources::gamedata->variables_;
|
||||
key = varname;
|
||||
std::string::const_iterator itor = std::find(key.begin(),key.end(),'.');
|
||||
int dot_index = key.find('.');
|
||||
|
||||
bool force_length = false;
|
||||
// example varname = "unit_store.modifications.trait[0]"
|
||||
while(itor != key.end()) { // subvar access
|
||||
std::string element=key.substr(0,dot_index);
|
||||
key = key.substr(dot_index+1);
|
||||
|
||||
size_t inner_index = 0;
|
||||
const std::string::iterator index_start = std::find(element.begin(),element.end(),'[');
|
||||
const bool inner_explicit_index = index_start != element.end();
|
||||
if(inner_explicit_index) {
|
||||
const std::string::iterator index_end = std::find(index_start,element.end(),']');
|
||||
const std::string index_str(index_start+1,index_end);
|
||||
inner_index = static_cast<size_t>(lexical_cast_default<int>(index_str));
|
||||
if(inner_index > game_config::max_loop) {
|
||||
ERR_NG << "variable_info: index greater than " << game_config::max_loop
|
||||
<< ", truncated\n";
|
||||
inner_index = game_config::max_loop;
|
||||
}
|
||||
element = std::string(element.begin(),index_start);
|
||||
}
|
||||
|
||||
size_t size = vars->child_count(element);
|
||||
if(size <= inner_index) {
|
||||
if(force_valid) {
|
||||
// Add elements to the array until the requested size is attained
|
||||
if(inner_explicit_index || key != "length") {
|
||||
for(; size <= inner_index; ++size) {
|
||||
vars->add_child(element);
|
||||
}
|
||||
}
|
||||
} else if(inner_explicit_index) {
|
||||
WRN_NG << "variable_info: invalid WML array index, "
|
||||
<< varname << std::endl;
|
||||
return;
|
||||
} else if(varname.length() >= 7 && varname.substr(varname.length()-7) == ".length") {
|
||||
// require '.' to avoid matching suffixes -> requires varname over key to always find length
|
||||
// return length 0 for non-existent WML array (handled below)
|
||||
force_length = true;
|
||||
} else {
|
||||
WRN_NG << "variable_info: retrieving member of non-existent WML container, "
|
||||
<< varname << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if((!inner_explicit_index && key == "length") || force_length) {
|
||||
switch(vartype) {
|
||||
case variable_info::TYPE_ARRAY:
|
||||
case variable_info::TYPE_CONTAINER:
|
||||
WRN_NG << "variable_info: using reserved WML variable as wrong type, "
|
||||
<< varname << std::endl;
|
||||
is_valid = force_valid || temporaries.child(varname);
|
||||
break;
|
||||
case variable_info::TYPE_SCALAR:
|
||||
default:
|
||||
// Store the length of the array as a temporary variable
|
||||
temporaries[varname] = int(size);
|
||||
is_valid = true;
|
||||
break;
|
||||
}
|
||||
key = varname;
|
||||
vars = &temporaries;
|
||||
return;
|
||||
}
|
||||
|
||||
vars = &vars->child(element, inner_index);
|
||||
itor = std::find(key.begin(),key.end(),'.');
|
||||
dot_index = key.find('.');
|
||||
} // end subvar access
|
||||
|
||||
const std::string::iterator index_start = std::find(key.begin(),key.end(),'[');
|
||||
explicit_index = index_start != key.end();
|
||||
if(explicit_index) {
|
||||
const std::string::iterator index_end = std::find(index_start,key.end(),']');
|
||||
const std::string index_str(index_start+1,index_end);
|
||||
index = static_cast<size_t>(lexical_cast_default<int>(index_str));
|
||||
if(index > game_config::max_loop) {
|
||||
ERR_NG << "variable_info: index greater than " << game_config::max_loop
|
||||
<< ", truncated\n";
|
||||
index = game_config::max_loop;
|
||||
}
|
||||
key = std::string(key.begin(),index_start);
|
||||
size_t size = vars->child_count(key);
|
||||
if(size <= index) {
|
||||
if(!force_valid) {
|
||||
WRN_NG << "variable_info: invalid WML array index, " << varname << std::endl;
|
||||
return;
|
||||
}
|
||||
for(; size <= index; ++size) {
|
||||
vars->add_child(key);
|
||||
}
|
||||
}
|
||||
switch(vartype) {
|
||||
case variable_info::TYPE_ARRAY:
|
||||
vars = &vars->child(key, index);
|
||||
key = "__array";
|
||||
is_valid = force_valid || vars->child(key);
|
||||
break;
|
||||
case variable_info::TYPE_SCALAR:
|
||||
vars = &vars->child(key, index);
|
||||
key = "__value";
|
||||
is_valid = force_valid || vars->has_attribute(key);
|
||||
break;
|
||||
case variable_info::TYPE_CONTAINER:
|
||||
case variable_info::TYPE_UNSPECIFIED:
|
||||
default:
|
||||
is_valid = true;
|
||||
return;
|
||||
}
|
||||
if (force_valid) {
|
||||
WRN_NG << "variable_info: using explicitly indexed "
|
||||
"container as wrong WML type, " << varname << '\n';
|
||||
}
|
||||
explicit_index = false;
|
||||
index = 0;
|
||||
} else {
|
||||
// Final variable is not an explicit index [...]
|
||||
switch(vartype) {
|
||||
case variable_info::TYPE_ARRAY:
|
||||
case variable_info::TYPE_CONTAINER:
|
||||
is_valid = force_valid || vars->child(key);
|
||||
break;
|
||||
case variable_info::TYPE_SCALAR:
|
||||
is_valid = force_valid || vars->has_attribute(key);
|
||||
break;
|
||||
case variable_info::TYPE_UNSPECIFIED:
|
||||
default:
|
||||
is_valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config::attribute_value &variable_info::as_scalar()
|
||||
{
|
||||
assert(is_valid);
|
||||
return (*vars)[key];
|
||||
}
|
||||
|
||||
config& variable_info::as_container() {
|
||||
assert(is_valid);
|
||||
if(explicit_index) {
|
||||
// Empty data for explicit index was already created if it was needed
|
||||
return vars->child(key, index);
|
||||
}
|
||||
if (config &temp = vars->child(key)) {
|
||||
// The container exists, index not specified, return index 0
|
||||
return temp;
|
||||
}
|
||||
// Add empty data for the new variable, since it does not exist yet
|
||||
return vars->add_child(key);
|
||||
}
|
||||
|
||||
variable_info::array_range variable_info::as_array() {
|
||||
assert(is_valid);
|
||||
return vars->child_range(key);
|
||||
}
|
52
src/variable_info.hpp
Normal file
52
src/variable_info.hpp
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
Copyright (C) 2003 by David White <dave@whitevine.net>
|
||||
Copyright (C) 2005 - 2014 by Philippe Plantier <ayin@anathas.org>
|
||||
|
||||
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 as published by
|
||||
the Free Software Foundation; either version 2 of the License, 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.
|
||||
*/
|
||||
|
||||
/** Information on a WML variable. */
|
||||
|
||||
#include "config.hpp"
|
||||
#include <string>
|
||||
|
||||
struct variable_info
|
||||
{
|
||||
typedef config::child_itors array_range;
|
||||
|
||||
/**
|
||||
* TYPE: the correct variable type should be decided by the user of the info structure
|
||||
* Note: an Array can also be considered a Container, since index 0 will be used by default
|
||||
*/
|
||||
enum TYPE { TYPE_SCALAR, //a Scalar variable resolves to a t_string attribute of *vars
|
||||
TYPE_ARRAY, //an Array variable is a series of Containers
|
||||
TYPE_CONTAINER, //a Container is a specific index of an Array (contains Scalars)
|
||||
TYPE_UNSPECIFIED };
|
||||
|
||||
variable_info(config& source, const std::string& varname, bool force_valid=true,
|
||||
TYPE validation_type=TYPE_UNSPECIFIED);
|
||||
|
||||
TYPE vartype; //default is TYPE_UNSPECIFIED
|
||||
bool is_valid;
|
||||
std::string key; //the name of the internal attribute or child
|
||||
bool explicit_index; //true if query ended in [...] specifier
|
||||
size_t index; //the index of the child
|
||||
config *vars; //the containing node in game_data s variables
|
||||
/**
|
||||
* Results: after deciding the desired type, these methods can retrieve the result
|
||||
* Note: first you should force_valid or check is_valid, otherwise these may fail
|
||||
*/
|
||||
config::attribute_value &as_scalar();
|
||||
config& as_container();
|
||||
array_range as_array(); //range may be empty
|
||||
static config& get_temporaries();
|
||||
};
|
Loading…
Add table
Reference in a new issue