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"
35 #define CHECK_TYPE(index, name, type) do { \
36 int t = lua_type(L, (index)); \
38 throw LuaError(std::string("Invalid ") + (name) + \
39 " (expected " + lua_typename(L, (type)) + \
40 " got " + lua_typename(L, t) + ")."); \
44 #define CHECK_FLOAT(value, name) do {\
45 if (std::isnan(value) || std::isinf(value)) { \
46 throw LuaError("Invalid float value for '" name \
47 "' (NaN or infinity)"); \
51 #define CHECK_POS_COORD(index, name) CHECK_TYPE(index, "vector coordinate " name, LUA_TNUMBER)
52 #define CHECK_POS_TAB(index) CHECK_TYPE(index, "vector", LUA_TTABLE)
56 * A helper which calls CUSTOM_RIDX_READ_VECTOR with the argument at the given index
58 static void read_v3_aux(lua_State *L, int index)
60 lua_pushvalue(L, index);
61 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_READ_VECTOR);
66 // Retrieve an integer vector where all components are optional
68 static bool getv3intfield(lua_State *L, int index,
69 const char *fieldname, T &result)
71 lua_getfield(L, index, fieldname);
73 if (lua_istable(L, -1)) {
74 got |= getintfield(L, -1, "x", result.X);
75 got |= getintfield(L, -1, "y", result.Y);
76 got |= getintfield(L, -1, "z", result.Z);
82 void push_v3f(lua_State *L, v3f p)
84 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_VECTOR);
85 lua_pushnumber(L, p.X);
86 lua_pushnumber(L, p.Y);
87 lua_pushnumber(L, p.Z);
91 void push_v2f(lua_State *L, v2f p)
93 lua_createtable(L, 0, 2);
94 lua_pushnumber(L, p.X);
95 lua_setfield(L, -2, "x");
96 lua_pushnumber(L, p.Y);
97 lua_setfield(L, -2, "y");
100 v2s16 read_v2s16(lua_State *L, int index)
103 CHECK_POS_TAB(index);
104 lua_getfield(L, index, "x");
105 p.X = lua_tonumber(L, -1);
107 lua_getfield(L, index, "y");
108 p.Y = lua_tonumber(L, -1);
113 void push_v2s16(lua_State *L, v2s16 p)
115 lua_createtable(L, 0, 2);
116 lua_pushinteger(L, p.X);
117 lua_setfield(L, -2, "x");
118 lua_pushinteger(L, p.Y);
119 lua_setfield(L, -2, "y");
122 void push_v2s32(lua_State *L, v2s32 p)
124 lua_createtable(L, 0, 2);
125 lua_pushinteger(L, p.X);
126 lua_setfield(L, -2, "x");
127 lua_pushinteger(L, p.Y);
128 lua_setfield(L, -2, "y");
131 void push_v2u32(lua_State *L, v2u32 p)
133 lua_createtable(L, 0, 2);
134 lua_pushinteger(L, p.X);
135 lua_setfield(L, -2, "x");
136 lua_pushinteger(L, p.Y);
137 lua_setfield(L, -2, "y");
140 v2s32 read_v2s32(lua_State *L, int index)
143 CHECK_POS_TAB(index);
144 lua_getfield(L, index, "x");
145 p.X = lua_tonumber(L, -1);
147 lua_getfield(L, index, "y");
148 p.Y = lua_tonumber(L, -1);
153 v2f read_v2f(lua_State *L, int index)
156 CHECK_POS_TAB(index);
157 lua_getfield(L, index, "x");
158 p.X = lua_tonumber(L, -1);
160 lua_getfield(L, index, "y");
161 p.Y = lua_tonumber(L, -1);
166 v2f check_v2f(lua_State *L, int index)
169 CHECK_POS_TAB(index);
170 lua_getfield(L, index, "x");
171 CHECK_POS_COORD(-1, "x");
172 p.X = lua_tonumber(L, -1);
173 CHECK_FLOAT(p.X, "x");
175 lua_getfield(L, index, "y");
176 CHECK_POS_COORD(-1, "y");
177 p.Y = lua_tonumber(L, -1);
178 CHECK_FLOAT(p.Y, "y");
183 v3f read_v3f(lua_State *L, int index)
185 read_v3_aux(L, index);
186 float x = lua_tonumber(L, -3);
187 float y = lua_tonumber(L, -2);
188 float z = lua_tonumber(L, -1);
193 v3f check_v3f(lua_State *L, int index)
195 read_v3_aux(L, index);
196 CHECK_POS_COORD(-3, "x");
197 CHECK_POS_COORD(-2, "y");
198 CHECK_POS_COORD(-1, "z");
199 float x = lua_tonumber(L, -3);
200 float y = lua_tonumber(L, -2);
201 float z = lua_tonumber(L, -1);
206 v3d read_v3d(lua_State *L, int index)
208 read_v3_aux(L, index);
209 double x = lua_tonumber(L, -3);
210 double y = lua_tonumber(L, -2);
211 double z = lua_tonumber(L, -1);
216 v3d check_v3d(lua_State *L, int index)
218 read_v3_aux(L, index);
219 CHECK_POS_COORD(-3, "x");
220 CHECK_POS_COORD(-2, "y");
221 CHECK_POS_COORD(-1, "z");
222 double x = lua_tonumber(L, -3);
223 double y = lua_tonumber(L, -2);
224 double z = lua_tonumber(L, -1);
229 void push_ARGB8(lua_State *L, video::SColor color)
231 lua_createtable(L, 0, 4);
232 lua_pushinteger(L, color.getAlpha());
233 lua_setfield(L, -2, "a");
234 lua_pushinteger(L, color.getRed());
235 lua_setfield(L, -2, "r");
236 lua_pushinteger(L, color.getGreen());
237 lua_setfield(L, -2, "g");
238 lua_pushinteger(L, color.getBlue());
239 lua_setfield(L, -2, "b");
242 void pushFloatPos(lua_State *L, v3f p)
248 v3f checkFloatPos(lua_State *L, int index)
250 return check_v3f(L, index) * BS;
253 void push_v3s16(lua_State *L, v3s16 p)
255 lua_rawgeti(L, LUA_REGISTRYINDEX, CUSTOM_RIDX_PUSH_VECTOR);
256 lua_pushinteger(L, p.X);
257 lua_pushinteger(L, p.Y);
258 lua_pushinteger(L, p.Z);
262 v3s16 read_v3s16(lua_State *L, int index)
264 // Correct rounding at <0
265 v3d pf = read_v3d(L, index);
266 return doubleToInt(pf, 1.0);
269 v3s16 check_v3s16(lua_State *L, int index)
271 // Correct rounding at <0
272 v3d pf = check_v3d(L, index);
273 return doubleToInt(pf, 1.0);
276 bool read_color(lua_State *L, int index, video::SColor *color)
278 if (lua_istable(L, index)) {
279 *color = read_ARGB8(L, index);
280 } else if (lua_isnumber(L, index)) {
281 color->set(lua_tonumber(L, index));
282 } else if (lua_isstring(L, index)) {
283 video::SColor parsed_color;
284 if (!parseColorString(lua_tostring(L, index), parsed_color, true))
287 *color = parsed_color;
295 video::SColor read_ARGB8(lua_State *L, int index)
297 video::SColor color(0);
298 CHECK_TYPE(index, "ARGB color", LUA_TTABLE);
299 lua_getfield(L, index, "a");
300 color.setAlpha(lua_isnumber(L, -1) ? lua_tonumber(L, -1) : 0xFF);
302 lua_getfield(L, index, "r");
303 color.setRed(lua_tonumber(L, -1));
305 lua_getfield(L, index, "g");
306 color.setGreen(lua_tonumber(L, -1));
308 lua_getfield(L, index, "b");
309 color.setBlue(lua_tonumber(L, -1));
314 bool is_color_table(lua_State *L, int index)
316 // Check whole table in case of missing ColorSpec keys:
317 // This check does not remove the checked value from the stack.
318 // Only update the value if we know we have a valid ColorSpec key pair.
319 if (!lua_istable(L, index))
322 bool is_color_table = false;
323 lua_getfield(L, index, "r");
325 is_color_table = lua_isnumber(L, -1);
326 lua_getfield(L, index, "g");
328 is_color_table = lua_isnumber(L, -1);
329 lua_getfield(L, index, "b");
331 is_color_table = lua_isnumber(L, -1);
332 lua_pop(L, 3); // b, g, r values
333 return is_color_table;
336 aabb3f read_aabb3f(lua_State *L, int index, f32 scale)
339 if(lua_istable(L, index)){
340 lua_rawgeti(L, index, 1);
341 box.MinEdge.X = lua_tonumber(L, -1) * scale;
343 lua_rawgeti(L, index, 2);
344 box.MinEdge.Y = lua_tonumber(L, -1) * scale;
346 lua_rawgeti(L, index, 3);
347 box.MinEdge.Z = lua_tonumber(L, -1) * scale;
349 lua_rawgeti(L, index, 4);
350 box.MaxEdge.X = lua_tonumber(L, -1) * scale;
352 lua_rawgeti(L, index, 5);
353 box.MaxEdge.Y = lua_tonumber(L, -1) * scale;
355 lua_rawgeti(L, index, 6);
356 box.MaxEdge.Z = lua_tonumber(L, -1) * scale;
363 void push_aabb3f(lua_State *L, aabb3f box)
365 lua_createtable(L, 6, 0);
366 lua_pushnumber(L, box.MinEdge.X);
367 lua_rawseti(L, -2, 1);
368 lua_pushnumber(L, box.MinEdge.Y);
369 lua_rawseti(L, -2, 2);
370 lua_pushnumber(L, box.MinEdge.Z);
371 lua_rawseti(L, -2, 3);
372 lua_pushnumber(L, box.MaxEdge.X);
373 lua_rawseti(L, -2, 4);
374 lua_pushnumber(L, box.MaxEdge.Y);
375 lua_rawseti(L, -2, 5);
376 lua_pushnumber(L, box.MaxEdge.Z);
377 lua_rawseti(L, -2, 6);
380 std::vector<aabb3f> read_aabb3f_vector(lua_State *L, int index, f32 scale)
382 std::vector<aabb3f> boxes;
383 if(lua_istable(L, index)){
384 int n = lua_objlen(L, index);
385 // Check if it's a single box or a list of boxes
386 bool possibly_single_box = (n == 6);
387 for(int i = 1; i <= n && possibly_single_box; i++){
388 lua_rawgeti(L, index, i);
389 if(!lua_isnumber(L, -1))
390 possibly_single_box = false;
393 if(possibly_single_box){
395 boxes.push_back(read_aabb3f(L, index, scale));
397 // Read a list of boxes
398 for(int i = 1; i <= n; i++){
399 lua_rawgeti(L, index, i);
400 boxes.push_back(read_aabb3f(L, -1, scale));
408 size_t read_stringlist(lua_State *L, int index, std::vector<std::string> *result)
411 index = lua_gettop(L) + 1 + index;
413 size_t num_strings = 0;
415 if (lua_istable(L, index)) {
417 while (lua_next(L, index)) {
418 if (lua_isstring(L, -1)) {
419 result->push_back(lua_tostring(L, -1));
424 } else if (lua_isstring(L, index)) {
425 result->push_back(lua_tostring(L, index));
436 bool check_field_or_nil(lua_State *L, int index, int type, const char *fieldname)
438 thread_local std::set<u64> warned_msgs;
440 int t = lua_type(L, index);
447 // Check coercion types
448 if (type == LUA_TNUMBER) {
449 if (lua_isnumber(L, index))
451 } else if (type == LUA_TSTRING) {
452 if (lua_isstring(L, index))
456 // Types mismatch. Log unique line.
457 std::string backtrace = std::string("Invalid field ") + fieldname +
458 " (expected " + lua_typename(L, type) +
459 " got " + lua_typename(L, t) + ").\n" + script_get_backtrace(L);
461 u64 hash = murmur_hash_64_ua(backtrace.data(), backtrace.length(), 0xBADBABE);
462 if (warned_msgs.find(hash) == warned_msgs.end()) {
463 errorstream << backtrace << std::endl;
464 warned_msgs.insert(hash);
470 bool getstringfield(lua_State *L, int table,
471 const char *fieldname, std::string &result)
473 lua_getfield(L, table, fieldname);
476 if (check_field_or_nil(L, -1, LUA_TSTRING, fieldname)) {
478 const char *ptr = lua_tolstring(L, -1, &len);
480 result.assign(ptr, len);
488 bool getfloatfield(lua_State *L, int table,
489 const char *fieldname, float &result)
491 lua_getfield(L, table, fieldname);
494 if (check_field_or_nil(L, -1, LUA_TNUMBER, fieldname)) {
495 result = lua_tonumber(L, -1);
502 bool getboolfield(lua_State *L, int table,
503 const char *fieldname, bool &result)
505 lua_getfield(L, table, fieldname);
508 if (check_field_or_nil(L, -1, LUA_TBOOLEAN, fieldname)){
509 result = lua_toboolean(L, -1);
516 size_t getstringlistfield(lua_State *L, int table, const char *fieldname,
517 std::vector<std::string> *result)
519 lua_getfield(L, table, fieldname);
521 size_t num_strings_read = read_stringlist(L, -1, result);
524 return num_strings_read;
527 std::string getstringfield_default(lua_State *L, int table,
528 const char *fieldname, const std::string &default_)
530 std::string result = default_;
531 getstringfield(L, table, fieldname, result);
535 int getintfield_default(lua_State *L, int table,
536 const char *fieldname, int default_)
538 int result = default_;
539 getintfield(L, table, fieldname, result);
543 float getfloatfield_default(lua_State *L, int table,
544 const char *fieldname, float default_)
546 float result = default_;
547 getfloatfield(L, table, fieldname, result);
551 bool getboolfield_default(lua_State *L, int table,
552 const char *fieldname, bool default_)
554 bool result = default_;
555 getboolfield(L, table, fieldname, result);
559 v3s16 getv3s16field_default(lua_State *L, int table,
560 const char *fieldname, v3s16 default_)
562 getv3intfield(L, table, fieldname, default_);
566 void setstringfield(lua_State *L, int table,
567 const char *fieldname, const std::string &value)
569 lua_pushlstring(L, value.c_str(), value.length());
572 lua_setfield(L, table, fieldname);
575 void setintfield(lua_State *L, int table,
576 const char *fieldname, int value)
578 lua_pushinteger(L, value);
581 lua_setfield(L, table, fieldname);
584 void setfloatfield(lua_State *L, int table,
585 const char *fieldname, float value)
587 lua_pushnumber(L, value);
590 lua_setfield(L, table, fieldname);
593 void setboolfield(lua_State *L, int table,
594 const char *fieldname, bool value)
596 lua_pushboolean(L, value);
599 lua_setfield(L, table, fieldname);
604 //// Array table slices
607 size_t write_array_slice_float(
615 v3u16 pmin, pmax(data_size);
617 if (slice_offset.X > 0) {
619 pmin.X = slice_offset.X;
620 pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X);
623 if (slice_offset.Y > 0) {
625 pmin.Y = slice_offset.Y;
626 pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y);
629 if (slice_offset.Z > 0) {
631 pmin.Z = slice_offset.Z;
632 pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z);
635 const u32 ystride = data_size.X;
636 const u32 zstride = data_size.X * data_size.Y;
639 for (u32 z = pmin.Z; z != pmax.Z; z++)
640 for (u32 y = pmin.Y; y != pmax.Y; y++)
641 for (u32 x = pmin.X; x != pmax.X; x++) {
642 u32 i = z * zstride + y * ystride + x;
643 lua_pushnumber(L, data[i]);
644 lua_rawseti(L, table_index, elem_index);
648 return elem_index - 1;