]> git.lizzy.rs Git - dragonfireclient.git/blob - src/script/lua_api/l_areastore.cpp
Areastore: fix "attempt to index a number value"
[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 "areastore.h"
26 #include "filesys.h"
27 #ifndef ANDROID
28         #include "cmake_config.h"
29 #endif
30 #include <fstream>
31
32 static inline void get_data_and_border_flags(lua_State *L, u8 start_i,
33                 bool *borders, bool *data)
34 {
35         if (!lua_isboolean(L, start_i))
36                 return;
37         *borders = lua_toboolean(L, start_i);
38         if (!lua_isboolean(L, start_i + 1))
39                 return;
40         *data = lua_toboolean(L, start_i + 1);
41 }
42
43 static void push_area(lua_State *L, const Area *a,
44                 bool include_borders, bool include_data)
45 {
46         if (!include_borders && !include_data) {
47                 lua_pushboolean(L, true);
48                 return;
49         }
50         lua_newtable(L);
51         if (include_borders) {
52                 push_v3s16(L, a->minedge);
53                 lua_setfield(L, -2, "min");
54                 push_v3s16(L, a->maxedge);
55                 lua_setfield(L, -2, "max");
56         }
57         if (include_data) {
58                 lua_pushlstring(L, a->data.c_str(), a->data.size());
59                 lua_setfield(L, -2, "data");
60         }
61 }
62
63 static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
64                 bool borders, bool data)
65 {
66         lua_newtable(L);
67         size_t cnt = areas.size();
68         for (size_t i = 0; i < cnt; i++) {
69                 lua_pushnumber(L, areas[i]->id);
70                 push_area(L, areas[i], borders, data);
71                 lua_settable(L, -3);
72         }
73 }
74
75 // garbage collector
76 int LuaAreaStore::gc_object(lua_State *L)
77 {
78         LuaAreaStore *o = *(LuaAreaStore **)(lua_touserdata(L, 1));
79         delete o;
80         return 0;
81 }
82
83 // get_area(id, include_borders, include_data)
84 int LuaAreaStore::l_get_area(lua_State *L)
85 {
86         NO_MAP_LOCK_REQUIRED;
87
88         LuaAreaStore *o = checkobject(L, 1);
89         AreaStore *ast = o->as;
90
91         u32 id = luaL_checknumber(L, 2);
92
93         bool include_borders = true;
94         bool include_data = false;
95         get_data_and_border_flags(L, 3, &include_borders, &include_data);
96
97         const Area *res;
98
99         res = ast->getArea(id);
100         push_area(L, res, include_borders, include_data);
101
102         return 1;
103 }
104
105 // get_areas_for_pos(pos, include_borders, include_data)
106 int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
107 {
108         NO_MAP_LOCK_REQUIRED;
109
110         LuaAreaStore *o = checkobject(L, 1);
111         AreaStore *ast = o->as;
112
113         v3s16 pos = check_v3s16(L, 2);
114
115         bool include_borders = true;
116         bool include_data = false;
117         get_data_and_border_flags(L, 3, &include_borders, &include_data);
118
119         std::vector<Area *> res;
120
121         ast->getAreasForPos(&res, pos);
122         push_areas(L, res, include_borders, include_data);
123
124         return 1;
125 }
126
127 // get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)
128 int LuaAreaStore::l_get_areas_in_area(lua_State *L)
129 {
130         NO_MAP_LOCK_REQUIRED;
131
132         LuaAreaStore *o = checkobject(L, 1);
133         AreaStore *ast = o->as;
134
135         v3s16 minedge = check_v3s16(L, 2);
136         v3s16 maxedge = check_v3s16(L, 3);
137
138         bool include_borders = true;
139         bool include_data = false;
140         bool accept_overlap = false;
141         if (lua_isboolean(L, 4)) {
142                 accept_overlap = lua_toboolean(L, 4);
143                 get_data_and_border_flags(L, 5, &include_borders, &include_data);
144         }
145         std::vector<Area *> res;
146
147         ast->getAreasInArea(&res, minedge, maxedge, accept_overlap);
148         push_areas(L, res, include_borders, include_data);
149
150         return 1;
151 }
152
153 // insert_area(edge1, edge2, data)
154 int LuaAreaStore::l_insert_area(lua_State *L)
155 {
156         NO_MAP_LOCK_REQUIRED;
157
158         LuaAreaStore *o = checkobject(L, 1);
159         AreaStore *ast = o->as;
160
161         Area a;
162
163         a.minedge = check_v3s16(L, 2);
164         a.maxedge = check_v3s16(L, 3);
165
166         a.extremifyEdges();
167         a.id = ast->getFreeId(a.minedge, a.maxedge);
168
169         if (a.id == AREA_ID_INVALID) {
170                 // couldn't get free id
171                 lua_pushnil(L);
172                 return 1;
173         }
174
175         size_t d_len;
176         const char *data = luaL_checklstring(L, 4, &d_len);
177
178         a.data = std::string(data, d_len);
179
180         ast->insertArea(a);
181
182         lua_pushnumber(L, a.id);
183         return 1;
184 }
185
186 // reserve(count)
187 int LuaAreaStore::l_reserve(lua_State *L)
188 {
189         NO_MAP_LOCK_REQUIRED;
190
191         LuaAreaStore *o = checkobject(L, 1);
192         AreaStore *ast = o->as;
193
194         size_t count = luaL_checknumber(L, 2);
195         ast->reserve(count);
196         return 0;
197 }
198
199 // remove_area(id)
200 int LuaAreaStore::l_remove_area(lua_State *L)
201 {
202         NO_MAP_LOCK_REQUIRED;
203
204         LuaAreaStore *o = checkobject(L, 1);
205         AreaStore *ast = o->as;
206
207         u32 id = luaL_checknumber(L, 2);
208         bool success = ast->removeArea(id);
209
210         lua_pushboolean(L, success);
211         return 1;
212 }
213
214 // set_cache_params(params)
215 int LuaAreaStore::l_set_cache_params(lua_State *L)
216 {
217         NO_MAP_LOCK_REQUIRED;
218
219         LuaAreaStore *o = checkobject(L, 1);
220         AreaStore *ast = o->as;
221
222         luaL_checktype(L, 2, LUA_TTABLE);
223
224         bool enabled = getboolfield_default(L, 2, "enabled", true);
225         u8 block_radius = getintfield_default(L, 2, "block_radius", 64);
226         size_t limit = getintfield_default(L, 2, "block_radius", 1000);
227
228         ast->setCacheParams(enabled, block_radius, limit);
229
230         return 0;
231 }
232
233 #if 0
234 // to_string()
235 int LuaAreaStore::l_to_string(lua_State *L)
236 {
237         NO_MAP_LOCK_REQUIRED;
238
239         LuaAreaStore *o = checkobject(L, 1);
240         AreaStore *ast = o->as;
241
242         std::ostringstream os(std::ios_base::binary);
243         ast->serialize(os);
244         std::string str = os.str();
245
246         lua_pushlstring(L, str.c_str(), str.length());
247         return 1;
248 }
249
250 // to_file(filename)
251 int LuaAreaStore::l_to_file(lua_State *L)
252 {
253         NO_MAP_LOCK_REQUIRED;
254
255         LuaAreaStore *o = checkobject(L, 1);
256         AreaStore *ast = o->as;
257
258         const char *filename = luaL_checkstring(L, 2);
259         CHECK_SECURE_PATH_OPTIONAL(L, filename);
260
261         std::ostringstream os(std::ios_base::binary);
262         ast->serialize(os);
263
264         lua_pushboolean(L, fs::safeWriteToFile(filename, os.str()));
265         return 1;
266 }
267
268 // from_string(str)
269 int LuaAreaStore::l_from_string(lua_State *L)
270 {
271         NO_MAP_LOCK_REQUIRED;
272
273         LuaAreaStore *o = checkobject(L, 1);
274         AreaStore *ast = o->as;
275
276         size_t len;
277         const char *str = luaL_checklstring(L, 2, &len);
278
279         std::istringstream is(std::string(str, len), std::ios::binary);
280         bool success = ast->deserialize(is);
281
282         lua_pushboolean(L, success);
283         return 1;
284 }
285
286 // from_file(filename)
287 int LuaAreaStore::l_from_file(lua_State *L)
288 {
289         NO_MAP_LOCK_REQUIRED;
290
291         LuaAreaStore *o = checkobject(L, 1);
292         AreaStore *ast = o->as;
293
294         const char *filename = luaL_checkstring(L, 2);
295         CHECK_SECURE_PATH_OPTIONAL(L, filename);
296
297         std::ifstream is(filename, std::ios::binary);
298         bool success = ast->deserialize(is);
299
300         lua_pushboolean(L, success);
301         return 1;
302 }
303 #endif
304
305 LuaAreaStore::LuaAreaStore()
306 {
307 #if USE_SPATIAL
308         this->as = new SpatialAreaStore();
309 #else
310         this->as = new VectorAreaStore();
311 #endif
312 }
313
314 LuaAreaStore::LuaAreaStore(const std::string &type)
315 {
316 #if USE_SPATIAL
317         if (type == "LibSpatial") {
318                 this->as = new SpatialAreaStore();
319         } else
320 #endif
321         {
322                 this->as = new VectorAreaStore();
323         }
324 }
325
326 LuaAreaStore::~LuaAreaStore()
327 {
328         delete as;
329 }
330
331 // LuaAreaStore()
332 // Creates an LuaAreaStore and leaves it on top of stack
333 int LuaAreaStore::create_object(lua_State *L)
334 {
335         NO_MAP_LOCK_REQUIRED;
336
337         LuaAreaStore *o = (lua_isstring(L, 1)) ?
338                 new LuaAreaStore(lua_tostring(L, 1)) :
339                 new LuaAreaStore();
340
341         *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
342         luaL_getmetatable(L, className);
343         lua_setmetatable(L, -2);
344         return 1;
345 }
346
347 LuaAreaStore *LuaAreaStore::checkobject(lua_State *L, int narg)
348 {
349         NO_MAP_LOCK_REQUIRED;
350
351         luaL_checktype(L, narg, LUA_TUSERDATA);
352
353         void *ud = luaL_checkudata(L, narg, className);
354         if (!ud)
355                 luaL_typerror(L, narg, className);
356
357         return *(LuaAreaStore **)ud;  // unbox pointer
358 }
359
360 void LuaAreaStore::Register(lua_State *L)
361 {
362         lua_newtable(L);
363         int methodtable = lua_gettop(L);
364         luaL_newmetatable(L, className);
365         int metatable = lua_gettop(L);
366
367         lua_pushliteral(L, "__metatable");
368         lua_pushvalue(L, methodtable);
369         lua_settable(L, metatable);  // hide metatable from Lua getmetatable()
370
371         lua_pushliteral(L, "__index");
372         lua_pushvalue(L, methodtable);
373         lua_settable(L, metatable);
374
375         lua_pushliteral(L, "__gc");
376         lua_pushcfunction(L, gc_object);
377         lua_settable(L, metatable);
378
379         lua_pop(L, 1);  // drop metatable
380
381         luaL_openlib(L, 0, methods, 0);  // fill methodtable
382         lua_pop(L, 1);  // drop methodtable
383
384         // Can be created from Lua (AreaStore())
385         lua_register(L, className, create_object);
386 }
387
388 const char LuaAreaStore::className[] = "AreaStore";
389 const luaL_reg LuaAreaStore::methods[] = {
390         luamethod(LuaAreaStore, get_area),
391         luamethod(LuaAreaStore, get_areas_for_pos),
392         luamethod(LuaAreaStore, get_areas_in_area),
393         luamethod(LuaAreaStore, insert_area),
394         luamethod(LuaAreaStore, reserve),
395         luamethod(LuaAreaStore, remove_area),
396         luamethod(LuaAreaStore, set_cache_params),
397         /* luamethod(LuaAreaStore, to_string),
398         luamethod(LuaAreaStore, to_file),
399         luamethod(LuaAreaStore, from_string),
400         luamethod(LuaAreaStore, from_file),*/
401         {0,0}
402 };