From 52ba1f867e5edb579a59a44fbb8286d4f1e54931 Mon Sep 17 00:00:00 2001 From: Loic Blot Date: Sun, 1 Jan 2017 16:13:01 +0100 Subject: [PATCH] Breath cheat fix: server side Breath is now handled server side. Changing this behaviour required some modifications to core: * Ignore TOSERVER_BREATH package, marking it as obsolete * Clients doesn't send the breath to server anymore * Use PlayerSAO pointer instead of peer_id in Server::SendPlayerBreath to prevent a useless lookup (little perf gain) * drop a useless static_cast in emergePlayer --- src/client.cpp | 11 ++-- src/content_sao.cpp | 39 ++++++++++++-- src/content_sao.h | 7 ++- src/environment.cpp | 84 ++++++++++++++--------------- src/network/clientopcodes.cpp | 2 +- src/network/networkprotocol.h | 6 ++- src/network/serveropcodes.cpp | 2 +- src/network/serverpackethandler.cpp | 40 -------------- src/remoteplayer.cpp | 2 +- src/script/lua_api/l_object.cpp | 5 -- src/server.cpp | 15 +++--- src/server.h | 3 +- src/unittest/test_player.cpp | 4 +- 13 files changed, 107 insertions(+), 113 deletions(-) diff --git a/src/client.cpp b/src/client.cpp index 5476aad0e..1446ebad8 100644 --- a/src/client.cpp +++ b/src/client.cpp @@ -499,9 +499,10 @@ void Client::step(float dtime) m_client_event_queue.push(event); } } - else if(event.type == CEE_PLAYER_BREATH) { - u16 breath = event.player_breath.amount; - sendBreath(breath); + // Protocol v29 or greater obsoleted this event + else if (event.type == CEE_PLAYER_BREATH && m_proto_ver < 29) { + u16 breath = event.player_breath.amount; + sendBreath(breath); } } @@ -1270,6 +1271,10 @@ void Client::sendBreath(u16 breath) { DSTACK(FUNCTION_NAME); + // Protocol v29 make this obsolete + if (m_proto_ver >= 29) + return; + NetworkPacket pkt(TOSERVER_BREATH, sizeof(u16)); pkt << breath; Send(&pkt); diff --git a/src/content_sao.cpp b/src/content_sao.cpp index 77ab51a02..f866d4372 100644 --- a/src/content_sao.cpp +++ b/src/content_sao.cpp @@ -26,6 +26,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "serialization.h" // For compressZlib #include "tool.h" // For ToolCapabilities #include "gamedef.h" +#include "nodedef.h" #include "remoteplayer.h" #include "server.h" #include "scripting_game.h" @@ -940,8 +941,35 @@ bool PlayerSAO::isAttached() void PlayerSAO::step(float dtime, bool send_recommended) { - if(!m_properties_sent) - { + if (m_drowning_interval.step(dtime, 2.0)) { + // get head position + v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_env->getMap().getNodeNoEx(p); + const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n); + // If node generates drown + if (c.drowning > 0) { + if (m_hp > 0 && m_breath > 0) + setBreath(m_breath - 1); + + // No more breath, damage player + if (m_breath == 0) { + setHP(m_hp - c.drowning); + ((Server*) m_env->getGameDef())->SendPlayerHPOrDie(this); + } + } + } + + if (m_breathing_interval.step(dtime, 0.5)) { + // get head position + v3s16 p = floatToInt(m_base_position + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_env->getMap().getNodeNoEx(p); + const ContentFeatures &c = ((Server*) m_env->getGameDef())->ndef()->get(n); + // If player is alive & no drowning, breath + if (m_hp > 0 && c.drowning == 0) + setBreath(m_breath + 1); + } + + if (!m_properties_sent) { m_properties_sent = true; std::string str = getPropertyPacket(); // create message and add to list @@ -1237,12 +1265,15 @@ void PlayerSAO::setHP(s16 hp) m_properties_sent = false; } -void PlayerSAO::setBreath(const u16 breath) +void PlayerSAO::setBreath(const u16 breath, bool send) { if (m_player && breath != m_breath) m_player->setDirty(true); - m_breath = breath; + m_breath = MYMIN(breath, PLAYER_MAX_BREATH); + + if (send) + ((Server *) m_env->getGameDef())->SendPlayerBreath(this); } void PlayerSAO::setArmorGroups(const ItemGroupList &armor_groups) diff --git a/src/content_sao.h b/src/content_sao.h index 86255183d..9c66068b3 100644 --- a/src/content_sao.h +++ b/src/content_sao.h @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #ifndef CONTENT_SAO_HEADER #define CONTENT_SAO_HEADER +#include #include "serverobject.h" #include "itemgroup.h" #include "object_properties.h" @@ -232,7 +233,7 @@ public: void setHPRaw(s16 hp) { m_hp = hp; } s16 readDamage(); u16 getBreath() const { return m_breath; } - void setBreath(const u16 breath); + void setBreath(const u16 breath, bool send = true); void setArmorGroups(const ItemGroupList &armor_groups); ItemGroupList getArmorGroups(); void setAnimation(v2f frame_range, float frame_speed, float frame_blend, bool frame_loop); @@ -339,6 +340,10 @@ private: v3s16 m_nocheat_dig_pos; float m_nocheat_dig_time; + // Timers + IntervalLimiter m_breathing_interval; + IntervalLimiter m_drowning_interval; + int m_wield_index; bool m_position_not_sent; ItemGroupList m_armor_groups; diff --git a/src/environment.cpp b/src/environment.cpp index 707d89659..ac9b5b079 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -2511,52 +2511,52 @@ void ClientEnvironment::step(float dtime) } } - /* - Drowning - */ - if(m_drowning_interval.step(dtime, 2.0)) - { - v3f pf = lplayer->getPosition(); + // Protocol v29 make this behaviour obsolete + if (((Client*) getGameDef())->getProtoVersion() < 29) { + /* + Drowning + */ + if (m_drowning_interval.step(dtime, 2.0)) { + v3f pf = lplayer->getPosition(); - // head - v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); - MapNode n = m_map->getNodeNoEx(p); - ContentFeatures c = m_gamedef->ndef()->get(n); - u8 drowning_damage = c.drowning; - if(drowning_damage > 0 && lplayer->hp > 0){ - u16 breath = lplayer->getBreath(); - if(breath > 10){ - breath = 11; - } - if(breath > 0){ - breath -= 1; - } - lplayer->setBreath(breath); - updateLocalPlayerBreath(breath); - } - - if(lplayer->getBreath() == 0 && drowning_damage > 0){ - damageLocalPlayer(drowning_damage, true); - } - } - if(m_breathing_interval.step(dtime, 0.5)) - { - v3f pf = lplayer->getPosition(); - - // head - v3s16 p = floatToInt(pf + v3f(0, BS*1.6, 0), BS); - MapNode n = m_map->getNodeNoEx(p); - ContentFeatures c = m_gamedef->ndef()->get(n); - if (!lplayer->hp){ - lplayer->setBreath(11); - } - else if(c.drowning == 0){ - u16 breath = lplayer->getBreath(); - if(breath <= 10){ - breath += 1; + // head + v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + u8 drowning_damage = c.drowning; + if (drowning_damage > 0 && lplayer->hp > 0) { + u16 breath = lplayer->getBreath(); + if (breath > 10) { + breath = 11; + } + if (breath > 0) { + breath -= 1; + } lplayer->setBreath(breath); updateLocalPlayerBreath(breath); } + + if (lplayer->getBreath() == 0 && drowning_damage > 0) { + damageLocalPlayer(drowning_damage, true); + } + } + if (m_breathing_interval.step(dtime, 0.5)) { + v3f pf = lplayer->getPosition(); + + // head + v3s16 p = floatToInt(pf + v3f(0, BS * 1.6, 0), BS); + MapNode n = m_map->getNodeNoEx(p); + ContentFeatures c = m_gamedef->ndef()->get(n); + if (!lplayer->hp) { + lplayer->setBreath(11); + } else if (c.drowning == 0) { + u16 breath = lplayer->getBreath(); + if (breath <= 10) { + breath += 1; + lplayer->setBreath(breath); + updateLocalPlayerBreath(breath); + } + } } } diff --git a/src/network/clientopcodes.cpp b/src/network/clientopcodes.cpp index 3364de8c5..6defdcf1b 100644 --- a/src/network/clientopcodes.cpp +++ b/src/network/clientopcodes.cpp @@ -193,7 +193,7 @@ const ServerCommandFactory serverCommandFactoryTable[TOSERVER_NUM_MSG_TYPES] = null_command_factory, // 0x3f { "TOSERVER_REQUEST_MEDIA", 1, true }, // 0x40 { "TOSERVER_RECEIVED_MEDIA", 1, true }, // 0x41 - { "TOSERVER_BREATH", 0, true }, // 0x42 + null_command_factory, // 0x42 old TOSERVER_BREATH. Ignored by servers { "TOSERVER_CLIENT_READY", 0, true }, // 0x43 null_command_factory, // 0x44 null_command_factory, // 0x45 diff --git a/src/network/networkprotocol.h b/src/network/networkprotocol.h index 018b392b6..f65167380 100644 --- a/src/network/networkprotocol.h +++ b/src/network/networkprotocol.h @@ -138,9 +138,11 @@ with this program; if not, write to the Free Software Foundation, Inc., Add nodedef v3 - connected nodeboxes PROTOCOL_VERSION 28: CPT2_MESHOPTIONS + PROTOCOL_VERSION 29: + Server doesn't accept TOSERVER_BREATH anymore */ -#define LATEST_PROTOCOL_VERSION 28 +#define LATEST_PROTOCOL_VERSION 29 // Server's supported network protocol range #define SERVER_PROTOCOL_VERSION_MIN 13 @@ -833,7 +835,7 @@ enum ToServerCommand */ - TOSERVER_BREATH = 0x42, + TOSERVER_BREATH = 0x42, // Obsolete /* u16 breath */ diff --git a/src/network/serveropcodes.cpp b/src/network/serveropcodes.cpp index 9b14a1be3..642dd376a 100644 --- a/src/network/serveropcodes.cpp +++ b/src/network/serveropcodes.cpp @@ -90,7 +90,7 @@ const ToServerCommandHandler toServerCommandTable[TOSERVER_NUM_MSG_TYPES] = null_command_handler, // 0x3f { "TOSERVER_REQUEST_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_RequestMedia }, // 0x40 { "TOSERVER_RECEIVED_MEDIA", TOSERVER_STATE_STARTUP, &Server::handleCommand_ReceivedMedia }, // 0x41 - { "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Breath }, // 0x42 + { "TOSERVER_BREATH", TOSERVER_STATE_INGAME, &Server::handleCommand_Deprecated }, // 0x42 Old breath model which is now deprecated for anticheating { "TOSERVER_CLIENT_READY", TOSERVER_STATE_STARTUP, &Server::handleCommand_ClientReady }, // 0x43 null_command_handler, // 0x44 null_command_handler, // 0x45 diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index d0f4d948d..eeabcca71 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1136,46 +1136,6 @@ void Server::handleCommand_Damage(NetworkPacket* pkt) } } -void Server::handleCommand_Breath(NetworkPacket* pkt) -{ - u16 breath; - - *pkt >> breath; - - RemotePlayer *player = m_env->getPlayer(pkt->getPeerId()); - - if (player == NULL) { - errorstream << "Server::ProcessData(): Canceling: " - "No player for peer_id=" << pkt->getPeerId() - << " disconnecting peer!" << std::endl; - m_con.DisconnectPeer(pkt->getPeerId()); - return; - } - - - PlayerSAO *playersao = player->getPlayerSAO(); - if (playersao == NULL) { - errorstream << "Server::ProcessData(): Canceling: " - "No player object for peer_id=" << pkt->getPeerId() - << " disconnecting peer!" << std::endl; - m_con.DisconnectPeer(pkt->getPeerId()); - return; - } - - /* - * If player is dead, we don't need to update the breath - * He is dead ! - */ - if (playersao->isDead()) { - verbosestream << "TOSERVER_BREATH: " << player->getName() - << " is dead. Ignoring packet"; - return; - } - - playersao->setBreath(breath); - SendPlayerBreath(pkt->getPeerId()); -} - void Server::handleCommand_Password(NetworkPacket* pkt) { if (pkt->getSize() != PASSWORD_SIZE * 2) diff --git a/src/remoteplayer.cpp b/src/remoteplayer.cpp index 67ab89113..18bfa1030 100644 --- a/src/remoteplayer.cpp +++ b/src/remoteplayer.cpp @@ -148,7 +148,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername, } catch (SettingNotFoundException &e) {} try { - sao->setBreath(args.getS32("breath")); + sao->setBreath(args.getS32("breath"), false); } catch (SettingNotFoundException &e) {} } diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 2a8b8a64e..cfdceb28e 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -1152,13 +1152,8 @@ int ObjectRef::l_set_breath(lua_State *L) PlayerSAO* co = getplayersao(ref); if (co == NULL) return 0; u16 breath = luaL_checknumber(L, 2); - // Do it co->setBreath(breath); - // If the object is a player sent the breath to client - if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) - getServer(L)->SendPlayerBreath(((PlayerSAO*)co)->getPeerID()); - return 0; } diff --git a/src/server.cpp b/src/server.cpp index fa7a838d4..60dbef0d2 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -1076,8 +1076,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id) } m_clients.unlock(); - RemotePlayer *player = - static_cast(m_env->getPlayer(playername.c_str())); + RemotePlayer *player = m_env->getPlayer(playername.c_str()); // If failed, cancel if ((playersao == NULL) || (player == NULL)) { @@ -1113,7 +1112,7 @@ PlayerSAO* Server::StageTwoClientInit(u16 peer_id) SendPlayerHPOrDie(playersao); // Send Breath - SendPlayerBreath(peer_id); + SendPlayerBreath(playersao); // Show death screen if necessary if (playersao->isDead()) @@ -1857,14 +1856,13 @@ void Server::SendPlayerHP(u16 peer_id) playersao->m_messages_out.push(aom); } -void Server::SendPlayerBreath(u16 peer_id) +void Server::SendPlayerBreath(PlayerSAO *sao) { DSTACK(FUNCTION_NAME); - PlayerSAO *playersao = getPlayerSAO(peer_id); - assert(playersao); + assert(sao); - m_script->player_event(playersao, "breath_changed"); - SendBreath(peer_id, playersao->getBreath()); + m_script->player_event(sao, "breath_changed"); + SendBreath(sao->getPeerID(), sao->getBreath()); } void Server::SendMovePlayer(u16 peer_id) @@ -2565,7 +2563,6 @@ void Server::RespawnPlayer(u16 peer_id) } SendPlayerHP(peer_id); - SendPlayerBreath(peer_id); } diff --git a/src/server.h b/src/server.h index cab7e2445..f0df0f9ec 100644 --- a/src/server.h +++ b/src/server.h @@ -180,7 +180,6 @@ public: void handleCommand_InventoryAction(NetworkPacket* pkt); void handleCommand_ChatMessage(NetworkPacket* pkt); void handleCommand_Damage(NetworkPacket* pkt); - void handleCommand_Breath(NetworkPacket* pkt); void handleCommand_Password(NetworkPacket* pkt); void handleCommand_PlayerItem(NetworkPacket* pkt); void handleCommand_Respawn(NetworkPacket* pkt); @@ -358,7 +357,7 @@ public: void printToConsoleOnly(const std::string &text); void SendPlayerHPOrDie(PlayerSAO *player); - void SendPlayerBreath(u16 peer_id); + void SendPlayerBreath(PlayerSAO *sao); void SendInventory(PlayerSAO* playerSAO); void SendMovePlayer(u16 peer_id); diff --git a/src/unittest/test_player.cpp b/src/unittest/test_player.cpp index 85fbc8b2d..655ee08fd 100644 --- a/src/unittest/test_player.cpp +++ b/src/unittest/test_player.cpp @@ -49,7 +49,7 @@ void TestPlayer::testSave(IGameDef *gamedef) PlayerSAO sao(NULL, 1, false); sao.initialize(&rplayer, std::set()); rplayer.setPlayerSAO(&sao); - sao.setBreath(10); + sao.setBreath(10, false); sao.setHPRaw(8); sao.setYaw(0.1f); sao.setPitch(0.6f); @@ -64,7 +64,7 @@ void TestPlayer::testLoad(IGameDef *gamedef) PlayerSAO sao(NULL, 1, false); sao.initialize(&rplayer, std::set()); rplayer.setPlayerSAO(&sao); - sao.setBreath(10); + sao.setBreath(10, false); sao.setHPRaw(8); sao.setYaw(0.1f); sao.setPitch(0.6f);