The Battle for Wesnoth  1.15.1+dev
persist_var.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2018 by Jody Northup
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "game_data.hpp"
16 #include "gettext.hpp"
17 #include "log.hpp"
18 #include "persist_context.hpp"
19 #include "persist_manager.hpp"
20 #include "persist_var.hpp"
21 #include "play_controller.hpp"
22 #include "synced_user_choice.hpp"
23 #include "resources.hpp"
24 #include "variable.hpp"
25 
26 #include <cassert>
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 
63 static 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).child("variables");
71  try
72  {
73  if (cfg) {
74  std::size_t arrsize = cfg.child_count(global);
75  if (arrsize == 0) {
76  resources::gamedata->set_variable(local,cfg[global]);
77  } else {
79  for (std::size_t i = 0; i < arrsize; i++)
80  resources::gamedata->add_variable_cfg(local,cfg.child(global,i));
81  }
82  } else {
84  }
85  }
86  catch(const invalid_variablename_exception&)
87  {
88  ERR_PERSIST << "cannot store global variable into invalid variablename " << local << std::endl;
89  }
90 }
91 
93 {
94  std::string global = pcfg["global"];
95  ctx.clear_var(global, pcfg["immediate"].to_bool());
96 }
97 
98 static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
99 {
100  if (pcfg["from_local"].empty()) {
101  clear_global_variable(ctx, pcfg);
102  } else {
103  std::string global = pcfg["to_global"];
104  std::string local = pcfg["from_local"];
105  config val;
106  const config &vars = resources::gamedata->get_variables();
107  std::size_t arraylen = vars.child_count(local);
108  if (arraylen == 0) {
109  try
110  {
111  val = pack_scalar(global,resources::gamedata->get_variable(local));
112  }
113  catch(const invalid_variablename_exception&)
114  {
115  val.clear();
116  }
117  } else {
118  for (std::size_t i = 0; i < arraylen; i++)
119  val.add_child(global,vars.child(local,i));
120  }
121  ctx.set_var(global, val, pcfg["immediate"].to_bool());
122  }
123 }
125 {
126  bool valid = true;
127  if (!pcfg.has_attribute("from_global")) {
128  ERR_PERSIST << "[get_global_variable] missing required attribute \"from_global\"";
129  valid = false;
130  }
131  if (!pcfg.has_attribute("to_local")) {
132  ERR_PERSIST << "[get_global_variable] missing required attribute \"to_local\"";
133  valid = false;
134  }
135  // TODO: allow for global namespace.
136  if (!pcfg.has_attribute("namespace")) {
137  ERR_PERSIST << "[get_global_variable] missing attribute \"namespace\"";
138  valid = false;
139  }
140  if (resources::controller->is_networked_mp()) {
141  DBG_PERSIST << "verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
142  config::attribute_value pcfg_side = pcfg["side"];
143  int side = (pcfg_side.str() == "global" || pcfg_side.empty()) ? resources::controller->current_side() : pcfg_side.to_int();
144  if (!resources::gameboard->has_team(side)) {
145  ERR_PERSIST << "[get_global_variable] attribute \"side\" specifies invalid side number." << "\n";
146  valid = false;
147  }
148  DBG_PERSIST << "end verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
149  }
150  if (valid)
151  {
152  persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
153  if (ctx.valid()) {
154  get_global_variable(ctx,pcfg);
155  } else {
156  LOG_PERSIST << "Error: [get_global_variable] attribute \"namespace\" is not valid.";
157  }
158  }
159 }
161 {
162  bool valid = true;
163  if (!pcfg.has_attribute("to_global")) {
164  ERR_PERSIST << "[set_global_variable] missing required attribute \"to_global\"";
165  valid = false;
166  }
167  if (!pcfg.has_attribute("from_local")) {
168  LOG_PERSIST << "Warning: [set_global_variable] missing attribute \"from_local\", global variable will be cleared";
169  }
170  // TODO: allow for global namespace.
171  if (!pcfg.has_attribute("namespace")) {
172  ERR_PERSIST << "[set_global_variable] missing attribute \"namespace\" and no global namespace provided.";
173  valid = false;
174  }
175  if (resources::controller->is_networked_mp()) {
176  config::attribute_value pcfg_side = pcfg["side"];
177  int side = pcfg_side;
178  //Check side matching only if the side is not "global" or empty.
179  if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
180  //Ensure that the side is valid.
181  if (!resources::gameboard->has_team(side)) {
182  ERR_PERSIST << "[set_global_variable] attribute \"side\" specifies invalid side number.";
183  valid = false;
184  } else if (resources::gameboard->get_team(side).is_empty()) {
185  LOG_PERSIST << "[set_global_variable] attribute \"side\" specifies a null-controlled side number.";
186  valid = false;
187  } else {
188  //Set the variable only if it is meant for a side we control
189  valid = resources::gameboard->get_team(side).is_local();
190  }
191  }
192  }
193  if (valid)
194  {
195  persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
196  if (ctx.valid()) {
197  set_global_variable(ctx,pcfg);
198  } else {
199  LOG_PERSIST << "Error: [set_global_variable] attribute \"namespace\" is not valid.";
200  }
201  }
202 }
204 {
205  bool valid = true;
206  if (!pcfg.has_attribute("global")) {
207  ERR_PERSIST << "[clear_global_variable] missing required attribute \"global\"";
208  valid = false;
209  }
210  if (!pcfg.has_attribute("namespace")) {
211  ERR_PERSIST << "[clear_global_variable] missing attribute \"namespace\" and no global namespace provided.";
212  valid = false;
213  }
214  if (resources::controller->is_networked_mp()) {
215  config::attribute_value pcfg_side = pcfg["side"];
216  const int side = pcfg_side.to_int();
217  //Check side matching only if the side is not "global" or empty.
218  if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
219  //Ensure that the side is valid.
220  if (!resources::gameboard->has_team(side)) {
221  ERR_PERSIST << "[clear_global_variable] attribute \"side\" specifies invalid side number.";
222  valid = false;
223  } else if (resources::gameboard->get_team(side).is_empty()) {
224  LOG_PERSIST << "[clear_global_variable] attribute \"side\" specifies a null-controlled side number.";
225  valid = false;
226  } else {
227  //Clear the variable only if it is meant for a side we control
228  valid = resources::gameboard->get_team(side).is_local();
229  }
230  }
231  }
232  if (valid)
233  {
234  persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
235  if (ctx.valid()) {
236  clear_global_variable(ctx,pcfg);
237  } else {
238  LOG_PERSIST << "Error: [clear_global_variable] attribute \"namespace\" is not valid.";
239  }
240  }
241 }
void verify_and_get_global_variable(const vconfig &pcfg)
play_controller * controller
Definition: resources.cpp:21
#define DBG_PERSIST
Definition: persist_var.cpp:29
bool empty() const
Tests for an attribute that either was never set or was set to "".
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
Definition: persist_var.cpp:63
config & child(config_key_type key, int n=0)
Returns the nth child with the given key, or a reference to an invalid config if there is none...
Definition: config.cpp:420
std::string var_name
Definition: persist_var.cpp:34
static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
Definition: persist_var.cpp:98
Variant for storing WML attributes.
unsigned child_count(config_key_type key) const
Definition: config.cpp:390
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:99
virtual config query_user(int) const
Definition: persist_var.cpp:41
persist_manager * persist
Definition: resources.cpp:26
void verify_and_set_global_variable(const vconfig &pcfg)
config pack_scalar(const std::string &name, const t_string &val)
void clear()
Definition: config.cpp:863
const config & get_variables() const
Definition: game_data.hpp:35
virtual bool set_var(const std::string &, const config &, bool immediate=false)=0
game_data * gamedata
Definition: resources.cpp:22
#define LOG_PERSIST
static const char * name(const std::vector< SDL_Joystick *> &joysticks, const std::size_t index)
Definition: joystick.cpp:48
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:91
bool valid() const
team & get_team(int i)
Definition: game_board.hpp:104
virtual std::string description() const
Definition: persist_var.cpp:53
virtual config get_var(const std::string &) const =0
persist_choice(const persist_context &context, const std::string &name, int side_num)
Definition: persist_var.cpp:36
game_board * gameboard
Definition: resources.cpp:20
Interface for querying local choices.
#define ERR_PERSIST
Definition: persist_var.cpp:30
virtual config random_choice(int) const
Definition: persist_var.cpp:49
void set_variable(const std::string &varname, const t_string &value)
does nothing if varname is no valid variable name.
Definition: game_data.cpp:84
virtual bool clear_var(const std::string &, bool immediate=false)=0
const persist_context & ctx
Definition: persist_var.cpp:33
std::size_t i
Definition: function.cpp:933
persist_context & get_context(const std::string &ns)
bool is_local() const
Definition: team.hpp:260
config & add_child(config_key_type key)
Definition: config.cpp:476
A variable-expanding proxy for the config class.
Definition: variable.hpp:42
Standard logging facilities (interface).
static void clear_global_variable(persist_context &ctx, const vconfig &pcfg)
Definition: persist_var.cpp:92
void clear_variable(const std::string &varname)
Clears attributes config children does nothing if varname is no valid variable name.
Definition: game_data.cpp:114
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:92
virtual bool is_visible() const
whether the choice is visible for the user like an advancement choice a non-visible choice is for exa...
Definition: persist_var.cpp:60
void verify_and_clear_global_variable(const vconfig &pcfg)
std::string str(const std::string &fallback="") const