3 Copyright (C) 2010-2016 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2014-2016 nerzhul, Loic Blot <loic.blot@unix-experience.fr>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "remoteplayer.h"
22 #include <json/json.h>
25 #include "porting.h" // strlcpy
28 #include "convert_json.h"
29 #include "server/player_sao.h"
34 // static config cache for remoteplayer
35 bool RemotePlayer::m_setting_cache_loaded
= false;
36 float RemotePlayer::m_setting_chat_message_limit_per_10sec
= 0.0f
;
37 u16
RemotePlayer::m_setting_chat_message_limit_trigger_kick
= 0;
39 RemotePlayer::RemotePlayer(const char *name
, IItemDefManager
*idef
):
42 if (!RemotePlayer::m_setting_cache_loaded
) {
43 RemotePlayer::m_setting_chat_message_limit_per_10sec
=
44 g_settings
->getFloat("chat_message_limit_per_10sec");
45 RemotePlayer::m_setting_chat_message_limit_trigger_kick
=
46 g_settings
->getU16("chat_message_limit_trigger_kick");
47 RemotePlayer::m_setting_cache_loaded
= true;
49 movement_acceleration_default
= g_settings
->getFloat("movement_acceleration_default") * BS
;
50 movement_acceleration_air
= g_settings
->getFloat("movement_acceleration_air") * BS
;
51 movement_acceleration_fast
= g_settings
->getFloat("movement_acceleration_fast") * BS
;
52 movement_speed_walk
= g_settings
->getFloat("movement_speed_walk") * BS
;
53 movement_speed_crouch
= g_settings
->getFloat("movement_speed_crouch") * BS
;
54 movement_speed_fast
= g_settings
->getFloat("movement_speed_fast") * BS
;
55 movement_speed_climb
= g_settings
->getFloat("movement_speed_climb") * BS
;
56 movement_speed_jump
= g_settings
->getFloat("movement_speed_jump") * BS
;
57 movement_liquid_fluidity
= g_settings
->getFloat("movement_liquid_fluidity") * BS
;
58 movement_liquid_fluidity_smooth
= g_settings
->getFloat("movement_liquid_fluidity_smooth") * BS
;
59 movement_liquid_sink
= g_settings
->getFloat("movement_liquid_sink") * BS
;
60 movement_gravity
= g_settings
->getFloat("movement_gravity") * BS
;
63 m_cloud_params
.density
= 0.4f
;
64 m_cloud_params
.color_bright
= video::SColor(229, 240, 240, 255);
65 m_cloud_params
.color_ambient
= video::SColor(255, 0, 0, 0);
66 m_cloud_params
.height
= 120.0f
;
67 m_cloud_params
.thickness
= 16.0f
;
68 m_cloud_params
.speed
= v2f(0.0f
, -2.0f
);
72 SkyboxDefaults sky_defaults
;
74 m_skybox_params
.sky_color
= sky_defaults
.getSkyColorDefaults();
75 m_skybox_params
.type
= "regular";
76 m_skybox_params
.clouds
= true;
77 m_skybox_params
.fog_sun_tint
= video::SColor(255, 244, 125, 29);
78 m_skybox_params
.fog_moon_tint
= video::SColorf(0.5, 0.6, 0.8, 1).toSColor();
79 m_skybox_params
.fog_tint_type
= "default";
81 m_sun_params
= sky_defaults
.getSunDefaults();
82 m_moon_params
= sky_defaults
.getMoonDefaults();
83 m_star_params
= sky_defaults
.getStarDefaults();
86 void RemotePlayer::serializeExtraAttributes(std::string
&output
)
89 Json::Value json_root
;
91 const StringMap
&attrs
= m_sao
->getMeta().getStrings();
92 for (const auto &attr
: attrs
) {
93 json_root
[attr
.first
] = attr
.second
;
96 output
= fastWriteJson(json_root
);
100 void RemotePlayer::deSerialize(std::istream
&is
, const std::string
&playername
,
105 if (!args
.parseConfigLines(is
, "PlayerArgsEnd")) {
106 throw SerializationError("PlayerArgsEnd of player " + playername
+ " not found!");
110 //args.getS32("version"); // Version field value not used
111 const std::string
&name
= args
.get("name");
112 strlcpy(m_name
, name
.c_str(), PLAYERNAME_SIZE
);
116 sao
->setHPRaw(args
.getU16("hp"));
117 } catch(SettingNotFoundException
&e
) {
118 sao
->setHPRaw(PLAYER_MAX_HP_DEFAULT
);
122 sao
->setBasePosition(args
.getV3F("position"));
123 } catch (SettingNotFoundException
&e
) {}
126 sao
->setLookPitch(args
.getFloat("pitch"));
127 } catch (SettingNotFoundException
&e
) {}
129 sao
->setPlayerYaw(args
.getFloat("yaw"));
130 } catch (SettingNotFoundException
&e
) {}
133 sao
->setBreath(args
.getU16("breath"), false);
134 } catch (SettingNotFoundException
&e
) {}
137 const std::string
&extended_attributes
= args
.get("extended_attributes");
138 std::istringstream
iss(extended_attributes
);
139 Json::CharReaderBuilder builder
;
140 builder
.settings_
["collectComments"] = false;
143 Json::Value attr_root
;
144 Json::parseFromStream(builder
, iss
, &attr_root
, &errs
);
146 const Json::Value::Members attr_list
= attr_root
.getMemberNames();
147 for (const auto &it
: attr_list
) {
148 Json::Value attr_value
= attr_root
[it
];
149 sao
->getMeta().setString(it
, attr_value
.asString());
151 sao
->getMeta().setModified(false);
152 } catch (SettingNotFoundException
&e
) {}
156 inventory
.deSerialize(is
);
157 } catch (SerializationError
&e
) {
158 errorstream
<< "Failed to deserialize player inventory. player_name="
159 << name
<< " " << e
.what() << std::endl
;
162 if (!inventory
.getList("craftpreview") && inventory
.getList("craftresult")) {
163 // Convert players without craftpreview
164 inventory
.addList("craftpreview", 1);
166 bool craftresult_is_preview
= true;
167 if(args
.exists("craftresult_is_preview"))
168 craftresult_is_preview
= args
.getBool("craftresult_is_preview");
169 if(craftresult_is_preview
)
172 inventory
.getList("craftresult")->changeItem(0, ItemStack());
177 void RemotePlayer::serialize(std::ostream
&os
)
179 // Utilize a Settings object for storing values
181 args
.setS32("version", 1);
182 args
.set("name", m_name
);
184 // This should not happen
186 args
.setU16("hp", m_sao
->getHP());
187 args
.setV3F("position", m_sao
->getBasePosition());
188 args
.setFloat("pitch", m_sao
->getLookPitch());
189 args
.setFloat("yaw", m_sao
->getRotation().Y
);
190 args
.setU16("breath", m_sao
->getBreath());
192 std::string extended_attrs
;
193 serializeExtraAttributes(extended_attrs
);
194 args
.set("extended_attributes", extended_attrs
);
198 os
<<"PlayerArgsEnd\n";
200 inventory
.serialize(os
);
203 const RemotePlayerChatResult
RemotePlayer::canSendChatMessage()
205 // Rate limit messages
206 u32 now
= time(NULL
);
207 float time_passed
= now
- m_last_chat_message_sent
;
208 m_last_chat_message_sent
= now
;
210 // If this feature is disabled
211 if (m_setting_chat_message_limit_per_10sec
<= 0.0) {
212 return RPLAYER_CHATRESULT_OK
;
215 m_chat_message_allowance
+= time_passed
* (m_setting_chat_message_limit_per_10sec
/ 8.0f
);
216 if (m_chat_message_allowance
> m_setting_chat_message_limit_per_10sec
) {
217 m_chat_message_allowance
= m_setting_chat_message_limit_per_10sec
;
220 if (m_chat_message_allowance
< 1.0f
) {
221 infostream
<< "Player " << m_name
222 << " chat limited due to excessive message amount." << std::endl
;
224 // Kick player if flooding is too intensive
225 m_message_rate_overhead
++;
226 if (m_message_rate_overhead
> RemotePlayer::m_setting_chat_message_limit_trigger_kick
) {
227 return RPLAYER_CHATRESULT_KICK
;
230 return RPLAYER_CHATRESULT_FLOODING
;
233 // Reinit message overhead
234 if (m_message_rate_overhead
> 0) {
235 m_message_rate_overhead
= 0;
238 m_chat_message_allowance
-= 1.0f
;
239 return RPLAYER_CHATRESULT_OK
;
242 void RemotePlayer::onSuccessfulSave()
246 m_sao
->getMeta().setModified(false);