The Battle for Wesnoth  1.19.2+dev
game_config_manager.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2013 - 2024
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  , achievements_()
63 {
64  assert(!singleton);
65  singleton = this;
66 
67  // All of the validation options imply --nocache, as the validation happens during cache
68  // rebuilding. If the cache isn't rebuilt, validation is silently skipped.
70  cache_.set_use_cache(false);
71  }
72 
75  }
76 
77  // Clean the cache of any old Wesnoth version's cache data
78  if(const std::string last_cleaned = prefs::get().last_cache_cleared_version(); !last_cleaned.empty()) {
79  if(version_info{last_cleaned} < game_config::wesnoth_version) {
80  if(cache_.clean_cache()) {
82  }
83  }
84  } else {
85  // If the preference wasn't set, set it, else the cleaning will never happen :P
87  }
88 }
89 
91 {
92  assert(singleton);
93  singleton = nullptr;
94 }
95 
97 {
98  return singleton;
99 }
100 
102 {
103  // Add preproc defines according to the command line arguments.
105  game_config::scoped_preproc_define test("TEST", cmdline_opts_.test.has_value());
108  game_config::scoped_preproc_define title_screen("TITLE_SCREEN",
110 
112 
113  load_game_config_with_loadscreen(force_reload, nullptr, "");
114 
115  game_config::load_config(game_config().mandatory_child("game_config"));
116 
117  // It's necessary to block the event thread while load_hotkeys() runs, otherwise keyboard input
118  // can cause a crash by accessing the list of hotkeys while it's being modified.
119  events::call_in_main_thread([this]() {
120  const hotkey::scope_changer hk_scope{hotkey::scope_main, false};
121 
122  // Load the standard hotkeys, then apply any player customizations.
125  });
126 
128 
132 
133  return true;
134 }
135 
136 namespace
137 {
138 /** returns true if every define in special is also defined in general */
139 bool map_includes(const preproc_map& general, const preproc_map& special)
140 {
141  return std::all_of(special.begin(), special.end(), [&general](const auto& pair) {
142  const auto it = general.find(pair.first);
143  return it != general.end() && it->second == pair.second;
144  });
145 }
146 } // end anonymous namespace
147 
149  FORCE_RELOAD_CONFIG force_reload, const game_classification* classification, const std::string& scenario_id)
150 {
151  if(!lg::info().dont_log(log_config)) {
152  auto out = formatter();
153  out << "load_game_config: defines:";
154 
155  for(const auto& pair : cache_.get_preproc_map()) {
156  out << pair.first << ",";
157  }
158 
159  out << "\n";
160  FORCE_LOG_TO(lg::info(), log_config) << out.str();
161  }
162 
163  game_config::scoped_preproc_define debug_mode("DEBUG_MODE",
165 
166  bool reload_everything = true;
167 
168  // Game_config already holds requested config in memory.
169  if(!game_config_.empty()) {
170  if(force_reload == NO_FORCE_RELOAD && old_defines_map_ == cache_.get_preproc_map()) {
171  reload_everything = false;
172  }
173 
174  if(force_reload == NO_INCLUDE_RELOAD && map_includes(old_defines_map_, cache_.get_preproc_map())) {
175  reload_everything = false;
176  }
177  }
178 
179  LOG_CONFIG << "load_game_config reload everything: " << reload_everything;
180 
181  gui2::dialogs::loading_screen::display([this, reload_everything, classification, scenario_id]() {
182  load_game_config(reload_everything, classification, scenario_id);
183  });
184 }
185 
186 void game_config_manager::load_game_config(bool reload_everything, const game_classification* classification, const std::string& scenario_id)
187 {
188  // Make sure that 'debug mode' symbol is set
189  // if command line parameter is selected
190  // also if we're in multiplayer and actual debug mode is disabled.
191 
192  // The loadscreen will erase the titlescreen.
193  // NOTE: even without loadscreen, needed after MP lobby.
194  try {
195  // Read all game configs.
196  // First we load all core configs, the mainline one and the ones from the addons.
197  // Validate the cores and discard the invalid.
198  // Then find the path to the selected core.
199  // Load the selected core.
200  // Handle terrains so that they are last loaded from the core.
201  // Load every compatible addon.
202  if(reload_everything) {
206 
207  // Start transaction so macros are shared.
208  game_config::config_cache_transaction main_transaction;
210 
211  // Load mainline cores definition file.
212  config cores_cfg;
213  cache_.get_config(game_config::path + "/data/cores.cfg", cores_cfg);
214 
215  // Append the $user_campaign_dir/*/cores.cfg files to the cores.
216  std::vector<std::string> user_dirs;
217  {
218  const std::string user_campaign_dir = filesystem::get_addons_dir();
219  std::vector<std::string> user_files;
221  user_campaign_dir, &user_files, &user_dirs, filesystem::name_mode::ENTIRE_FILE_PATH);
222  }
223 
224  for(const std::string& umc : user_dirs) {
225  const std::string cores_file = umc + "/cores.cfg";
226  if(filesystem::file_exists(cores_file)) {
227  config cores;
228  cache_.get_config(cores_file, cores);
229  cores_cfg.append(cores);
230  }
231  }
232 
233  // Validate every core
234  config valid_cores;
235  bool current_core_valid = false;
236  std::string wml_tree_root;
237 
238  for(const config& core : cores_cfg.child_range("core")) {
239  const std::string& id = core["id"];
240  if(id.empty()) {
243  _("Error validating data core."),
244  _("Found a core without id attribute.")
245  + '\n' + _("Skipping the core."));
246  });
247  continue;
248  }
249 
250  if(valid_cores.find_child("core", "id", id)) {
253  _("Error validating data core."),
254  _("Core ID: ") + id
255  + '\n' + _("The ID is already in use.")
256  + '\n' + _("Skipping the core."));
257  });
258  continue;
259  }
260 
261  const std::string& path = core["path"];
265  _("Error validating data core."),
266  _("Core ID: ") + id
267  + '\n' + _("Core Path: ") + path
268  + '\n' + _("File not found.")
269  + '\n' + _("Skipping the core."));
270  });
271  continue;
272  }
273 
274  if(id == "default" && !current_core_valid) {
275  wml_tree_root = path;
276  }
277  if(id == prefs::get().core_id()) {
278  current_core_valid = true;
279  wml_tree_root = path;
280  }
281 
282  valid_cores.add_child("core", core); // append(core);
283  }
284 
285  if(!current_core_valid) {
288  _("Error loading core data."),
289  _("Core ID: ") + prefs::get().core_id()
290  + '\n' + _("Error loading the core with named id.")
291  + '\n' + _("Falling back to the default core."));
292  });
293  prefs::get().set_core_id("default");
294  }
295 
296  // check if we have a valid default core which should always be the case.
297  if(wml_tree_root.empty()) {
300  _("Error loading core data."),
301  _("Can't locate the default core.")
302  + '\n' + _("The game will now exit."));
303  });
304  throw;
305  }
306 
307  // Load the selected core
308  std::unique_ptr<schema_validation::schema_validator> validator;
310  validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location("schema/game_config.cfg").value()));
311  validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
312  }
313 
314  cache_.get_config(filesystem::get_wml_location(wml_tree_root).value(), game_config_, validator.get());
315  game_config_.append(valid_cores);
316 
317  main_transaction.lock();
318 
320  load_addons_cfg();
321  }
322  }
323 
324  // only after addon configs have been loaded do we check for which addons are needed and whether they exist to be used
325  LOG_CONFIG << "active_addons_ has size " << active_addons_.size() << " and contents: " << utils::join(active_addons_);
326  if(classification) {
327  LOG_CONFIG << "Enabling only some add-ons!";
328  std::set<std::string> active_addons = classification->active_addons(scenario_id);
329  // IMPORTANT: this is a significant performance optimization, particularly for the worst case example of the batched WML unit tests
330  if(!reload_everything && active_addons == active_addons_) {
331  LOG_CONFIG << "Configs not reloaded and active add-ons remain the same; returning early.";
332  LOG_CONFIG << "active_addons has size " << active_addons_.size() << " and contents: " << utils::join(active_addons);
333  return;
334  }
335  active_addons_ = active_addons;
337  } else {
338  LOG_CONFIG << "Enabling all add-ons!";
340  }
341 
342  // Extract the Lua scripts at toplevel.
344 
345  set_unit_data();
347  tdata_ = std::make_shared<terrain_type_data>(game_config());
350 
352 
354 
355  } catch(const game::error& e) {
356  ERR_CONFIG << "Error loading game configuration files\n" << e.message;
357 
358  // Try reloading without add-ons
360  game_config::no_addons = true;
363  _("Error loading custom game configuration files. The game will try without loading add-ons."),
364  e.message);
365  });
366  load_game_config(reload_everything, classification, scenario_id);
367  } else if(prefs::get().core_id() != "default") {
370  _("Error loading custom game configuration files. The game will fallback to the default core files."),
371  e.message);
372  });
373  prefs::get().set_core_id("default");
374  game_config::no_addons = false;
375  load_game_config(reload_everything, classification, scenario_id);
376  } else {
379  _("Error loading default core game configuration files. The game will now exit."),
380  e.message);
381  });
382  throw;
383  }
384  }
385 
387 
388  // Set new binary paths.
390 }
391 static void show_deprecated_warnings(config& umc_cfg)
392 {
393  for(auto& units : umc_cfg.child_range("units")) {
394  for(auto& unit_type : units.child_range("unit_type")) {
395  for(const auto& advancefrom : unit_type.child_range("advancefrom")) {
396  auto symbols = utils::string_map {
397  {"lower_level", advancefrom["unit"]},
398  {"higher_level", unit_type["id"]}
399  };
400  auto message = VGETTEXT(
401  // TRANSLATORS: For example, 'Cuttle Fish' units will not be able to advance to 'Kraken'.
402  // The substituted strings are unit ids, not translated names; hopefully any add-ons
403  // that trigger this will be quickly fixed and stop triggering the warning.
404  "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.",
405  symbols);
406  deprecated_message("[advancefrom]", DEP_LEVEL::REMOVED, {1, 15, 4}, message);
407  }
408  unit_type.remove_children("advancefrom", [](const config&){return true;});
409  }
410  }
411 
412 
413  // hardcoded list of 1.14 advancement macros, just used for the error mesage below.
414  static const std::set<std::string> deprecated_defines {
415  "ENABLE_PARAGON",
416  "DISABLE_GRAND_MARSHAL",
417  "ENABLE_ARMAGEDDON_DRAKE",
418  "ENABLE_DWARVISH_ARCANISTER",
419  "ENABLE_DWARVISH_RUNESMITH",
420  "ENABLE_WOLF_ADVANCEMENT",
421  "ENABLE_NIGHTBLADE",
422  "ENABLE_TROLL_SHAMAN",
423  "ENABLE_ANCIENT_LICH",
424  "ENABLE_DEATH_KNIGHT",
425  "ENABLE_WOSE_SHAMAN"
426  };
427 
428  for(auto& campaign : umc_cfg.child_range("campaign")) {
429  for(auto str : utils::split(campaign["extra_defines"])) {
430  if(deprecated_defines.count(str) > 0) {
431  //TODO: we could try to implement a compatibility path by
432  // somehow getting the content of that macro from the
433  // cache_ object, but considering that 1) the breakage
434  // isn't that bad (just one disabled unit) and 2)
435  // it before also didn't work in all cases (see #4402)
436  // i don't think it is worth it.
438  "campaign id='" + campaign["id"].str() + "' has extra_defines=" + str,
440  {1, 15, 4},
441  _("instead, use the macro with the same name in the [campaign] tag")
442  );
443  }
444  }
445  }
446 }
447 
449 {
450  const std::string user_campaign_dir = filesystem::get_addons_dir();
451 
452  std::vector<std::string> error_log;
453  std::vector<std::string> error_addons;
454  std::vector<std::string> user_dirs;
455  std::vector<std::string> user_files;
456 
457  filesystem::get_files_in_dir(user_campaign_dir, &user_files, &user_dirs, filesystem::name_mode::ENTIRE_FILE_PATH);
458 
459  // Warn player about addons using the no-longer-supported single-file format.
460  for(const std::string& file : user_files) {
461 
462  if(filesystem::is_cfg(file)) {
463  ERR_CONFIG << "error reading usermade add-on '" << file << "'";
464 
465  error_addons.push_back(file);
466 
467  const std::string short_wml_path = filesystem::get_short_wml_path(file);
468  const std::string log_msg = formatter()
469  << "The format '"
470  << short_wml_path
471  << "' (for single-file add-ons) is not supported anymore, use '"
472  << short_wml_path.substr(0, short_wml_path.size() - filesystem::wml_extension.size())
473  << "/_main.cfg' instead.";
474 
475  error_log.push_back(log_msg);
476  }
477  }
478 
479  loading_screen::spin();
480 
481  // Rerun the directory scan using filename only, to get the addon_ids more easily.
482  user_files.clear();
483  user_dirs.clear();
484 
485  filesystem::get_files_in_dir(user_campaign_dir, nullptr, &user_dirs,
487 
488  loading_screen::spin();
489 
490  // Load the addons.
491  for(const std::string& addon_id : user_dirs) {
492  log_scope2(log_config, "Loading add-on '" + addon_id + "'");
493  const std::string addon_dir = user_campaign_dir + "/" + addon_id;
494 
495  const std::string main_cfg = addon_dir + "/_main.cfg";
496  const std::string info_cfg = addon_dir + "/_info.cfg";
497 
498  if(!filesystem::file_exists(main_cfg)) {
499  continue;
500  }
501 
502  loading_screen::spin();
503 
504  // Try to find this addon's metadata. Author publishing info (_server.pbl) is given
505  // precedence over addon sever-generated info (_info.cfg). If neither are found, it
506  // probably means the addon was installed manually and certain defaults will be used.
507  config metadata;
508 
509  if(have_addon_pbl_info(addon_id)) {
510  // Publishing info needs to be read from disk.
511  try {
512  metadata = get_addon_pbl_info(addon_id, false);
513  } catch(const invalid_pbl_exception& e) {
514  const std::string log_msg = formatter()
515  << "The provided addon has an invalid pbl file"
516  << " for addon "
517  << addon_id;
518 
519  error_addons.push_back(e.message);
520  error_log.push_back(log_msg);
521  }
522  } else if(filesystem::file_exists(info_cfg)) {
523  // Addon server-generated info can be fetched from cache.
524  config temp;
525  cache_.get_config(info_cfg, temp);
526 
527  metadata = temp.child_or_empty("info");
528  }
529 
530  std::string using_core = metadata["core"];
531  if(using_core.empty()) {
532  using_core = "default";
533  }
534 
535  // Skip add-ons not matching our current core. Cores themselves should be selectable
536  // at all times, so they aren't considered here.
537  if(!metadata.empty() && metadata["type"] != "core" && using_core != prefs::get().core_id()) {
538  continue;
539  }
540 
541  std::string addon_title = metadata["title"].str();
542  if(addon_title.empty()) {
543  addon_title = addon_id;
544  }
545 
546  version_info addon_version(metadata["version"]);
547 
548  try {
549  std::unique_ptr<schema_validation::schema_validator> validator;
551  validator.reset(new schema_validation::schema_validator(filesystem::get_wml_location("schema/game_config.cfg").value()));
552  validator->set_create_exceptions(false); // Don't crash if there's an error, just go ahead anyway
553  }
554 
555  loading_screen::spin();
556 
557  // Load this addon from the cache to a config.
558  config umc_cfg;
559  cache_.get_config(main_cfg, umc_cfg, validator.get());
560 
561  static const std::set<std::string> tags_with_addon_id {
562  "era",
563  "modification",
564  "resource",
565  "multiplayer",
566  "scenario",
567  "campaign",
568  "test"
569  };
570 
571  // Annotate appropriate addon types with addon_id info.
572  for(auto child : umc_cfg.all_children_range()) {
573  if(tags_with_addon_id.count(child.key) > 0) {
574  auto& cfg = child.cfg;
575  cfg["addon_id"] = addon_id;
576  cfg["addon_title"] = addon_title;
577  // Note that this may reformat the string in a canonical form.
578  cfg["addon_version"] = addon_version.str();
579  }
580  }
581 
582  loading_screen::spin();
583 
584  show_deprecated_warnings(umc_cfg);
585 
586  loading_screen::spin();
587 
588  static const std::set<std::string> entry_tags {
589  "era",
590  "modification",
591  "resource",
592  "multiplayer",
593  "scenario",
594  "campaign"
595  };
596 
597  for(const std::string& tagname : entry_tags) {
598  game_config_.append_children_by_move(umc_cfg, tagname);
599  }
600 
601  loading_screen::spin();
602 
603  addon_cfgs_[addon_id] = std::move(umc_cfg);
604  } catch(const config::error& err) {
605  ERR_CONFIG << "config error reading usermade add-on '" << main_cfg << "'";
606  ERR_CONFIG << err.message;
607  error_addons.push_back(main_cfg);
608  error_log.push_back(err.message);
609  } catch(const preproc_config::error& err) {
610  ERR_CONFIG << "preprocessor config error reading usermade add-on '" << main_cfg << "'";
611  ERR_CONFIG << err.message;
612  error_addons.push_back(main_cfg);
613  error_log.push_back(err.message);
614  } catch(const filesystem::io_exception&) {
615  ERR_CONFIG << "filesystem I/O error reading usermade add-on '" << main_cfg << "'";
616  error_addons.push_back(main_cfg);
617  }
618  }
619 
622  ERR_CONFIG << "Didn’t find an add-on for --validate-addon - check whether the id has a typo";
623  const std::string log_msg = formatter()
624  << "Didn't find an add-on for --validate-addon - check whether the id has a typo";
625  error_log.push_back(log_msg);
626  throw game::error("Did not find an add-on for --validate-addon");
627  }
628 
629  WRN_CONFIG << "Note: for --validate-addon to find errors, you have to play (in the GUI) a game that uses the add-on.";
630  }
631 
632  if(!error_addons.empty()) {
633  const std::size_t n = error_addons.size();
634  const std::string& msg1 =
635  _n("The following add-on had errors and could not be loaded:",
636  "The following add-ons had errors and could not be loaded:",
637  n);
638  const std::string& msg2 =
639  _n("Please report this to the author or maintainer of this add-on.",
640  "Please report this to the respective authors or maintainers of these add-ons.",
641  n);
642 
643  const std::string& report = utils::join(error_log, "\n\n");
645  gui2::dialogs::wml_error::display(msg1, msg2, error_addons, report);
646  });
647  }
648 }
649 
651 {
652  config& hashes = game_config_.add_child("multiplayer_hashes");
653  for(const config& ch : game_config().child_range("multiplayer")) {
654  hashes[ch["id"].str()] = ch.hash();
655  }
656 }
657 
659 {
661  unit_types.set_config(game_config().merged_children_view("units"));
662 }
663 
665 {
666  // Rebuild addon version info cache.
668 
669  // Force a reload of configuration information.
671  old_defines_map_.clear();
674 
677 }
678 
680 {
683 }
684 
686  const game_classification& classification, const std::string& scenario_id)
687 {
689  !classification.difficulty.empty());
695  !classification.era_define.empty());
696  game_config::scoped_preproc_define multiplayer("MULTIPLAYER",
700 
701  //
702  // NOTE: these deques aren't used here, but the objects within are utilized as RAII helpers.
703  //
704 
705  std::deque<game_config::scoped_preproc_define> extra_defines;
706  for(const std::string& extra_define : classification.campaign_xtra_defines) {
707  extra_defines.emplace_back(extra_define);
708  }
709 
710  std::deque<game_config::scoped_preproc_define> modification_defines;
711  for(const std::string& mod_define : classification.mod_defines) {
712  modification_defines.emplace_back(mod_define, !mod_define.empty());
713  }
714 
715  try {
717  } catch(const game::error&) {
719 
720  std::deque<game_config::scoped_preproc_define> previous_defines;
721  for(const preproc_map::value_type& preproc : old_defines_map_) {
722  previous_defines.emplace_back(preproc.first);
723  }
724 
726  throw;
727  }
728 
729  // This needs to be done in the main thread since this function (load_game_config_for_game)
730  // might be called from a loading screen worker thread (and currently is, in fact). If the
731  // image cache is purged from the worker thread, there's a possibility for a data race where
732  // the main thread accesses the image cache and the worker thread simultaneously clears it.
734 }
735 
737 {
738  game_config::scoped_preproc_define multiplayer("MULTIPLAYER", is_mp);
739  game_config::scoped_preproc_define test("TEST", is_test);
740  game_config::scoped_preproc_define mptest("MP_TEST", cmdline_opts_.mptest && is_mp);
741  /** During an mp game the default difficulty define is also defined so better already load it now if we already must reload config cache. */
744 
745  try {
747  } catch(const game::error&) {
749 
750  std::deque<game_config::scoped_preproc_define> previous_defines;
751  for (const preproc_map::value_type& preproc : old_defines_map_) {
752  previous_defines.emplace_back(preproc.first);
753  }
754 
756  throw;
757  }
758 }
759 
760 void game_config_manager::set_enabled_addon(std::set<std::string> addon_ids)
761 {
762  auto& vec = game_config_view_.data();
763  vec.clear();
764  vec.push_back(game_config_);
765 
766  for(const std::string& id : addon_ids) {
767  auto it = addon_cfgs_.find(id);
768  if(it != addon_cfgs_.end()) {
769  LOG_CONFIG << "Enabling add-on " << id;
770  vec.push_back(it->second);
771  } else {
772  ERR_CONFIG << "Attempted to enable add-on '" << id << "' but its config could not be found";
773  }
774  }
775 }
776 
778 {
779  active_addons_.clear();
780  auto& vec = game_config_view_.data();
781  vec.clear();
782  vec.push_back(game_config_);
783 
784  for(const auto& pair : addon_cfgs_) {
785  LOG_CONFIG << "Enabling add-on " << pair.first;
786  vec.push_back(pair.second);
787  active_addons_.emplace(pair.first);
788  }
789 }
config get_addon_pbl_info(const std::string &addon_name, bool do_validate)
Gets the publish information for an add-on.
Definition: manager.cpp:70
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:65
void refresh_addon_version_info_cache()
Refreshes the per-session cache of add-on's version information structs.
Definition: manager.cpp:387
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:159
void append(const config &cfg)
Append data from another config object to this one.
Definition: config.cpp:204
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:395
void append_children_by_move(config &cfg, const std::string &key)
Moves children with the given name from the given config to this one.
Definition: config.cpp:229
optional_config_impl< 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:787
const_all_children_itors all_children_range() const
In-order iteration over all children.
Definition: config.cpp:887
child_itors child_range(config_key_type key)
Definition: config.cpp:273
bool empty() const
Definition: config.cpp:852
const attribute_value * get(config_key_type key) const
Returns a pointer to the attribute with the given key or nullptr if it does not exist.
Definition: config.cpp:687
std::string hash() const
Definition: config.cpp:1287
config & add_child(config_key_type key)
Definition: config.cpp:441
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.
void set_force_valid_cache(bool force)
Enable/disable cache validation.
void get_config(const std::string &path, config &cfg, abstract_validator *validator=nullptr)
Gets a config object from given path.
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()
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_
std::shared_ptr< terrain_type_data > tdata_
game_config_manager(const commandline_options &cmdline_opts)
void set_enabled_addon(std::set< std::string > addon_ids)
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(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
void set_core_id(const std::string &root)
static prefs & get()
void set_last_cache_cleared_version(const std::string &version)
void load_advanced_prefs(const game_config_view &gc)
void load_hotkeys()
std::string core_id()
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:289
static void set_known_themes(const game_config_view *cfg)
Copies the theme configs from the main game config.
Definition: theme.cpp:977
void set_config(const game_config_view &cfg)
Resets all data based on the provided config.
Definition: types.cpp:1101
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
#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:97
static std::string _(const char *str)
Definition: gettext.hpp:93
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:205
void init_textdomains(const game_config_view &cfg)
Initializes the list of textdomains from a configuration object.
Definition: language.cpp:371
bool init_strings(const game_config_view &cfg)
Initializes certain English strings.
Definition: language.cpp:389
Standard logging facilities (interface).
#define log_scope2(domain, description)
Definition: log.hpp:278
#define FORCE_LOG_TO(logger, domain)
Definition: log.hpp:293
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:812
utils::optional< 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, if either exists.
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:410
const std::string wml_extension
Definition: filesystem.hpp:80
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:324
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:89
const version_info wesnoth_version(VERSION)
const bool & debug
Definition: game_config.cpp:92
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:216
logger & err()
Definition: log.cpp:304
log_domain & general()
Definition: log.cpp:330
logger & info()
Definition: log.cpp:316
game_classification * classification
Definition: resources.cpp:34
void flush_cache()
Definition: sound.cpp:193
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:66
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:1486
#define e