Server-side checking of digging; disable_anticheat setting
parent
b0ba05c9ac
commit
2795f44f03
|
@ -158,6 +158,8 @@
|
|||
#static_spawnpoint = 0, 10, 0
|
||||
# If true, new players cannot join with an empty password
|
||||
#disallow_empty_password = false
|
||||
# If true, disable cheat prevention in multiplayer
|
||||
#disable_anticheat = false
|
||||
|
||||
# Profiler data print interval. #0 = disable.
|
||||
#profiler_print_interval = 0
|
||||
|
|
|
@ -764,6 +764,8 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, Player *player_, u16 peer_id_,
|
|||
m_last_good_position(0,0,0),
|
||||
m_last_good_position_age(0),
|
||||
m_time_from_last_punch(0),
|
||||
m_nocheat_dig_pos(32767, 32767, 32767),
|
||||
m_nocheat_dig_time(0),
|
||||
m_wield_index(0),
|
||||
m_position_not_sent(false),
|
||||
m_armor_groups_sent(false),
|
||||
|
@ -874,8 +876,9 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
|||
}
|
||||
|
||||
m_time_from_last_punch += dtime;
|
||||
m_nocheat_dig_time += dtime;
|
||||
|
||||
if(m_is_singleplayer)
|
||||
if(m_is_singleplayer || g_settings->getBool("disable_anticheat"))
|
||||
{
|
||||
m_last_good_position = m_player->getPosition();
|
||||
m_last_good_position_age = 0;
|
||||
|
@ -888,7 +891,8 @@ void PlayerSAO::step(float dtime, bool send_recommended)
|
|||
NOTE: Actually the server should handle player physics like the
|
||||
client does and compare player's position to what is calculated
|
||||
on our side. This is required when eg. players fly due to an
|
||||
explosion.
|
||||
explosion. Altough a node-based alternative might be possible
|
||||
too, and much more lightweight.
|
||||
*/
|
||||
|
||||
float player_max_speed = 0;
|
||||
|
|
|
@ -173,6 +173,9 @@ public:
|
|||
{
|
||||
return m_peer_id;
|
||||
}
|
||||
|
||||
// Cheat prevention
|
||||
|
||||
v3f getLastGoodPosition() const
|
||||
{
|
||||
return m_last_good_position;
|
||||
|
@ -183,6 +186,26 @@ public:
|
|||
m_time_from_last_punch = 0.0;
|
||||
return r;
|
||||
}
|
||||
void noCheatDigStart(v3s16 p)
|
||||
{
|
||||
m_nocheat_dig_pos = p;
|
||||
m_nocheat_dig_time = 0;
|
||||
}
|
||||
v3s16 getNoCheatDigPos()
|
||||
{
|
||||
return m_nocheat_dig_pos;
|
||||
}
|
||||
float getNoCheatDigTime()
|
||||
{
|
||||
return m_nocheat_dig_time;
|
||||
}
|
||||
void noCheatDigEnd()
|
||||
{
|
||||
m_nocheat_dig_pos = v3s16(32767, 32767, 32767);
|
||||
}
|
||||
|
||||
// Other
|
||||
|
||||
void updatePrivileges(const std::set<std::string> &privs,
|
||||
bool is_singleplayer)
|
||||
{
|
||||
|
@ -196,9 +219,14 @@ private:
|
|||
Player *m_player;
|
||||
u16 m_peer_id;
|
||||
Inventory *m_inventory;
|
||||
|
||||
// Cheat prevention
|
||||
v3f m_last_good_position;
|
||||
float m_last_good_position_age;
|
||||
float m_time_from_last_punch;
|
||||
v3s16 m_nocheat_dig_pos;
|
||||
float m_nocheat_dig_time;
|
||||
|
||||
int m_wield_index;
|
||||
bool m_position_not_sent;
|
||||
ItemGroupList m_armor_groups;
|
||||
|
|
|
@ -121,6 +121,7 @@ void set_default_settings(Settings *settings)
|
|||
settings->setDefault("unlimited_player_transfer_distance", "true");
|
||||
settings->setDefault("enable_pvp", "true");
|
||||
settings->setDefault("disallow_empty_password", "false");
|
||||
settings->setDefault("disable_anticheat", "false");
|
||||
|
||||
settings->setDefault("profiler_print_interval", "0");
|
||||
settings->setDefault("enable_mapgen_debug_info", "false");
|
||||
|
|
|
@ -2113,6 +2113,8 @@ void the_game(
|
|||
}
|
||||
MapNode n = client.getEnv().getClientMap().getNode(nodepos);
|
||||
|
||||
// NOTE: Similar piece of code exists on the server side for
|
||||
// cheat detection.
|
||||
// Get digging parameters
|
||||
DigParams params = getDigParams(nodedef->get(n).groups,
|
||||
&playeritem_toolcap);
|
||||
|
|
|
@ -3014,6 +3014,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
}
|
||||
if(n.getContent() != CONTENT_IGNORE)
|
||||
scriptapi_node_on_punch(m_lua, p_under, n, playersao);
|
||||
// Cheat prevention
|
||||
playersao->noCheatDigStart(p_under);
|
||||
}
|
||||
else if(pointed.type == POINTEDTHING_OBJECT)
|
||||
{
|
||||
|
@ -3051,7 +3053,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
*/
|
||||
else if(action == 2)
|
||||
{
|
||||
// Only complete digging of nodes
|
||||
// Only digging of nodes
|
||||
if(pointed.type == POINTEDTHING_NODE)
|
||||
{
|
||||
MapNode n(CONTENT_IGNORE);
|
||||
|
@ -3067,10 +3069,65 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||
m_emerge_queue.addBlock(peer_id,
|
||||
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
|
||||
}
|
||||
if(n.getContent() != CONTENT_IGNORE)
|
||||
|
||||
/* Cheat prevention */
|
||||
bool is_valid_dig = true;
|
||||
if(!isSingleplayer() && !g_settings->getBool("disable_anticheat"))
|
||||
{
|
||||
v3s16 nocheat_p = playersao->getNoCheatDigPos();
|
||||
float nocheat_t = playersao->getNoCheatDigTime();
|
||||
playersao->noCheatDigEnd();
|
||||
// If player didn't start digging this, ignore dig
|
||||
if(nocheat_p != p_under){
|
||||
infostream<<"Server: NoCheat: "<<player->getName()
|
||||
<<" started digging "
|
||||
<<PP(nocheat_p)<<" and completed digging "
|
||||
<<PP(p_under)<<"; not digging."<<std::endl;
|
||||
is_valid_dig = false;
|
||||
}
|
||||
// Get player's wielded item
|
||||
ItemStack playeritem;
|
||||
InventoryList *mlist = playersao->getInventory()->getList("main");
|
||||
if(mlist != NULL)
|
||||
playeritem = mlist->getItem(playersao->getWieldIndex());
|
||||
ToolCapabilities playeritem_toolcap =
|
||||
playeritem.getToolCapabilities(m_itemdef);
|
||||
// Get diggability and expected digging time
|
||||
DigParams params = getDigParams(m_nodedef->get(n).groups,
|
||||
&playeritem_toolcap);
|
||||
// If can't dig, try hand
|
||||
if(!params.diggable){
|
||||
const ItemDefinition &hand = m_itemdef->get("");
|
||||
const ToolCapabilities *tp = hand.tool_capabilities;
|
||||
if(tp)
|
||||
params = getDigParams(m_nodedef->get(n).groups, tp);
|
||||
}
|
||||
// If can't dig, ignore dig
|
||||
if(!params.diggable){
|
||||
infostream<<"Server: NoCheat: "<<player->getName()
|
||||
<<" completed digging "<<PP(p_under)
|
||||
<<", which is not diggable with tool. not digging."
|
||||
<<std::endl;
|
||||
is_valid_dig = false;
|
||||
}
|
||||
// If time is considerably too short, ignore dig
|
||||
// Check time only for medium and slow timed digs
|
||||
if(params.diggable && params.time > 0.3 && nocheat_t < 0.5 * params.time){
|
||||
infostream<<"Server: NoCheat: "<<player->getName()
|
||||
<<" completed digging "
|
||||
<<PP(p_under)<<" in "<<nocheat_t<<"s; expected "
|
||||
<<params.time<<"s; not digging."<<std::endl;
|
||||
is_valid_dig = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Actually dig node */
|
||||
|
||||
if(is_valid_dig && n.getContent() != CONTENT_IGNORE)
|
||||
scriptapi_node_on_dig(m_lua, p_under, n, playersao);
|
||||
|
||||
if (m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
|
||||
// Send unusual result (that is, node not being removed)
|
||||
if(m_env->getMap().getNodeNoEx(p_under).getContent() != CONTENT_AIR)
|
||||
{
|
||||
// Re-send block to revert change on client-side
|
||||
RemoteClient *client = getClient(peer_id);
|
||||
|
|
Loading…
Reference in New Issue