1 /**
2 * @file
3 * @brief Utility functions and macros for Lua bindings.
4 **/
5
6 #pragma once
7
8 #include "AppHdr.h"
9
10 extern "C" {
11 #include <lua.h>
12 #include <lauxlib.h>
13 #include <lualib.h>
14 }
15
16 #include <vector>
17
18 using std::vector;
19
20 lua_Integer luaL_safe_checkinteger(lua_State *L, int idx);
21 lua_Integer luaL_safe_tointeger(lua_State *L, int idx);
22 // override some #defines in the lua libs.
23 #define luaL_safe_checkint(L,n) ((int)luaL_safe_checkinteger(L, (n)))
24 #define luaL_safe_checklong(L,n) ((long)luaL_safe_checkinteger(L, (n)))
25
26 /*
27 * Function definitions.
28 */
29
30 #define LUAFN(name) static int name(lua_State *ls)
31 #define LUAWRAP(name, wrapexpr) \
32 static int name(lua_State *ls) \
33 { \
34 UNUSED(ls); \
35 wrapexpr; \
36 return 0; \
37 }
38 #define PLUARET(type, val) \
39 do { \
40 lua_push##type(ls, val); \
41 return 1; \
42 } while (false)
43 #define LUARET1(name, type, val) \
44 static int name(lua_State *ls) \
45 { \
46 lua_push##type(ls, val); \
47 return 1; \
48 }
49 #define LUARET2(name, type, val1, val2) \
50 static int name(lua_State *ls) \
51 { \
52 lua_push##type(ls, val1); \
53 lua_push##type(ls, val2); \
54 return 2; \
55 }
56
57 #define ASSERT_DLUA \
58 do { \
59 if (CLua::get_vm(ls).managed_vm) \
60 luaL_error(ls, "Operation forbidden in end-user script"); \
61 } while (false)
62
63 // FIXME: remove one of these.
64 void luaopen_setmeta(lua_State *ls,
65 const char *global,
66 const luaL_reg *lua_lib,
67 const char *meta);
68
69 void clua_register_metatable(lua_State *ls, const char *tn,
70 const luaL_reg *lr,
71 int (*gcfn)(lua_State *ls) = nullptr);
72
73 int clua_stringtable(lua_State *ls, const vector<string> &s);
74
75 /*
76 * User-data templates.
77 * TODO: Consolidate these.
78 */
79
80 template <class T>
clua_get_lightuserdata(lua_State * ls,int ndx)81 static inline T *clua_get_lightuserdata(lua_State *ls, int ndx)
82 {
83 return (lua_islightuserdata(ls, ndx))?
84 static_cast<T *>(lua_touserdata(ls, ndx))
85 : nullptr;
86 }
87
88 template <class T>
89 static inline T *clua_get_userdata(lua_State *ls, const char *mt, int ndx = 1)
90 {
91 return static_cast<T*>(luaL_checkudata(ls, ndx, mt));
92 }
93
94 // Use for cases where the userdata is simply a pointer and is guaranteed
95 // to be created by `new`. For a more complex pattern, see _delete_wrapped_item
96 // in l-item.cc. The pattern instantiate here requires checking the pointer
97 // for validity...
98 template <class T>
lua_object_gc(lua_State * ls)99 static int lua_object_gc(lua_State *ls)
100 {
101 T **pptr = static_cast<T**>(lua_touserdata(ls, 1));
102 if (pptr && *pptr)
103 {
104 delete *pptr;
105 *pptr = nullptr;
106 }
107 return 0;
108 }
109
110 // allocate space for an object of type T via lua. Any memory allocated this
111 // way will be garbage-collected by lua. There are basically two patterns:
112 // (i) T is a pointer (call it `*S`), so the type signature of this ends up as
113 // **S. In that case, the memory management is probably handled on the c++
114 // side, perhaps by creating a new object when instantiating this userdef.
115 // (ii) T is a wrapper struct, for example `item_wrapper` in l-item.cc. In this
116 // case the memory management may be a bit more complicated, but the
117 // wrapper object will still usually have a pointer to a c++ object, and
118 // may still need a gc function.
119 //
120 // If a `delete` is needed on cleanup, bind an appropriate function to the __gc
121 // metamethod. For example, case (i) can usually use `lua_object_gc` above.
122 // Be aware that this method is callable directly from the lua side in addition
123 // to being automatically triggered -- so you need to be careful with your
124 // pointers!
clua_new_userdata(lua_State * ls,const char * mt)125 template <class T> T *clua_new_userdata(
126 lua_State *ls, const char *mt)
127 {
128 void *udata = lua_newuserdata(ls, sizeof(T));
129 luaL_getmetatable(ls, mt);
130 lua_setmetatable(ls, -2);
131 return static_cast<T*>(udata);
132 }
133
134 template <typename T>
dlua_push_userdata(lua_State * ls,T udata,const char * meta)135 static inline void dlua_push_userdata(lua_State *ls, T udata, const char *meta)
136 {
137 T *de = clua_new_userdata<T>(ls, meta);
138 *de = udata;
139 }
140
141 template <class T>
dlua_push_object_type(lua_State * ls,const char * meta,const T & data)142 static int dlua_push_object_type(lua_State *ls, const char *meta, const T &data)
143 {
144 T **ptr = clua_new_userdata<T*>(ls, meta);
145 if (ptr)
146 *ptr = new T(data);
147 else
148 lua_pushnil(ls);
149 return 1;
150 }
151
152 /*
153 * Passing objects from and to Lua.
154 */
155 struct activity_interrupt_data;
156 int push_activity_interrupt(lua_State *ls, activity_interrupt_data *t);
157
158 class map_def;
159 void clua_push_map(lua_State *ls, map_def *map);
160
161 class dgn_event;
162 void clua_push_dgn_event(lua_State *ls, const dgn_event *devent);
163
164 class monster;
165 struct MonsterWrap
166 {
167 monster* mons;
168 int turn;
169 };
170
171 // XXX: These are currently defined outside cluautil.cc.
172 void push_monster(lua_State *ls, monster* mons);
173 void clua_push_item(lua_State *ls, item_def *item);
174 item_def *clua_get_item(lua_State *ls, int ndx);
175 void lua_push_floor_items(lua_State *ls, int link);
176 dungeon_feature_type check_lua_feature(lua_State *ls, int idx,
177 bool optional = false);
178 tileidx_t get_tile_idx(lua_State *ls, int arg);
179 level_id dlua_level_id(lua_State *ls, int ndx);
180
181 #define GETCOORD(c, p1, p2, boundfn) \
182 coord_def c; \
183 c.x = luaL_safe_checkint(ls, p1); \
184 c.y = luaL_safe_checkint(ls, p2); \
185 if (!boundfn(c)) \
186 luaL_error( \
187 ls, \
188 make_stringf("Point (%d,%d) is out of bounds", \
189 c.x, c.y).c_str()); \
190 else {};
191
192 #define COORDS(c, p1, p2) \
193 GETCOORD(c, p1, p2, in_bounds)
194
195 #define COORDSHOW(c, p1, p2) \
196 GETCOORD(c, p1, p2, in_show_bounds)
197
198 #define PLAYERCOORDS(p, p1, p2) \
199 const coord_def p = player2grid(coord_def(luaL_safe_checkint(ls,p1), \
200 luaL_safe_checkint(ls,p2)));
201
202 #define FEAT(f, pos) \
203 dungeon_feature_type f = check_lua_feature(ls, pos)
204
205 #define LEVEL(br, pos) \
206 const char *branch_name = luaL_checkstring(ls, pos); \
207 branch_type br = branch_by_abbrevname(branch_name); \
208 if (br == NUM_BRANCHES) \
209 luaL_error(ls, "Expected branch name");
210
211 #define MAP(ls, n, var) \
212 map_def *var = *(map_def **) luaL_checkudata(ls, n, MAP_METATABLE); \
213 if (!var) \
214 return 0
215
216 // TODO: ugh
217 #define LINES(ls, n, map_var, lines_var) \
218 MAP(ls, n, map_var); \
219 map_lines &lines_var = map_var->map
220
221 #define DEVENT(ls, n, var) \
222 dgn_event *var = *(dgn_event **) luaL_checkudata(ls, n, DEVENT_METATABLE); \
223 if (!var) \
224 return 0
225
226 #define MAPMARKER(ls, n, var) \
227 map_marker *var = *(map_marker **) luaL_checkudata(ls, n, MAPMARK_METATABLE); \
228 if (!var) \
229 return 0
230
231 #define LUA_ITEM(ls, name, n) \
232 item_def *name = *(item_def **) luaL_checkudata(ls, n, ITEM_METATABLE); \
233 if (!name) \
234 return 0
235
236 template <typename list, typename lpush>
clua_gentable(lua_State * ls,const list & strings,lpush push)237 static int clua_gentable(lua_State *ls, const list &strings, lpush push)
238 {
239 lua_newtable(ls);
240 for (int i = 0, size = strings.size(); i < size; ++i)
241 {
242 push(ls, strings[i]);
243 lua_rawseti(ls, -2, i + 1);
244 }
245 return 1;
246 }
247
248 int clua_pushcxxstring(lua_State *ls, const string &s);
249 int clua_pushpoint(lua_State *ls, const coord_def &pos);
250