Add player:get_meta(), deprecate player attributes (#7202)

* Add player:get_meta(), deprecate player attributes
This commit is contained in:
rubenwardy 2018-04-06 09:52:29 +01:00 committed by Loïc Blot
parent 7e3f88f539
commit 91615f9588
22 changed files with 314 additions and 70 deletions

View File

@ -347,6 +347,7 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_nodetimer.cpp \ jni/src/script/lua_api/l_nodetimer.cpp \
jni/src/script/lua_api/l_noise.cpp \ jni/src/script/lua_api/l_noise.cpp \
jni/src/script/lua_api/l_object.cpp \ jni/src/script/lua_api/l_object.cpp \
jni/src/script/lua_api/l_playermeta.cpp \
jni/src/script/lua_api/l_particles.cpp \ jni/src/script/lua_api/l_particles.cpp \
jni/src/script/lua_api/l_particles_local.cpp\ jni/src/script/lua_api/l_particles_local.cpp\
jni/src/script/lua_api/l_rollback.cpp \ jni/src/script/lua_api/l_rollback.cpp \

View File

@ -3902,7 +3902,7 @@ An interface to use mod channels on client and server
* Message size is limited to 65535 characters by protocol. * Message size is limited to 65535 characters by protocol.
### `MetaDataRef` ### `MetaDataRef`
See `StorageRef`, `NodeMetaRef` and `ItemStackMetaRef`. See `StorageRef`, `NodeMetaRef`, `ItemStackMetaRef`, and `PlayerMetaRef`.
#### Methods #### Methods
* `set_string(name, value)` * `set_string(name, value)`
@ -3952,6 +3952,15 @@ Can be obtained via `minetest.get_mod_storage()` during load time.
#### Methods #### Methods
* All methods in MetaDataRef * All methods in MetaDataRef
### `PlayerMetaRef`
Player metadata.
Uses the same method of storage as the deprecated player attribute API, so
data there will also be in player meta.
Can be obtained using `player:get_meta()`.
#### Methods
* All methods in MetaDataRef
### `NodeTimerRef` ### `NodeTimerRef`
Node Timers: a high resolution persistent per-node timer. Node Timers: a high resolution persistent per-node timer.
Can be gotten via `minetest.get_node_timer(pos)`. Can be gotten via `minetest.get_node_timer(pos)`.
@ -4101,14 +4110,15 @@ This is basically a reference to a C++ `ServerActiveObject`
* `0`: player is drowning * `0`: player is drowning
* max: bubbles bar is not shown * max: bubbles bar is not shown
* See Object Properties for more information * See Object Properties for more information
* `set_attribute(attribute, value)`: * `set_attribute(attribute, value)`: DEPRECATED, use get_meta() instead
* Sets an extra attribute with value on player. * Sets an extra attribute with value on player.
* `value` must be a string, or a number which will be converted to a * `value` must be a string, or a number which will be converted to a
string. string.
* If `value` is `nil`, remove attribute from player. * If `value` is `nil`, remove attribute from player.
* `get_attribute(attribute)`: * `get_attribute(attribute)`: DEPRECATED, use get_meta() instead
* Returns value (a string) for extra attribute. * Returns value (a string) for extra attribute.
* Returns `nil` if no attribute found. * Returns `nil` if no attribute found.
* `get_meta()`: Returns a PlayerMetaRef.
* `set_inventory_formspec(formspec)` * `set_inventory_formspec(formspec)`
* Redefine player's inventory form * Redefine player's inventory form
* Should usually be called in `on_joinplayer` * Should usually be called in `on_joinplayer`

View File

@ -13,7 +13,7 @@ assert(pseudo:next() == 13854)
-- HP Change Reasons -- HP Change Reasons
-- --
local expect = nil local expect = nil
minetest.register_on_joinplayer(function(player) local function run_hpchangereason_tests(player)
expect = { type = "set_hp", from = "mod" } expect = { type = "set_hp", from = "mod" }
player:set_hp(3) player:set_hp(3)
assert(expect == nil) assert(expect == nil)
@ -25,8 +25,7 @@ minetest.register_on_joinplayer(function(player)
expect = { df = 3458973454, type = "fall", from = "mod" } expect = { df = 3458973454, type = "fall", from = "mod" }
player:set_hp(10, { type = "fall", df = 3458973454 }) player:set_hp(10, { type = "fall", df = 3458973454 })
assert(expect == nil) assert(expect == nil)
end) end
minetest.register_on_player_hpchange(function(player, hp, reason) minetest.register_on_player_hpchange(function(player, hp, reason)
for key, value in pairs(reason) do for key, value in pairs(reason) do
assert(expect[key] == value) assert(expect[key] == value)
@ -38,3 +37,32 @@ minetest.register_on_player_hpchange(function(player, hp, reason)
expect = nil expect = nil
end) end)
local function run_player_meta_tests(player)
local meta = player:get_meta()
meta:set_string("foo", "bar")
assert(meta:get_string("foo") == "bar")
local meta2 = player:get_meta()
assert(meta2:get_string("foo") == "bar")
assert(meta:equals(meta2))
assert(player:get_attribute("foo") == "bar")
meta:set_string("bob", "dillan")
assert(meta:get_string("foo") == "bar")
assert(meta:get_string("bob") == "dillan")
assert(meta2:get_string("foo") == "bar")
assert(meta2:get_string("bob") == "dillan")
assert(meta:equals(meta2))
assert(player:get_attribute("foo") == "bar")
assert(player:get_attribute("bob") == "dillan")
end
local function run_player_tests(player)
run_hpchangereason_tests(player)
run_player_meta_tests(player)
minetest.chat_send_all("All tests pass!")
end
minetest.register_on_joinplayer(run_player_tests)

View File

@ -197,7 +197,6 @@ public:
} }
}; };
typedef std::unordered_map<std::string, std::string> PlayerAttributes;
class RemotePlayer; class RemotePlayer;
class PlayerSAO : public UnitSAO class PlayerSAO : public UnitSAO
@ -269,49 +268,6 @@ public:
int getWieldIndex() const; int getWieldIndex() const;
void setWieldIndex(int i); void setWieldIndex(int i);
/*
Modding interface
*/
inline void setExtendedAttribute(const std::string &attr, const std::string &value)
{
m_extra_attributes[attr] = value;
m_extended_attributes_modified = true;
}
inline bool getExtendedAttribute(const std::string &attr, std::string *value)
{
if (m_extra_attributes.find(attr) == m_extra_attributes.end())
return false;
*value = m_extra_attributes[attr];
return true;
}
inline void removeExtendedAttribute(const std::string &attr)
{
PlayerAttributes::iterator it = m_extra_attributes.find(attr);
if (it == m_extra_attributes.end())
return;
m_extra_attributes.erase(it);
m_extended_attributes_modified = true;
}
inline const PlayerAttributes &getExtendedAttributes()
{
return m_extra_attributes;
}
inline bool extendedAttributesModified() const
{
return m_extended_attributes_modified;
}
inline void setExtendedAttributeModified(bool v)
{
m_extended_attributes_modified = v;
}
/* /*
PlayerSAO-specific PlayerSAO-specific
*/ */
@ -375,6 +331,8 @@ public:
v3f getEyePosition() const { return m_base_position + getEyeOffset(); } v3f getEyePosition() const { return m_base_position + getEyeOffset(); }
v3f getEyeOffset() const; v3f getEyeOffset() const;
inline Metadata &getMeta() { return m_meta; }
private: private:
std::string getPropertyPacket(); std::string getPropertyPacket();
void unlinkPlayerSessionAndSave(); void unlinkPlayerSessionAndSave();
@ -410,8 +368,7 @@ private:
f32 m_fov = 0.0f; f32 m_fov = 0.0f;
s16 m_wanted_range = 0.0f; s16 m_wanted_range = 0.0f;
PlayerAttributes m_extra_attributes; Metadata m_meta;
bool m_extended_attributes_modified = false;
public: public:
float m_physics_override_speed = 1.0f; float m_physics_override_speed = 1.0f;
float m_physics_override_jump = 1.0f; float m_physics_override_jump = 1.0f;

