init.lua 6.5 KB

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