The Battle for Wesnoth  1.17.17+dev
lua_object.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2011 - 2023
3  by Dmitry Kovalenko <nephro.wes@gmail.com>
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  * Lua object(value) wrapper implementation
19  */
20 
21 #pragma once
22 
23 #include "config.hpp"
24 #include "log.hpp"
25 #include "lua/lua.h"
26 #include "map/location.hpp"
27 #include "resources.hpp"
28 #include "scripting/lua_common.hpp"
29 #include "terrain/filter.hpp"
30 #include "variable.hpp"
31 #include "ai/default/contexts.hpp"
33 
34 #include <iterator>
35 #include <string>
36 #include <vector>
37 
38 static lg::log_domain log_scripting_lua("scripting/lua");
39 #define ERR_OBJ_LUA LOG_STREAM(err, log_scripting_lua)
40 
41 namespace ai {
42 
44 
45 public:
47  virtual ~lua_object_base() {}
48 
49  virtual void store(lua_State* L, int n) = 0;
50 };
51 
52 template <typename T>
54 {
55 
56 public:
57 
59  : value_()
60  {
61  // empty
62  }
63 
64  lua_object(const T& init)
65  : value_(std::make_shared<T>(init))
66  {
67  // empty
68  }
69 
70  std::shared_ptr<T> get()
71  {
72  return value_;
73  }
74 
75  void store(lua_State* L, int n)
76  {
77  this->value_ = to_type(L, lua_absindex(L, n));
78  }
79 
80  void push(lua_State* L)
81  {
82  from_type(L, this->value_);
83  }
84 
85 protected:
86 
87  // A group of functions that deal with the translation of the results to C++
88  std::shared_ptr<T> to_type(lua_State *, int)
89  {
90  return std::shared_ptr<T>();
91  }
92 
93  // A group of functions that deal with the translations of values back to Lua
94  void from_type(lua_State* L, std::shared_ptr<T>)
95  {
96  lua_pushliteral(L, "Unsupported AI aspect type for Lua!");
97  lua_error(L);
98  }
99 
100  std::shared_ptr<T> value_;
101 };
102 
103 template <>
104 inline std::shared_ptr<double> lua_object<double>::to_type(lua_State *L, int n)
105 {
106  return std::make_shared<double>(lua_tonumber(L, n));
107 }
108 
109 template <>
110 inline void lua_object<double>::from_type(lua_State *L, std::shared_ptr<double> value)
111 {
112  if(value) lua_pushnumber(L, *value);
113  else lua_pushnil(L);
114 }
115 
116 template <>
117 inline std::shared_ptr<std::string> lua_object<std::string>::to_type(lua_State *L, int n)
118 {
119  return std::make_shared<std::string>(lua_tostring(L, n));
120 }
121 
122 template <>
123 inline void lua_object<utils::variant<bool, std::vector<std::string>>>::from_type(lua_State *L, std::shared_ptr<utils::variant<bool, std::vector<std::string>>> value)
124 {
125  if(value) {
126  // TODO: this is is duplicated as a helper function in ai/lua/core.cpp
127  utils::visit(
128  [L](const auto& v) {
129  if constexpr(utils::decayed_is_same<bool, decltype(v)>) {
130  lua_pushboolean(L, v);
131  } else {
132  lua_createtable(L, v.size(), 0);
133  for(const std::string& str : v) {
134  lua_pushlstring(L, str.c_str(), str.size());
135  lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
136  }
137  }
138  },
139  *value);
140  } else lua_pushnil(L);
141 }
142 
143 template <>
144 inline std::shared_ptr< utils::variant<bool, std::vector<std::string>> > lua_object< utils::variant<bool, std::vector<std::string>> >::to_type(lua_State *L, int n)
145 {
146  if (lua_isboolean(L, n)) {
147  return std::make_shared<utils::variant<bool, std::vector<std::string>>>(luaW_toboolean(L, n));
148  } else {
149  auto v = std::make_shared<std::vector<std::string>>();
150  int l = lua_rawlen(L, n);
151  for (int i = 1; i < l + 1; ++i)
152  {
153  lua_pushinteger(L, i);
154  lua_gettable(L, n);
155  std::string s = lua_tostring(L, -1);
156  lua_settop(L, n);
157  v->push_back(s);
158  }
159 
160  return std::make_shared<utils::variant<bool, std::vector<std::string>>>(*v);
161  }
162 }
163 
164 template <>
165 inline void lua_object<std::string>::from_type(lua_State *L, std::shared_ptr<std::string> value)
166 {
167  if(value) lua_pushlstring(L, value->c_str(), value->size());
168  else lua_pushnil(L);
169 }
170 
171 template <>
172 inline std::shared_ptr<bool> lua_object<bool>::to_type(lua_State *L, int n)
173 {
174  return std::make_shared<bool>(luaW_toboolean(L, n));
175 }
176 
177 template <>
178 inline void lua_object<bool>::from_type(lua_State *L, std::shared_ptr<bool> value)
179 {
180  if(value) lua_pushboolean(L, *value);
181  else lua_pushnil(L);
182 }
183 
184 template <>
185 inline std::shared_ptr<int> lua_object<int>::to_type(lua_State *L, int n)
186 {
187  return std::make_shared<int>(static_cast<int>(lua_tointeger(L, n)));
188 }
189 
190 template <>
191 inline void lua_object<int>::from_type(lua_State *L, std::shared_ptr<int> value)
192 {
193  if(value) lua_pushnumber(L, *value);
194  else lua_pushnil(L);
195 }
196 
197 template <>
198 inline std::shared_ptr< std::vector<std::string> > lua_object< std::vector<std::string> >::to_type(lua_State *L, int n)
199 {
200  auto v = std::make_shared<std::vector<std::string>>();
201  int l = lua_rawlen(L, n);
202  for (int i = 1; i < l + 1; ++i)
203  {
204  lua_pushinteger(L, i);
205  lua_gettable(L, n);
206  std::string s = lua_tostring(L, -1);
207  lua_settop(L, n);
208  v->push_back(s);
209  }
210 
211  return v;
212 }
213 
214 template <>
215 inline void lua_object< std::vector<std::string> >::from_type(lua_State *L, std::shared_ptr< std::vector<std::string> > value)
216 {
217  if(value) {
218  lua_createtable(L, value->size(), 0);
219  for(const std::string& str : *value) {
220  lua_pushlstring(L, str.c_str(), str.size());
221  lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
222  }
223  } else lua_pushnil(L);
224 }
225 
226 template <>
227 inline std::shared_ptr<config> lua_object<config>::to_type(lua_State *L, int n)
228 {
229  auto cfg = std::make_shared<config>();
230  luaW_toconfig(L, n, *cfg);
231  return cfg;
232 }
233 
234 template <>
235 inline void lua_object<config>::from_type(lua_State *L, std::shared_ptr<config> value)
236 {
237  if(value) luaW_pushconfig(L, *value);
238  else lua_pushnil(L);
239 }
240 
241 template <>
242 inline std::shared_ptr<terrain_filter> lua_object<terrain_filter>::to_type(lua_State *L, int n)
243 {
244  auto cfg = std::make_shared<config>();
245  auto vcfg = std::make_shared<vconfig>(*cfg);
246  if (!luaW_tovconfig(L, n, *vcfg)) {
247  cfg->add_child("not");
248  }
249  vcfg->make_safe();
250  return std::make_shared<terrain_filter>(*vcfg, resources::filter_con, false);
251 }
252 
253 template <>
254 inline void lua_object<terrain_filter>::from_type(lua_State *L, std::shared_ptr<terrain_filter> value)
255 {
256  if(value) {
257  std::set<map_location> locs;
258  value->get_locations(locs);
259  lua_createtable(L, locs.size(), 0);
260  for(const map_location& loc : locs) {
261  luaW_pushlocation(L, loc);
262  lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
263  }
264  } else lua_pushnil(L);
265 }
266 
267 template <>
268 inline std::shared_ptr<std::vector<target> > lua_object< std::vector<target> >::to_type(lua_State *L, int n)
269 {
270  auto targets = std::make_shared<std::vector<target>>();
271  int l = lua_rawlen(L, n);
272 
273  for (int i = 1; i <= l; ++i)
274  {
275  lua_rawgeti(L, n, i); // st n + 1 TABLE @ N table @ n + 1
276 
277  lua_pushstring(L, "loc"); // st n + 2
278  lua_rawget(L, -2); // st n + 2
279 
280  lua_pushstring(L, "x"); // st n + 3
281  lua_rawget(L, -2); // st n + 3
282  int x = static_cast<int>(lua_tointeger(L, -1)); // st n + 3
283  lua_pop(L, 1); // st n + 2
284 
285  lua_pushstring(L, "y"); // st n + 3
286  lua_rawget(L, -2); // st n + 3
287  int y = static_cast<int>(lua_tointeger(L, -1)); // st n + 3
288 
289  lua_pop(L, 2); // st n + 1
290 
291  lua_pushstring(L, "type"); // st n + 2
292  lua_rawget(L, -2); // st n + 2
293  std::optional<ai_target::type> type = ai_target::type::xplicit;
294  if(lua_isnumber(L, -1)) {
295  int target = static_cast<int>(lua_tointeger(L, -1));
296  type = ai_target::get_enum(target); // st n + 2
297  if(!type) {
298  ERR_OBJ_LUA << "Failed to convert ai target type of " << target << ", skipping.";
299  continue;
300  }
301  } else if(lua_isstring(L, -1)) {
302  std::string target = lua_tostring(L, -1);
303  type = ai_target::get_enum(target); // st n + 2
304  if(!type) {
305  ERR_OBJ_LUA << "Failed to convert ai target type of " << target << ", skipping.";
306  continue;
307  }
308  }
309  lua_pop(L, 1); // st n + 1
310 
311  lua_pushstring(L, "value");
312  lua_rawget(L, -2);
313  int value = static_cast<int>(lua_tointeger(L, -1));
314 
315  map_location ml(x, y, wml_loc());
316 
317  targets->emplace_back(ml, value, *type);
318  }
319 
320  lua_settop(L, n);
321  return targets;
322 }
323 
324 template <>
325 inline std::shared_ptr<unit_advancements_aspect> lua_object<unit_advancements_aspect>::to_type(lua_State *L, int n)
326 {
327  return std::make_shared<unit_advancements_aspect>(L, n);
328 }
329 
330 // This one is too complex to define in the header.
332 template <>
333 std::shared_ptr<aspect_attacks_lua_filter> lua_object<aspect_attacks_lua_filter>::to_type(lua_State *L, int n);
334 } // end of namespace ai
virtual void store(lua_State *L, int n)=0
virtual ~lua_object_base()
Definition: lua_object.hpp:47
void store(lua_State *L, int n)
Definition: lua_object.hpp:75
void from_type(lua_State *L, std::shared_ptr< T >)
Definition: lua_object.hpp:94
lua_object(const T &init)
Definition: lua_object.hpp:64
std::shared_ptr< T > to_type(lua_State *, int)
Definition: lua_object.hpp:88
std::shared_ptr< T > get()
Definition: lua_object.hpp:70
std::shared_ptr< T > value_
Definition: lua_object.hpp:100
void push(lua_State *L)
Definition: lua_object.hpp:80
Default AI contexts.
std::size_t i
Definition: function.cpp:968
Standard logging facilities (interface).
void luaW_pushconfig(lua_State *L, const config &cfg)
Converts a config object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:830
void luaW_pushlocation(lua_State *L, const map_location &ml)
Converts a map location object to a Lua table pushed at the top of the stack.
Definition: lua_common.cpp:733
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
Gets an optional vconfig from either a table or a userdata.
Definition: lua_common.cpp:937
bool luaW_toboolean(lua_State *L, int n)
Definition: lua_common.cpp:991
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
Definition: lua_common.cpp:842
static lg::log_domain log_scripting_lua("scripting/lua")
#define ERR_OBJ_LUA
Definition: lua_object.hpp:39
A small explanation about what's going on here: Each action has access to two game_info objects First...
Definition: actions.cpp:61
filter_context * filter_con
Definition: resources.cpp:24
struct utils::detail::formula_initer init
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
Definition: general.hpp:34
Encapsulates the map of the game.
Definition: location.hpp:38
static constexpr std::optional< enum_type > get_enum(const std::string_view value)
Converts a string into its enum equivalent.
Definition: enum_base.hpp:57
static map_location::DIRECTION n
static map_location::DIRECTION s