The Battle for Wesnoth  1.15.0-dev
game_config_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2018 by Andrius Silinskas <silinskas.andrius@gmail.com>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 #include "game_config_manager.hpp"
15 
16 #include "about.hpp"
17 #include "addon/manager.hpp"
18 #include "ai/configuration.hpp"
19 #include "cursor.hpp"
20 #include "events.hpp"
21 #include "formatter.hpp"
22 #include "game_config.hpp"
23 #include "gettext.hpp"
24 #include "game_classification.hpp"
27 #include "hotkey/hotkey_item.hpp"
29 #include "language.hpp"
30 #include "log.hpp"
31 #include "preferences/general.hpp"
33 #include "terrain/builder.hpp"
34 #include "terrain/type_data.hpp"
35 #include "units/types.hpp"
36 #include "game_version.hpp"
37 #include "theme.hpp"
38 #include "picture.hpp"
40 
41 static lg::log_domain log_config("config");
42 #define ERR_CONFIG LOG_STREAM(err, log_config)
43 #define WRN_CONFIG LOG_STREAM(warn, log_config)
44 #define LOG_CONFIG LOG_STREAM(info, log_config)
45 
47 
49  const commandline_options& cmdline_opts,
50  const bool jump_to_editor) :
51  cmdline_opts_(cmdline_opts),
52  jump_to_editor_(jump_to_editor),
53  game_config_(),
54  old_defines_map_(),
55  paths_manager_(),
56  cache_(game_config::config_cache::instance())
57 {
58  assert(!singleton);
59  singleton = this;
60 
62  cache_.set_use_cache(false);
63  }
66  }
67 }
68 
70 {
71  assert(singleton);
72  singleton = nullptr;
73 }
74 
76  return singleton;
77 }
78 
80 {
81  // Add preproc defines according to the command line arguments.
82  game_config::scoped_preproc_define multiplayer("MULTIPLAYER",
87  game_config::scoped_preproc_define title_screen("TITLE_SCREEN",
89 
92 
94 
97 
98  // Load the standard hotkeys, then apply any player customizations.
101 
105 
106  return true;
107 }
108 
109 namespace {
110 /// returns true if every define in special is also defined in general
111 bool map_includes(const preproc_map& general, const preproc_map& special)
112 {
113  for (const preproc_map::value_type& pair : special)
114  {
115  preproc_map::const_iterator it = general.find(pair.first);
116  if (it == general.end() || it->second != pair.second) {
117  return false;
118  }
119  }
120  return true;
121 }
122 } // end anonymous namespace
123 
126 {
127  game_config::scoped_preproc_define debug_mode("DEBUG_MODE",
129 
130  // Game_config already holds requested config in memory.
131  if (!game_config_.empty()) {
132  if ((force_reload == NO_FORCE_RELOAD) && old_defines_map_ == cache_.get_preproc_map()) {
133  return;
134  }
135  if ((force_reload == NO_INCLUDE_RELOAD) && map_includes(old_defines_map_, cache_.get_preproc_map())) {
136  return;
137  }
138  }
139 
140  gui2::dialogs::loading_screen::display([this, force_reload, classification]() {
141  load_game_config(force_reload, classification);
142  });
143 }
144 
147 {
148  // Make sure that 'debug mode' symbol is set
149  // if command line parameter is selected
150  // also if we're in multiplayer and actual debug mode is disabled.
151 
152  // The loadscreen will erase the titlescreen.
153  // NOTE: even without loadscreen, needed after MP lobby.
154  try {
155  // Read all game configs.
156  // First we load all core configs, the mainline one and the ones from the addons.
157  // Validate the cores and discard the invalid.
158  // Then find the path to the selected core.
159  // Load the selected core.
160  // Handle terrains so that they are last loaded from the core.
161  // Load every compatible addon.
165 
166  // Start transaction so macros are shared.
167  game_config::config_cache_transaction main_transaction;
168 
169  config cores_cfg;
170  // Load mainline cores definition file.
171  cache_.get_config(game_config::path + "/data/cores.cfg", cores_cfg);
172 
173  // Append the $user_campaign_dir/*/cores.cfg files to the cores.
174  std::vector<std::string> user_dirs;
175  {
176  const std::string user_campaign_dir = filesystem::get_addons_dir();
177  std::vector<std::string> user_files;
178  filesystem::get_files_in_dir(user_campaign_dir, &user_files, &user_dirs,
180  }
181  for (const std::string& umc : user_dirs) {
182  const std::string cores_file = umc + "/cores.cfg";
183  if (filesystem::file_exists(cores_file)) {
184  config cores;
185  cache_.get_config(cores_file, cores);
186  cores_cfg.append(cores);
187  }
188  }
189 
190  // Validate every core
191  config valid_cores;
192  bool current_core_valid = false;
193  std::string wml_tree_root;
194  for (const config& core : cores_cfg.child_range("core")) {
195 
196  const std::string& id = core["id"];
197  if (id.empty()) {
200  _("Error validating data core."),
201  _("Found a core without id attribute.")
202  + '\n' + _("Skipping the core."));
203  });
204  continue;
205  }
206  if (*&valid_cores.find_child("core", "id", id)) {
209  _("Error validating data core."),
210  _("Core ID: ") + id
211  + '\n' + _("The ID is already in use.")
212  + '\n' + _("Skipping the core."));
213  });
214  continue;
215  }
216 
217  const std::string& path = core["path"];
221  _("Error validating data core."),
222  _("Core ID: ") + id
223  + '\n' + _("Core Path: ") + path
224  + '\n' + _("File not found.")
225  + '\n' + _("Skipping the core."));
226  });
227  continue;
228  }
229 
230  if (id == "default" && !current_core_valid) {
231  wml_tree_root = path;
232  }
233  if (id == preferences::core_id()) {
234  current_core_valid = true;
235  wml_tree_root = path;
236  }
237 
238  valid_cores.add_child("core", core); // append(core);
239  }
240 
241  if (!current_core_valid) {
244  _("Error loading core data."),
245  _("Core ID: ") + preferences::core_id()
246  + '\n' + _("Error loading the core with named id.")
247  + '\n' + _("Falling back to the default core."));
248  });
249  preferences::set_core_id("default");
250  }
251 
252  // check if we have a valid default core which should always be the case.
253  if (wml_tree_root.empty()) {
256  _("Error loading core data."),
257  _("Can't locate the default core.")
258  + '\n' + _("The game will now exit."));
259  });
260  throw;
261  }
262 
263  // Load the selected core
264  std::unique_ptr<schema_validation::schema_validator> validator;
266  validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location("schema/game_config.cfg")));
267  validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
268  }
269  cache_.get_config(filesystem::get_wml_location(wml_tree_root), game_config_, validator.get());
270  game_config_.append(valid_cores);
271 
272  main_transaction.lock();
273 
274  // Put the gfx rules aside so that we can prepend the add-on
275  // rules to them.
276  config core_terrain_rules;
277  core_terrain_rules.splice_children(game_config_, "terrain_graphics");
278 
280  load_addons_cfg();
281 
282  // If multiplayer campaign is being loaded, [scenario] tags should
283  // become [multiplayer] tags and campaign's id should be added to them
284  // to allow to recognize which scenarios belongs to a loaded campaign.
285  if (classification != nullptr) {
286  if (const config& campaign = game_config().find_child("campaign", "id", classification->campaign))
287  {
288  const bool require_campaign = campaign["require_campaign"].to_bool(true);
289  for (config& scenario : game_config_.child_range("scenario"))
290  {
291  scenario["require_scenario"] = require_campaign;
292  }
293  }
294  }
295 
296  // Extract the Lua scripts at toplevel.
299 
300  // Put the gfx rules back to game config.
301  game_config_.splice_children(core_terrain_rules, "terrain_graphics");
302 
304  set_unit_data();
306 
308  tdata_ = std::make_shared<terrain_type_data>(game_config_);
311  } catch(const game::error& e) {
312  ERR_CONFIG << "Error loading game configuration files\n" << e.message << '\n';
313 
314  // Try reloading without add-ons
315  if (!game_config::no_addons) {
316  game_config::no_addons = true;
319  _("Error loading custom game configuration files. The game will try without loading add-ons."),
320  e.message);
321  });
322  load_game_config(force_reload, classification);
323  } else if (preferences::core_id() != "default") {
326  _("Error loading custom game configuration files. The game will fallback to the default core files."),
327  e.message);
328  });
329  preferences::set_core_id("default");
330  game_config::no_addons = false;
331  load_game_config(force_reload, classification);
332  } else {
335  _("Error loading default core game configuration files. The game will now exit."),
336  e.message);
337  });
338  throw;
339  }
340  }
341 
343 
344  // Set new binary paths.
346 }
347 
349 {
350  const std::string user_campaign_dir = filesystem::get_addons_dir();
351 
352  std::vector<std::string> error_log;
353  std::vector<std::string> error_addons;
354  std::vector<std::string> user_dirs;
355  std::vector<std::string> user_files;
356 
357  filesystem::get_files_in_dir(user_campaign_dir, &user_files, &user_dirs,
359 
360  // Warn player about addons using the no-longer-supported single-file format.
361  for(const std::string& file : user_files) {
362  const int size_minus_extension = file.size() - 4;
363 
364  if(file.substr(size_minus_extension, file.size()) == ".cfg") {
365  ERR_CONFIG << "error reading usermade add-on '" << file << "'\n";
366 
367  error_addons.push_back(file);
368 
369  const int userdata_loc = file.find("data/add-ons") + 5;
370  const std::string log_msg = formatter()
371  << "The format '~"
372  << file.substr(userdata_loc)
373  << "' (for single-file add-ons) is not supported anymore, use '~"
374  << file.substr(userdata_loc, size_minus_extension - userdata_loc)
375  << "/_main.cfg' instead.";
376 
377  error_log.push_back(log_msg);
378  }
379  }
380 
381  // Rerun the directory scan using filename only, to get the addon_ids more easily.
382  user_files.clear();
383  user_dirs.clear();
384 
385  filesystem::get_files_in_dir(user_campaign_dir, nullptr, &user_dirs,
387 
388  // Load the addons.
389  for(const std::string& addon_id : user_dirs) {
390  log_scope2(log_config, "Loading add-on '" + addon_id + "'");
391  const std::string addon_dir = user_campaign_dir + "/" + addon_id;
392 
393  const std::string main_cfg = addon_dir + "/_main.cfg";
394  const std::string info_cfg = addon_dir + "/_info.cfg";
395 
396  if(!filesystem::file_exists(main_cfg)) {
397  continue;
398  }
399 
400  // Try to find this addon's metadata. Author publishing info (_server.pbl) is given
401  // precedence over addon sever-generated info (_info.cfg). If neither are found, it
402  // probably means the addon was installed manually and certain defaults will be used.
403  config metadata;
404 
405  if(have_addon_pbl_info(addon_id)) {
406  // Publishing info needs to be read from disk.
407  metadata = get_addon_pbl_info(addon_id);
408  } else if(filesystem::file_exists(info_cfg)) {
409  // Addon server-generated info can be fetched from cache.
410  config temp;
411  cache_.get_config(info_cfg, temp);
412 
413  metadata = temp.child_or_empty("info");
414  }
415 
416  std::string using_core = metadata["core"];
417  if(using_core.empty()) {
418  using_core = "default";
419  }
420 
421  // Skip add-ons not matching our current core. Cores themselves should be selectable
422  // at all times, so they aren't considered here.
423  if(!metadata.empty() && metadata["type"] != "core" && using_core != preferences::core_id()) {
424  continue;
425  }
426 
427  std::string addon_title = metadata["title"].str();
428  if(addon_title.empty()) {
429  addon_title = addon_id;
430  }
431 
432  version_info addon_version(metadata["version"]);
433 
434  try {
435  std::unique_ptr<schema_validation::schema_validator> validator;
437  validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location("schema/game_config.cfg")));
438  validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
439  }
440  // Load this addon from the cache to a config.
441  config umc_cfg;
442  cache_.get_config(main_cfg, umc_cfg, validator.get());
443 
444  static const std::set<std::string> tags_with_addon_id {
445  "era",
446  "modification",
447  "resource",
448  "multiplayer",
449  "scenario",
450  "campaign"
451  };
452 
453  // Annotate appropriate addon types with addon_id info.
454  for(auto child : umc_cfg.all_children_range()) {
455  if(tags_with_addon_id.count(child.key) > 0) {
456  auto& cfg = child.cfg;
457  cfg["addon_id"] = addon_id;
458  cfg["addon_title"] = addon_title;
459  // Note that this may reformat the string in a canonical form.
460  cfg["addon_version"] = addon_version.str();
461  }
462  }
463 
464  game_config_.append(std::move(umc_cfg));
465  } catch(const config::error& err) {
466  ERR_CONFIG << "error reading usermade add-on '" << main_cfg << "'" << std::endl;
467  ERR_CONFIG << err.message << '\n';
468  error_addons.push_back(main_cfg);
469  error_log.push_back(err.message);
470  } catch(const preproc_config::error& err) {
471  ERR_CONFIG << "error reading usermade add-on '" << main_cfg << "'" << std::endl;
472  ERR_CONFIG << err.message << '\n';
473  error_addons.push_back(main_cfg);
474  error_log.push_back(err.message);
475  } catch(const filesystem::io_exception&) {
476  ERR_CONFIG << "error reading usermade add-on '" << main_cfg << "'" << std::endl;
477  error_addons.push_back(main_cfg);
478  }
479  }
480 
481  if(!error_addons.empty()) {
482  const std::size_t n = error_addons.size();
483  const std::string& msg1 =
484  _n("The following add-on had errors and could not be loaded:",
485  "The following add-ons had errors and could not be loaded:",
486  n);
487  const std::string& msg2 =
488  _n("Please report this to the author or maintainer of this add-on.",
489  "Please report this to the respective authors or maintainers of these add-ons.",
490  n);
491 
492  const std::string& report = utils::join(error_log, "\n\n");
494  gui2::dialogs::wml_error::display(msg1, msg2, error_addons, report);
495  });
496  }
497 }
498 
500 {
501  config& hashes = game_config_.add_child("multiplayer_hashes");
502  for (const config &ch : game_config_.child_range("multiplayer")) {
503  hashes[ch["id"].str()] = ch.hash();
504  }
505 }
506 
508 {
509  game_config_.merge_children("units");
511  if(config &units = game_config_.child("units")) {
512  unit_types.set_config(units);
513  }
514 }
515 
517 {
518  // Rebuild addon version info cache.
520 
521  // Force a reload of configuration information.
523  old_defines_map_.clear();
526 
528 }
529 
531 {
534 }
535 
538 {
539  game_config::scoped_preproc_define difficulty(classification.difficulty,
540  !classification.difficulty.empty());
541  game_config::scoped_preproc_define campaign(classification.campaign_define,
542  !classification.campaign_define.empty());
543  game_config::scoped_preproc_define scenario(classification.scenario_define,
544  !classification.scenario_define.empty());
546  !classification.era_define.empty());
547  game_config::scoped_preproc_define multiplayer("MULTIPLAYER",
548  classification.campaign_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER);
550  classification.campaign_type == game_classification::CAMPAIGN_TYPE::MULTIPLAYER);
551 
552  //
553  // NOTE: these deques aren't used here, but the objects within are utilized as RAII helpers.
554  //
555 
556  typedef std::unique_ptr<game_config::scoped_preproc_define> define;
557 
558  std::deque<define> extra_defines;
559  for(const std::string& extra_define : classification.campaign_xtra_defines) {
560  extra_defines.emplace_back(new game_config::scoped_preproc_define(extra_define));
561  }
562 
563  std::deque<define> modification_defines;
564  for(const std::string& mod_define : classification.mod_defines) {
565  modification_defines.emplace_back(new game_config::scoped_preproc_define(mod_define, !mod_define.empty()));
566  }
567 
568  try {
570  } catch(const game::error&) {
572 
573  std::deque<define> previous_defines;
574  for(const preproc_map::value_type& preproc : old_defines_map_) {
575  previous_defines.emplace_back(new game_config::scoped_preproc_define(preproc.first));
576  }
577 
579 
580  throw;
581  }
582 
583  // This needs to be done in the main thread since this function (load_game_config_for_game)
584  // might be called from a loading screen worker thread (and currently is, in fact). If the
585  // image cache is purged from the worker thread, there's a possibility for a data race where
586  // the main thread accesses the image cache and the worker thread simultaneously clears it.
588 }
589 
591 {
592  game_config::scoped_preproc_define multiplayer("MULTIPLAYER", is_mp);
593  game_config::scoped_preproc_define test("TEST", is_test);
594  game_config::scoped_preproc_define mptest("MP_TEST", cmdline_opts_.mptest && is_mp);
595 ///During an mp game the default difficuly define is also defined so better already load it now if we alreeady must reload config cache.
597 
598  typedef std::unique_ptr<game_config::scoped_preproc_define> define;
599  try{
601  }
602  catch(const game::error&) {
604 
605  std::deque<define> previous_defines;
606  for (const preproc_map::value_type& preproc : old_defines_map_) {
607  previous_defines.emplace_back(new game_config::scoped_preproc_define(preproc.first));
608  }
609 
611 
612  throw;
613  }
614 }
void set_config(config &cfg)
Resets all data based on the provided config.
Definition: types.cpp:1113
Don&#39;t reload if the previous defines include the new defines.
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
bool mptest
True if –mp-test was given on the command line.
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:921
void set_paths(const config &cfg)
void clear_children(T... keys)
Definition: config.hpp:509
std::string era()
Definition: game.cpp:698
Interfaces for manipulating version numbers of engine, add-ons, etc.
game_classification * classification
Definition: resources.cpp:34
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:287
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
config & find_child(config_key_type key, const std::string &name, const std::string &value)
Returns the first child of tag key with a name attribute containing value.
Definition: config.cpp:836
static void set_known_themes(const config *cfg)
Definition: theme.cpp:928
void merge_children(const std::string &key)
All children with the given key will be merged into the first element with that key.
Definition: config.cpp:325
bool noaddons
True if –noaddons was given on the command line. Disables the loading of all add-ons.
void lock()
Lock the transaction so no more macros are added.
void set_scope_active(scope s, bool set)
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:280
child_itors child_range(config_key_type key)
Definition: config.cpp:362
filesystem::binary_paths_manager paths_manager_
static void progress(loading_stage stage=loading_stage::none)
const std::string DEFAULT_DIFFICULTY
The default difficulty setting for campaigns.
#define ERR_CONFIG
unit_type_data unit_types
Definition: types.cpp:1452
Don&#39;t reload if the previous defines equal the new defines.
static lg::log_domain log_config("config")
void load_config(const config &v)
static void add_color_info(const config &v, bool build_defaults)
Used to set and unset scoped defines to preproc_map.
void call_in_main_thread(const std::function< void(void)> &f)
Definition: events.cpp:819
void flush_cache()
Definition: picture.cpp:234
void clear_binary_paths_cache()
One of the realizations of serialization/validator.hpp abstract validator.
static void extract_preload_scripts(const config &game_config)
static game_config_manager * get()
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
void splice_children(config &src, const std::string &key)
Moves all the children with tag key from src to this.
Definition: config.cpp:626
void load_hotkeys()
Definition: general.cpp:993
std::ostringstream wrapper.
Definition: formatter.hpp:38
std::string campaign_define
If there is a define the campaign uses to customize data.
static UNUSEDNOWARN std::string _n(const char *str1, const char *str2, int n)
Definition: gettext.hpp:95
void set_force_valid_cache(bool force)
Enable/disable cache validation.
void set_core_id(const std::string &core_id)
Definition: general.cpp:319
static game_config_manager * singleton
std::string path
Definition: game_config.cpp:39
boost::optional< std::string > test
Non-empty if –test was given on the command line. Goes directly into test mode, into a scenario...
void init_textdomains(const config &cfg)
Initializes the list of textdomains from a configuration object.
Definition: language.cpp:303
#define log_scope2(domain, description)
Definition: log.hpp:187
bool multiplayer
True if –multiplayer was given on the command line. Goes directly into multiplayer mode...
void refresh_addon_version_info_cache()
Refreshes the per-session cache of add-on&#39;s version information structs.
Definition: manager.cpp:283
std::string campaign
The id of the campaign being played.
void deactivate_all_scopes()
log_domain & general()
Definition: log.cpp:104
config get_addon_pbl_info(const std::string &addon_name)
Gets the publish information for an add-on.
Definition: manager.cpp:79
std::string era_define
If there is a define the era uses to customize data.
void get_config(const std::string &path, config &cfg, abstract_validator *validator=nullptr)
Gets a config object from given path.
void set_use_cache(bool use)
Enable/disable caching.
void clear_defines()
Clear stored defines map to default values.
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, file_name_option mode, file_filter_option filter, file_reorder_option reorder, file_tree_checksum *checksum)
Populates &#39;files&#39; with all the files and &#39;dirs&#39; with all the directories in dir.
Definition: filesystem.cpp:366
game_config_manager(const commandline_options &cmdline_opts, const bool jump_to_editor)
bool nocache
True if –nocache was given on the command line. Disables cache usage.
logger & err()
Definition: log.cpp:78
std::vector< std::string > campaign_xtra_defines
more customization of data
std::string get_wml_location(const std::string &filename, const std::string &current_dir)
Returns a complete path to the actual WML file or directory or an empty string if the file isn&#39;t pres...
bool have_addon_pbl_info(const std::string &addon_name)
Returns true if there&#39;s a local .pbl file stored for the specified add-on.
Definition: manager.cpp:74
void load_game_config_for_create(bool is_mp, bool is_test=false)
Game configuration data as global variables.
Definition: build_info.cpp:49
const preproc_map & get_preproc_map() const
An exception object used when an IO error occurs.
Definition: filesystem.hpp:48
void reset_color_info()
std::string scenario_define
If there is a define the scenario uses to customize data.
std::vector< std::string > mod_defines
If there are defines the modifications use to customize data.
Definitions related to theme-support.
const bool & debug
Definitions for the terrain builder.
static void display(const std::string &summary, const std::string &post_summary, const std::vector< std::string > &files, const std::string &details)
The display function; see modal_dialog for more information.
Definition: wml_error.hpp:43
Represents version numbers.
config & add_child(config_key_type key)
Definition: config.cpp:476
const file_tree_checksum & data_tree_checksum(bool reset=false)
Get the time at which the data/ tree was last modified at.
std::string difficulty
The difficulty level the game is being played on.
std::string core_id()
Definition: general.cpp:313
void set_about(const config &cfg)
Regenerates the credits config.
Definition: about.cpp:106
Used to share macros between cache objects You have to create transaction object to load all macros t...
static void display(std::function< void()> f)
void load_game_config_for_game(const game_classification &classification)
static void set_terrain_rules_cfg(const config &cfg)
Set the config where we will parse the global terrain rules.
Definition: builder.cpp:290
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
void load_hotkeys(const config &cfg, bool set_as_default)
Iterates through all hotkeys present in the config struct and creates and adds them to the hotkey lis...
std::string get_addons_dir()
Managing the AIs configuration - headers.
bool validate_core
True if –validate-core was given on the command line. Makes Wesnoth validate the core WML...
Standard logging facilities (interface).
std::string str() const
Serializes the version number into string form.
std::string message
Definition: exceptions.hpp:31
const commandline_options & cmdline_opts_
bool validcache
True if –validcache was given on the command line. Makes Wesnoth assume the cache is valid...
bool init_strings(const config &cfg)
Initializes certain English strings.
Definition: language.cpp:326
game_config::config_cache & cache_
std::map< std::string, struct preproc_define > preproc_map
#define e
Realization of serialization/validator.hpp abstract validator.
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:453
static void init(const config &game_config)
Init the parameters of ai configuration parser.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
static map_location::DIRECTION n
bool init_game_config(FORCE_RELOAD_CONFIG force_reload)
std::string hash() const
Definition: config.cpp:1322
bool empty() const
Definition: config.cpp:884
boost::optional< std::string > validate_addon
Non-empty if –validate-addon was given on the command line. Makes Wesnoth validate an addon&#39;s WML...
const config & game_config() const
void load_game_config(FORCE_RELOAD_CONFIG force_reload, game_classification const *classification=nullptr)
void recheck_filetree_checksum()
Force cache checksum validation.
void load_game_config_with_loadscreen(FORCE_RELOAD_CONFIG force_reload, game_classification const *classification=nullptr)