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