forked from Mirrorlandia_minetest/minetest
Server-side checking of digging; disable_anticheat setting
This commit is contained in:
parent
b0ba05c9ac
commit
2795f44f03
@ -158,6 +158,8 @@
|
|||||||
#static_spawnpoint = 0, 10, 0
|
#static_spawnpoint = 0, 10, 0
|
||||||
# If true, new players cannot join with an empty password
|
# If true, new players cannot join with an empty password
|
||||||
#disallow_empty_password = false
|
#disallow_empty_password = false
|
||||||
|
# If true, disable cheat prevention in multiplayer
|
||||||
|
#disable_anticheat = false
|
||||||
|
|
||||||
# Profiler data print interval. #0 = disable.
|
# Profiler data print interval. #0 = disable.
|
||||||
#profiler_print_interval = 0
|
#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(0,0,0),
|
||||||
m_last_good_position_age(0),
|
m_last_good_position_age(0),
|
||||||
m_time_from_last_punch(0),
|
m_time_from_last_punch(0),
|
||||||
|
m_nocheat_dig_pos(32767, 32767, 32767),
|
||||||
|
m_nocheat_dig_time(0),
|
||||||
m_wield_index(0),
|
m_wield_index(0),
|
||||||
m_position_not_sent(false),
|
m_position_not_sent(false),
|
||||||
m_armor_groups_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_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 = m_player->getPosition();
|
||||||
m_last_good_position_age = 0;
|
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
|
NOTE: Actually the server should handle player physics like the
|
||||||
client does and compare player's position to what is calculated
|
client does and compare player's position to what is calculated
|
||||||
on our side. This is required when eg. players fly due to an
|
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;
|
float player_max_speed = 0;
|
||||||
|
@ -173,6 +173,9 @@ public:
|
|||||||
{
|
{
|
||||||
return m_peer_id;
|
return m_peer_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cheat prevention
|
||||||
|
|
||||||
v3f getLastGoodPosition() const
|
v3f getLastGoodPosition() const
|
||||||
{
|
{
|
||||||
return m_last_good_position;
|
return m_last_good_position;
|
||||||
@ -183,6 +186,26 @@ public:
|
|||||||
m_time_from_last_punch = 0.0;
|
m_time_from_last_punch = 0.0;
|
||||||
return r;
|
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,
|
void updatePrivileges(const std::set<std::string> &privs,
|
||||||
bool is_singleplayer)
|
bool is_singleplayer)
|
||||||
{
|
{
|
||||||
@ -196,9 +219,14 @@ private:
|
|||||||
Player *m_player;
|
Player *m_player;
|
||||||
u16 m_peer_id;
|
u16 m_peer_id;
|
||||||
Inventory *m_inventory;
|
Inventory *m_inventory;
|
||||||
|
|
||||||
|
// Cheat prevention
|
||||||
v3f m_last_good_position;
|
v3f m_last_good_position;
|
||||||
float m_last_good_position_age;
|
float m_last_good_position_age;
|
||||||
float m_time_from_last_punch;
|
float m_time_from_last_punch;
|
||||||
|
v3s16 m_nocheat_dig_pos;
|
||||||
|
float m_nocheat_dig_time;
|
||||||
|
|
||||||
int m_wield_index;
|
int m_wield_index;
|
||||||
bool m_position_not_sent;
|
bool m_position_not_sent;
|
||||||
ItemGroupList m_armor_groups;
|
ItemGroupList m_armor_groups;
|
||||||
|
@ -121,6 +121,7 @@ void set_default_settings(Settings *settings)
|
|||||||
settings->setDefault("unlimited_player_transfer_distance", "true");
|
settings->setDefault("unlimited_player_transfer_distance", "true");
|
||||||
settings->setDefault("enable_pvp", "true");
|
settings->setDefault("enable_pvp", "true");
|
||||||
settings->setDefault("disallow_empty_password", "false");
|
settings->setDefault("disallow_empty_password", "false");
|
||||||
|
settings->setDefault("disable_anticheat", "false");
|
||||||
|
|
||||||
settings->setDefault("profiler_print_interval", "0");
|
settings->setDefault("profiler_print_interval", "0");
|
||||||
settings->setDefault("enable_mapgen_debug_info", "false");
|
settings->setDefault("enable_mapgen_debug_info", "false");
|
||||||
|
@ -2112,7 +2112,9 @@ void the_game(
|
|||||||
ldown_for_dig = true;
|
ldown_for_dig = true;
|
||||||
}
|
}
|
||||||
MapNode n = client.getEnv().getClientMap().getNode(nodepos);
|
MapNode n = client.getEnv().getClientMap().getNode(nodepos);
|
||||||
|
|
||||||
|
// NOTE: Similar piece of code exists on the server side for
|
||||||
|
// cheat detection.
|
||||||
// Get digging parameters
|
// Get digging parameters
|
||||||
DigParams params = getDigParams(nodedef->get(n).groups,
|
DigParams params = getDigParams(nodedef->get(n).groups,
|
||||||
&playeritem_toolcap);
|
&playeritem_toolcap);
|
||||||
@ -2160,7 +2162,7 @@ void the_game(
|
|||||||
{
|
{
|
||||||
dig_index = crack_animation_length;
|
dig_index = crack_animation_length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't show cracks if not diggable
|
// Don't show cracks if not diggable
|
||||||
if(dig_time_complete >= 100000.0)
|
if(dig_time_complete >= 100000.0)
|
||||||
{
|
{
|
||||||
|
@ -3014,6 +3014,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
}
|
}
|
||||||
if(n.getContent() != CONTENT_IGNORE)
|
if(n.getContent() != CONTENT_IGNORE)
|
||||||
scriptapi_node_on_punch(m_lua, p_under, n, playersao);
|
scriptapi_node_on_punch(m_lua, p_under, n, playersao);
|
||||||
|
// Cheat prevention
|
||||||
|
playersao->noCheatDigStart(p_under);
|
||||||
}
|
}
|
||||||
else if(pointed.type == POINTEDTHING_OBJECT)
|
else if(pointed.type == POINTEDTHING_OBJECT)
|
||||||
{
|
{
|
||||||
@ -3051,7 +3053,7 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
*/
|
*/
|
||||||
else if(action == 2)
|
else if(action == 2)
|
||||||
{
|
{
|
||||||
// Only complete digging of nodes
|
// Only digging of nodes
|
||||||
if(pointed.type == POINTEDTHING_NODE)
|
if(pointed.type == POINTEDTHING_NODE)
|
||||||
{
|
{
|
||||||
MapNode n(CONTENT_IGNORE);
|
MapNode n(CONTENT_IGNORE);
|
||||||
@ -3067,10 +3069,65 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
|
|||||||
m_emerge_queue.addBlock(peer_id,
|
m_emerge_queue.addBlock(peer_id,
|
||||||
getNodeBlockPos(p_above), BLOCK_EMERGE_FLAG_FROMDISK);
|
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);
|
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
|
// Re-send block to revert change on client-side
|
||||||
RemoteClient *client = getClient(peer_id);
|
RemoteClient *client = getClient(peer_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user