The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
aspect.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2009 - 2025
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
33namespace ai {
34
36public:
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_lua_ = false;
45 }
46
47 virtual void get_lua(lua_State* L) const = 0;
48
49 virtual void recalculate() const = 0;
50
51 virtual void on_create();
52
53 virtual bool redeploy(const config &cfg, const std::string & id);
54
55 virtual config to_config() const;
56
57 virtual bool delete_all_facets();
58
59 void handle_generic_event(const std::string &/*event_name*/)
60 {
61 invalidate();
62 }
63
64 virtual bool active() const;
65
66 virtual std::string get_name() const
67 { return name_; }
68
69 virtual std::string get_id() const
70 { return id_; }
71
72 virtual std::string get_engine() const
73 { return engine_; }
74
75 static lg::log_domain& log();
76
77protected:
78 std::string time_of_day_;
79 std::string turns_;
80
81 mutable bool valid_;
82 mutable bool valid_lua_;
83
88 std::string engine_;
89 std::string name_;
90 std::string id_;
91
92};
93
94template<typename T>
95class typesafe_aspect : public aspect {
96public:
97 typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
98 : aspect(context,cfg,id)
99 , value_()
100 , value_lua_()
101 {
102 }
103
105 {
106 }
107
108 virtual const T& get() const
109 {
110 return *get_ptr();
111 }
112
113 void get_lua(lua_State* L) const {
114 if(auto p = get_ptr()) {
115 lua_object<T> obj(get());
116 obj.push(L);
117 } else lua_pushnil(L);
118 }
119
120 virtual void recalculate() const = 0;
121
122 virtual std::shared_ptr<T> get_ptr() const
123 {
124 if (!valid_) {
125 if (!valid_lua_) {
126 recalculate();
127 }
128
129 if (!valid_ ) {
130 if (valid_lua_){
131 value_ = value_lua_->get();
132 valid_ = true;
133 } else {
134 assert(valid_);
135 }
136 }
137 }
138 return value_;
139 }
140
141protected:
142 mutable std::shared_ptr<T> value_;
143 mutable std::shared_ptr< lua_object<T>> value_lua_;
144};
145
147public:
148 known_aspect(const std::string &name);
149
150 virtual ~known_aspect();
151
152 virtual void set(aspect_ptr a) = 0;
153
154 virtual void add_facet(const config &cfg) = 0;
155
156 const std::string& get_name() const;
157
158protected:
159 const std::string name_;
160};
161
162template<class T>
163class composite_aspect;
164
165template<typename T>
167public:
168 typesafe_known_aspect(const std::string &name, typesafe_aspect_ptr<T>& where, aspect_map &aspects)
169 : known_aspect(name), where_(where), aspects_(aspects)
170 {
171 }
172
174 {
175 typesafe_aspect_ptr<T> c = std::dynamic_pointer_cast<typesafe_aspect<T>>(a);
176 if (c) {
177 assert (c->get_id()== this->get_name());
178 where_ = c;
179 aspects_.emplace(this->get_name(),c);
180 } else {
181 LOG_STREAM(debug, aspect::log()) << "typesafe_known_aspect [" << this->get_name() << "] : while setting aspect, got null. this might be caused by invalid [aspect] WML";
182 }
183 }
184
185 virtual void add_facet(const config &cfg)
186 {
187 std::shared_ptr< composite_aspect <T>> c = std::dynamic_pointer_cast< composite_aspect<T>>(where_);
188 if (c) {
189 assert (c->get_id()==this->get_name());
190 c->add_facet(-1, cfg);
191 c->invalidate();
192 } else {
193 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";
194 }
195 }
196
197protected:
200};
201
202template<typename T>
204public:
205
206 composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
207 : typesafe_aspect<T>(context, cfg, id)
208 , facets_()
209 , default_()
210 , parent_id_(id)
211 {
212 for (const config &cfg_element : this->cfg_.child_range("facet")) {
213 add_facet(-1,cfg_element);
214 }
215
216 if (auto cfg_default = this->cfg_.optional_child("default")) {
217 cfg_default["id"] = "default_facet";
218 std::vector< aspect_ptr > default_aspects;
219 engine::parse_aspect_from_config(*this, *cfg_default, parent_id_, std::back_inserter(default_aspects));
220 if (!default_aspects.empty()) {
221 typesafe_aspect_ptr<T> b = std::dynamic_pointer_cast< typesafe_aspect<T>>(default_aspects.front());
222 if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
223 c->parent_id_ = parent_id_;
224 }
225 default_ = b;
226 }
227 }
228
229 std::function<void(typesafe_aspect_vector<T>&, const config&)> factory_facets =
230 std::bind(&ai::composite_aspect<T>::create_facet, *this, std::placeholders::_1, std::placeholders::_2);
231
232 register_facets_property(this->property_handlers(),"facet",facets_,default_, factory_facets);
233
234 }
235
237 {
238 std::vector<aspect_ptr> facets_base;
239 engine::parse_aspect_from_config(*this,cfg,parent_id_,std::back_inserter(facets_base));
240 for (aspect_ptr a : facets_base) {
241 typesafe_aspect_ptr<T> b = std::dynamic_pointer_cast< typesafe_aspect<T>> (a);
242 if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
243 c->parent_id_ = parent_id_;
244 }
245 facets.push_back(b);
246 }
247 }
248
249 virtual void recalculate() const
250 {
251 for(const auto& f : facets_ | utils::views::reverse) {
252 if (f->active()) {
253 this->value_ = f->get_ptr();
254 this->valid_ = true;
255 return;
256 }
257 }
258 if (default_) {
259 this->value_ = default_->get_ptr();
260 this->valid_ = true;
261 }
262 }
263
264 virtual config to_config() const
265 {
267 for (const typesafe_aspect_ptr<T>& f : facets_) {
268 cfg.add_child("facet",f->to_config());
269 }
270 if (default_) {
271 cfg.add_child("default",default_->to_config());
272 }
273 return cfg;
274 }
275
277 virtual bool add_facet(int pos, const config &cfg)
278 {
279 if (pos<0) {
280 pos = facets_.size();
281 }
282 std::vector< aspect_ptr > facets;
283 engine::parse_aspect_from_config(*this,cfg,parent_id_,std::back_inserter(facets));
284 int j=0;
285 for (aspect_ptr a : facets) {
286 typesafe_aspect_ptr<T> b = std::dynamic_pointer_cast< typesafe_aspect<T>> (a);
287 if (composite_aspect<T>* c = dynamic_cast<composite_aspect<T>*>(b.get())) {
288 c->parent_id_ = parent_id_;
289 }
290 facets_.insert(facets_.begin()+pos+j,b);
291 j++;
292 }
293 return (j>0);
294 }
295
296 virtual bool delete_all_facets()
297 {
298 bool b = !facets_.empty();
299 facets_.clear();
300 return b;
301 }
302
304 {
305 for(aspect_ptr a : facets_) {
306 if(a->active()) {
307 return *a;
308 }
309 }
310 return *default_;
311 }
312
313protected:
316 std::string parent_id_;
317
318};
319
320template<typename T>
322public:
323 standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
324 : typesafe_aspect<T>(context, cfg, id)
325 {
326 this->name_ = "standard_aspect";
327 this->value_ = std::make_shared<T>(config_value_translator<T>::cfg_to_value(this->cfg_));
328 LOG_STREAM(debug, aspect::log()) << "standard aspect has value: "<< std::endl << config_value_translator<T>::value_to_cfg(this->get());
329 }
330
331 void recalculate() const
332 {
333 //nothing to recalculate
334 this->valid_ = true;
335 }
336
338 {
341 return cfg;
342 }
343
344};
345
347#ifdef USING_BOOST_VARIANT
348 : public boost::static_visitor<std::string>
349#endif
350{
351 static std::string quote_string(const std::string& s);
352public:
353 std::string operator()(bool b) const {return utils::bool_string(b);}
354 std::string operator()(int i) const {return std::to_string(i);}
355 std::string operator()(unsigned long long i) const {return std::to_string(i);}
356 std::string operator()(double i) const {return std::to_string(i);}
357 std::string operator()(const std::string& s) const {return quote_string(s);}
358 std::string operator()(const t_string& s) const {return quote_string(s.str());}
359 std::string operator()(utils::monostate) const {return "nil";}
360};
361
362template<typename T>
364{
365public:
366 lua_aspect(readonly_context &context, const config &cfg, const std::string &id, std::shared_ptr<lua_ai_context>& l_ctx)
367 : typesafe_aspect<T>(context, cfg, id)
368 , handler_(), code_(), params_(cfg.child_or_empty("args"))
369 {
370 this->name_ = "lua_aspect";
371 if (cfg.has_attribute("code"))
372 {
373 code_ = cfg["code"].str();
374 }
375 else if (cfg.has_attribute("value"))
376 {
377 code_ = "return " + cfg["value"].apply_visitor(lua_aspect_visitor());
378 }
379 else
380 {
381 // error
382 return;
383 }
384 handler_.reset(resources::lua_kernel->create_lua_ai_action_handler(code_.c_str(), *l_ctx));
385 }
386
387 void recalculate() const
388 {
389 this->valid_lua_ = true;
390 this->value_lua_.reset(new lua_object<T>);
391 const config empty_cfg;
392 handler_->handle(params_, empty_cfg, true, this->value_lua_);
393 }
394
396 {
398 cfg["code"] = code_;
399 if (!params_.empty()) {
400 cfg.add_child("args", params_);
401 }
402 return cfg;
403 }
404
405private:
406 std::shared_ptr<lua_ai_action_handler> handler_;
407 std::string code_;
409};
410
412 bool is_duplicate(const std::string &name);
413public:
414 typedef std::shared_ptr< aspect_factory > factory_ptr;
415 typedef std::map<std::string, factory_ptr> factory_map;
416 typedef std::pair<const std::string, factory_ptr> factory_map_pair;
417
419 static factory_map *aspect_factories;
420 if (aspect_factories==nullptr) {
421 aspect_factories = new factory_map;
422 }
423 return *aspect_factories;
424 }
425
426 virtual aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id) = 0;
427
428 aspect_factory( const std::string &name )
429 {
430 if (is_duplicate(name)) {
431 return;
432 }
433 factory_ptr ptr_to_this(this);
434 get_list().emplace(name,ptr_to_this);
435 }
436
437 virtual ~aspect_factory() {}
438};
439
440template<class ASPECT>
442public:
443 register_aspect_factory( const std::string &name )
444 : aspect_factory( name )
445 {
446 }
447
448 aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id)
449 {
450 aspect_ptr a = std::make_shared<ASPECT>(context, cfg, id);
451 a->on_create();
452 return a;
453 }
454};
455
457public:
458 typedef std::shared_ptr< lua_aspect_factory > factory_ptr;
459 typedef std::map<std::string, factory_ptr> factory_map;
460 typedef std::pair<const std::string, factory_ptr> factory_map_pair;
461
463 static factory_map *aspect_factories;
464 if (aspect_factories==nullptr) {
465 aspect_factories = new factory_map;
466 }
467 return *aspect_factories;
468 }
469
470 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;
471
472 lua_aspect_factory( const std::string &name )
473 {
474 factory_ptr ptr_to_this(this);
475 get_list().emplace(name,ptr_to_this);
476 }
477
479};
480
481template<class ASPECT>
483public:
484 register_lua_aspect_factory( const std::string &name )
485 : lua_aspect_factory( name )
486 {
487 }
488
489 aspect_ptr get_new_instance( readonly_context &context, const config &cfg, const std::string &id, std::shared_ptr<lua_ai_context>& l_ctx)
490 {
491 aspect_ptr a = std::make_shared<ASPECT>(context, cfg, id, l_ctx);
492 a->on_create();
493 return a;
494 }
495};
496
497} //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:415
static factory_map & get_list()
Definition aspect.hpp:418
std::shared_ptr< aspect_factory > factory_ptr
Definition aspect.hpp:414
bool is_duplicate(const std::string &name)
Definition aspect.cpp:159
virtual ~aspect_factory()
Definition aspect.hpp:437
aspect_factory(const std::string &name)
Definition aspect.hpp:428
std::pair< const std::string, factory_ptr > factory_map_pair
Definition aspect.hpp:416
config cfg_
Definition aspect.hpp:84
bool invalidate_on_gamestate_change_
Definition aspect.hpp:87
virtual void get_lua(lua_State *L) const =0
std::string time_of_day_
Definition aspect.hpp:78
bool invalidate_on_turn_start_
Definition aspect.hpp:85
virtual std::string get_engine() const
Definition aspect.hpp:72
static lg::log_domain & log()
Definition aspect.cpp:60
virtual void recalculate() const =0
virtual config to_config() const
Definition aspect.cpp:105
std::string id_
Definition aspect.hpp:90
std::string engine_
Definition aspect.hpp:88
virtual bool delete_all_facets()
Definition aspect.cpp:128
void handle_generic_event(const std::string &)
Definition aspect.hpp:59
bool invalidate_on_tod_change_
Definition aspect.hpp:86
std::string turns_
Definition aspect.hpp:79
virtual void on_create()
Definition aspect.cpp:65
std::string name_
Definition aspect.hpp:89
void invalidate() const
Definition aspect.hpp:41
virtual std::string get_id() const
Definition aspect.hpp:69
virtual ~aspect()
Definition aspect.cpp:46
bool valid_lua_
Definition aspect.hpp:82
virtual std::string get_name() const
Definition aspect.hpp:66
bool valid_
Definition aspect.hpp:81
virtual bool active() const
Definition aspect.cpp:123
virtual bool redeploy(const config &cfg, const std::string &id)
Definition aspect.cpp:69
property_handler_map & property_handlers()
virtual bool delete_all_facets()
Definition aspect.hpp:296
std::string parent_id_
Definition aspect.hpp:316
composite_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition aspect.hpp:206
typesafe_aspect_ptr< T > default_
Definition aspect.hpp:315
virtual bool add_facet(int pos, const config &cfg)
Definition aspect.hpp:277
virtual void recalculate() const
Definition aspect.hpp:249
virtual config to_config() const
Definition aspect.hpp:264
typesafe_aspect_vector< T > facets_
Definition aspect.hpp:314
aspect & find_active()
Definition aspect.hpp:303
void create_facet(typesafe_aspect_vector< T > &facets, const config &cfg)
Definition aspect.hpp:236
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:143
virtual void add_facet(const config &cfg)=0
const std::string & get_name() const
Definition aspect.cpp:138
virtual void set(aspect_ptr a)=0
const std::string name_
Definition aspect.hpp:159
std::shared_ptr< lua_aspect_factory > factory_ptr
Definition aspect.hpp:458
lua_aspect_factory(const std::string &name)
Definition aspect.hpp:472
std::pair< const std::string, factory_ptr > factory_map_pair
Definition aspect.hpp:460
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
virtual ~lua_aspect_factory()
Definition aspect.hpp:478
std::map< std::string, factory_ptr > factory_map
Definition aspect.hpp:459
static factory_map & get_list()
Definition aspect.hpp:462
static std::string quote_string(const std::string &s)
Definition aspect.cpp:147
std::string operator()(double i) const
Definition aspect.hpp:356
std::string operator()(bool b) const
Definition aspect.hpp:353
std::string operator()(int i) const
Definition aspect.hpp:354
std::string operator()(const t_string &s) const
Definition aspect.hpp:358
std::string operator()(const std::string &s) const
Definition aspect.hpp:357
std::string operator()(utils::monostate) const
Definition aspect.hpp:359
std::string operator()(unsigned long long i) const
Definition aspect.hpp:355
std::shared_ptr< lua_ai_action_handler > handler_
Definition aspect.hpp:406
const config params_
Definition aspect.hpp:408
void recalculate() const
Definition aspect.hpp:387
config to_config() const
Definition aspect.hpp:395
std::string code_
Definition aspect.hpp:407
lua_aspect(readonly_context &context, const config &cfg, const std::string &id, std::shared_ptr< lua_ai_context > &l_ctx)
Definition aspect.hpp:366
void push(lua_State *L)
aspect_ptr get_new_instance(readonly_context &context, const config &cfg, const std::string &id)
Definition aspect.hpp:448
register_aspect_factory(const std::string &name)
Definition aspect.hpp:443
register_lua_aspect_factory(const std::string &name)
Definition aspect.hpp:484
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:489
standard_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition aspect.hpp:323
config to_config() const
Definition aspect.hpp:337
void recalculate() const
Definition aspect.hpp:331
typesafe_aspect(readonly_context &context, const config &cfg, const std::string &id)
Definition aspect.hpp:97
virtual std::shared_ptr< T > get_ptr() const
Definition aspect.hpp:122
virtual const T & get() const
Definition aspect.hpp:108
void get_lua(lua_State *L) const
Definition aspect.hpp:113
std::shared_ptr< T > value_
Definition aspect.hpp:142
std::shared_ptr< lua_object< T > > value_lua_
Definition aspect.hpp:143
virtual ~typesafe_aspect()
Definition aspect.hpp:104
virtual void recalculate() const =0
typesafe_known_aspect(const std::string &name, typesafe_aspect_ptr< T > &where, aspect_map &aspects)
Definition aspect.hpp:168
typesafe_aspect_ptr< T > & where_
Definition aspect.hpp:198
void set(aspect_ptr a)
Definition aspect.hpp:173
virtual void add_facet(const config &cfg)
Definition aspect.hpp:185
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
config & add_child(std::string_view key)
Definition config.cpp:436
optional_config_impl< config > optional_child(std::string_view key, int n=0)
Equivalent to mandatory_child, but returns an empty optional if the nth child was not found.
Definition config.cpp:380
child_itors child_range(std::string_view key)
Definition config.cpp:268
bool has_attribute(std::string_view key) const
Definition config.cpp:157
bool empty() const
Definition config.cpp:823
const config * cfg
std::string id
Text to match against addon_info.tags()
Definition manager.cpp:199
Standard logging facilities (interface).
#define LOG_STREAM(level, domain)
Definition log.hpp:278
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:97
std::map< std::string, aspect_ptr > aspect_map
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, Factory &&construction_factory)
std::vector< typesafe_aspect_ptr< T > > typesafe_aspect_vector
Definition game_info.hpp:61
game_lua_kernel * lua_kernel
Definition resources.cpp:25
constexpr auto reverse
Definition ranges.hpp:44
std::string bool_string(const bool value)
Converts a bool value to 'true' or 'false'.
Composite AI component.
mock_party p
static map_location::direction s
#define i
#define f
#define c
#define b