add config::find_mandatory_child

unlike find_child which returns an optional, this returns
reference, and throws when no such child is found.

This was intended but forgottten for the
"deploy optional_child" commit.

This fixes some codes that used config::find_child and
relied on the throwing behaviour by catching config::error
This commit is contained in:
gfgtdf 2023-04-07 23:08:49 +02:00
parent 242a9874c8
commit 246a3a5609
13 changed files with 65 additions and 25 deletions

View File

@ -808,6 +808,24 @@ optional_config config::find_child(config_key_type key, const std::string& name,
return std::nullopt;
}
config& config::find_mandatory_child(config_key_type key, const std::string &name, const std::string &value)
{
auto res = find_child(key, name, value);
if(res) {
return *res;
}
throw error("Cannot find child [" + std::string(key) + "] with " + name + "=" + value);
}
const config& config::find_mandatory_child(config_key_type key, const std::string &name, const std::string &value) const
{
auto res = find_child(key, name, value);
if(res) {
return *res;
}
throw error("Cannot find child [" + std::string(key) + "] with " + name + "=" + value);
}
void config::clear()
{
// No validity check for this function.

View File

@ -623,6 +623,13 @@ public:
const std::string &value) const
{ return const_cast<config *>(this)->find_child(key, name, value); }
config& find_mandatory_child(config_key_type key, const std::string &name,
const std::string &value);
const config& find_mandatory_child(config_key_type key, const std::string &name,
const std::string &value) const;
private:
void clear_children_impl(config_key_type key);
public:

View File

@ -953,14 +953,14 @@ void context_manager::revert_map()
void context_manager::new_map(int width, int height, const t_translation::terrain_code& fill, bool new_context)
{
auto default_schedule = game_config_.find_child("editor_times", "id", "empty");
const config& default_schedule = game_config_.find_mandatory_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);
}
}
@ -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);
auto default_schedule = game_config_.find_child("editor_times", "id", "empty");
add_map_context(editor_map(44, 33, default_terrain), true, *default_schedule);
const config& default_schedule = game_config_.find_mandatory_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_mandatory_child("editor_times", "id", "empty")))
, mp_settings_()
, game_classification_()
, music_tracks_()

View File