View File

@ -518,7 +518,7 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player)
} }
execPrepared("remove_player_metadata", 1, rmvalues); execPrepared("remove_player_metadata", 1, rmvalues);
const PlayerAttributes &attrs = sao->getExtendedAttributes(); const StringMap &attrs = sao->getMeta().getStrings();
for (const auto &attr : attrs) { for (const auto &attr : attrs) {
const char *meta_values[] = { const char *meta_values[] = {
player->getName(), player->getName(),
@ -527,6 +527,7 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player)
}; };
execPrepared("save_player_metadata", 3, meta_values); execPrepared("save_player_metadata", 3, meta_values);
} }
sao->getMeta().setModified(false);
endSave(); endSave();
} }
@ -594,8 +595,9 @@ bool PlayerDatabasePostgreSQL::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
int numrows = PQntuples(results); int numrows = PQntuples(results);
for (int row = 0; row < numrows; row++) { for (int row = 0; row < numrows; row++) {
sao->setExtendedAttribute(PQgetvalue(results, row, 0),PQgetvalue(results, row, 1)); sao->getMeta().setString(PQgetvalue(results, row, 0), PQgetvalue(results, row, 1));
} }
sao->getMeta().setModified(false);
PQclear(results); PQclear(results);

View File

@ -520,7 +520,7 @@ void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player)
sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_remove), SQLITE_DONE); sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_remove), SQLITE_DONE);
sqlite3_reset(m_stmt_player_metadata_remove); sqlite3_reset(m_stmt_player_metadata_remove);
const PlayerAttributes &attrs = sao->getExtendedAttributes(); const StringMap &attrs = sao->getMeta().getStrings();
for (const auto &attr : attrs) { for (const auto &attr : attrs) {
str_to_sqlite(m_stmt_player_metadata_add, 1, player->getName()); str_to_sqlite(m_stmt_player_metadata_add, 1, player->getName());
str_to_sqlite(m_stmt_player_metadata_add, 2, attr.first); str_to_sqlite(m_stmt_player_metadata_add, 2, attr.first);
@ -528,6 +528,7 @@ void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player)
sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_add), SQLITE_DONE); sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_add), SQLITE_DONE);
sqlite3_reset(m_stmt_player_metadata_add); sqlite3_reset(m_stmt_player_metadata_add);
} }
sao->getMeta().setModified(false);
endSave(); endSave();
} }
@ -578,8 +579,9 @@ bool PlayerDatabaseSQLite3::loadPlayer(RemotePlayer *player, PlayerSAO *sao)
std::string attr = sqlite_to_string(m_stmt_player_metadata_load, 0); std::string attr = sqlite_to_string(m_stmt_player_metadata_load, 0);
std::string value = sqlite_to_string(m_stmt_player_metadata_load, 1); std::string value = sqlite_to_string(m_stmt_player_metadata_load, 1);
sao->setExtendedAttribute(attr, value); sao->getMeta().setString(attr, value);
} }
sao->getMeta().setModified(false);
sqlite3_reset(m_stmt_player_metadata_load); sqlite3_reset(m_stmt_player_metadata_load);
return true; return true;
} }

