More aggressive priv caching strategy

Instead of caching privs only for the current tick, and only for
NodeCore itself, change the base API to use caching universally,
including for naive mod code.  Privs are cached until invalidated
by a change; it's assumed here that the "auth_reload" command
exists in the first place because this kind of caching is allowed
and accounted for, even if it's not actually done by the engine
or builtin.
This commit is contained in:
Aaron Suen 2022-10-07 06:59:04 -04:00
parent a15146dc4c
commit ee99c24d52
10 changed files with 61 additions and 47 deletions

View File

@ -0,0 +1,44 @@
-- LUALOCALS < ---------------------------------------------------------
local minetest, type
= minetest, type
-- LUALOCALS > ---------------------------------------------------------
local function player_name(player)
if not player then return end
if type(player) == "string" then return player end
player = player.get_player_name and player:get_player_name()
if type(player) == "string" then return player end
end
local priv_cache = {}
local function invalidateon(method)
local oldfunc = minetest[method]
minetest[method] = function(player, ...)
local function helper(...)
local name = player_name(player)
if name then priv_cache[name] = nil end
return ...
end
return helper(oldfunc(player, ...))
end
end
invalidateon("set_privileges")
invalidateon("remove_player_auth")
local oldreload = minetest.auth_reload
function minetest.auth_reload(...)
priv_cache = {}
return oldreload(...)
end
local oldget = minetest.get_player_privs
function minetest.get_player_privs(player)
player = player_name(player)
if not player then return {} end
local cached = priv_cache[player]
if cached then return cached end
cached = oldget(player)
priv_cache[player] = cached
return cached
end

View File

@ -90,6 +90,7 @@ include("compat_creative")
include("compat_issue10127")
include("compat_legacyent")
include("compat_nodealpha")
include("compat_authcache")
include("util_settings")
include("util_privs")

View File

@ -1,48 +1,17 @@
-- LUALOCALS < ---------------------------------------------------------
local minetest, nodecore, type
= minetest, nodecore, type
local minetest, nodecore
= minetest, nodecore
-- LUALOCALS > ---------------------------------------------------------
local function player_name(player)
if not player then return end
if type(player) == "string" then return player end
player = player.get_player_name and player:get_player_name()
if type(player) == "string" then return player end
end
local dirty
local priv_cache = {}
minetest.register_globalstep(function()
if dirty then
priv_cache = {}
dirty = false
end
end)
function nodecore.get_player_privs_cached(player)
player = player_name(player)
if not player then return {} end
local cached = priv_cache[player]
if cached then return cached end
cached = minetest.get_player_privs(player)
priv_cache[player] = cached
dirty = true
return cached
end
local oldset = minetest.set_player_privs
function minetest.set_player_privs(player, ...)
local function helper(...)
local name = player_name(player)
if name then priv_cache[name] = nil end
return ...
local warned
function nodecore.get_player_privs_cached(...)
if not warned then
nodecore.log("warning", "deprecated nodecore.get_player_privs_cached(...)")
warned = true
end
return helper(oldset(player, ...))
return minetest.get_player_privs(...)
end
function nodecore.interact(player)
return nodecore.get_player_privs_cached(player).interact
return minetest.get_player_privs(player).interact
end

View File

@ -170,7 +170,7 @@ nodecore.register_playerstep({
label = "hint tab watch interact",
action = function(player, data)
local privs = {}
for k, v in pairs(nodecore.get_player_privs_cached(data.pname)) do
for k, v in pairs(minetest.get_player_privs(data.pname)) do
if v then privs[#privs + 1] = k end
end
table_sort(privs)

View File

@ -39,7 +39,7 @@ local function gethint(player)
local found, done = nodecore.hint_state(pname)
local future
if nodecore.get_player_privs_cached(pname).debug then
if minetest.get_player_privs(pname).debug then
local seen = {}
for _, v in pairs(found) do seen[v] = true end
for _, v in pairs(done) do seen[v] = true end

View File

@ -24,7 +24,7 @@ minetest.register_privilege("ncdqd", {
function nodecore.player_can_take_damage(player)
return not player:get_armor_groups().immortal
and not nodecore.get_player_privs_cached(player).ncdqd
and not minetest.get_player_privs(player).ncdqd
end
function nodecore.register_virtual_item(name, def)

View File

@ -21,7 +21,7 @@ local cheats = {
local function ischeating(player)
local cheating = false
local privs = nodecore.get_player_privs_cached(player:get_player_name())
local privs = minetest.get_player_privs(player:get_player_name())
if privs.interact then
cheating = cheating or not nodecore.player_can_take_damage(player)
cheating = cheating or not nodecore.player_visible(player)

View File

@ -47,7 +47,7 @@ nodecore.player_skin = nodecore.player_skin or function(player, options)
getcolors(name, layers)
local privs = options.privs or nodecore.get_player_privs_cached(
local privs = options.privs or minetest.get_player_privs(
options.privname or name)
if options.noarms or not privs.interact then
layers[#layers + 1] = modname .. "_no_interact.png"

View File

@ -29,7 +29,7 @@ local function patchplayers()
function meta:set_pos(pos, ...)
if (not self) or (not self.is_player) or (not self:is_player())
or (not pos) or type(pos) ~= "table" or pos.keepinv
or nodecore.get_player_privs_cached(self)[keepname] then
or minetest.get_player_privs(self)[keepname] then
return setraw(self, pos, ...)
end
local old = self:get_pos()

View File

@ -55,7 +55,7 @@ nodecore.register_playerstep({
action = function(player, data, dtime)
local function reset() data.pushout = nil end
if nodecore.get_player_privs_cached(player).noclip
if minetest.get_player_privs(player).noclip
or nodecore.player_pushout_disable(player, data)
then return reset() end