Aaron Suen 906cf51cbb Trying to fix some issues
- In some cases, players are not being kicked, even though their
  status clearly indicates they should be.  Make sure the "should we
  kick them" logic in the status check command matches the logic in
  the thing that actually does the kick.
- Clean up the way we handle event hooks to reduce the code mess.
- Don't rely on the bump/bumpn functions returning pname; always
  return nil with them and determine pname at the outer layers and
  pass it in as necessary.  This is how we should have fixed the
  earlier bug that caused players digging things not to get the node.
2022-10-06 06:42:06 -04:00

96 lines
2.8 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local minetest, pairs, string, tonumber
= minetest, pairs, string, tonumber
local string_format
= string.format
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local invert = minetest.settings:get_bool(modname .. "_invert")
local timeout = tonumber(minetest.settings:get(modname .. "_timeout")) or 600
local reason = minetest.settings:get(modname .. "_reason") or "idle timeout"
minetest.register_privilege(modname, {
description = (invert and "Kick" or "Do not kick") .. " this player when idle",
give_to_singleplayer = false,
give_to_admin = false
})
local function now() return minetest.get_us_time() / 1000000 end
local times = {}
local actions = {}
minetest.register_chatcommand(modname, {
description = "Check player idle time and last action",
privs = {server = true},
func = function(_, param)
local time = times[param]
if not time then
return true, string_format("Player %q not found", param)
end
local active = (not minetest.check_player_privs(param, modname))
== (not invert)
return true, string_format(
"Player %q idle %0.2f/%s last action %q",
param,
now() - time,
active and string_format("%.2f", timeout) or "never",
actions[param] or "unknown")
end
})
local function bumpn(pname, action)
times[pname] = now()
actions[pname] = action
end
local function bump(player, action)
if not (player and player.get_player_name) then return end
local pname = player:get_player_name()
if not pname then return end
return bumpn(pname, action)
end
local function wrapon(event, idx, func)
minetest["register_on_" .. event](function(...)
return func(({...})[idx], event)
end)
end
wrapon("joinplayer", 1, bump)
wrapon("placenode", 3, bump)
wrapon("dignode", 3, bump)
wrapon("punchnode", 3, bump)
wrapon("chat_message", 1, bumpn)
wrapon("player_receive_fields", 1, bump)
wrapon("craft", 2, bump)
wrapon("player_inventory_action", 1, bump)
local looks = {}
local ctlbits = {}
local function checkplayer(player, pname)
local bits = player:get_player_control_bits()
local oldbits = ctlbits[pname]
ctlbits[pname] = bits
local look = player:get_look_dir()
local oldlook = looks[pname]
looks[pname] = look
if bits ~= oldbits then
return bumpn(pname, "control")
elseif not (oldlook and vector.distance(look, oldlook) < 0.001) then
return bumpn(pname, "lookdir")
end
end
minetest.register_globalstep(function()
for _, player in pairs(minetest.get_connected_players()) do
if (not minetest.check_player_privs(player, modname)) ~= (not invert) then return end
local pname = player:get_player_name()
checkplayer(player, pname)
if now() - times[pname] >= timeout then
minetest.kick_player(pname, reason)
end
end
end)