l_metadata.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. Minetest
  3. Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
  4. Copyright (C) 2017-8 rubenwardy <rw@rubenwardy.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.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License along
  14. with this program; if not, write to the Free Software Foundation, Inc.,
  15. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  16. */
  17. #include "lua_api/l_metadata.h"
  18. #include "lua_api/l_internal.h"
  19. #include "common/c_content.h"
  20. #include "serverenvironment.h"
  21. #include "map.h"
  22. #include "server.h"
  23. #include "util/basic_macros.h"
  24. MetaDataRef *MetaDataRef::checkAnyMetadata(lua_State *L, int narg)
  25. {
  26. void *ud = lua_touserdata(L, narg);
  27. bool ok = ud && luaL_getmetafield(L, narg, "metadata_class");
  28. if (ok) {
  29. ok = lua_isstring(L, -1);
  30. lua_pop(L, 1);
  31. }
  32. if (!ok)
  33. luaL_typerror(L, narg, "MetaDataRef");
  34. return *(MetaDataRef **)ud; // unbox pointer
  35. }
  36. int MetaDataRef::gc_object(lua_State *L)
  37. {
  38. MetaDataRef *o = *(MetaDataRef **)lua_touserdata(L, 1);
  39. delete o;
  40. return 0;
  41. }
  42. // Exported functions
  43. // contains(self, name)
  44. int MetaDataRef::l_contains(lua_State *L)
  45. {
  46. MAP_LOCK_REQUIRED;
  47. MetaDataRef *ref = checkAnyMetadata(L, 1);
  48. std::string name = luaL_checkstring(L, 2);
  49. IMetadata *meta = ref->getmeta(false);
  50. if (meta == NULL)
  51. return 0;
  52. lua_pushboolean(L, meta->contains(name));
  53. return 1;
  54. }
  55. // get(self, name)
  56. int MetaDataRef::l_get(lua_State *L)
  57. {
  58. MAP_LOCK_REQUIRED;
  59. MetaDataRef *ref = checkAnyMetadata(L, 1);
  60. std::string name = luaL_checkstring(L, 2);
  61. IMetadata *meta = ref->getmeta(false);
  62. if (meta == NULL)
  63. return 0;
  64. std::string str;
  65. if (meta->getStringToRef(name, str)) {
  66. lua_pushlstring(L, str.c_str(), str.size());
  67. } else {
  68. lua_pushnil(L);
  69. }
  70. return 1;
  71. }
  72. // get_string(self, name)
  73. int MetaDataRef::l_get_string(lua_State *L)
  74. {
  75. MAP_LOCK_REQUIRED;
  76. MetaDataRef *ref = checkAnyMetadata(L, 1);
  77. std::string name = luaL_checkstring(L, 2);
  78. IMetadata *meta = ref->getmeta(false);
  79. if (meta == NULL) {
  80. lua_pushlstring(L, "", 0);
  81. return 1;
  82. }
  83. std::string str_;
  84. const std::string &str = meta->getString(name, &str_);
  85. lua_pushlstring(L, str.c_str(), str.size());
  86. return 1;
  87. }
  88. // set_string(self, name, var)
  89. int MetaDataRef::l_set_string(lua_State *L)
  90. {
  91. MAP_LOCK_REQUIRED;
  92. MetaDataRef *ref = checkAnyMetadata(L, 1);
  93. std::string name = luaL_checkstring(L, 2);
  94. size_t len = 0;
  95. const char *s = lua_tolstring(L, 3, &len);
  96. std::string str(s, len);
  97. IMetadata *meta = ref->getmeta(!str.empty());
  98. if (meta != NULL && meta->setString(name, str))
  99. ref->reportMetadataChange(&name);
  100. return 0;
  101. }
  102. // get_int(self, name)
  103. int MetaDataRef::l_get_int(lua_State *L)
  104. {
  105. MAP_LOCK_REQUIRED;
  106. MetaDataRef *ref = checkAnyMetadata(L, 1);
  107. std::string name = luaL_checkstring(L, 2);
  108. IMetadata *meta = ref->getmeta(false);
  109. if (meta == NULL) {
  110. lua_pushnumber(L, 0);
  111. return 1;
  112. }
  113. std::string str_;
  114. const std::string &str = meta->getString(name, &str_);
  115. lua_pushnumber(L, stoi(str));
  116. return 1;
  117. }
  118. // set_int(self, name, var)
  119. int MetaDataRef::l_set_int(lua_State *L)
  120. {
  121. MAP_LOCK_REQUIRED;
  122. MetaDataRef *ref = checkAnyMetadata(L, 1);
  123. std::string name = luaL_checkstring(L, 2);
  124. int a = luaL_checkint(L, 3);
  125. std::string str = itos(a);
  126. IMetadata *meta = ref->getmeta(true);
  127. if (meta != NULL && meta->setString(name, str))
  128. ref->reportMetadataChange(&name);
  129. return 0;
  130. }
  131. // get_float(self, name)
  132. int MetaDataRef::l_get_float(lua_State *L)
  133. {
  134. MAP_LOCK_REQUIRED;
  135. MetaDataRef *ref = checkAnyMetadata(L, 1);
  136. std::string name = luaL_checkstring(L, 2);
  137. IMetadata *meta = ref->getmeta(false);
  138. if (meta == NULL) {
  139. lua_pushnumber(L, 0);
  140. return 1;
  141. }
  142. std::string str_;
  143. const std::string &str = meta->getString(name, &str_);
  144. // Convert with Lua, as is done in set_float.
  145. lua_pushlstring(L, str.data(), str.size());
  146. lua_pushnumber(L, lua_tonumber(L, -1));
  147. return 1;
  148. }
  149. // set_float(self, name, var)
  150. int MetaDataRef::l_set_float(lua_State *L)
  151. {
  152. MAP_LOCK_REQUIRED;
  153. MetaDataRef *ref = checkAnyMetadata(L, 1);
  154. std::string name = luaL_checkstring(L, 2);
  155. luaL_checknumber(L, 3);
  156. // Convert number to string with Lua as it gives good precision.
  157. std::string str = readParam<std::string>(L, 3);
  158. IMetadata *meta = ref->getmeta(true);
  159. if (meta != NULL && meta->setString(name, str))
  160. ref->reportMetadataChange(&name);
  161. return 0;
  162. }
  163. // get_keys(self)
  164. int MetaDataRef::l_get_keys(lua_State *L)
  165. {
  166. MAP_LOCK_REQUIRED;
  167. MetaDataRef *ref = checkAnyMetadata(L, 1);
  168. IMetadata *meta = ref->getmeta(false);
  169. if (meta == NULL) {
  170. lua_newtable(L);
  171. return 1;
  172. }
  173. std::vector<std::string> keys_;
  174. const std::vector<std::string> &keys = meta->getKeys(&keys_);
  175. int i = 0;
  176. lua_createtable(L, keys.size(), 0);
  177. for (const std::string &key : keys) {
  178. lua_pushlstring(L, key.c_str(), key.size());
  179. lua_rawseti(L, -2, ++i);
  180. }
  181. return 1;
  182. }
  183. // to_table(self)
  184. int MetaDataRef::l_to_table(lua_State *L)
  185. {
  186. MAP_LOCK_REQUIRED;
  187. MetaDataRef *ref = checkAnyMetadata(L, 1);
  188. IMetadata *meta = ref->getmeta(true);
  189. if (meta == NULL) {
  190. lua_pushnil(L);
  191. return 1;
  192. }
  193. lua_newtable(L);
  194. ref->handleToTable(L, meta);
  195. return 1;
  196. }
  197. // from_table(self, table)
  198. int MetaDataRef::l_from_table(lua_State *L)
  199. {
  200. MAP_LOCK_REQUIRED;
  201. MetaDataRef *ref = checkAnyMetadata(L, 1);
  202. int base = 2;
  203. ref->clearMeta();
  204. if (!lua_istable(L, base)) {
  205. // No metadata
  206. lua_pushboolean(L, true);
  207. return 1;
  208. }
  209. // Create new metadata
  210. IMetadata *meta = ref->getmeta(true);
  211. if (meta == NULL) {
  212. lua_pushboolean(L, false);
  213. return 1;
  214. }
  215. bool was_successful = ref->handleFromTable(L, base, meta);
  216. ref->reportMetadataChange();
  217. lua_pushboolean(L, was_successful);
  218. return 1;
  219. }
  220. void MetaDataRef::handleToTable(lua_State *L, IMetadata *meta)
  221. {
  222. lua_newtable(L);
  223. {
  224. StringMap fields_;
  225. const StringMap &fields = meta->getStrings(&fields_);
  226. for (const auto &field : fields) {
  227. const std::string &name = field.first;
  228. const std::string &value = field.second;
  229. lua_pushlstring(L, name.c_str(), name.size());
  230. lua_pushlstring(L, value.c_str(), value.size());
  231. lua_settable(L, -3);
  232. }
  233. }
  234. lua_setfield(L, -2, "fields");
  235. }
  236. bool MetaDataRef::handleFromTable(lua_State *L, int table, IMetadata *meta)
  237. {
  238. // Set fields
  239. lua_getfield(L, table, "fields");
  240. if (lua_istable(L, -1)) {
  241. int fieldstable = lua_gettop(L);
  242. lua_pushnil(L);
  243. while (lua_next(L, fieldstable) != 0) {
  244. // key at index -2 and value at index -1
  245. std::string name = readParam<std::string>(L, -2);
  246. size_t cl;
  247. const char *cs = lua_tolstring(L, -1, &cl);
  248. meta->setString(name, std::string(cs, cl));
  249. lua_pop(L, 1); // Remove value, keep key for next iteration
  250. }
  251. lua_pop(L, 1);
  252. }
  253. return true;
  254. }
  255. // equals(self, other)
  256. int MetaDataRef::l_equals(lua_State *L)
  257. {
  258. MetaDataRef *ref1 = checkAnyMetadata(L, 1);
  259. IMetadata *data1 = ref1->getmeta(false);
  260. MetaDataRef *ref2 = checkAnyMetadata(L, 2);
  261. IMetadata *data2 = ref2->getmeta(false);
  262. if (data1 == NULL || data2 == NULL)
  263. lua_pushboolean(L, data1 == data2);
  264. else
  265. lua_pushboolean(L, *data1 == *data2);
  266. return 1;
  267. }
  268. void MetaDataRef::registerMetadataClass(lua_State *L, const char *name,
  269. const luaL_Reg *methods)
  270. {
  271. const luaL_Reg metamethods[] = {
  272. {"__eq", l_equals},
  273. {"__gc", gc_object},
  274. {0, 0}
  275. };
  276. registerClass(L, name, methods, metamethods);
  277. // Set metadata_class in the metatable for MetaDataRef::checkAnyMetadata.
  278. luaL_getmetatable(L, name);
  279. lua_pushstring(L, name);
  280. lua_setfield(L, -2, "metadata_class");
  281. lua_pop(L, 1);
  282. }