The Battle for Wesnoth  1.19.1+dev
mp_game_settings.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2006 - 2024
3  by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
4  Copyright (C) 2003 by David White <dave@whitevine.net>
5  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6 
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY.
13 
14  See the COPYING file for more details.
15 */
16 
17 /**
18  * @file
19  * Container for multiplayer game-creation parameters.
20  */
21 
22 #include "log.hpp"
23 #include "mp_game_settings.hpp"
25 
26 static lg::log_domain log_engine("engine");
27 #define ERR_NG LOG_STREAM(err, log_engine)
28 #define WRN_NG LOG_STREAM(warn, log_engine)
29 #define LOG_NG LOG_STREAM(info, log_engine)
30 #define DBG_NG LOG_STREAM(debug, log_engine)
31 
33  name(),
34  password(),
35  hash(),
36  mp_era_name(),
37  mp_scenario(),
38  mp_scenario_name(),
39  mp_campaign(),
40  side_users(),
41  num_turns(0),
42  village_gold(0),
43  village_support(1),
44  xp_modifier(100),
45  mp_countdown_init_time(0),
46  mp_countdown_reservoir_time(0),
47  mp_countdown_turn_bonus(0),
48  mp_countdown_action_bonus(0),
49  mp_countdown(false),
50  use_map_settings(false),
51  random_start_time(false),
52  fog_game(false),
53  shroud_game(false),
54  allow_observers(true),
55  private_replay(false),
56  shuffle_sides(false),
58  mode(random_faction_mode::type::independent),
59  options(),
60  addons()
61 {}
62 
64  : name(cfg["scenario"].str())
65  , password()
66  , hash(cfg["hash"].str())
67  , mp_era_name(cfg["mp_era_name"].str())
68  , mp_scenario(cfg["mp_scenario"].str())
69  , mp_scenario_name(cfg["mp_scenario_name"].str())
70  , mp_campaign(cfg["mp_campaign"].str())
71  , side_users(utils::map_split(cfg["side_users"]))
72  , num_turns(cfg["mp_num_turns"])
73  , village_gold(cfg["mp_village_gold"])
74  , village_support(cfg["mp_village_support"])
75  , xp_modifier(cfg["experience_modifier"].to_int(100))
76  , mp_countdown_init_time(cfg["mp_countdown_init_time"])
77  , mp_countdown_reservoir_time(cfg["mp_countdown_reservoir_time"])
78  , mp_countdown_turn_bonus(cfg["mp_countdown_turn_bonus"])
79  , mp_countdown_action_bonus(cfg["mp_countdown_action_bonus"])
80  , mp_countdown(cfg["mp_countdown"].to_bool())
81  , use_map_settings(cfg["mp_use_map_settings"].to_bool())
82  , random_start_time(cfg["mp_random_start_time"].to_bool())
83  , fog_game(cfg["mp_fog"].to_bool())
84  , shroud_game(cfg["mp_shroud"].to_bool())
85  , allow_observers(cfg["observer"].to_bool())
86  , private_replay(cfg["private_replay"].to_bool())
87  , shuffle_sides(cfg["shuffle_sides"].to_bool())
88  , saved_game(saved_game_mode::get_enum(cfg["savegame"].str()).value_or(saved_game_mode::type::no))
89  , mode(random_faction_mode::get_enum(cfg["random_faction_mode"].str()).value_or(random_faction_mode::type::independent))
90  , options(cfg.child_or_empty("options"))
91  , addons()
92 {
93  for (const config & a : cfg.child_range("addon")) {
94  if (!a["id"].empty()) {
95  addons.emplace(a["id"].str(), addon_version_info(a));
96  }
97  }
98 }
99 
101 {
102  config cfg;
103 
104  cfg["scenario"] = name;
105  cfg["hash"] = hash;
106  cfg["mp_era_name"] = mp_era_name;
107  cfg["mp_scenario"] = mp_scenario;
108  cfg["mp_scenario_name"] = mp_scenario_name;
109  cfg["mp_campaign"] = mp_campaign;
110  cfg["side_users"] = utils::join_map(side_users);
111  cfg["experience_modifier"] = xp_modifier;
112  cfg["mp_countdown"] = mp_countdown;
113  cfg["mp_countdown_init_time"] = mp_countdown_init_time;
114  cfg["mp_countdown_turn_bonus"] = mp_countdown_turn_bonus;
115  cfg["mp_countdown_reservoir_time"] = mp_countdown_reservoir_time;
116  cfg["mp_countdown_action_bonus"] = mp_countdown_action_bonus;
117  cfg["mp_num_turns"] = num_turns;
118  cfg["mp_village_gold"] = village_gold;
119  cfg["mp_village_support"] = village_support;
120  cfg["mp_fog"] = fog_game;
121  cfg["mp_shroud"] = shroud_game;
122  cfg["mp_use_map_settings"] = use_map_settings;
123  cfg["mp_random_start_time"] = random_start_time;
124  cfg["observer"] = allow_observers;
125  cfg["private_replay"] = private_replay;
126  cfg["shuffle_sides"] = shuffle_sides;
127  cfg["random_faction_mode"] = random_faction_mode::get_string(mode);
128  cfg["savegame"] = saved_game_mode::get_string(saved_game);
129  cfg.add_child("options", options);
130 
131  for(auto& p : addons) {
132  config & c = cfg.add_child("addon");
133  p.second.write(c);
134  c["id"] = p.first;
135  }
136 
137  return cfg;
138 }
139 
141  : version()
142  , min_version()
143  , name(cfg["name"])
144  , required(cfg["required"].to_bool(false))
145  , content()
146 {
147  if (!cfg["version"].empty()) {
148  version = cfg["version"].str();
149  }
150  if (!cfg["min_version"].empty()) {
151  min_version = cfg["min_version"].str();
152  }
153  for(const auto& child : cfg.child_range("content")) {
154  content.emplace_back(addon_content{ child["id"].str(), child["name"].str(), child["type"].str() });
155  }
156 }
157 
159  if (version) {
160  cfg["version"] = *version;
161  }
162  if (min_version) {
163  cfg["min_version"] = *min_version;
164  }
165 
166  cfg["name"] = name;
167  cfg["required"] = required;
168  for(const auto& item : content) {
169  config& c = cfg.add_child("content");
170  c["id"] = item.id;
171  c["name"] = item.name;
172  c["type"] = item.type;
173  }
174 }
175 
177  if (cfg["id"].empty()) {
178  WRN_NG << "Tried to add add-on metadata to a game, missing mandatory id field... skipping.\n" << cfg.debug();
179  return;
180  }
181 
183 
184  // if the add-on doesn't require all players have it, then min_version is irrelevant
185  if(!new_data.required) {
186  new_data.min_version = {};
187  }
188  // else if it is required and no min_version was explicitly specified, default the min_version to the add-on's version
189  else if(new_data.required && !new_data.min_version) {
190  new_data.min_version = new_data.version;
191  }
192 
194  // Check if this add-on already has an entry as a dependency for this scenario. If so, try to reconcile their version info,
195  // by taking the larger of the min versions. The version should be the same for all WML from the same add-on...
196  if (it != addons.end()) {
197  addon_version_info& addon = it->second;
198 
199  // an add-on can contain multiple types of content
200  // for example, an era and a scenario
201  for(const auto& item : new_data.content) {
202  addon.content.emplace_back(addon_content{ item.id, item.name, item.type });
203  }
204 
205  if(addon.version != new_data.version) {
206  ERR_NG << "Addon version data mismatch! Not all local WML has same version of the addon: '" << cfg["id"].str() << "'.";
207  }
208 
209  if(new_data.required) {
210  addon.required = true;
211 
212  // if the existing entry for the add-on didn't have a min_version or had a lower min_version, update it to this min_version
213  if (!addon.min_version || *new_data.min_version > *addon.min_version) {
214  addon.min_version = new_data.min_version;
215  }
216  }
217  } else {
218  // Didn't find this addon-id in the map, so make a new entry.
219  addons.emplace(cfg["id"].str(), new_data);
220  }
221 }
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
child_itors child_range(config_key_type key)
Definition: config.cpp:273
std::string debug() const
Definition: config.cpp:1244
config & add_child(config_key_type key)
Definition: config.cpp:441
Standard logging facilities (interface).
#define WRN_NG
static lg::log_domain log_engine("engine")
#define ERR_NG
int village_support
Definition: game_config.cpp:39
std::pair< std::string, unsigned > item
Definition: help_impl.hpp:410
std::map< std::string, std::string > map_split(const std::string &val, char major, char minor, int flags, const std::string &default_value)
Splits a string based on two separators into a map.
std::string join_map(const T &v, const std::string &major=",", const std::string &minor=":")
std::string::const_iterator iterator
Definition: tokenizer.hpp:25
std::optional< version_info > min_version
std::vector< addon_content > content
std::optional< version_info > version
random_faction_mode::type mode
std::string mp_campaign
void update_addon_requirements(const config &addon_cfg)
Takes a config with addon metadata (id, name, version, min_version) and adds it as a requirement for ...
config to_config() const
std::string mp_scenario_name
std::string mp_era_name
std::map< std::string, std::string > side_users
std::map< std::string, addon_version_info > addons
the key is the addon_id
std::string mp_scenario
The base template for associating string values with enum values.
Definition: enum_base.hpp:33
static std::string get_string(enum_type key)
Converts a enum to its string equivalent.
Definition: enum_base.hpp:46
mock_char c
mock_party p
#define a