Skip to content

Commit

Permalink
Various anticheat improvements
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
sfan5 committed Dec 26, 2016
1 parent b95f543 commit b16252d
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 39 deletions.
7 changes: 4 additions & 3 deletions doc/lua_api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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=<cheat_type>}`, where `<cheat_type>` 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))`
Expand Down
84 changes: 52 additions & 32 deletions src/network/serverpackethandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -1384,16 +1402,45 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
pointed_pos_above = pointed_pos_under;
}

/*
Make sure the player is allowed to do it
*/
if (!checkPriv(player->getName(), "interact")) {
actionstream<<player->getName()<<" attempted to interact with "
<<pointed.dump()<<" without 'interact' privilege"
<<std::endl;
// Re-send block to revert change on client-side
RemoteClient *client = getClient(pkt->getPeerId());
// Digging completed -> under
if (action == 2) {
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
client->SetBlockNotSent(blockpos);
}
// Placement -> above
if (action == 3) {
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
client->SetBlockNotSent(blockpos);
}
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) &&
if ((action == 0 || action == 2 || action == 3 || action == 4) &&
(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) {
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: "
Expand All @@ -1410,28 +1457,6 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
}
}

/*
Make sure the player is allowed to do it
*/
if (!checkPriv(player->getName(), "interact")) {
actionstream<<player->getName()<<" attempted to interact with "
<<pointed.dump()<<" without 'interact' privilege"
<<std::endl;
// Re-send block to revert change on client-side
RemoteClient *client = getClient(pkt->getPeerId());
// Digging completed -> under
if (action == 2) {
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_under, BS));
client->SetBlockNotSent(blockpos);
}
// Placement -> above
if (action == 3) {
v3s16 blockpos = getNodeBlockPos(floatToInt(pointed_pos_above, BS));
client->SetBlockNotSent(blockpos);
}
return;
}

/*
If something goes wrong, this player is to blame
*/
Expand All @@ -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;

Expand Down
8 changes: 4 additions & 4 deletions src/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}


Expand Down

0 comments on commit b16252d

Please sign in to comment.