l_metadata.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. auto str = readParam<std::string_view>(L, 3);
  95. IMetadata *meta = ref->getmeta(!str.empty());
  96. if (meta != NULL && meta->setString(name, str))
  97. ref->reportMetadataChange(&name);
  98. return 0;
  99. }
  100. // get_int(self, name)
  101. int MetaDataRef::l_get_int(lua_State *L)
  102. {
  103. MAP_LOCK_REQUIRED;
  104. MetaDataRef *ref = checkAnyMetadata(L, 1);
  105. std::string name = luaL_checkstring(L, 2);
  106. IMetadata *meta = ref->getmeta(false);
  107. if (meta == NULL) {
  108. lua_pushnumber(L, 0);
  109. return 1;
  110. }
  111. std::string str_;
  112. const std::string &str = meta->getString(name, &str_);
  113. lua_pushnumber(L, stoi(str));
  114. return 1;
  115. }
  116. // set_int(self, name, var)
  117. int MetaDataRef::l_set_int(lua_State *L)
  118. {
  119. MAP_LOCK_REQUIRED;
  120. MetaDataRef *ref = checkAnyMetadata(L, 1);
  121. std::string name = luaL_checkstring(L, 2);
  122. int a = luaL_checkint(L, 3);
  123. std::string str = itos(a);
  124. IMetadata *meta = ref->getmeta(true);
  125. if (meta != NULL && meta->setString(name, str))
  126. ref->reportMetadataChange(&name);
  127. return 0;
  128. }
  129. // get_float(self, name)
  130. int MetaDataRef::l_get_float(lua_State *L)
  131. {
  132. MAP_LOCK_REQUIRED;
  133. MetaDataRef *ref = checkAnyMetadata(L, 1);
  134. std::string name = luaL_checkstring(L, 2);
  135. IMetadata *meta = ref->getmeta(false);
  136. if (meta == NULL) {
  137. lua_pushnumber(L, 0);
  138. return 1;
  139. }
  140. std::string str_;
  141. const std::string &str = meta->getString(name, &str_);
  142. // Convert with Lua, as is done in set_float.
  143. lua_pushlstring(L, str.data(), str.size());
  144. lua_pushnumber(L, lua_tonumber(L, -1));
  145. return 1;
  146. }
  147. // set_float(self, name, var)
  148. int MetaDataRef::l_set_float(lua_State *L)
  149. {
  150. MAP_LOCK_REQUIRED;
  151. MetaDataRef *ref = checkAnyMetadata(L, 1);
  152. std::string name = luaL_checkstring(L, 2);
  153. luaL_checknumber(L, 3);
  154. // Convert number to string with Lua as it gives good precision.
  155. std::string str = readParam<std::string>(L, 3);
  156. IMetadata *meta = ref->getmeta(true);
  157. if (meta != NULL && meta->setString(name, str))
  158. ref->reportMetadataChange(&name);
  159. return 0;
  160. }
  161. // get_keys(self)
  162. int MetaDataRef::l_get_keys(lua_State *L)
  163. {
  164. MAP_LOCK_REQUIRED;
  165. MetaDataRef *ref = checkAnyMetadata(L, 1);
  166. IMetadata *meta = ref->getmeta(false);
  167. if (meta == NULL) {
  168. lua_newtable(L);
  169. return 1;
  170. }
  171. std::vector<std::string> keys_;
  172. const std::vector<std::string> &keys = meta->getKeys(&keys_);
  173. int i = 0;
  174. lua_createtable(L, keys.size(), 0);
  175. for (const std::string &key : keys) {
  176. lua_pushlstring(L, key.c_str(), key.size());
  177. lua_rawseti(L, -2, ++i);
  178. }
  179. return 1;
  180. }
  181. // to_table(self)
  182. int MetaDataRef::l_to_table(lua_State *L)
  183. {
  184. MAP_LOCK_REQUIRED;
  185. MetaDataRef *ref = checkAnyMetadata(L, 1);
  186. IMetadata *meta = ref->getmeta(true);
  187. if (meta == NULL) {
  188. lua_pushnil(L);
  189. return 1;
  190. }
  191. lua_newtable(L);
  192. ref->handleToTable(L, meta);
  193. return 1;
  194. }
  195. // from_table(self, table)
  196. int MetaDataRef::l_from_table(lua_State *L)
  197. {
  198. MAP_LOCK_REQUIRED;
  199. MetaDataRef *ref = checkAnyMetadata(L, 1);
  200. int base = 2;
  201. ref->clearMeta();
  202. if (!lua_istable(L, base)) {
  203. // No metadata
  204. lua_pushboolean(L, true);
  205. return 1;
  206. }
  207. // Create new metadata
  208. IMetadata *meta = ref->getmeta(true);
  209. if (meta == NULL) {
  210. lua_pushboolean(L, false);
  211. return 1;
  212. }
  213. bool was_successful = ref->handleFromTable(L, base, meta);
  214. ref->reportMetadataChange();
  215. lua_pushboolean(L, was_successful);
  216. return 1;
  217. }
  218. void MetaDataRef::handleToTable(lua_State *L, IMetadata *meta)
  219. {
  220. lua_newtable(L);
  221. {
  222. StringMap fields_;
  223. const StringMap &fields = meta->getStrings(&fields_);
  224. for (const auto &field : fields) {
  225. const std::string &name = field.first;
  226. const std::string &value = field.second;
  227. lua_pushlstring(L, name.c_str(), name.size());
  228. lua_pushlstring(L, value.c_str(), value.size());
  229. lua_settable(L, -3);
  230. }
  231. }
  232. lua_setfield(L, -2, "fields");
  233. }
  234. bool MetaDataRef::handleFromTable(lua_State *L, int table, IMetadata *meta)
  235. {
  236. // Set fields
  237. lua_getfield(L, table, "fields");
  238. if (lua_istable(L, -1)) {
  239. int fieldstable = lua_gettop(L);
  240. lua_pushnil(L);
  241. while (lua_next(L, fieldstable) != 0) {
  242. // key at index -2 and value at index -1
  243. std::string name = readParam<std::string>(L, -2);
  244. auto value = readParam<std::string_view>(L, -1);
  245. meta->setString(name, value);
  246. lua_pop(L, 1); // Remove value, keep key for next iteration
  247. }
  248. lua_pop(L, 1);
  249. }
  250. return true;
  251. }
  252. // equals(self, other)
  253. int MetaDataRef::l_equals(lua_State *L)
  254. {
  255. MetaDataRef *ref1 = checkAnyMetadata(L, 1);
  256. IMetadata *data1 = ref1->getmeta(false);
  257. MetaDataRef *ref2 = checkAnyMetadata(L, 2);
  258. IMetadata *data2 = ref2->getmeta(false);
  259. if (data1 == NULL || data2 == NULL)
  260. lua_pushboolean(L, data1 == data2);
  261. else
  262. lua_pushboolean(L, *data1 == *data2);
  263. return 1;
  264. }
  265. void MetaDataRef::registerMetadataClass(lua_State *L, const char *name,
  266. const luaL_Reg *methods)
  267. {
  268. const luaL_Reg metamethods[] = {
  269. {"__eq", l_equals},
  270. {"__gc", gc_object},
  271. {0, 0}
  272. };
  273. registerClass(L, name, methods, metamethods);
  274. // Set metadata_class in the metatable for MetaDataRef::checkAnyMetadata.
  275. luaL_getmetatable(L, name);
  276. lua_pushstring(L, name);
  277. lua_setfield(L, -2, "metadata_class");
  278. lua_pop(L, 1);
  279. }