From 8831669505905dd9cd415711063f705d8e7ce02c Mon Sep 17 00:00:00 2001
From: Perttu Ahola <celeron55@gmail.com>
Date: Sun, 4 Aug 2013 00:45:49 +0300
Subject: [PATCH] Allow mods to listen to cheat detections using
 minetest.register_on_cheat()

---
 builtin/misc_register.lua       |  1 +
 doc/lua_api.txt                 |  3 +++
 src/content_sao.cpp             |  5 ++++-
 src/content_sao.h               |  3 ++-
 src/script/cpp_api/s_player.cpp | 16 ++++++++++++++++
 src/script/cpp_api/s_player.h   |  1 +
 src/server.cpp                  | 14 +++++++++++++-
 7 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/builtin/misc_register.lua b/builtin/misc_register.lua
index 2d25568b6..d5e086702 100644
--- a/builtin/misc_register.lua
+++ b/builtin/misc_register.lua
@@ -319,4 +319,5 @@ minetest.registered_on_respawnplayers, minetest.register_on_respawnplayer = make
 minetest.registered_on_joinplayers, minetest.register_on_joinplayer = make_registration()
 minetest.registered_on_leaveplayers, minetest.register_on_leaveplayer = make_registration()
 minetest.registered_on_player_receive_fields, minetest.register_on_player_receive_fields = make_registration_reverse()
+minetest.registered_on_cheats, minetest.register_on_cheat = make_registration()
 
diff --git a/doc/lua_api.txt b/doc/lua_api.txt
index 67ff823da..d34588786 100644
--- a/doc/lua_api.txt
+++ b/doc/lua_api.txt
@@ -1142,6 +1142,9 @@ minetest.register_on_joinplayer(func(ObjectRef))
 ^ Called when a player joins the game
 minetest.register_on_leaveplayer(func(ObjectRef))
 ^ Called when a player leaves the game
+minetest.register_on_cheat(func(ObjectRef, cheat))
+^ Called when a player cheats
+^ cheat: {type="moved_too_fast"/"interacted_too_far"/"finished_unknown_dig"/"dug_unbreakable"/"dug_too_fast"}
 minetest.register_on_chat_message(func(name, message))
 ^ Called always when a player says something
 minetest.register_on_player_receive_fields(func(player, formname, fields))
diff --git a/src/content_sao.cpp b/src/content_sao.cpp
index 8d46d4237..799c279a4 100644
--- a/src/content_sao.cpp
+++ b/src/content_sao.cpp
@@ -1454,8 +1454,9 @@ std::string PlayerSAO::getPropertyPacket()
 	return gob_cmd_set_properties(m_prop);
 }
 
-void PlayerSAO::checkMovementCheat()
+bool PlayerSAO::checkMovementCheat()
 {
+	bool cheated = false;
 	if(isAttached() || m_is_singleplayer ||
 			g_settings->getBool("disable_anticheat"))
 	{
@@ -1503,8 +1504,10 @@ void PlayerSAO::checkMovementCheat()
 					<<std::endl;
 			m_player->setPosition(m_last_good_position);
 			m_moved = true;
+			cheated = true;
 		}
 	}
+	return cheated;
 }
 
 bool PlayerSAO::getCollisionBox(aabb3f *toset) {
diff --git a/src/content_sao.h b/src/content_sao.h
index 9640e5f08..413fd3e68 100644
--- a/src/content_sao.h
+++ b/src/content_sao.h
@@ -262,7 +262,8 @@ class PlayerSAO : public ServerActiveObject
 	{
 		return m_dig_pool;
 	}
-	void checkMovementCheat();
+	// Returns true if cheated
+	bool checkMovementCheat();
 
 	// Other
 
diff --git a/src/script/cpp_api/s_player.cpp b/src/script/cpp_api/s_player.cpp
index e736d745d..0dbd52527 100644
--- a/src/script/cpp_api/s_player.cpp
+++ b/src/script/cpp_api/s_player.cpp
@@ -81,6 +81,22 @@ void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player)
 	runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
 }
 
+void ScriptApiPlayer::on_cheat(ServerActiveObject *player,
+		const std::string &cheat_type)
+{
+	SCRIPTAPI_PRECHECKHEADER
+
+	// Get minetest.registered_on_cheats
+	lua_getglobal(L, "minetest");
+	lua_getfield(L, -1, "registered_on_cheats");
+	// Call callbacks
+	objectrefGetOrCreate(player);
+	lua_newtable(L);
+	lua_pushlstring(L, cheat_type.c_str(), cheat_type.size());
+	lua_setfield(L, -2, "type");
+	runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
+}
+
 void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
 		const std::string &formname,
 		const std::map<std::string, std::string> &fields)
diff --git a/src/script/cpp_api/s_player.h b/src/script/cpp_api/s_player.h
index 663e3c2ab..c0409a481 100644
--- a/src/script/cpp_api/s_player.h
+++ b/src/script/cpp_api/s_player.h
@@ -34,6 +34,7 @@ class ScriptApiPlayer
 	bool on_respawnplayer(ServerActiveObject *player);
 	void on_joinplayer(ServerActiveObject *player);
 	void on_leaveplayer(ServerActiveObject *player);
+	void on_cheat(ServerActiveObject *player, const std::string &cheat_type);
 
 	void on_playerReceiveFields(ServerActiveObject *player,
 			const std::string &formname,
diff --git a/src/server.cpp b/src/server.cpp
index cdd42c2e9..7527f172c 100644
--- a/src/server.cpp
+++ b/src/server.cpp
@@ -2251,7 +2251,11 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 		player->control.LMB = (bool)(keyPressed&128);
 		player->control.RMB = (bool)(keyPressed&256);
 
-		playersao->checkMovementCheat();
+		bool cheated = playersao->checkMovementCheat();
+		if(cheated){
+			// Call callbacks
+			m_script->on_cheat(playersao, "moved_too_fast");
+		}
 
 		/*infostream<<"Server::ProcessData(): Moved player "<<peer_id<<" to "
 				<<"("<<position.X<<","<<position.Y<<","<<position.Z<<")"
@@ -2811,6 +2815,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 				RemoteClient *client = getClient(peer_id);
 				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;
 			}
@@ -2939,6 +2945,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 								<<PP(nocheat_p)<<" and completed digging "
 								<<PP(p_under)<<"; not digging."<<std::endl;
 						is_valid_dig = false;
+						// Call callbacks
+						m_script->on_cheat(playersao, "finished_unknown_dig");
 					}
 					// Get player's wielded item
 					ItemStack playeritem;
@@ -2964,6 +2972,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 								<<", which is not diggable with tool. not digging."
 								<<std::endl;
 						is_valid_dig = false;
+						// Call callbacks
+						m_script->on_cheat(playersao, "dug_unbreakable");
 					}
 					// Check digging time
 					// If already invalidated, we don't have to
@@ -2987,6 +2997,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 								<<" completed digging "<<PP(p_under)
 								<<"too fast; not digging."<<std::endl;
 						is_valid_dig = false;
+						// Call callbacks
+						m_script->on_cheat(playersao, "dug_too_fast");
 					}
 				}
 
-- 
GitLab