ee99c24d52
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.
110 lines
3.2 KiB
Lua
110 lines
3.2 KiB
Lua
-- LUALOCALS < ---------------------------------------------------------
|
|
local math, minetest, nodecore, pairs, string, type, vector
|
|
= math, minetest, nodecore, pairs, string, type, vector
|
|
local math_random, string_format
|
|
= math.random, string.format
|
|
-- LUALOCALS > ---------------------------------------------------------
|
|
|
|
local modname = minetest.get_current_modname()
|
|
local mintime = nodecore.setting_float(modname .. "_time", 2,
|
|
"Push out of solid time", [[The amount of time a player
|
|
needs to be trapped in a solid node before being pushed out.]])
|
|
local stepdist = nodecore.setting_float(modname .. "_stepdist", 5,
|
|
"Push out of solid distance", [[The maximum distance in
|
|
nodes that a player will be pushed out of solids.]])
|
|
|
|
local function normalbox(box)
|
|
if not box then return true end
|
|
if type(box) ~= "table" then return end
|
|
if box.fixed then return normalbox(box.fixed) end
|
|
if #box == 1 then return normalbox(box[1]) end
|
|
return box[1] == -0.5 and box[2] == -0.5 and box[3] == -0.5
|
|
and box[4] == 0.5 and box[5] == 0.5 and box[6] == 0.5
|
|
end
|
|
|
|
local function ispushout(def)
|
|
if not def.walkable then return end
|
|
if def.liquidtype ~= "none" then return end
|
|
if def.groups and def.groups.is_stack_only then return end
|
|
return normalbox(def.collision_box)
|
|
end
|
|
|
|
local solids = {}
|
|
minetest.after(0, function()
|
|
for k, v in pairs(minetest.registered_nodes) do
|
|
if ispushout(v) then
|
|
solids[k] = true
|
|
end
|
|
end
|
|
solids.ignore = nil
|
|
end)
|
|
|
|
local function isroom(pos)
|
|
return not (solids[minetest.get_node(pos).name]
|
|
or solids[minetest.get_node({
|
|
x = pos.x,
|
|
y = pos.y + 1,
|
|
z = pos.z
|
|
}).name])
|
|
end
|
|
|
|
nodecore.player_pushout_disable = nodecore.player_pushout_disable or function() end
|
|
|
|
nodecore.register_playerstep({
|
|
label = "push player out of solids",
|
|
action = function(player, data, dtime)
|
|
local function reset() data.pushout = nil end
|
|
|
|
if minetest.get_player_privs(player).noclip
|
|
or nodecore.player_pushout_disable(player, data)
|
|
then return reset() end
|
|
|
|
local pos = vector.round(player:get_pos())
|
|
if isroom(pos) then return reset() end
|
|
|
|
local podata = data.pushout or {}
|
|
local oldpos = podata.pos or pos
|
|
if not vector.equals(pos, oldpos) then return reset() end
|
|
|
|
local pt = (podata.time or 0) + dtime
|
|
if pt < mintime then
|
|
data.pushout = {time = pt, pos = pos}
|
|
return
|
|
end
|
|
|
|
local function pushto(newpos)
|
|
local dist = vector.distance(pos, newpos)
|
|
if dist > 1 then
|
|
nodecore.addphealth(player, -dist + 1, {
|
|
nc_type = "pushout"
|
|
})
|
|
end
|
|
newpos.y = newpos.y - 0.49
|
|
nodecore.log("action", string_format("%s pushed out of"
|
|
.. " solid from %s to %s",
|
|
data.pname,
|
|
minetest.pos_to_string(pos),
|
|
minetest.pos_to_string(newpos)))
|
|
newpos.keepinv = true
|
|
player:set_pos(newpos)
|
|
return reset()
|
|
end
|
|
|
|
for rel in nodecore.settlescan() do
|
|
local p = vector.add(pos, rel)
|
|
if isroom(p) then
|
|
return pushto(p)
|
|
end
|
|
end
|
|
local function bias(n)
|
|
return n + ((n > 0) and math_random(-stepdist - 1, stepdist - 1)
|
|
or math_random(-stepdist + 1, stepdist + 1))
|
|
end
|
|
return pushto({
|
|
x = bias(pos.x),
|
|
y = bias(pos.y),
|
|
z = bias(pos.z)
|
|
})
|
|
end
|
|
})
|