]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_areastore.cpp
Added the API additions from waspsaliva
[dragonfireclient.git] / src / script / lua_api / l_areastore.cpp
1 /*
2 Minetest
3 Copyright (C) 2015 est31 <mtest31@outlook.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20
21 #include "lua_api/l_areastore.h"
22 #include "lua_api/l_internal.h"
23 #include "common/c_converter.h"
24 #include "cpp_api/s_security.h"
25 #include "irr_v3d.h"
26 #include "util/areastore.h"
27 #include "filesys.h"
28 #include <fstream>
29
30 static inline void get_data_and_border_flags(lua_State *L, u8 start_i,
31                 bool *borders, bool *data)
32 {
33         if (!lua_isboolean(L, start_i))
34                 return;
35         *borders = lua_toboolean(L, start_i);
36         if (!lua_isboolean(L, start_i + 1))
37                 return;
38         *data = lua_toboolean(L, start_i + 1);
39 }
40
41 static void push_area(lua_State *L, const Area *a,
42                 bool include_borders, bool include_data)
43 {
44         if (!include_borders && !include_data) {
45                 lua_pushboolean(L, true);
46                 return;
47         }
48         lua_newtable(L);
49         if (include_borders) {
50                 push_v3s16(L, a->minedge);
51                 lua_setfield(L, -2, "min");
52                 push_v3s16(L, a->maxedge);
53                 lua_setfield(L, -2, "max");
54         }
55         if (include_data) {
56                 lua_pushlstring(L, a->data.c_str(), a->data.size());
57                 lua_setfield(L, -2, "data");
58         }
59 }
60
61 static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
62                 bool borders, bool data)
63 {
64         lua_newtable(L);
65         size_t cnt = areas.size();
66         for (size_t i = 0; i < cnt; i++) {
67                 lua_pushnumber(L, areas[i]->id);
68                 push_area(L, areas[i], borders, data);
69                 lua_settable(L, -3);
70         }
71 }
72
73 // Deserializes value and handles errors
74 static int deserialization_helper(lua_State *L, AreaStore *as,
75                 std::istream &is)
76 {
77         try {
78                 as->deserialize(is);
79         } catch (const SerializationError &e) {
80                 lua_pushboolean(L, false);
81                 lua_pushstring(L, e.what());
82                 return 2;
83         }
84
85         lua_pushboolean(L, true);
86         return 1;
87 }
88
89 // garbage collector
90 int LuaAreaStore::gc_object(lua_State *L)
91 {
92         LuaAreaStore *o = *(LuaAreaStore **)(lua_touserdata(L, 1));
93         delete o;
94         return 0;
95 }
96
97 // get_area(id, include_borders, include_data)
98 int LuaAreaStore::l_get_area(lua_State *L)
99 {
100         NO_MAP_LOCK_REQUIRED;
101
102         LuaAreaStore *o = checkobject(L, 1);
103         AreaStore *ast = o->as;
104
105         u32 id = luaL_checknumber(L, 2);
106
107         bool include_borders = true;
108         bool include_data = false;
109         get_data_and_border_flags(L, 3, &include_borders, &include_data);
110
111         const Area *res;
112
113         res = ast->getArea(id);
114         if (!res)
115                 return 0;
116
117         push_area(L, res, include_borders, include_data);
118
119         return 1;
120 }
121
122 // get_areas_for_pos(pos, include_borders, include_data)
123 int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
124 {
125         NO_MAP_LOCK_REQUIRED;
126
127         LuaAreaStore *o = checkobject(L, 1);
128         AreaStore *ast = o->as;
129
130         v3s16 pos = check_v3s16(L, 2);
131
132         bool include_borders = true;
133         bool include_data = false;
134         get_data_and_border_flags(L, 3, &include_borders, &include_data);
135
136         std::vector<Area *> res;
137
138         ast->getAreasForPos(&res, pos);
139         push_areas(L, res, include_borders, include_data);
140
141         return 1;
142 }
143
144 // get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)
145 int LuaAreaStore::l_get_areas_in_area(lua_State *L)
146 {
147         NO_MAP_LOCK_REQUIRED;
148
149         LuaAreaStore *o = checkobject(L, 1);
150         AreaStore *ast = o->as;
151
152         v3s16 minedge = check_v3s16(L, 2);
153         v3s16 maxedge = check_v3s16(L, 3);
154
155         bool include_borders = true;
156         bool include_data = false;
157         bool accept_overlap = false;
158         if (lua_isboolean(L, 4)) {
159                 accept_overlap = readParam<bool>(L, 4);
160                 get_data_and_border_flags(L, 5, &include_borders, &include_data);
161         }
162         std::vector<Area *> res;
163
164         ast->getAreasInArea(&res, minedge, maxedge, accept_overlap);
165         push_areas(L, res, include_borders, include_data);
166
167         return 1;
168 }
169
170 // insert_area(edge1, edge2, data, id)
171 int LuaAreaStore::l_insert_area(lua_State *L)
172 {
173         NO_MAP_LOCK_REQUIRED;
174
175         LuaAreaStore *o = checkobject(L, 1);
176         AreaStore *ast = o->as;
177
178         Area a(check_v3s16(L, 2), check_v3s16(L, 3));
179
180         size_t d_len;
181         const char *data = luaL_checklstring(L, 4, &d_len);
182
183         a.data = std::string(data, d_len);
184
185         if (lua_isnumber(L, 5))
186                 a.id = lua_tonumber(L, 5);
187
188         // Insert & assign a new ID if necessary
189         if (!ast->insertArea(&a))
190                 return 0;
191
192         lua_pushnumber(L, a.id);
193         return 1;
194 }
195
196 // reserve(count)
197 int LuaAreaStore::l_reserve(lua_State *L)
198 {
199         NO_MAP_LOCK_REQUIRED;
200
201         LuaAreaStore *o = checkobject(L, 1);
202         AreaStore *ast = o->as;
203
204         size_t count = luaL_checknumber(L, 2);
205         ast->reserve(count);
206         return 0;
207 }
208
209 // remove_area(id)
210 int LuaAreaStore::l_remove_area(lua_State *L)
211 {
212         NO_MAP_LOCK_REQUIRED;
213
214         LuaAreaStore *o = checkobject(L, 1);
215         AreaStore *ast = o->as;
216
217         u32 id = luaL_checknumber(L, 2);
218         bool success = ast->removeArea(id);
219
220         lua_pushboolean(L, success);
221         return 1;
222 }
223
224 // set_cache_params(params)
225 int LuaAreaStore::l_set_cache_params(lua_State *L)
226 {
227         NO_MAP_LOCK_REQUIRED;
228
229         LuaAreaStore *o = checkobject(L, 1);
230         AreaStore *ast = o->as;
231
232         luaL_checktype(L, 2, LUA_TTABLE);
233
234         bool enabled = getboolfield_default(L, 2, "enabled", true);
235         u8 block_radius = getintfield_default(L, 2, "block_radius", 64);
236         size_t limit = getintfield_default(L, 2, "block_radius", 1000);
237
238         ast->setCacheParams(enabled, block_radius, limit);
239
240         return 0;
241 }
242
243 // to_string()
244 int LuaAreaStore::l_to_string(lua_State *L)
245 {
246         NO_MAP_LOCK_REQUIRED;
247
248         LuaAreaStore *o = checkobject(L, 1);
249
250         std::ostringstream os(std::ios_base::binary);
251         o->as->serialize(os);
252         std::string str = os.str();
253
254         lua_pushlstring(L, str.c_str(), str.length());
255         return 1;
256 }
257
258 // to_file(filename)
259 int LuaAreaStore::l_to_file(lua_State *L)
260 {
261         NO_MAP_LOCK_REQUIRED;
262
263         LuaAreaStore *o = checkobject(L, 1);
264         AreaStore *ast = o->as;
265
266         const char *filename = luaL_checkstring(L, 2);
267         CHECK_SECURE_PATH(L, filename, true);
268
269         std::ostringstream os(std::ios_base::binary);
270         ast->serialize(os);
271
272         lua_pushboolean(L, fs::safeWriteToFile(filename, os.str()));
273         return 1;
274 }
275
276 // from_string(str)
277 int LuaAreaStore::l_from_string(lua_State *L)
278 {
279         NO_MAP_LOCK_REQUIRED;
280
281         LuaAreaStore *o = checkobject(L, 1);
282
283         size_t len;
284         const char *str = luaL_checklstring(L, 2, &len);
285
286         std::istringstream is(std::string(str, len), std::ios::binary);
287         return deserialization_helper(L, o->as, is);
288 }
289
290 // from_file(filename)
291 int LuaAreaStore::l_from_file(lua_State *L)
292 {
293         NO_MAP_LOCK_REQUIRED;
294
295         LuaAreaStore *o = checkobject(L, 1);
296
297         const char *filename = luaL_checkstring(L, 2);
298         CHECK_SECURE_PATH(L, filename, false);
299
300         std::ifstream is(filename, std::ios::binary);
301         return deserialization_helper(L, o->as, is);
302 }
303
304 LuaAreaStore::LuaAreaStore() : as(AreaStore::getOptimalImplementation())
305 {
306 }
307
308 LuaAreaStore::LuaAreaStore(const std::string &type)
309 {
310 #if USE_SPATIAL
311         if (type == "LibSpatial") {
312                 as = new SpatialAreaStore();
313         } else
314 #endif
315         {
316                 as = new VectorAreaStore();
317         }
318 }
319
320 LuaAreaStore::~LuaAreaStore()
321 {
322         delete as;
323 }
324
325 // LuaAreaStore()
326 // Creates an LuaAreaStore and leaves it on top of stack
327 int LuaAreaStore::create_object(lua_State *L)
328 {
329         NO_MAP_LOCK_REQUIRED;
330
331         LuaAreaStore *o = (lua_isstring(L, 1)) ?
332                 new LuaAreaStore(readParam<std::string>(L, 1)) :
333                 new LuaAreaStore();
334
335         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
336         luaL_getmetatable(L, className);
337         lua_setmetatable(L, -2);
338         return 1;
339 }
340
341 LuaAreaStore *LuaAreaStore::checkobject(lua_State *L, int narg)
342 {
343         NO_MAP_LOCK_REQUIRED;
344
345         luaL_checktype(L, narg, LUA_TUSERDATA);
346
347         void *ud = luaL_checkudata(L, narg, className);
348         if (!ud)
349                 luaL_typerror(L, narg, className);
350
351         return *(LuaAreaStore **)ud;  // unbox pointer
352 }
353
354 void LuaAreaStore::Register(lua_State *L)
355 {
356         lua_newtable(L);
357         int methodtable = lua_gettop(L);
358         luaL_newmetatable(L, className);
359         int metatable = lua_gettop(L);
360
361         lua_pushliteral(L, "__metatable");
362         lua_pushvalue(L, methodtable);
363         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
364
365         lua_pushliteral(L, "__index");
366         lua_pushvalue(L, methodtable);
367         lua_settable(L, metatable);
368
369         lua_pushliteral(L, "__gc");
370         lua_pushcfunction(L, gc_object);
371         lua_settable(L, metatable);
372
373         lua_pop(L, 1);  // drop metatable
374
375         luaL_openlib(L, 0, methods, 0);  // fill methodtable
376         lua_pop(L, 1);  // drop methodtable
377
378         // Can be created from Lua (AreaStore())
379         lua_register(L, className, create_object);
380 }
381
382 const char LuaAreaStore::className[] = "AreaStore";
383 const luaL_Reg LuaAreaStore::methods[] = {
384         luamethod(LuaAreaStore, get_area),
385         luamethod(LuaAreaStore, get_areas_for_pos),
386         luamethod(LuaAreaStore, get_areas_in_area),
387         luamethod(LuaAreaStore, insert_area),
388         luamethod(LuaAreaStore, reserve),
389         luamethod(LuaAreaStore, remove_area),
390         luamethod(LuaAreaStore, set_cache_params),
391         luamethod(LuaAreaStore, to_string),
392         luamethod(LuaAreaStore, to_file),
393         luamethod(LuaAreaStore, from_string),
394         luamethod(LuaAreaStore, from_file),
395         {0,0}
396 };