View File

@ -1,3 +1,23 @@
/*
Minetest
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 "itemstackmetadata.h" #include "itemstackmetadata.h"
#include "util/serialize.h" #include "util/serialize.h"
#include "util/strfnd.h" #include "util/strfnd.h"

View File

@ -1,6 +1,6 @@
/* /*
Minetest Minetest
Copyright (C) 2010-2013 rubenwardy <rubenwardy@gmail.com> Copyright (C) 2017-8 rubenwardy <rw@rubenwardy.com>
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU Lesser General Public License as published by

View File

@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
void Metadata::clear() void Metadata::clear()
{ {
m_stringvars.clear(); m_stringvars.clear();
m_modified = true;
} }
bool Metadata::empty() const bool Metadata::empty() const
@ -68,6 +69,18 @@ const std::string &Metadata::getString(const std::string &name, u16 recursion) c
return resolveString(it->second, recursion); return resolveString(it->second, recursion);
} }
bool Metadata::getStringToRef(
const std::string &name, std::string &str, u16 recursion) const
{
StringMap::const_iterator it = m_stringvars.find(name);
if (it == m_stringvars.end()) {
return false;
}
str = resolveString(it->second, recursion);
return true;
}
/** /**
* Sets var to name key in the metadata storage * Sets var to name key in the metadata storage
* *
@ -88,6 +101,7 @@ bool Metadata::setString(const std::string &name, const std::string &var)
} }
m_stringvars[name] = var; m_stringvars[name] = var;
m_modified = true;
return true; return true;
} }

View File

@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class Metadata class Metadata
{ {
bool m_modified = false;
public: public:
virtual ~Metadata() = default; virtual ~Metadata() = default;
@ -45,14 +46,18 @@ public:
size_t size() const; size_t size() const;
bool contains(const std::string &name) const; bool contains(const std::string &name) const;
const std::string &getString(const std::string &name, u16 recursion = 0) const; const std::string &getString(const std::string &name, u16 recursion = 0) const;
bool getStringToRef(const std::string &name, std::string &str, u16 recursion = 0) const;
virtual bool setString(const std::string &name, const std::string &var); virtual bool setString(const std::string &name, const std::string &var);
inline bool removeString(const std::string &name) { return setString(name, ""); }
const StringMap &getStrings() const const StringMap &getStrings() const
{ {
return m_stringvars; return m_stringvars;
} }
// Add support for variable names in values // Add support for variable names in values
const std::string &resolveString(const std::string &str, u16 recursion = 0) const; const std::string &resolveString(const std::string &str, u16 recursion = 0) const;
inline bool isModified() const { return m_modified; }
inline void setModified(bool v) { m_modified = v; }
protected: protected:
StringMap m_stringvars; StringMap m_stringvars;
}; };

View File

@ -72,14 +72,15 @@ void RemotePlayer::serializeExtraAttributes(std::string &output)
{ {
assert(m_sao); assert(m_sao);
Json::Value json_root; Json::Value json_root;
const PlayerAttributes &attrs = m_sao->getExtendedAttributes();
const StringMap &attrs = m_sao->getMeta().getStrings();
for (const auto &attr : attrs) { for (const auto &attr : attrs) {
json_root[attr.first] = attr.second; json_root[attr.first] = attr.second;
} }
output = fastWriteJson(json_root); output = fastWriteJson(json_root);
m_sao->setExtendedAttributeModified(false); m_sao->getMeta().setModified(false);
} }
@ -132,8 +133,9 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
const Json::Value::Members attr_list = attr_root.getMemberNames(); const Json::Value::Members attr_list = attr_root.getMemberNames();
for (const auto &it : attr_list) { for (const auto &it : attr_list) {
Json::Value attr_value = attr_root[it]; Json::Value attr_value = attr_root[it];
sao->setExtendedAttribute(it, attr_value.asString()); sao->getMeta().setString(it, attr_value.asString());
} }
sao->getMeta().setModified(false);
} catch (SettingNotFoundException &e) {} } catch (SettingNotFoundException &e) {}
} }

View File

@ -15,6 +15,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_object.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_object.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_particles.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_particles.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_playermeta.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_rollback.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_rollback.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_server.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_server.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp ${CMAKE_CURRENT_SOURCE_DIR}/l_settings.cpp

View File

@ -1,6 +1,8 @@
/* /*
Minetest Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017-8 rubenwardy <rw@rubenwardy.com>
Copyright (C) 2017 raymoo
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU Lesser General Public License as published by

View File

@ -1,6 +1,8 @@
/* /*
Minetest Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2017-8 rubenwardy <rw@rubenwardy.com>
Copyright (C) 2017 raymoo
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU Lesser General Public License as published by

View File

@ -1,6 +1,7 @@
/* /*
Minetest Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> 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 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 it under the terms of the GNU Lesser General Public License as published by

View File

@ -1,6 +1,7 @@
/* /*
Minetest Minetest
Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com> Copyright (C) 2013-8 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 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 it under the terms of the GNU Lesser General Public License as published by

View File

@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h" #include "lua_api/l_internal.h"
#include "lua_api/l_inventory.h" #include "lua_api/l_inventory.h"
#include "lua_api/l_item.h" #include "lua_api/l_item.h"
#include "lua_api/l_playermeta.h"
#include "common/c_converter.h" #include "common/c_converter.h"
#include "common/c_content.h" #include "common/c_content.h"
#include "log.h" #include "log.h"
@ -1218,16 +1219,15 @@ int ObjectRef::l_set_attribute(lua_State *L)
{ {
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref); PlayerSAO* co = getplayersao(ref);
if (co == NULL) { if (co == NULL)
return 0; return 0;
}
std::string attr = luaL_checkstring(L, 2); std::string attr = luaL_checkstring(L, 2);
if (lua_isnil(L, 3)) { if (lua_isnil(L, 3)) {
co->removeExtendedAttribute(attr); co->getMeta().removeString(attr);
} else { } else {
std::string value = luaL_checkstring(L, 3); std::string value = luaL_checkstring(L, 3);
co->setExtendedAttribute(attr, value); co->getMeta().setString(attr, value);
} }
return 1; return 1;
} }
@ -1237,14 +1237,13 @@ int ObjectRef::l_get_attribute(lua_State *L)
{ {
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref); PlayerSAO* co = getplayersao(ref);
if (co == NULL) { if (co == NULL)
return 0; return 0;
}
std::string attr = luaL_checkstring(L, 2); std::string attr = luaL_checkstring(L, 2);
std::string value; std::string value;
if (co->getExtendedAttribute(attr, &value)) { if (co->getMeta().getStringToRef(attr, value)) {
lua_pushstring(L, value.c_str()); lua_pushstring(L, value.c_str());
return 1; return 1;
} }
@ -1253,6 +1252,19 @@ int ObjectRef::l_get_attribute(lua_State *L)
} }
// get_meta(self, attribute)
int ObjectRef::l_get_meta(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
PlayerSAO *co = getplayersao(ref);
if (co == NULL)
return 0;
PlayerMetaRef::create(L, &co->getMeta());
return 1;
}
// set_inventory_formspec(self, formspec) // set_inventory_formspec(self, formspec)
int ObjectRef::l_set_inventory_formspec(lua_State *L) int ObjectRef::l_set_inventory_formspec(lua_State *L)
{ {
@ -1884,6 +1896,7 @@ const luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, set_breath), luamethod(ObjectRef, set_breath),
luamethod(ObjectRef, get_attribute), luamethod(ObjectRef, get_attribute),
luamethod(ObjectRef, set_attribute), luamethod(ObjectRef, set_attribute),
luamethod(ObjectRef, get_meta),
luamethod(ObjectRef, set_inventory_formspec), luamethod(ObjectRef, set_inventory_formspec),
luamethod(ObjectRef, get_inventory_formspec), luamethod(ObjectRef, get_inventory_formspec),
luamethod(ObjectRef, set_formspec_prepend), luamethod(ObjectRef, set_formspec_prepend),

View File

@ -250,6 +250,9 @@ private:
// get_attribute(self, attribute) // get_attribute(self, attribute)
static int l_get_attribute(lua_State *L); static int l_get_attribute(lua_State *L);
// get_meta(self)
static int l_get_meta(lua_State *L);
// set_inventory_formspec(self, formspec) // set_inventory_formspec(self, formspec)
static int l_set_inventory_formspec(lua_State *L); static int l_set_inventory_formspec(lua_State *L);

View File

@ -0,0 +1,121 @@
/*
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_playermeta.h"
#include "lua_api/l_internal.h"
#include "common/c_content.h"
/*
PlayerMetaRef
*/
PlayerMetaRef *PlayerMetaRef::checkobject(lua_State *L, int narg)
{
luaL_checktype(L, narg, LUA_TUSERDATA);
void *ud = luaL_checkudata(L, narg, className);
if (!ud)
luaL_typerror(L, narg, className);
return *(PlayerMetaRef **)ud; // unbox pointer
}
Metadata *PlayerMetaRef::getmeta(bool auto_create)
{
return metadata;
}
void PlayerMetaRef::clearMeta()
{
metadata->clear();
}
void PlayerMetaRef::reportMetadataChange()
{
// TODO
}
// garbage collector
int PlayerMetaRef::gc_object(lua_State *L)
{
PlayerMetaRef *o = *(PlayerMetaRef **)(lua_touserdata(L, 1));
delete o;
return 0;
}
// Creates an PlayerMetaRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
void PlayerMetaRef::create(lua_State *L, Metadata *metadata)
{
PlayerMetaRef *o = new PlayerMetaRef(metadata);
*(void **)(lua_newuserdata(L, sizeof(void *))) = o;
luaL_getmetatable(L, className);
lua_setmetatable(L, -2);
}
void PlayerMetaRef::Register(lua_State *L)
{
lua_newtable(L);
int methodtable = lua_gettop(L);
luaL_newmetatable(L, className);
int metatable = lua_gettop(L);
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable); // hide metatable from Lua getmetatable()
lua_pushliteral(L, "metadata_class");
lua_pushlstring(L, className, strlen(className));
lua_settable(L, metatable);
lua_pushliteral(L, "__index");
lua_pushvalue(L, methodtable);
lua_settable(L, metatable);
lua_pushliteral(L, "__gc");
lua_pushcfunction(L, gc_object);
lua_settable(L, metatable);
lua_pushliteral(L, "__eq");
lua_pushcfunction(L, l_equals);
lua_settable(L, metatable);
lua_pop(L, 1); // drop metatable
luaL_openlib(L, 0, methods, 0);
lua_pop(L, 1);
// Cannot be created from Lua
// lua_register(L, className, create_object);
}
// clang-format off
const char PlayerMetaRef::className[] = "PlayerMetaRef";
const luaL_Reg PlayerMetaRef::methods[] = {
luamethod(MetaDataRef, get_string),
luamethod(MetaDataRef, set_string),
luamethod(MetaDataRef, get_int),
luamethod(MetaDataRef, set_int),
luamethod(MetaDataRef, get_float),
luamethod(MetaDataRef, set_float),
luamethod(MetaDataRef, to_table),
luamethod(MetaDataRef, from_table),
luamethod(MetaDataRef, equals),
{0,0}
};
// clang-format on

