init.lua 6.7 KB

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