123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343 |
- /*
- Minetest
- Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
- Copyright (C) 2017-8 rubenwardy <rw@rubenwardy.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.
- */
- #include "lua_api/l_metadata.h"
- #include "lua_api/l_internal.h"
- #include "common/c_content.h"
- #include "serverenvironment.h"
- #include "map.h"
- #include "server.h"
- #include "util/basic_macros.h"
- MetaDataRef *MetaDataRef::checkAnyMetadata(lua_State *L, int narg)
- {
- void *ud = lua_touserdata(L, narg);
- bool ok = ud && luaL_getmetafield(L, narg, "metadata_class");
- if (ok) {
- ok = lua_isstring(L, -1);
- lua_pop(L, 1);
- }
- if (!ok)
- luaL_typerror(L, narg, "MetaDataRef");
- return *(MetaDataRef **)ud; // unbox pointer
- }
- int MetaDataRef::gc_object(lua_State *L)
- {
- MetaDataRef *o = *(MetaDataRef **)lua_touserdata(L, 1);
- delete o;
- return 0;
- }
- // Exported functions
- // contains(self, name)
- int MetaDataRef::l_contains(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- IMetadata *meta = ref->getmeta(false);
- if (meta == NULL)
- return 0;
- lua_pushboolean(L, meta->contains(name));
- return 1;
- }
- // get(self, name)
- int MetaDataRef::l_get(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- IMetadata *meta = ref->getmeta(false);
- if (meta == NULL)
- return 0;
- std::string str;
- if (meta->getStringToRef(name, str)) {
- lua_pushlstring(L, str.c_str(), str.size());
- } else {
- lua_pushnil(L);
- }
- return 1;
- }
- // get_string(self, name)
- int MetaDataRef::l_get_string(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- IMetadata *meta = ref->getmeta(false);
- if (meta == NULL) {
- lua_pushlstring(L, "", 0);
- return 1;
- }
- std::string str_;
- const std::string &str = meta->getString(name, &str_);
- lua_pushlstring(L, str.c_str(), str.size());
- return 1;
- }
- // set_string(self, name, var)
- int MetaDataRef::l_set_string(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- size_t len = 0;
- const char *s = lua_tolstring(L, 3, &len);
- std::string str(s, len);
- IMetadata *meta = ref->getmeta(!str.empty());
- if (meta != NULL && meta->setString(name, str))
- ref->reportMetadataChange(&name);
- return 0;
- }
- // get_int(self, name)
- int MetaDataRef::l_get_int(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- IMetadata *meta = ref->getmeta(false);
- if (meta == NULL) {
- lua_pushnumber(L, 0);
- return 1;
- }
- std::string str_;
- const std::string &str = meta->getString(name, &str_);
- lua_pushnumber(L, stoi(str));
- return 1;
- }
- // set_int(self, name, var)
- int MetaDataRef::l_set_int(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- int a = luaL_checkint(L, 3);
- std::string str = itos(a);
- IMetadata *meta = ref->getmeta(true);
- if (meta != NULL && meta->setString(name, str))
- ref->reportMetadataChange(&name);
- return 0;
- }
- // get_float(self, name)
- int MetaDataRef::l_get_float(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- IMetadata *meta = ref->getmeta(false);
- if (meta == NULL) {
- lua_pushnumber(L, 0);
- return 1;
- }
- std::string str_;
- const std::string &str = meta->getString(name, &str_);
- // Convert with Lua, as is done in set_float.
- lua_pushlstring(L, str.data(), str.size());
- lua_pushnumber(L, lua_tonumber(L, -1));
- return 1;
- }
- // set_float(self, name, var)
- int MetaDataRef::l_set_float(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- std::string name = luaL_checkstring(L, 2);
- luaL_checknumber(L, 3);
- // Convert number to string with Lua as it gives good precision.
- std::string str = readParam<std::string>(L, 3);
- IMetadata *meta = ref->getmeta(true);
- if (meta != NULL && meta->setString(name, str))
- ref->reportMetadataChange(&name);
- return 0;
- }
- // get_keys(self)
- int MetaDataRef::l_get_keys(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- IMetadata *meta = ref->getmeta(false);
- if (meta == NULL) {
- lua_newtable(L);
- return 1;
- }
- std::vector<std::string> keys_;
- const std::vector<std::string> &keys = meta->getKeys(&keys_);
- int i = 0;
- lua_createtable(L, keys.size(), 0);
- for (const std::string &key : keys) {
- lua_pushlstring(L, key.c_str(), key.size());
- lua_rawseti(L, -2, ++i);
- }
- return 1;
- }
- // to_table(self)
- int MetaDataRef::l_to_table(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- IMetadata *meta = ref->getmeta(true);
- if (meta == NULL) {
- lua_pushnil(L);
- return 1;
- }
- lua_newtable(L);
- ref->handleToTable(L, meta);
- return 1;
- }
- // from_table(self, table)
- int MetaDataRef::l_from_table(lua_State *L)
- {
- MAP_LOCK_REQUIRED;
- MetaDataRef *ref = checkAnyMetadata(L, 1);
- int base = 2;
- ref->clearMeta();
- if (!lua_istable(L, base)) {
- // No metadata
- lua_pushboolean(L, true);
- return 1;
- }
- // Create new metadata
- IMetadata *meta = ref->getmeta(true);
- if (meta == NULL) {
- lua_pushboolean(L, false);
- return 1;
- }
- bool was_successful = ref->handleFromTable(L, base, meta);
- ref->reportMetadataChange();
- lua_pushboolean(L, was_successful);
- return 1;
- }
- void MetaDataRef::handleToTable(lua_State *L, IMetadata *meta)
- {
- lua_newtable(L);
- {
- StringMap fields_;
- const StringMap &fields = meta->getStrings(&fields_);
- for (const auto &field : fields) {
- const std::string &name = field.first;
- const std::string &value = field.second;
- lua_pushlstring(L, name.c_str(), name.size());
- lua_pushlstring(L, value.c_str(), value.size());
- lua_settable(L, -3);
- }
- }
- lua_setfield(L, -2, "fields");
- }
- bool MetaDataRef::handleFromTable(lua_State *L, int table, IMetadata *meta)
- {
- // Set fields
- lua_getfield(L, table, "fields");
- if (lua_istable(L, -1)) {
- int fieldstable = lua_gettop(L);
- lua_pushnil(L);
- while (lua_next(L, fieldstable) != 0) {
- // key at index -2 and value at index -1
- std::string name = readParam<std::string>(L, -2);
- size_t cl;
- const char *cs = lua_tolstring(L, -1, &cl);
- meta->setString(name, std::string(cs, cl));
- lua_pop(L, 1); // Remove value, keep key for next iteration
- }
- lua_pop(L, 1);
- }
- return true;
- }
- // equals(self, other)
- int MetaDataRef::l_equals(lua_State *L)
- {
- MetaDataRef *ref1 = checkAnyMetadata(L, 1);
- IMetadata *data1 = ref1->getmeta(false);
- MetaDataRef *ref2 = checkAnyMetadata(L, 2);
- IMetadata *data2 = ref2->getmeta(false);
- if (data1 == NULL || data2 == NULL)
- lua_pushboolean(L, data1 == data2);
- else
- lua_pushboolean(L, *data1 == *data2);
- return 1;
- }
- void MetaDataRef::registerMetadataClass(lua_State *L, const char *name,
- const luaL_Reg *methods)
- {
- const luaL_Reg metamethods[] = {
- {"__eq", l_equals},
- {"__gc", gc_object},
- {0, 0}
- };
- registerClass(L, name, methods, metamethods);
- // Set metadata_class in the metatable for MetaDataRef::checkAnyMetadata.
- luaL_getmetatable(L, name);
- lua_pushstring(L, name);
- lua_setfield(L, -2, "metadata_class");
- lua_pop(L, 1);
- }
|