3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
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.
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.
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.
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"
34 #define CHECK_TYPE(index, name, type) { \
35 int t = lua_type(L, (index)); \
37 throw LuaError(std::string("Invalid ") + (name) + \
38 " (expected " + lua_typename(L, (type)) + \
39 " got " + lua_typename(L, t) + ")."); \
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()); \
51 #define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE)
54 void push_float_string(lua_State *L, float value)
60 lua_pushstring(L, str.c_str());
63 void push_v3f(lua_State *L, v3f p)
65 lua_createtable(L, 0, 3);
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");
74 void push_v2f(lua_State *L, v2f p)
76 lua_createtable(L, 0, 2);
77 lua_pushnumber(L, p.X);
78 lua_setfield(L, -2, "x");
79 lua_pushnumber(L, p.Y);
80 lua_setfield(L, -2, "y");
83 void push_v3_float_string(lua_State *L, v3f p)
85 lua_createtable(L, 0, 3);
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");
94 void push_v2_float_string(lua_State *L, v2f p)
96 lua_createtable(L, 0, 2);
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");
103 v2s16 read_v2s16(lua_State *L, int index)
106 CHECK_POS_TAB(index);
107 lua_getfield(L, index, "x");
108 p.X = lua_tonumber(L, -1);
110 lua_getfield(L, index, "y");
111 p.Y = lua_tonumber(L, -1);
116 void push_v2s16(lua_State *L, v2s16 p)
118 lua_createtable(L, 0, 2);
119 lua_pushinteger(L, p.X);
120 lua_setfield(L, -2, "x");
121 lua_pushinteger(L, p.Y);
122 lua_setfield(L, -2, "y");
125 void push_v2s32(lua_State *L, v2s32 p)
127 lua_createtable(L, 0, 2);
128 lua_pushinteger(L, p.X);
129 lua_setfield(L, -2, "x");
130 lua_pushinteger(L, p.Y);
131 lua_setfield(L, -2, "y");
134 v2s32 read_v2s32(lua_State *L, int index)
137 CHECK_POS_TAB(index);
138 lua_getfield(L, index, "x");
139 p.X = lua_tonumber(L, -1);
141 lua_getfield(L, index, "y");
142 p.Y = lua_tonumber(L, -1);
147 v2f read_v2f(lua_State *L, int index)
150 CHECK_POS_TAB(index);
151 lua_getfield(L, index, "x");
152 p.X = lua_tonumber(L, -1);
154 lua_getfield(L, index, "y");
155 p.Y = lua_tonumber(L, -1);
160 v2f check_v2f(lua_State *L, int index)
163 CHECK_POS_TAB(index);
164 lua_getfield(L, index, "x");
165 CHECK_POS_COORD("x");
166 p.X = lua_tonumber(L, -1);
168 lua_getfield(L, index, "y");
169 CHECK_POS_COORD("y");
170 p.Y = lua_tonumber(L, -1);
175 v3f read_v3f(lua_State *L, int index)
178 CHECK_POS_TAB(index);
179 lua_getfield(L, index, "x");
180 pos.X = lua_tonumber(L, -1);
182 lua_getfield(L, index, "y");
183 pos.Y = lua_tonumber(L, -1);
185 lua_getfield(L, index, "z");
186 pos.Z = lua_tonumber(L, -1);
191 v3f check_v3f(lua_State *L, int index)
194 CHECK_POS_TAB(index);
195 lua_getfield(L, index, "x");
196 CHECK_POS_COORD("x");
197 pos.X = lua_tonumber(L, -1);
198 CHECK_FLOAT_RANGE(pos.X, "x")
200 lua_getfield(L, index, "y");
201 CHECK_POS_COORD("y");
202 pos.Y = lua_tonumber(L, -1);
203 CHECK_FLOAT_RANGE(pos.Y, "y")
205 lua_getfield(L, index, "z");
206 CHECK_POS_COORD("z");
207 pos.Z = lua_tonumber(L, -1);
208 CHECK_FLOAT_RANGE(pos.Z, "z")
213 v3d read_v3d(lua_State *L, int index)
216 CHECK_POS_TAB(index);
217 lua_getfield(L, index, "x");
218 pos.X = lua_tonumber(L, -1);
220 lua_getfield(L, index, "y");
221 pos.Y = lua_tonumber(L, -1);
223 lua_getfield(L, index, "z");
224 pos.Z = lua_tonumber(L, -1);
229 v3d check_v3d(lua_State *L, int index)
232 CHECK_POS_TAB(index);
233 lua_getfield(L, index, "x");
234 CHECK_POS_COORD("x");
235 pos.X = lua_tonumber(L, -1);
236 CHECK_FLOAT_RANGE(pos.X, "x")
238 lua_getfield(L, index, "y");
239 CHECK_POS_COORD("y");
240 pos.Y = lua_tonumber(L, -1);
241 CHECK_FLOAT_RANGE(pos.Y, "y")
243 lua_getfield(L, index, "z");
244 CHECK_POS_COORD("z");
245 pos.Z = lua_tonumber(L, -1);
246 CHECK_FLOAT_RANGE(pos.Z, "z")
251 void push_ARGB8(lua_State *L, video::SColor color)
253 lua_createtable(L, 0, 4);
254 lua_pushinteger(L, color.getAlpha());
255 lua_setfield(L, -2, "a");
256 lua_pushinteger(L, color.getRed());
257 lua_setfield(L, -2, "r");
258 lua_pushinteger(L, color.getGreen());
259 lua_setfield(L, -2, "g");
260 lua_pushinteger(L, color.getBlue());
261 lua_setfield(L, -2, "b");
264 void pushFloatPos(lua_State *L, v3f p)
270 v3f checkFloatPos(lua_State *L, int index)
272 return check_v3f(L, index) * BS;
275 void push_v3s16(lua_State *L, v3s16 p)
277 lua_createtable(L, 0, 3);
278 lua_pushinteger(L, p.X);
279 lua_setfield(L, -2, "x");
280 lua_pushinteger(L, p.Y);
281 lua_setfield(L, -2, "y");
282 lua_pushinteger(L, p.Z);
283 lua_setfield(L, -2, "z");
286 v3s16 read_v3s16(lua_State *L, int index)
288 // Correct rounding at <0
289 v3d pf = read_v3d(L, index);
290 return doubleToInt(pf, 1.0);
293 v3s16 check_v3s16(lua_State *L, int index)
295 // Correct rounding at <0
296 v3d pf = check_v3d(L, index);
297 return doubleToInt(pf, 1.0);
300 bool read_color(lua_State *L, int index, video::SColor *color)
302 if (lua_istable(L, index)) {
303 *color = read_ARGB8(L, index);
304 } else if (lua_isnumber(L, index)) {
305 color->set(lua_tonumber(L, index));
306 } else if (lua_isstring(L, index)) {
307 video::SColor parsed_color;
308 if (!parseColorString(lua_tostring(L, index), parsed_color, true))
311 *color = parsed_color;
319 video::SColor read_ARGB8(lua_State *L, int index)
321 video::SColor color(0);
322 CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
323 lua_getfield(L, index, "a");
324 color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
326 lua_getfield(L, index, "r");
327 color.setRed(lua_tonumber(L, -1));
329 lua_getfield(L, index, "g");
330 color.setGreen(lua_tonumber(L, -1));
332 lua_getfield(L, index, "b");
333 color.setBlue(lua_tonumber(L, -1));
338 bool is_color_table(lua_State *L, int index)
340 // Check whole table in case of missing ColorSpec keys:
341 // This check does not remove the checked value from the stack.
342 // Only update the value if we know we have a valid ColorSpec key pair.
343 if (!lua_istable(L, index))
346 bool is_color_table = false;
347 lua_getfield(L, index, "r");
349 is_color_table = lua_isnumber(L, -1);
350 lua_getfield(L, index, "g");
352 is_color_table = lua_isnumber(L, -1);
353 lua_getfield(L, index, "b");
355 is_color_table = lua_isnumber(L, -1);
356 lua_pop(L, 3); // b, g, r values
357 return is_color_table;
360 aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
363 if(lua_istable(L, index)){
364 lua_rawgeti(L, index, 1);
365 box.MinEdge.X = lua_tonumber(L, -1) * scale;
367 lua_rawgeti(L, index, 2);
368 box.MinEdge.Y = lua_tonumber(L, -1) * scale;
370 lua_rawgeti(L, index, 3);
371 box.MinEdge.Z = lua_tonumber(L, -1) * scale;
373 lua_rawgeti(L, index, 4);
374 box.MaxEdge.X = lua_tonumber(L, -1) * scale;
376 lua_rawgeti(L, index, 5);
377 box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
379 lua_rawgeti(L, index, 6);
380 box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
387 void push_aabb3f(lua_State *L, aabb3f box)
389 lua_createtable(L, 6, 0);
390 lua_pushnumber(L, box.MinEdge.X);
391 lua_rawseti(L, -2, 1);
392 lua_pushnumber(L, box.MinEdge.Y);
393 lua_rawseti(L, -2, 2);
394 lua_pushnumber(L, box.MinEdge.Z);
395 lua_rawseti(L, -2, 3);
396 lua_pushnumber(L, box.MaxEdge.X);
397 lua_rawseti(L, -2, 4);
398 lua_pushnumber(L, box.MaxEdge.Y);
399 lua_rawseti(L, -2, 5);
400 lua_pushnumber(L, box.MaxEdge.Z);
401 lua_rawseti(L, -2, 6);
404 std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
406 std::vector<aabb3f> boxes;
407 if(lua_istable(L, index)){
408 int n = lua_objlen(L, index);
409 // Check if it's a single box or a list of boxes
410 bool possibly_single_box = (n == 6);
411 for(int i = 1; i <= n && possibly_single_box; i++){
412 lua_rawgeti(L, index, i);
413 if(!lua_isnumber(L, -1))
414 possibly_single_box = false;
417 if(possibly_single_box){
419 boxes.push_back(read_aabb3f(L, index, scale));
421 // Read a list of boxes
422 for(int i = 1; i <= n; i++){
423 lua_rawgeti(L, index, i);
424 boxes.push_back(read_aabb3f(L, -1, scale));
432 size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
435 index = lua_gettop(L) + 1 + index;
437 size_t num_strings = 0;
439 if (lua_istable(L, index)) {
441 while (lua_next(L, index)) {
442 if (lua_isstring(L, -1)) {
443 result->push_back(lua_tostring(L, -1));
448 } else if (lua_isstring(L, index)) {
449 result->push_back(lua_tostring(L, index));
460 #if defined(__MINGW32__) && !defined(__MINGW64__)
461 /* MinGW 32-bit somehow crashes in the std::set destructor when this
462 * variable is thread-local, so just don't do that. */
463 static std::set<u64> warned_msgs;
466 bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname)
468 #if !defined(__MINGW32__) || defined(__MINGW64__)
469 thread_local std::set<u64> warned_msgs;
472 int t = lua_type(L, index);
479 // Check coercion types
480 if (type == LUA_TNUMBER) {
481 if (lua_isnumber(L, index))
483 } else if (type == LUA_TSTRING) {
484 if (lua_isstring(L, index))
488 // Types mismatch. Log unique line.
489 std::string backtrace = std::string("Invalid field ") + fieldname +
490 " (expected " + lua_typename(L, type) +
491 " got " + lua_typename(L, t) + ").\n" + script_get_backtrace(L);
493 u64 hash = murmur_hash_64_ua(backtrace.data(), backtrace.length(), 0xBADBABE);
494 if (warned_msgs.find(hash) == warned_msgs.end()) {
495 errorstream << backtrace << std::endl;
496 warned_msgs.insert(hash);
502 bool getstringfield(lua_State *L, int table,
503 const char *fieldname, std::string &result)
505 lua_getfield(L, table, fieldname);
508 if (check_field_or_nil(L, -1, LUA_TSTRING, fieldname)) {
510 const char *ptr = lua_tolstring(L, -1, &len);
512 result.assign(ptr, len);
520 bool getfloatfield(lua_State *L, int table,
521 const char *fieldname, float &result)
523 lua_getfield(L, table, fieldname);
526 if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)) {
527 result = lua_tonumber(L, -1);
534 bool getboolfield(lua_State *L, int table,
535 const char *fieldname, bool &result)
537 lua_getfield(L, table, fieldname);
540 if (check_field_or_nil(L, -1, LUA_TBOOLEAN, fieldname)){
541 result = lua_toboolean(L, -1);
548 size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
549 std::vector<std::string> *result)
551 lua_getfield(L, table, fieldname);
553 size_t num_strings_read = read_stringlist(L, -1, result);
556 return num_strings_read;
559 std::string getstringfield_default(lua_State *L, int table,
560 const char *fieldname, const std::string &default_)
562 std::string result = default_;
563 getstringfield(L, table, fieldname, result);
567 int getintfield_default(lua_State *L, int table,
568 const char *fieldname, int default_)
570 int result = default_;
571 getintfield(L, table, fieldname, result);
575 float getfloatfield_default(lua_State *L, int table,
576 const char *fieldname, float default_)
578 float result = default_;
579 getfloatfield(L, table, fieldname, result);
583 bool getboolfield_default(lua_State *L, int table,
584 const char *fieldname, bool default_)
586 bool result = default_;
587 getboolfield(L, table, fieldname, result);
591 v3s16 getv3s16field_default(lua_State *L, int table,
592 const char *fieldname, v3s16 default_)
594 getv3intfield(L, table, fieldname, default_);
598 void setstringfield(lua_State *L, int table,
599 const char *fieldname, const std::string &value)
601 lua_pushlstring(L, value.c_str(), value.length());
604 lua_setfield(L, table, fieldname);
607 void setintfield(lua_State *L, int table,
608 const char *fieldname, int value)
610 lua_pushinteger(L, value);
613 lua_setfield(L, table, fieldname);
616 void setfloatfield(lua_State *L, int table,
617 const char *fieldname, float value)
619 lua_pushnumber(L, value);
622 lua_setfield(L, table, fieldname);
625 void setboolfield(lua_State *L, int table,
626 const char *fieldname, bool value)
628 lua_pushboolean(L, value);
631 lua_setfield(L, table, fieldname);
636 //// Array table slices
639 size_t write_array_slice_float(
647 v3u16 pmin, pmax(data_size);
649 if (slice_offset.X > 0) {
651 pmin.X = slice_offset.X;
652 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
655 if (slice_offset.Y > 0) {
657 pmin.Y = slice_offset.Y;
658 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
661 if (slice_offset.Z > 0) {
663 pmin.Z = slice_offset.Z;
664 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
667 const u32 ystride = data_size.X;
668 const u32 zstride = data_size.X * data_size.Y;
671 for (u32 z = pmin.Z; z != pmax.Z; z++)
672 for (u32 y = pmin.Y; y != pmax.Y; y++)
673 for (u32 x = pmin.X; x != pmax.X; x++) {
674 u32 i = z * zstride + y * ystride + x;
675 lua_pushnumber(L, data[i]);
676 lua_rawseti(L, table_index, elem_index);
680 return elem_index - 1;