Deploy and refactor config::optional_child

Previously the config class had an operator bool and
it was a common pattern to use if(const config& = cfg.child(..)).
While this pattern was nice to use. It has severe drawbacks, in
particular it was unclear whether a function that took a config&
parameter allowed "invalid" configs, while most functions
did not, there were some that did. Furtheremore it lead to a few
buggy codes that were unconvered by this change (Not fixed though!),
in particular codes that tested local config objects that were
not references to being invalid, which could never be the case.
This commits replaces those with just `true` in order to not
change behaviour.

Some obvious cases were also removed including for example
things like `assert(config());` There is ony case in the ai code
that i'm not 100% sure of where one implementation of a virtual
function checked for an invalid config and another one that didn't.

With this, all code that check for a config child to be
present now uses config::optional_child which returns an object
that behaves similar to optional<(const) config&>, so it throws
on invalid dereferencing. But it also has operator[string] for
convinience, in particular to make is similary
easy to use the the previous `if (config& = .. child())`.
Also it has a tool DEBUG_CONFIG which tests whether all
optional_config values are checked before they are derefereneced.

Another method manditory_child was
added that throws when the key is not found, which replaces all
occurances of child() that did not check whether the result was
valid. This was neccecary (this= adding a new method instead of
renaming .child) to keep track of converted changes, and be sure
no occurances of child() were accidentally changed to the
throwing version.

We might want to rename one of mandatory_child or optional_child
to just child later. Not sure which one yet. I think it's better
to keep it in the current state (no config::child() ) for a while
though, so that people that currently used child() in their open
prs or other work get an error and not wrongly rely on the previous
behviour of config::child.

The interface of vconfig was not changed in this commit.
This commit is contained in:
gfgtdf 2023-03-30 16:49:41 +02:00
parent 231f9ea905
commit f8bd32eb15
150 changed files with 918 additions and 999 deletions

View file

@ -32,7 +32,7 @@ tprogress_bar_definition::tresolution::tresolution(const config& cfg) /*@ \label
* * state_enabled, the progress bar is enabled.
*/
// Note the order should be the same as the enum tstate is progress_bar.hpp.
state.push_back(tstate_definition(cfg.child("state_enabled")));
state.push_back(state_definition(cfg.optional_child("state_enabled")));
}
} // namespace gui2

View file

@ -86,7 +86,7 @@ undo_action_base * undo_list::create_action(const config & cfg)
else if ( str == "recruit" ) {
// Validate the unit type.
const config & child = cfg.child("unit");
const config & child = cfg.mandatory_child("unit");
const unit_type * u_type = unit_types.find(child["type"]);
if ( !u_type ) {
@ -102,7 +102,7 @@ undo_action_base * undo_list::create_action(const config & cfg)
res = new undo::recall_action(cfg, map_location(cfg.child_or_empty("leader"), nullptr));
else if ( str == "dismiss" )
res = new undo::dismiss_action(cfg, cfg.child("unit"));
res = new undo::dismiss_action(cfg, cfg.mandatory_child("unit"));
else if ( str == "auto_shroud" )
res = new undo::auto_shroud_action(cfg["active"].to_bool());
@ -403,8 +403,7 @@ void undo_list::redo()
auto action = std::move(redos_.back());
redos_.pop_back();
auto [commandname, data] = action->child("command").all_children_range().front();
auto [commandname, data] = action->mandatory_child("command").all_children_range().front();
// Note that this might add more than one [command]
resources::recorder->redo(*action);

View file

@ -111,8 +111,8 @@ namespace {
u2.reset(new scoped_xy_unit("unit", who->get_location(), resources::gameboard->units()));
}
scoped_weapon_info w1("weapon", e.data.child("first"));
scoped_weapon_info w2("second_weapon", e.data.child("second"));
scoped_weapon_info w1("weapon", e.data.optional_child("first"));
scoped_weapon_info w2("second_weapon", e.data.optional_child("second"));
game_events::queued_event q(tag, "", map_location(x1, y1, wml_loc()), map_location(x2, y2, wml_loc()), e.data);
resources::lua_kernel->run_wml_action("command", vconfig(e.commands), q);

View file

@ -56,7 +56,7 @@ void move_action::write(config & cfg) const
shroud_clearing_action::write(cfg);
cfg["starting_direction"] = map_location::write_direction(starting_dir);
cfg["starting_moves"] = starting_moves;
config & child = cfg.child("unit");
config & child = cfg.mandatory_child("unit");
child["goto_x"] = goto_hex.wml_x();
child["goto_y"] = goto_hex.wml_y();
}

View file

@ -60,7 +60,7 @@ void recruit_action::write(config & cfg) const
shroud_clearing_action::write(cfg);
recruit_from.write(cfg.add_child("leader"));
config & child = cfg.child("unit");
config & child = cfg.mandatory_child("unit");
child["type"] = u_type.parent_id();
}

View file

