init.lua 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. sheriff = sheriff or {}
  2. sheriff.modpath = minetest.get_modpath("sheriff")
  3. sheriff.players = sheriff.players or {}
  4. -- Localize for performance.
  5. local vector_round = vector.round
  6. local math_random = math.random
  7. -- Get mod storage if not done already.
  8. if not sheriff.storage then
  9. sheriff.storage = minetest.get_mod_storage()
  10. end
  11. -- Let other mods query whether player *might* be a cheater, based on
  12. -- heuristics.
  13. function sheriff.is_suspected_cheater(pname)
  14. -- If player is a confirmed cheater then they're a suspected cheater, too.
  15. if sheriff.is_cheater(pname) then
  16. return true
  17. end
  18. local total_suspicion = ac.get_total_suspicion(pname)
  19. local clean_sessions = ac.get_clean_sessions(pname)
  20. if clean_sessions < 1 then clean_sessions = 1 end
  21. local avg_suspicion = total_suspicion / clean_sessions
  22. if avg_suspicion >= ac.high_average_suspicion then
  23. return true
  24. end
  25. end
  26. -- Let other mods query whether a given player is a registered cheater.
  27. function sheriff.is_cheater(pname)
  28. local data = sheriff.players[pname]
  29. if data then
  30. if data.is_cheater then
  31. -- Cheater time may be nil (thus 0) if cheater was registered before
  32. -- times started to be recorded.
  33. return true, (data.cheater_time or 0)
  34. end
  35. else
  36. -- Not in cache, load from mod storage.
  37. local s = sheriff.storage:get_string(pname)
  38. if s and s ~= "" then
  39. local d = minetest.deserialize(s)
  40. if d then
  41. sheriff.players[pname] = d
  42. if d.is_cheater then
  43. -- Cheater time may be nil (thus 0) if cheater was registered before
  44. -- times started to be recorded.
  45. return true, (d.cheater_time or 0)
  46. end
  47. end
  48. end
  49. end
  50. end
  51. function sheriff.get_data_or_nil(pname)
  52. local data = sheriff.players[pname]
  53. if data then
  54. return data
  55. end
  56. -- Not in cache, load from mod storage.
  57. local s = sheriff.storage:get_string(pname)
  58. if s and s ~= "" then
  59. local d = minetest.deserialize(s)
  60. if d then
  61. sheriff.players[pname] = d
  62. return d
  63. end
  64. end
  65. end
  66. -- Call to register a player as a cheater.
  67. function sheriff.register_cheater(pname)
  68. local data = sheriff.get_data_or_nil(pname) or {}
  69. -- Record the fact that the player is a cheater (boolean) and time of record.
  70. data.is_cheater = true
  71. data.cheater_time = os.time()
  72. local s = minetest.serialize(data)
  73. sheriff.storage:set_string(pname, s)
  74. -- Also add it to the cache.
  75. sheriff.players[pname] = data
  76. -- Notify the exile mod.
  77. exile.notify_new_exile(pname)
  78. -- Notify the administrator.
  79. local from = "SERVER"
  80. local to = gdac.name_of_admin or "singleplayer"
  81. local subject = "CHEATER REGISTRATION"
  82. local message = "Player <" .. rename.gpn(pname) ..
  83. "> was registered as a cheater. Please check the cheat log, and use " ..
  84. "/unregister_cheater if this was done in error."
  85. email.send_mail_single(from, to, subject, message)
  86. end
  87. -- Call to unregister a player as a cheater.
  88. function sheriff.unregister_cheater(pname)
  89. local data = sheriff.get_data_or_nil(pname)
  90. if data then
  91. -- Remove from mod storage.
  92. sheriff.storage:set_string(pname, "")
  93. -- Remove from cache.
  94. sheriff.players[pname] = nil
  95. end
  96. -- Remove cheat statistics, too.
  97. ac.erase_statistics(pname)
  98. end
  99. -- Can be called by mods to check if player should be punished *this time*.
  100. function sheriff.punish_probability(pname)
  101. if math_random(1, 100) == 1 then
  102. return true
  103. end
  104. end
  105. -- May be called by mods to execute a random punishment on a player.
  106. -- This may be called from `minetest.after`, etc.
  107. function sheriff.punish_player(pname)
  108. -- Check that player actually exists and is logged in.
  109. local player = minetest.get_player_by_name(pname)
  110. if not player then
  111. return
  112. end
  113. sheriff.random_hit(player)
  114. minetest.after(1, function()
  115. sheriff.random_gloat(pname)
  116. end)
  117. end
  118. --[[
  119. -- Usage is as follows:
  120. if sheriff.is_cheater(name) then
  121. if sheriff.punish_probability(name) then
  122. sheriff.punish_player(name)
  123. -- May possibly need to do `return` here, to abort other operations.
  124. -- Depends on context.
  125. return
  126. end
  127. end
  128. --]]
  129. local accidents = {
  130. {
  131. func = function(player)
  132. local pname = player:get_player_name()
  133. minetest.after(2, function()
  134. minetest.chat_send_player(pname, "# Server: Close call!")
  135. end)
  136. end,
  137. },
  138. {
  139. func = function(player)
  140. minetest.chat_send_player(player:get_player_name(), "# Server: Poison dart!")
  141. hb4.delayed_harm({
  142. name = player:get_player_name(),
  143. step = 10,
  144. min = 1,
  145. max = math_random(1, 2),
  146. msg = "# Server: Someone got poisoned!",
  147. poison = true,
  148. })
  149. end,
  150. },
  151. {
  152. func = function(player)
  153. tnt.boom(vector_round(player:get_pos()), {
  154. radius = 2,
  155. ignore_protection = false,
  156. ignore_on_blast = false,
  157. damage_radius = 3,
  158. disable_drops = true,
  159. })
  160. end,
  161. },
  162. {
  163. func = function(player)
  164. local pname = player:get_player_name()
  165. local inv = player:get_inventory()
  166. local sz = inv:get_size("main")
  167. local pos = math_random(1, sz)
  168. local stack = inv:get_stack("main", pos)
  169. if not stack:is_empty() and not passport.is_passport(stack:get_name()) then
  170. minetest.chat_send_player(pname, "# Server: Pick-pocket!")
  171. stack:take_item(stack:get_count())
  172. inv:set_stack("main", pos, stack)
  173. else
  174. minetest.after(2, function()
  175. minetest.chat_send_player(pname, "# Server: Close call!")
  176. end)
  177. end
  178. end,
  179. },
  180. }
  181. -- Called with a player object to actually apply a random punishment.
  182. function sheriff.random_hit(player)
  183. if #accidents > 0 then
  184. local act = accidents[math_random(1, #accidents)]
  185. act.func(player)
  186. end
  187. end
  188. local gloats = {
  189. "Oops.",
  190. "Sorry ....",
  191. "An accident!",
  192. "Uhoh.",
  193. "Accidents happen ....",
  194. "Help!",
  195. "No!",
  196. }
  197. -- Called to send a random chat message to a punished player.
  198. function sheriff.random_gloat(pname)
  199. if #gloats > 0 then
  200. local msg = gloats[math_random(1, #gloats)]
  201. minetest.chat_send_player(pname, "# Server: " .. msg)
  202. end
  203. end
  204. function sheriff.command_register_cheater(pname, param)
  205. param = param:trim()
  206. if param and param ~= "" then
  207. param = rename.grn(param)
  208. if minetest.player_exists(param) then
  209. sheriff.register_cheater(param)
  210. minetest.chat_send_player(pname, "# Server: Player <" .. rename.gpn(param) .. "> has been registered as a cheater.")
  211. else
  212. minetest.chat_send_player(pname, "# Server: Named player does not exist.")
  213. end
  214. else
  215. minetest.chat_send_player(pname, "# Server: You must provide the name of a player.")
  216. end
  217. return true
  218. end
  219. function sheriff.command_unregister_cheater(pname, param)
  220. param = param:trim()
  221. if param and param ~= "" then
  222. param = rename.grn(param)
  223. if minetest.player_exists(param) then
  224. sheriff.unregister_cheater(param)
  225. minetest.chat_send_player(pname, "# Server: Player <" .. rename.gpn(param) .. "> is not registered as a cheater.")
  226. else
  227. minetest.chat_send_player(pname, "# Server: Named player does not exist.")
  228. end
  229. else
  230. minetest.chat_send_player(pname, "# Server: You must provide the name of a player.")
  231. end
  232. return true
  233. end
  234. if not sheriff.loaded then
  235. -- Register reloadable mod.
  236. local c = "sheriff:core"
  237. local f = sheriff.modpath .. "/init.lua"
  238. reload.register_file(c, f, false)
  239. minetest.register_chatcommand("register_cheater", {
  240. params = "[name]",
  241. description = "Register user as confirmed cheater.",
  242. privs = {server=true},
  243. func = function(...)
  244. return sheriff.command_register_cheater(...)
  245. end,
  246. })
  247. minetest.register_chatcommand("unregister_cheater", {
  248. params = "[name]",
  249. description = "Unregister user from being a cheater.",
  250. privs = {server=true},
  251. func = function(...)
  252. return sheriff.command_unregister_cheater(...)
  253. end,
  254. })
  255. sheriff.loaded = true
  256. end