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