@ -88,7 +88,7 @@ void addons_client::connect()
wait_for_transfer_done(msg);
if(!update_last_error(response_buf)) {
if(const auto& info = response_buf.child("server_id")) {
if(auto info = response_buf.optional_child("server_id")) {
server_id_ = info["id"].str();
server_version_ = info["version"].str();
@ -127,7 +127,7 @@ bool addons_client::request_addons_list(config& cfg)
send_simple_request("request_campaign_list", response_buf);
wait_for_transfer_done(_("Downloading list of add-ons..."));
std::swap(cfg, response_buf.child("campaigns"));
std::swap(cfg, response_buf.mandatory_child("campaigns"));
return !update_last_error(response_buf);
}
@ -148,7 +148,7 @@ bool addons_client::request_distribution_terms(std::string& terms)
send_simple_request("request_terms", response_buf);
wait_for_transfer_done(_("Requesting distribution terms..."));
if(const config& msg_cfg = response_buf.child("message")) {
if(auto msg_cfg = response_buf.optional_child("message")) {
terms = msg_cfg["message"].str();
}
@ -224,7 +224,7 @@ bool addons_client::upload_addon(const std::string& id, std::string& response_me
wait_for_transfer_done(_("Requesting file index..."));
// A silent error check
if(!hashlist.child("error")) {
if(!hashlist.has_child("error")) {
if(!contains_hashlist(addon_data, hashlist) || !contains_hashlist(hashlist, addon_data)) {
LOG_ADDONS << "making an update pack for the add-on " << id;
config updatepack;
@ -240,7 +240,7 @@ bool addons_client::upload_addon(const std::string& id, std::string& response_me
wait_for_transfer_done(VGETTEXT("Sending an update pack for the add-on <i>$addon_title</i>...", i18n_symbols
), transfer_mode::upload);
if(const config& message_cfg = response_buf.child("message")) {
if(auto message_cfg = response_buf.optional_child("message")) {
response_message = message_cfg["message"].str();
LOG_ADDONS << "server response: " << response_message;
}
@ -261,7 +261,7 @@ bool addons_client::upload_addon(const std::string& id, std::string& response_me
wait_for_transfer_done(VGETTEXT("Sending add-on <i>$addon_title</i>...", i18n_symbols
), transfer_mode::upload);
if(const config& message_cfg = response_buf.child("message")) {
if(auto message_cfg = response_buf.optional_child("message")) {
response_message = message_cfg["message"].str();
LOG_ADDONS << "server response: " << response_message;
}
@ -309,7 +309,7 @@ bool addons_client::delete_remote_addon(const std::string& id, std::string& resp
send_request(request_buf, response_buf);
wait_for_transfer_done(VGETTEXT("Removing add-on <i>$addon_title</i> from the server...", i18n_symbols));
if(const config& message_cfg = response_buf.child("message")) {
if(auto message_cfg = response_buf.optional_child("message")) {
response_message = message_cfg["message"].str();
LOG_ADDONS << "server response: " << response_message;
}
@ -599,15 +599,15 @@ addons_client::install_result addons_client::install_addon_with_checks(const add
bool addons_client::update_last_error(config& response_cfg)
{
if(const config& error = response_cfg.child("error")) {
if(error.has_attribute("status_code")) {
if(auto error = response_cfg.optional_child("error")) {
if(error->has_attribute("status_code")) {
const auto& status_msg = translated_addon_check_status(error["status_code"].to_unsigned());
last_error_ = font::escape_text(status_msg);
} else {
last_error_ = font::escape_text(error["message"].str());
}
last_error_data_ = font::escape_text(error["extra_data"].str());
ERR_ADDONS << "server error: " << error;
ERR_ADDONS << "server error: " << *error;
return true;
} else {
last_error_.clear();

View file

@ -113,8 +113,8 @@ void get_addon_install_info(const std::string& addon_name, config& cfg)
cfg.clear();
config envelope;
read(envelope, *stream);
if(config& info = envelope.child("info")) {
cfg = std::move(info);
if(auto info = envelope.optional_child("info")) {
cfg = std::move(*info);
}
} catch(const config::error& e) {
ERR_CFG << "Failed to read add-on installation information for '"

View file

@ -57,10 +57,6 @@ bool get_addons_list(addons_client& client, addons_list& list)
config cfg;
client.request_addons_list(cfg);
if(!cfg) {
return false;
}
read_addons_list(cfg, list);
return true;

View file

@ -301,9 +301,9 @@ bool contains_hashlist(const config& from, const config& to)
}
for(const config& d : to.child_range("dir")) {
const config& origin_dir = from.find_child("dir", "name", d["name"]);
auto origin_dir = from.find_child("dir", "name", d["name"]);
if(origin_dir) {
if(!contains_hashlist(origin_dir, d)) {
if(!contains_hashlist(*origin_dir, d)) {
return false;
}
} else {
@ -343,10 +343,10 @@ static bool write_difference(config& pack, const config& from, const config& to,
}
for(const config& d : to.child_range("dir")) {
const config& origin_dir = from.find_child("dir", "name", d["name"]);
auto origin_dir = from.find_child("dir", "name", d["name"]);
config dir;
if(origin_dir) {
if(write_difference(dir, origin_dir, d, with_content)) {
if(write_difference(dir, *origin_dir, d, with_content)) {
pack.add_child("dir", dir);
has_changes = true;
}

View file

@ -250,8 +250,9 @@ public:
add_facet(-1,cfg_element);
}
config _default = this->cfg_.child("default");
if (_default) {
config _default = this->cfg_.mandatory_child("default");
// TODO: this was a faulty invalid config test.
if ((true)) {
_default["id"] = "default_facet";
std::vector< aspect_ptr > default_aspects;
engine::parse_aspect_from_config(*this,_default,parent_id_,std::back_inserter(default_aspects));

View file

@ -185,11 +185,11 @@ bool component_manager::add_component(component *root, const std::string &path,
if (c==nullptr) {
return false;
}
const config &ch = cfg.child(tail.property);
auto ch = cfg.optional_child(tail.property);
if (!ch) {
return false;
}
return c->add_child(tail, ch);
return c->add_child(tail, *ch);
}
@ -200,11 +200,11 @@ bool component_manager::change_component(component *root, const std::string &pat
if (c==nullptr) {
return false;
}
const config &ch = cfg.child(tail.property);
auto ch = cfg.optional_child(tail.property);
if (!ch) {
return false;
}
return c->change_child(tail,ch);
return c->change_child(tail, *ch);
}
bool component_manager::delete_component(component *root, const std::string &path)

View file

@ -130,11 +130,11 @@ void target_unit_goal::add_targets(std::back_insert_iterator< std::vector< targe
return;
}
const config &criteria = cfg_.child("criteria");
auto criteria = cfg_.optional_child("criteria");
if (!criteria) return;
//find the enemy leaders and explicit targets
const unit_filter ufilt{ vconfig(criteria) };
const unit_filter ufilt{ vconfig(*criteria) };
for (const unit &u : resources::gameboard->units()) {
if (ufilt( u )) {
LOG_AI_GOAL << "found explicit target unit at ... " << u.get_location() << " with value: " << value();
@ -161,9 +161,9 @@ void target_location_goal::on_create()
if (cfg_.has_attribute("value")) {
value_ = cfg_["value"].to_double(0);
}
const config &criteria = cfg_.child("criteria");
auto criteria = cfg_.optional_child("criteria");
if (criteria) {
filter_ptr_.reset(new terrain_filter(vconfig(criteria),resources::filter_con, false));
filter_ptr_.reset(new terrain_filter(vconfig(*criteria),resources::filter_con, false));
}
}
@ -210,9 +210,9 @@ void protect_goal::on_create()
if (radius_<1) {
radius_=20;
}
const config &criteria = cfg_.child("criteria");
auto criteria = cfg_.optional_child("criteria");
if (criteria) {
filter_ptr_.reset(new terrain_filter(vconfig(criteria), resources::filter_con, false));
filter_ptr_.reset(new terrain_filter(vconfig(*criteria), resources::filter_con, false));
}
}
@ -231,19 +231,19 @@ void protect_goal::add_targets(std::back_insert_iterator< std::vector< target >>
return;
}
const config &criteria = cfg_.child("criteria");
auto criteria = cfg_.optional_child("criteria");
if (!criteria) {
LOG_AI_GOAL << "skipping " << goal_type << " goal - no criteria given";
return;
} else {
DBG_AI_GOAL << "side " << get_side() << ": "<< goal_type << " goal with criteria" << std::endl << cfg_.child("criteria");
DBG_AI_GOAL << "side " << get_side() << ": "<< goal_type << " goal with criteria" << std::endl << cfg_.mandatory_child("criteria");
}
unit_map &units = resources::gameboard->units();
std::set<map_location> items;
if (protect_unit_) {
const unit_filter ufilt{ vconfig(criteria) };
const unit_filter ufilt{ vconfig(*criteria) };
for (const unit &u : units)
{
// 'protect_unit' can be set to any unit of any side -> exclude hidden units

View file

@ -40,8 +40,8 @@ candidate_action::candidate_action(rca_context &context, const config &cfg):
max_score_(cfg["max_score"].to_double(HIGH_SCORE)),
id_(cfg["id"]), name_(cfg["name"]), type_(cfg["type"]), to_be_removed_(false)
{
if (const config &filter_own = cfg.child("filter_own")) {
vconfig vcfg(filter_own);
if (auto filter_own = cfg.optional_child("filter_own")) {
vconfig vcfg(*filter_own);
vcfg.make_safe();
filter_own_.reset(new unit_filter(vcfg));
}

View file

@ -192,8 +192,8 @@ public:
static void cfg_to_value(const config &cfg, config &value)
{
if (const config &v = cfg.child("value")) {
value = v;
if (auto v = cfg.optional_child("value")) {
value = *v;
} else {
value.clear();
}
@ -223,8 +223,8 @@ public:
static terrain_filter cfg_to_value(const config &cfg)
{
if (const config &v = cfg.child("value")) {
return terrain_filter(vconfig(v), resources::filter_con, false);
if (auto v = cfg.optional_child("value")) {
return terrain_filter(vconfig(*v), resources::filter_con, false);
}
static config c("not");
return terrain_filter(vconfig(c),resources::filter_con, false);

View file

@ -48,9 +48,10 @@ void configuration::init(const game_config_view &game_config)
era_ai_configurations_.clear();
mod_ai_configurations_.clear();
const config &ais = game_config.child("ais");
default_config_ = ais.child("default_config");
if (!default_config_) {
const config &ais = game_config.mandatory_child("ais");
default_config_ = ais.mandatory_child("default_config");
// TODO: this was a faulty invalid config test.
if ((false)) {
ERR_AI_CONFIGURATION << "Missing AI [default_config]. Therefore, default_config_ set to empty.";
default_config_.clear();
}
@ -217,7 +218,8 @@ bool configuration::parse_side_config(side_number side, const config& original_c
DBG_AI_CONFIGURATION << "side " << side << ": config contains:"<< std::endl << cfg;
//insert default config at the beginning
if (default_config_) {
// TODO: this was a faulty invalid config test.
if ((true)) {
DBG_AI_CONFIGURATION << "side "<< side <<": applying default configuration";
cfg.add_child_at("ai",default_config_,0);
} else {
@ -246,12 +248,12 @@ bool configuration::parse_side_config(side_number side, const config& original_c
// No point in warning about Lua or standard aspects lacking [default]
continue;
}
if (!aspect_cfg.child("default")) {
if (!aspect_cfg.has_child("default")) {
WRN_AI_CONFIGURATION << "side "<< side <<": aspect with id=["<<aspect_cfg["id"]<<"] lacks default config facet!";
continue;
}
aspect_cfg.merge_children("default");
config& dflt = aspect_cfg.child("default");
config& dflt = aspect_cfg.mandatory_child("default");
if (dflt.has_child("value")) {
while (dflt.child_count("value") > 1) {
dflt.remove_child("value", 0);

View file

@ -53,14 +53,14 @@ aspect_attacks::aspect_attacks(readonly_context& context, const config& cfg, con
, filter_own_()
, filter_enemy_()
{
if(const config& filter_own = cfg.child("filter_own")) {
vconfig vcfg(filter_own);
if(auto filter_own = cfg.optional_child("filter_own")) {
vconfig vcfg(*filter_own);
vcfg.make_safe();
filter_own_.reset(new unit_filter(vcfg));
}
if(const config& filter_enemy = cfg.child("filter_enemy")) {
vconfig vcfg(filter_enemy);
if(auto filter_enemy = cfg.optional_child("filter_enemy")) {
vconfig vcfg(*filter_enemy);
vcfg.make_safe();
filter_enemy_.reset(new unit_filter(vcfg));
}

View file

@ -277,9 +277,10 @@ move_leader_to_goals_phase::~move_leader_to_goals_phase()
double move_leader_to_goals_phase::evaluate()
{
const config &goal = get_leader_goal();
config goal = get_leader_goal();
//passive leader can reach a goal
if (!goal) {
// TODO: this was a faulty invalid config test.
if ((false)) {
LOG_AI_TESTING_AI_DEFAULT << get_name() << "No goal found";
return BAD_SCORE;
}

View file

@ -1817,7 +1817,7 @@ void recruitment::recruit_situation_change_observer::reset_gamestate_changed() {
recruitment_aspect::recruitment_aspect(readonly_context &context, const config &cfg, const std::string &id)
: standard_aspect<config>(context, cfg, id)
{
config parsed_cfg(cfg.has_child("value") ? cfg.child("value") : cfg);
config parsed_cfg(cfg.has_child("value") ? cfg.mandatory_child("value") : cfg);
// First, transform simplified tags into [recruit] tags.
for (config pattern : parsed_cfg.child_range("pattern")) {
parsed_cfg["pattern"] = true;

View file

@ -755,10 +755,6 @@ bool formula_ai::gamestate_change_observer::continue_check() {
config formula_ai::to_config() const
{
if (!cfg_)
{
return config();
}
DBG_AI << "formula_ai::to_config(): "<< cfg_;
config cfg = cfg_;

View file

@ -62,10 +62,10 @@ candidate_action_with_filters::candidate_action_with_filters(
: base_candidate_action(name, type, cfg, function_table)
, filter_map_()
{
const config & filter_params = cfg.child("filter");
auto filter_params = cfg.optional_child("filter");
if( filter_params ) {
for(const config::attribute& filter_param : filter_params.attribute_range())
for(const config::attribute& filter_param : filter_params->attribute_range())
{
const_formula_ptr filter_formula(
new formula(filter_param.second, function_table));

View file

@ -91,9 +91,7 @@ void engine_fai::do_parse_candidate_action_from_config( rca_context &context, co
void engine_fai::do_parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr >> b )
{
if (!cfg) {
return;
}
// This checekd for !cfg but oter implementation of do_parse_stage_from_config didn't.
const std::string &name = cfg["name"];
stage_ptr st_ptr;

View file

@ -303,11 +303,8 @@ void engine_lua::push_ai_table()
}
}
void engine_lua::do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b ){
if (!cfg) {
return;
}
void engine_lua::do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b )
{
if (!lua_ai_context_) {
return;
}
@ -333,10 +330,6 @@ void engine_lua::do_parse_candidate_action_from_config( rca_context &context, co
void engine_lua::do_parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
{
if (!cfg) {
return;
}
if (!lua_ai_context_) {
return;
}

View file

@ -71,62 +71,10 @@ int map_erase_key(Map& map, Key&& key)
}
struct config_implementation
{
/**
* Implementation for the wrappers for
* [const] config& child(const std::string& key, const std::string& parent);
*
* @tparam T A pointer to the config.
*/
template<class T>
static utils::const_clone_ref<config, T> child(T config, config_key_type key, const std::string& parent)
{
config->check_valid();
assert(!parent.empty());
assert(parent.front() == '[');
assert(parent.back() == ']');
if(config->has_child(key)) {
return *(config->children_.find(key)->second.front());
}
/**
* @todo Implement a proper wml_exception here.
*
* at the moment there seem to be dependency issues, which i don't want
* to fix right now.
*/
// FAIL(missing_mandatory_wml_section(parent, key));
std::stringstream sstr;
sstr << "Mandatory WML child »[" << key << "]« missing in »" << parent << "«. Please report this bug.";
throw config::error(sstr.str());
}
};
/* ** config implementation ** */
config config::invalid;
const char* config::diff_track_attribute = "__diff_track";
void config::check_valid() const
{
if(!*this) {
throw error("Mandatory WML child missing yet untested for. Please report.");
}
}
void config::check_valid(const config& cfg) const
{
if(!*this || !cfg) {
throw error("Mandatory WML child missing yet untested for. Please report.");
}
}
config::config()
: values_()
, children_()
@ -210,20 +158,16 @@ bool config::valid_attribute(config_key_type name)
bool config::has_attribute(config_key_type key) const
{
check_valid();
return values_.find(key) != values_.end();
}
void config::remove_attribute(config_key_type key)
{
check_valid();
map_erase_key(values_, key);
}
void config::append_children(const config& cfg)
{
check_valid(cfg);
for(const any_child value : cfg.all_children_range()) {
add_child(value.key, value.cfg);
}
@ -231,8 +175,6 @@ void config::append_children(const config& cfg)
void config::append_children(config&& cfg)
{
check_valid(cfg);
#if 0
//For some unknown reason this doesn't compile.
if(children_.empty()) {
@ -251,7 +193,6 @@ void config::append_children(config&& cfg)
void config::append_attributes(const config& cfg)
{
check_valid(cfg);
for(const attribute& v : cfg.values_) {
values_[v.first] = v.second;
}
@ -259,8 +200,6 @@ void config::append_attributes(const config& cfg)
void config::append_children(const config& cfg, const std::string& key)
{
check_valid(cfg);
for(const config& value : cfg.child_range(key)) {
add_child(key, value);
}
@ -293,8 +232,6 @@ void config::append(config&& cfg)
void config::append_children_by_move(config& cfg, const std::string& key)
{
check_valid(cfg);
// DO note this leaves the tags empty in the source config. Not sure if
// that should be changed.
for(config& value : cfg.child_range(key)) {
@ -306,8 +243,6 @@ void config::append_children_by_move(config& cfg, const std::string& key)
void config::merge_children(const std::string& key)
{
check_valid();
if(child_count(key) < 2) {
return;
}
@ -323,8 +258,6 @@ void config::merge_children(const std::string& key)
void config::merge_children_by_attribute(const std::string& key, const std::string& attribute)
{
check_valid();
if(child_count(key) < 2) {
return;
}
@ -343,8 +276,6 @@ void config::merge_children_by_attribute(const std::string& key, const std::stri
config::child_itors config::child_range(config_key_type key)
{
check_valid();
child_map::iterator i = children_.find(key);
static child_list dummy;
child_list* p = &dummy;
@ -357,8 +288,6 @@ config::child_itors config::child_range(config_key_type key)
config::const_child_itors config::child_range(config_key_type key) const
{
check_valid();
child_map::const_iterator i = children_.find(key);
static child_list dummy;
const child_list* p = &dummy;
@ -371,8 +300,6 @@ config::const_child_itors config::child_range(config_key_type key) const
unsigned config::child_count(config_key_type key) const
{
check_valid();
child_map::const_iterator i = children_.find(key);
if(i != children_.end()) {
return i->second.size();
@ -393,25 +320,19 @@ unsigned config::attribute_count() const
bool config::has_child(config_key_type key) const
{
check_valid();
child_map::const_iterator i = children_.find(key);
return i != children_.end() && !i->second.empty();
}
config& config::child(config_key_type key, int n)
namespace {
template<class Tchildren>
auto get_child_impl(Tchildren& children, config_key_type key, int n) -> optional_config_impl<std::remove_reference_t<decltype(**(*children.begin()).second.begin())>>
{
check_valid();
const child_map::const_iterator i = children_.find(key);
if(i == children_.end()) {
auto i = children.find(key);
if(i == children.end()) {
DBG_CF << "The config object has no child named »" << key << "«.";
if(throw_when_child_not_found::do_throw()) {
throw error("Child not found");
} else {
return invalid;
}
return std::nullopt;
}
if(n < 0) {
@ -423,50 +344,61 @@ config& config::child(config_key_type key, int n)
} catch(const std::out_of_range&) {
DBG_CF << "The config object has only »" << i->second.size() << "« children named »" << key
<< "«; request for the index »" << n << "« cannot be honored.";
if(throw_when_child_not_found::do_throw()) {
throw error("Child at index not found");
} else {
return invalid;
}
}
}
config& config::child(config_key_type key, const std::string& parent)
{
return config_implementation::child(this, key, parent);
}
const config& config::child(config_key_type key, const std::string& parent) const
{
return config_implementation::child(this, key, parent);
}
utils::optional_reference<config> config::optional_child(config_key_type key, int n)
{
try {
throw_when_child_not_found raii_helper{};
return child(key, n);
} catch(const error&) {
return std::nullopt;
}
}
utils::optional_reference<const config> config::optional_child(config_key_type key, int n) const
}
config& config::mandatory_child(config_key_type key, const std::string& parent)
{
try {
throw_when_child_not_found raii_helper{};
return child(key, n);
} catch(const error&) {
return std::nullopt;
if(auto res = get_child_impl(children_, key, 0)) {
return *res;
} else {
throw error("Mandatory WML child »[" + std::string(key) + "]« missing in »" + parent + "«. Please report this bug.");
}
}
const config& config::mandatory_child(config_key_type key, const std::string& parent) const
{
if(auto res = get_child_impl(children_, key, 0)) {
return *res;
} else {
throw error("Mandatory WML child »[" + std::string(key) + "]« missing in »" + parent + "«. Please report this bug.");
}
}
config& config::mandatory_child(config_key_type key, int n)
{
if(auto res = get_child_impl(children_, key, n)) {
return *res;
} else {
throw error("Child [" + std::string(key) + "] at index " + std::to_string(n) + " not found");
}
}
const config& config::mandatory_child(config_key_type key, int n) const
{
if(auto res = get_child_impl(children_, key, n)) {
return *res;
} else {
throw error("Child [" + std::string(key) + "] at index " + std::to_string(n) + " not found");
}
}
optional_config config::optional_child(config_key_type key, int n)
{
return get_child_impl(children_, key, n);
}
optional_const_config config::optional_child(config_key_type key, int n) const
{
return get_child_impl(children_, key, n);
}
const config& config::child_or_empty(config_key_type key) const
{
static const config empty_cfg;
check_valid();
child_map::const_iterator i = children_.find(key);
if(i != children_.end() && !i->second.empty()) {
return *i->second.front();
@ -485,20 +417,19 @@ config& config::child_or_add(config_key_type key)
return add_child(key);
}
utils::optional_reference<const config> config::get_deprecated_child(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const {
check_valid();
if(auto i = children_.find(old_key); i != children_.end() && !i->second.empty()) {
optional_config_impl<const config> config::get_deprecated_child(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const
{
if(auto res = optional_child(old_key)) {
const std::string what = formatter() << "[" << in_tag << "][" << old_key << "]";
deprecated_message(what, level, "", message);
return *i->second.front();
return res;
}
return std::nullopt;
}
config::const_child_itors config::get_deprecated_child_range(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const {
check_valid();
config::const_child_itors config::get_deprecated_child_range(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const
{
static child_list dummy;
const child_list* p = &dummy;
@ -513,8 +444,6 @@ config::const_child_itors config::get_deprecated_child_range(config_key_type old
config& config::add_child(config_key_type key)
{
check_valid();
child_list& v = map_get(children_, key);
v.emplace_back(new config());
ordered_children.emplace_back(children_.find(key), v.size() - 1);
@ -523,8 +452,6 @@ config& config::add_child(config_key_type key)
config& config::add_child(config_key_type key, const config& val)
{
check_valid(val);
child_list& v = map_get(children_, key);
v.emplace_back(new config(val));
ordered_children.emplace_back(children_.find(key), v.size() - 1);
@ -534,8 +461,6 @@ config& config::add_child(config_key_type key, const config& val)
config& config::add_child(config_key_type key, config&& val)
{
check_valid(val);
child_list& v = map_get(children_, key);
v.emplace_back(new config(std::move(val)));
ordered_children.emplace_back(children_.find(key), v.size() - 1);
@ -545,8 +470,6 @@ config& config::add_child(config_key_type key, config&& val)
config& config::add_child_at(config_key_type key, const config& val, unsigned index)
{
check_valid(val);
child_list& v = map_get(children_, key);
if(index > v.size()) {
throw error("illegal index to add child at");
@ -648,8 +571,6 @@ private:
void config::clear_children_impl(config_key_type key)
{
check_valid();
child_map::iterator i = children_.find(key);
if(i == children_.end())
return;
@ -663,8 +584,6 @@ void config::clear_children_impl(config_key_type key)
void config::splice_children(config& src, const std::string& key)
{
check_valid(src);
child_map::iterator i_src = src.children_.find(key);
if(i_src == src.children_.end()) {
return;
@ -689,8 +608,6 @@ void config::splice_children(config& src, const std::string& key)
void config::recursive_clear_value(config_key_type key)
{
check_valid();
map_erase_key(values_, key);
for(std::pair<const std::string, child_list>& p : children_) {
@ -731,8 +648,6 @@ config::all_children_iterator config::erase(const config::all_children_iterator&
void config::remove_child(config_key_type key, unsigned index)
{
check_valid();
child_map::iterator i = children_.find(key);
if(i == children_.end() || index >= i->second.size()) {
ERR_CF << "Error: attempting to delete non-existing child: " << key << "[" << index << "]";
@ -744,8 +659,6 @@ void config::remove_child(config_key_type key, unsigned index)
void config::remove_children(config_key_type key, std::function<bool(const config&)> p)
{
check_valid();
child_map::iterator pos = children_.find(key);
if(pos == children_.end()) {
return;
@ -766,8 +679,6 @@ void config::remove_children(config_key_type key, std::function<bool(const confi
const config::attribute_value& config::operator[](config_key_type key) const
{
check_valid();
const attribute_map::const_iterator i = values_.find(key);
if(i != values_.end()) {
return i->second;
@ -779,15 +690,12 @@ const config::attribute_value& config::operator[](config_key_type key) const
const config::attribute_value* config::get(config_key_type key) const
{
check_valid();
attribute_map::const_iterator i = values_.find(key);
return i != values_.end() ? &i->second : nullptr;
}
config::attribute_value& config::operator[](config_key_type key)
{
check_valid();
auto res = values_.lower_bound(key);
if(res == values_.end() || key != res->first) {
@ -799,8 +707,6 @@ config::attribute_value& config::operator[](config_key_type key)
const config::attribute_value& config::get_old_attribute(config_key_type key, const std::string& old_key, const std::string& in_tag, const std::string& message) const
{
check_valid();
if(has_attribute(old_key)) {
const std::string what = formatter() << "[" << in_tag << "]" << old_key << "=";
const std::string msg = formatter() << "Use " << key << "= instead. " << message;
@ -821,9 +727,8 @@ const config::attribute_value& config::get_old_attribute(config_key_type key, co
return empty_attribute;
}
const config::attribute_value& config::get_deprecated_attribute(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const {
check_valid();
const config::attribute_value& config::get_deprecated_attribute(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const
{
if(auto i = values_.find(old_key); i != values_.end()) {
const std::string what = formatter() << "[" << in_tag << "]" << old_key << "=";
deprecated_message(what, level, "", message);
@ -836,8 +741,6 @@ const config::attribute_value& config::get_deprecated_attribute(config_key_type
void config::merge_attributes(const config& cfg)
{
check_valid(cfg);
assert(this != &cfg);
for(const attribute& v : cfg.values_) {
std::string key = v.first;
@ -857,8 +760,6 @@ void config::merge_attributes(const config& cfg)
config::const_attr_itors config::attribute_range() const
{
check_valid();
const_attr_itors range(const_attribute_iterator(values_.begin()), const_attribute_iterator(values_.end()));
// Ensure the first element is not blank, as a few places assume this
@ -871,7 +772,6 @@ config::const_attr_itors config::attribute_range() const
config::attr_itors config::attribute_range()
{
check_valid();
attr_itors range(attribute_iterator(values_.begin()), attribute_iterator(values_.end()));
// Ensure the first element is not blank, as a few places assume this
@ -882,19 +782,14 @@ config::attr_itors config::attribute_range()
return range;
}
config& config::find_child(config_key_type key, const std::string& name, const std::string& value)
optional_config config::find_child(config_key_type key, const std::string& name, const std::string& value)
{
check_valid();
const child_map::iterator i = children_.find(key);
if(i == children_.end()) {
DBG_CF << "Key »" << name << "« value »" << value << "« pair not found as child of key »" << key << "«.";
if(throw_when_child_not_found::do_throw()) {
throw error("Child not found");
} else {
return invalid;
}
return std::nullopt;
}
const child_list::iterator j = std::find_if(i->second.begin(), i->second.end(),
@ -910,11 +805,7 @@ config& config::find_child(config_key_type key, const std::string& name, const s
DBG_CF << "Key »" << name << "« value »" << value << "« pair not found as child of key »" << key << "«.";
if(throw_when_child_not_found::do_throw()) {
throw error("Child not found");
} else {
return invalid;
}
return std::nullopt;
}
void config::clear()
@ -940,8 +831,6 @@ void config::clear_attributes()
bool config::empty() const
{
check_valid();
return children_.empty() && values_.empty();
}
@ -1003,8 +892,6 @@ config::all_children_itors config::all_children_range()
config config::get_diff(const config& c) const
{
check_valid(c);
config res;
get_diff(c, res);
return res;
@ -1012,9 +899,6 @@ config config::get_diff(const config& c) const
void config::get_diff(const config& c, config& res) const
{
check_valid(c);
check_valid(res);
config* inserts = nullptr;
for(const auto& v : values_) {
@ -1124,8 +1008,6 @@ void config::get_diff(const config& c, config& res) const
void config::apply_diff(const config& diff, bool track /* = false */)
{
check_valid(diff);
if(track) {
values_[diff_track_attribute] = "modified";
}
@ -1223,8 +1105,6 @@ void config::clear_diff_track(const config& diff)
*/
void config::merge_with(const config& c)
{
check_valid(c);
std::vector<child_pos> to_remove;
std::map<std::string, unsigned> visitations;
@ -1288,7 +1168,6 @@ void config::inherit_from(const config& c)
*/
void config::inherit_attributes(const config& cfg)
{
check_valid(cfg);
for(const attribute& v : cfg.values_) {
attribute_value& v2 = values_[v.first];
if(v2.blank()) {
@ -1298,8 +1177,6 @@ void config::inherit_attributes(const config& cfg)
}
bool config::matches(const config& filter) const
{
check_valid(filter);
bool result = true;
for(const attribute& i : filter.attribute_range()) {
@ -1346,8 +1223,6 @@ bool config::matches(const config& filter) const
std::string config::debug() const
{
check_valid();
std::ostringstream outstream;
outstream << *this;
return outstream.str();
@ -1391,8 +1266,6 @@ std::ostream& operator<<(std::ostream& outstream, const config& cfg)
std::string config::hash() const
{
check_valid();
static const unsigned int hash_length = 128;
static const char hash_string[] = "+-,.<>0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
char hash_str[hash_length + 1];
@ -1446,8 +1319,6 @@ std::string config::hash() const
void config::swap(config& cfg)
{
check_valid(cfg);
values_.swap(cfg.values_);
children_.swap(cfg.children_);
ordered_children.swap(cfg.ordered_children);
@ -1474,8 +1345,6 @@ bool config::validate_wml() const
bool operator==(const config& a, const config& b)
{
a.check_valid(b);
if(a.values_ != b.values_) {
return false;
}

View file

@ -30,6 +30,7 @@
#include "config_attribute_value.hpp"
#include "exceptions.hpp"
#include "utils/const_clone.hpp"
#include "utils/optional_reference.hpp"
#include <climits>
@ -52,6 +53,105 @@ enum class DEP_LEVEL : uint8_t;
class config;
template<class T>
class optional_config_impl
{
public:
optional_config_impl() = default;
optional_config_impl(T& ref)
: opt_(&ref)
{
}
optional_config_impl(std::nullopt_t)
: opt_()
{
}
T& value() const
{
if(opt_) {
return *opt_;
} else {
// We're going to drop this codepath once we can use optional::value anyway, but just
// noting we want this function to ultimately throw std::bad_optional_access.
throw std::runtime_error("Optional reference has no value");
}
}
optional_config_impl<T>& operator=(T& new_ref)
{
opt_ = &new_ref;
return *this;
}
bool has_value() const
{
#ifdef DEBUG_CONFIG
tested_ = true;
#endif
return opt_ != nullptr;
}
explicit operator bool() const
{
return has_value();
}
operator optional_config_impl<const T>() const
{
return opt_ ? optional_config_impl<const T>(*opt_) : optional_config_impl<const T>();
}
/** Returns a pointer to the referenced object or nullptr if no reference is held. */
T* ptr() const
{
if(opt_) {
return &value();
} else {
return nullptr;
}
}
T* operator->() const
{
assert(tested());
return &value();
}
T& operator*() const
{
assert(tested());
return value();
}
utils::const_clone_t<config_attribute_value, T>& operator[](config_key_type key)
{
assert(tested());
return value()[key];
}
operator utils::optional_reference<T>() const
{
return has_value() ? utils::optional_reference<T>(value()) : utils::optional_reference<T>();
}
bool tested() const
{
#ifdef DEBUG_CONFIG
return tested_;
#else
return true;
#endif
}
private:
T* opt_;
#ifdef DEBUG_CONFIG
mutable bool tested_;
#endif
};
bool operator==(const config &, const config &);
inline bool operator!=(const config &a, const config &b) { return !operator==(a, b); }
std::ostream &operator << (std::ostream &, const config &);
@ -60,20 +160,6 @@ std::ostream &operator << (std::ostream &, const config &);
class config
{
friend bool operator==(const config& a, const config& b);
friend struct config_implementation;
static config invalid;
/**
* Raises an exception if @a this is not valid.
*/
void check_valid() const;
/**
* Raises an exception if @a this or @a cfg is not valid.
*/
void check_valid(const config &cfg) const;
public:
// Create an empty node.
config();
@ -105,12 +191,6 @@ public:
// Verifies that the string can be used as an attribute name
static bool valid_attribute(config_key_type name);
explicit operator bool() const
{ return this != &invalid; }
static config& get_invalid()
{ return invalid; }
typedef std::vector<std::unique_ptr<config>> child_list;
typedef std::map<std::string, child_list, std::less<>> child_map;
@ -302,60 +382,27 @@ public:
*/
const config & child_or_empty(config_key_type key) const;
/**
* An object of this type will cause the following functions to throw a config::error instead
* of returning a reference to the invalid config for the duration of its lfetime. If multiple
* instances exist simultaneously, this behavior will persist until all objects are destroyed.
*
* - @c child
* - @c find_child
*/
class throw_when_child_not_found
{
public:
friend class config;
throw_when_child_not_found()
{
instances++;
}
~throw_when_child_not_found()
{
instances--;
}
static bool do_throw()
{
return instances > 0;
}
private:
static inline unsigned instances = 0;
};
/**
* Returns the nth child with the given @a key, or
* a reference to an invalid config if there is none.
* throws an error if there is none.
* @note A negative @a n accesses from the end of the object.
* For instance, -1 is the index of the last child.
*/
config& child(config_key_type key, int n = 0);
config& mandatory_child(config_key_type key, int n = 0);
/**
* Returns the nth child with the given @a key, or
* a reference to an invalid config if there is none.
* throws an error if there is none.
* @note A negative @a n accesses from the end of the object.
* For instance, -1 is the index of the last child.
*/
const config& child(config_key_type key, int n = 0) const
{ return const_cast<config*>(this)->child(key, n); }
const config& mandatory_child(config_key_type key, int n = 0) const;
/** Euivalent to @ref child, but returns an empty optional if the nth child was not found. */
utils::optional_reference<config> optional_child(config_key_type key, int n = 0);
/** Euivalent to @ref mandatory_child, but returns an empty optional if the nth child was not found. */
optional_config_impl<config> optional_child(config_key_type key, int n = 0);
/** Euivalent to @ref child, but returns an empty optional if the nth child was not found. */
utils::optional_reference<const config> optional_child(config_key_type key, int n = 0) const;
/** Euivalent to @ref mandatory_child, but returns an empty optional if the nth child was not found. */
optional_config_impl<const config> optional_child(config_key_type key, int n = 0) const;
/**
* Returns a mandatory child node.
@ -371,7 +418,7 @@ public:
*
* @returns The wanted child node.
*/
config& child(config_key_type key, const std::string& parent);
config& mandatory_child(config_key_type key, const std::string& parent);
/**
* Returns a mandatory child node.
@ -387,7 +434,7 @@ public:
*
* @returns The wanted child node.
*/
const config& child(config_key_type key, const std::string& parent) const;
const config& mandatory_child(config_key_type key, const std::string& parent) const;
/**
* Get a deprecated child and log a deprecation message
@ -397,7 +444,7 @@ public:
* @param message An explanation of the deprecation, possibly mentioning an alternative
* @note The deprecation message will be a level 3 deprecation.
*/
utils::optional_reference<const config> get_deprecated_child(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const;
optional_config_impl<const config> get_deprecated_child(config_key_type old_key, const std::string& in_tag, DEP_LEVEL level, const std::string& message) const;
/**
* Get a deprecated child rangw and log a deprecation message
@ -569,10 +616,10 @@ public:
* Returns the first child of tag @a key with a @a name attribute
* containing @a value.
*/
config& find_child(config_key_type key, const std::string &name,
optional_config_impl<config> find_child(config_key_type key, const std::string &name,
const std::string &value);
const config& find_child(config_key_type key, const std::string &name,
optional_config_impl<const config> find_child(config_key_type key, const std::string &name,
const std::string &value) const
{ return const_cast<config *>(this)->find_child(key, name, value); }
@ -870,6 +917,9 @@ private:
std::vector<child_pos> ordered_children;
};
using optional_config = optional_config_impl<config>;
using optional_const_config = optional_config_impl<const config>;
/** Implement non-member swap function for std::swap (calls @ref config::swap). */
void swap(config& lhs, config& rhs);

View file

@ -144,8 +144,8 @@ inline std::string pretty_path(const std::string& path)
inline config get_bookmarks_config()
{
const config& cfg = preferences::get_child("dir_bookmarks");
return cfg ? cfg : config{};
auto cfg = preferences::get_child("dir_bookmarks");
return cfg ? *cfg : config{};
}
inline void commit_bookmarks_config(config& cfg)

View file

@ -2924,13 +2924,13 @@ void display::refresh_report(const std::string& report_name, const config * new_
if (!str.empty()) {
config &e = report.add_child_at("element", config(), 0);
e["text"] = str;
e["tooltip"] = report.child("element")["tooltip"];
e["tooltip"] = report.mandatory_child("element")["tooltip"];
}
str = item->postfix();
if (!str.empty()) {
config &e = report.add_child("element");
e["text"] = str;
e["tooltip"] = report.child("element", -1)["tooltip"];
e["tooltip"] = report.mandatory_child("element", -1)["tooltip"];
}
// Do a fake run of drawing the report, so tooltips can be determined.

View file

@ -953,27 +953,27 @@ void context_manager::revert_map()
void context_manager::new_map(int width, int height, const t_translation::terrain_code& fill, bool new_context)
{
const config& default_schedule = game_config_.find_child("editor_times", "id", "empty");
auto default_schedule = game_config_.find_child("editor_times", "id", "empty");
editor_map m(width, height, fill);
if(new_context) {
int new_id = add_map_context(m, true, default_schedule);
int new_id = add_map_context(m, true, *default_schedule);
switch_context(new_id);
} else {
replace_map_context(m, true, default_schedule);
replace_map_context(m, true, *default_schedule);
}
}
void context_manager::new_scenario(int width, int height, const t_translation::terrain_code& fill, bool new_context)
{
const config& default_schedule = game_config_.find_child("editor_times", "id", "empty");
auto default_schedule = game_config_.find_child("editor_times", "id", "empty");
editor_map m(width, height, fill);
if(new_context) {
int new_id = add_map_context(m, false, default_schedule);
int new_id = add_map_context(m, false, *default_schedule);
switch_context(new_id);
} else {
replace_map_context(m, false, default_schedule);
replace_map_context(m, false, *default_schedule);
}
// Give the new scenario an initial side.
@ -1019,8 +1019,8 @@ void context_manager::create_default_context()
t_translation::terrain_code default_terrain =
t_translation::read_terrain_code(game_config::default_terrain);
const config& default_schedule = game_config_.find_child("editor_times", "id", "empty");
add_map_context(editor_map(44, 33, default_terrain), true, default_schedule);
auto default_schedule = game_config_.find_child("editor_times", "id", "empty");
add_map_context(editor_map(44, 33, default_terrain), true, *default_schedule);
} else {
for(const std::string& filename : saved_windows_) {
add_map_context(game_config_, filename);

View file

@ -112,7 +112,7 @@ map_context::map_context(const game_config_view& game_config, const std::string&
, labels_(nullptr)
, units_()
, teams_()
, tod_manager_(new tod_manager(game_config.find_child("editor_times", "id", "empty")))
, tod_manager_(new tod_manager(*game_config.find_child("editor_times", "id", "empty")))
, mp_settings_()
, game_classification_()
, music_tracks_()

View file

@ -103,7 +103,7 @@ bool load_font_config()
return false;
}
const config &fonts_config = cfg.child("fonts");
auto fonts_config = cfg.optional_child("fonts");
if (!fonts_config)
return false;

View file

@ -970,12 +970,12 @@ variant event_callable::get_value(const std::string &key) const
}
} else if(key == "weapon") {
if(event_info.data.has_child("first")) {
first_weapon = std::make_shared<attack_type>(event_info.data.child("first"));
first_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("first"));
return variant(std::make_shared<attack_type_callable>(*first_weapon));
}
} else if(key == "second_weapon") {
if(event_info.data.has_child("second")) {
second_weapon = std::make_shared<attack_type>(event_info.data.child("second"));
second_weapon = std::make_shared<attack_type>(event_info.data.mandatory_child("second"));
return variant(std::make_shared<attack_type_callable>(*second_weapon));
}
}

View file

@ -142,11 +142,11 @@ std::set<std::string> game_classification::active_addons(const std::string& scen
continue;
}
}
if(const config& cfg = game_config_manager::get()->game_config().find_child(current.type, "id", current.id)) {
if(auto cfg = game_config_manager::get()->game_config().find_child(current.type, "id", current.id)) {
if(!cfg["addon_id"].empty()) {
res.insert(cfg["addon_id"]);
}
for (const config& load_res : cfg.child_range("load_resource")) {
for (const config& load_res : cfg->child_range("load_resource")) {
mods.emplace_back("resource", load_res["id"].str());
}
} else {

View file

@ -306,7 +306,7 @@ void load_config(const config &v)
default_victory_music = utils::split(v["default_victory_music"].str());
default_defeat_music = utils::split(v["default_defeat_music"].str());
if(const config& i = v.child("colors")){
if(auto i = v.optional_child("colors")){
using namespace game_config::colors;
moved_orb_color = i["moved_orb_color"].str();
@ -324,7 +324,7 @@ void load_config(const config &v)
show_unmoved_orb = v["show_unmoved_orb"].to_bool(true);
show_disengaged_orb = v["show_disengaged_orb"].to_bool(true);
if(const config& i = v.child("images")){
if(auto i = v.optional_child("images")){
using namespace game_config::images;
game_title = i["game_title"].str();
@ -416,7 +416,7 @@ void load_config(const config &v)
server_list.push_back(sinf);
}
if(const config& s = v.child("sounds")) {
if(auto s = v.optional_child("sounds")) {
using namespace game_config::sounds;
const auto load_attribute = [](const config& c, const std::string& key, std::string& member) {
@ -425,26 +425,26 @@ void load_config(const config &v)
}
};
load_attribute(s, "turn_bell", turn_bell);
load_attribute(s, "timer_bell", timer_bell);
load_attribute(s, "public_message", public_message);
load_attribute(s, "private_message", private_message);
load_attribute(s, "friend_message", friend_message);
load_attribute(s, "server_message", server_message);
load_attribute(s, "player_joins", player_joins);
load_attribute(s, "player_leaves", player_leaves);
load_attribute(s, "game_created", game_created);
load_attribute(s, "game_user_arrive", game_user_arrive);
load_attribute(s, "game_user_leave", game_user_leave);
load_attribute(s, "ready_for_start", ready_for_start);
load_attribute(s, "game_has_begun", game_has_begun);
load_attribute(*s, "turn_bell", turn_bell);
load_attribute(*s, "timer_bell", timer_bell);
load_attribute(*s, "public_message", public_message);
load_attribute(*s, "private_message", private_message);
load_attribute(*s, "friend_message", friend_message);
load_attribute(*s, "server_message", server_message);
load_attribute(*s, "player_joins", player_joins);
load_attribute(*s, "player_leaves", player_leaves);
load_attribute(*s, "game_created", game_created);
load_attribute(*s, "game_user_arrive", game_user_arrive);
load_attribute(*s, "game_user_leave", game_user_leave);
load_attribute(*s, "ready_for_start", ready_for_start);
load_attribute(*s, "game_has_begun", game_has_begun);
if(const config & ss = s.child("status")) {
if(auto ss = s->optional_child("status")) {
using namespace game_config::sounds::status;
load_attribute(ss, "poisoned", poisoned);
load_attribute(ss, "slowed", slowed);
load_attribute(ss, "petrified", petrified);
load_attribute(*ss, "poisoned", poisoned);
load_attribute(*ss, "slowed", slowed);
load_attribute(*ss, "petrified", petrified);
}
}
}

View file

@ -114,7 +114,7 @@ bool game_config_manager::init_game_config(FORCE_RELOAD_CONFIG force_reload)
load_game_config_with_loadscreen(force_reload, nullptr, "");
game_config::load_config(game_config().child("game_config"));
game_config::load_config(game_config().mandatory_child("game_config"));
// It's necessary to block the event thread while load_hotkeys() runs, otherwise keyboard input
// can cause a crash by accessing the list of hotkeys while it's being modified.
@ -250,7 +250,7 @@ void game_config_manager::load_game_config(bool reload_everything, const game_cl
continue;
}
if(*&valid_cores.find_child("core", "id", id)) {
if(valid_cores.find_child("core", "id", id)) {
events::call_in_main_thread([&]() {
gui2::dialogs::wml_error::display(
_("Error validating data core."),

View file

@ -49,27 +49,35 @@ config_array_view game_config_view::child_range(config_key_type key) const
return res;
}
const config& game_config_view::find_child(config_key_type key, const std::string &name, const std::string &value) const
optional_const_config game_config_view::find_child(config_key_type key, const std::string &name, const std::string &value) const
{
for(const config& cfg : cfgs_) {
if(const config& res = cfg.find_child(key, name, value)) {
if(optional_const_config res = cfg.find_child(key, name, value)) {
return res;
}
}
LOG_CONFIG << "gcv : cannot find [" << key << "] with " << name << "=" << value << ", count = " << cfgs_.size();
const config cfg;
return cfg.child("invalid");
return optional_const_config();
}
const config& game_config_view::child(config_key_type key) const
const config& game_config_view::mandatory_child(config_key_type key) const
{
for(const config& cfg : cfgs_) {
if(const auto res = cfg.optional_child(key)) {
return res.value();
}
}
const config cfg;
return cfg.child("invalid");
throw config::error("missing WML tag [" + std::string(key) + "]");
}
optional_const_config game_config_view::optional_child(config_key_type key) const
{
for(const config& cfg : cfgs_) {
if(const auto res = cfg.optional_child(key)) {
return res.value();
}
}
return optional_const_config();
}

View file

@ -36,9 +36,11 @@ public:
config_array_view child_range(config_key_type key) const;
const config& find_child(config_key_type key, const std::string &name, const std::string &value) const;
optional_const_config find_child(config_key_type key, const std::string &name, const std::string &value) const;
const config& child(config_key_type key) const;
// const config& child(config_key_type key) const;
const config& mandatory_child(config_key_type key) const;
optional_const_config optional_child(config_key_type key) const;
const config& child_or_empty(config_key_type key) const;

View file

@ -212,7 +212,7 @@ bool conditional_passed(const vconfig& cond)
return matches;
}
bool matches_special_filter(const config &cfg, const vconfig& filter)
bool matches_special_filter(optional_const_config cfg, const vconfig& filter)
{
if (!cfg) {
WRN_NG << "attempt to filter attack for an event with no attack data.";
@ -221,7 +221,7 @@ bool matches_special_filter(const config &cfg, const vconfig& filter)
}
// Though it may seem wasteful to put this on the heap, it's necessary.
// matches_filter() could potentially call a WFL formula, which would call shared_from_this().
auto attack = std::make_shared<const attack_type>(cfg);
auto attack = std::make_shared<const attack_type>(*cfg);
return attack->matches_filter(filter.get_parsed_config());
}

View file

@ -21,14 +21,14 @@
#pragma once
class config;
class vconfig;
#include "config.hpp"
namespace game_events
{
bool conditional_passed(const vconfig& cond);
bool matches_special_filter(const config &cfg, const vconfig& filter);
bool matches_special_filter(optional_const_config cfg, const vconfig& filter);
namespace builtin_conditions {
bool have_unit(const vconfig& cfg);

View file

@ -243,7 +243,7 @@ struct filter_attack : public event_filter {
const auto& loc = first_ ? event_info.loc1 : event_info.loc2;
auto unit = units.find(loc);
if(unit != units.end() && loc.matches_unit(unit)) {
const config& attack = event_info.data.child(first_ ? "first" : "second");
auto attack = event_info.data.optional_child(first_ ? "first" : "second");
return swf_.empty() || matches_special_filter(attack, swf_);
}
return false;

View file

@ -208,8 +208,8 @@ void wml_event_pump::process_event(handler_ptr& handler_p, const queued_event& e
unit_map& units = resources::gameboard->units();
scoped_xy_unit first_unit("unit", ev.loc1, units);
scoped_xy_unit second_unit("second_unit", ev.loc2, units);
scoped_weapon_info first_weapon("weapon", ev.data.child("first"));
scoped_weapon_info second_weapon("second_weapon", ev.data.child("second"));
scoped_weapon_info first_weapon("weapon", ev.data.optional_child("first"));
scoped_weapon_info second_weapon("second_weapon", ev.data.optional_child("second"));
if(!handler_p->filter_event(ev)) {
return;

View file

@ -92,8 +92,8 @@ connect_engine::connect_engine(saved_game& state, const bool first_scenario, mp_
config::child_itors sides = current_config()->child_range("side");
// AI algorithms.
if(const config& era = level_.child("era")) {
ai::configuration::add_era_ai_from_config(era);
if(auto era = level_.optional_child("era")) {
ai::configuration::add_era_ai_from_config(*era);
}
ai::configuration::add_mod_ai_from_config(level_.child_range("modification"));
@ -174,7 +174,7 @@ connect_engine::connect_engine(saved_game& state, const bool first_scenario, mp_
}
// Selected era's factions.
for(const config& era : level_.child("era").child_range("multiplayer_side")) {
for(const config& era : level_.mandatory_child("era").child_range("multiplayer_side")) {
era_factions_.push_back(&era);
}
@ -225,11 +225,7 @@ connect_engine::connect_engine(saved_game& state, const bool first_scenario, mp_
config* connect_engine::current_config() {
if(config& s = scenario()) {
return &s;
}
return nullptr;
return &scenario();
}
void connect_engine::import_user(const std::string& name, const bool observer, int side_taken)
@ -422,7 +418,7 @@ void connect_engine::start_game()
// Shuffle sides (check settings and if it is a re-loaded game).
// Must be done after resolve_random() or shuffle sides, or they won't work.
if(state_.mp_settings().shuffle_sides && !force_lock_settings_ && !(level_.child("snapshot") && level_.child("snapshot").child("side"))) {
if(state_.mp_settings().shuffle_sides && !force_lock_settings_ && !(level_.has_child("snapshot") && level_.mandatory_child("snapshot").has_child("side"))) {
// Only playable sides should be shuffled.
std::vector<int> playable_sides;
@ -506,7 +502,7 @@ void connect_engine::start_game_commandline(const commandline_options& cmdline_o
// Set AI algorithm to default for all sides,
// then override if commandline option was given.
std::string ai_algorithm = game_config.child("ais")["default_ai_algorithm"].str();
std::string ai_algorithm = game_config.mandatory_child("ais")["default_ai_algorithm"].str();
side->set_ai_algorithm(ai_algorithm);
if(cmdline_opts.multiplayer_algorithm) {
@ -578,13 +574,13 @@ std::pair<bool, bool> connect_engine::process_network_data(const config& data)
{
std::pair<bool, bool> result(false, true);
if(data.child("leave_game")) {
if(data.has_child("leave_game")) {
result.first = true;
return result;
}
// A side has been dropped.
if(const config& side_drop = data.child("side_drop")) {
if(auto side_drop = data.optional_child("side_drop")) {
unsigned side_index = side_drop["side_num"].to_int() - 1;
if(side_index < side_engines_.size()) {
@ -691,20 +687,20 @@ std::pair<bool, bool> connect_engine::process_network_data(const config& data)
}
}
if(const config& change_faction = data.child("change_faction")) {
if(auto change_faction = data.optional_child("change_faction")) {
int side_taken = find_user_side_index_by_id(change_faction["name"]);
if(side_taken != -1 || !first_scenario_) {
import_user(change_faction, false, side_taken);
import_user(*change_faction, false, side_taken);
update_and_send_diff();
}
}
if(const config& observer = data.child("observer")) {
import_user(observer, true);
if(auto observer = data.optional_child("observer")) {
import_user(*observer, true);
update_and_send_diff();
}
if(const config& observer = data.child("observer_quit")) {
if(auto observer = data.optional_child("observer_quit")) {
const std::string& observer_name = observer["name"];
if(connected_users().find(observer_name) != connected_users().end()) {
@ -773,12 +769,12 @@ void connect_engine::save_reserved_sides_information()
}
}
level_.child("multiplayer")["side_users"] = utils::join_map(side_users);
level_.mandatory_child("multiplayer")["side_users"] = utils::join_map(side_users);
}
void connect_engine::load_previous_sides_users()
{
std::map<std::string, std::string> side_users = utils::map_split(level_.child("multiplayer")["side_users"]);
std::map<std::string, std::string> side_users = utils::map_split(level_.mandatory_child("multiplayer")["side_users"]);
std::set<std::string> names;
for(side_engine_ptr side : side_engines_) {
const std::string& save_id = side->previous_save_id();
@ -942,7 +938,7 @@ side_engine::side_engine(const config& cfg, connect_engine& parent_engine, const
}
// Initialize ai algorithm.
if(const config& ai = cfg.child("ai")) {
if(auto ai = cfg.optional_child("ai")) {
ai_algorithm_ = ai["ai_algorithm"].str();
}
}

View file

@ -82,10 +82,10 @@ public:
const config& level() const { return level_; }
config& scenario()
{
if(config& scenario = level_.child("scenario"))
return scenario;
else if(config& snapshot = level_.child("snapshot"))
return snapshot;
if(auto scenario = level_.optional_child("scenario"))
return *scenario;
else if(auto snapshot = level_.optional_child("snapshot"))
return *snapshot;
else
throw "No scenariodata found";
}

View file

@ -165,7 +165,7 @@ random_map::random_map(const config& data)
data_["description"] = "Error: Random map found with missing generator information. Scenario should have a [generator] child.";
data_["error_message"] = "missing [generator] tag";
} else {
generator_data_ = data.child("generator");
generator_data_ = data.mandatory_child("generator");
}
if(!data.has_attribute("scenario_generation") && !data.has_attribute("map_generation")) {
@ -646,8 +646,8 @@ const mp_game_settings& create_engine::get_parameters()
void create_engine::init_all_levels()
{
if(const config& generic_multiplayer = game_config_.child("generic_multiplayer")) {
config gen_mp_data = generic_multiplayer;
if(auto generic_multiplayer = game_config_.optional_child("generic_multiplayer")) {
config gen_mp_data = *generic_multiplayer;
// User maps.
int dep_index_offset = 0;

View file

@ -155,7 +155,7 @@ bool manager::exists(const elem& e) const
std::string manager::find_name_for(const elem& e) const
{
const config& cfg = depinfo_.find_child(e.type, "id", e.id);
auto cfg = depinfo_.find_child(e.type, "id", e.id);
return cfg["name"];
}
@ -182,7 +182,7 @@ std::vector<std::string> manager::get_required(const elem& e) const
return result;
}
config data = depinfo_.find_child(e.type, "id", e.id);
config data = *depinfo_.find_child(e.type, "id", e.id);
if(data.has_attribute("force_modification")) {
result = utils::split(data["force_modification"].str(), ',');
@ -230,8 +230,8 @@ bool manager::does_conflict(const elem& elem1, const elem& elem2, bool directonl
return false;
}
config data1 = depinfo_.find_child(elem1.type, "id", elem1.id);
config data2 = depinfo_.find_child(elem2.type, "id", elem2.id);
config data1 = *depinfo_.find_child(elem1.type, "id", elem1.id);
config data2 = *depinfo_.find_child(elem2.type, "id", elem2.id);
// Whether we should skip the check entirely
if(data1.has_attribute("ignore_incompatible_" + elem2.type)) {
@ -323,7 +323,7 @@ bool manager::does_require(const elem& elem1, const elem& elem2) const
return false;
}
config data = depinfo_.find_child(elem1.type, "id", elem1.id);
config data = *depinfo_.find_child(elem1.type, "id", elem1.id);
if(data.has_attribute("force_modification")) {
std::vector<std::string> required = utils::split(data["force_modification"]);
@ -369,7 +369,7 @@ void manager::try_modifications(const std::vector<std::string>& ids, bool force)
void manager::try_modification_by_index(int index, bool activate, bool force)
{
std::string id = depinfo_.child("modification", index)["id"];
std::string id = depinfo_.mandatory_child("modification", index)["id"];
std::vector<std::string> mods_copy = mods_;
if(activate) {
@ -388,12 +388,12 @@ void manager::try_modification_by_index(int index, bool activate, bool force)
void manager::try_era_by_index(int index, bool force)
{
try_era(depinfo_.child("era", index)["id"], force);
try_era(depinfo_.mandatory_child("era", index)["id"], force);
}
void manager::try_scenario_by_index(int index, bool force)
{
try_scenario(depinfo_.child("scenario", index)["id"], force);
try_scenario(depinfo_.mandatory_child("scenario", index)["id"], force);
}
int manager::get_era_index() const
@ -427,7 +427,7 @@ int manager::get_scenario_index() const
bool manager::is_modification_active(int index) const
{
std::string id = depinfo_.child("modification", index)["id"];
std::string id = depinfo_.mandatory_child("modification", index)["id"];
return std::find(mods_.begin(), mods_.end(), id) != mods_.end();
}

View file

@ -62,8 +62,8 @@ flg_manager::flg_manager(const std::vector<const config*>& era_factions,
const std::string& leader_id = side["id"];
if(!leader_id.empty()) {
// Check if leader was carried over and now is in [unit] tag.
default_leader_cfg_ = &side.find_child("unit", "id", leader_id);
if(*default_leader_cfg_) {
default_leader_cfg_ = side.find_child("unit", "id", leader_id).ptr();
if(default_leader_cfg_) {
default_leader_type_ = (*default_leader_cfg_)["type"].str();
default_leader_gender_ = (*default_leader_cfg_)["gender"].str();
} else {
@ -546,8 +546,8 @@ void flg_manager::set_current_gender(const std::string& gender)
const config& flg_manager::get_default_faction(const config& cfg)
{
if(const config& df = cfg.child("default_faction")) {
return df;
if(auto df = cfg.optional_child("default_faction")) {
return *df;
} else {
return cfg;
}

View file

@ -175,13 +175,13 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
}
if(!game["mp_era"].empty()) {
const config& era_cfg = game_config.find_child("era", "id", game["mp_era"]);
auto era_cfg = game_config.find_child("era", "id", game["mp_era"]);
const bool require = game["require_era"].to_bool(true);
if(era_cfg) {
era = era_cfg["name"].str();
if(require) {
addon_req result = check_addon_version_compatibility(era_cfg, game);
addon_req result = check_addon_version_compatibility(*era_cfg, game);
addons_outcome = std::max(addons_outcome, result); // Elevate to most severe error level encountered so far
}
} else {
@ -206,8 +206,8 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
info_stream << ' ' << mod_info.back().first;
if(cfg["require_modification"].to_bool(false)) {
if(const config& mod = game_config.find_child("modification", "id", cfg["id"])) {
addon_req result = check_addon_version_compatibility(mod, game);
if(auto mod = game_config.find_child("modification", "id", cfg["id"])) {
addon_req result = check_addon_version_compatibility(*mod, game);
addons_outcome = std::max(addons_outcome, result); // Elevate to most severe error level encountered so far
} else {
have_all_mods = false;
@ -252,15 +252,15 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
//
if(!game["mp_scenario"].empty() && game["mp_campaign"].empty()) {
// Check if it's a multiplayer scenario
const config* level_cfg = &game_config.find_child("multiplayer", "id", game["mp_scenario"]);
const config* level_cfg = game_config.find_child("multiplayer", "id", game["mp_scenario"]).ptr();
const bool require = game["require_scenario"].to_bool(false);
// Check if it's a user map
if(!*level_cfg) {
level_cfg = &game_config.find_child("generic_multiplayer", "id", game["mp_scenario"]);
if(level_cfg) {
level_cfg = game_config.find_child("generic_multiplayer", "id", game["mp_scenario"]).ptr();
}
if(*level_cfg) {
if(level_cfg) {
type_marker = make_game_type_marker(_("scenario_abbreviation^S"), false);
scenario = (*level_cfg)["name"].str();
info_stream << scenario;
@ -268,10 +268,10 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
// Reloaded games do not match the original scenario hash, so it makes no sense
// to test them, since they always would appear as remote scenarios
if(!reloaded) {
if(const config& hashes = game_config.child("multiplayer_hashes")) {
if(auto hashes = game_config.optional_child("multiplayer_hashes")) {
std::string hash = game["hash"];
bool hash_found = false;
for(const auto & i : hashes.attribute_range()) {
for(const auto & i : hashes->attribute_range()) {
if(i.first == game["mp_scenario"] && i.second == hash) {
hash_found = true;
break;
@ -301,7 +301,7 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
verified = false;
}
} else if(!game["mp_campaign"].empty()) {
if(const config& campaign_cfg = game_config.find_child("campaign", "id", game["mp_campaign"])) {
if(auto campaign_cfg = game_config.find_child("campaign", "id", game["mp_campaign"])) {
type_marker = make_game_type_marker(_("campaign_abbreviation^C"), false);
std::stringstream campaign_text;
@ -310,7 +310,7 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
<< game["mp_scenario_name"];
// Difficulty
config difficulties = gui2::dialogs::generate_difficulty_config(campaign_cfg);
config difficulties = gui2::dialogs::generate_difficulty_config(*campaign_cfg);
for(const config& difficulty : difficulties.child_range("difficulty")) {
if(difficulty["define"] == game["difficulty_define"]) {
campaign_text << spaced_em_dash() << difficulty["description"];
@ -324,7 +324,7 @@ game_info::game_info(const config& game, const std::vector<std::string>& install
// TODO: should we have this?
//if(game["require_scenario"].to_bool(false)) {
addon_req result = check_addon_version_compatibility(campaign_cfg, game);
addon_req result = check_addon_version_compatibility(*campaign_cfg, game);
addons_outcome = std::max(addons_outcome, result); // Elevate to most severe error level encountered so far
//}
} else {
@ -412,7 +412,7 @@ game_info::addon_req game_info::check_addon_version_compatibility(const config&
return addon_req::SATISFIED;
}
if(const config& game_req = game.find_child("addon", "id", local_item["addon_id"])) {
if(auto game_req = game.find_child("addon", "id", local_item["addon_id"])) {
if(!game_req["require"].to_bool(false)) {
return addon_req::SATISFIED;
}
@ -429,7 +429,7 @@ game_info::addon_req game_info::check_addon_version_compatibility(const config&
// Remote version
const version_info remote_ver(game_req["version"].str());
version_info remote_min_ver(game_req.has_attribute("min_version") ? game_req["min_version"] : game_req["version"]);
version_info remote_min_ver(game_req->has_attribute("min_version") ? game_req["min_version"] : game_req["version"]);
remote_min_ver = std::min(remote_min_ver, remote_ver);

View file

@ -126,13 +126,13 @@ void lobby_info::process_gamelist(const config& data)
games_by_id_.clear();
for(const auto& c : gamelist_.child("gamelist").child_range("game")) {
for(const auto& c : gamelist_.mandatory_child("gamelist").child_range("game")) {
game_info game(c, installed_addons_);
games_by_id_.emplace(game.id, std::move(game));
}
DBG_LB << dump_games_map(games_by_id_);
DBG_LB << dump_games_config(gamelist_.child("gamelist"));
DBG_LB << dump_games_config(gamelist_.mandatory_child("gamelist"));
process_userlist();
}
@ -155,7 +155,7 @@ bool lobby_info::process_gamelist_diff_impl(const config& data)
return false;
}
DBG_LB << "prediff " << dump_games_config(gamelist_.child("gamelist"));
DBG_LB << "prediff " << dump_games_config(gamelist_.mandatory_child("gamelist"));
try {
gamelist_.apply_diff(data, true);
@ -164,10 +164,10 @@ bool lobby_info::process_gamelist_diff_impl(const config& data)
return false;
}
DBG_LB << "postdiff " << dump_games_config(gamelist_.child("gamelist"));
DBG_LB << "postdiff " << dump_games_config(gamelist_.mandatory_child("gamelist"));
DBG_LB << dump_games_map(games_by_id_);
for(config& c : gamelist_.child("gamelist").child_range("game")) {
for(config& c : gamelist_.mandatory_child("gamelist").child_range("game")) {
DBG_LB << "data process: " << c["id"] << " (" << c[config::diff_track_attribute] << ")";
const int game_id = c["id"];
@ -219,7 +219,7 @@ bool lobby_info::process_gamelist_diff_impl(const config& data)
return false;
}
DBG_LB << "postclean " << dump_games_config(gamelist_.child("gamelist"));
DBG_LB << "postclean " << dump_games_config(gamelist_.mandatory_child("gamelist"));
process_userlist();
return true;

View file

@ -96,7 +96,7 @@ config initial_level_config(saved_game& state)
*/
const game_config_view& game_config = game_config_manager::get()->game_config();
const config& era_cfg = game_config.find_child("era", "id", era);
auto era_cfg = game_config.find_child("era", "id", era);
if(!era_cfg) {
if(params.saved_game == saved_game_mode::type::no) {
@ -107,20 +107,20 @@ config initial_level_config(saved_game& state)
WRN_CF << "Missing era in MP load game '" << era << "'";
} else {
level.add_child("era", era_cfg);
level.add_child("era", *era_cfg);
// Initialize the list of sides available for the current era.
// We also need this so not to get a segfault in mp_staging for ai configuration.
const config& custom_side = game_config.find_child("multiplayer_side", "id", "Custom");
level.child("era").add_child_at("multiplayer_side", custom_side, 0);
auto custom_side = game_config.find_child("multiplayer_side", "id", "Custom");
level.mandatory_child("era").add_child_at("multiplayer_side", *custom_side, 0);
}
// Add modifications, needed for ai algorithms which are applied in mp_staging.
const std::vector<std::string>& mods = state.classification().active_mods;
for(unsigned i = 0; i < mods.size(); ++i) {
if(const config& mod_cfg = game_config.find_child("modification", "id", mods[i])) {
level.add_child("modification", mod_cfg);
if(auto mod_cfg = game_config.find_child("modification", "id", mods[i])) {
level.add_child("modification", *mod_cfg);
}
}

View file

@ -520,8 +520,8 @@ bool mp_manager::enter_lobby_mode()
// We use a loop here to allow returning to the lobby if you, say, cancel game creation.
while(true) {
if(const config& cfg = game_config_manager::get()->game_config().child("lobby_music")) {
for(const config& i : cfg.child_range("music")) {
if(auto cfg = game_config_manager::get()->game_config().optional_child("lobby_music")) {
for(const config& i : cfg->child_range("music")) {
sound::play_music_config(i);
}
@ -739,7 +739,7 @@ void start_local_game_commandline(const commandline_options& cmdline_opts)
state.classification().era_id = *cmdline_opts.multiplayer_era;
}
if(const config& cfg_era = game_config.find_child("era", "id", state.classification().era_id)) {
if(auto cfg_era = game_config.find_child("era", "id", state.classification().era_id)) {
state.classification().era_define = cfg_era["define"].str();
} else {
PLAIN_LOG << "Could not find era '" << state.classification().era_id << "'";
@ -751,7 +751,7 @@ void start_local_game_commandline(const commandline_options& cmdline_opts)
parameters.name = *cmdline_opts.multiplayer_scenario;
}
if(const config& cfg_multiplayer = game_config.find_child("multiplayer", "id", parameters.name)) {
if(auto cfg_multiplayer = game_config.find_child("multiplayer", "id", parameters.name)) {
state.classification().scenario_define = cfg_multiplayer["define"].str();
} else {
PLAIN_LOG << "Could not find [multiplayer] '" << parameters.name << "'";

View file

@ -63,9 +63,9 @@ game_state::game_state(const config& level, play_controller& pc)
, first_human_team_(-1)
{
lua_kernel_->load_core();
if(const config& endlevel_cfg = level.child("end_level_data")) {
if(auto endlevel_cfg = level.optional_child("end_level_data")) {
end_level_data el_data;
el_data.read(endlevel_cfg);
el_data.read(*endlevel_cfg);
el_data.transient.carryover_report = false;
end_level_data_ = el_data;
}

View file

@ -37,7 +37,7 @@ cave_map_generator::cave_map_generator(const config &cfg) :
village_(t_translation::UNDERGROUND_VILLAGE),
castle_(t_translation::DWARVEN_CASTLE),
keep_(t_translation::DWARVEN_KEEP),
cfg_(cfg ? cfg : config()),
cfg_(cfg),
width_(50),
height_(50),
village_density_(0),
@ -193,8 +193,8 @@ void cave_map_generator::cave_map_generator_job::generate_chambers()
new_chamber.center = map_location(x,y);
build_chamber(new_chamber.center,new_chamber.locs,chamber_size,jagged_edges);
const config &items = ch.child("items");
new_chamber.items = items ? &items : nullptr;
auto items = ch.optional_child("items");
new_chamber.items = items ? &*items : nullptr;
const std::string &id = ch["id"];
if (!id.empty()) {
@ -231,11 +231,12 @@ void cave_map_generator::cave_map_generator_job::place_chamber(const chamber& c)
for (const config::any_child it : c.items->all_children_range())
{
config cfg = it.cfg;
config &filter = cfg.child("filter");
auto filter = cfg.optional_child("filter");
config* object_filter = nullptr;
if (config &object = cfg.child("object")) {
if (config &of = object.child("filter"))
object_filter = &of;
if (auto object = cfg.optional_child("object")) {
if (auto of = object->optional_child("filter")) {
object_filter = &*of;
}
}
if (!it.cfg["same_location_as_previous"].to_bool()) {

View file

@ -67,7 +67,7 @@ std::string default_map_generator::name() const { return "default"; }
std::string default_map_generator::config_name() const
{
if (const config &c = cfg_.child("scenario"))
if (auto c = cfg_.optional_child("scenario"))
return c["name"];
return std::string();

View file

@ -109,7 +109,7 @@ namespace {
static std::string terrain;
terrain = t_translation::write_terrain_code(c);
double res = getNoPathValue();
if(const config &child = cfg_.find_child("road_cost", "terrain", terrain)) {
if(auto child = cfg_.find_child("road_cost", "terrain", terrain)) {
res = child["cost"].to_double();
}
@ -628,7 +628,7 @@ static map_location place_village(const t_translation::ter_map& map,
const t_translation::terrain_code t = map[i.x][i.y];
const std::string str = t_translation::write_terrain_code(t);
if(const config &child = cfg.find_child("village", "terrain", str)) {
if(auto child = cfg.find_child("village", "terrain", str)) {
tcode_list_cache::iterator l = adj_liked_cache.find(t);
t_translation::ter_list *adjacent_liked;
if(l != adj_liked_cache.end()) {
@ -707,7 +707,7 @@ std::string default_map_generator_job::default_generate_map(generator_data data,
VALIDATE(is_even(data.width), _("Random maps with an odd width aren't supported."));
// Try to find configuration for castles
const config& castle_config = cfg.child("castle");
auto castle_config = cfg.optional_child("castle");
int ticks = SDL_GetTicks();
@ -721,8 +721,8 @@ std::string default_map_generator_job::default_generate_map(generator_data data,
config naming;
if(cfg.has_child("naming")) {
naming = game_config_.child("naming");
naming.append_attributes(cfg.child("naming"));
naming = game_config_.mandatory_child("naming");
naming.append_attributes(cfg.mandatory_child("naming"));
}
// If the [naming] child is empty, we cannot provide good names.
@ -1055,8 +1055,8 @@ std::string default_map_generator_job::default_generate_map(generator_data data,
}
// Find the configuration which tells us what to convert this tile to, to make it into a road.
const config& child = cfg.find_child("road_cost", "terrain", t_translation::write_terrain_code(terrain[x][y]));
if(child.empty()){
auto child = cfg.find_child("road_cost", "terrain", t_translation::write_terrain_code(terrain[x][y]));
if(!child || child->empty()){
continue;
}
@ -1255,10 +1255,10 @@ std::string default_map_generator_job::default_generate_map(generator_data data,
std::set<std::string> used_names;
tcode_list_cache adj_liked_cache;
config village_naming = game_config_.child("village_naming");
config village_naming = game_config_.mandatory_child("village_naming");
if(cfg.has_child("village_naming")) {
village_naming.append_attributes(cfg.child("village_naming"));
village_naming.append_attributes(cfg.mandatory_child("village_naming"));
}
// If the [village_naming] child is empty, we cannot provide good names.

View file

@ -122,7 +122,7 @@ gui_definition::gui_definition(const config& cfg)
* - Override the default and above per instance of the widget, some buttons
* can give a different sound.
*/
const config& settings = cfg.child("settings");
const config& settings = cfg.mandatory_child("settings");
popup_show_delay_ = settings["popup_show_delay"];
popup_show_time_ = settings["popup_show_time"];

View file

@ -25,10 +25,10 @@
namespace gui2
{
state_definition::state_definition(const config& cfg)
: canvas_cfg_(cfg ? cfg.child("draw") : cfg)
state_definition::state_definition(optional_const_config cfg)
: canvas_cfg_(cfg ? cfg->child_or_empty("draw") : config())
{
VALIDATE(canvas_cfg_, _("No state or draw section defined."));
VALIDATE(cfg && cfg->has_child("draw"), _("No state or draw section defined."));
}
resolution_definition::resolution_definition(const config& cfg)

View file

@ -35,7 +35,7 @@ namespace gui2
*/
struct state_definition
{
explicit state_definition(const config& cfg);
explicit state_definition(optional_const_config cfg);
config canvas_cfg_;
};

View file

@ -162,11 +162,11 @@ builder_window::window_resolution::window_resolution(const config& cfg)
wfl::formula(cfg["functions"], &functions).evaluate();
}
const config& c = cfg.child("grid");
auto c = cfg.optional_child("grid");
VALIDATE(c, _("No grid defined."));
grid = std::make_shared<builder_grid>(c);
grid = std::make_shared<builder_grid>(*c);
if(!automatic_placement) {
VALIDATE(width.has_formula() || width(), missing_mandatory_wml_key("resolution", "width"));

View file

@ -545,7 +545,8 @@ void addon_manager::toggle_details(button& btn, stacked_widget& stk)
void addon_manager::fetch_addons_list()
{
client_.request_addons_list(cfg_);
if(!cfg_) {
// TODO: this was a faulty invalid config test.
if((false)) {
gui2::show_error_message(_("An error occurred while downloading the add-ons list from the server."));
get_window()->close();
}

View file

@ -110,7 +110,7 @@ void campaign_difficulty::post_show(window& window)
{
if(get_retval() == retval::OK) {
listbox& list = find_widget<listbox>(&window, "listbox", false);
selected_difficulty_ = difficulties_.child("difficulty", list.get_selected_row())["define"].str();
selected_difficulty_ = difficulties_.mandatory_child("difficulty", list.get_selected_row())["define"].str();
}
}
} // namespace dialogs

View file

@ -370,8 +370,8 @@ void game_load::evaluate_summary_string(std::stringstream& str, const config& cf
case campaign_type::type::scenario: {
const config* campaign = nullptr;
if(!campaign_id.empty()) {
if(const config& c = cache_config_.find_child("campaign", "id", campaign_id)) {
campaign = &c;
if(auto c = cache_config_.find_child("campaign", "id", campaign_id)) {
campaign = c.ptr();
}
}
@ -421,8 +421,8 @@ void game_load::evaluate_summary_string(std::stringstream& str, const config& cf
case campaign_type::type::multiplayer: {
const config* campaign = nullptr;
if (!campaign_id.empty()) {
if (const config& c = cache_config_.find_child("campaign", "id", campaign_id)) {
campaign = &c;
if (auto c = cache_config_.find_child("campaign", "id", campaign_id)) {
campaign = c.ptr();
}
}
@ -433,7 +433,7 @@ void game_load::evaluate_summary_string(std::stringstream& str, const config& cf
if (campaign != nullptr) {
str << "\n" << _("Difficulty: ");
try {
const config& difficulty = campaign->find_child("difficulty", "define", cfg_summary["difficulty"]);
auto difficulty = campaign->find_child("difficulty", "define", cfg_summary["difficulty"]);
std::ostringstream ss;
ss << difficulty["label"] << " (" << difficulty["description"] << ")";
str << ss.str();

View file

@ -550,7 +550,7 @@ void variable_mode_controller::show_array(tree_view_node& node)
std::size_t n_start = var.find_last_of('[') + 1;
std::size_t n_len = var.size() - n_start - 1;
int n = std::stoi(var.substr(n_start, n_len));
model().set_data(config_to_string(vars().child(var.substr(1, n_start - 3), n)));
model().set_data(config_to_string(vars().mandatory_child(var.substr(1, n_start - 3), n)));
}
}
@ -585,7 +585,7 @@ void event_mode_controller::show_list(tree_view_node& node, bool is_wmi)
void event_mode_controller::show_event(tree_view_node& node, bool is_wmi)
{
int n = node.describe_path().back();
model().set_data(config_to_string(events.child(is_wmi ? "menu_item" : "event", n)));
model().set_data(config_to_string(events.mandatory_child(is_wmi ? "menu_item" : "event", n)));
}
static stuff_list_adder add_unit_entry(stuff_list_adder& progress, const unit& u, const display_context& dc)
@ -705,7 +705,7 @@ void unit_mode_controller::show_array(tree_view_node& node)
std::size_t n_start = var.find_last_of('[') + 1;
std::size_t n_len = var.size() - n_start - 1;
int n = std::stoi(var.substr(n_start, n_len));
model().set_data(config_to_string(u->variables().child(var.substr(1, n_start - 3), n)));
model().set_data(config_to_string(u->variables().mandatory_child(var.substr(1, n_start - 3), n)));
}
}
@ -907,7 +907,7 @@ void team_mode_controller::show_array(tree_view_node& node, int side)
std::size_t n_start = var.find_last_of('[') + 1;
std::size_t n_len = var.size() - n_start - 1;
int n = std::stoi(var.substr(n_start, n_len));
model().set_data(config_to_string(t.variables().child(var.substr(1, n_start - 3), n)));
model().set_data(config_to_string(t.variables().mandatory_child(var.substr(1, n_start - 3), n)));
}
}

View file

@ -46,7 +46,7 @@ REGISTER_DIALOG(help_browser)
help_browser::help_browser()
: modal_dialog(window_id())
, initial_topic_("introduction")
, help_cfg_(game_config_manager::get()->game_config().child("help"))
, help_cfg_(game_config_manager::get()->game_config().mandatory_child("help"))
{
}

View file

@ -752,13 +752,13 @@ void mp_lobby::network_handler()
void mp_lobby::process_network_data(const config& data)
{
if(const config& error = data.child("error")) {
if(auto error = data.optional_child("error")) {
throw wesnothd_error(error["message"]);
} else if(data.child("gamelist")) {
} else if(data.has_child("gamelist")) {
process_gamelist(data);
} else if(const config& gamelist_diff = data.child("gamelist_diff")) {
process_gamelist_diff(gamelist_diff);
} else if(const config& info = data.child("message")) {
} else if(auto gamelist_diff = data.optional_child("gamelist_diff")) {
process_gamelist_diff(*gamelist_diff);
} else if(auto info = data.optional_child("message")) {
if(info["type"] == "server_info") {
server_information_ = info["message"].str();
return;

View file

@ -103,20 +103,20 @@ bool mp_join_game::fetch_game_config()
network_connection_.wait_and_receive_data(revc);
});
if(const config& err = revc.child("error")) {
if(auto err = revc.optional_child("error")) {
throw wesnothd_error(err["message"]);
} else if(revc.child("leave_game")) {
} else if(revc.has_child("leave_game")) {
return false;
} else if(config& next_scenario = revc.child("next_scenario")) {
level_.swap(next_scenario);
} else if(auto next_scenario = revc.optional_child("next_scenario")) {
level_.swap(*next_scenario);
} else if(revc.has_attribute("version")) {
level_.swap(revc);
has_scenario_and_controllers = true;
} else if(config& controllers = revc.child("controllers")) {
} else if(auto controllers = revc.optional_child("controllers")) {
int index = 0;
for(const config& controller : controllers.child_range("controller")) {
if(config& side = get_scenario().child("side", index)) {
for(const config& controller : controllers->child_range("controller")) {
if(auto side = get_scenario().optional_child("side", index)) {
side["is_local"] = controller["is_local"];
}
++index;
@ -140,7 +140,7 @@ bool mp_join_game::fetch_game_config()
// since add-ons are now only enabled when used, the scenario ID may still not be known
// so check in the MP info sent from the server for the scenario ID if that's the case
if(scenario_id == "") {
for(const auto& addon : level_.child("multiplayer").child_range("addon")) {
for(const auto& addon : level_.mandatory_child("multiplayer").child_range("addon")) {
for(const auto& content : addon.child_range("content")) {
if(content["type"] == "scenario") {
scenario_id = content["id"].str();
@ -245,7 +245,7 @@ void mp_join_game::pre_show(window& window)
//
label& title = find_widget<label>(&window, "title", false);
// FIXME: very hacky way to get the game name...
title.set_label((formatter() << level_.child("multiplayer")["scenario"] << " " << font::unicode_em_dash << " " << get_scenario()["name"].t_str()).str());
title.set_label((formatter() << level_.mandatory_child("multiplayer")["scenario"] << " " << font::unicode_em_dash << " " << get_scenario()["name"].t_str()).str());
//
// Set up sides list
@ -283,18 +283,18 @@ void mp_join_game::pre_show(window& window)
bool mp_join_game::show_flg_select(int side_num, bool first_time)
{
if(const config& side_choice = get_scenario().child("side", side_num - 1)) {
if(auto side_choice = get_scenario().optional_child("side", side_num - 1)) {
if(!side_choice["allow_changes"].to_bool(true)) {
return true;
}
const config& era = level_.child("era");
auto era = level_.optional_child("era");
if(!era) {
ERR_MP << "no era information";
return false;
}
config::const_child_itors possible_sides = era.child_range("multiplayer_side");
config::const_child_itors possible_sides = era->child_range("multiplayer_side");
if(possible_sides.empty()) {
WRN_MP << "no [multiplayer_side] found in era '" << era["id"] << "'.";
return false;
@ -312,10 +312,10 @@ bool mp_join_game::show_flg_select(int side_num, bool first_time)
const bool is_mp = state_.classification().is_normal_mp_game();
const bool lock_settings = get_scenario()["force_lock_settings"].to_bool(!is_mp);
const bool use_map_settings = level_.child("multiplayer")["mp_use_map_settings"].to_bool();
const saved_game_mode::type saved_game = saved_game_mode::get_enum(level_.child("multiplayer")["savegame"].str()).value_or(saved_game_mode::type::no);
const bool use_map_settings = level_.mandatory_child("multiplayer")["mp_use_map_settings"].to_bool();
const saved_game_mode::type saved_game = saved_game_mode::get_enum(level_.mandatory_child("multiplayer")["savegame"].str()).value_or(saved_game_mode::type::no);
ng::flg_manager flg(era_factions, side_choice, lock_settings, use_map_settings, saved_game == saved_game_mode::type::midgame);
ng::flg_manager flg(era_factions, *side_choice, lock_settings, use_map_settings, saved_game == saved_game_mode::type::midgame);
{
gui2::dialogs::faction_select flg_dialog(flg, color, side_num);
@ -515,34 +515,34 @@ void mp_join_game::network_handler()
close_faction_select_dialog_if_open();
set_retval(retval::CANCEL);
} else if(data.child("start_game")) {
} else if(data.has_child("start_game")) {
close_faction_select_dialog_if_open();
level_["started"] = true;
set_retval(retval::OK);
} else if(data.child("leave_game")) {
} else if(data.has_child("leave_game")) {
close_faction_select_dialog_if_open();
set_retval(retval::CANCEL);
}
if(data.child("stop_updates")) {
if(data.has_child("stop_updates")) {
stop_updates_ = true;
} else if(const config& c = data.child("scenario_diff")) {
} else if(auto c = data.optional_child("scenario_diff")) {
// TODO: We should catch config::error and then leave the game.
level_.apply_diff(c);
level_.apply_diff(*c);
generate_side_list();
} else if(const config& change = data.child("change_controller")) {
if(config& side_to_change = get_scenario().find_child("side", "side", change["side"])) {
side_to_change.merge_with(change);
} else if(auto change = data.optional_child("change_controller")) {
if(auto side_to_change = get_scenario().find_child("side", "side", change["side"])) {
side_to_change->merge_with(*change);
}
if(flg_dialog_ && flg_dialog_->get_side_num() == change["side"].to_int()) {
close_faction_select_dialog_if_open();
}
} else if(data.has_child("scenario") || data.has_child("snapshot") || data.child("next_scenario")) {
level_ = first_scenario_ ? data : data.child("next_scenario");
} else if(data.has_child("scenario") || data.has_child("snapshot") || data.has_child("next_scenario")) {
level_ = first_scenario_ ? data : data.mandatory_child("next_scenario");
generate_side_list();
}
@ -559,10 +559,10 @@ void mp_join_game::network_handler()
config& mp_join_game::get_scenario()
{
if(config& scenario = level_.child("scenario")) {
return scenario;
} else if(config& snapshot = level_.child("snapshot")) {
return snapshot;
if(auto scenario = level_.optional_child("scenario")) {
return *scenario;
} else if(auto snapshot = level_.optional_child("snapshot")) {
return *snapshot;
}
return level_;
@ -576,9 +576,9 @@ void mp_join_game::post_show(window& window)
}
if(window.get_retval() == retval::OK) {
if(const config& stats = level_.child("statistics")) {
if(auto stats = level_.optional_child("statistics")) {
statistics::fresh_stats();
statistics::read_stats(stats);
statistics::read_stats(*stats);
}
mp::level_to_gamestate(level_, state_);

View file

@ -427,10 +427,10 @@ addon_list_definition::resolution::resolution(const config& cfg)
static config dummy("draw");
state.emplace_back(dummy);
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
namespace implementation

View file

@ -159,10 +159,10 @@ button_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg)
{
// Note the order should be the same as the enum state_t in button.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_pressed"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_pressed"));
state.emplace_back(cfg.optional_child("state_focused"));
}
// }---------- BUILDER -----------{

View file

@ -653,13 +653,13 @@ chatbox_definition::chatbox_definition(const config& cfg)
chatbox_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg), grid()
{
state.emplace_back(cfg.child("background"));
state.emplace_back(cfg.child("foreground"));
state.emplace_back(cfg.optional_child("background"));
state.emplace_back(cfg.optional_child("foreground"));
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
// }---------- BUILDER -----------{

View file

@ -23,6 +23,9 @@
#include "gui/core/register_widget.hpp"
#include "gui/widgets/settings.hpp"
#include "gettext.hpp"
#include "wml_exception.hpp"
#include <functional>
namespace gui2
@ -113,7 +116,7 @@ builder_drawing::builder_drawing(const config& cfg)
: builder_styled_widget(cfg)
, width(cfg["width"])
, height(cfg["height"])
, draw(cfg.child("draw"))
, draw(VALIDATE_WML_CHILD(cfg, "draw", _("Missing [draw] in drawing")))
{
assert(!draw.empty());
}

View file

@ -129,10 +129,10 @@ horizontal_scrollbar_definition::resolution::resolution(const config& cfg)
"minimum_positioner_length"));
// Note the order should be the same as the enum state_t is scrollbar.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_pressed"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_pressed"));
state.emplace_back(cfg.optional_child("state_focused"));
}
// }---------- BUILDER -----------{

View file

@ -110,7 +110,7 @@ image_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg)
{
// Note the order should be the same as the enum state_t in image.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
}
// }---------- BUILDER -----------{

View file

@ -237,8 +237,8 @@ label_definition::resolution::resolution(const config& cfg)
, link_color(cfg["link_color"].empty() ? color_t::from_hex_string("ffff00") : color_t::from_rgba_string(cfg["link_color"].str()))
{
// Note the order should be the same as the enum state_t is label.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
}
// }---------- BUILDER -----------{

View file

@ -706,11 +706,10 @@ listbox_definition::resolution::resolution(const config& cfg)
, grid(nullptr)
{
// Note the order should be the same as the enum state_t in listbox.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
const config& child = cfg.child("grid");
VALIDATE(child, _("No grid defined."));
auto child = VALIDATE_WML_CHILD(cfg, "grid", _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
}
@ -759,25 +758,25 @@ builder_listbox::builder_listbox(const config& cfg)
, has_minimum_(cfg["has_minimum"].to_bool(true))
, has_maximum_(cfg["has_maximum"].to_bool(true))
{
if(const config& h = cfg.child("header")) {
header = std::make_shared<builder_grid>(h);
if(auto h = cfg.optional_child("header")) {
header = std::make_shared<builder_grid>(*h);
}
if(const config& f = cfg.child("footer")) {
footer = std::make_shared<builder_grid>(f);
if(auto f = cfg.optional_child("footer")) {
footer = std::make_shared<builder_grid>(*f);
}
const config& l = cfg.child("list_definition");
auto l = cfg.optional_child("list_definition");
VALIDATE(l, _("No list defined."));
list_builder = std::make_shared<builder_grid>(l);
list_builder = std::make_shared<builder_grid>(*l);
assert(list_builder);
VALIDATE(list_builder->rows == 1, _("A 'list_definition' should contain one row."));
if(cfg.has_child("list_data")) {
list_data = parse_list_data(cfg.child("list_data"), list_builder->cols);
list_data = parse_list_data(cfg.mandatory_child("list_data"), list_builder->cols);
}
}
@ -810,17 +809,17 @@ builder_horizontal_listbox::builder_horizontal_listbox(const config& cfg)
, has_minimum_(cfg["has_minimum"].to_bool(true))
, has_maximum_(cfg["has_maximum"].to_bool(true))
{
const config& l = cfg.child("list_definition");
auto l = cfg.optional_child("list_definition");
VALIDATE(l, _("No list defined."));
list_builder = std::make_shared<builder_grid>(l);
list_builder = std::make_shared<builder_grid>(*l);
assert(list_builder);
VALIDATE(list_builder->rows == 1, _("A 'list_definition' should contain one row."));
if(cfg.has_child("list_data")) {
list_data = parse_list_data(cfg.child("list_data"), list_builder->cols);
list_data = parse_list_data(cfg.mandatory_child("list_data"), list_builder->cols);
}
}
@ -853,17 +852,17 @@ builder_grid_listbox::builder_grid_listbox(const config& cfg)
, has_minimum_(cfg["has_minimum"].to_bool(true))
, has_maximum_(cfg["has_maximum"].to_bool(true))
{
const config& l = cfg.child("list_definition");
auto l = cfg.optional_child("list_definition");
VALIDATE(l, _("No list defined."));
list_builder = std::make_shared<builder_grid>(l);
list_builder = std::make_shared<builder_grid>(*l);
assert(list_builder);
VALIDATE(list_builder->rows == 1, _("A 'list_definition' should contain one row."));
if(cfg.has_child("list_data")) {
list_data = parse_list_data(cfg.child("list_data"), list_builder->cols);
list_data = parse_list_data(cfg.mandatory_child("list_data"), list_builder->cols);
}
}

View file

@ -17,6 +17,7 @@
#include "gui/widgets/matrix.hpp"
#include "gettext.hpp"
#include "gui/auxiliary/find_widget.hpp"
#include "gui/auxiliary/iterator/walker.hpp"
#include "gui/core/log.hpp"
@ -184,11 +185,11 @@ matrix_definition::matrix_definition(const config& cfg)
matrix_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg)
, content(new builder_grid(cfg.child("content", "[matrix_definition]")))
, content(new builder_grid(VALIDATE_WML_CHILD(cfg, "content", _("Missing [content] in [matrix_definition]"))))
{
// Note the order should be the same as the enum state_t in matrix.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
}
// }---------- BUILDER -----------{
@ -206,22 +207,22 @@ builder_matrix::builder_matrix(const config& cfg)
, builder_bottom(nullptr)
, builder_left(nullptr)
, builder_right(nullptr)
, builder_main(create_widget_builder(cfg.child("main", "[matrix]")))
, builder_main(create_widget_builder(VALIDATE_WML_CHILD(cfg, "main", _("Missing [main] in [matrix]"))))
{
if(const config& top = cfg.child("top")) {
builder_top = std::make_shared<builder_grid>(top);
if(auto top = cfg.optional_child("top")) {
builder_top = std::make_shared<builder_grid>(*top);
}
if(const config& bottom = cfg.child("bottom")) {
builder_bottom = std::make_shared<builder_grid>(bottom);
if(auto bottom = cfg.optional_child("bottom")) {
builder_bottom = std::make_shared<builder_grid>(*bottom);
}
if(const config& left = cfg.child("left")) {
builder_left = std::make_shared<builder_grid>(left);
if(auto left = cfg.optional_child("left")) {
builder_left = std::make_shared<builder_grid>(*left);
}
if(const config& right = cfg.child("right")) {
builder_right = std::make_shared<builder_grid>(right);
if(auto right = cfg.optional_child("right")) {
builder_right = std::make_shared<builder_grid>(*right);
}
}

View file

@ -229,10 +229,10 @@ menu_button_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg)
{
// Note the order should be the same as the enum state_t in menu_button.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_pressed"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_pressed"));
state.emplace_back(cfg.optional_child("state_focused"));
}
// }---------- BUILDER -----------{

View file

@ -112,7 +112,7 @@ minimap_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg)
{
// Note the order should be the same as the enum state_t in minimap.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
}
// }---------- BUILDER -----------{

View file

@ -172,10 +172,10 @@ multi_page_definition::multi_page_definition(const config& cfg)
multi_page_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg), grid(nullptr)
{
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
// }---------- BUILDER -----------{
@ -195,13 +195,13 @@ builder_multi_page::builder_multi_page(const config& cfg)
VALIDATE(!builders.empty(), _("No page defined."));
/** @todo This part is untested. */
const config& d = cfg.child("page_data");
auto d = cfg.optional_child("page_data");
if(!d) {
return;
}
auto builder = builders.begin()->second;
for(const auto & row : d.child_range("row"))
for(const auto & row : d->child_range("row"))
{
unsigned col = 0;

View file

@ -252,10 +252,10 @@ multimenu_button_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg)
{
// Note the order should be the same as the enum state_t in multimenu_button.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_pressed"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_pressed"));
state.emplace_back(cfg.optional_child("state_focused"));
}
// }---------- BUILDER -----------{

View file

@ -358,7 +358,7 @@ builder_pane::builder_pane(const config& cfg)
: builder_widget(cfg)
, grow_dir(*grow_direction::get_enum(cfg["grow_direction"].str()))
, parallel_items(cfg["parallel_items"])
, item_definition(new builder_grid(cfg.child("item_definition", "[pane]")))
, item_definition(new builder_grid(VALIDATE_WML_CHILD(cfg, "item_definition", _("Missing [item_definition] in [pane]"))))
{
VALIDATE(parallel_items > 0, _("Need at least 1 parallel item."));
}

View file

@ -108,8 +108,8 @@ panel_definition::resolution::resolution(const config& cfg)
, right_border(cfg["right_border"])
{
// The panel needs to know the order.
state.emplace_back(cfg.child("background"));
state.emplace_back(cfg.child("foreground"));
state.emplace_back(cfg.optional_child("background"));
state.emplace_back(cfg.optional_child("foreground"));
}
// }---------- BUILDER -----------{
@ -120,11 +120,11 @@ namespace implementation
builder_panel::builder_panel(const config& cfg)
: builder_styled_widget(cfg), grid(nullptr)
{
const config& c = cfg.child("grid");
auto c = cfg.optional_child("grid");
VALIDATE(c, _("No grid defined."));
grid = std::make_shared<builder_grid>(c);
grid = std::make_shared<builder_grid>(*c);
}
std::unique_ptr<widget> builder_panel::build() const

View file

@ -91,7 +91,7 @@ progress_bar_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg)
{
// Note the order should be the same as the enum state_t in progress_bar.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
}
// }---------- BUILDER -----------{

View file

@ -179,10 +179,10 @@ repeating_button_definition::resolution::resolution(const config& cfg)
{
// Note the order should be the same as the enum state_t in
// repeating_button.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_pressed"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_pressed"));
state.emplace_back(cfg.optional_child("state_focused"));
}
// }---------- BUILDER -----------{

View file

@ -176,13 +176,13 @@ scroll_label_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg), grid(nullptr)
{
// Note the order should be the same as the enum state_t is scroll_label.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
// }---------- BUILDER -----------{

View file

@ -67,13 +67,13 @@ scrollbar_panel_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg), grid()
{
// The panel needs to know the order.
state.emplace_back(cfg.child("background"));
state.emplace_back(cfg.child("foreground"));
state.emplace_back(cfg.optional_child("background"));
state.emplace_back(cfg.optional_child("foreground"));
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
// }---------- BUILDER -----------{
@ -89,10 +89,10 @@ builder_scrollbar_panel::builder_scrollbar_panel(const config& cfg)
get_scrollbar_mode(cfg["horizontal_scrollbar_mode"]))
, grid_(nullptr)
{
const config& grid_definition = cfg.child("definition");
auto grid_definition = cfg.optional_child("definition");
VALIDATE(grid_definition, _("No list defined."));
grid_ = std::make_shared<builder_grid>(grid_definition);
grid_ = std::make_shared<builder_grid>(*grid_definition);
assert(grid_);
}

View file

@ -107,10 +107,10 @@ size_lock_definition::resolution::resolution(const config& cfg)
static config dummy("draw");
state.emplace_back(dummy);
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
namespace implementation
@ -122,7 +122,7 @@ builder_size_lock::builder_size_lock(const config& cfg)
, content_(nullptr)
{
VALIDATE(cfg.has_child("widget"), _("No widget defined."));
content_ = create_widget_builder(cfg.child("widget"));
content_ = create_widget_builder(cfg.mandatory_child("widget"));
}
std::unique_ptr<widget> builder_size_lock::build() const

View file

@ -310,10 +310,10 @@ slider_definition::resolution::resolution(const config& cfg)
VALIDATE(positioner_length, missing_mandatory_wml_key("resolution", "minimum_positioner_length"));
// Note the order should be the same as the enum state_t is slider.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_pressed"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_pressed"));
state.emplace_back(cfg.optional_child("state_focused"));
}
// }---------- BUILDER -----------{
@ -331,12 +331,12 @@ builder_slider::builder_slider(const config& cfg)
, maximum_value_label_(cfg["maximum_value_label"].t_str())
, value_labels_()
{
const config& labels = cfg.child("value_labels");
auto labels = cfg.optional_child("value_labels");
if(!labels) {
return;
}
for(const auto& label : labels.child_range("value")) {
for(const auto& label : labels->child_range("value")) {
value_labels_.push_back(label["label"]);
}
}

View file

@ -221,10 +221,10 @@ stacked_widget_definition::resolution::resolution(const config& cfg)
static config dummy("draw");
state.emplace_back(dummy);
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
// }---------- BUILDER -----------{
@ -235,7 +235,7 @@ namespace implementation
builder_stacked_widget::builder_stacked_widget(const config& real_cfg)
: builder_styled_widget(real_cfg), stack()
{
const config& cfg = real_cfg.has_child("stack") ? real_cfg.child("stack") : real_cfg;
const config& cfg = real_cfg.has_child("stack") ? real_cfg.mandatory_child("stack") : real_cfg;
if(&cfg != &real_cfg) {
lg::log_to_chat() << "Stacked widgets no longer require a [stack] tag. Instead, place [layer] tags directly in the widget definition.\n";
ERR_WML << "Stacked widgets no longer require a [stack] tag. Instead, place [layer] tags directly in the widget definition.";

View file

@ -273,8 +273,6 @@ void text_box::handle_mouse_selection(point mouse, const bool start_selection)
void text_box::update_offsets()
{
assert(config());
const auto conf = cast_config_to<text_box_definition>();
assert(conf);
@ -408,10 +406,10 @@ text_box_definition::resolution::resolution(const config& cfg)
, text_y_offset(cfg["text_y_offset"])
{
// Note the order should be the same as the enum state_t in text_box.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.child("state_hovered"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_focused"));
state.emplace_back(cfg.optional_child("state_hovered"));
}
// }---------- BUILDER -----------{

View file

@ -209,9 +209,9 @@ toggle_button_definition::resolution::resolution(const config& cfg)
// toggle_button.hpp.
for(const auto& c : cfg.child_range("state"))
{
state.emplace_back(c.child("enabled"));
state.emplace_back(c.child("disabled"));
state.emplace_back(c.child("focused"));
state.emplace_back(c.optional_child("enabled"));
state.emplace_back(c.optional_child("disabled"));
state.emplace_back(c.optional_child("focused"));
}
}

View file

@ -299,9 +299,9 @@ toggle_panel_definition::resolution::resolution(const config& cfg)
// Note the order should be the same as the enum state_t in toggle_panel.hpp.
for(const auto& c : cfg.child_range("state"))
{
state.emplace_back(c.child("enabled"));
state.emplace_back(c.child("disabled"));
state.emplace_back(c.child("focused"));
state.emplace_back(c.optional_child("enabled"));
state.emplace_back(c.optional_child("disabled"));
state.emplace_back(c.optional_child("focused"));
}
}
@ -316,11 +316,11 @@ builder_toggle_panel::builder_toggle_panel(const config& cfg)
, retval_id_(cfg["return_value_id"])
, retval_(cfg["return_value"])
{
const config& c = cfg.child("grid");
auto c = cfg.optional_child("grid");
VALIDATE(c, _("No grid defined."));
grid = std::make_shared<builder_grid>(c);
grid = std::make_shared<builder_grid>(*c);
}
std::unique_ptr<widget> builder_toggle_panel::build() const

View file

@ -265,13 +265,13 @@ tree_view_definition::resolution::resolution(const config& cfg)
, grid(nullptr)
{
// Note the order should be the same as the enum state_t is listbox.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
// }---------- BUILDER -----------{
@ -326,11 +326,11 @@ tree_node::tree_node(const config& cfg)
// TODO: interpolate this value into the error message
VALIDATE(id != tree_view::root_node_id, _("[node]id 'root' is reserved for the implementation."));
const config& node_definition = cfg.child("node_definition");
auto node_definition = cfg.optional_child("node_definition");
VALIDATE(node_definition, _("No node defined."));
builder = std::make_shared<builder_grid>(node_definition);
builder = std::make_shared<builder_grid>(*node_definition);
}
} // namespace implementation

View file

@ -608,13 +608,13 @@ unit_preview_pane_definition::unit_preview_pane_definition(const config& cfg)
unit_preview_pane_definition::resolution::resolution(const config& cfg)
: resolution_definition(cfg), grid()
{
state.emplace_back(cfg.child("background"));
state.emplace_back(cfg.child("foreground"));
state.emplace_back(cfg.optional_child("background"));
state.emplace_back(cfg.optional_child("foreground"));
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
VALIDATE(child, _("No grid defined."));
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
// }---------- BUILDER -----------{

View file

@ -119,10 +119,10 @@ vertical_scrollbar_definition::resolution::resolution(const config& cfg)
"minimum_positioner_length"));
// Note the order should be the same as the enum state_t in scrollbar.hpp.
state.emplace_back(cfg.child("state_enabled"));
state.emplace_back(cfg.child("state_disabled"));
state.emplace_back(cfg.child("state_pressed"));
state.emplace_back(cfg.child("state_focused"));
state.emplace_back(cfg.optional_child("state_enabled"));
state.emplace_back(cfg.optional_child("state_disabled"));
state.emplace_back(cfg.optional_child("state_pressed"));
state.emplace_back(cfg.optional_child("state_focused"));
}
// }---------- BUILDER -----------{

View file

@ -20,7 +20,9 @@
#include "gui/auxiliary/iterator/walker.hpp"
#include "gui/core/log.hpp"
#include "config.hpp"
#include "gettext.hpp"
#include "utils/const_clone.hpp"
#include "wml_exception.hpp"
#define LOG_SCOPE_HEADER "viewport [" + id() + "] " + __func__
#define LOG_HEADER LOG_SCOPE_HEADER + ':'
@ -167,7 +169,7 @@ namespace implementation
builder_viewport::builder_viewport(const config& cfg)
: builder_widget(cfg)
, widget_(create_widget_builder(cfg.child("widget", "[viewport]")))
, widget_(create_widget_builder(VALIDATE_WML_CHILD(cfg, "widget", _("Missing [widget] in [viewport]"))))
{
}

View file

@ -1308,12 +1308,12 @@ window_definition::window_definition(const config& cfg)
window_definition::resolution::resolution(const config& cfg)
: panel_definition::resolution(cfg), grid(nullptr)
{
const config& child = cfg.child("grid");
auto child = cfg.optional_child("grid");
// VALIDATE(child, _("No grid defined."));
/** @todo Evaluate whether the grid should become mandatory. */
if(child) {
grid = std::make_shared<builder_grid>(child);
grid = std::make_shared<builder_grid>(*child);
}
}

View file

@ -150,7 +150,7 @@ static bool is_cjk_char(const char32_t ch)
bool section_is_referenced(const std::string &section_id, const config &cfg)
{
if (const config &toplevel = cfg.child("toplevel"))
if (auto toplevel = cfg.optional_child("toplevel"))
{
const std::vector<std::string> toplevel_refs
= utils::quoted_split(toplevel["sections"]);
@ -174,7 +174,7 @@ bool section_is_referenced(const std::string &section_id, const config &cfg)
bool topic_is_referenced(const std::string &topic_id, const config &cfg)
{
if (const config &toplevel = cfg.child("toplevel"))
if (auto toplevel = cfg.optional_child("toplevel"))
{
const std::vector<std::string> toplevel_refs
= utils::quoted_split(toplevel["topics"]);
@ -218,10 +218,10 @@ void parse_config_internal(const config *help_cfg, const config *section_cfg,
std::vector<std::string>::const_iterator it;
// Find all child sections.
for (it = sections.begin(); it != sections.end(); ++it) {
if (const config &child_cfg = help_cfg->find_child("section", "id", *it))
if (auto child_cfg = help_cfg->find_child("section", "id", *it))
{
section child_section;
parse_config_internal(help_cfg, &child_cfg, child_section, level + 1);
parse_config_internal(help_cfg, child_cfg.ptr(), child_section, level + 1);
sec.add_section(child_section);
}
else {
@ -263,7 +263,7 @@ void parse_config_internal(const config *help_cfg, const config *section_cfg,
// Find all topics in this section.
for (it = topics_id.begin(); it != topics_id.end(); ++it) {
if (const config &topic_cfg = help_cfg->find_child("topic", "id", *it))
if (auto topic_cfg = help_cfg->find_child("topic", "id", *it))
{
std::string text = topic_cfg["text"];
text += generate_topic_text(topic_cfg["generator"], help_cfg, sec, generated_topics);
@ -304,8 +304,8 @@ section parse_config(const config *cfg)
{
section sec;
if (cfg != nullptr) {
const config& toplevel_cfg = cfg->child("toplevel");
parse_config_internal(cfg, toplevel_cfg ? &toplevel_cfg : nullptr, sec);
auto toplevel_cfg = cfg->optional_child("toplevel");
parse_config_internal(cfg, toplevel_cfg.ptr(), sec);
}
return sec;
}
@ -483,7 +483,7 @@ std::vector<topic> generate_weapon_special_topics(const bool sort_generated)
for(config adv : type.modification_advancements()) {
for(config effect : adv.child_range("effect")) {
if(effect["apply_to"] == "new_attack" && effect.has_child("specials")) {
for(config::any_child spec : effect.child("specials").all_children_range()) {
for(config::any_child spec : effect.mandatory_child("specials").all_children_range()) {
if(!spec.cfg["name"].empty()) {
special_description.emplace(spec.cfg["name"].t_str(), spec.cfg["description"].t_str());
if(!type.hide_help()) {
@ -500,7 +500,7 @@ std::vector<topic> generate_weapon_special_topics(const bool sort_generated)
}
}
} else if(effect["apply_to"] == "attack" && effect.has_child("set_specials")) {
for(config::any_child spec : effect.child("set_specials").all_children_range()) {
for(config::any_child spec : effect.mandatory_child("set_specials").all_children_range()) {
if(!spec.cfg["name"].empty()) {
special_description.emplace(spec.cfg["name"].t_str(), spec.cfg["description"].t_str());
if(!type.hide_help()) {
@ -611,9 +611,9 @@ std::vector<topic> generate_era_topics(const bool sort_generated, const std::str
{
std::vector<topic> topics;
const config & era = game_cfg->find_child("era","id", era_id);
auto era = game_cfg->find_child("era","id", era_id);
if(era && !era["hide_help"].to_bool()) {
topics = generate_faction_topics(era, sort_generated);
topics = generate_faction_topics(*era, sort_generated);
std::vector<std::string> faction_links;
for (const topic & t : topics) {
@ -1200,7 +1200,7 @@ UNIT_DESCRIPTION_TYPE description_type(const unit_type &type)
std::string generate_contents_links(const std::string& section_name, config const *help_cfg)
{
const config& section_cfg = help_cfg->find_child("section", "id", section_name);
auto section_cfg = help_cfg->find_child("section", "id", section_name);
if (!section_cfg) {
return std::string();
}
@ -1216,7 +1216,7 @@ std::string generate_contents_links(const std::string& section_name, config cons
std::vector<std::string>::iterator t;
// Find all topics in this section.
for (t = topics.begin(); t != topics.end(); ++t) {
if (const config& topic_cfg = help_cfg->find_child("topic", "id", *t)) {
if (auto topic_cfg = help_cfg->find_child("topic", "id", *t)) {
std::string id = topic_cfg["id"];
if (is_visible_id(id))
topics_links.emplace_back(topic_cfg["title"], id);

View file

@ -133,8 +133,8 @@ void help_text_area::set_items()
read(cfg, stream);
#define TRY(name) do { \
if (config &child = cfg.child(#name)) \
handle_##name##_cfg(child); \
if (auto child = cfg.optional_child(#name)) \
handle_##name##_cfg(*child); \
} while (0)
TRY(ref);

View file

@ -686,7 +686,7 @@ std::string unit_topic_generator::operator()() const {
for (const config & t : traits) {
if (t["availability"].str() == "musthave") {
for (const config & effect : t.child_range("effect")) {
if (!effect.child("filter") // If this is musthave but has a unit filter, it might not always apply, so don't apply it in the help.
if (!effect.has_child("filter") // If this is musthave but has a unit filter, it might not always apply, so don't apply it in the help.
&& movetype::effects.find(effect["apply_to"].str()) != movetype::effects.end()) {
movement_type.merge(effect, effect["replace"].to_bool());
}

View file

@ -1316,8 +1316,8 @@ protected:
"whiteboard_options", &console_handler::do_whiteboard_options, _("Access whiteboard options dialog."));
register_alias("whiteboard_options", "wbo");
if(const config& alias_list = preferences::get_alias()) {
for(const config::attribute& a : alias_list.attribute_range()) {
if(auto alias_list = preferences::get_alias()) {
for(const config::attribute& a : alias_list->attribute_range()) {
register_alias(a.second, a.first);
}
}
@ -1817,7 +1817,7 @@ void console_handler::do_choose_level()
// find scenarios of multiplayer campaigns
// (assumes that scenarios are ordered properly in the game_config)
std::string scenario_id = menu_handler_.pc_.get_mp_settings().mp_scenario;
if(const config& this_scenario = menu_handler_.game_config_.find_child(tag, "id", scenario_id)) {
if(auto this_scenario = menu_handler_.game_config_.find_child(tag, "id", scenario_id)) {
std::string addon_id = this_scenario["addon_id"].str();
for(const config& sc : menu_handler_.game_config_.child_range(tag)) {
if(sc["addon_id"] == addon_id) {

View file

@ -276,7 +276,7 @@ const teleport_map get_teleport_locations(const unit &u,
for (const unit_ability & teleport : u.get_abilities("teleport")) {
const int tunnel_count = (teleport.ability_cfg)->child_count("tunnel");
for(int i = 0; i < tunnel_count; ++i) {
config teleport_group_cfg = (teleport.ability_cfg)->child("tunnel", i);
config teleport_group_cfg = (teleport.ability_cfg)->mandatory_child("tunnel", i);
groups.emplace_back(vconfig(teleport_group_cfg, true), false);
}
}
@ -290,7 +290,7 @@ const teleport_map get_teleport_locations(const unit &u,
manager::manager(const config &cfg) : tunnels_(), id_(cfg["next_teleport_group_id"].to_int(0)) {
const int tunnel_count = cfg.child_count("tunnel");
for(int i = 0; i < tunnel_count; ++i) {
const config& t = cfg.child("tunnel", i);
const config& t = cfg.mandatory_child("tunnel", i);
if(!t["saved"].to_bool()) {
lg::log_to_chat() << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.\n";
ERR_WML << "Do not use [tunnel] directly in a [scenario]. Use it in an [event] or [abilities] tag.";

View file

@ -70,7 +70,7 @@ bool persist_file_context::clear_var(const std::string &global, bool immediate)
bool ret = active->has_child("variables");
if (ret) {
config &cfg = active->child("variables");
config &cfg = active->mandatory_child("variables");
bool exists = cfg.has_attribute(global);
if (!exists) {
if (cfg.has_child(global)) {
@ -100,7 +100,7 @@ bool persist_file_context::clear_var(const std::string &global, bool immediate)
name_space prev = working.prev();
active = get_node(cfg_, prev);
active->clear_children(working.node_);
if (active->has_child("variables") && active->child("variables").empty()) {
if (active->has_child("variables") && active->mandatory_child("variables").empty()) {
active->clear_children("variables");
active->remove_attribute("variables");
}
@ -149,7 +149,7 @@ bool persist_file_context::clear_var(const std::string &global, bool immediate)
break;
}
active->clear_children(namespace_.node_);
if (active->has_child("variables") && active->child("variables").empty()) {
if (active->has_child("variables") && active->mandatory_child("variables").empty()) {
active->clear_children("variables");
active->remove_attribute("variables");
}
@ -163,11 +163,11 @@ config persist_file_context::get_var(const std::string &global) const
config ret;
const config *active = get_node(cfg_, namespace_);
if (active && (active->has_child("variables"))) {
const config &cfg = active->child("variables");
const config &cfg = active->mandatory_child("variables");
std::size_t arrsize = cfg.child_count(global);
if (arrsize > 0) {
for (std::size_t i = 0; i < arrsize; i++)
ret.add_child(global,cfg.child(global,i));
ret.add_child(global, cfg.mandatory_child(global,i));
} else {
ret = pack_scalar(global,cfg[global]);
}

View file

@ -125,7 +125,7 @@ protected:
if (force)
return get_node(cfg.child_or_add(next.root_), next, true);
else if (cfg.has_child(next.root_))
return get_node(cfg.child(next.root_), next);
return get_node(cfg.mandatory_child(next.root_), next);
else
return nullptr;
}
@ -137,7 +137,7 @@ protected:
name_space next = ns.next();
if (next) {
if (cfg.has_child(next.root_))
return get_node(cfg.child(next.root_), next);
return get_node(cfg.mandatory_child(next.root_), next);
else
return nullptr;
}

Some files were not shown because too many files have changed in this diff Show more