105 lines
2.9 KiB
Lua
105 lines
2.9 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 kickable(pname)
|
|
return (not minetest.check_player_privs(pname, modname)) == (not invert)
|
|
end
|
|
|
|
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)
|
|
if not minetest.get_player_by_name(param) then
|
|
return true, string_format("Player %q not found", param)
|
|
end
|
|
if not kickable(param) then
|
|
return true, string_format("Player %q exempt", param)
|
|
end
|
|
local time = times[param]
|
|
if not time then
|
|
return true, string_format("Player %q no data", param)
|
|
end
|
|
return true, string_format(
|
|
"Player %q idle %0.2f/%0.2f last action %q",
|
|
param,
|
|
now() - time,
|
|
timeout,
|
|
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
|
|
local pname = player:get_player_name()
|
|
if kickable(pname) then
|
|
checkplayer(player, pname)
|
|
if now() - times[pname] >= timeout then
|
|
minetest.kick_player(pname, reason)
|
|
end
|
|
end
|
|
end
|
|
end)
|