init.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. afk_removal = afk_removal or {}
  2. afk_removal.players = afk_removal.players or {}
  3. afk_removal.modpath = minetest.get_modpath("afk_removal")
  4. afk_removal.steptime = 5
  5. afk_removal.timeout = 60 * 30
  6. afk_removal.warntime = 60 * 29
  7. afk_removal.disable_kick = minetest.is_singleplayer()
  8. -- Localize vector.distance() for performance.
  9. local vector_distance = vector.distance
  10. local vector_round = vector.round
  11. local math_floor = math.floor
  12. -- Public API function.
  13. -- This should be called from any mod that wishes to reset the kick timeout for a player.
  14. -- For example, a chat mod may call this when a player chats.
  15. afk_removal.reset_timeout = function(name)
  16. -- localize
  17. local players = afk_removal.players
  18. -- Ensure an entry exists for this name.
  19. local data = players[name]
  20. if not data then
  21. players[name] = {time=0, pos={x=0, y=0, z=0}}
  22. data = players[name]
  23. end
  24. data.time = 0
  25. data.afk = nil
  26. end
  27. function afk_removal.on_joinplayer(player)
  28. local name = player:get_player_name()
  29. afk_removal.players[name] = {time=0, pos=player:get_pos()}
  30. end
  31. function afk_removal.on_leaveplayer(player, timedout)
  32. local pname = player:get_player_name()
  33. afk_removal.players[pname] = nil
  34. end
  35. -- API function to query whether a player is currently AFK.
  36. -- Note that this only has meaning for registered players.
  37. -- Unregistered players are kicked, so you generally won't encounter those.
  38. function afk_removal.is_afk(pname)
  39. local p = afk_removal.players
  40. local o = p[pname]
  41. if o then
  42. if o.afk then
  43. return true
  44. end
  45. end
  46. return false
  47. end
  48. -- Returns the number of seconds since player's last action.
  49. -- Returns -1 if player data is not available (wrong player name?).
  50. function afk_removal.seconds_since_action(pname)
  51. local p = afk_removal.players
  52. local o = p[pname]
  53. if o then
  54. return o.time
  55. end
  56. return -1
  57. end
  58. afk_removal.update = function()
  59. local allplayers = minetest.get_connected_players()
  60. for k, player in ipairs(allplayers) do
  61. local name = player:get_player_name()
  62. local target = afk_removal.players[name]
  63. local pos = vector_round(player:getpos())
  64. local dist = vector_distance(pos, target.pos)
  65. local nokick = false
  66. if afk_removal.disable_kick or minetest.check_player_privs(name, {canafk=true}) then
  67. nokick = true
  68. end
  69. if dist > 0.5 then
  70. target.pos = pos
  71. target.time = 0
  72. target.afk = nil
  73. else
  74. -- Increase time since AFK started.
  75. local time = target.time
  76. time = time + afk_removal.steptime
  77. target.time = time
  78. if not nokick and time >= afk_removal.warntime then
  79. -- Only ignore players who are registered and NOT dead.
  80. if player:get_hp() > 0 and passport.player_registered(name) then
  81. -- If player is registered and NOT dead, don't send message.
  82. nokick = true
  83. else
  84. local remain = afk_removal.timeout - time
  85. minetest.chat_send_player(name, "# Server: You will be kicked for inactivity in " .. math_floor(remain) .. " seconds.")
  86. easyvend.sound_error(name)
  87. end
  88. end
  89. end
  90. -- Kick players who have done nothing for too long.
  91. if target.time >= afk_removal.timeout then
  92. if nokick then
  93. -- If player is registered and NOT dead, then just mark them as AFK.
  94. -- If player is registered but dead, they'll be kicked anyway.
  95. target.afk = true
  96. else
  97. minetest.kick_player(name, "Kicked for inactivity.")
  98. local dname = rename.gpn(name)
  99. minetest.chat_send_all("# Server: <" .. dname .. "> was kicked for being AFK too long.")
  100. end
  101. end
  102. end
  103. end
  104. local timer = 0
  105. local delay = afk_removal.steptime
  106. function afk_removal.globalstep(dtime)
  107. timer = timer + dtime
  108. if timer < delay then return end
  109. timer = 0
  110. afk_removal.update()
  111. end
  112. function afk_removal.on_craft(itemstack, player, old_craft_grid, craft_inv)
  113. if not player then return end
  114. if not player:is_player() then return end
  115. -- Ensure this player has an entry in the table.
  116. local name = player:get_player_name()
  117. if not afk_removal.players[name] then
  118. afk_removal.players[name] = {time=0, pos={x=0, y=0, z=0}}
  119. end
  120. afk_removal.players[name].time = 0
  121. end
  122. local function toggle_status(name)
  123. if not afk_removal.players[name] then
  124. return
  125. end
  126. if afk_removal.players[name].afk then
  127. afk_removal.players[name].afk = nil
  128. minetest.chat_send_player(name, "# Server: You're no longer AFK.")
  129. else
  130. afk_removal.players[name].afk = true
  131. minetest.chat_send_player(name, "# Server: You've gone AFK!")
  132. end
  133. end
  134. function afk_removal.do_afk(name, param)
  135. if param ~= "" then
  136. local pname = rename.grn(param)
  137. if afk_removal.is_afk(pname) then
  138. minetest.chat_send_player(name, "# Server: <" .. rename.gpn(pname) .. "> is AFK!")
  139. else
  140. if minetest.get_player_by_name(pname) then
  141. local time = afk_removal.seconds_since_action(pname)
  142. if time < 60 then
  143. minetest.chat_send_player(name, "# Server: <" .. rename.gpn(pname) .. "> is active.")
  144. elseif time < 60*2 then
  145. minetest.chat_send_player(name, "# Server: <" .. rename.gpn(pname) .. "> might be AFK.")
  146. else
  147. minetest.chat_send_player(name, "# Server: <" .. rename.gpn(pname) .. "> is probably AFK.")
  148. end
  149. else
  150. minetest.chat_send_player(name, "# Server: <" .. param .. "> is not online.")
  151. end
  152. end
  153. else
  154. minetest.after(0, toggle_status, name)
  155. end
  156. end
  157. if not afk_removal.registered then
  158. -- Crafting resets the player's AFK timeout.
  159. minetest.register_on_craft(function(...)
  160. return afk_removal.on_craft(...)
  161. end)
  162. minetest.register_globalstep(function(...)
  163. return afk_removal.globalstep(...)
  164. end)
  165. minetest.register_privilege("canafk", {
  166. description = "Player can remain AFK without being kicked.",
  167. give_to_singleplayer = false,
  168. })
  169. minetest.register_on_joinplayer(function(...)
  170. return afk_removal.on_joinplayer(...)
  171. end)
  172. minetest.register_on_leaveplayer(function(...)
  173. return afk_removal.on_leaveplayer(...)
  174. end)
  175. minetest.register_chatcommand("afk", {
  176. params = "[name]",
  177. description = "Query whether another player is AFK, or toggle your own AFK status.",
  178. privs = {interact=true},
  179. func = function(...)
  180. afk_removal.do_afk(...)
  181. return true
  182. end,
  183. })
  184. local c = "afk_removal:core"
  185. local f = afk_removal.modpath .. "/init.lua"
  186. reload.register_file(c, f, false)
  187. afk_removal.registered = true
  188. end