summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLoïc Blot <nerzhul@users.noreply.github.com>2017-01-27 08:59:30 +0100
committerGitHub <noreply@github.com>2017-01-27 08:59:30 +0100
commitb7a98e98500402c3bbdb6d56d0fe42b4f5b3cedb (patch)
treecc45c9609f5e0fe7714e33615b0defe5d42f4840
parent2a8953107181b4df6ff55d0ae214490575609f49 (diff)
downloadminetest-b7a98e98500402c3bbdb6d56d0fe42b4f5b3cedb.tar.gz
minetest-b7a98e98500402c3bbdb6d56d0fe42b4f5b3cedb.tar.bz2
minetest-b7a98e98500402c3bbdb6d56d0fe42b4f5b3cedb.zip
Implement player attribute backend (#4155)
* This backend permit mods to store extra players attributes to a common interface. * Add the obj:set_attribute(attr, value) Lua call * Add the obj:get_attribute(attr) Lua call Examples: * player:set_attribute("home:home", "10,25,-78") * player:get_attribute("default:mana") Attributes are saved as a json in the player file in extended_attributes key They are saved only if a modification on the attributes occurs and loaded when emergePlayer is called (they are attached to PlayerSAO).
-rw-r--r--doc/lua_api.txt2
-rw-r--r--src/content_sao.cpp1
-rw-r--r--src/content_sao.h37
-rw-r--r--src/remoteplayer.cpp38
-rw-r--r--src/remoteplayer.h5
-rw-r--r--src/script/lua_api/l_object.cpp41
-rw-r--r--src/script/lua_api/l_object.h6
-rw-r--r--src/server.h1
-rw-r--r--src/serverenvironment.cpp3
9 files changed, 128 insertions, 6 deletions
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 62a7b81f7..ee7d57c2f 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -2899,6 +2899,8 @@ This is basically a reference to a C++ `ServerActiveObject`
* `0`: player is drowning,
* `1`-`10`: remaining number of bubbles
* `11`: bubbles bar is not shown
+* `set_attribute(attribute, value)`: sets an extra attribute with value on player
+* `get_attribute(attribute)`: returns value for extra attribute. Returns nil if no attribute found.
* `set_inventory_formspec(formspec)`
* Redefine player's inventory form
* Should usually be called in on_joinplayer
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index bb62aea7d..35133490e 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -791,6 +791,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer
m_pitch(0),
m_fov(0),
m_wanted_range(0),
+ m_extended_attributes_modified(false),
// public
m_physics_override_speed(1),
m_physics_override_jump(1),
diff --git a/src/content_sao.h b/src/content_sao.h
index c3674fa2d..bbf244742 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -180,6 +180,7 @@ public:
}
};
+typedef UNORDERED_MAP<std::string, std::string> PlayerAttributes;
class RemotePlayer;
class PlayerSAO : public UnitSAO
@@ -250,6 +251,39 @@ 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 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
*/
@@ -343,6 +377,9 @@ private:
f32 m_pitch;
f32 m_fov;
s16 m_wanted_range;
+
+ PlayerAttributes m_extra_attributes;
+ bool m_extended_attributes_modified;
public:
float m_physics_override_speed;
float m_physics_override_jump;
diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp
index 18bfa1030..6853ad6d9 100644
--- a/src/remoteplayer.cpp
+++ b/src/remoteplayer.cpp
@@ -19,13 +19,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/
#include "remoteplayer.h"
+#include <json/json.h>
#include "content_sao.h"
#include "filesys.h"
#include "gamedef.h"
#include "porting.h" // strlcpy
+#include "server.h"
#include "settings.h"
-
/*
RemotePlayer
*/
@@ -112,9 +113,23 @@ void RemotePlayer::save(std::string savedir, IGameDef *gamedef)
}
infostream << "Didn't find free file for player " << m_name << std::endl;
- return;
}
+void RemotePlayer::serializeExtraAttributes(std::string &output)
+{
+ assert(m_sao);
+ Json::Value json_root;
+ const PlayerAttributes &attrs = m_sao->getExtendedAttributes();
+ for (PlayerAttributes::const_iterator it = attrs.begin(); it != attrs.end(); ++it) {
+ json_root[(*it).first] = (*it).second;
+ }
+
+ Json::FastWriter writer;
+ output = writer.write(json_root);
+ m_sao->setExtendedAttributeModified(false);
+}
+
+
void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
PlayerSAO *sao)
{
@@ -150,6 +165,20 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
try {
sao->setBreath(args.getS32("breath"), false);
} catch (SettingNotFoundException &e) {}
+
+ try {
+ std::string extended_attributes = args.get("extended_attributes");
+ Json::Reader reader;
+ Json::Value attr_root;
+ reader.parse(extended_attributes, attr_root);
+
+ const Json::Value::Members attr_list = attr_root.getMemberNames();
+ for (Json::Value::Members::const_iterator it = attr_list.begin();
+ it != attr_list.end(); ++it) {
+ Json::Value attr_value = attr_root[*it];
+ sao->setExtendedAttribute(*it, attr_value.asString());
+ }
+ } catch (SettingNotFoundException &e) {}
}
inventory.deSerialize(is);
@@ -175,7 +204,6 @@ void RemotePlayer::serialize(std::ostream &os)
Settings args;
args.setS32("version", 1);
args.set("name", m_name);
- //args.set("password", m_password);
// This should not happen
assert(m_sao);
@@ -185,6 +213,10 @@ void RemotePlayer::serialize(std::ostream &os)
args.setFloat("yaw", m_sao->getYaw());
args.setS32("breath", m_sao->getBreath());
+ std::string extended_attrs = "";
+ serializeExtraAttributes(extended_attrs);
+ args.set("extended_attributes", extended_attrs);
+
args.writeLines(os);
os<<"PlayerArgsEnd\n";
diff --git a/src/remoteplayer.h b/src/remoteplayer.h
index 61b5a23de..f44fb9332 100644
--- a/src/remoteplayer.h
+++ b/src/remoteplayer.h
@@ -25,11 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
class PlayerSAO;
-enum RemotePlayerChatResult {
+enum RemotePlayerChatResult
+{
RPLAYER_CHATRESULT_OK,
RPLAYER_CHATRESULT_FLOODING,
RPLAYER_CHATRESULT_KICK,
};
+
/*
Player on the server
*/
@@ -135,6 +137,7 @@ private:
deSerialize stops reading exactly at the right point.
*/
void serialize(std::ostream &os);
+ void serializeExtraAttributes(std::string &output);
PlayerSAO *m_sao;
bool m_dirty;
diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp
index be4451704..9352812ab 100644
--- a/src/script/lua_api/l_object.cpp
+++ b/src/script/lua_api/l_object.cpp
@@ -1181,6 +1181,45 @@ int ObjectRef::l_get_breath(lua_State *L)
return 1;
}
+// set_attribute(self, attribute, value)
+int ObjectRef::l_set_attribute(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO* co = getplayersao(ref);
+ if (co == NULL) {
+ return 0;
+ }
+
+ std::string attr = luaL_checkstring(L, 2);
+ std::string value = luaL_checkstring(L, 3);
+
+ if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
+ co->setExtendedAttribute(attr, value);
+ }
+ return 1;
+}
+
+// get_attribute(self, attribute)
+int ObjectRef::l_get_attribute(lua_State *L)
+{
+ ObjectRef *ref = checkobject(L, 1);
+ PlayerSAO* co = getplayersao(ref);
+ if (co == NULL) {
+ return 0;
+ }
+
+ std::string attr = luaL_checkstring(L, 2);
+
+ std::string value = "";
+ if (co->getExtendedAttribute(attr, &value)) {
+ lua_pushstring(L, value.c_str());
+ return 1;
+ }
+
+ return 0;
+}
+
+
// set_inventory_formspec(self, formspec)
int ObjectRef::l_set_inventory_formspec(lua_State *L)
{
@@ -1839,6 +1878,8 @@ const luaL_reg ObjectRef::methods[] = {
luamethod(ObjectRef, set_look_pitch),
luamethod(ObjectRef, get_breath),
luamethod(ObjectRef, set_breath),
+ luamethod(ObjectRef, get_attribute),
+ luamethod(ObjectRef, set_attribute),
luamethod(ObjectRef, set_inventory_formspec),
luamethod(ObjectRef, get_inventory_formspec),
luamethod(ObjectRef, get_player_control),
diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h
index 96d0abae8..2c9aa559a 100644
--- a/src/script/lua_api/l_object.h
+++ b/src/script/lua_api/l_object.h
@@ -226,6 +226,12 @@ private:
// get_breath(self, breath)
static int l_get_breath(lua_State *L);
+ // set_attribute(self, attribute, value)
+ static int l_set_attribute(lua_State *L);
+
+ // get_attribute(self, attribute)
+ static int l_get_attribute(lua_State *L);
+
// set_inventory_formspec(self, formspec)
static int l_set_inventory_formspec(lua_State *L);
diff --git a/src/server.h b/src/server.h
index e5121bdc3..8f553ce38 100644
--- a/src/server.h
+++ b/src/server.h
@@ -576,7 +576,6 @@ private:
float m_time_of_day_send_timer;
// Uptime of server in seconds
MutexedVariable<double> m_uptime;
-
/*
Client interface
*/
diff --git a/src/serverenvironment.cpp b/src/serverenvironment.cpp
index 01dc3ff10..7a5cfafd6 100644
--- a/src/serverenvironment.cpp
+++ b/src/serverenvironment.cpp
@@ -500,7 +500,8 @@ void ServerEnvironment::saveLoadedPlayers()
for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
it != m_players.end();
++it) {
- if ((*it)->checkModified()) {
+ if ((*it)->checkModified() ||
+ ((*it)->getPlayerSAO() && (*it)->getPlayerSAO()->extendedAttributesModified())) {
(*it)->save(players_path, m_server);
}
}