View File

@ -0,0 +1,57 @@
/*
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.
*/
#pragma once
#include "lua_api/l_base.h"
#include "lua_api/l_metadata.h"
#include "irrlichttypes_bloated.h"
#include "inventory.h"
#include "metadata.h"
class PlayerMetaRef : public MetaDataRef
{
private:
Metadata *metadata = nullptr;
static const char className[];
static const luaL_Reg methods[];
static PlayerMetaRef *checkobject(lua_State *L, int narg);
virtual Metadata *getmeta(bool auto_create);
virtual void clearMeta();
virtual void reportMetadataChange();
// garbage collector
static int gc_object(lua_State *L);
public:
PlayerMetaRef(Metadata *metadata) : metadata(metadata) {}
~PlayerMetaRef() = default;
// Creates an ItemStackMetaRef and leaves it on top of stack
// Not callable from Lua; all references are created on the C side.
static void create(lua_State *L, Metadata *metadata);
static void Register(lua_State *L);
};

View File

@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_nodetimer.h" #include "lua_api/l_nodetimer.h"
#include "lua_api/l_noise.h" #include "lua_api/l_noise.h"
#include "lua_api/l_object.h" #include "lua_api/l_object.h"
#include "lua_api/l_playermeta.h"
#include "lua_api/l_particles.h" #include "lua_api/l_particles.h"
#include "lua_api/l_rollback.h" #include "lua_api/l_rollback.h"
#include "lua_api/l_server.h" #include "lua_api/l_server.h"
@ -99,6 +100,7 @@ void ServerScripting::InitializeModApi(lua_State *L, int top)
NodeMetaRef::Register(L); NodeMetaRef::Register(L);
NodeTimerRef::Register(L); NodeTimerRef::Register(L);
ObjectRef::Register(L); ObjectRef::Register(L);
PlayerMetaRef::Register(L);
LuaSettings::Register(L); LuaSettings::Register(L);
StorageRef::Register(L); StorageRef::Register(L);
ModChannelRef::Register(L); ModChannelRef::Register(L);

View File

@ -535,7 +535,7 @@ void ServerEnvironment::saveLoadedPlayers()
for (RemotePlayer *player : m_players) { for (RemotePlayer *player : m_players) {
if (player->checkModified() || (player->getPlayerSAO() && if (player->checkModified() || (player->getPlayerSAO() &&
player->getPlayerSAO()->extendedAttributesModified())) { player->getPlayerSAO()->getMeta().isModified())) {
try { try {
m_player_database->savePlayer(player); m_player_database->savePlayer(player);
} catch (DatabaseException &e) { } catch (DatabaseException &e) {