257 lines
7.8 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local error, math, minetest, pairs, string, type
= error, math, minetest, pairs, string, type
local math_ceil, math_random, string_format, string_gsub, string_lower,
string_sub
= math.ceil, math.random, string.format, string.gsub, string.lower,
string.sub
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local modstore = minetest.get_mod_storage()
local closed = modstore:get_string("closed") ~= ""
local function conf(k, n)
return minetest.settings[k](minetest.settings, modname .. "_" .. n)
end
local motddesc = conf("get", "desc") or "terms"
local limitsoft = conf("get", "limitsoft") or 3
local limithard = conf("get", "limithard") or math_ceil(limitsoft * 1.5)
if limithard < limitsoft then error("hard limit cannot be less than soft limit") end
local limitmsg = conf("get", "limitmsg") or "There are too many new players"
.. " right now; please try again in a few minutes."
local cmdname = conf("get", "cmdname") or "agree"
local cmdparam = conf("get", "cmdparam") or ("to " .. motddesc)
local cmdinstruct = conf("get", "cmdinstruct")
or "Please use the /motd chat command for instructions."
local grantprivs = conf("get", "grant") or "interact"
local purge = conf("get_bool", "purge")
local hudline1 = conf("get", "hudline1")
or ("You must agree to the " .. motddesc .. " to participate.")
local hudline2 = conf("get", "hudline2") or cmdinstruct
local hudclosed1 = conf("get", "hudclosed1")
or "New player registrations are currently disabled."
local hudclosed2 = conf("get", "hudclosed2") or hudline2
local already = conf("get", "already")
or ("You have already agreed and privileges were"
.. " already granted. If you have lost them, then they can"
.. " only be restored by an admin or moderator.")
local notice = conf("get", "notice") or ("*** %s agreed to " .. motddesc)
local noticeclosed = conf("get", "noticeclosed") or (notice
.. " ... but registration currently is closed.")
notice = notice .. "."
local jointag = conf("get", "jointag") or " [new]"
local purgetag = conf("get", "purgetag") or " [gone]"
local phashkey = minetest.settings:get("szutil_motd_hashkey") or ""
local function phash(pname)
if #phashkey < 1 then return "0000" end
return string_sub(minetest.sha1(phashkey .. pname .. phashkey .. pname), 1, 4)
end
local function phsub(line, pname)
return string_gsub(line, "<phash>", phash(pname))
end
local function tagmsg(func, suff)
return function(pname, ...)
if minetest.check_player_privs(pname, modname) then
return func(pname, ...)
end
local oldsend = minetest.chat_send_all
function minetest.chat_send_all(text, ...)
minetest.chat_send_all = oldsend
return oldsend(text .. suff, ...)
end
local function helper(...)
minetest.chat_send_all = oldsend
return ...
end
return helper(func(pname, ...))
end
end
if jointag and jointag ~= "" then
minetest.send_join_message = tagmsg(minetest.send_join_message, jointag)
end
if limitsoft >= 0 and limithard > 0 then
local emerging = {}
local function now() return minetest.get_us_time() / 1000000 end
minetest.register_on_prejoinplayer(function(name)
if minetest.check_player_privs(name, modname) then return end
local lobby = 0
for _, p in pairs(minetest.get_connected_players()) do
local pname = p:get_player_name()
emerging[pname] = nil
if not minetest.check_player_privs(p:get_player_name(), modname)
then lobby = lobby + 1 end
end
for _, t in pairs(emerging) do
if now() < t + 60 then lobby = lobby + 1 end
end
if lobby > math_random(limitsoft, limithard) then return limitmsg end
emerging[name] = now()
end)
end
local invitepriv = modname .. "_invite"
local huds = {}
local function dohud(player, id, offset, text)
if not id then
return player:hud_add({
hud_elem_type = "text",
position = {x = 0.5, y = 0.5},
text = text,
number = 0xFFC000,
alignment = {x = 0, y = offset},
offset = {x = 0, y = offset}
})
end
player:hud_change(id, "text", text)
return id
end
local function hudcheck(pname)
pname = type(pname) == "string" and pname or pname:get_player_name()
minetest.after(0, function()
local player = minetest.get_player_by_name(pname)
if not player then return end
local phud = huds[pname]
if minetest.check_player_privs(player, modname) then
player:hud_set_flags({crosshair = true})
if phud then
for _, id in pairs(phud) do
player:hud_remove(id)
end
end
huds[pname] = nil
return
end
player:hud_set_flags({crosshair = false})
if not phud then
phud = {}
huds[pname] = phud
end
local myclosed = closed and not minetest.check_player_privs(
player, invitepriv)
phud[1] = dohud(player, phud[1], -1, phsub(
myclosed and hudclosed1 or hudline1, pname))
phud[2] = dohud(player, phud[2], 1, phsub(
myclosed and hudclosed2 or hudline2, pname))
end)
end
minetest.register_on_leaveplayer(function(player)
huds[player:get_player_name()] = nil
end)
minetest.register_on_joinplayer(hudcheck)
minetest.register_privilege(modname, {
description = "agreed to " .. motddesc,
give_to_singleplayer = false,
give_to_admin = false,
on_grant = hudcheck,
on_revoke = hudcheck
})
minetest.register_privilege(invitepriv, {
description = "can agree to " .. motddesc .. " even when closed",
give_to_singleplayer = false,
give_to_admin = false,
on_grant = hudcheck,
on_revoke = hudcheck
})
minetest.register_chatcommand(cmdname, {
description = cmdinstruct,
func = function(pname, param)
if param ~= phsub(cmdparam, pname) then return false, cmdinstruct end
if minetest.check_player_privs(pname, modname) then
return false, already
end
if closed and not minetest.check_player_privs(pname, invitepriv) then
return minetest.chat_send_all(string_format(noticeclosed, pname))
end
minetest.chat_send_all(string_format(notice, pname))
local grant = minetest.string_to_privs(grantprivs)
grant[modname] = true
local privs = minetest.get_player_privs(pname)
for priv in pairs(grant) do
privs[priv] = true
minetest.run_priv_callbacks(pname, priv, pname, "grant")
end
minetest.set_player_privs(pname, privs)
hudcheck(pname)
end
})
local function setclosed(val)
if closed == val then return end
closed = val
modstore:set_string("closed", closed and "1" or "")
for _, p in pairs(minetest.get_connected_players()) do
hudcheck(p)
end
end
minetest.register_chatcommand(modname, {
description = "Toggle new player registrations by /" .. cmdname,
params = "[on|off]",
privs = {ban = true},
func = function(_, param)
if string_lower(param) == "on" then
setclosed(false)
elseif string_lower(param) == "off" then
setclosed(true)
elseif param ~= "" then
return false, "Use on/off to enable/disable registration,"
.. " or blank to query current state"
end
return true, "New player registrations "
.. (closed and "DISALLOWED" or "ALLOWED")
end
})
if purge then
local s = modstore:get_string("purge")
local cache = s and s ~= "" and minetest.deserialize(s) or {}
local function save() modstore:set_string("purge", minetest.serialize(cache)) end
local function processqueue()
minetest.after(1 + math_random(), processqueue)
local keep = {}
for _, p in pairs(minetest.get_connected_players()) do
keep[p:get_player_name()] = true
end
for k in pairs(cache) do
if not keep[k] then
minetest.remove_player(k)
minetest.remove_player_auth(k)
end
cache[k] = nil
end
save()
end
minetest.after(0, processqueue)
minetest.register_on_leaveplayer(function(player)
local pname = player:get_player_name()
if minetest.check_player_privs(pname, modname) then return end
cache[pname] = true
end)
if purgetag and purgetag ~= "" then
minetest.send_leave_message = tagmsg(minetest.send_leave_message, purgetag)
end
end