/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ extern "C" { #include "lua.h" #include "lauxlib.h" } #include "util/numeric.h" #include "util/serialize.h" #include "util/string.h" #include "common/c_converter.h" #include "common/c_internal.h" #include "constants.h" #define CHECK_TYPE(index, name, type) { \ int t = lua_type(L, (index)); \ if (t != (type)) { \ std::string traceback = script_get_backtrace(L); \ throw LuaError(std::string("Invalid ") + (name) + \ " (expected " + lua_typename(L, (type)) + \ " got " + lua_typename(L, t) + ").\n" + traceback); \ } \ } #define CHECK_POS_COORD(name) CHECK_TYPE(-1, "position coordinate '" name "'", LUA_TNUMBER) #define CHECK_FLOAT_RANGE(value, name) \ if (value < F1000_MIN || value > F1000_MAX) { \ std::ostringstream error_text; \ error_text << "Invalid float vector dimension range '" name "' " << \ "(expected " << F1000_MIN << " < " name " < " << F1000_MAX << \ " got " << value << ")." << std::endl; \ throw LuaError(error_text.str()); \ } #define CHECK_POS_TAB(index) CHECK_TYPE(index, "position", LUA_TTABLE) void push_float_string(lua_State *L, float value) { std::stringstream ss; std::string str; ss << value; str = ss.str(); lua_pushstring(L, str.c_str()); } void push_v3f(lua_State *L, v3f p) { lua_newtable(L); lua_pushnumber(L, p.X); lua_setfield(L, -2, "x"); lua_pushnumber(L, p.Y); lua_setfield(L, -2, "y"); lua_pushnumber(L, p.Z); lua_setfield(L, -2, "z"); } void push_v2f(lua_State *L, v2f p) { lua_newtable(L); lua_pushnumber(L, p.X); lua_setfield(L, -2, "x"); lua_pushnumber(L, p.Y); lua_setfield(L, -2, "y"); } void push_v3_float_string(lua_State *L, v3f p) { lua_newtable(L); push_float_string(L, p.X); lua_setfield(L, -2, "x"); push_float_string(L, p.Y); lua_setfield(L, -2, "y"); push_float_string(L, p.Z); lua_setfield(L, -2, "z"); } void push_v2_float_string(lua_State *L, v2f p) { lua_newtable(L); push_float_string(L, p.X); lua_setfield(L, -2, "x"); push_float_string(L, p.Y); lua_setfield(L, -2, "y"); } v2s16 read_v2s16(lua_State *L, int index) { v2s16 p; CHECK_POS_TAB(index); lua_getfield(L, index, "x"); p.X = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "y"); p.Y = lua_tonumber(L, -1); lua_pop(L, 1); return p; } void push_v2s16(lua_State *L, v2s16 p) { lua_newtable(L); lua_pushnumber(L, p.X); lua_setfield(L, -2, "x"); lua_pushnumber(L, p.Y); lua_setfield(L, -2, "y"); } void push_v2s32(lua_State *L, v2s32 p) { lua_newtable(L); lua_pushnumber(L, p.X); lua_setfield(L, -2, "x"); lua_pushnumber(L, p.Y); lua_setfield(L, -2, "y"); } v2s32 read_v2s32(lua_State *L, int index) { v2s32 p; CHECK_POS_TAB(index); lua_getfield(L, index, "x"); p.X = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "y"); p.Y = lua_tonumber(L, -1); lua_pop(L, 1); return p; } v2f read_v2f(lua_State *L, int index) { v2f p; CHECK_POS_TAB(index); lua_getfield(L, index, "x"); p.X = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "y"); p.Y = lua_tonumber(L, -1); lua_pop(L, 1); return p; } v2f check_v2f(lua_State *L, int index) { v2f p; CHECK_POS_TAB(index); lua_getfield(L, index, "x"); CHECK_POS_COORD("x"); p.X = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "y"); CHECK_POS_COORD("y"); p.Y = lua_tonumber(L, -1); lua_pop(L, 1); return p; } v3f read_v3f(lua_State *L, int index) { v3f pos; CHECK_POS_TAB(index); lua_getfield(L, index, "x"); pos.X = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "y"); pos.Y = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "z"); pos.Z = lua_tonumber(L, -1); lua_pop(L, 1); return pos; } v3f check_v3f(lua_State *L, int index) { v3f pos; CHECK_POS_TAB(index); lua_getfield(L, index, "x"); CHECK_POS_COORD("x"); pos.X = lua_tonumber(L, -1); CHECK_FLOAT_RANGE(pos.X, "x") lua_pop(L, 1); lua_getfield(L, index, "y"); CHECK_POS_COORD("y"); pos.Y = lua_tonumber(L, -1); CHECK_FLOAT_RANGE(pos.Y, "y") lua_pop(L, 1); lua_getfield(L, index, "z"); CHECK_POS_COORD("z"); pos.Z = lua_tonumber(L, -1); CHECK_FLOAT_RANGE(pos.Z, "z") lua_pop(L, 1); return pos; } v3d read_v3d(lua_State *L, int index) { v3d pos; CHECK_POS_TAB(index); lua_getfield(L, index, "x"); pos.X = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "y"); pos.Y = lua_tonumber(L, -1); lua_pop(L, 1); lua_getfield(L, index, "z"); pos.Z = lua_tonumber(L, -1); lua_pop(L/* Minetest Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /******************************************************************************/ /******************************************************************************/ /* WARNING!!!! do NOT add this header in any include file or any code file */ /* not being a modapi file!!!!!!!! */ /******************************************************************************/ /******************************************************************************/ #ifndef S_INTERNAL_H_ #define S_INTERNAL_H_ #include "common/c_internal.h" #include "cpp_api/s_base.h" #ifdef SCRIPTAPI_LOCK_DEBUG #include "debug.h" // assert() class LockChecker { public: LockChecker(bool* variable) { assert(*variable == false); m_variable = variable; *m_variable = true; } ~LockChecker() { *m_variable = false; } private: bool* m_variable; }; #define SCRIPTAPI_LOCK_CHECK LockChecker(&(this->m_locked)) #else #define SCRIPTAPI_LOCK_CHECK while(0) #endif #define SCRIPTAPI_PRECHECKHEADER \ JMutexAutoLock(this->m_luastackmutex); \ SCRIPTAPI_LOCK_CHECK; \ realityCheck(); \ lua_State *L = getStack(); \ assert(lua_checkstack(L, 20)); \ StackUnroller stack_unroller(L); #endif /* S_INTERNAL_H_ */ } } lua_pop(L, 1); return got; } bool getfloatfield(lua_State *L, int table, const char *fieldname, float &result) { lua_getfield(L, table, fieldname); bool got = false; if(lua_isnumber(L, -1)){ result = lua_tonumber(L, -1); got = true; } lua_pop(L, 1); return got; } bool getboolfield(lua_State *L, int table, const char *fieldname, bool &result) { lua_getfield(L, table, fieldname); bool got = false; if(lua_isboolean(L, -1)){ result = lua_toboolean(L, -1); got = true; } lua_pop(L, 1); return got; } size_t getstringlistfield(lua_State *L, int table, const char *fieldname, std::vector *result) { lua_getfield(L, table, fieldname); size_t num_strings_read = read_stringlist(L, -1, result); lua_pop(L, 1); return num_strings_read; } std::string checkstringfield(lua_State *L, int table, const char *fieldname) { lua_getfield(L, table, fieldname); CHECK_TYPE(-1, std::string("field \"") + fieldname + '"', LUA_TSTRING); size_t len; const char *s = lua_tolstring(L, -1, &len); lua_pop(L, 1); return std::string(s, len); } std::string getstringfield_default(lua_State *L, int table, const char *fieldname, const std::string &default_) { std::string result = default_; getstringfield(L, table, fieldname, result); return result; } int getintfield_default(lua_State *L, int table, const char *fieldname, int default_) { int result = default_; getintfield(L, table, fieldname, result); return result; } float getfloatfield_default(lua_State *L, int table, const char *fieldname, float default_) { float result = default_; getfloatfield(L, table, fieldname, result); return result; } bool getboolfield_default(lua_State *L, int table, const char *fieldname, bool default_) { bool result = default_; getboolfield(L, table, fieldname, result); return result; } v3s16 getv3s16field_default(lua_State *L, int table, const char *fieldname, v3s16 default_) { getv3intfield(L, table, fieldname, default_); return default_; } void setstringfield(lua_State *L, int table, const char *fieldname, const char *value) { lua_pushstring(L, value); if(table < 0) table -= 1; lua_setfield(L, table, fieldname); } void setintfield(lua_State *L, int table, const char *fieldname, int value) { lua_pushinteger(L, value); if(table < 0) table -= 1; lua_setfield(L, table, fieldname); } void setfloatfield(lua_State *L, int table, const char *fieldname, float value) { lua_pushnumber(L, value); if(table < 0) table -= 1; lua_setfield(L, table, fieldname); } void setboolfield(lua_State *L, int table, const char *fieldname, bool value) { lua_pushboolean(L, value); if(table < 0) table -= 1; lua_setfield(L, table, fieldname); } //// //// Array table slices //// size_t write_array_slice_float( lua_State *L, int table_index, float *data, v3u16 data_size, v3u16 slice_offset, v3u16 slice_size) { v3u16 pmin, pmax(data_size); if (slice_offset.X > 0) { slice_offset.X--; pmin.X = slice_offset.X; pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X); } if (slice_offset.Y > 0) { slice_offset.Y--; pmin.Y = slice_offset.Y; pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y); } if (slice_offset.Z > 0) { slice_offset.Z--; pmin.Z = slice_offset.Z; pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z); } const u32 ystride = data_size.X; const u32 zstride = data_size.X * data_size.Y; u32 elem_index = 1; for (u32 z = pmin.Z; z != pmax.Z; z++) for (u32 y = pmin.Y; y != pmax.Y; y++) for (u32 x = pmin.X; x != pmax.X; x++) { u32 i = z * zstride + y * ystride + x; lua_pushnumber(L, data[i]); lua_rawseti(L, table_index, elem_index); elem_index++; } return elem_index - 1; } size_t write_array_slice_u16( lua_State *L, int table_index, u16 *data, v3u16 data_size, v3u16 slice_offset, v3u16 slice_size) { v3u16 pmin, pmax(data_size); if (slice_offset.X > 0) { slice_offset.X--; pmin.X = slice_offset.X; pmax.X = MYMIN(slice_offset.X + slice_size.X, data_size.X); } if (slice_offset.Y > 0) { slice_offset.Y--; pmin.Y = slice_offset.Y; pmax.Y = MYMIN(slice_offset.Y + slice_size.Y, data_size.Y); } if (slice_offset.Z > 0) { slice_offset.Z--; pmin.Z = slice_offset.Z; pmax.Z = MYMIN(slice_offset.Z + slice_size.Z, data_size.Z); } const u32 ystride = data_size.X; const u32 zstride = data_size.X * data_size.Y; u32 elem_index = 1; for (u32 z = pmin.Z; z != pmax.Z; z++) for (u32 y = pmin.Y; y != pmax.Y; y++) for (u32 x = pmin.X; x != pmax.X; x++) { u32 i = z * zstride + y * ystride + x; lua_pushinteger(L, data[i]); lua_rawseti(L, table_index, elem_index); elem_index++; } return elem_index - 1; }