Skip to content

Commit

Permalink
Derive NodeMetaRef from MetaDataRef
Browse files Browse the repository at this point in the history
  • Loading branch information
rubenwardy committed Feb 4, 2017
1 parent 13f94ec commit c2e7b1f
Show file tree
Hide file tree
Showing 9 changed files with 407 additions and 232 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -74,6 +74,7 @@ locale/
*.a
*.ninja
.ninja*
*.gch

## Android build files
build/android/src/main/assets
Expand All @@ -86,4 +87,3 @@ build/android/obj
build/android/local.properties
build/android/.gradle
timestamp

1 change: 1 addition & 0 deletions build/android/jni/Android.mk
Expand Up @@ -307,6 +307,7 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_item.cpp \
jni/src/script/lua_api/l_mainmenu.cpp \
jni/src/script/lua_api/l_mapgen.cpp \
jni/src/script/lua_api/l_metadata.cpp \
jni/src/script/lua_api/l_nodemeta.cpp \
jni/src/script/lua_api/l_nodetimer.cpp \
jni/src/script/lua_api/l_noise.cpp \
Expand Down
48 changes: 37 additions & 11 deletions src/metadata.cpp
Expand Up @@ -37,12 +37,39 @@ bool Metadata::empty() const
return m_stringvars.size() == 0;
}

std::string Metadata::getString(const std::string &name,
u16 recursion) const
size_t Metadata::size() const
{
return m_stringvars.size();
}

bool Metadata::contains(const std::string &name) const
{
return m_stringvars.find(name) != m_stringvars.end();
}

bool Metadata::operator==(const Metadata &other) const
{
if (size() != other.size())
return false;

for (StringMap::const_iterator it = m_stringvars.begin();
it != m_stringvars.end(); ++it) {
if (!other.contains(it->first) ||
other.getString(it->first) != it->second)
return false;
}

return true;
}

const std::string &Metadata::getString(const std::string &name,
u16 recursion) const
{
StringMap::const_iterator it = m_stringvars.find(name);
if (it == m_stringvars.end())
return "";
if (it == m_stringvars.end()) {
static const std::string empty_string = std::string("");
return empty_string;
}

return resolveString(it->second, recursion);
}
Expand All @@ -56,14 +83,13 @@ void Metadata::setString(const std::string &name, const std::string &var)
}
}

std::string Metadata::resolveString(const std::string &str,
u16 recursion) const
const std::string &Metadata::resolveString(const std::string &str,
u16 recursion) const
{
if (recursion > 1) {
return str;
}
if (str.substr(0, 2) == "${" && str[str.length() - 1] == '}') {
if (recursion <= 1 &&
str.substr(0, 2) == "${" && str[str.length() - 1] == '}') {
return getString(str.substr(2, str.length() - 3), recursion + 1);
} else {
return str;
}
return str;
}
4 changes: 2 additions & 2 deletions src/metadata.h
Expand Up @@ -44,10 +44,10 @@ class Metadata
bool empty() const;

// Generic key/value store
std::string getString(const std::string &name, u16 recursion = 0) const;
const std::string &getString(const std::string &name, u16 recursion = 0) const;
void setString(const std::string &name, const std::string &var);
// Support variable names in values
std::string resolveString(const std::string &str, u16 recursion = 0) const;
const std::string &resolveString(const std::string &str, u16 recursion = 0) const;
const StringMap &getStrings() const
{
return m_stringvars;
Expand Down
2 changes: 1 addition & 1 deletion src/script/lua_api/CMakeLists.txt
Expand Up @@ -6,6 +6,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_inventory.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_item.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_mapgen.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_metadata.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodemeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_nodetimer.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp
Expand All @@ -22,4 +23,3 @@ set(common_SCRIPT_LUA_API_SRCS
set(client_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_mainmenu.cpp
PARENT_SCOPE)

252 changes: 252 additions & 0 deletions src/script/lua_api/l_metadata.cpp
@@ -0,0 +1,252 @@
/*
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.
*/

#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"

// LUALIB_API
void *luaL_checkudata_is_metadataref(lua_State *L, int ud) {
void *p = lua_touserdata(L, ud);
if (p != NULL && // value is a userdata?
lua_getmetatable(L, ud)) { // does it have a metatable?
lua_getfield(L, -1, "metadata_class");
if (lua_type(L, -1) == LUA_TSTRING) { // does it have a metadata_class field?
return p;
}
}
luaL_typerror(L, ud, "MetaDataRef");
return NULL;
}

MetaDataRef* MetaDataRef::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
void *ud = luaL_checkudata_is_metadataref(L, narg);
if (!ud)
luaL_typerror(L, narg, "MetaDataRef");

return *(MetaDataRef**)ud; // unbox pointer
}

// Exported functions

// get_string(self, name)
int MetaDataRef::l_get_string(lua_State *L)
{
MAP_LOCK_REQUIRED;

MetaDataRef *ref = checkobject(L, 1);
std::string name = luaL_checkstring(L, 2);

Metadata *meta = ref->getmeta(false);
if (meta == NULL) {
lua_pushlstring(L, "", 0);
return 1;
}

const std::string &str = meta->getString(name);
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 = checkobject(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);

Metadata *meta = ref->getmeta(!str.empty());
if (meta == NULL || str == meta->getString(name))
return 0;

meta->setString(name, str);
ref->reportMetadataChange();
return 0;
}

// get_int(self, name)
int MetaDataRef::l_get_int(lua_State *L)
{
MAP_LOCK_REQUIRED;

MetaDataRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);

Metadata *meta = ref->getmeta(false);
if (meta == NULL) {
lua_pushnumber(L, 0);
return 1;
}

const std::string &str = meta->getString(name);
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 = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
int a = lua_tointeger(L, 3);
std::string str = itos(a);

Metadata *meta = ref->getmeta(true);
if (meta == NULL || str == meta->getString(name))
return 0;

meta->setString(name, str);
ref->reportMetadataChange();
return 0;
}

// get_float(self, name)
int MetaDataRef::l_get_float(lua_State *L)
{
MAP_LOCK_REQUIRED;

MetaDataRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);

Metadata *meta = ref->getmeta(false);
if (meta == NULL) {
lua_pushnumber(L, 0);
return 1;
}

const std::string &str = meta->getString(name);
lua_pushnumber(L, stof(str));
return 1;
}

// set_float(self, name, var)
int MetaDataRef::l_set_float(lua_State *L)
{
MAP_LOCK_REQUIRED;

MetaDataRef *ref = checkobject(L, 1);
std::string name = lua_tostring(L, 2);
float a = lua_tonumber(L, 3);
std::string str = ftos(a);

Metadata *meta = ref->getmeta(true);
if (meta == NULL || str == meta->getString(name))
return 0;

meta->setString(name, str);
ref->reportMetadataChange();
return 0;
}

// to_table(self)
int MetaDataRef::l_to_table(lua_State *L)
{
MAP_LOCK_REQUIRED;

MetaDataRef *ref = checkobject(L, 1);

Metadata *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 = checkobject(L, 1);
int base = 2;

ref->clearMeta();

if (!lua_istable(L, base)) {
// No metadata
lua_pushboolean(L, true);
return 1;
}

// Create new metadata
Metadata *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, Metadata *meta)
{
lua_newtable(L);
{
const StringMap &fields = meta->getStrings();
for (StringMap::const_iterator
it = fields.begin(); it != fields.end(); ++it) {
const std::string &name = it->first;
const std::string &value = it->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, Metadata *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 = lua_tostring(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;
}

0 comments on commit c2e7b1f

Please sign in to comment.