The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
aspect.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2016 by Yurii Chernyi <[email protected]>
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 /**
16  * @file
17  */
18 
19 #ifndef AI_COMPOSITE_ASPECT_HPP_INCLUDED
20 #define AI_COMPOSITE_ASPECT_HPP_INCLUDED
21 
24 #include "ai/lua/lua_object.hpp"
25 #include "ai/lua/core.hpp"
27 
28 #include "log.hpp"
29 #include "util.hpp"
30 
31 #include "utils/functional.hpp"
32 #include <boost/pointer_cast.hpp>
33 
34 #ifdef _MSC_VER
35 #pragma warning(push)
36 //silence "inherits via dominance" warnings
37 #pragma warning(disable:4250)
38 #endif
39 
40 namespace ai {
41 
42 class aspect : public readonly_context_proxy, public events::observer, public component {
43 public:
44  aspect(readonly_context &context, const config &cfg, const std::string &id);
45 
46  virtual ~aspect();
47 
48  void invalidate() const
49  {
50  valid_ = false;
51  valid_variant_ = false;
52  valid_lua_ = false;
53  }
54 
55 
56  virtual const variant& get_variant() const = 0;
57 
58 
59  virtual boost::shared_ptr<variant> get_variant_ptr() const = 0;
60 
61 
62  virtual void recalculate() const = 0;
63 
64 
65  virtual void on_create();
66 
67 
68  virtual bool redeploy(const config &cfg, const std::string & id);
69 
70 
71  virtual config to_config() const;
72 
73 
74  virtual bool delete_all_facets();
75 
76 
77  void handle_generic_event(const std::string &/*event_name*/)
78  {
79  invalidate();
80  }
81 
82 
83  virtual bool active() const;
84 
85  virtual std::string get_name() const
86  { return name_; }
87 
88  virtual std::string get_id() const
89  { return id_; }
90 
91  virtual std::string get_engine() const
92  { return engine_; }
93 
94  static lg::log_domain& log();
95 
96 protected:
99 
100  mutable bool valid_;
101  mutable bool valid_variant_;
102  mutable bool valid_lua_;
103 
112 
113 };
114 
115 template<typename T>
116 class typesafe_aspect : public aspect {
117 public:
118  typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
119  : aspect(context,cfg,id)
120  , value_()
121  , value_variant_()
122  , value_lua_()
123  {
124  }
125 
127  {
128  }
129 
130 
131  virtual const T& get() const
132  {
133  return *get_ptr();
134  }
135 
136 
137  virtual const variant& get_variant() const
138  {
139  return *get_variant_ptr();
140  }
141 
143  {
144  if (!valid_variant_) {
145  if (!valid_) {
146  recalculate();
147  }
148 
149  if (!valid_variant_ && valid_ ) {
151  valid_variant_ = true;
152  } else if (!valid_variant_ && valid_lua_) {
153  value_ = value_lua_->get();
155  valid_variant_ = true; // @note: temporary workaround
156  } else {
157  assert(valid_variant_);
158  }
159  }
160  return value_variant_;
161  }
162 
163  virtual void recalculate() const = 0;
164 
165 
167  {
168  if (!valid_) {
169  if (!(valid_variant_ || valid_lua_)) {
170  recalculate();
171  }
172 
173  if (!valid_ ) {
174  if (valid_variant_) {
176  valid_ = true;
177  } else if (valid_lua_){
178  value_ = value_lua_->get();
179  valid_ = true;
180  } else {
181  assert(valid_);
182  }
183  }
184  }
185  return value_;
186  }
187 
188 protected:
192 };
193 
194 
196 public:
197  known_aspect(const std::string &name);
198 
199 
200  virtual ~known_aspect();
201 
202 
203  virtual void set(aspect_ptr a) = 0;
204 
205 
206  virtual void add_facet(const config &cfg) = 0;
207 
208 
209  const std::string& get_name() const;
210 
211 protected:
213 };
214 
215 
216 template<class T>
218 
219 template<typename T>
221 public:
223  : known_aspect(name), where_(where), aspects_(aspects)
224  {
225  }
226 
228  {
229  boost::shared_ptr< typesafe_aspect <T> > c = boost::dynamic_pointer_cast< typesafe_aspect<T> >(a);
230  if (c) {
231  assert (c->get_id()== this->get_name());
232  where_ = c;
233  aspects_.insert(make_pair(this->get_name(),c));
234  } else {
235  LOG_STREAM(debug, aspect::log()) << "typesafe_known_aspect [" << this->get_name() << "] : while setting aspect, got null. this might be caused by invalid [aspect] WML" << std::endl;
236  }
237  }
238 
239  virtual void add_facet(const config &cfg)
240  {
241  boost::shared_ptr< composite_aspect <T> > c = boost::dynamic_pointer_cast< composite_aspect<T> >(where_);
242  if (c) {
243  assert (c->get_id()==this->get_name());
244  c->add_facet(-1, cfg);
245  c->invalidate();
246  } else {
247  LOG_STREAM(debug, aspect::log()) << "typesafe_known_aspect [" << this->get_name() << "] : while adding facet to aspect, got null. this might be caused by target [aspect] being not composite" << std::endl;
248  }
249  }
250 
251 protected:
254 
255 };
256 
257 
258 template<typename T>
259 class composite_aspect : public typesafe_aspect<T> {
260 public:
261 
262  composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
263  : typesafe_aspect<T>(context, cfg, id)
264  , facets_()
265  , default_()
266  , parent_id_(id)
267  {
268  for (const config &cfg_element : this->cfg_.child_range("facet")) {
269  add_facet(-1,cfg_element);
270  }
271 
272  config _default = this->cfg_.child("default");
273  if (_default) {
274  _default["id"] = "default_facet";
275  std::vector< aspect_ptr > default_aspects;
276  engine::parse_aspect_from_config(*this,_default,parent_id_,std::back_inserter(default_aspects));
277  if (!default_aspects.empty()) {
278  typename aspect_type<T>::typesafe_ptr b = boost::dynamic_pointer_cast< typesafe_aspect<T> >(default_aspects.front());
279  if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
280  c->parent_id_ = parent_id_;
281  }
282  default_ = b;
283  }
284  }
285 
286  std::function<void(typename aspect_type<T>::typesafe_ptr_vector&, const config&)> factory_facets =
287  std::bind(&ai::composite_aspect<T>::create_facet,*this,_1,_2);
288 
289  register_facets_property(this->property_handlers(),"facet",facets_,default_, factory_facets);
290 
291  }
292 
293 
294  void create_facet( typename aspect_type<T>::typesafe_ptr_vector &facets, const config &cfg)
295  {
296  std::vector<aspect_ptr> facets_base;
297  engine::parse_aspect_from_config(*this,cfg,parent_id_,std::back_inserter(facets_base));
298  for (aspect_ptr a : facets_base) {
299  typename aspect_type<T>::typesafe_ptr b = boost::dynamic_pointer_cast< typesafe_aspect<T> > (a);
300  if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
301  c->parent_id_ = parent_id_;
302  }
303  facets.push_back(b);
304  }
305  }
306 
307 
308  virtual void recalculate() const
309  {
310  ///@todo 1.9 optimize in case of an aspect which returns variant
311  for (const typename aspect_type<T>::typesafe_ptr &f : make_pair(facets_.rbegin(),facets_.rend())) {
312  if (f->active()) {
313  this->value_ = boost::shared_ptr<T>(f->get_ptr());
314  this->valid_ = true;
315  return;
316  }
317  }
318  if (default_) {
319  this->value_ = boost::shared_ptr<T>(default_->get_ptr());
320  this->valid_ = true;
321  }
322  }
323 
324 
325  virtual config to_config() const
326  {
327  config cfg = aspect::to_config();
328  for (const typename aspect_type<T>::typesafe_ptr f : facets_) {
329  cfg.add_child("facet",f->to_config());
330  }
331  if (default_) {
332  cfg.add_child("default",default_->to_config());
333  }
334  return cfg;
335  }
336 
337 
339  virtual bool add_facet(int pos, const config &cfg)
340  {
341  if (pos<0) {
342  pos = facets_.size();
343  }
344  std::vector< aspect_ptr > facets;
345  engine::parse_aspect_from_config(*this,cfg,parent_id_,std::back_inserter(facets));
346  int j=0;
347  for (aspect_ptr a : facets) {
348  typename aspect_type<T>::typesafe_ptr b = boost::dynamic_pointer_cast< typesafe_aspect<T> > (a);
349  if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
350  c->parent_id_ = parent_id_;
351  }
352  facets_.insert(facets_.begin()+pos+j,b);
353  j++;
354  }
355  return (j>0);
356  }
357 
358 
359  virtual bool delete_all_facets()
360  {
361  bool b = !facets_.empty();
362  facets_.clear();
363  return b;
364  }
365 
366 protected:
370 
371 };
372 
373 template<typename T>
374 class standard_aspect : public typesafe_aspect<T> {
375 public:
376  standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
377  : typesafe_aspect<T>(context, cfg, id)
378  {
379  this->name_ = "standard_aspect";
381  this->value_= value;
382  LOG_STREAM(debug, aspect::log()) << "standard aspect has value: "<< std::endl << config_value_translator<T>::value_to_cfg(this->get()) << std::endl;
383  }
384 
385 
386  void recalculate() const
387  {
388  //nothing to recalculate
389  this->valid_ = true;
390  }
391 
392 
394  {
395  config cfg = aspect::to_config();
397  return cfg;
398  }
399 
400 };
401 
402 class lua_aspect_visitor : public boost::static_visitor<std::string> {
403  static std::string quote_string(const std::string& s);
404 public:
405  std::string operator()(bool b) const {return b ? "true" : "false";}
406  std::string operator()(int i) const {return std::to_string(i);}
407  std::string operator()(unsigned long long i) const {return std::to_string(i);}
408  std::string operator()(double i) const {return std::to_string(i);}
409  std::string operator()(const std::string& s) const {return quote_string(s);}
410  std::string operator()(const t_string& s) const {return quote_string(s.str());}
411  std::string operator()(boost::blank) const {return "nil";}
412 };
413 
414 template<typename T>
415 class lua_aspect : public typesafe_aspect<T>
416 {
417 public:
419  : typesafe_aspect<T>(context, cfg, id)
420  , handler_(), code_(), params_(cfg.child_or_empty("args"))
421  {
422  this->name_ = "lua_aspect";
423  if (cfg.has_attribute("code"))
424  {
425  code_ = cfg["code"].str();
426  }
427  else if (cfg.has_attribute("value"))
428  {
429  code_ = "return " + cfg["value"].apply_visitor(lua_aspect_visitor());
430  }
431  else
432  {
433  // error
434  return;
435  }
437  }
438 
439  void recalculate() const
440  {
441  this->valid_lua_ = true;
442  this->value_lua_.reset(new lua_object<T>);
443  handler_->handle(params_, true, this->value_lua_);
444  }
445 
447  {
448  config cfg = aspect::to_config();
449  cfg["code"] = code_;
450  if (!params_.empty()) {
451  cfg.add_child("args", params_);
452  }
453  return cfg;
454  }
455 
456 private:
460 };
461 
462 
464  bool is_duplicate(const std::string &name);
465 public:
467  typedef std::map<std::string, factory_ptr> factory_map;
468  typedef std::pair<const std::string, factory_ptr> factory_map_pair;
469 
470  static factory_map& get_list() {
471  static factory_map *aspect_factories;
472  if (aspect_factories==nullptr) {
473  aspect_factories = new factory_map;
474  }
475  return *aspect_factories;
476  }
477 
478  virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id) = 0;
479 
481  {
482  if (is_duplicate(name)) {
483  return;
484  }
485  factory_ptr ptr_to_this(this);
486  get_list().insert(make_pair(name,ptr_to_this));
487  }
488 
489  virtual ~aspect_factory() {}
490 };
491 
492 
493 template<class ASPECT>
495 public:
497  : aspect_factory( name )
498  {
499  }
500 
502  {
503  boost::shared_ptr<ASPECT> _a(new ASPECT(context,cfg,id));
504  aspect_ptr a = _a;
505  a->on_create();
506  return a;
507  }
508 };
509 
511 public:
513  typedef std::map<std::string, factory_ptr> factory_map;
514  typedef std::pair<const std::string, factory_ptr> factory_map_pair;
515 
516  static factory_map& get_list() {
517  static factory_map *aspect_factories;
518  if (aspect_factories==nullptr) {
519  aspect_factories = new factory_map;
520  }
521  return *aspect_factories;
522  }
523 
524  virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr<lua_ai_context>& l_ctx) = 0;
525 
527  {
528  factory_ptr ptr_to_this(this);
529  get_list().insert(make_pair(name,ptr_to_this));
530  }
531 
532  virtual ~lua_aspect_factory() {}
533 };
534 
535 template<class ASPECT>
537 public:
539  : lua_aspect_factory( name )
540  {
541  }
542 
544  {
545  boost::shared_ptr<ASPECT> _a(new ASPECT(context,cfg,id,l_ctx));
546  aspect_ptr a = _a;
547  a->on_create();
548  return a;
549  }
550 };
551 
552 
553 } //end of namespace ai
554 
555 #ifdef _MSC_VER
556 #pragma warning(pop)
557 #endif
558 
559 #endif
child_itors child_range(const std::string &key)
Definition: config.cpp:613
lua_aspect_factory(const std::string &name)
Definition: aspect.hpp:526
virtual config to_config() const
Definition: aspect.cpp:117
virtual bool add_facet(int pos, const config &cfg)
Definition: aspect.hpp:339
bool invalidate_on_tod_change_
Definition: aspect.hpp:106
aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:501
void set(aspect_ptr a)
Definition: aspect.hpp:227
std::string operator()(boost::blank) const
Definition: aspect.hpp:411
bool valid_variant_
Definition: aspect.hpp:101
virtual ~lua_aspect_factory()
Definition: aspect.hpp:532
virtual const variant & get_variant() const
Definition: aspect.hpp:137
const std::string & get_name() const
Definition: aspect.cpp:151
std::map< std::string, factory_ptr > factory_map
Definition: aspect.hpp:513
boost::shared_ptr< T > value_
Definition: aspect.hpp:189
std::string turns_
Definition: aspect.hpp:98
static factory_map & get_list()
Definition: aspect.hpp:516
const GLfloat * c
Definition: glew.h:12741
int pos
Definition: formula.cpp:800
bool is_duplicate(const std::string &name)
Definition: aspect.cpp:172
aspect_factory(const std::string &name)
Definition: aspect.hpp:480
virtual void recalculate() const =0
virtual void set(aspect_ptr a)=0
property_handler_map & property_handlers()
Definition: component.cpp:133
void recalculate() const
Definition: aspect.hpp:439
virtual void recalculate() const =0
virtual ~aspect()
Definition: aspect.cpp:47
aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr< lua_ai_context > &l_ctx)
Definition: aspect.hpp:543
std::string operator()(int i) const
Definition: aspect.hpp:406
bool invalidate_on_minor_gamestate_change_
Definition: aspect.hpp:108
virtual aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id)=0
void handle_generic_event(const std::string &)
Definition: aspect.hpp:77
virtual bool redeploy(const config &cfg, const std::string &id)
Definition: aspect.cpp:73
virtual boost::shared_ptr< variant > get_variant_ptr() const =0
std::string operator()(unsigned long long i) const
Definition: aspect.hpp:407
virtual config to_config() const
Definition: aspect.hpp:325
register_aspect_factory(const std::string &name)
Definition: aspect.hpp:496
std::string time_of_day_
Definition: aspect.hpp:97
bool valid_lua_
Definition: aspect.hpp:102
#define LOG_STREAM(level, domain)
Definition: log.hpp:188
bool empty() const
Definition: config.cpp:1105
aspect_type< T >::typesafe_ptr default_
Definition: aspect.hpp:368
std::string operator()(double i) const
Definition: aspect.hpp:408
Lua object(value) wrapper implementation.
virtual bool delete_all_facets()
Definition: aspect.cpp:141
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
virtual bool active() const
Definition: aspect.cpp:136
virtual void add_facet(const config &cfg)
Definition: aspect.hpp:239
config to_config() const
Definition: aspect.hpp:446
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:57
std::string name_
Definition: aspect.hpp:110
virtual std::string get_id() const
Definition: aspect.hpp:88
virtual bool delete_all_facets()
Definition: aspect.hpp:359
static void register_facets_property(std::map< std::string, property_handler_ptr > &property_handlers, const std::string &property, std::vector< boost::shared_ptr< X > > &values, boost::shared_ptr< X > &def, std::function< void(std::vector< boost::shared_ptr< X > > &, const config &)> construction_factory)
virtual void recalculate() const
Definition: aspect.hpp:308
boost::shared_ptr< lua_object< T > > value_lua_
Definition: aspect.hpp:191
boost::shared_ptr< lua_ai_action_handler > handler_
Definition: aspect.hpp:457
static lg::log_domain & log()
Definition: aspect.cpp:64
GLsizei const GLfloat * value
Definition: glew.h:1817
static std::string quote_string(const std::string &s)
Definition: aspect.cpp:160
aspect_map & aspects_
Definition: aspect.hpp:253
typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:118
lua_aspect(readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr< lua_ai_context > &l_ctx)
Definition: aspect.hpp:418
known_aspect(const std::string &name)
Definition: aspect.cpp:146
GLboolean GLboolean GLboolean GLboolean a
Definition: glew.h:7319
const std::string name_
Definition: aspect.hpp:212
std::string operator()(const std::string &s) const
Definition: aspect.hpp:409
config & add_child(const std::string &key)
Definition: config.cpp:743
virtual boost::shared_ptr< T > get_ptr() const
Definition: aspect.hpp:166
virtual ~typesafe_aspect()
Definition: aspect.hpp:126
Templates and utility-routines for strings and numbers.
void invalidate() const
Definition: aspect.hpp:48
std::string id_
Definition: aspect.hpp:111
virtual std::string get_engine() const
Definition: aspect.hpp:91
aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.cpp:31
bool invalidate_on_turn_start_
Definition: aspect.hpp:105
composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:262
typesafe_known_aspect(const std::string &name, boost::shared_ptr< typesafe_aspect< T > > &where, aspect_map &aspects)
Definition: aspect.hpp:222
std::string operator()(bool b) const
Definition: aspect.hpp:405
std::vector< boost::shared_ptr< typesafe_aspect< T > > > typesafe_ptr_vector
Definition: game_info.hpp:77
std::string operator()(const t_string &s) const
Definition: aspect.hpp:410
virtual aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id, boost::shared_ptr< lua_ai_context > &l_ctx)=0
virtual void add_facet(const config &cfg)=0
std::map< std::string, aspect_ptr > aspect_map
Definition: game_info.hpp:114
config to_config() const
Definition: aspect.hpp:393
static void parse_aspect_from_config(readonly_context &context, const config &cfg, const std::string &id, std::back_insert_iterator< std::vector< aspect_ptr > > b)
Definition: engine.cpp:51
size_t i
Definition: function.cpp:1057
virtual void on_create()
Definition: aspect.cpp:69
ai::lua_ai_action_handler * create_lua_ai_action_handler(char const *code, ai::lua_ai_context &context)
boost::shared_ptr< typesafe_aspect< T > > & where_
Definition: aspect.hpp:252
virtual std::string get_name() const
Definition: aspect.hpp:85
#define debug(x)
const config params_
Definition: aspect.hpp:459
GLuint const GLchar * name
Definition: glew.h:1782
bool valid_
Definition: aspect.hpp:100
std::pair< const std::string, factory_ptr > factory_map_pair
Definition: aspect.hpp:514
Composite AI component.
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
virtual const variant & get_variant() const =0
virtual ~aspect_factory()
Definition: aspect.hpp:489
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
static void value_to_cfg(const T &value, config &cfg)
static factory_map & get_list()
Definition: aspect.hpp:470
Standard logging facilities (interface).
config cfg_
Definition: aspect.hpp:104
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
#define c
Definition: glew.h:12743
boost::shared_ptr< lua_aspect_factory > factory_ptr
Definition: aspect.hpp:512
std::string parent_id_
Definition: aspect.hpp:369
std::string engine_
Definition: aspect.hpp:109
register_lua_aspect_factory(const std::string &name)
Definition: aspect.hpp:538
std::pair< const std::string, factory_ptr > factory_map_pair
Definition: aspect.hpp:468
aspect_type< T >::typesafe_ptr_vector facets_
Definition: aspect.hpp:367
boost::shared_ptr< variant > value_variant_
Definition: aspect.hpp:190
virtual boost::shared_ptr< variant > get_variant_ptr() const
Definition: aspect.hpp:142
const std::string & str() const
Definition: tstring.hpp:170
std::map< std::string, factory_ptr > factory_map
Definition: aspect.hpp:467
void create_facet(typename aspect_type< T >::typesafe_ptr_vector &facets, const config &cfg)
Definition: aspect.hpp:294
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
virtual ~known_aspect()
Definition: aspect.cpp:156
GLdouble s
Definition: glew.h:1358
std::string code_
Definition: aspect.hpp:458
boost::shared_ptr< aspect_factory > factory_ptr
Definition: aspect.hpp:466
bool invalidate_on_gamestate_change_
Definition: aspect.hpp:107
GLsizei const GLcharARB ** string
Definition: glew.h:4503
standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:376
GLclampf f
Definition: glew.h:3024
void recalculate() const
Definition: aspect.hpp:386