The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
persist_var.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2010 - 2016 by Jody Northup
3  Part of the Battle for Wesnoth Project http://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 "global.hpp"
16 
17 #include "game_data.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"
23 #include "synced_user_choice.hpp"
24 #include "resources.hpp"
25 #include "util.hpp"
26 #include "variable.hpp"
27 
28 #include <cassert>
29 
30 //TODO: remove LOG_PERSIST, ERR_PERSIST from persist_context.hpp to .cpp files.
31 #define DBG_PERSIST LOG_STREAM(debug, log_persist)
32 #define ERR_PERSIST LOG_STREAM(err, log_persist)
33 
37  int side;
38  persist_choice(const persist_context &context,const std::string &name, int side_num)
39  : ctx(context)
40  , var_name(name)
41  , side(side_num) {
42  }
43  virtual config query_user(int /*side_for*/) const {
44  //side can be different from side_for: if side was null-controlled
45  //then get_user_choice will use the next non-null-controlled side instead
46  config ret;
47  ret["side"] = side;
48  ret.add_child("variables",ctx.get_var(var_name));
49  return ret;
50  }
51  virtual config random_choice(int /*side_for*/) const {
52  return config();
53  }
54 
55  virtual std::string description() const
56  {
57  return "a global variable";
58  }
59  virtual bool is_visible() const { return false; }
60 };
61 
62 static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
63 {
64  std::string global = pcfg["from_global"];
65  std::string local = pcfg["to_local"];
66  config::attribute_value pcfg_side = pcfg["side"];
67  const int side = pcfg_side.to_int(resources::controller->current_side());
68  persist_choice choice(ctx, global, side);
69  config cfg = mp_sync::get_user_choice("global_variable",choice,side).child("variables");
70  try
71  {
72  if (cfg) {
73  size_t arrsize = cfg.child_count(global);
74  if (arrsize == 0) {
75  resources::gamedata->set_variable(local,cfg[global]);
76  } else {
78  for (size_t i = 0; i < arrsize; i++)
79  resources::gamedata->add_variable_cfg(local,cfg.child(global,i));
80  }
81  } else {
83  }
84  }
85  catch(const invalid_variablename_exception&)
86  {
87  ERR_PERSIST << "cannot store global variable into invalid variablename " << local << std::endl;
88  }
89 }
90 
91 static void clear_global_variable(persist_context &ctx, const vconfig &pcfg)
92 {
93  std::string global = pcfg["global"];
94  ctx.clear_var(global, pcfg["immediate"].to_bool());
95 }
96 
97 static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
98 {
99  if (pcfg["from_local"].empty()) {
100  clear_global_variable(ctx, pcfg);
101  } else {
102  std::string global = pcfg["to_global"];
103  std::string local = pcfg["from_local"];
104  config val;
105  const config &vars = resources::gamedata->get_variables();
106  size_t arraylen = vars.child_count(local);
107  if (arraylen == 0) {
108  try
109  {
110  val = pack_scalar(global,resources::gamedata->get_variable(local));
111  }
112  catch(const invalid_variablename_exception&)
113  {
114  val = config();
115  }
116  } else {
117  for (size_t i = 0; i < arraylen; i++)
118  val.add_child(global,vars.child(local,i));
119  }
120  ctx.set_var(global, val, pcfg["immediate"].to_bool());
121  }
122 }
124 {
125  bool valid = true;
126  if (!pcfg.has_attribute("from_global")) {
127  ERR_PERSIST << "[get_global_variable] missing required attribute \"from_global\"";
128  valid = false;
129  }
130  if (!pcfg.has_attribute("to_local")) {
131  ERR_PERSIST << "[get_global_variable] missing required attribute \"to_local\"";
132  valid = false;
133  }
134  // TODO: allow for global namespace.
135  if (!pcfg.has_attribute("namespace")) {
136  ERR_PERSIST << "[get_global_variable] missing attribute \"namespace\"";
137  valid = false;
138  }
139  if (resources::controller->is_networked_mp()) {
140  DBG_PERSIST << "verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
141  config::attribute_value pcfg_side = pcfg["side"];
142  int side = (pcfg_side.str() == "global" || pcfg_side.empty()) ? resources::controller->current_side() : pcfg_side.to_int();
143  if (unsigned (side - 1) >= resources::teams->size()) {
144  ERR_PERSIST << "[get_global_variable] attribute \"side\" specifies invalid side number." << "\n";
145  valid = false;
146  }
147  DBG_PERSIST << "end verify_and_get_global_variable with from_global=" << pcfg["from_global"] << " from side " << pcfg["side"] << "\n";
148  }
149  if (valid)
150  {
151  persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
152  if (ctx.valid()) {
153  get_global_variable(ctx,pcfg);
154  } else {
155  LOG_PERSIST << "Error: [get_global_variable] attribute \"namespace\" is not valid.";
156  }
157  }
158 }
160 {
161  bool valid = true;
162  if (!pcfg.has_attribute("to_global")) {
163  ERR_PERSIST << "[set_global_variable] missing required attribute \"to_global\"";
164  valid = false;
165  }
166  if (!pcfg.has_attribute("from_local")) {
167  LOG_PERSIST << "Warning: [set_global_variable] missing attribute \"from_local\", global variable will be cleared";
168  }
169  // TODO: allow for global namespace.
170  if (!pcfg.has_attribute("namespace")) {
171  ERR_PERSIST << "[set_global_variable] missing attribute \"namespace\" and no global namespace provided.";
172  valid = false;
173  }
174  if (resources::controller->is_networked_mp()) {
175  config::attribute_value pcfg_side = pcfg["side"];
176  int side = pcfg_side;
177  //Check side matching only if the side is not "global" or empty.
178  if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
179  //Ensure that the side is valid.
180  if (unsigned(side-1) > resources::teams->size()) {
181  ERR_PERSIST << "[set_global_variable] attribute \"side\" specifies invalid side number.";
182  valid = false;
183  } else if ((*resources::teams)[side - 1].is_empty()) {
184  LOG_PERSIST << "[set_global_variable] attribute \"side\" specifies a null-controlled side number.";
185  valid = false;
186  } else {
187  //Set the variable only if it is meant for a side we control
188  valid = (*resources::teams)[side - 1].is_local();
189  }
190  }
191  }
192  if (valid)
193  {
194  persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
195  if (ctx.valid()) {
196  set_global_variable(ctx,pcfg);
197  } else {
198  LOG_PERSIST << "Error: [set_global_variable] attribute \"namespace\" is not valid.";
199  }
200  }
201 }
203 {
204  bool valid = true;
205  if (!pcfg.has_attribute("global")) {
206  ERR_PERSIST << "[clear_global_variable] missing required attribute \"from_global\"";
207  valid = false;
208  }
209  if (!pcfg.has_attribute("namespace")) {
210  ERR_PERSIST << "[clear_global_variable] missing attribute \"namespace\" and no global namespace provided.";
211  valid = false;
212  }
213  if (resources::controller->is_networked_mp()) {
214  config::attribute_value pcfg_side = pcfg["side"];
215  const int side = pcfg_side.to_int();
216  //Check side matching only if the side is not "global" or empty.
217  if (pcfg_side.str() != "global" && !pcfg_side.empty()) {
218  //Ensure that the side is valid.
219  if (unsigned(side-1) > resources::teams->size()) {
220  ERR_PERSIST << "[clear_global_variable] attribute \"side\" specifies invalid side number.";
221  valid = false;
222  } else if ((*resources::teams)[side - 1].is_empty()) {
223  LOG_PERSIST << "[clear_global_variable] attribute \"side\" specifies a null-controlled side number.";
224  valid = false;
225  } else {
226  //Clear the variable only if it is meant for a side we control
227  valid = (*resources::teams)[side - 1].is_local();
228  }
229  }
230  }
231  if (valid)
232  {
233  persist_context &ctx = resources::persist->get_context((pcfg["namespace"]));
234  if (ctx.valid()) {
235  clear_global_variable(ctx,pcfg);
236  } else {
237  LOG_PERSIST << "Error: [clear_global_variable] attribute \"namespace\" is not valid.";
238  }
239  }
240 }
void verify_and_get_global_variable(const vconfig &pcfg)
play_controller * controller
Definition: resources.cpp:21
#define DBG_PERSIST
Definition: persist_var.cpp:31
config get_user_choice(const std::string &name, const user_choice &uch, int side=0)
std::string str() const
Definition: config.cpp:353
static void get_global_variable(persist_context &ctx, const vconfig &pcfg)
Definition: persist_var.cpp:62
virtual std::string description() const
Definition: persist_var.cpp:55
std::string var_name
Definition: persist_var.cpp:36
static void set_global_variable(persist_context &ctx, const vconfig &pcfg)
Definition: persist_var.cpp:97
virtual config random_choice(int) const
Definition: persist_var.cpp:51
GLuint const GLfloat * val
Definition: glew.h:2614
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)
virtual bool set_var(const std::string &, const config &, bool immediate=false)=0
virtual bool is_visible() const
whether the choice is visible for the user like an advacement choice a non-visible choice is for exam...
Definition: persist_var.cpp:59
bool empty() const
Tests for an attribute that either was never set or was set to "".
Definition: config.cpp:375
virtual config query_user(int) const
Definition: persist_var.cpp:43
Variant for storing WML attributes.
Definition: config.hpp:223
game_data * gamedata
Definition: resources.cpp:22
const config & get_variables() const
Definition: game_data.hpp:37
#define LOG_PERSIST
std::vector< team > * teams
Definition: resources.cpp:29
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:38
Interface for querying local choices.
#define ERR_PERSIST
Definition: persist_var.cpp:32
void set_variable(const std::string &varname, const t_string &value)
does nothing if varname is no valid variable name.
Definition: game_data.cpp:92
config & add_child(const std::string &key)
Definition: config.cpp:743
Templates and utility-routines for strings and numbers.
virtual bool clear_var(const std::string &, bool immediate=false)=0
const persist_context & ctx
Definition: persist_var.cpp:35
persist_context & get_context(const std::string &ns)
Information on a WML variable.
size_t i
Definition: function.cpp:1057
unsigned child_count(const std::string &key) const
Definition: config.cpp:635
GLuint const GLchar * name
Definition: glew.h:1782
GLsizeiptr size
Definition: glew.h:1649
config & child(const std::string &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:658
A variable-expanding proxy for the config class.
Definition: variable.hpp:36
Standard logging facilities (interface).
int to_int(int def=0) const
Definition: config.cpp:308
static void clear_global_variable(persist_context &ctx, const vconfig &pcfg)
Definition: persist_var.cpp:91
void clear_variable(const std::string &varname)
Clears attributes config children does nothing if varname is no valid variable name.
Definition: game_data.cpp:122
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
GLsizei const GLcharARB ** string
Definition: glew.h:4503
bool has_attribute(const std::string &key) const
< Synonym for operator[]
Definition: variable.hpp:92
bool valid() const
void verify_and_clear_global_variable(const vconfig &pcfg)
const std::string valid
Little parts of regex templates used to parse Wml annoations.