The Battle for Wesnoth  1.19.18+dev
game_config_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2025
3  by Andrius Silinskas <silinskas.andrius@gmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "game_config_manager.hpp"
17 
18 #include "about.hpp"
19 #include "addon/manager.hpp"
20 #include "ai/configuration.hpp"
21 #include "events.hpp"
22 #include "formatter.hpp"
23 #include "formula/string_utils.hpp"
24 #include "game_classification.hpp"
25 #include "game_config.hpp"
26 #include "game_version.hpp"
27 #include "gettext.hpp"
30 #include "hotkey/hotkey_item.hpp"
31 #include "language.hpp"
32 #include "log.hpp"
33 #include "picture.hpp"
37 #include "sound.hpp"
39 #include "terrain/builder.hpp"
40 #include "terrain/type_data.hpp"
41 #include "theme.hpp"
42 #include "units/types.hpp"
43 
44 static lg::log_domain log_config("config");
45 #define ERR_CONFIG LOG_STREAM(err, log_config)
46 #define WRN_CONFIG LOG_STREAM(warn, log_config)
47 #define LOG_CONFIG LOG_STREAM(info, log_config)
48 
50 
52 
54  : cmdline_opts_(cmdline_opts)
55  , game_config_()
56  , game_config_view_()
57  , addon_cfgs_()
58  , active_addons_()
59  , old_defines_map_()
60  , paths_manager_()
61  , cache_(game_config::config_cache::instance())
62  , tdata_(game_config())
63  , achievements_()
64 {
65  assert(!singleton);
66  singleton = this;
67 
68  // All of the validation options imply --nocache, as the validation happens during cache
69  // rebuilding. If the cache isn't rebuilt, validation is silently skipped.
71  cache_.set_use_cache(false);
72  }
73 
76  }
77 
78  // Clean the cache of any old Wesnoth version's cache data
79  if(const std::string last_cleaned = prefs::get()._last_cache_cleaned_ver(); !last_cleaned.empty()) {
80  if(version_info{last_cleaned} < game_config::wesnoth_version) {
81  if(cache_.clean_cache()) {
82  prefs::get().set__last_cache_cleaned_ver(game_config::wesnoth_version.str());
83  }
84  }
85  } else {
86  // If the preference wasn't set, set it, else the cleaning will never happen :P
87  prefs::get().set__last_cache_cleaned_ver(game_config::wesnoth_version.str());
88  }
89 }
90 
92 {
93  assert(singleton);
94  singleton = nullptr;
95 }
96 
98 {
99  return singleton;
100 }
101 
103 {
104  // Add preproc defines according to the command line arguments.
106  game_config::scoped_preproc_define test("TEST", cmdline_opts_.test.has_value());
109 #ifdef __ANDROID__
110  game_config::scoped_preproc_define android("ANDROID", true);
111 #endif
112  game_config::scoped_preproc_define title_screen("TITLE_SCREEN",
114 
116 
117  load_game_config_with_loadscreen(force_reload, nullptr, "");
118 
119  game_config::load_config(game_config().mandatory_child("game_config"));
120 
121  // It's necessary to block the event thread while load_hotkeys() runs, otherwise keyboard input
122  // can cause a crash by accessing the list of hotkeys while it's being modified.
123  events::call_in_main_thread([this]() {
124  const hotkey::scope_changer hk_scope{hotkey::scope_main, false};
125 
126  // Load the standard hotkeys, then apply any player customizations.
129  });
130 
132 
136 
137  return true;
138 }
139 
140 namespace
141 {
142 /** returns true if every define in special is also defined in general */
143 bool map_includes(const preproc_map& general, const preproc_map& special)
144 {
145  return std::all_of(special.begin(), special.end(), [&general](const auto& pair) {
146  const auto it = general.find(pair.first);
147  return it != general.end() && it->second == pair.second;
148  });
149 }
150 } // end anonymous namespace
151 
153  FORCE_RELOAD_CONFIG force_reload, const game_classification* classification, const std::string& scenario_id)
154 {
155  if(!lg::info().dont_log(log_config)) {
156  auto out = formatter();
157  out << "load_game_config: defines:";
158 
159  for(const auto& pair : cache_.get_preproc_map()) {
160  out << pair.first << ",";
161  }
162 
163  out << "\n";
164  FORCE_LOG_TO(lg::info(), log_config) << out.str();
165  }
166 
167  game_config::scoped_preproc_define debug_mode("DEBUG_MODE",
169 
170  bool reload_everything = true;
171 
172  // Game_config already holds requested config in memory.
173  if(!game_config_.empty()) {
174  if(force_reload == NO_FORCE_RELOAD && old_defines_map_ == cache_.get_preproc_map()) {
175  reload_everything = false;
176  }
177 
178  if(force_reload == NO_INCLUDE_RELOAD && map_includes(old_defines_map_, cache_.get_preproc_map())) {
179  reload_everything = false;
180  }
181  }
182 
183  LOG_CONFIG << "load_game_config reload everything: " << reload_everything;
184 
185  gui2::dialogs::loading_screen::display([this, reload_everything, classification, scenario_id]() {
186  load_game_config(reload_everything, classification, scenario_id);
187  });
188 }
189 
190 void game_config_manager::load_game_config(bool reload_everything, const game_classification* classification, const std::string& scenario_id)
191 {
192  // Make sure that 'debug mode' symbol is set
193  // if command line parameter is selected
194  // also if we're in multiplayer and actual debug mode is disabled.
195 
196  // The loadscreen will erase the titlescreen.
197  // NOTE: even without loadscreen, needed after MP lobby.
198  try {
199  // Read all game configs.
200  // First we load all core configs, the mainline one and the ones from the addons.
201  // Validate the cores and discard the invalid.
202  // Then find the path to the selected core.
203  // Load the selected core.
204  // Handle terrains so that they are last loaded from the core.
205  // Load every compatible addon.
206  if(reload_everything) {
210 
211  // Start transaction so macros are shared.
212  game_config::config_cache_transaction main_transaction;
214 
215  // Load mainline cores definition file.
216  config cores_cfg = cache_.get_config(game_config::path + "/data/cores.cfg");
217 
218  // Append the $user_campaign_dir/*/cores.cfg files to the cores.
219  std::vector<std::string> user_dirs;
220  {
221  const std::string user_campaign_dir = filesystem::get_addons_dir();
222  std::vector<std::string> user_files;
224  user_campaign_dir, &user_files, &user_dirs, filesystem::name_mode::ENTIRE_FILE_PATH);
225  }
226 
227  for(const std::string& umc : user_dirs) {
228  const std::string cores_file = umc + "/cores.cfg";
229  if(filesystem::file_exists(cores_file)) {
230  cores_cfg.append(cache_.get_config(cores_file));
231  }
232  }
233 
234  // Validate every core
235  config valid_cores;
236  bool current_core_valid = false;
237  std::string wml_tree_root;
238 
239  for(const config& core : cores_cfg.child_range("core")) {
240  const std::string& id = core["id"];
241  if(id.empty()) {
244  _("Error validating data core."),
245  _("Found a core without id attribute.")
246  + '\n' + _("Skipping the core."));
247  });
248  continue;
249  }
250 
251  if(valid_cores.find_child("core", "id", id)) {
254  _("Error validating data core."),
255  _("Core ID: ") + id
256  + '\n' + _("The ID is already in use.")
257  + '\n' + _("Skipping the core."));
258  });
259  continue;
260  }
261 
262  const std::string& path = core["path"];
266  _("Error validating data core."),
267  _("Core ID: ") + id
268  + '\n' + _("Core Path: ") + path
269  + '\n' + _("File not found.")
270  + '\n' + _("Skipping the core."));
271  });
272  continue;
273  }
274 
275  if(id == "default" && !current_core_valid) {
276  wml_tree_root = path;
277  }
278  if(id == prefs::get().core()) {
279  current_core_valid = true;
280  wml_tree_root = path;
281  }
282 
283  valid_cores.add_child("core", core); // append(core);
284  }
285 
286  if(!current_core_valid) {
289  _("Error loading core data."),
290  _("Core ID: ") + prefs::get().core()
291  + '\n' + _("Error loading the core with named id.")
292  + '\n' + _("Falling back to the default core."));
293  });
294  prefs::get().set_core("default");
295  }
296 
297  // check if we have a valid default core which should always be the case.
298  if(wml_tree_root.empty()) {
301  _("Error loading core data."),
302  _("Can’t locate the default core.")
303  + '\n' + _("The game will now exit."));
304  });
305  throw;
306  }
307 
308  // Load the selected core
309  std::unique_ptr<schema_validation::schema_validator> validator;
311  validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location("schema/game_config.cfg").value()));
312  validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
313  }
314 
315  game_config_ = cache_.get_config(filesystem::get_wml_location(wml_tree_root).value(), validator.get());
316  game_config_.append(valid_cores);
317 
318  main_transaction.lock();
319 
321  load_addons_cfg();
322  }
323  }
324 
325  // only after addon configs have been loaded do we check for which addons are needed and whether they exist to be used
326  LOG_CONFIG << "active_addons_ has size " << active_addons_.size() << " and contents: " << utils::join(active_addons_);
327  if(classification) {
328  LOG_CONFIG << "Enabling only some add-ons!";
329  std::set<std::string> active_addons = classification->active_addons(scenario_id);
330  // IMPORTANT: this is a significant performance optimization, particularly for the worst case example of the batched WML unit tests
331  if(!reload_everything && active_addons == active_addons_) {
332  LOG_CONFIG << "Configs not reloaded and active add-ons remain the same; returning early.";
333  LOG_CONFIG << "active_addons has size " << active_addons_.size() << " and contents: " << utils::join(active_addons);
334  return;
335  }
336  active_addons_ = active_addons;
338  } else {
339  LOG_CONFIG << "Enabling all add-ons!";
341  }
342 
343  // Extract the Lua scripts at toplevel.
345 
346  set_unit_data();
348  tdata_.reset();
351 
353 
355 
356  } catch(const game::error& e) {
357  ERR_CONFIG << "Error loading game configuration files\n" << e.message;
358 
359  // Try reloading without add-ons
361  game_config::no_addons = true;
364  _("Error loading custom game configuration files. The game will try without loading add-ons."),
365  e.message);
366  });
367  load_game_config(reload_everything, classification, scenario_id);
368  } else if(prefs::get().core() != "default") {
371  _("Error loading custom game configuration files. The game will fallback to the default core files."),
372  e.message);
373  });
374  prefs::get().set_core("default");
375  game_config::no_addons = false;
376  load_game_config(reload_everything, classification, scenario_id);
377  } else {
380  _("Error loading default core game configuration files. The game will now exit."),
381  e.message);
382  });
383  throw;
384  }
385  }
386 
388 
389  // Set new binary paths.
391 }
392 static void show_deprecated_warnings(config& umc_cfg)
393 {
394  for(auto& units : umc_cfg.child_range("units")) {
395  for(auto& unit_type : units.child_range("unit_type")) {
396  for(const auto& advancefrom : unit_type.child_range("advancefrom")) {
397  auto symbols = utils::string_map {
398  {"lower_level", advancefrom["unit"].str()},
399  {"higher_level", unit_type["id"].str()}
400  };
401  auto message = VGETTEXT(
402  // TRANSLATORS: For example, 'Cuttle Fish' units will not be able to advance to 'Kraken'.
403  // The substituted strings are unit ids, not translated names; hopefully any add-ons
404  // that trigger this will be quickly fixed and stop triggering the warning.
405  "Error: [advancefrom] no longer works. ‘$lower_level’ units will not be able to advance to ‘$higher_level’; please ask the add-on author to use [modify_unit_type] instead.",
406  symbols);
407  deprecated_message("[advancefrom]", DEP_LEVEL::REMOVED, {1, 15, 4}, message);
408  }
409  unit_type.remove_children("advancefrom");
410  }
411  }
412 
413 
414  // hardcoded list of 1.14 advancement macros, just used for the error mesage below.
415  static const std::set<std::string> deprecated_defines {
416  "ENABLE_PARAGON",
417  "DISABLE_GRAND_MARSHAL",
418  "ENABLE_ARMAGEDDON_DRAKE",
419  "ENABLE_DWARVISH_ARCANISTER",
420  "ENABLE_DWARVISH_RUNESMITH",
421  "ENABLE_WOLF_ADVANCEMENT",
422  "ENABLE_NIGHTBLADE",
423  "ENABLE_TROLL_SHAMAN",
424  "ENABLE_ANCIENT_LICH",
425  "ENABLE_DEATH_KNIGHT",
426  "ENABLE_WOSE_SHAMAN"
427  };
428 
429  for(auto& campaign : umc_cfg.child_range("campaign")) {
430  for(auto str : utils::split(campaign["extra_defines"])) {
431  if(deprecated_defines.count(str) > 0) {
432  //TODO: we could try to implement a compatibility path by
433  // somehow getting the content of that macro from the
434  // cache_ object, but considering that 1) the breakage
435  // isn't that bad (just one disabled unit) and 2)
436  // it before also didn't work in all cases (see #4402)
437  // i don't think it is worth it.
439  "campaign id='" + campaign["id"].str() + "' has extra_defines=" + str,
441  {1, 15, 4},
442  _("instead, use the macro with the same name in the [campaign] tag")
443  );
444  }
445  }
446  }
447 }
448 
450 {
451  const std::string user_campaign_dir = filesystem::get_addons_dir();
452 
453  std::vector<std::string> error_log;
454  std::vector<std::string> error_addons;
455  std::vector<std::string> user_dirs;
456  std::vector<std::string> user_files;
457 
458  filesystem::get_files_in_dir(user_campaign_dir, &user_files, &user_dirs, filesystem::name_mode::ENTIRE_FILE_PATH);
459 
460  // Warn player about addons using the no-longer-supported single-file format.
461  for(const std::string& file : user_files) {
462 
463  if(filesystem::is_cfg(file)) {
464  ERR_CONFIG << "error reading usermade add-on '" << file << "'";
465 
466  error_addons.push_back(file);
467 
468  const std::string short_wml_path = filesystem::get_short_wml_path(file);
469  const std::string log_msg = formatter()
470  << "The format '"
471  << short_wml_path
472  << "' (for single-file add-ons) is not supported anymore, use '"
473  << short_wml_path.substr(0, short_wml_path.size() - filesystem::wml_extension.size())
474  << "/_main.cfg' instead.";
475 
476  error_log.push_back(log_msg);
477  }
478  }
479 
480  loading_screen::spin();
481 
482  // Rerun the directory scan using filename only, to get the addon_ids more easily.
483  user_files.clear();
484  user_dirs.clear();
485 
486  filesystem::get_files_in_dir(user_campaign_dir, nullptr, &user_dirs,
488 
489  loading_screen::spin();
490 
491  // Load the addons.
492  for(const std::string& addon_id : user_dirs) {
493  log_scope2(log_config, "Loading add-on '" + addon_id + "'");
494  const std::string addon_dir = user_campaign_dir + "/" + addon_id;
495 
496  const std::string main_cfg = addon_dir + "/_main.cfg";
497  const std::string info_cfg = addon_dir + "/_info.cfg";
498 
499  if(!filesystem::file_exists(main_cfg)) {
500  continue;
501  }
502 
503  loading_screen::spin();
504 
505  // Try to find this addon's metadata. Author publishing info (_server.pbl) is given
506  // precedence over addon sever-generated info (_info.cfg). If neither are found, it
507  // probably means the addon was installed manually and certain defaults will be used.
508  config metadata;
509 
510  if(have_addon_pbl_info(addon_id)) {
511  // Publishing info needs to be read from disk.
512  try {
513  metadata = get_addon_pbl_info(addon_id, false);
514  } catch(const invalid_pbl_exception& e) {
515  const std::string log_msg = formatter()
516  << "The provided addon has an invalid pbl file"
517  << " for addon "
518  << addon_id;
519 
520  error_addons.push_back(e.message);
521  error_log.push_back(log_msg);
522  }
523  } else if(filesystem::file_exists(info_cfg)) {
524  // Addon server-generated info can be fetched from cache.
525  metadata = cache_.get_config(info_cfg).child_or_empty("info");
526  }
527 
528  std::string using_core = metadata["core"];
529  if(using_core.empty()) {
530  using_core = "default";
531  }
532 
533  // Skip add-ons not matching our current core. Cores themselves should be selectable
534  // at all times, so they aren't considered here.
535  if(!metadata.empty() && metadata["type"] != "core" && using_core != prefs::get().core()) {
536  continue;
537  }
538 
539  std::string addon_title = metadata["title"].str();
540  if(addon_title.empty()) {
541  addon_title = addon_id;
542  }
543 
544  version_info addon_version(metadata["version"]);
545 
546  try {
547  std::unique_ptr<schema_validation::schema_validator> validator;
549  validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location("schema/game_config.cfg").value()));
550  validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
551  }
552 
553  loading_screen::spin();
554 
555  // Load this addon from the cache to a config.
556  config umc_cfg = cache_.get_config(main_cfg, validator.get());
557 
558  static const std::set<std::string> tags_with_addon_id {
559  "era",
560  "modification",
561  "resource",
562  "multiplayer",
563  "scenario",
564  "campaign",
565  "test"
566  };
567 
568  // Annotate appropriate addon types with addon_id info.
569  for(auto [key, cfg] : umc_cfg.all_children_view()) {
570  if(tags_with_addon_id.count(key) > 0) {
571  cfg["addon_id"] = addon_id;
572  cfg["addon_title"] = addon_title;
573  // Note that this may reformat the string in a canonical form.
574  cfg["addon_version"] = addon_version.str();
575  }
576  }
577 
578  loading_screen::spin();
579 
580  show_deprecated_warnings(umc_cfg);
581 
582  loading_screen::spin();
583 
584  static const std::set<std::string> entry_tags {
585  "era",
586  "modification",
587  "resource",
588  "multiplayer",
589  "scenario",
590  "campaign"
591  };
592 
593  for(const std::string& tagname : entry_tags) {
594  game_config_.append_children_by_move(umc_cfg, tagname);
595  }
596 
597  loading_screen::spin();
598 
599  addon_cfgs_[addon_id] = std::move(umc_cfg);
600  } catch(const config::error& err) {
601  ERR_CONFIG << "config error reading usermade add-on '" << main_cfg << "'";
602  ERR_CONFIG << err.message;
603  error_addons.push_back(main_cfg);
604  error_log.push_back(err.message);
605  } catch(const preproc_config::error& err) {
606  ERR_CONFIG << "preprocessor config error reading usermade add-on '" << main_cfg << "'";
607  ERR_CONFIG << err.message;
608  error_addons.push_back(main_cfg);
609  error_log.push_back(err.message);
610  } catch(const filesystem::io_exception&) {
611  ERR_CONFIG << "filesystem I/O error reading usermade add-on '" << main_cfg << "'";
612  error_addons.push_back(main_cfg);
613  }
614  }
615 
618  ERR_CONFIG << "Didn’t find an add-on for --validate-addon - check whether the id has a typo";
619  const std::string log_msg = formatter()
620  << "Didn't find an add-on for --validate-addon - check whether the id has a typo";
621  error_log.push_back(log_msg);
622  throw game::error("Did not find an add-on for --validate-addon");
623  }
624 
625  WRN_CONFIG << "Note: for --validate-addon to find errors, you have to play (in the GUI) a game that uses the add-on.";
626  }
627 
628  if(!error_addons.empty()) {
629  const std::size_t n = error_addons.size();
630  const std::string& msg1 =
631  _n("The following add-on had errors and could not be loaded:",
632  "The following add-ons had errors and could not be loaded:",
633  n);
634  const std::string& msg2 =
635  _n("Please report this to the author or maintainer of this add-on.",
636  "Please report this to the respective authors or maintainers of these add-ons.",
637  n);
638 
639  const std::string& report = utils::join(error_log, "\n\n");
641  gui2::dialogs::wml_error::display(msg1, msg2, error_addons, report);
642  });
643  }
644 }
645 
647 {
648  config& hashes = game_config_.add_child("multiplayer_hashes");
649  for(const config& ch : game_config().child_range("multiplayer")) {
650  hashes[ch["id"].str()] = ch.hash();
651  }
652 }
653 
655 {
657  unit_types.set_config(game_config().merged_children_view("units"));
658 }
659 
661 {
662  // Rebuild addon version info cache.
664 
665  // Force a reload of configuration information.
667  old_defines_map_.clear();
670 
673 }
674 
676 {
679 }
680 
682  const game_classification& classification, const std::string& scenario_id)
683 {
685  !classification.difficulty.empty());
691  !classification.era_define.empty());
692  game_config::scoped_preproc_define multiplayer("MULTIPLAYER",
696 
697  //
698  // NOTE: these deques aren't used here, but the objects within are utilized as RAII helpers.
699  //
700 
701  std::deque<game_config::scoped_preproc_define> extra_defines;
702  for(const std::string& extra_define : classification.campaign_xtra_defines) {
703  extra_defines.emplace_back(extra_define);
704  }
705 
706  std::deque<game_config::scoped_preproc_define> modification_defines;
707  for(const std::string& mod_define : classification.mod_defines) {
708  modification_defines.emplace_back(mod_define, !mod_define.empty());
709  }
710 
711  try {
713  } catch(const game::error&) {
715 
716  std::deque<game_config::scoped_preproc_define> previous_defines;
717  for(const preproc_map::value_type& preproc : old_defines_map_) {
718  previous_defines.emplace_back(preproc.first);
719  }
720 
722  throw;
723  }
724 
725  // This needs to be done in the main thread since this function (load_game_config_for_game)
726  // might be called from a loading screen worker thread (and currently is, in fact). If the
727  // image cache is purged from the worker thread, there's a possibility for a data race where
728  // the main thread accesses the image cache and the worker thread simultaneously clears it.
730 }
731 
733 {
734  game_config::scoped_preproc_define multiplayer("MULTIPLAYER", is_mp);
735  game_config::scoped_preproc_define test("TEST", is_test);
736  game_config::scoped_preproc_define mptest("MP_TEST", cmdline_opts_.mptest && is_mp);
737  /** During an mp game the default difficulty define is also defined so better already load it now if we already must reload config cache. */
740 
741  try {
743  } catch(const game::error&) {
745 
746  std::deque<game_config::scoped_preproc_define> previous_defines;
747  for (const preproc_map::value_type& preproc : old_defines_map_) {
748  previous_defines.emplace_back(preproc.first);
749  }
750 
752  throw;
753  }
754 }
755 
756 void game_config_manager::set_enabled_addon(const std::set<std::string>& addon_ids)
757 {
758  auto& vec = game_config_view_.data();
759  vec.clear();
760  vec.push_back(game_config_);
761 
762  for(const std::string& id : addon_ids) {
763  auto it = addon_cfgs_.find(id);
764  if(it != addon_cfgs_.end()) {
765  LOG_CONFIG << "Enabling add-on " << id;
766  vec.push_back(it->second);
767  } else {
768  ERR_CONFIG << "Attempted to enable add-on '" << id << "' but its config could not be found";
769  }
770  }
771 }
772 
774 {
775  active_addons_.clear();
776  auto& vec = game_config_view_.data();
777  vec.clear();
778  vec.push_back(game_config_);
779 
780  for(const auto& pair : addon_cfgs_) {
781  LOG_CONFIG << "Enabling add-on " << pair.first;
782  vec.push_back(pair.second);
783  active_addons_.emplace(pair.first);
784  }
785 }
config get_addon_pbl_info(const std::string &addon_name, bool do_validate)
Gets the publish information for an add-on.
Definition: manager.cpp:71
bool have_addon_pbl_info(const std::string &addon_name)
Returns whether a .pbl file is present for the specified add-on or not.
Definition: manager.cpp:66
void refresh_addon_version_info_cache()
Refreshes the per-session cache of add-on's version information structs.
Definition: manager.cpp:381
Definitions for the terrain builder.
void reload()
Reads the mainline achievements.cfg and then all the achievements of each installed add-on.
static void init(const game_config_view &game_config)
Init the parameters of ai configuration parser.
utils::optional< std::string > test
Non-empty if –test was given on the command line.
utils::optional< std::string > validate_addon
Non-empty if –validate-addon was given on the command line.
bool mptest
True if –mp-test was given on the command line.
bool multiplayer
True if –multiplayer was given on the command line.
bool validcache
True if –validcache was given on the command line.
bool noaddons
True if –noaddons was given on the command line.
utils::optional< std::string > editor
Non-empty if –editor was given on the command line.
bool any_validation_option() const
True if the –validate or any of the –validate-* options are given.
bool validate_core
True if –validate-core was given on the command line.
bool nocache
True if –nocache was given on the command line.
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:157
config & add_child(std::string_view key)
Definition: config.cpp:436
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:188
void append_children_by_move(config &cfg, std::string_view key)
Moves children with the given name from the given config to this one.
Definition: config.cpp:224
auto all_children_view() const
In-order iteration over all children.
Definition: config.hpp:795
child_itors child_range(std::string_view key)
Definition: config.cpp:268
optional_config_impl< config > find_child(std::string_view 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:764
const config & child_or_empty(std::string_view key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:390
bool empty() const
Definition: config.cpp:823
std::string hash() const
Definition: config.cpp:1227
std::ostringstream wrapper.
Definition: formatter.hpp:40
std::vector< std::string > campaign_xtra_defines
more customization of data
std::vector< std::string > mod_defines
If there are defines the modifications use to customize data.
std::set< std::string > active_addons(const std::string &scenario_id) const
std::string scenario_define
If there is a define the scenario uses to customize data.
std::string difficulty
The difficulty level the game is being played on.
std::string era_define
If there is a define the era uses to customize data.
std::string campaign_define
If there is a define the campaign uses to customize data.
Used to share macros between cache objects You have to create transaction object to load all macros t...
void lock()
Lock the transaction so no more macros are added.
void recheck_filetree_checksum()
Force cache checksum validation.
void set_use_cache(bool use)
Enable/disable caching.
const preproc_map & get_preproc_map() const
void clear_defines()
Clear stored defines map to default values.
bool clean_cache()
Deletes stale cache files not in use by the game.
config get_config(const std::string &path, abstract_validator *validator=nullptr)
Gets a config object from given path.
void set_force_valid_cache(bool force)
Enable/disable cache validation.
Used to set and unset scoped defines to preproc_map.
void load_game_config_with_loadscreen(FORCE_RELOAD_CONFIG force_reload, const game_classification *classification, const std::string &scenario_id)
@ FORCE_RELOAD
Always reload config.
@ NO_INCLUDE_RELOAD
Don't reload if the previous defines include the new defines.
@ NO_FORCE_RELOAD
Don't reload if the previous defines equal the new defines.
std::map< std::string, config > addon_cfgs_
bool init_game_config(FORCE_RELOAD_CONFIG force_reload)
static game_config_manager * get()
terrain_type_data tdata_
void load_game_config_for_game(const game_classification &classification, const std::string &scenario_id)
void load_game_config(bool reload_everything, const game_classification *classification, const std::string &scenario_id)
std::set< std::string > active_addons_
void load_game_config_for_create(bool is_mp, bool is_test=false)
filesystem::binary_paths_manager paths_manager_
game_config_view game_config_view_
game_config::config_cache & cache_
void set_enabled_addon(const std::set< std::string > &addon_ids)
game_config_manager(const commandline_options &cmdline_opts)
const game_config_view & game_config() const
const commandline_options & cmdline_opts_
config_array_view & data()
static void extract_preload_scripts(const game_config_view &game_config)
static void progress(loading_stage stage=loading_stage::none)
Report what is being loaded to the loading screen.
static void display(const std::function< void()> &f)
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:41
static prefs & get()
void load_advanced_prefs(const game_config_view &gc)
void load_hotkeys()
Realization of serialization/validator.hpp abstract validator.
static void set_terrain_rules_cfg(const game_config_view &cfg)
Set the config where we will parse the global terrain rules.
Definition: builder.cpp:279
void reset() const
Clears the database and queues reinitialization on the next call to lazy_initialization.
Definition: type_data.cpp:50
static void set_known_themes(const game_config_view *cfg)
Copies the theme configs from the main game config.
Definition: theme.cpp:991
void set_config(const game_config_view &cfg)
Resets all data based on the provided config.
Definition: types.cpp:1087
A single unit type that the player may recruit.
Definition: types.hpp:43
Represents version numbers.
std::string str() const
Serializes the version number into string form.
Managing the AIs configuration - headers.
std::string deprecated_message(const std::string &elem_name, DEP_LEVEL level, const version_info &version, const std::string &detail)
Definition: deprecation.cpp:29
const config * cfg
#define VGETTEXT(msgid,...)
Handy wrappers around interpolate_variables_into_string and gettext.
const std::string DEFAULT_DIFFICULTY
The default difficulty setting for campaigns.
#define LOG_CONFIG
static game_config_manager * singleton
static void show_deprecated_warnings(config &umc_cfg)
#define ERR_CONFIG
#define WRN_CONFIG
static lg::log_domain log_config("config")
Interfaces for manipulating version numbers of engine, add-ons, etc.
static std::string _n(const char *str1, const char *str2, int n)
Definition: gettext.hpp:101
static std::string _(const char *str)
Definition: gettext.hpp:97
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:199
void init_textdomains(const game_config_view &cfg)
Initializes the list of textdomains from a configuration object.
Definition: language.cpp:367
bool init_strings(const game_config_view &cfg)
Initializes certain English strings.
Definition: language.cpp:385
Standard logging facilities (interface).
#define log_scope2(domain, description)
Definition: log.hpp:276
#define FORCE_LOG_TO(logger, domain)
Definition: log.hpp:291
void set_about(const game_config_view &cfg)
Regenerates the credits data.
Definition: about.cpp:119
void call_in_main_thread(const std::function< void(void)> &f)
Definition: events.cpp:778
void get_files_in_dir(const std::string &dir, std::vector< std::string > *files, std::vector< std::string > *dirs, name_mode mode, filter_mode filter, reorder_mode reorder, file_tree_checksum *checksum)
Get a list of all files and/or directories in a given directory.
Definition: filesystem.cpp:466
const std::string wml_extension
Definition: filesystem.cpp:281
bool is_cfg(const std::string &filename)
Returns true if the file ends with the wmlfile extension.
static bool file_exists(const bfs::path &fpath)
Definition: filesystem.cpp:344
utils::optional< std::string > get_wml_location(const std::string &path, const utils::optional< std::string > &current_dir)
Returns a translated path to the actual file or directory, if it exists.
const file_tree_checksum & data_tree_checksum(bool reset=false)
Get the time at which the data/ tree was last modified at.
void clear_binary_paths_cache()
std::string get_short_wml_path(const std::string &filename)
Returns a short path to filename, skipping the (user) data directory.
std::string get_addons_dir()
Game configuration data as global variables.
Definition: build_info.cpp:61
std::string path
Definition: filesystem.cpp:106
const version_info wesnoth_version(VERSION)
const bool & debug
Definition: game_config.cpp:95
static void add_color_info(const game_config_view &v, bool build_defaults)
void reset_color_info()
void load_config(const config &v)
void load_default_hotkeys(const game_config_view &cfg)
Registers all hotkeys present in this config.
constexpr uint32_t scope_main
void flush_cache()
Purges all image caches.
Definition: picture.cpp:210
logger & err()
Definition: log.cpp:339
log_domain & general()
Definition: log.cpp:365
logger & info()
Definition: log.cpp:351
game_classification * classification
Definition: resources.cpp:34
void flush_cache()
Definition: sound.cpp:192
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::map< std::string, t_string > string_map
std::vector< std::string > split(const config_attribute_value &val)
std::map< std::string, struct preproc_define > preproc_map
One of the realizations of serialization/validator.hpp abstract validator.
void set_paths(const game_config_view &cfg)
An exception object used when an IO error occurs.
Definition: filesystem.hpp:67
Base class for all the errors encountered by the engine.
Definition: exceptions.hpp:29
Exception thrown when the WML parser fails to read a .pbl file.
Definition: manager.hpp:45
static map_location::direction n
Definitions related to theme-support.
unit_type_data unit_types
Definition: types.cpp:1514
#define e