The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
mp_game_settings.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2006 - 2025
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
26static 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),
57 saved_game(saved_game_mode::type::no),
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"].to_int())
73 , village_gold(cfg["mp_village_gold"].to_int())
74 , village_support(cfg["mp_village_support"].to_int())
75 , xp_modifier(cfg["experience_modifier"].to_int(100))
76 , mp_countdown_init_time(cfg["mp_countdown_init_time"].to_int())
77 , mp_countdown_reservoir_time(cfg["mp_countdown_reservoir_time"].to_int())
78 , mp_countdown_turn_bonus(cfg["mp_countdown_turn_bonus"].to_int())
79 , mp_countdown_action_bonus(cfg["mp_countdown_action_bonus"].to_int())
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);
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
193 std::map<std::string, addon_version_info>::iterator it = addons.find(cfg["id"].str());
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}
#define WRN_NG
#define ERR_NG
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
child_itors child_range(std::string_view key)
Definition config.cpp:268
std::string debug() const
Definition config.cpp:1214
const config * cfg
Standard logging facilities (interface).
static lg::log_domain log_engine("engine")
std::string join_map(const T &v, const std::string &major=",", const std::string &minor=":")
std::vector< addon_content > content
utils::optional< version_info > min_version
utils::optional< version_info > version
random_faction_mode::type mode
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::chrono::seconds mp_countdown_reservoir_time
std::string mp_scenario_name
std::chrono::seconds mp_countdown_action_bonus
std::chrono::seconds mp_countdown_turn_bonus
std::map< std::string, std::string > side_users
std::chrono::seconds mp_countdown_init_time
std::map< std::string, addon_version_info > addons
the key is the addon_id
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_party p
#define c