-- 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)