The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
lua_object.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2011 - 2025
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"
29#include "terrain/filter.hpp"
30#include "utils/general.hpp"
31#include "variable.hpp"
34
35#include <string>
36#include <vector>
37
38static lg::log_domain log_scripting_lua("scripting/lua");
39#define ERR_OBJ_LUA LOG_STREAM(err, log_scripting_lua)
40
41namespace ai {
42
44
45public:
47 virtual ~lua_object_base() {}
48
49 virtual void store(lua_State* L, int n) = 0;
50};
51
52template <typename T>
54{
55
56public:
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
85protected:
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
103template <>
104inline 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
109template <>
110inline 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
116template <>
117inline 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
122template <>
123inline 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
143template <>
144inline 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
164template <>
165inline 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
171template <>
172inline 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
177template <>
178inline 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
184template <>
185inline 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
190template <>
191inline 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
197template <>
198inline 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
214template <>
215inline 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
226template <>
227inline 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
234template <>
235inline 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
241template <>
242inline 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
253template <>
254inline 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) {
262 lua_rawseti(L, -2, lua_rawlen(L, -2) + 1);
263 }
264 } else lua_pushnil(L);
265}
266
267template <>
268inline 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 utils::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
324template <>
325inline 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.
332template <>
333std::shared_ptr<aspect_attacks_lua_filter> lua_object<aspect_attacks_lua_filter>::to_type(lua_State *L, int n);
334} // end of namespace ai
map_location loc
Definition move.cpp:172
virtual void store(lua_State *L, int n)=0
virtual ~lua_object_base()
void store(lua_State *L, int n)
void from_type(lua_State *L, std::shared_ptr< T >)
lua_object(const T &init)
std::shared_ptr< T > to_type(lua_State *, int)
std::shared_ptr< T > get()
std::shared_ptr< T > value_
void push(lua_State *L)
config & add_child(std::string_view key)
Definition config.cpp:436
Definitions for the interface to Wesnoth Markup Language (WML).
Default AI contexts.
const config * cfg
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.
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.
bool luaW_tovconfig(lua_State *L, int index, vconfig &vcfg)
Gets an optional vconfig from either a table or a userdata.
bool luaW_toboolean(lua_State *L, int n)
bool luaW_toconfig(lua_State *L, int index, config &cfg)
Converts an optional table or vconfig to a config object.
static lg::log_domain log_scripting_lua("scripting/lua")
#define ERR_OBJ_LUA
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
STL namespace.
constexpr bool decayed_is_same
Equivalent to as std::is_same_v except both types are passed through std::decay first.
Definition general.hpp:32
std::unique_ptr< MIX_Audio, decltype(&MIX_DestroyAudio)> value
Definition sound.cpp:139
Encapsulates the map of the game.
Definition location.hpp:46
static constexpr utils::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
#define i