Browse Source

Add "player:get_meta" API function (#7202)

Port of Old MT commit 91615f9588
From: rubenwardy <rw@rubenwardy.com>
Date: Fri, 6 Apr 2018 09:52:29 +0100
master
OldCoder 3 months ago
parent
commit
1990975348

+ 1
- 0
build/android/jni/Android.mk View File

@@ -326,6 +326,7 @@ LOCAL_SRC_FILES += \
jni/src/script/lua_api/l_nodetimer.cpp \
jni/src/script/lua_api/l_noise.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_rollback.cpp \
jni/src/script/lua_api/l_server.cpp \

+ 11
- 11
doc/lua_api.txt View File

@@ -3493,7 +3493,7 @@ Class reference
---------------

### `MetaDataRef`
See `StorageRef`, `NodeMetaRef` and `ItemStackMetaRef`.
See `StorageRef`, `NodeMetaRef`, `ItemStackMetaRef`, and `PlayerMetaRef`.

#### Methods
* `set_string(name, value)`
@@ -3541,6 +3541,15 @@ Can be obtained via `minetest.get_mod_storage()` during load time.
#### Methods
* 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`
Node Timers: a high resolution persistent per-node timer.
Can be gotten via `minetest.get_node_timer(pos)`.
@@ -3687,6 +3696,7 @@ This is basically a reference to a C++ `ServerActiveObject`
* `get_attribute(attribute)`:
* Returns value (a string) for extra attribute.
* Returns `nil` if no attribute found.
* `get_meta()`: Returns a PlayerMetaRef.
* `set_inventory_formspec(formspec)`
* Redefine player's inventory form
* Should usually be called in `on_joinplayer`
@@ -5285,13 +5295,3 @@ Note that in params, use of symbols is as follows:
| ly only partly correct. It'll be brought into sync in due course. |
| |
+--------------------------------------------------------------------+
@@@
--- doc/lua_api.txt
+++ doc/lua_api.txt
@@ -4844,6 +4844,18 @@ Schematics
the Lua code generated will use that number of spaces as indentation
instead of a tab character.
HTTP Requests
-------------

+ 3
- 46
src/content_sao.h View File

@@ -198,7 +198,6 @@ public:
}
};

typedef std::unordered_map<std::string, std::string> PlayerAttributes;
class RemotePlayer;

class PlayerSAO : public UnitSAO
@@ -270,49 +269,6 @@ public:
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
*/

@@ -375,6 +331,8 @@ public:
v3f getEyePosition() const { return m_base_position + getEyeOffset(); }
v3f getEyeOffset() const;

inline Metadata &getMeta() { return m_meta; }

private:
std::string getPropertyPacket();
void unlinkPlayerSessionAndSave();
@@ -410,8 +368,7 @@ private:
f32 m_fov = 0.0f;
s16 m_wanted_range = 0.0f;

PlayerAttributes m_extra_attributes;
bool m_extended_attributes_modified = false;
Metadata m_meta;
public:
float m_physics_override_speed = 1.0f;
float m_physics_override_jump = 1.0f;

+ 4
- 2
src/database-postgresql.cpp View File

@@ -518,7 +518,7 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player)
}

execPrepared("remove_player_metadata", 1, rmvalues);
const PlayerAttributes &attrs = sao->getExtendedAttributes();
const StringMap &attrs = sao->getMeta().getStrings();
for (const auto &attr : attrs) {
const char *meta_values[] = {
player->getName(),
@@ -527,6 +527,7 @@ void PlayerDatabasePostgreSQL::savePlayer(RemotePlayer *player)
};
execPrepared("save_player_metadata", 3, meta_values);
}
sao->getMeta().setModified(false);
endSave();
}

@@ -594,8 +595,9 @@ bool PlayerDatabasePostgreSQL::loadPlayer(RemotePlayer *player, PlayerSAO *sao)

int numrows = PQntuples(results);
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);


+ 4
- 2
src/database-sqlite3.cpp View File

@@ -520,7 +520,7 @@ void PlayerDatabaseSQLite3::savePlayer(RemotePlayer *player)
sqlite3_vrfy(sqlite3_step(m_stmt_player_metadata_remove), SQLITE_DONE);
sqlite3_reset(m_stmt_player_metadata_remove);

const PlayerAttributes &attrs = sao->getExtendedAttributes();
const StringMap &attrs = sao->getMeta().getStrings();
for (const auto &attr : attrs) {
str_to_sqlite(m_stmt_player_metadata_add, 1, player->getName());
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_reset(m_stmt_player_metadata_add);
}
sao->getMeta().setModified(false);

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 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);
return true;
}

+ 20
- 0
src/itemstackmetadata.cpp 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 "util/serialize.h"
#include "util/strfnd.h"

+ 1
- 1
src/itemstackmetadata.h View File

@@ -1,6 +1,6 @@
/*
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
it under the terms of the GNU Lesser General Public License as published by

+ 14
- 0
src/metadata.cpp View File

@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
void Metadata::clear()
{
m_stringvars.clear();
m_modified = true;
}

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);
}

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
*
@@ -88,6 +101,7 @@ bool Metadata::setString(const std::string &name, const std::string &var)
}

m_stringvars[name] = var;
m_modified = true;
return true;
}


+ 6
- 1
src/metadata.h View File

@@ -27,6 +27,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,

class Metadata
{
bool m_modified = false;
public:
virtual ~Metadata() = default;

@@ -46,16 +47,20 @@ public:
size_t size() const;
bool contains(const std::string &name) 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);
inline bool removeString(const std::string &name) { return setString(name, ""); }
const StringMap &getStrings() const
{
return m_stringvars;
}
// Add support for variable names in values
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:
StringMap m_stringvars;

};

#endif

+ 5
- 3
src/remoteplayer.cpp View File

@@ -63,14 +63,15 @@ void RemotePlayer::serializeExtraAttributes(std::string &output)
{
assert(m_sao);
Json::Value json_root;
const PlayerAttributes &attrs = m_sao->getExtendedAttributes();
const StringMap &attrs = m_sao->getMeta().getStrings();

for (const auto &attr : attrs) {
json_root[attr.first] = attr.second;
}

Json::FastWriter writer;
output = writer.write(json_root);
m_sao->setExtendedAttributeModified(false);
m_sao->getMeta().setModified(false);
}


@@ -119,8 +120,9 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
const Json::Value::Members attr_list = attr_root.getMemberNames();
for (const auto &it : attr_list) {
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) {}
}


+ 1
- 0
src/script/lua_api/CMakeLists.txt View File

@@ -14,6 +14,7 @@ set(common_SCRIPT_LUA_API_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/l_noise.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_object.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_server.cpp
${CMAKE_CURRENT_SOURCE_DIR}/l_storage.cpp

+ 2
- 0
src/script/lua_api/l_itemstackmeta.cpp View File

@@ -1,6 +1,8 @@
/*
Minetest
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
it under the terms of the GNU Lesser General Public License as published by

+ 2
- 0
src/script/lua_api/l_itemstackmeta.h View File

@@ -1,6 +1,8 @@
/*
Minetest
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
it under the terms of the GNU Lesser General Public License as published by

+ 1
- 0
src/script/lua_api/l_metadata.cpp View File

@@ -1,6 +1,7 @@
/*
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

+ 2
- 1
src/script/lua_api/l_metadata.h View File

@@ -1,6 +1,7 @@
/*
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
it under the terms of the GNU Lesser General Public License as published by

+ 20
- 9
src/script/lua_api/l_object.cpp View File

@@ -21,6 +21,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "lua_api/l_internal.h"
#include "lua_api/l_inventory.h"
#include "lua_api/l_item.h"
#include "lua_api/l_playermeta.h"
#include "common/c_converter.h"
#include "common/c_content.h"
#include "log.h"
@@ -1253,16 +1254,15 @@ int ObjectRef::l_set_attribute(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) {
if (co == NULL)
return 0;
}

std::string attr = luaL_checkstring(L, 2);
if (lua_isnil(L, 3)) {
co->removeExtendedAttribute(attr);
co->getMeta().removeString(attr);
} else {
std::string value = luaL_checkstring(L, 3);
co->setExtendedAttribute(attr, value);
co->getMeta().setString(attr, value);
}
return 1;
}
@@ -1272,14 +1272,11 @@ int ObjectRef::l_get_attribute(lua_State *L)
{
ObjectRef *ref = checkobject(L, 1);
PlayerSAO* co = getplayersao(ref);
if (co == NULL) {
return 0;
}

if (co == NULL) return 0;
std::string attr = luaL_checkstring(L, 2);

std::string value = "";
if (co->getExtendedAttribute(attr, &value)) {
if (co->getMeta().getStringToRef(attr, value)) {
lua_pushstring(L, value.c_str());
return 1;
}
@@ -1288,6 +1285,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)
int ObjectRef::l_set_inventory_formspec(lua_State *L)
{
@@ -1955,6 +1965,7 @@ const luaL_Reg ObjectRef::methods[] = {
luamethod(ObjectRef, set_breath),
luamethod(ObjectRef, get_attribute),
luamethod(ObjectRef, set_attribute),
luamethod(ObjectRef, get_meta),
luamethod(ObjectRef, set_inventory_formspec),
luamethod(ObjectRef, get_inventory_formspec),
luamethod(ObjectRef, get_player_control),

+ 3
- 0
src/script/lua_api/l_object.h View File

@@ -251,6 +251,9 @@ private:
// get_attribute(self, attribute)
static int l_get_attribute(lua_State *L);

// get_meta(self)
static int l_get_meta(lua_State *L);

// set_inventory_formspec(self, formspec)
static int l_set_inventory_formspec(lua_State *L);


+ 121
- 0
src/script/lua_api/l_playermeta.cpp 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

+ 57
- 0
src/script/lua_api/l_playermeta.h 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);
};

+ 2
- 0
src/script/scripting_server.cpp 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_noise.h"
#include "lua_api/l_object.h"
#include "lua_api/l_playermeta.h"
#include "lua_api/l_particles.h"
#include "lua_api/l_rollback.h"
#include "lua_api/l_server.h"
@@ -99,6 +100,7 @@ void ServerScripting::InitializeModApi(lua_State *L, int top)
NodeMetaRef::Register(L);
NodeTimerRef::Register(L);
ObjectRef::Register(L);
PlayerMetaRef::Register(L);
LuaSettings::Register(L);
StorageRef::Register(L);


+ 1
- 1
src/serverenvironment.cpp View File

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

Loading…
Cancel
Save