The Battle for Wesnoth  1.19.4+dev
aspect.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2024
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_ ) {
134  valid_variant_ = true;
135  } else if (!valid_variant_ && valid_lua_) {
136  value_ = value_lua_->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>
200 class composite_aspect;
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";
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";
231  }
232  }
233 
234 protected:
237 };
238 
239 template<typename 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  if (auto cfg_default = this->cfg_.optional_child("default")) {
254  cfg_default["id"] = "default_facet";
255  std::vector< aspect_ptr > default_aspects;
256  engine::parse_aspect_from_config(*this, *cfg_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());
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
#define debug(x)
virtual aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id)=0
std::map< std::string, factory_ptr > factory_map
Definition: aspect.hpp:452
std::shared_ptr< aspect_factory > factory_ptr
Definition: aspect.hpp:451
bool is_duplicate(const std::string &name)
Definition: aspect.cpp:160
virtual ~aspect_factory()
Definition: aspect.hpp:474
static factory_map & get_list()
Definition: aspect.hpp:455
aspect_factory(const std::string &name)
Definition: aspect.hpp:465
std::pair< const std::string, factory_ptr > factory_map_pair
Definition: aspect.hpp:453
config cfg_
Definition: aspect.hpp:90
bool invalidate_on_gamestate_change_
Definition: aspect.hpp:93
virtual void get_lua(lua_State *L) const =0
std::string time_of_day_
Definition: aspect.hpp:83
bool invalidate_on_turn_start_
Definition: aspect.hpp:91
virtual std::string get_engine() const
Definition: aspect.hpp:77
static lg::log_domain & log()
Definition: aspect.cpp:60
virtual void recalculate() const =0
virtual config to_config() const
Definition: aspect.cpp:106
bool valid_variant_
Definition: aspect.hpp:87
virtual std::shared_ptr< wfl::variant > get_variant_ptr() const =0
std::string id_
Definition: aspect.hpp:96
std::string engine_
Definition: aspect.hpp:94
virtual bool delete_all_facets()
Definition: aspect.cpp:129
virtual const wfl::variant & get_variant() const =0
void handle_generic_event(const std::string &)
Definition: aspect.hpp:64
aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.cpp:32
bool invalidate_on_tod_change_
Definition: aspect.hpp:92
std::string turns_
Definition: aspect.hpp:84
virtual void on_create()
Definition: aspect.cpp:65
std::string name_
Definition: aspect.hpp:95
void invalidate() const
Definition: aspect.hpp:41
virtual std::string get_id() const
Definition: aspect.hpp:74
virtual ~aspect()
Definition: aspect.cpp:46
bool valid_lua_
Definition: aspect.hpp:88
virtual std::string get_name() const
Definition: aspect.hpp:71
bool valid_
Definition: aspect.hpp:86
virtual bool active() const
Definition: aspect.cpp:124
virtual bool redeploy(const config &cfg, const std::string &id)
Definition: aspect.cpp:69
property_handler_map & property_handlers()
Definition: component.cpp:116
virtual bool delete_all_facets()
Definition: aspect.hpp:333
std::string parent_id_
Definition: aspect.hpp:353
composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:243
typesafe_aspect_ptr< T > default_
Definition: aspect.hpp:352
virtual bool add_facet(int pos, const config &cfg)
Definition: aspect.hpp:314
aspect & find_active()
Definition: aspect.hpp:340
virtual void recalculate() const
Definition: aspect.hpp:286
virtual config to_config() const
Definition: aspect.hpp:301
typesafe_aspect_vector< T > facets_
Definition: aspect.hpp:351
void create_facet(typesafe_aspect_vector< T > &facets, const config &cfg)
Definition: aspect.hpp:273
static void value_to_cfg(const T &value, config &cfg)
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 ~known_aspect()
Definition: aspect.cpp:144
virtual void add_facet(const config &cfg)=0
const std::string & get_name() const
Definition: aspect.cpp:139
virtual void set(aspect_ptr a)=0
const std::string name_
Definition: aspect.hpp:196
known_aspect(const std::string &name)
Definition: aspect.cpp:134
std::shared_ptr< lua_aspect_factory > factory_ptr
Definition: aspect.hpp:495
lua_aspect_factory(const std::string &name)
Definition: aspect.hpp:509
std::pair< const std::string, factory_ptr > factory_map_pair
Definition: aspect.hpp:497
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 factory_map & get_list()
Definition: aspect.hpp:499
virtual ~lua_aspect_factory()
Definition: aspect.hpp:515
std::map< std::string, factory_ptr > factory_map
Definition: aspect.hpp:496
static std::string quote_string(const std::string &s)
Definition: aspect.cpp:148
std::string operator()(double i) const
Definition: aspect.hpp:393
std::string operator()(bool b) const
Definition: aspect.hpp:390
std::string operator()(int i) const
Definition: aspect.hpp:391
std::string operator()(const t_string &s) const
Definition: aspect.hpp:395
std::string operator()(const std::string &s) const
Definition: aspect.hpp:394
std::string operator()(utils::monostate) const
Definition: aspect.hpp:396
std::string operator()(unsigned long long i) const
Definition: aspect.hpp:392
std::shared_ptr< lua_ai_action_handler > handler_
Definition: aspect.hpp:443
const config params_
Definition: aspect.hpp:445
void recalculate() const
Definition: aspect.hpp:424
config to_config() const
Definition: aspect.hpp:432
std::string code_
Definition: aspect.hpp:444
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 push(lua_State *L)
Definition: lua_object.hpp:79
aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:485
register_aspect_factory(const std::string &name)
Definition: aspect.hpp:480
register_lua_aspect_factory(const std::string &name)
Definition: aspect.hpp:521
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
standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:360
config to_config() const
Definition: aspect.hpp:374
void recalculate() const
Definition: aspect.hpp:368
typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition: aspect.hpp:103
virtual std::shared_ptr< wfl::variant > get_variant_ptr() const
Definition: aspect.hpp:125
std::shared_ptr< wfl::variant > value_variant_
Definition: aspect.hpp:179
void get_lua(lua_State *L) const
Definition: aspect.hpp:146
std::shared_ptr< T > value_
Definition: aspect.hpp:178
std::shared_ptr< lua_object< T > > value_lua_
Definition: aspect.hpp:180
virtual std::shared_ptr< T > get_ptr() const
Definition: aspect.hpp:155
virtual const wfl::variant & get_variant() const
Definition: aspect.hpp:120
virtual const T & get() const
Definition: aspect.hpp:115
virtual ~typesafe_aspect()
Definition: aspect.hpp:111
virtual void recalculate() const =0
typesafe_known_aspect(const std::string &name, typesafe_aspect_ptr< T > &where, aspect_map &aspects)
Definition: aspect.hpp:205
typesafe_aspect_ptr< T > & where_
Definition: aspect.hpp:235
aspect_map & aspects_
Definition: aspect.hpp:236
void set(aspect_ptr a)
Definition: aspect.hpp:210
virtual void add_facet(const config &cfg)
Definition: aspect.hpp:222
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
bool has_attribute(config_key_type key) const
Definition: config.cpp:156
child_itors child_range(config_key_type key)
Definition: config.cpp:271
bool empty() const
Definition: config.cpp:853
optional_config_impl< config > optional_child(config_key_type key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition: config.cpp:383
config & add_child(config_key_type key)
Definition: config.cpp:439
std::size_t i
Definition: function.cpp:1023
std::string id
Text to match against addon_info.tags()
Definition: manager.cpp:197
Standard logging facilities (interface).
#define LOG_STREAM(level, domain)
Definition: log.hpp:281
Lua object(value) wrapper implementation.
A small explanation about what'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:58
std::shared_ptr< aspect > aspect_ptr
Definition: game_info.hpp:95
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::map< std::string, aspect_ptr > aspect_map
Definition: game_info.hpp:104
std::vector< typesafe_aspect_ptr< T > > typesafe_aspect_vector
Definition: game_info.hpp:61
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
auto reversed_view(T &container)
Definition: ranges.hpp:26
std::string bool_string(const bool value)
Converts a bool value to 'true' or 'false'.
Composite AI component.
mock_char c
mock_party p
static map_location::DIRECTION s
#define f
#define b