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).
This commit is contained in:
parent
2a89531071
commit
b7a98e9850
|
@ -2899,6 +2899,8 @@ This is basically a reference to a C++ `ServerActiveObject`
|
||||||
* `0`: player is drowning,
|
* `0`: player is drowning,
|
||||||
* `1`-`10`: remaining number of bubbles
|
* `1`-`10`: remaining number of bubbles
|
||||||
* `11`: bubbles bar is not shown
|
* `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)`
|
* `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
|
||||||
|
|
|
@ -791,6 +791,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, u16 peer_id_, bool is_singleplayer
|
||||||
m_pitch(0),
|
m_pitch(0),
|
||||||
m_fov(0),
|
m_fov(0),
|
||||||
m_wanted_range(0),
|
m_wanted_range(0),
|
||||||
|
m_extended_attributes_modified(false),
|
||||||
// public
|
// public
|
||||||
m_physics_override_speed(1),
|
m_physics_override_speed(1),
|
||||||
m_physics_override_jump(1),
|
m_physics_override_jump(1),
|
||||||
|
|
|
@ -180,6 +180,7 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef UNORDERED_MAP<std::string, std::string> PlayerAttributes;
|
||||||
class RemotePlayer;
|
class RemotePlayer;
|
||||||
|
|
||||||
class PlayerSAO : public UnitSAO
|
class PlayerSAO : public UnitSAO
|
||||||
|
@ -249,6 +250,39 @@ 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 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
|
||||||
*/
|
*/
|
||||||
|
@ -343,6 +377,9 @@ private:
|
||||||
f32 m_pitch;
|
f32 m_pitch;
|
||||||
f32 m_fov;
|
f32 m_fov;
|
||||||
s16 m_wanted_range;
|
s16 m_wanted_range;
|
||||||
|
|
||||||
|
PlayerAttributes m_extra_attributes;
|
||||||
|
bool m_extended_attributes_modified;
|
||||||
public:
|
public:
|
||||||
float m_physics_override_speed;
|
float m_physics_override_speed;
|
||||||
float m_physics_override_jump;
|
float m_physics_override_jump;
|
||||||
|
|
|
@ -19,13 +19,14 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "remoteplayer.h"
|
#include "remoteplayer.h"
|
||||||
|
#include <json/json.h>
|
||||||
#include "content_sao.h"
|
#include "content_sao.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
#include "gamedef.h"
|
#include "gamedef.h"
|
||||||
#include "porting.h" // strlcpy
|
#include "porting.h" // strlcpy
|
||||||
|
#include "server.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
RemotePlayer
|
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;
|
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,
|
void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
|
||||||
PlayerSAO *sao)
|
PlayerSAO *sao)
|
||||||
{
|
{
|
||||||
|
@ -150,6 +165,20 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
|
||||||
try {
|
try {
|
||||||
sao->setBreath(args.getS32("breath"), false);
|
sao->setBreath(args.getS32("breath"), false);
|
||||||
} catch (SettingNotFoundException &e) {}
|
} 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);
|
inventory.deSerialize(is);
|
||||||
|
@ -175,7 +204,6 @@ void RemotePlayer::serialize(std::ostream &os)
|
||||||
Settings args;
|
Settings args;
|
||||||
args.setS32("version", 1);
|
args.setS32("version", 1);
|
||||||
args.set("name", m_name);
|
args.set("name", m_name);
|
||||||
//args.set("password", m_password);
|
|
||||||
|
|
||||||
// This should not happen
|
// This should not happen
|
||||||
assert(m_sao);
|
assert(m_sao);
|
||||||
|
@ -185,6 +213,10 @@ void RemotePlayer::serialize(std::ostream &os)
|
||||||
args.setFloat("yaw", m_sao->getYaw());
|
args.setFloat("yaw", m_sao->getYaw());
|
||||||
args.setS32("breath", m_sao->getBreath());
|
args.setS32("breath", m_sao->getBreath());
|
||||||
|
|
||||||
|
std::string extended_attrs = "";
|
||||||
|
serializeExtraAttributes(extended_attrs);
|
||||||
|
args.set("extended_attributes", extended_attrs);
|
||||||
|
|
||||||
args.writeLines(os);
|
args.writeLines(os);
|
||||||
|
|
||||||
os<<"PlayerArgsEnd\n";
|
os<<"PlayerArgsEnd\n";
|
||||||
|
|
|
@ -25,11 +25,13 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
|
||||||
class PlayerSAO;
|
class PlayerSAO;
|
||||||
|
|
||||||
enum RemotePlayerChatResult {
|
enum RemotePlayerChatResult
|
||||||
|
{
|
||||||
RPLAYER_CHATRESULT_OK,
|
RPLAYER_CHATRESULT_OK,
|
||||||
RPLAYER_CHATRESULT_FLOODING,
|
RPLAYER_CHATRESULT_FLOODING,
|
||||||
RPLAYER_CHATRESULT_KICK,
|
RPLAYER_CHATRESULT_KICK,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Player on the server
|
Player on the server
|
||||||
*/
|
*/
|
||||||
|
@ -135,6 +137,7 @@ private:
|
||||||
deSerialize stops reading exactly at the right point.
|
deSerialize stops reading exactly at the right point.
|
||||||
*/
|
*/
|
||||||
void serialize(std::ostream &os);
|
void serialize(std::ostream &os);
|
||||||
|
void serializeExtraAttributes(std::string &output);
|
||||||
|
|
||||||
PlayerSAO *m_sao;
|
PlayerSAO *m_sao;
|
||||||
bool m_dirty;
|
bool m_dirty;
|
||||||
|
|
|
@ -1181,6 +1181,45 @@ int ObjectRef::l_get_breath(lua_State *L)
|
||||||
return 1;
|
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)
|
// set_inventory_formspec(self, formspec)
|
||||||
int ObjectRef::l_set_inventory_formspec(lua_State *L)
|
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, set_look_pitch),
|
||||||
luamethod(ObjectRef, get_breath),
|
luamethod(ObjectRef, get_breath),
|
||||||
luamethod(ObjectRef, set_breath),
|
luamethod(ObjectRef, set_breath),
|
||||||
|
luamethod(ObjectRef, get_attribute),
|
||||||
|
luamethod(ObjectRef, set_attribute),
|
||||||
luamethod(ObjectRef, set_inventory_formspec),
|
luamethod(ObjectRef, set_inventory_formspec),
|
||||||
luamethod(ObjectRef, get_inventory_formspec),
|
luamethod(ObjectRef, get_inventory_formspec),
|
||||||
luamethod(ObjectRef, get_player_control),
|
luamethod(ObjectRef, get_player_control),
|
||||||
|
|
|
@ -226,6 +226,12 @@ private:
|
||||||
// get_breath(self, breath)
|
// get_breath(self, breath)
|
||||||
static int l_get_breath(lua_State *L);
|
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)
|
// set_inventory_formspec(self, formspec)
|
||||||
static int l_set_inventory_formspec(lua_State *L);
|
static int l_set_inventory_formspec(lua_State *L);
|
||||||
|
|
||||||
|
|
|
@ -576,7 +576,6 @@ private:
|
||||||
float m_time_of_day_send_timer;
|
float m_time_of_day_send_timer;
|
||||||
// Uptime of server in seconds
|
// Uptime of server in seconds
|
||||||
MutexedVariable<double> m_uptime;
|
MutexedVariable<double> m_uptime;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Client interface
|
Client interface
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -500,7 +500,8 @@ void ServerEnvironment::saveLoadedPlayers()
|
||||||
for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
|
for (std::vector<RemotePlayer *>::iterator it = m_players.begin();
|
||||||
it != m_players.end();
|
it != m_players.end();
|
||||||
++it) {
|
++it) {
|
||||||
if ((*it)->checkModified()) {
|
if ((*it)->checkModified() ||
|
||||||
|
((*it)->getPlayerSAO() && (*it)->getPlayerSAO()->extendedAttributesModified())) {
|
||||||
(*it)->save(players_path, m_server);
|
(*it)->save(players_path, m_server);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue