You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

397 lines
9.6 KiB

  1. /*
  2. Minetest
  3. Copyright (C) 2015 est31 <mtest31@outlook.com>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as published by
  6. the Free Software Foundation; either version 2.1 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include "lua_api/l_areastore.h"
  17. #include "lua_api/l_internal.h"
  18. #include "common/c_converter.h"
  19. #include "cpp_api/s_security.h"
  20. #include "irr_v3d.h"
  21. #include "util/areastore.h"
  22. #include "filesys.h"
  23. #include <fstream>
  24. static inline void get_data_and_border_flags(lua_State *L, u8 start_i,
  25. bool *borders, bool *data)
  26. {
  27. if (!lua_isboolean(L, start_i))
  28. return;
  29. *borders = lua_toboolean(L, start_i);
  30. if (!lua_isboolean(L, start_i + 1))
  31. return;
  32. *data = lua_toboolean(L, start_i + 1);
  33. }
  34. static void push_area(lua_State *L, const Area *a,
  35. bool include_borders, bool include_data)
  36. {
  37. if (!include_borders && !include_data) {
  38. lua_pushboolean(L, true);
  39. return;
  40. }
  41. lua_newtable(L);
  42. if (include_borders) {
  43. push_v3s16(L, a->minedge);
  44. lua_setfield(L, -2, "min");
  45. push_v3s16(L, a->maxedge);
  46. lua_setfield(L, -2, "max");
  47. }
  48. if (include_data) {
  49. lua_pushlstring(L, a->data.c_str(), a->data.size());
  50. lua_setfield(L, -2, "data");
  51. }
  52. }
  53. static inline void push_areas(lua_State *L, const std::vector<Area *> &areas,
  54. bool borders, bool data)
  55. {
  56. lua_newtable(L);
  57. size_t cnt = areas.size();
  58. for (size_t i = 0; i < cnt; i++) {
  59. lua_pushnumber(L, areas[i]->id);
  60. push_area(L, areas[i], borders, data);
  61. lua_settable(L, -3);
  62. }
  63. }
  64. // Deserializes value and handles errors
  65. static int deserialization_helper(lua_State *L, AreaStore *as,
  66. std::istream &is)
  67. {
  68. try {
  69. as->deserialize(is);
  70. } catch (const SerializationError &e) {
  71. lua_pushboolean(L, false);
  72. lua_pushstring(L, e.what());
  73. return 2;
  74. }
  75. lua_pushboolean(L, true);
  76. return 1;
  77. }
  78. // garbage collector
  79. int LuaAreaStore::gc_object(lua_State *L)
  80. {
  81. LuaAreaStore *o = *(LuaAreaStore **)(lua_touserdata(L, 1));
  82. delete o;
  83. return 0;
  84. }
  85. // get_area(id, include_borders, include_data)
  86. int LuaAreaStore::l_get_area(lua_State *L)
  87. {
  88. NO_MAP_LOCK_REQUIRED;
  89. LuaAreaStore *o = checkobject(L, 1);
  90. AreaStore *ast = o->as;
  91. u32 id = luaL_checknumber(L, 2);
  92. bool include_borders = true;
  93. bool include_data = false;
  94. get_data_and_border_flags(L, 3, &include_borders, &include_data);
  95. const Area *res;
  96. res = ast->getArea(id);
  97. if (!res)
  98. return 0;
  99. push_area(L, res, include_borders, include_data);
  100. return 1;
  101. }
  102. // get_areas_for_pos(pos, include_borders, include_data)
  103. int LuaAreaStore::l_get_areas_for_pos(lua_State *L)
  104. {
  105. NO_MAP_LOCK_REQUIRED;
  106. LuaAreaStore *o = checkobject(L, 1);
  107. AreaStore *ast = o->as;
  108. v3s16 pos = check_v3s16(L, 2);
  109. bool include_borders = true;
  110. bool include_data = false;
  111. get_data_and_border_flags(L, 3, &include_borders, &include_data);
  112. std::vector<Area *> res;
  113. ast->getAreasForPos(&res, pos);
  114. push_areas(L, res, include_borders, include_data);
  115. return 1;
  116. }
  117. // get_areas_in_area(edge1, edge2, accept_overlap, include_borders, include_data)
  118. int LuaAreaStore::l_get_areas_in_area(lua_State *L)
  119. {
  120. NO_MAP_LOCK_REQUIRED;
  121. LuaAreaStore *o = checkobject(L, 1);
  122. AreaStore *ast = o->as;
  123. v3s16 minedge = check_v3s16(L, 2);
  124. v3s16 maxedge = check_v3s16(L, 3);
  125. bool include_borders = true;
  126. bool include_data = false;
  127. bool accept_overlap = false;
  128. if (lua_isboolean(L, 4)) {
  129. accept_overlap = readParam<bool>(L, 4);
  130. get_data_and_border_flags(L, 5, &include_borders, &include_data);
  131. }
  132. std::vector<Area *> res;
  133. ast->getAreasInArea(&res, minedge, maxedge, accept_overlap);
  134. push_areas(L, res, include_borders, include_data);
  135. return 1;
  136. }
  137. // insert_area(edge1, edge2, data, id)
  138. int LuaAreaStore::l_insert_area(lua_State *L)
  139. {
  140. NO_MAP_LOCK_REQUIRED;
  141. LuaAreaStore *o = checkobject(L, 1);
  142. AreaStore *ast = o->as;
  143. Area a(check_v3s16(L, 2), check_v3s16(L, 3));
  144. size_t d_len;
  145. const char *data = luaL_checklstring(L, 4, &d_len);
  146. a.data = std::string(data, d_len);
  147. if (lua_isnumber(L, 5))
  148. a.id = lua_tonumber(L, 5);
  149. // Insert & assign a new ID if necessary
  150. if (!ast->insertArea(&a))
  151. return 0;
  152. lua_pushnumber(L, a.id);
  153. return 1;
  154. }
  155. // reserve(count)
  156. int LuaAreaStore::l_reserve(lua_State *L)
  157. {
  158. NO_MAP_LOCK_REQUIRED;
  159. LuaAreaStore *o = checkobject(L, 1);
  160. AreaStore *ast = o->as;
  161. size_t count = luaL_checknumber(L, 2);
  162. ast->reserve(count);
  163. return 0;
  164. }
  165. // remove_area(id)
  166. int LuaAreaStore::l_remove_area(lua_State *L)
  167. {
  168. NO_MAP_LOCK_REQUIRED;
  169. LuaAreaStore *o = checkobject(L, 1);
  170. AreaStore *ast = o->as;
  171. u32 id = luaL_checknumber(L, 2);
  172. bool success = ast->removeArea(id);
  173. lua_pushboolean(L, success);
  174. return 1;
  175. }
  176. // set_cache_params(params)
  177. int LuaAreaStore::l_set_cache_params(lua_State *L)
  178. {
  179. NO_MAP_LOCK_REQUIRED;
  180. LuaAreaStore *o = checkobject(L, 1);
  181. AreaStore *ast = o->as;
  182. luaL_checktype(L, 2, LUA_TTABLE);
  183. bool enabled = getboolfield_default(L, 2, "enabled", true);
  184. u8 block_radius = getintfield_default(L, 2, "block_radius", 64);
  185. size_t limit = getintfield_default(L, 2, "block_radius", 1000);
  186. ast->setCacheParams(enabled, block_radius, limit);
  187. return 0;
  188. }
  189. // to_string()
  190. int LuaAreaStore::l_to_string(lua_State *L)
  191. {
  192. NO_MAP_LOCK_REQUIRED;
  193. LuaAreaStore *o = checkobject(L, 1);
  194. std::ostringstream os(std::ios_base::binary);
  195. o->as->serialize(os);
  196. std::string str = os.str();
  197. lua_pushlstring(L, str.c_str(), str.length());
  198. return 1;
  199. }
  200. // to_file(filename)
  201. int LuaAreaStore::l_to_file(lua_State *L)
  202. {
  203. NO_MAP_LOCK_REQUIRED;
  204. LuaAreaStore *o = checkobject(L, 1);
  205. AreaStore *ast = o->as;
  206. const char *filename = luaL_checkstring(L, 2);
  207. CHECK_SECURE_PATH(L, filename, true);
  208. std::ostringstream os(std::ios_base::binary);
  209. ast->serialize(os);
  210. lua_pushboolean(L, fs::safeWriteToFile(filename, os.str()));
  211. return 1;
  212. }
  213. // from_string(str)
  214. int LuaAreaStore::l_from_string(lua_State *L)
  215. {
  216. NO_MAP_LOCK_REQUIRED;
  217. LuaAreaStore *o = checkobject(L, 1);
  218. size_t len;
  219. const char *str = luaL_checklstring(L, 2, &len);
  220. std::istringstream is(std::string(str, len), std::ios::binary);
  221. return deserialization_helper(L, o->as, is);
  222. }
  223. // from_file(filename)
  224. int LuaAreaStore::l_from_file(lua_State *L)
  225. {
  226. NO_MAP_LOCK_REQUIRED;
  227. LuaAreaStore *o = checkobject(L, 1);
  228. const char *filename = luaL_checkstring(L, 2);
  229. CHECK_SECURE_PATH(L, filename, false);
  230. std::ifstream is(filename, std::ios::binary);
  231. return deserialization_helper(L, o->as, is);
  232. }
  233. LuaAreaStore::LuaAreaStore() : as(AreaStore::getOptimalImplementation())
  234. {
  235. }
  236. LuaAreaStore::LuaAreaStore(const std::string &type)
  237. {
  238. #if USE_SPATIAL
  239. if (type == "LibSpatial") {
  240. as = new SpatialAreaStore();
  241. } else
  242. #endif
  243. {
  244. as = new VectorAreaStore();
  245. }
  246. }
  247. LuaAreaStore::~LuaAreaStore()
  248. {
  249. delete as;
  250. }
  251. // LuaAreaStore()
  252. // Creates an LuaAreaStore and leaves it on top of stack
  253. int LuaAreaStore::create_object(lua_State *L)
  254. {
  255. NO_MAP_LOCK_REQUIRED;
  256. LuaAreaStore *o = (lua_isstring(L, 1)) ?
  257. new LuaAreaStore(readParam<std::string>(L, 1)) :
  258. new LuaAreaStore();
  259. *(void **)(lua_newuserdata(L, sizeof(void *))) = o;
  260. luaL_getmetatable(L, className);
  261. lua_setmetatable(L, -2);
  262. return 1;
  263. }
  264. LuaAreaStore *LuaAreaStore::checkobject(lua_State *L, int narg)
  265. {
  266. NO_MAP_LOCK_REQUIRED;
  267. luaL_checktype(L, narg, LUA_TUSERDATA);
  268. void *ud = luaL_checkudata(L, narg, className);
  269. if (!ud)
  270. luaL_typerror(L, narg, className);
  271. return *(LuaAreaStore **)ud; // unbox pointer
  272. }
  273. void LuaAreaStore::Register(lua_State *L)
  274. {
  275. lua_newtable(L);
  276. int methodtable = lua_gettop(L);
  277. luaL_newmetatable(L, className);
  278. int metatable = lua_gettop(L);
  279. lua_pushliteral(L, "__metatable");
  280. lua_pushvalue(L, methodtable);
  281. lua_settable(L, metatable); // hide metatable from Lua getmetatable()
  282. lua_pushliteral(L, "__index");
  283. lua_pushvalue(L, methodtable);
  284. lua_settable(L, metatable);
  285. lua_pushliteral(L, "__gc");
  286. lua_pushcfunction(L, gc_object);
  287. lua_settable(L, metatable);
  288. lua_pop(L, 1); // drop metatable
  289. luaL_openlib(L, 0, methods, 0); // fill methodtable
  290. lua_pop(L, 1); // drop methodtable
  291. // Can be created from Lua (AreaStore())
  292. lua_register(L, className, create_object);
  293. }
  294. const char LuaAreaStore::className[] = "AreaStore";
  295. const luaL_Reg LuaAreaStore::methods[] = {
  296. luamethod(LuaAreaStore, get_area),
  297. luamethod(LuaAreaStore, get_areas_for_pos),
  298. luamethod(LuaAreaStore, get_areas_in_area),
  299. luamethod(LuaAreaStore, insert_area),
  300. luamethod(LuaAreaStore, reserve),
  301. luamethod(LuaAreaStore, remove_area),
  302. luamethod(LuaAreaStore, set_cache_params),
  303. luamethod(LuaAreaStore, to_string),
  304. luamethod(LuaAreaStore, to_file),
  305. luamethod(LuaAreaStore, from_string),
  306. luamethod(LuaAreaStore, from_file),
  307. {0,0}
  308. };