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