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