@ -60,6 +60,15 @@ optional_const_config game_config_view::find_child(config_key_type key, const st
return optional_const_config();
}
const config& game_config_view::find_mandatory_child(config_key_type key, const std::string &name, const std::string &value) const
{
auto res = find_child(key, name, value);
if(res) {
return *res;
}
throw config::error("Cannot find child [" + std::string(key) + "] with " + name + "=" + value);
}
const config& game_config_view::mandatory_child(config_key_type key) const
{
for(const config& cfg : cfgs_) {

View File

@ -22,6 +22,11 @@
using config_array_view = std::vector<std::reference_wrapper<const config>>;
/**
* A class grating read only view to a vector of config objects, viewed as one config
* with all children appended, used by the game_config class to read data from addons
* config, and from the main config.
**/
class game_config_view
{
@ -37,6 +42,7 @@ public:
config_array_view child_range(config_key_type key) const;
optional_const_config find_child(config_key_type key, const std::string &name, const std::string &value) const;
const config& find_mandatory_child(config_key_type key, const std::string &name, const std::string &value) const;
// const config& child(config_key_type key) const;
const config& mandatory_child(config_key_type key) const;

View File

@ -375,9 +375,9 @@ void create_engine::prepare_for_new_level()
void create_engine::prepare_for_era_and_mods()
{
get_parameters();
state_.classification().era_define = game_config_.find_child("era", "id", state_.classification().era_id)["define"].str();
state_.classification().era_define = game_config_.find_mandatory_child("era", "id", state_.classification().era_id)["define"].str();
for(const std::string& mod_id : state_.classification().active_mods) {
state_.classification().mod_defines.push_back(game_config_.find_child("modification", "id", mod_id)["define"].str());
state_.classification().mod_defines.push_back(game_config_.find_mandatory_child("modification", "id", mod_id)["define"].str());
}
}

View File

@ -155,7 +155,7 @@ bool manager::exists(const elem& e) const
std::string manager::find_name_for(const elem& e) const
{
auto cfg = depinfo_.find_child(e.type, "id", e.id);
auto cfg = depinfo_.find_mandatory_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_mandatory_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_mandatory_child(elem1.type, "id", elem1.id);
config data2 = depinfo_.find_mandatory_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_mandatory_child(elem1.type, "id", elem1.id);
if(data.has_attribute("force_modification")) {
std::vector<std::string> required = utils::split(data["force_modification"]);
@ -440,7 +440,7 @@ bool manager::enable_mods_dialog(const std::vector<std::string>& mods, const std
{
std::vector<std::string> items;
for(const std::string& mod : mods) {
items.push_back(depinfo_.find_child("modification", "id", mod)["name"]);
items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
}
return gui2::dialogs::depcheck_confirm_change::execute(true, items, requester);
@ -450,7 +450,7 @@ bool manager::disable_mods_dialog(const std::vector<std::string>& mods, const st
{
std::vector<std::string> items;
for(const std::string& mod : mods) {
items.push_back(depinfo_.find_child("modification", "id", mod)["name"]);
items.push_back(depinfo_.find_mandatory_child("modification", "id", mod)["name"]);
}
return gui2::dialogs::depcheck_confirm_change::execute(false, items, requester);
@ -460,7 +460,7 @@ std::string manager::change_era_dialog(const std::vector<std::string>& eras)
{
std::vector<std::string> items;
for(const std::string& era : eras) {
items.push_back(depinfo_.find_child("era", "id", era)["name"]);
items.push_back(depinfo_.find_mandatory_child("era", "id", era)["name"]);
}
gui2::dialogs::depcheck_select_new dialog(ERA, items);
@ -476,7 +476,7 @@ std::string manager::change_scenario_dialog(const std::vector<std::string>& scen
{
std::vector<std::string> items;
for(const std::string& scenario : scenarios) {
items.push_back(depinfo_.find_child("scenario", "id", scenario)["name"]);
items.push_back(depinfo_.find_mandatory_child("scenario", "id", scenario)["name"]);
}
gui2::dialogs::depcheck_select_new dialog(SCENARIO, items);

View File

@ -111,8 +111,8 @@ config initial_level_config(saved_game& state)
// 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.
auto custom_side = game_config.find_child("multiplayer_side", "id", "Custom");
level.mandatory_child("era").add_child_at("multiplayer_side", *custom_side, 0);
const config& custom_side = game_config.find_mandatory_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.

View File

@ -1283,7 +1283,7 @@ std::string default_map_generator_job::default_generate_map(generator_data data,
const std::string str = t_translation::write_terrain_code(terrain[res.x][res.y]);
const std::string& convert_to = cfg.find_child("village", "terrain", str)["convert_to"].str();
const std::string& convert_to = cfg.find_mandatory_child("village", "terrain", str)["convert_to"].str();
if(convert_to.empty()) {
continue;
}

View File

@ -433,7 +433,7 @@ void game_load::evaluate_summary_string(std::stringstream& str, const config& cf
if (campaign != nullptr) {
str << "\n" << _("Difficulty: ");
try {
auto difficulty = campaign->find_child("difficulty", "define", cfg_summary["difficulty"]);
const config& difficulty = campaign->find_mandatory_child("difficulty", "define", cfg_summary["difficulty"]);
std::ostringstream ss;
ss << difficulty["label"] << " (" << difficulty["description"] << ")";
str << ss.str();
@ -463,7 +463,7 @@ void game_load::evaluate_summary_string(std::stringstream& str, const config& cf
for(const auto& mod_id : active_mods) {
std::string mod_name;
try {
mod_name = cache_config_.find_child("modification", "id", mod_id)["name"].str();
mod_name = cache_config_.find_mandatory_child("modification", "id", mod_id)["name"].str();
} catch(const config::error&) {
// Fallback to nontranslatable mod id.
mod_name = "(" + mod_id + ")";

View File

@ -1311,7 +1311,7 @@ int game_lua_kernel::impl_game_config_get(lua_State *L)
if(classification.type==campaign_type::type::multiplayer) {
return_cfgref_attrib_deprecated("mp_settings", "wesnoth.game_config", INDEFINITE, "1.17", "Use wesnoth.scenario.mp_settings instead", mp_settings.to_config());
return_cfgref_attrib_deprecated("era", "wesnoth.game_config", INDEFINITE, "1.17", "Use wesnoth.scenario.era instead",
*game_config_manager::get()->game_config().find_child("era","id",classification.era_id));
game_config_manager::get()->game_config().find_mandatory_child("era","id",classification.era_id));
//^ finds the era with name matching mp_era, and creates a lua reference from the config of that era.
}
@ -1353,7 +1353,7 @@ int game_lua_kernel::impl_game_config_set(lua_State *L)
namespace {
static config find_addon(const std::string& type, const std::string& id)
{
return *game_config_manager::get()->game_config().find_child(type, "id", id);
return game_config_manager::get()->game_config().find_mandatory_child(type, "id", id);
}
}

View File

@ -65,7 +65,7 @@ struct mp_connect_fixture {
state->mp_settings().use_map_settings = true;
state->mp_settings().saved_game = saved_game_mode::type::no;
state->set_scenario(*config_manager->game_config().find_child("multiplayer", "id", state->mp_settings().name));
state->set_scenario(config_manager->game_config().find_mandatory_child("multiplayer", "id", state->mp_settings().name));
state->mp_settings().num_turns = state->get_starting_point()["turns"];