From b16252dcae8c6b0e79c20fa4c3cbddc37ad377cb Mon Sep 17 00:00:00 2001 From: sfan5 Date: Thu, 22 Dec 2016 19:29:15 +0100 Subject: [PATCH] Various anticheat improvements * Calculate maximum interact distance from wielded tool * New "interacted_while_dead" cheat_type for the Lua API * Disallow dropping items while dead * Move player to spawn before resurrecting them --- doc/lua_api.txt | 7 ++- src/network/serverpackethandler.cpp | 86 ++++++++++++++++++----------- src/server.cpp | 8 +-- 3 files changed, 61 insertions(+), 40 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 34c64b8df..d2ddc635b 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2036,9 +2036,10 @@ Call these functions only at load time! * `minetest.register_on_cheat(func(ObjectRef, cheat))` * Called when a player cheats * `cheat`: `{type=}`, where `` is one of: - * `"moved_too_fast"` - * `"interacted_too_far"` - * `"finished_unknown_dig"` + * `moved_too_fast` + * `interacted_too_far` + * `interacted_while_dead` + * `finished_unknown_dig` * `dug_unbreakable` * `dug_too_fast` * `minetest.register_on_chat_message(func(name, message))` diff --git a/src/network/serverpackethandler.cpp b/src/network/serverpackethandler.cpp index dca9aabc4..f99e104ec 100644 --- a/src/network/serverpackethandler.cpp +++ b/src/network/serverpackethandler.cpp @@ -1021,6 +1021,15 @@ void Server::handleCommand_InventoryAction(NetworkPacket* pkt) delete a; return; } + + // Disallow dropping items if dead + if (playersao->isDead()) { + infostream << "Ignoring IDropAction from " + << (da->from_inv.dump()) << ":" << da->from_list + << " because player is dead." << std::endl; + delete a; + return; + } } /* Handle restrictions and special cases of the craft action @@ -1313,6 +1322,7 @@ void Server::handleCommand_Interact(NetworkPacket* pkt) 2: digging completed 3: place block or item (to abovesurface) 4: use item + 5: rightclick air ("activate") */ u8 action; u16 item_i; @@ -1345,8 +1355,16 @@ void Server::handleCommand_Interact(NetworkPacket* pkt) } if (playersao->isDead()) { - verbosestream << "TOSERVER_INTERACT: " << player->getName() - << " is dead. Ignoring packet"; + actionstream << "Server: NoCheat: " << player->getName() + << " tried to interact while dead; ignoring." << std::endl; + if (pointed.type == POINTEDTHING_NODE) { + // Re-send block to revert change on client-side + RemoteClient *client = getClient(pkt->getPeerId()); + v3s16 blockpos = getNodeBlockPos(pointed.node_undersurface); + client->SetBlockNotSent(blockpos); + } + // Call callbacks + m_script->on_cheat(playersao, "interacted_while_dead"); return; } @@ -1384,32 +1402,6 @@ void Server::handleCommand_Interact(NetworkPacket* pkt) pointed_pos_above = pointed_pos_under; } - /* - Check that target is reasonably close - (only when digging or placing things) - */ - static const bool enable_anticheat = !g_settings->getBool("disable_anticheat"); - if ((action == 0 || action == 2 || action == 3) && - (enable_anticheat && !isSingleplayer())) { - float d = player_pos.getDistanceFrom(pointed_pos_under); - float max_d = BS * 14; // Just some large enough value - if (d > max_d) { - actionstream << "Player " << player->getName() - << " tried to access " << pointed.dump() - << " from too far: " - << "d=" << d <<", max_d=" << max_d - << ". ignoring." << std::endl; - // Re-send block to revert change on client-side - RemoteClient *client = getClient(pkt->getPeerId()); - v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); - client->SetBlockNotSent(blockpos); - // Call callbacks - m_script->on_cheat(playersao, "interacted_too_far"); - // Do nothing else - return; - } - } - /* Make sure the player is allowed to do it */ @@ -1432,6 +1424,39 @@ void Server::handleCommand_Interact(NetworkPacket* pkt) return; } + /* + Check that target is reasonably close + (only when digging or placing things) + */ + static const bool enable_anticheat = !g_settings->getBool("disable_anticheat"); + if ((action == 0 || action == 2 || action == 3 || action == 4) && + (enable_anticheat && !isSingleplayer())) { + float d = player_pos.getDistanceFrom(pointed_pos_under); + const ItemDefinition &playeritem_def = + playersao->getWieldedItem().getDefinition(m_itemdef); + float max_d = BS * playeritem_def.range; + float max_d_hand = BS * m_itemdef->get("").range; + if (max_d < 0 && max_d_hand >= 0) + max_d = max_d_hand; + else if (max_d < 0) + max_d = BS * 4.0; + if (d > max_d * 1.5) { + actionstream << "Player " << player->getName() + << " tried to access " << pointed.dump() + << " from too far: " + << "d=" << d <<", max_d=" << max_d + << ". ignoring." << std::endl; + // Re-send block to revert change on client-side + RemoteClient *client = getClient(pkt->getPeerId()); + v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS)); + client->SetBlockNotSent(blockpos); + // Call callbacks + m_script->on_cheat(playersao, "interacted_too_far"); + // Do nothing else + return; + } + } + /* If something goes wrong, this player is to blame */ @@ -1443,11 +1468,6 @@ void Server::handleCommand_Interact(NetworkPacket* pkt) */ if (action == 0) { if (pointed.type == POINTEDTHING_NODE) { - /* - NOTE: This can be used in the future to check if - somebody is cheating, by checking the timing. - */ - MapNode n(CONTENT_IGNORE); bool pos_ok; diff --git a/src/server.cpp b/src/server.cpp index c9d5c7129..fa7a838d4 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -2557,15 +2557,15 @@ void Server::RespawnPlayer(u16 peer_id) playersao->setHP(PLAYER_MAX_HP); playersao->setBreath(PLAYER_MAX_BREATH); - SendPlayerHP(peer_id); - SendPlayerBreath(peer_id); - bool repositioned = m_script->on_respawnplayer(playersao); - if(!repositioned){ + if (!repositioned) { v3f pos = findSpawnPos(); // setPos will send the new position to client playersao->setPos(pos); } + + SendPlayerHP(peer_id); + SendPlayerBreath(peer_id); }