The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
engine_lua.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2009 - 2016 by Yurii Chernyi <[email protected]>
3  Part of the Battle for Wesnoth Project http://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  * LUA AI Support engine - creating specific ai components from config
17  * @file
18  */
19 
20 #include "ai/lua/engine_lua.hpp"
21 #include "ai/composite/ai.hpp"
22 #include "ai/composite/goal.hpp"
23 #include "ai/composite/rca.hpp"
24 #include "ai/composite/stage.hpp"
25 #include "ai/composite/aspect.hpp"
26 
28 
29 #include "log.hpp"
30 #include "resources.hpp"
31 #include "ai/lua/core.hpp"
32 #include "ai/lua/lua_object.hpp"
34 #include "util.hpp"
35 #include "units/unit.hpp"
36 #include "units/map.hpp"
37 
38 
39 namespace ai {
40 
41 static lg::log_domain log_ai_engine_lua("ai/engine/lua");
42 #define DBG_AI_LUA LOG_STREAM(debug, log_ai_engine_lua)
43 #define LOG_AI_LUA LOG_STREAM(info, log_ai_engine_lua)
44 #define WRN_AI_LUA LOG_STREAM(warn, log_ai_engine_lua)
45 #define ERR_AI_LUA LOG_STREAM(err, log_ai_engine_lua)
46 
47 #ifdef _MSC_VER
48 #pragma warning(push)
49 //silence "inherits via dominance" warnings
50 #pragma warning(disable:4250)
51 #endif
52 
54 
56 
57 public:
60  {
61  // do nothing
62  }
63 
65 
66  virtual double evaluate()
67  {
68  lua_int_obj l_obj = lua_int_obj(new lua_object<int>());
69 
72  } else {
73  return BAD_SCORE;
74  }
75 
76  boost::shared_ptr<int> result = l_obj->get();
77 
78  return result ? *result : 0.0;
79  }
80 
81 
82  virtual void execute() {
84  lua_object_ptr nil;
86  }
87  }
88 
89  virtual config to_config() const {
92  return cfg;
93  }
94 
95 protected:
99 };
100 
102 
103 public:
104  lua_candidate_action_wrapper( rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
105  : lua_candidate_action_wrapper_base(context,cfg),evaluation_(cfg["evaluation"]),execution_(cfg["execution"])
106  {
109  }
110 
112 
113  virtual config to_config() const
114  {
116  cfg["evaluation"] = evaluation_;
117  cfg["execution"] = execution_;
118  return cfg;
119  }
120 
121 private:
124 };
125 
127 public:
129  : lua_candidate_action_wrapper_base(context,cfg), location_(cfg["location"]), use_parms_(false)
130  {
131  if (cfg.has_attribute("exec_parms") || cfg.has_attribute("eval_parms")) {
132  use_parms_ = true;
133  exec_parms_ = cfg["exec_parms"].str();
134  eval_parms_ = cfg["eval_parms"].str();
135  }
136  std::string eval_code;
137  std::string exec_code;
138  generate_code(eval_code, exec_code);
139 
142  }
143 
145 
146  virtual config to_config() const
147  {
149  cfg["location"] = location_;
150  if (use_parms_) {
151  cfg["eval_parms"] = eval_parms_;
152  cfg["exec_parms"] = exec_parms_;
153  }
154  return cfg;
155  }
156 
157 private:
162 
163  void generate_code(std::string& eval, std::string& exec) {
164  std::string preamble = "local self, params, data = ...\n";
165  std::string load = "wesnoth.require(\"" + location_ + "\")";
166  if (use_parms_) {
167  eval = preamble + "return " + load + ":evaluation(ai, {" + eval_parms_ + "}, {data = data})";
168  exec = preamble + load + ":execution(ai, {" + exec_parms_ + "}, {data = data})";
169  } else {
170  eval = preamble + "return " + load + ".evaluation(self, params, data)";
171  exec = preamble + load + ".execution(self, params, data)";
172  }
173  }
174 };
175 
177 public:
179  : lua_candidate_action_wrapper(context, cfg, lua_ai_ctx)
180  , bound_unit_()
181  {
182  map_location loc(cfg["unit_x"] - 1, cfg["unit_y"] - 1); // lua and c++ coords differ by one
184  }
185 
186  virtual double evaluate()
187  {
188  if (resources::units->find(bound_unit_->underlying_id()).valid())
189  {
191  }
192  else
193  {
194  this->set_to_be_removed();
195  return 0; // Is 0 what we return when we don't want the action to be executed?
196  }
197  }
198 
199  virtual void execute()
200  {
202  this->disable(); // we do not want to execute the same sticky CA twice -> will be moved out to Lua later
203  }
204 private:
206 
207 };
208 
209 class lua_stage_wrapper : public stage {
210 public:
211  lua_stage_wrapper( ai_context &context, const config &cfg, lua_ai_context &lua_ai_ctx )
212  : stage(context,cfg),action_handler_(),code_(cfg["code"]),serialized_evaluation_state_(cfg.child_or_empty("args"))
213  {
215  }
216 
218  {
219  }
220 
221  virtual bool do_play_stage()
222  {
223  gamestate_observer gs_o;
224 
225  if (action_handler_) {
226  lua_object_ptr nil;
227  action_handler_->handle(serialized_evaluation_state_, false, nil);
228  }
229 
230  return gs_o.is_gamestate_changed();
231  }
232 
233  virtual config to_config() const
234  {
235  config cfg = stage::to_config();
236  cfg["code"] = code_;
238  return cfg;
239  }
240 private:
244 };
245 
246 
247 /**
248  * Note that initially we get access only to readonly context (engine is created rather early, when there's no way to move/attack.
249  * We inject full ai_context later.
250  */
252  : engine(context,cfg)
253  , code_(get_engine_code(cfg))
254  , lua_ai_context_(resources::lua_kernel->create_lua_ai_context(
255  get_engine_code(cfg).c_str(), this))
256 {
257  name_ = "lua";
258  config data(cfg.child_or_empty("data"));
259  config args(cfg.child_or_empty("args"));
260 
261  if (lua_ai_context_) { // The context might be nullptr if the config contains errors
262  lua_ai_context_->set_persistent_data(data);
263  lua_ai_context_->set_arguments(args);
264  lua_ai_context_->update_state();
265  }
266 }
267 
269 {
270  if (cfg.has_attribute("code")) {
271  return cfg["code"].str();
272  }
273  // If there is no engine defined we create a dummy engine
274  std::string code = "wesnoth.require(\"ai/lua/dummy_engine_lua.lua\")";
275  return code;
276 }
277 
279 {
280 }
281 
282 bool engine_lua::is_ok() const
283 {
284  return lua_ai_context_ ? true : false;
285 }
286 
288 {
289  if (game_config::debug)
290  {
291  lua_ai_context_->push_ai_table();
292  }
293 }
294 
295 void engine_lua::do_parse_candidate_action_from_config( rca_context &context, const config &cfg, std::back_insert_iterator<std::vector< candidate_action_ptr > > b ){
296  if (!cfg) {
297  return;
298  }
299 
300  if (!lua_ai_context_) {
301  return;
302  }
303 
305  if (!cfg["sticky"].to_bool())
306  {
307  if (cfg.has_attribute("location")) {
309  } else {
311  }
312  }
313  else
314  {
316  }
317 
318  if (ca_ptr) {
319  *b = ca_ptr;
320  }
321 }
322 
323 void engine_lua::do_parse_stage_from_config( ai_context &context, const config &cfg, std::back_insert_iterator<std::vector< stage_ptr > > b )
324 {
325  if (!cfg) {
326  return;
327  }
328 
329  if (!lua_ai_context_) {
330  return;
331  }
332 
333  stage_ptr st_ptr = stage_ptr(new lua_stage_wrapper(context,cfg,*lua_ai_context_));
334  if (st_ptr) {
335  st_ptr->on_create();
336  *b = st_ptr;
337  }
338 }
339 
340 void engine_lua::do_parse_aspect_from_config( const config &cfg, const std::string &id, std::back_insert_iterator<std::vector< aspect_ptr > > b )
341 {
342  const std::string aspect_factory_key = id+"*lua_aspect"; // @note: factory key for a lua_aspect
344 
345  if (f == lua_aspect_factory::get_list().end()){
346  ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNKNOWN aspect["<<aspect_factory_key<<"]" << std::endl;
347  DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
348  return;
349  }
350  aspect_ptr new_aspect = f->second->get_new_instance(ai_,cfg,id,lua_ai_context_);
351  if (!new_aspect) {
352  ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNABLE TO CREATE aspect, key=["<<aspect_factory_key<<"]"<< std::endl;
353  DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
354  return;
355  }
356  *b = new_aspect;
357 }
358 
359 void engine_lua::do_parse_goal_from_config(const config &cfg, std::back_insert_iterator<std::vector< goal_ptr > > b )
360 {
362  if (f == goal_factory::get_list().end()){
363  ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNKNOWN goal["<<cfg["name"]<<"]"<< std::endl;
364  DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
365  return;
366  }
367  goal_ptr new_goal = f->second->get_new_instance(ai_,cfg);
368  new_goal->on_create(lua_ai_context_);
369  if (!new_goal || !new_goal->ok()) {
370  ERR_AI_LUA << "side "<<ai_.get_side()<< " : UNABLE TO CREATE goal["<<cfg["name"]<<"]"<< std::endl;
371  DBG_AI_LUA << "config snippet contains: " << std::endl << cfg << std::endl;
372  return;
373  }
374  *b = new_goal;
375 }
376 
377 
379 {
380  ///@todo this is not mandatory, but if we want to allow lua to evaluate
381  // something 'in context' of this ai, this will be useful
382  return "";
383 }
384 
386 {
387  config cfg = engine::to_config();
388 
389  cfg["id"] = get_id();
390  cfg["code"] = this->code_;
391 
392  if (lua_ai_context_) {
393  config data = config();
394  lua_ai_context_->get_persistent_data(data);
395  cfg.add_child("data") = data;
396  }
397 
398  return cfg;
399 }
400 
401 #ifdef _MSC_VER
402 #pragma warning(pop)
403 #endif
404 
405 } //end of namespace ai
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: engine_lua.cpp:66
virtual void execute()
Execute the candidate action.
Definition: engine_lua.cpp:199
boost::shared_ptr< stage > stage_ptr
Definition: game_info.hpp:112
lua_stage_wrapper(ai_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
Definition: engine_lua.cpp:211
Definition: unit.hpp:95
std::string code_
Method to inject AI context into the engine.
Definition: engine_lua.hpp:84
static factory_map & get_list()
Definition: aspect.hpp:516
bool is_gamestate_changed()
Check if the gamestate has changed since last reset reset is done once on construction, and can be done by hand via reset() method.
game_logic::candidate_action_ptr ca_ptr
Definition: ai.cpp:78
static factory_map & get_list()
Definition: goal.hpp:188
virtual ~engine_lua()
Definition: engine_lua.cpp:278
Composite AI stages.
void generate_code(std::string &eval, std::string &exec)
Definition: engine_lua.cpp:163
virtual ~lua_stage_wrapper()
Definition: engine_lua.cpp:217
const config & child_or_empty(const std::string &key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:722
GLint GLenum GLsizei GLint GLsizei const GLvoid * data
Definition: glew.h:1347
std::string get_engine_code(const config &) const
Definition: engine_lua.cpp:268
A helper class to observe the game state.
Lua object(value) wrapper implementation.
engine_lua(readonly_context &context, const config &cfg)
Note that initially we get access only to readonly context (engine is created rather early...
Definition: engine_lua.cpp:251
virtual config to_config() const
Serialize to config.
Definition: engine_lua.cpp:385
GLdouble GLdouble GLdouble b
Definition: glew.h:6966
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:57
GLuint GLuint end
Definition: glew.h:1221
GLuint64EXT * result
Definition: glew.h:10727
virtual config to_config() const
serialize
Definition: stage.cpp:66
virtual config to_config() const
serialize
Definition: engine.cpp:138
Proxy table for the AI context.
Definition: core.hpp:35
virtual void do_parse_goal_from_config(const config &cfg, std::back_insert_iterator< std::vector< goal_ptr > > b)
Definition: engine_lua.cpp:359
Composite AI with turn sequence which is a vector of stages.
virtual void execute()
Execute the candidate action.
Definition: engine_lua.cpp:82
virtual config to_config() const
serialize
Definition: rca.cpp:88
config serialized_evaluation_state_
Definition: engine_lua.cpp:243
virtual void do_parse_aspect_from_config(const config &cfg, const std::string &id, std::back_insert_iterator< std::vector< aspect_ptr > > b)
Taka a config (with engine=lua in it) and parse several (usually, 1) aspects out of it...
Definition: engine_lua.cpp:340
config & add_child(const std::string &key)
Definition: config.cpp:743
virtual void set_to_be_removed()
Definition: rca.cpp:101
virtual config to_config() const
serialize
Definition: engine_lua.cpp:233
#define DBG_AI_LUA
Definition: engine_lua.cpp:42
static lg::log_domain log_ai_engine_lua("ai/engine/lua")
virtual std::string get_id() const
Definition: engine.hpp:96
Templates and utility-routines for strings and numbers.
virtual void do_parse_stage_from_config(ai_context &context, const config &cfg, std::back_insert_iterator< std::vector< stage_ptr > > b)
Taka a config (with engine=lua in it) and parse several (usually, 1) stages out of it...
Definition: engine_lua.cpp:323
virtual config to_config() const
serialize
Definition: engine_lua.cpp:146
Encapsulates the map of the game.
Definition: location.hpp:38
#define ERR_AI_LUA
Definition: engine_lua.cpp:45
boost::shared_ptr< lua_ai_action_handler > evaluation_action_handler_
Definition: engine_lua.cpp:96
virtual bool do_play_stage()
Play the turn - implementation.
Definition: engine_lua.cpp:221
virtual double evaluate()
Evaluate the candidate action, resetting the internal state of the action.
Definition: engine_lua.cpp:186
boost::shared_ptr< lua_object< int > > lua_int_obj
Definition: engine_lua.cpp:53
virtual void push_ai_table()
Method that pushes the AI table of the lua_context on the stack for debugging purposes.
Definition: engine_lua.cpp:287
virtual config to_config() const
serialize
Definition: engine_lua.cpp:113
boost::shared_ptr< candidate_action > candidate_action_ptr
Definition: rca.hpp:148
ai::lua_ai_action_handler * create_lua_ai_action_handler(char const *code, ai::lua_ai_context &context)
boost::shared_ptr< lua_ai_context > lua_ai_context_
Definition: engine_lua.hpp:87
lua_candidate_action_wrapper(rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
Definition: engine_lua.cpp:104
virtual config to_config() const
serialize
Definition: engine_lua.cpp:89
void disable()
Disable the candidate action.
Definition: rca.cpp:66
boost::intrusive_ptr< unit > unit_ptr
Definition: ptr.hpp:29
lua_sticky_candidate_action_wrapper(rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
Definition: engine_lua.cpp:178
bool has_attribute(const std::string &key) const
Definition: config.cpp:514
bool find(E event, F functor)
Tests whether an event handler is available.
std::string name_
Definition: engine.hpp:112
Standard logging facilities (interface).
virtual side_number get_side() const =0
Get the side number.
boost::shared_ptr< lua_ai_action_handler > action_handler_
Definition: engine_lua.cpp:241
static const double BAD_SCORE
Definition: rca.hpp:38
game_lua_kernel * lua_kernel
Definition: resources.cpp:25
virtual void do_parse_candidate_action_from_config(rca_context &context, const config &cfg, std::back_insert_iterator< std::vector< candidate_action_ptr > > b)
Taka a config (with engine=lua in it) and parse several (usually, 1) candidate actions out of it...
Definition: engine_lua.cpp:295
lua_candidate_action_wrapper_base(rca_context &context, const config &cfg)
Definition: engine_lua.cpp:58
virtual std::string evaluate(const std::string &str)
Definition: engine_lua.cpp:378
std::string::const_iterator iterator
Definition: tokenizer.hpp:21
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
LUA AI Support engine - creating specific ai components from config.
bool is_ok() const
Definition: engine_lua.cpp:282
GLsizei const GLcharARB ** string
Definition: glew.h:4503
lua_candidate_action_wrapper_external(rca_context &context, const config &cfg, lua_ai_context &lua_ai_ctx)
Definition: engine_lua.cpp:128
unit_map * units
Definition: resources.cpp:35
boost::shared_ptr< lua_ai_action_handler > execution_action_handler_
Definition: engine_lua.cpp:97
readonly_context & ai_
Definition: engine.hpp:106
candidate action framework
const std::string valid
Little parts of regex templates used to parse Wml annoations.
GLclampf f
Definition: glew.h:3024