Spawn level: Add 'get_spawn_level(x, z)' API
[oweals/minetest.git] / src / script / common / c_converter.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.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 extern "C" {
21 #include "lua.h"
22 #include "lauxlib.h"
23 }
24
25 #include "util/numeric.h"
26 #include "util/serialize.h"
27 #include "util/string.h"
28 #include "common/c_converter.h"
29 #include "common/c_internal.h"
30 #include "constants.h"
31
32
33 #define CHECK_TYPE(index, name, type) { \
34                 int t = lua_type(L, (index)); \
35                 if (t != (type)) { \
36                         std::string traceback = script_get_backtrace(L); \
37                         throw LuaError(std::string("Invalid ") + (name) + \
38                                 " (expected " + lua_typename(L, (type)) + \
39                                 " got " + lua_typename(L, t) + ").\n" + traceback); \
40                 } \
41         }
42 #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER)
43 #define CHECK_FLOAT_RANGE(value, name) \
44 if (value < F1000_MIN || value > F1000_MAX) { \
45         std::ostringstream error_text; \
46         error_text << "Invalid float vector dimension range '" name "' " << \
47         "(expected " << F1000_MIN << " < " name " < " << F1000_MAX << \
48         " got " << value << ")." << std::endl; \
49         throw LuaError(error_text.str()); \
50 }
51 #define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE)
52
53
54 void push_float_string(lua_State *L, float value)
55 {
56         std::stringstream ss;
57         std::string str;
58         ss << value;
59         str = ss.str();
60         lua_pushstring(L, str.c_str());
61 }
62
63 void push_v3f(lua_State *L, v3f p)
64 {
65         lua_newtable(L);
66         lua_pushnumber(L, p.X);
67         lua_setfield(L, -2, "x");
68         lua_pushnumber(L, p.Y);
69         lua_setfield(L, -2, "y");
70         lua_pushnumber(L, p.Z);
71         lua_setfield(L, -2, "z");
72 }
73
74 void push_v2f(lua_State *L, v2f p)
75 {
76         lua_newtable(L);
77         lua_pushnumber(L, p.X);
78         lua_setfield(L, -2, "x");
79         lua_pushnumber(L, p.Y);
80         lua_setfield(L, -2, "y");
81 }
82
83 void push_v3_float_string(lua_State *L, v3f p)
84 {
85         lua_newtable(L);
86         push_float_string(L, p.X);
87         lua_setfield(L, -2, "x");
88         push_float_string(L, p.Y);
89         lua_setfield(L, -2, "y");
90         push_float_string(L, p.Z);
91         lua_setfield(L, -2, "z");
92 }
93
94 void push_v2_float_string(lua_State *L, v2f p)
95 {
96         lua_newtable(L);
97         push_float_string(L, p.X);
98         lua_setfield(L, -2, "x");
99         push_float_string(L, p.Y);
100         lua_setfield(L, -2, "y");
101 }
102
103 v2s16 read_v2s16(lua_State *L, int index)
104 {
105         v2s16 p;
106         CHECK_POS_TAB(index);
107         lua_getfield(L, index, "x");
108         p.X = lua_tonumber(L, -1);
109         lua_pop(L, 1);
110         lua_getfield(L, index, "y");
111         p.Y = lua_tonumber(L, -1);
112         lua_pop(L, 1);
113         return p;
114 }
115
116 v2s16 check_v2s16(lua_State *L, int index)
117 {
118         v2s16 p;
119         CHECK_POS_TAB(index);
120         lua_getfield(L, index, "x");
121         CHECK_POS_COORD("x");
122         p.X = lua_tonumber(L, -1);
123         lua_pop(L, 1);
124         lua_getfield(L, index, "y");
125         CHECK_POS_COORD("y");
126         p.Y = lua_tonumber(L, -1);
127         lua_pop(L, 1);
128         return p;
129 }
130
131 void push_v2s16(lua_State *L, v2s16 p)
132 {
133         lua_newtable(L);
134         lua_pushnumber(L, p.X);
135         lua_setfield(L, -2, "x");
136         lua_pushnumber(L, p.Y);
137         lua_setfield(L, -2, "y");
138 }
139
140 void push_v2s32(lua_State *L, v2s32 p)
141 {
142         lua_newtable(L);
143         lua_pushnumber(L, p.X);
144         lua_setfield(L, -2, "x");
145         lua_pushnumber(L, p.Y);
146         lua_setfield(L, -2, "y");
147 }
148
149 v2s32 read_v2s32(lua_State *L, int index)
150 {
151         v2s32 p;
152         CHECK_POS_TAB(index);
153         lua_getfield(L, index, "x");
154         p.X = lua_tonumber(L, -1);
155         lua_pop(L, 1);
156         lua_getfield(L, index, "y");
157         p.Y = lua_tonumber(L, -1);
158         lua_pop(L, 1);
159         return p;
160 }
161
162 v2f read_v2f(lua_State *L, int index)
163 {
164         v2f p;
165         CHECK_POS_TAB(index);
166         lua_getfield(L, index, "x");
167         p.X = lua_tonumber(L, -1);
168         lua_pop(L, 1);
169         lua_getfield(L, index, "y");
170         p.Y = lua_tonumber(L, -1);
171         lua_pop(L, 1);
172         return p;
173 }
174
175 v2f check_v2f(lua_State *L, int index)
176 {
177         v2f p;
178         CHECK_POS_TAB(index);
179         lua_getfield(L, index, "x");
180         CHECK_POS_COORD("x");
181         p.X = lua_tonumber(L, -1);
182         lua_pop(L, 1);
183         lua_getfield(L, index, "y");
184         CHECK_POS_COORD("y");
185         p.Y = lua_tonumber(L, -1);
186         lua_pop(L, 1);
187         return p;
188 }
189
190 v3f read_v3f(lua_State *L, int index)
191 {
192         v3f pos;
193         CHECK_POS_TAB(index);
194         lua_getfield(L, index, "x");
195         pos.X = lua_tonumber(L, -1);
196         lua_pop(L, 1);
197         lua_getfield(L, index, "y");
198         pos.Y = lua_tonumber(L, -1);
199         lua_pop(L, 1);
200         lua_getfield(L, index, "z");
201         pos.Z = lua_tonumber(L, -1);
202         lua_pop(L, 1);
203         return pos;
204 }
205
206 v3f check_v3f(lua_State *L, int index)
207 {
208         v3f pos;
209         CHECK_POS_TAB(index);
210         lua_getfield(L, index, "x");
211         CHECK_POS_COORD("x");
212         pos.X = lua_tonumber(L, -1);
213         CHECK_FLOAT_RANGE(pos.X, "x")
214         lua_pop(L, 1);
215         lua_getfield(L, index, "y");
216         CHECK_POS_COORD("y");
217         pos.Y = lua_tonumber(L, -1);
218         CHECK_FLOAT_RANGE(pos.Y, "y")
219         lua_pop(L, 1);
220         lua_getfield(L, index, "z");
221         CHECK_POS_COORD("z");
222         pos.Z = lua_tonumber(L, -1);
223         CHECK_FLOAT_RANGE(pos.Z, "z")
224         lua_pop(L, 1);
225         return pos;
226 }
227
228 v3d read_v3d(lua_State *L, int index)
229 {
230         v3d pos;
231         CHECK_POS_TAB(index);
232         lua_getfield(L, index, "x");
233         pos.X = lua_tonumber(L, -1);
234         lua_pop(L, 1);
235         lua_getfield(L, index, "y");
236         pos.Y = lua_tonumber(L, -1);
237         lua_pop(L, 1);
238         lua_getfield(L, index, "z");
239         pos.Z = lua_tonumber(L, -1);
240         lua_pop(L, 1);
241         return pos;
242 }
243
244 v3d check_v3d(lua_State *L, int index)
245 {
246         v3d pos;
247         CHECK_POS_TAB(index);
248         lua_getfield(L, index, "x");
249         CHECK_POS_COORD("x");
250         pos.X = lua_tonumber(L, -1);
251         CHECK_FLOAT_RANGE(pos.X, "x")
252         lua_pop(L, 1);
253         lua_getfield(L, index, "y");
254         CHECK_POS_COORD("y");
255         pos.Y = lua_tonumber(L, -1);
256         CHECK_FLOAT_RANGE(pos.Y, "y")
257         lua_pop(L, 1);
258         lua_getfield(L, index, "z");
259         CHECK_POS_COORD("z");
260         pos.Z = lua_tonumber(L, -1);
261         CHECK_FLOAT_RANGE(pos.Z, "z")
262         lua_pop(L, 1);
263         return pos;
264 }
265
266 void push_ARGB8(lua_State *L, video::SColor color)
267 {
268         lua_newtable(L);
269         lua_pushnumber(L, color.getAlpha());
270         lua_setfield(L, -2, "a");
271         lua_pushnumber(L, color.getRed());
272         lua_setfield(L, -2, "r");
273         lua_pushnumber(L, color.getGreen());
274         lua_setfield(L, -2, "g");
275         lua_pushnumber(L, color.getBlue());
276         lua_setfield(L, -2, "b");
277 }
278
279 void pushFloatPos(lua_State *L, v3f p)
280 {
281         p /= BS;
282         push_v3f(L, p);
283 }
284
285 v3f checkFloatPos(lua_State *L, int index)
286 {
287         return check_v3f(L, index) * BS;
288 }
289
290 void push_v3s16(lua_State *L, v3s16 p)
291 {
292         lua_newtable(L);
293         lua_pushnumber(L, p.X);
294         lua_setfield(L, -2, "x");
295         lua_pushnumber(L, p.Y);
296         lua_setfield(L, -2, "y");
297         lua_pushnumber(L, p.Z);
298         lua_setfield(L, -2, "z");
299 }
300
301 v3s16 read_v3s16(lua_State *L, int index)
302 {
303         // Correct rounding at <0
304         v3d pf = read_v3d(L, index);
305         return doubleToInt(pf, 1.0);
306 }
307
308 v3s16 check_v3s16(lua_State *L, int index)
309 {
310         // Correct rounding at <0
311         v3d pf = check_v3d(L, index);
312         return doubleToInt(pf, 1.0);
313 }
314
315 bool read_color(lua_State *L, int index, video::SColor *color)
316 {
317         if (lua_istable(L, index)) {
318                 *color = read_ARGB8(L, index);
319         } else if (lua_isnumber(L, index)) {
320                 color->set(lua_tonumber(L, index));
321         } else if (lua_isstring(L, index)) {
322                 video::SColor parsed_color;
323                 if (!parseColorString(lua_tostring(L, index), parsed_color, true))
324                         return false;
325
326                 *color = parsed_color;
327         } else {
328                 return false;
329         }
330
331         return true;
332 }
333
334 video::SColor read_ARGB8(lua_State *L, int index)
335 {
336         video::SColor color(0);
337         CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
338         lua_getfield(L, index, "a");
339         color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
340         lua_pop(L, 1);
341         lua_getfield(L, index, "r");
342         color.setRed(lua_tonumber(L, -1));
343         lua_pop(L, 1);
344         lua_getfield(L, index, "g");
345         color.setGreen(lua_tonumber(L, -1));
346         lua_pop(L, 1);
347         lua_getfield(L, index, "b");
348         color.setBlue(lua_tonumber(L, -1));
349         lua_pop(L, 1);
350         return color;
351 }
352
353 aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
354 {
355         aabb3f box;
356         if(lua_istable(L, index)){
357                 lua_rawgeti(L, index, 1);
358                 box.MinEdge.X = lua_tonumber(L, -1) * scale;
359                 lua_pop(L, 1);
360                 lua_rawgeti(L, index, 2);
361                 box.MinEdge.Y = lua_tonumber(L, -1) * scale;
362                 lua_pop(L, 1);
363                 lua_rawgeti(L, index, 3);
364                 box.MinEdge.Z = lua_tonumber(L, -1) * scale;
365                 lua_pop(L, 1);
366                 lua_rawgeti(L, index, 4);
367                 box.MaxEdge.X = lua_tonumber(L, -1) * scale;
368                 lua_pop(L, 1);
369                 lua_rawgeti(L, index, 5);
370                 box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
371                 lua_pop(L, 1);
372                 lua_rawgeti(L, index, 6);
373                 box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
374                 lua_pop(L, 1);
375         }
376         box.repair();
377         return box;
378 }
379
380 void push_aabb3f(lua_State *L, aabb3f box)
381 {
382         lua_newtable(L);
383         lua_pushnumber(L, box.MinEdge.X);
384         lua_rawseti(L, -2, 1);
385         lua_pushnumber(L, box.MinEdge.Y);
386         lua_rawseti(L, -2, 2);
387         lua_pushnumber(L, box.MinEdge.Z);
388         lua_rawseti(L, -2, 3);
389         lua_pushnumber(L, box.MaxEdge.X);
390         lua_rawseti(L, -2, 4);
391         lua_pushnumber(L, box.MaxEdge.Y);
392         lua_rawseti(L, -2, 5);
393         lua_pushnumber(L, box.MaxEdge.Z);
394         lua_rawseti(L, -2, 6);
395 }
396
397 std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
398 {
399         std::vector<aabb3f> boxes;
400         if(lua_istable(L, index)){
401                 int n = lua_objlen(L, index);
402                 // Check if it's a single box or a list of boxes
403                 bool possibly_single_box = (n == 6);
404                 for(int i = 1; i <= n && possibly_single_box; i++){
405                         lua_rawgeti(L, index, i);
406                         if(!lua_isnumber(L, -1))
407                                 possibly_single_box = false;
408                         lua_pop(L, 1);
409                 }
410                 if(possibly_single_box){
411                         // Read a single box
412                         boxes.push_back(read_aabb3f(L, index, scale));
413                 } else {
414                         // Read a list of boxes
415                         for(int i = 1; i <= n; i++){
416                                 lua_rawgeti(L, index, i);
417                                 boxes.push_back(read_aabb3f(L, -1, scale));
418                                 lua_pop(L, 1);
419                         }
420                 }
421         }
422         return boxes;
423 }
424
425 size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
426 {
427         if (index < 0)
428                 index = lua_gettop(L) + 1 + index;
429
430         size_t num_strings = 0;
431
432         if (lua_istable(L, index)) {
433                 lua_pushnil(L);
434                 while (lua_next(L, index)) {
435                         if (lua_isstring(L, -1)) {
436                                 result->push_back(lua_tostring(L, -1));
437                                 num_strings++;
438                         }
439                         lua_pop(L, 1);
440                 }
441         } else if (lua_isstring(L, index)) {
442                 result->push_back(lua_tostring(L, index));
443                 num_strings++;
444         }
445
446         return num_strings;
447 }
448
449 /*
450         Table field getters
451 */
452
453 bool getstringfield(lua_State *L, int table,
454                 const char *fieldname, std::string &result)
455 {
456         lua_getfield(L, table, fieldname);
457         bool got = false;
458         if(lua_isstring(L, -1)){
459                 size_t len = 0;
460                 const char *ptr = lua_tolstring(L, -1, &len);
461                 if (ptr) {
462                         result.assign(ptr, len);
463                         got = true;
464                 }
465         }
466         lua_pop(L, 1);
467         return got;
468 }
469
470 bool getfloatfield(lua_State *L, int table,
471                 const char *fieldname, float &result)
472 {
473         lua_getfield(L, table, fieldname);
474         bool got = false;
475         if(lua_isnumber(L, -1)){
476                 result = lua_tonumber(L, -1);
477                 got = true;
478         }
479         lua_pop(L, 1);
480         return got;
481 }
482
483 bool getboolfield(lua_State *L, int table,
484                 const char *fieldname, bool &result)
485 {
486         lua_getfield(L, table, fieldname);
487         bool got = false;
488         if(lua_isboolean(L, -1)){
489                 result = lua_toboolean(L, -1);
490                 got = true;
491         }
492         lua_pop(L, 1);
493         return got;
494 }
495
496 size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
497                 std::vector<std::string> *result)
498 {
499         lua_getfield(L, table, fieldname);
500
501         size_t num_strings_read = read_stringlist(L, -1, result);
502
503         lua_pop(L, 1);
504         return num_strings_read;
505 }
506
507 std::string checkstringfield(lua_State *L, int table,
508                 const char *fieldname)
509 {
510         lua_getfield(L, table, fieldname);
511         CHECK_TYPE(-1, std::string("field \"") + fieldname + '"', LUA_TSTRING);
512         size_t len;
513         const char *s = lua_tolstring(L, -1, &len);
514         lua_pop(L, 1);
515         return std::string(s, len);
516 }
517
518 std::string getstringfield_default(lua_State *L, int table,
519                 const char *fieldname, const std::string &default_)
520 {
521         std::string result = default_;
522         getstringfield(L, table, fieldname, result);
523         return result;
524 }
525
526 int getintfield_default(lua_State *L, int table,
527                 const char *fieldname, int default_)
528 {
529         int result = default_;
530         getintfield(L, table, fieldname, result);
531         return result;
532 }
533
534 float getfloatfield_default(lua_State *L, int table,
535                 const char *fieldname, float default_)
536 {
537         float result = default_;
538         getfloatfield(L, table, fieldname, result);
539         return result;
540 }
541
542 bool getboolfield_default(lua_State *L, int table,
543                 const char *fieldname, bool default_)
544 {
545         bool result = default_;
546         getboolfield(L, table, fieldname, result);
547         return result;
548 }
549
550 v3s16 getv3s16field_default(lua_State *L, int table,
551                 const char *fieldname, v3s16 default_)
552 {
553         getv3intfield(L, table, fieldname, default_);
554         return default_;
555 }
556
557 void setstringfield(lua_State *L, int table,
558                 const char *fieldname, const char *value)
559 {
560         lua_pushstring(L, value);
561         if(table < 0)
562                 table -= 1;
563         lua_setfield(L, table, fieldname);
564 }
565
566 void setintfield(lua_State *L, int table,
567                 const char *fieldname, int value)
568 {
569         lua_pushinteger(L, value);
570         if(table < 0)
571                 table -= 1;
572         lua_setfield(L, table, fieldname);
573 }
574
575 void setfloatfield(lua_State *L, int table,
576                 const char *fieldname, float value)
577 {
578         lua_pushnumber(L, value);
579         if(table < 0)
580                 table -= 1;
581         lua_setfield(L, table, fieldname);
582 }
583
584 void setboolfield(lua_State *L, int table,
585                 const char *fieldname, bool value)
586 {
587         lua_pushboolean(L, value);
588         if(table < 0)
589                 table -= 1;
590         lua_setfield(L, table, fieldname);
591 }
592
593
594 ////
595 //// Array table slices
596 ////
597
598 size_t write_array_slice_float(
599         lua_State *L,
600         int table_index,
601         float *data,
602         v3u16 data_size,
603         v3u16 slice_offset,
604         v3u16 slice_size)
605 {
606         v3u16 pmin, pmax(data_size);
607
608         if (slice_offset.X > 0) {
609                 slice_offset.X--;
610                 pmin.X = slice_offset.X;
611                 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
612         }
613
614         if (slice_offset.Y > 0) {
615                 slice_offset.Y--;
616                 pmin.Y = slice_offset.Y;
617                 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
618         }
619
620         if (slice_offset.Z > 0) {
621                 slice_offset.Z--;
622                 pmin.Z = slice_offset.Z;
623                 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
624         }
625
626         const u32 ystride = data_size.X;
627         const u32 zstride = data_size.X * data_size.Y;
628
629         u32 elem_index = 1;
630         for (u32 z = pmin.Z; z != pmax.Z; z++)
631         for (u32 y = pmin.Y; y != pmax.Y; y++)
632         for (u32 x = pmin.X; x != pmax.X; x++) {
633                 u32 i = z * zstride + y * ystride + x;
634                 lua_pushnumber(L, data[i]);
635                 lua_rawseti(L, table_index, elem_index);
636                 elem_index++;
637         }
638
639         return elem_index - 1;
640 }
641
642
643 size_t write_array_slice_u16(
644         lua_State *L,
645         int table_index,
646         u16 *data,
647         v3u16 data_size,
648         v3u16 slice_offset,
649         v3u16 slice_size)
650 {
651         v3u16 pmin, pmax(data_size);
652
653         if (slice_offset.X > 0) {
654                 slice_offset.X--;
655                 pmin.X = slice_offset.X;
656                 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
657         }
658
659         if (slice_offset.Y > 0) {
660                 slice_offset.Y--;
661                 pmin.Y = slice_offset.Y;
662                 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
663         }
664
665         if (slice_offset.Z > 0) {
666                 slice_offset.Z--;
667                 pmin.Z = slice_offset.Z;
668                 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
669         }
670
671         const u32 ystride = data_size.X;
672         const u32 zstride = data_size.X * data_size.Y;
673
674         u32 elem_index = 1;
675         for (u32 z = pmin.Z; z != pmax.Z; z++)
676         for (u32 y = pmin.Y; y != pmax.Y; y++)
677         for (u32 x = pmin.X; x != pmax.X; x++) {
678                 u32 i = z * zstride + y * ystride + x;
679                 lua_pushinteger(L, data[i]);
680                 lua_rawseti(L, table_index, elem_index);
681                 elem_index++;
682         }
683
684         return elem_index - 1;
685 }