1 /* 2 Minetest 3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com> 4 Copyright (C) 2013-2020 Minetest core developers & community 5 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. 10 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. 15 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. 19 */ 20 21 #pragma once 22 23 #include "constants.h" 24 #include "network/networkprotocol.h" 25 #include "unit_sao.h" 26 #include "util/numeric.h" 27 28 /* 29 PlayerSAO needs some internals exposed. 30 */ 31 32 class LagPool 33 { 34 float m_pool = 15.0f; 35 float m_max = 15.0f; 36 37 public: 38 LagPool() = default; 39 setMax(float new_max)40 void setMax(float new_max) 41 { 42 m_max = new_max; 43 if (m_pool > new_max) 44 m_pool = new_max; 45 } 46 add(float dtime)47 void add(float dtime) 48 { 49 m_pool -= dtime; 50 if (m_pool < 0) 51 m_pool = 0; 52 } 53 empty()54 void empty() { m_pool = m_max; } 55 grab(float dtime)56 bool grab(float dtime) 57 { 58 if (dtime <= 0) 59 return true; 60 if (m_pool + dtime > m_max) 61 return false; 62 m_pool += dtime; 63 return true; 64 } 65 }; 66 67 class RemotePlayer; 68 69 class PlayerSAO : public UnitSAO 70 { 71 public: 72 PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, session_t peer_id_, 73 bool is_singleplayer); 74 getType()75 ActiveObjectType getType() const { return ACTIVEOBJECT_TYPE_PLAYER; } getSendType()76 ActiveObjectType getSendType() const { return ACTIVEOBJECT_TYPE_GENERIC; } 77 std::string getDescription(); 78 79 /* 80 Active object <-> environment interface 81 */ 82 83 void addedToEnvironment(u32 dtime_s); 84 void removingFromEnvironment(); isStaticAllowed()85 bool isStaticAllowed() const { return false; } shouldUnload()86 bool shouldUnload() const { return false; } 87 std::string getClientInitializationData(u16 protocol_version); 88 void getStaticData(std::string *result) const; 89 void step(float dtime, bool send_recommended); 90 void setBasePosition(const v3f &position); 91 void setPos(const v3f &pos); 92 void moveTo(v3f pos, bool continuous); 93 void setPlayerYaw(const float yaw); 94 // Data should not be sent at player initialization 95 void setPlayerYawAndSend(const float yaw); 96 void setLookPitch(const float pitch); 97 // Data should not be sent at player initialization 98 void setLookPitchAndSend(const float pitch); getLookPitch()99 f32 getLookPitch() const { return m_pitch; } getRadLookPitch()100 f32 getRadLookPitch() const { return m_pitch * core::DEGTORAD; } 101 // Deprecated getRadLookPitchDep()102 f32 getRadLookPitchDep() const { return -1.0 * m_pitch * core::DEGTORAD; } 103 void setFov(const float pitch); getFov()104 f32 getFov() const { return m_fov; } 105 void setWantedRange(const s16 range); getWantedRange()106 s16 getWantedRange() const { return m_wanted_range; } 107 108 /* 109 Interaction interface 110 */ 111 112 u16 punch(v3f dir, const ToolCapabilities *toolcap, ServerActiveObject *puncher, 113 float time_from_last_punch); 114 void rightClick(ServerActiveObject *clicker); 115 void setHP(s32 hp, const PlayerHPChangeReason &reason); setHPRaw(u16 hp)116 void setHPRaw(u16 hp) { m_hp = hp; } getBreath()117 u16 getBreath() const { return m_breath; } 118 void setBreath(const u16 breath, bool send = true); 119 120 /* 121 Inventory interface 122 */ 123 Inventory *getInventory() const; 124 InventoryLocation getInventoryLocation() const; setInventoryModified()125 void setInventoryModified() {} getWieldList()126 std::string getWieldList() const { return "main"; } 127 u16 getWieldIndex() const; 128 ItemStack getWieldedItem(ItemStack *selected, ItemStack *hand = nullptr) const; 129 bool setWieldedItem(const ItemStack &item); 130 131 /* 132 PlayerSAO-specific 133 */ 134 135 void disconnected(); 136 getPlayer()137 RemotePlayer *getPlayer() { return m_player; } getPeerID()138 session_t getPeerID() const { return m_peer_id; } 139 140 // Cheat prevention 141 getLastGoodPosition()142 v3f getLastGoodPosition() const { return m_last_good_position; } resetTimeFromLastPunch()143 float resetTimeFromLastPunch() 144 { 145 float r = m_time_from_last_punch; 146 m_time_from_last_punch = 0.0; 147 return r; 148 } noCheatDigStart(const v3s16 & p)149 void noCheatDigStart(const v3s16 &p) 150 { 151 m_nocheat_dig_pos = p; 152 m_nocheat_dig_time = 0; 153 } getNoCheatDigPos()154 v3s16 getNoCheatDigPos() { return m_nocheat_dig_pos; } getNoCheatDigTime()155 float getNoCheatDigTime() { return m_nocheat_dig_time; } noCheatDigEnd()156 void noCheatDigEnd() { m_nocheat_dig_pos = v3s16(32767, 32767, 32767); } getDigPool()157 LagPool &getDigPool() { return m_dig_pool; } 158 void setMaxSpeedOverride(const v3f &vel); 159 // Returns true if cheated 160 bool checkMovementCheat(); 161 162 // Other 163 updatePrivileges(const std::set<std::string> & privs,bool is_singleplayer)164 void updatePrivileges(const std::set<std::string> &privs, bool is_singleplayer) 165 { 166 m_privs = privs; 167 m_is_singleplayer = is_singleplayer; 168 } 169 170 bool getCollisionBox(aabb3f *toset) const; 171 bool getSelectionBox(aabb3f *toset) const; collideWithObjects()172 bool collideWithObjects() const { return true; } 173 174 void finalize(RemotePlayer *player, const std::set<std::string> &privs); 175 getEyePosition()176 v3f getEyePosition() const { return m_base_position + getEyeOffset(); } 177 v3f getEyeOffset() const; 178 float getZoomFOV() const; 179 getMeta()180 inline Metadata &getMeta() { return m_meta; } 181 182 private: 183 std::string getPropertyPacket(); 184 void unlinkPlayerSessionAndSave(); 185 std::string generateUpdatePhysicsOverrideCommand() const; 186 187 RemotePlayer *m_player = nullptr; 188 session_t m_peer_id = 0; 189 190 // Cheat prevention 191 LagPool m_dig_pool; 192 LagPool m_move_pool; 193 v3f m_last_good_position; 194 float m_time_from_last_teleport = 0.0f; 195 float m_time_from_last_punch = 0.0f; 196 v3s16 m_nocheat_dig_pos = v3s16(32767, 32767, 32767); 197 float m_nocheat_dig_time = 0.0f; 198 float m_max_speed_override_time = 0.0f; 199 v3f m_max_speed_override = v3f(0.0f, 0.0f, 0.0f); 200 201 // Timers 202 IntervalLimiter m_breathing_interval; 203 IntervalLimiter m_drowning_interval; 204 IntervalLimiter m_node_hurt_interval; 205 206 bool m_position_not_sent = false; 207 208 // Cached privileges for enforcement 209 std::set<std::string> m_privs; 210 bool m_is_singleplayer; 211 212 u16 m_breath = PLAYER_MAX_BREATH_DEFAULT; 213 f32 m_pitch = 0.0f; 214 f32 m_fov = 0.0f; 215 s16 m_wanted_range = 0.0f; 216 217 Metadata m_meta; 218 219 public: 220 float m_physics_override_speed = 1.0f; 221 float m_physics_override_jump = 1.0f; 222 float m_physics_override_gravity = 1.0f; 223 bool m_physics_override_sneak = true; 224 bool m_physics_override_sneak_glitch = false; 225 bool m_physics_override_new_move = true; 226 bool m_physics_override_sent = false; 227 }; 228 229 struct PlayerHPChangeReason 230 { 231 enum Type : u8 232 { 233 SET_HP, 234 PLAYER_PUNCH, 235 FALL, 236 NODE_DAMAGE, 237 DROWNING, 238 RESPAWN 239 }; 240 241 Type type = SET_HP; 242 bool from_mod = false; 243 int lua_reference = -1; 244 245 // For PLAYER_PUNCH 246 ServerActiveObject *object = nullptr; 247 // For NODE_DAMAGE 248 std::string node; 249 hasLuaReferencePlayerHPChangeReason250 inline bool hasLuaReference() const { return lua_reference >= 0; } 251 setTypeFromStringPlayerHPChangeReason252 bool setTypeFromString(const std::string &typestr) 253 { 254 if (typestr == "set_hp") 255 type = SET_HP; 256 else if (typestr == "punch") 257 type = PLAYER_PUNCH; 258 else if (typestr == "fall") 259 type = FALL; 260 else if (typestr == "node_damage") 261 type = NODE_DAMAGE; 262 else if (typestr == "drown") 263 type = DROWNING; 264 else if (typestr == "respawn") 265 type = RESPAWN; 266 else 267 return false; 268 269 return true; 270 } 271 getTypeAsStringPlayerHPChangeReason272 std::string getTypeAsString() const 273 { 274 switch (type) { 275 case PlayerHPChangeReason::SET_HP: 276 return "set_hp"; 277 case PlayerHPChangeReason::PLAYER_PUNCH: 278 return "punch"; 279 case PlayerHPChangeReason::FALL: 280 return "fall"; 281 case PlayerHPChangeReason::NODE_DAMAGE: 282 return "node_damage"; 283 case PlayerHPChangeReason::DROWNING: 284 return "drown"; 285 case PlayerHPChangeReason::RESPAWN: 286 return "respawn"; 287 default: 288 return "?"; 289 } 290 } 291 PlayerHPChangeReasonPlayerHPChangeReason292 PlayerHPChangeReason(Type type) : type(type) {} 293 PlayerHPChangeReasonPlayerHPChangeReason294 PlayerHPChangeReason(Type type, ServerActiveObject *object) : 295 type(type), object(object) 296 { 297 } 298 PlayerHPChangeReasonPlayerHPChangeReason299 PlayerHPChangeReason(Type type, std::string node) : type(type), node(node) {} 300 }; 301