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