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)
55 * A helper which sets (if available) the vector metatable from builtin as metatable
56 * for the table on top of the stack
58 static void set_vector_metatable(lua_State *L)
60 // get vector.metatable
61 lua_getglobal(L, "vector");
62 if (!lua_istable(L, -1)) {
63 // there is no global vector table
65 errorstream << "set_vector_metatable in c_converter.cpp: " <<
66 "missing global vector table" << std::endl;
69 lua_getfield(L, -1, "metatable");
71 lua_setmetatable(L, -3);
77 void push_float_string(lua_State *L, float value)
79 auto str = ftos(value);
80 lua_pushstring(L, str.c_str());
83 void push_v3f(lua_State *L, v3f p)
85 lua_createtable(L, 0, 3);
86 lua_pushnumber(L, p.X);
87 lua_setfield(L, -2, "x");
88 lua_pushnumber(L, p.Y);
89 lua_setfield(L, -2, "y");
90 lua_pushnumber(L, p.Z);
91 lua_setfield(L, -2, "z");
92 set_vector_metatable(L);
95 void push_v2f(lua_State *L, v2f p)
97 lua_createtable(L, 0, 2);
98 lua_pushnumber(L, p.X);
99 lua_setfield(L, -2, "x");
100 lua_pushnumber(L, p.Y);
101 lua_setfield(L, -2, "y");
104 void push_v3_float_string(lua_State *L, v3f p)
106 lua_createtable(L, 0, 3);
107 push_float_string(L, p.X);
108 lua_setfield(L, -2, "x");
109 push_float_string(L, p.Y);
110 lua_setfield(L, -2, "y");
111 push_float_string(L, p.Z);
112 lua_setfield(L, -2, "z");
115 void push_v2_float_string(lua_State *L, v2f p)
117 lua_createtable(L, 0, 2);
118 push_float_string(L, p.X);
119 lua_setfield(L, -2, "x");
120 push_float_string(L, p.Y);
121 lua_setfield(L, -2, "y");
124 v2s16 read_v2s16(lua_State *L, int index)
127 CHECK_POS_TAB(index);
128 lua_getfield(L, index, "x");
129 p.X = lua_tonumber(L, -1);
131 lua_getfield(L, index, "y");
132 p.Y = lua_tonumber(L, -1);
137 void push_v2s16(lua_State *L, v2s16 p)
139 lua_createtable(L, 0, 2);
140 lua_pushinteger(L, p.X);
141 lua_setfield(L, -2, "x");
142 lua_pushinteger(L, p.Y);
143 lua_setfield(L, -2, "y");
146 void push_v2s32(lua_State *L, v2s32 p)
148 lua_createtable(L, 0, 2);
149 lua_pushinteger(L, p.X);
150 lua_setfield(L, -2, "x");
151 lua_pushinteger(L, p.Y);
152 lua_setfield(L, -2, "y");
155 v2s32 read_v2s32(lua_State *L, int index)
158 CHECK_POS_TAB(index);
159 lua_getfield(L, index, "x");
160 p.X = lua_tonumber(L, -1);
162 lua_getfield(L, index, "y");
163 p.Y = lua_tonumber(L, -1);
168 v2f read_v2f(lua_State *L, int index)
171 CHECK_POS_TAB(index);
172 lua_getfield(L, index, "x");
173 p.X = lua_tonumber(L, -1);
175 lua_getfield(L, index, "y");
176 p.Y = lua_tonumber(L, -1);
181 v2f check_v2f(lua_State *L, int index)
184 CHECK_POS_TAB(index);
185 lua_getfield(L, index, "x");
186 CHECK_POS_COORD("x");
187 p.X = lua_tonumber(L, -1);
189 lua_getfield(L, index, "y");
190 CHECK_POS_COORD("y");
191 p.Y = lua_tonumber(L, -1);
196 v3f read_v3f(lua_State *L, int index)
199 CHECK_POS_TAB(index);
200 lua_getfield(L, index, "x");
201 pos.X = lua_tonumber(L, -1);
203 lua_getfield(L, index, "y");
204 pos.Y = lua_tonumber(L, -1);
206 lua_getfield(L, index, "z");
207 pos.Z = lua_tonumber(L, -1);
212 v3f check_v3f(lua_State *L, int index)
215 CHECK_POS_TAB(index);
216 lua_getfield(L, index, "x");
217 CHECK_POS_COORD("x");
218 pos.X = lua_tonumber(L, -1);
219 CHECK_FLOAT_RANGE(pos.X, "x")
221 lua_getfield(L, index, "y");
222 CHECK_POS_COORD("y");
223 pos.Y = lua_tonumber(L, -1);
224 CHECK_FLOAT_RANGE(pos.Y, "y")
226 lua_getfield(L, index, "z");
227 CHECK_POS_COORD("z");
228 pos.Z = lua_tonumber(L, -1);
229 CHECK_FLOAT_RANGE(pos.Z, "z")
234 v3d read_v3d(lua_State *L, int index)
237 CHECK_POS_TAB(index);
238 lua_getfield(L, index, "x");
239 pos.X = lua_tonumber(L, -1);
241 lua_getfield(L, index, "y");
242 pos.Y = lua_tonumber(L, -1);
244 lua_getfield(L, index, "z");
245 pos.Z = lua_tonumber(L, -1);
250 v3d check_v3d(lua_State *L, int index)
253 CHECK_POS_TAB(index);
254 lua_getfield(L, index, "x");
255 CHECK_POS_COORD("x");
256 pos.X = lua_tonumber(L, -1);
257 CHECK_FLOAT_RANGE(pos.X, "x")
259 lua_getfield(L, index, "y");
260 CHECK_POS_COORD("y");
261 pos.Y = lua_tonumber(L, -1);
262 CHECK_FLOAT_RANGE(pos.Y, "y")
264 lua_getfield(L, index, "z");
265 CHECK_POS_COORD("z");
266 pos.Z = lua_tonumber(L, -1);
267 CHECK_FLOAT_RANGE(pos.Z, "z")
272 void push_ARGB8(lua_State *L, video::SColor color)
274 lua_createtable(L, 0, 4);
275 lua_pushinteger(L, color.getAlpha());
276 lua_setfield(L, -2, "a");
277 lua_pushinteger(L, color.getRed());
278 lua_setfield(L, -2, "r");
279 lua_pushinteger(L, color.getGreen());
280 lua_setfield(L, -2, "g");
281 lua_pushinteger(L, color.getBlue());
282 lua_setfield(L, -2, "b");
285 void pushFloatPos(lua_State *L, v3f p)
291 v3f checkFloatPos(lua_State *L, int index)
293 return check_v3f(L, index) * BS;
296 void push_v3s16(lua_State *L, v3s16 p)
298 lua_createtable(L, 0, 3);
299 lua_pushinteger(L, p.X);
300 lua_setfield(L, -2, "x");
301 lua_pushinteger(L, p.Y);
302 lua_setfield(L, -2, "y");
303 lua_pushinteger(L, p.Z);
304 lua_setfield(L, -2, "z");
305 set_vector_metatable(L);
308 v3s16 read_v3s16(lua_State *L, int index)
310 // Correct rounding at <0
311 v3d pf = read_v3d(L, index);
312 return doubleToInt(pf, 1.0);
315 v3s16 check_v3s16(lua_State *L, int index)
317 // Correct rounding at <0
318 v3d pf = check_v3d(L, index);
319 return doubleToInt(pf, 1.0);
322 bool read_color(lua_State *L, int index, video::SColor *color)
324 if (lua_istable(L, index)) {
325 *color = read_ARGB8(L, index);
326 } else if (lua_isnumber(L, index)) {
327 color->set(lua_tonumber(L, index));
328 } else if (lua_isstring(L, index)) {
329 video::SColor parsed_color;
330 if (!parseColorString(lua_tostring(L, index), parsed_color, true))
333 *color = parsed_color;
341 video::SColor read_ARGB8(lua_State *L, int index)
343 video::SColor color(0);
344 CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
345 lua_getfield(L, index, "a");
346 color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
348 lua_getfield(L, index, "r");
349 color.setRed(lua_tonumber(L, -1));
351 lua_getfield(L, index, "g");
352 color.setGreen(lua_tonumber(L, -1));
354 lua_getfield(L, index, "b");
355 color.setBlue(lua_tonumber(L, -1));
360 bool is_color_table(lua_State *L, int index)
362 // Check whole table in case of missing ColorSpec keys:
363 // This check does not remove the checked value from the stack.
364 // Only update the value if we know we have a valid ColorSpec key pair.
365 if (!lua_istable(L, index))
368 bool is_color_table = false;
369 lua_getfield(L, index, "r");
371 is_color_table = lua_isnumber(L, -1);
372 lua_getfield(L, index, "g");
374 is_color_table = lua_isnumber(L, -1);
375 lua_getfield(L, index, "b");
377 is_color_table = lua_isnumber(L, -1);
378 lua_pop(L, 3); // b, g, r values
379 return is_color_table;
382 aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
385 if(lua_istable(L, index)){
386 lua_rawgeti(L, index, 1);
387 box.MinEdge.X = lua_tonumber(L, -1) * scale;
389 lua_rawgeti(L, index, 2);
390 box.MinEdge.Y = lua_tonumber(L, -1) * scale;
392 lua_rawgeti(L, index, 3);
393 box.MinEdge.Z = lua_tonumber(L, -1) * scale;
395 lua_rawgeti(L, index, 4);
396 box.MaxEdge.X = lua_tonumber(L, -1) * scale;
398 lua_rawgeti(L, index, 5);
399 box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
401 lua_rawgeti(L, index, 6);
402 box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
409 void push_aabb3f(lua_State *L, aabb3f box)
411 lua_createtable(L, 6, 0);
412 lua_pushnumber(L, box.MinEdge.X);
413 lua_rawseti(L, -2, 1);
414 lua_pushnumber(L, box.MinEdge.Y);
415 lua_rawseti(L, -2, 2);
416 lua_pushnumber(L, box.MinEdge.Z);
417 lua_rawseti(L, -2, 3);
418 lua_pushnumber(L, box.MaxEdge.X);
419 lua_rawseti(L, -2, 4);
420 lua_pushnumber(L, box.MaxEdge.Y);
421 lua_rawseti(L, -2, 5);
422 lua_pushnumber(L, box.MaxEdge.Z);
423 lua_rawseti(L, -2, 6);
426 std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
428 std::vector<aabb3f> boxes;
429 if(lua_istable(L, index)){
430 int n = lua_objlen(L, index);
431 // Check if it's a single box or a list of boxes
432 bool possibly_single_box = (n == 6);
433 for(int i = 1; i <= n && possibly_single_box; i++){
434 lua_rawgeti(L, index, i);
435 if(!lua_isnumber(L, -1))
436 possibly_single_box = false;
439 if(possibly_single_box){
441 boxes.push_back(read_aabb3f(L, index, scale));
443 // Read a list of boxes
444 for(int i = 1; i <= n; i++){
445 lua_rawgeti(L, index, i);
446 boxes.push_back(read_aabb3f(L, -1, scale));
454 size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
457 index = lua_gettop(L) + 1 + index;
459 size_t num_strings = 0;
461 if (lua_istable(L, index)) {
463 while (lua_next(L, index)) {
464 if (lua_isstring(L, -1)) {
465 result->push_back(lua_tostring(L, -1));
470 } else if (lua_isstring(L, index)) {
471 result->push_back(lua_tostring(L, index));
482 #if defined(__MINGW32__) && !defined(__MINGW64__)
483 /* MinGW 32-bit somehow crashes in the std::set destructor when this
484 * variable is thread-local, so just don't do that. */
485 static std::set<u64> warned_msgs;
488 bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname)
490 #if !defined(__MINGW32__) || defined(__MINGW64__)
491 thread_local std::set<u64> warned_msgs;
494 int t = lua_type(L, index);
501 // Check coercion types
502 if (type == LUA_TNUMBER) {
503 if (lua_isnumber(L, index))
505 } else if (type == LUA_TSTRING) {
506 if (lua_isstring(L, index))
510 // Types mismatch. Log unique line.
511 std::string backtrace = std::string("Invalid field ") + fieldname +
512 " (expected " + lua_typename(L, type) +
513 " got " + lua_typename(L, t) + ").\n" + script_get_backtrace(L);
515 u64 hash = murmur_hash_64_ua(backtrace.data(), backtrace.length(), 0xBADBABE);
516 if (warned_msgs.find(hash) == warned_msgs.end()) {
517 errorstream << backtrace << std::endl;
518 warned_msgs.insert(hash);
524 bool getstringfield(lua_State *L, int table,
525 const char *fieldname, std::string &result)
527 lua_getfield(L, table, fieldname);
530 if (check_field_or_nil(L, -1, LUA_TSTRING, fieldname)) {
532 const char *ptr = lua_tolstring(L, -1, &len);
534 result.assign(ptr, len);
542 bool getfloatfield(lua_State *L, int table,
543 const char *fieldname, float &result)
545 lua_getfield(L, table, fieldname);
548 if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)) {
549 result = lua_tonumber(L, -1);
556 bool getboolfield(lua_State *L, int table,
557 const char *fieldname, bool &result)
559 lua_getfield(L, table, fieldname);
562 if (check_field_or_nil(L, -1, LUA_TBOOLEAN, fieldname)){
563 result = lua_toboolean(L, -1);
570 size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
571 std::vector<std::string> *result)
573 lua_getfield(L, table, fieldname);
575 size_t num_strings_read = read_stringlist(L, -1, result);
578 return num_strings_read;
581 std::string getstringfield_default(lua_State *L, int table,
582 const char *fieldname, const std::string &default_)
584 std::string result = default_;
585 getstringfield(L, table, fieldname, result);
589 int getintfield_default(lua_State *L, int table,
590 const char *fieldname, int default_)
592 int result = default_;
593 getintfield(L, table, fieldname, result);
597 float getfloatfield_default(lua_State *L, int table,
598 const char *fieldname, float default_)
600 float result = default_;
601 getfloatfield(L, table, fieldname, result);
605 bool getboolfield_default(lua_State *L, int table,
606 const char *fieldname, bool default_)
608 bool result = default_;
609 getboolfield(L, table, fieldname, result);
613 v3s16 getv3s16field_default(lua_State *L, int table,
614 const char *fieldname, v3s16 default_)
616 getv3intfield(L, table, fieldname, default_);
620 void setstringfield(lua_State *L, int table,
621 const char *fieldname, const std::string &value)
623 lua_pushlstring(L, value.c_str(), value.length());
626 lua_setfield(L, table, fieldname);
629 void setintfield(lua_State *L, int table,
630 const char *fieldname, int value)
632 lua_pushinteger(L, value);
635 lua_setfield(L, table, fieldname);
638 void setfloatfield(lua_State *L, int table,
639 const char *fieldname, float value)
641 lua_pushnumber(L, value);
644 lua_setfield(L, table, fieldname);
647 void setboolfield(lua_State *L, int table,
648 const char *fieldname, bool value)
650 lua_pushboolean(L, value);
653 lua_setfield(L, table, fieldname);
658 //// Array table slices
661 size_t write_array_slice_float(
669 v3u16 pmin, pmax(data_size);
671 if (slice_offset.X > 0) {
673 pmin.X = slice_offset.X;
674 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
677 if (slice_offset.Y > 0) {
679 pmin.Y = slice_offset.Y;
680 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
683 if (slice_offset.Z > 0) {
685 pmin.Z = slice_offset.Z;
686 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
689 const u32 ystride = data_size.X;
690 const u32 zstride = data_size.X * data_size.Y;
693 for (u32 z = pmin.Z; z != pmax.Z; z++)
694 for (u32 y = pmin.Y; y != pmax.Y; y++)
695 for (u32 x = pmin.X; x != pmax.X; x++) {
696 u32 i = z * zstride + y * ystride + x;
697 lua_pushnumber(L, data[i]);
698 lua_rawseti(L, table_index, elem_index);
702 return elem_index - 1;