The Battle for Wesnoth  1.15.2+dev
aspect.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2018 by Yurii Chernyi <terraninfo@terraninfo.net>
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 /**
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 namespace ai {
34 
35 class aspect : public readonly_context_proxy, public events::observer, public component {
36 public:
37  aspect(readonly_context &context, const config &cfg, const std::string &id);
38 
39  virtual ~aspect();
40 
41  void invalidate() const
42  {
43  valid_ = false;
44  valid_variant_ = false;
45  valid_lua_ = false;
46  }
47 
48 
49  virtual const wfl::variant& get_variant() const = 0;
50 
51 
52  virtual std::shared_ptr<wfl::variant> get_variant_ptr() const = 0;
53 
54 
55  virtual void get_lua(lua_State* L) const = 0;
56 
57 
58  virtual void recalculate() const = 0;
59 
60 
61  virtual void on_create();
62 
63 
64  virtual bool redeploy(const config &cfg, const std::string & id);
65 
66 
67  virtual config to_config() const;
68 
69 
70  virtual bool delete_all_facets();
71 
72 
73  void handle_generic_event(const std::string &/*event_name*/)
74  {
75  invalidate();
76  }
77 
78 
79  virtual bool active() const;
80 
81  virtual std::string get_name() const
82  { return name_; }
83 
84  virtual std::string get_id() const
85  { return id_; }
86 
87  virtual std::string get_engine() const
88  { return engine_; }
89 
90  static lg::log_domain& log();
91 
92 protected:
93  std::string time_of_day_;
94  std::string turns_;
95 
96  mutable bool valid_;
97  mutable bool valid_variant_;
98  mutable bool valid_lua_;
99 
104  std::string engine_;
105  std::string name_;
106  std::string id_;
107 
108 };
109 
110 template<typename T>
111 class typesafe_aspect : public aspect {
112 public:
113  typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
114  : aspect(context,cfg,id)
115  , value_()
116  , value_variant_()
117  , value_lua_()
118  {
119  }
120 
122  {
123  }
124 
125 
126  virtual const T& get() const
127  {
128  return *get_ptr();
129  }
130 
131 
132  virtual const wfl::variant& get_variant() const
133  {
134  return *get_variant_ptr();
135  }
136 
137  virtual std::shared_ptr<wfl::variant> get_variant_ptr() const
138  {
139  if (!valid_variant_) {
140  if (!valid_) {
141  recalculate();
142  }
143 
144  if (!valid_variant_ && valid_ ) {
145  value_variant_.reset(new wfl::variant(variant_value_translator<T>::value_to_variant(this->get())));
146  valid_variant_ = true;
147  } else if (!valid_variant_ && valid_lua_) {
148  value_ = value_lua_->get();
149  value_variant_.reset(new wfl::variant(variant_value_translator<T>::value_to_variant(this->get())));
150  valid_variant_ = true; // @note: temporary workaround
151  } else {
152  assert(valid_variant_);
153  }
154  }
155  return value_variant_;
156  }
157 
158  void get_lua(lua_State* L) const {
159  if(auto p = get_ptr()) {
160  lua_object<T> obj(get());
161  obj.push(L);
162  } else lua_pushnil(L);
163  }
164 
165  virtual void recalculate() const = 0;
166 
167 
168  virtual std::shared_ptr<T> get_ptr() const
169  {
170  if (!valid_) {
171  if (!(valid_variant_ || valid_lua_)) {
172  recalculate();
173  }
174 
175  if (!valid_ ) {
176  if (valid_variant_) {
178  valid_ = true;
179  } else if (valid_lua_){
180  value_ = value_lua_->get();
181  valid_ = true;
182  } else {
183  assert(valid_);
184  }
185  }
186  }
187  return value_;
188  }
189 
190 protected:
191  mutable std::shared_ptr<T> value_;
192  mutable std::shared_ptr<wfl::variant> value_variant_;
193  mutable std::shared_ptr< lua_object<T>> value_lua_;
194 };
195 
196 
198 public:
199  known_aspect(const std::string &name);
200 
201 
202  virtual ~known_aspect();
203 
204 
205  virtual void set(aspect_ptr a) = 0;
206 
207 
208  virtual void add_facet(const config &cfg) = 0;
209 
210 
211  const std::string& get_name() const;
212 
213 protected:
214  const std::string name_;
215 };
216 
217 
218 template<class T>
220 
221 template<typename T>
223 public:
224  typesafe_known_aspect(const std::string &name, typesafe_aspect_ptr<T>& where, aspect_map &aspects)
225  : known_aspect(name), where_(where), aspects_(aspects)
226  {
227  }
228 
229  void set(aspect_ptr a)
230  {
231  typesafe_aspect_ptr<T> c = std::dynamic_pointer_cast<typesafe_aspect<T>>(a);
232  if (c) {
233  assert (c->get_id()== this->get_name());
234  where_ = c;
235  aspects_.emplace(this->get_name(),c);
236  } else {
237  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;
238  }
239  }
240 
241  virtual void add_facet(const config &cfg)
242  {
243  std::shared_ptr< composite_aspect <T>> c = std::dynamic_pointer_cast< composite_aspect<T>>(where_);
244  if (c) {
245  assert (c->get_id()==this->get_name());
246  c->add_facet(-1, cfg);
247  c->invalidate();
248  } else {
249  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;
250  }
251  }
252 
253 protected:
256 };
257 
258 
259 template<typename T>
260 class composite_aspect : public typesafe_aspect<T> {
261 public:
262 
263  composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
264  : typesafe_aspect<T>(context, cfg, id)
265  , facets_()
266  , default_()
267  , parent_id_(id)
268  {
269  for (const config &cfg_element : this->cfg_.child_range("facet")) {
270  add_facet(-1,cfg_element);
271  }
272 
273  config _default = this->cfg_.child("default");
274  if (_default) {
275  _default["id"] = "default_facet";
276  std::vector< aspect_ptr > default_aspects;
277  engine::parse_aspect_from_config(*this,_default,parent_id_,std::back_inserter(default_aspects));
278  if (!default_aspects.empty()) {
279  typesafe_aspect_ptr<T> b = std::dynamic_pointer_cast< typesafe_aspect<T>>(default_aspects.front());
280  if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
281  c->parent_id_ = parent_id_;
282  }
283  default_ = b;
284  }
285  }
286 
287  std::function<void(typesafe_aspect_vector<T>&, const config&)> factory_facets =
288  std::bind(&ai::composite_aspect<T>::create_facet,*this,_1,_2);
289 
290  register_facets_property(this->property_handlers(),"facet",facets_,default_, factory_facets);
291 
292  }
293 
294 
296  {
297  std::vector<aspect_ptr> facets_base;
298  engine::parse_aspect_from_config(*this,cfg,parent_id_,std::back_inserter(facets_base));
299  for (aspect_ptr a : facets_base) {
300  typesafe_aspect_ptr<T> b = std::dynamic_pointer_cast< typesafe_aspect<T>> (a);
301  if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
302  c->parent_id_ = parent_id_;
303  }
304  facets.push_back(b);
305  }
306  }
307 
308 
309  virtual void recalculate() const
310  {
311  for(const auto& f : boost::adaptors::reverse(facets_)) {
312  if (f->active()) {
313  this->value_ = f->get_ptr();
314  this->valid_ = true;
315  return;
316  }
317  }
318  if (default_) {
319  this->value_ = 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 typesafe_aspect_ptr<T> 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  typesafe_aspect_ptr<T> b = std::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 
367  {
368  for(aspect_ptr a : facets_) {
369  if(a->active()) {
370  return *a;
371  }
372  }
373  return *default_;
374  }
375 
376 protected:
379  std::string parent_id_;
380 
381 };
382 
383 template<typename T>
384 class standard_aspect : public typesafe_aspect<T> {
385 public:
386  standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
387  : typesafe_aspect<T>(context, cfg, id)
388  {
389  this->name_ = "standard_aspect";
390  this->value_ = std::make_shared<T>(config_value_translator<T>::cfg_to_value(this->cfg_));
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  const config empty_cfg;
453  handler_->handle(params_, empty_cfg, true, this->value_lua_);
454  }
455 
457  {
458  config cfg = aspect::to_config();
459  cfg["code"] = code_;
460  if (!params_.empty()) {
461  cfg.add_child("args", params_);
462  }
463  return cfg;
464  }
465 
466 private:
467  std::shared_ptr<lua_ai_action_handler> handler_;
468  std::string code_;
470 };
471 
472 
474  bool is_duplicate(const std::string &name);
475 public:
476  typedef std::shared_ptr< aspect_factory > factory_ptr;
477  typedef std::map<std::string, factory_ptr> factory_map;
478  typedef std::pair<const std::string, factory_ptr> factory_map_pair;
479 
480  static factory_map& get_list() {
481  static factory_map *aspect_factories;
482  if (aspect_factories==nullptr) {
483  aspect_factories = new factory_map;
484  }
485  return *aspect_factories;
486  }
487 
488  virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id) = 0;
489 
490  aspect_factory( const std::string &name )
491  {
492  if (is_duplicate(name)) {
493  return;
494  }
495  factory_ptr ptr_to_this(this);
496  get_list().emplace(name,ptr_to_this);
497  }
498 
499  virtual ~aspect_factory() {}
500 };
501 
502 
503 template<class ASPECT>
505 public:
506  register_aspect_factory( const std::string &name )
507  : aspect_factory( name )
508  {
509  }
510 
511  aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id)
512  {
513  aspect_ptr a = std::make_shared<ASPECT>(context, cfg, id);
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 
535  lua_aspect_factory( const std::string &name )
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:
547  register_lua_aspect_factory( const std::string &name )
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  aspect_ptr a = std::make_shared<ASPECT>(context, cfg, id, l_ctx);
555  a->on_create();
556  return a;
557  }
558 };
559 
560 
561 } //end of namespace ai
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
virtual void recalculate() const
Definition: aspect.hpp:309
static std::unique_ptr< class sdl_event_handler > handler_
Definition: handler.cpp:62
std::string operator()(bool b) const
Definition: aspect.hpp:414
lua_aspect_factory(const std::string &name)
Definition: aspect.hpp:535
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
bool invalidate_on_tod_change_
Definition: aspect.hpp:102
aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:511
std::string operator()(const std::string &s) const
Definition: aspect.hpp:418
std::string operator()(const t_string &s) const
Definition: aspect.hpp:419
virtual bool add_facet(int pos, const config &cfg)
Definition: aspect.hpp:339
bool valid_variant_
Definition: aspect.hpp:97
virtual ~lua_aspect_factory()
Definition: aspect.hpp:541
std::map< std::string, factory_ptr > factory_map
Definition: aspect.hpp:522
virtual std::shared_ptr< wfl::variant > get_variant_ptr() const
Definition: aspect.hpp:137
std::string turns_
Definition: aspect.hpp:94
static factory_map & get_list()
Definition: aspect.hpp:525
aspect_factory(const std::string &name)
Definition: aspect.hpp:490
bool has_attribute(config_key_type key) const
Definition: config.cpp:213
#define a
property_handler_map & property_handlers()
Definition: component.cpp:132
virtual void recalculate() const =0
virtual ~aspect()
Definition: aspect.cpp:46
typesafe_known_aspect(const std::string &name, typesafe_aspect_ptr< T > &where, aspect_map &aspects)
Definition: aspect.hpp:224
child_itors child_range(config_key_type key)
Definition: config.cpp:362
void handle_generic_event(const std::string &)
Definition: aspect.hpp:73
virtual bool redeploy(const config &cfg, const std::string &id)
Definition: aspect.cpp:69
register_aspect_factory(const std::string &name)
Definition: aspect.hpp:506
std::string time_of_day_
Definition: aspect.hpp:93
bool valid_lua_
Definition: aspect.hpp:98
virtual void add_facet(const std::string &id, const config &cfg) const override
Definition: contexts.hpp:650
void recalculate() const
Definition: aspect.hpp:448
std::shared_ptr< T > value_
Definition: aspect.hpp:191
#define LOG_STREAM(level, domain)
Definition: log.hpp:189
void invalidate() const
Definition: aspect.hpp:41
lua_aspect(readonly_context &context, const config &cfg, const std::string &id, std::shared_ptr< lua_ai_context > &l_ctx)
Definition: aspect.hpp:427
void get_lua(lua_State *L) const
Definition: aspect.hpp:158
Lua object(value) wrapper implementation.
config to_config() const
Definition: aspect.hpp:402
virtual bool delete_all_facets()
Definition: aspect.cpp:129
virtual std::shared_ptr< T > get_ptr() const
Definition: aspect.hpp:168
std::shared_ptr< aspect > aspect_ptr
Definition: game_info.hpp:94
virtual std::string get_name() const
Definition: aspect.hpp:81
#define b
virtual void add_facet(const config &cfg)
Definition: aspect.hpp:241
virtual void get_lua(lua_State *L) const =0
std::shared_ptr< wfl::variant > value_variant_
Definition: aspect.hpp:192
A small explanation about what&#39;s going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:58
std::shared_ptr< typesafe_aspect< T > > typesafe_aspect_ptr
Definition: game_info.hpp:57
std::string name_
Definition: aspect.hpp:105
std::string operator()(double i) const
Definition: aspect.hpp:417
virtual config to_config() const
Definition: aspect.hpp:325
static lg::log_domain & log()
Definition: aspect.cpp:60
virtual std::string get_id() const
Definition: aspect.hpp:84
typesafe_aspect_ptr< T > & where_
Definition: aspect.hpp:254
virtual const wfl::variant & get_variant() const =0
aspect_map & aspects_
Definition: aspect.hpp:255
typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:113
void push(lua_State *L)
Definition: lua_object.hpp:79
void recalculate() const
Definition: aspect.hpp:395
const std::string name_
Definition: aspect.hpp:214
virtual std::shared_ptr< wfl::variant > get_variant_ptr() const =0
virtual config to_config() const
Definition: aspect.cpp:106
virtual ~typesafe_aspect()
Definition: aspect.hpp:121
LUA_API void lua_pushnil(lua_State *L)
Definition: lapi.cpp:450
std::string parent_id_
Definition: aspect.hpp:379
std::string id_
Definition: aspect.hpp:106
std::string operator()(int i) const
Definition: aspect.hpp:415
void create_facet(typesafe_aspect_vector< T > &facets, const config &cfg)
Definition: aspect.hpp:295
aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.cpp:31
bool invalidate_on_turn_start_
Definition: aspect.hpp:101
aspect & find_active()
Definition: aspect.hpp:366
typesafe_aspect_ptr< T > default_
Definition: aspect.hpp:378
typesafe_aspect_vector< T > facets_
Definition: aspect.hpp:377
static T cfg_to_value(const config &cfg)
std::size_t i
Definition: function.cpp:933
std::shared_ptr< lua_object< T > > value_lua_
Definition: aspect.hpp:193
mock_party p
static map_location::DIRECTION s
virtual bool delete_all_facets()
Definition: aspect.hpp:359
std::string bool_string(const bool value)
Converts a bool value to &#39;true&#39; or &#39;false&#39;.
virtual void on_create()
Definition: aspect.cpp:65
std::shared_ptr< lua_aspect_factory > factory_ptr
Definition: aspect.hpp:521
#define debug(x)
virtual bool active() const
Definition: aspect.cpp:124
config & add_child(config_key_type key)
Definition: config.cpp:476
const config params_
Definition: aspect.hpp:469
bool valid_
Definition: aspect.hpp:96
std::shared_ptr< lua_ai_action_handler > handler_
Definition: aspect.hpp:467
std::pair< const std::string, factory_ptr > factory_map_pair
Definition: aspect.hpp:523
Composite AI component.
std::map< std::string, aspect_ptr > aspect_map
Definition: game_info.hpp:103
#define f
std::shared_ptr< aspect_factory > factory_ptr
Definition: aspect.hpp:476
virtual ~aspect_factory()
Definition: aspect.hpp:499
static void value_to_cfg(const T &value, config &cfg)
std::string operator()(boost::blank) const
Definition: aspect.hpp:420
static factory_map & get_list()
Definition: aspect.hpp:480
Standard logging facilities (interface).
virtual std::string get_engine() const
Definition: aspect.hpp:87
config cfg_
Definition: aspect.hpp:100
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
std::string engine_
Definition: aspect.hpp:104
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:478
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
config to_config() const
Definition: aspect.hpp:456
std::map< std::string, factory_ptr > factory_map
Definition: aspect.hpp:477
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:68
mock_char c
const std::string & str() const
Definition: tstring.hpp:186
std::string code_
Definition: aspect.hpp:468
composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:263
bool invalidate_on_gamestate_change_
Definition: aspect.hpp:103
standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:386
std::string operator()(unsigned long long i) const
Definition: aspect.hpp:416
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
virtual const wfl::variant & get_variant() const
Definition: aspect.hpp:132
std::vector< typesafe_aspect_ptr< T > > typesafe_aspect_vector
Definition: game_info.hpp:60