The Battle for Wesnoth  1.17.0-dev
aspect.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2021
3  by Yurii Chernyi <terraninfo@terraninfo.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 /**
17  * @file
18  */
19 
20 #pragma once
21 
24 #include "ai/lua/lua_object.hpp"
25 #include "ai/lua/core.hpp"
27 #include "utils/ranges.hpp"
28 
29 #include "log.hpp"
30 
31 #include <functional>
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 : utils::reversed_view(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:52
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:402
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:211
#define a
property_handler_map & property_handlers()
Definition: component.cpp:125
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:205
child_itors child_range(config_key_type key)
Definition: config.cpp:344
auto reversed_view(T &container)
Definition: ranges.hpp:28
void handle_generic_event(const std::string &)
Definition: aspect.hpp:64
virtual bool redeploy(const config &cfg, const std::string &id)
Definition: aspect.cpp:69
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:571
void recalculate() const
Definition: aspect.hpp:425
std::shared_ptr< T > value_
Definition: aspect.hpp:178
#define LOG_STREAM(level, domain)
Definition: log.hpp:221
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:129
virtual std::shared_ptr< T > get_ptr() const
Definition: aspect.hpp:155
std::shared_ptr< aspect > aspect_ptr
Definition: game_info.hpp:95
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:61
std::shared_ptr< typesafe_aspect< T > > typesafe_aspect_ptr
Definition: game_info.hpp:58
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:60
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:76
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:106
virtual ~typesafe_aspect()
Definition: aspect.hpp:111
LUA_API void lua_pushnil(lua_State *L)
Definition: lapi.cpp:473
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:32
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
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:215
static T cfg_to_value(const config &cfg)
std::size_t i
Definition: function.cpp:967
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 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:496
#define debug(x)
virtual bool active() const
Definition: aspect.cpp:124
config & add_child(config_key_type key)
Definition: config.cpp:514
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:104
#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:26
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
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:61
mock_char c
const std::string & str() const
Definition: tstring.hpp:191
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:61