The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
persist_var.cpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2010 - 2025
3 by Jody Northup
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_data.hpp"
17#include "gettext.hpp"
18#include "log.hpp"
19#include "persist_context.hpp"
20#include "persist_manager.hpp"
21#include "persist_var.hpp"
22#include "play_controller.hpp"
24#include "resources.hpp"
25#include "variable.hpp"
26
27
28//TODO: remove LOG_PERSIST, ERR_PERSIST from persist_context.hpp to .cpp files.
29#define DBG_PERSIST LOG_STREAM(debug, log_persist)
30#define ERR_PERSIST LOG_STREAM(err, log_persist)
31
34 std::string var_name;
35 int side;
36 persist_choice(const persist_context &context,const std::string &name, int side_num)
37 : ctx(context)
38 , var_name(name)
39 , side(side_num) {
40 }
41 virtual config query_user(int /*side_for*/) const {
42 //side can be different from side_for: if side was null-controlled
43 //then get_user_choice will use the next non-null-controlled side instead
44 config ret;
45 ret["side"] = side;
46 ret.add_child("variables",ctx.get_var(var_name));
47 return ret;
48 }
49 virtual config random_choice(int /*side_for*/) const {
50 return config();
51 }
52
53 virtual std::string description() const
54 {
55 // TRANSLATORS: In networked games, this text is shown for other
56 // clients, while they wait to receive the content of a global variable
57 // from another player. This text will be embedded into a sentence.
58 return _("waiting for^a global variable");
59 }
60 virtual bool is_visible() const { return false; }
61};
62
63static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
64{
65 std::string global = pcfg["from_global"];
66 std::string local = pcfg["to_local"];
67 config::attribute_value pcfg_side = pcfg["side"];
68 const int side = pcfg_side.to_int(resources::controller->current_side());
69 persist_choice choice(ctx, global, side);
70 config cfg = mp_sync::get_user_choice("global_variable",choice,side).mandatory_child("variables");
71 try
72 {
73 std::size_t arrsize = cfg.child_count(global);
74 if (arrsize == 0) {
75 resources::gamedata->set_variable(local,cfg[global]);
76 } else {
78 for (std::size_t i = 0; i < arrsize; i++)
79 resources::gamedata->add_variable_cfg(local, cfg.mandatory_child(global,i));
80 }
81 }
83 {
84 ERR_PERSIST << "cannot store global variable into invalid variablename " << local;
85 }
86}
87
88static void clear_global_variable(persist_context &ctx, const vconfig &pcfg)
89{
90 std::string global = pcfg["global"];
91 ctx.clear_var(global, pcfg["immediate"].to_bool());
92}
93
94static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
95{
96 if (pcfg["from_local"].empty()) {
97 clear_global_variable(ctx, pcfg);
98 } else {
99 std::string global = pcfg["to_global"];
100 std::string local = pcfg["from_local"];
101 config val;
103 std::size_t arraylen = vars.child_count(local);
104 if (arraylen == 0) {
105 try
106 {
107 val = pack_scalar(global, resources::gamedata->get_variable(local).t_str());
108 }
110 {
111 val.clear();
112 }
113 } else {
114 for (std::size_t i = 0; i < arraylen; i++)
115 val.add_child(global, vars.mandatory_child(local,i));
116 }
117 ctx.set_var(global, val, pcfg["immediate"].to_bool());
118 }
119}
121{
122 bool valid = true;
123 if (!pcfg.has_attribute("from_global")) {
124 ERR_PERSIST << "[get_global_variable] missing required attribute \"from_global\"";
125 valid = false;
126 }
127 if (!pcfg.has_attribute("to_local")) {
128 ERR_PERSIST << "[get_global_variable] missing required attribute \"to_local\"";
129 valid = false;
130 }
131 // TODO: allow for global namespace.
132 if (!pcfg.has_attribute("namespace")) {
133 ERR_PERSIST << "[get_global_variable] missing attribute \"namespace\"";
134 valid = false;
135 }
136 if (resources::controller->is_networked_mp()) {
137 DBG_PERSIST << "verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"];
138 config::attribute_value pcfg_side = pcfg["side"];
139 int side = (pcfg_side.str() == "global" || pcfg_side.empty()) ? resources::controller->current_side() : pcfg_side.to_int();
140 if (!resources::gameboard->has_team(side)) {
141 ERR_PERSIST << "[get_global_variable] attribute \"side\" specifies invalid side number.";
142 valid = false;
143 }
144 DBG_PERSIST << "end verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"];
145 }
146 if (valid)
147 {
148 persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
149 if (ctx.valid()) {
150 get_global_variable(ctx,pcfg);
151 } else {
152 LOG_PERSIST << "Error: [get_global_variable] attribute \"namespace\" is not valid.";
153 }
154 }
155}
157{
158 bool valid = true;
159 if (!pcfg.has_attribute("to_global")) {
160 ERR_PERSIST << "[set_global_variable] missing required attribute \"to_global\"";
161 valid = false;
162 }
163 if (!pcfg.has_attribute("from_local")) {
164 LOG_PERSIST << "Warning: [set_global_variable] missing attribute \"from_local\", global variable will be cleared";
165 }
166 // TODO: allow for global namespace.
167 if (!pcfg.has_attribute("namespace")) {
168 ERR_PERSIST << "[set_global_variable] missing attribute \"namespace\" and no global namespace provided.";
169 valid = false;
170 }
171 if (resources::controller->is_networked_mp()) {
172 config::attribute_value pcfg_side = pcfg["side"];
173 int side = pcfg_side.to_int();
174 //Check side matching only if the side is not "global" or empty.
175 if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
176 //Ensure that the side is valid.
177 if (!resources::gameboard->has_team(side)) {
178 ERR_PERSIST << "[set_global_variable] attribute \"side\" specifies invalid side number.";
179 valid = false;
180 } else if (resources::gameboard->get_team(side).is_empty()) {
181 LOG_PERSIST << "[set_global_variable] attribute \"side\" specifies a null-controlled side number.";
182 valid = false;
183 } else {
184 //Set the variable only if it is meant for a side we control
185 valid = resources::gameboard->get_team(side).is_local();
186 }
187 }
188 }
189 if (valid)
190 {
191 persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
192 if (ctx.valid()) {
193 set_global_variable(ctx,pcfg);
194 } else {
195 LOG_PERSIST << "Error: [set_global_variable] attribute \"namespace\" is not valid.";
196 }
197 }
198}
200{
201 bool valid = true;
202 if (!pcfg.has_attribute("global")) {
203 ERR_PERSIST << "[clear_global_variable] missing required attribute \"global\"";
204 valid = false;
205 }
206 if (!pcfg.has_attribute("namespace")) {
207 ERR_PERSIST << "[clear_global_variable] missing attribute \"namespace\" and no global namespace provided.";
208 valid = false;
209 }
210 if (resources::controller->is_networked_mp()) {
211 config::attribute_value pcfg_side = pcfg["side"];
212 const int side = pcfg_side.to_int();
213 //Check side matching only if the side is not "global" or empty.
214 if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
215 //Ensure that the side is valid.
216 if (!resources::gameboard->has_team(side)) {
217 ERR_PERSIST << "[clear_global_variable] attribute \"side\" specifies invalid side number.";
218 valid = false;
219 } else if (resources::gameboard->get_team(side).is_empty()) {
220 LOG_PERSIST << "[clear_global_variable] attribute \"side\" specifies a null-controlled side number.";
221 valid = false;
222 } else {
223 //Clear the variable only if it is meant for a side we control
224 valid = resources::gameboard->get_team(side).is_local();
225 }
226 }
227 }
228 if (valid)
229 {
230 persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
231 if (ctx.valid()) {
232 clear_global_variable(ctx,pcfg);
233 } else {
234 LOG_PERSIST << "Error: [clear_global_variable] attribute \"namespace\" is not valid.";
235 }
236 }
237}
Variant for storing WML attributes.
std::string str(const std::string &fallback="") const
bool empty() const
Tests for an attribute that either was never set or was set to "".
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
std::size_t child_count(std::string_view key) const
Definition config.cpp:292
config & mandatory_child(std::string_view key, int n=0)
Returns the nth child with the given key, or throws an error if there is none.
Definition config.cpp:362
void clear()
Definition config.cpp:802
team & get_team(int i)
void clear_variable(const std::string &varname)
Clears attributes config children does nothing if varname is no valid variable name.
const config & get_variables() const
Definition game_data.hpp:33
void set_variable(const std::string &varname, const config::attribute_value &value)
does nothing if varname is no valid variable name.
Definition game_data.cpp:88
virtual config get_var(const std::string &) const =0
virtual bool set_var(const std::string &, const config &, bool immediate=false)=0
virtual bool clear_var(const std::string &, bool immediate=false)=0
persist_context & get_context(const std::string &ns)
bool is_local() const
Definition team.hpp:288
A variable-expanding proxy for the config class.
Definition variable.hpp:45
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition variable.hpp:99
const config * cfg
static std::string _(const char *str)
Definition gettext.hpp:100
Standard logging facilities (interface).
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
game_board * gameboard
Definition resources.cpp:20
persist_manager * persist
Definition resources.cpp:26
game_data * gamedata
Definition resources.cpp:22
play_controller * controller
Definition resources.cpp:21
config pack_scalar(const std::string &name, const t_string &val)
#define LOG_PERSIST
static void clear_global_variable(persist_context &ctx, const vconfig &pcfg)
static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
void verify_and_set_global_variable(const vconfig &pcfg)
void verify_and_clear_global_variable(const vconfig &pcfg)
#define ERR_PERSIST
static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
#define DBG_PERSIST
void verify_and_get_global_variable(const vconfig &pcfg)
Interface for querying local choices.
virtual config random_choice(int) const
const persist_context & ctx
persist_choice(const persist_context &context, const std::string &name, int side_num)
virtual std::string description() const
std::string var_name
virtual bool is_visible() const
whether the choice is visible for the user like an advancement choice a non-visible choice is for exa...
virtual config query_user(int) const
#define i