Hyrbid immediate/delayed witnessing

If we have line of sight to see the event happen
now, then discover it immediately, otherwise save
it for delayed witnessing on punch.
This commit is contained in:
Aaron Suen 2020-09-26 20:17:31 -04:00
parent 64e917fc95
commit fb6a4d7dd1

View File

@ -1,12 +1,32 @@
-- LUALOCALS < ---------------------------------------------------------
local minetest, nodecore, pairs, table, type, vector
= minetest, nodecore, pairs, table, type, vector
local table_remove
= table.remove
local math, minetest, nodecore, pairs, table, type, vector
= math, minetest, nodecore, pairs, table, type, vector
local math_pi, table_remove
= math.pi, table.remove
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local seethru = {}
minetest.after(0, function()
for name, def in pairs(minetest.registered_nodes) do
if (minetest.get_item_group(name, "witness_opaque") == 0)
and (
minetest.get_item_group(name, "witness_transparent") > 0
or def.sunlight_propagates
or (
def.paramtype == "light"
and def.alpha
and def.alpha > 0
and def.alpha < 255
)
) then
seethru[name] = true
end
end
end)
local metakey = modname .. "_witness"
local cache = {}
local function witnessdata(player)
@ -22,31 +42,59 @@ local function witnessdata(player)
return data, function() return meta:set_string(metakey, minetest.serialize(data)) end
end
local function canwitnessnow(player, pos)
local ppos = player:get_pos()
ppos.y = ppos.y + player:get_properties().eye_height
local look = player:get_look_dir()
local targ = vector.normalize(vector.subtract(pos, ppos))
if vector.angle(look, targ) > math_pi / 8 then return end
local rp = vector.round(pos)
for pt in minetest.raycast(pos, ppos, false, true) do
if not pt.under then return end
if vector.equals(pt.under, rp) then return true end
local node = minetest.get_node(pt.under)
if not seethru[node.name] then return end
end
return true
end
local function witnesslater(player, pos, disc)
local data, save = witnessdata(player)
local newdata = {
node = minetest.get_node(pos).name,
stack = nodecore.stack_get(pos):get_name(),
disc = disc
}
local posstr = minetest.pos_to_string(pos)
local olddata = data.lookup[posstr]
if olddata and (olddata.node == newdata.node) and (olddata.stack
== newdata.stack) then
for k in pairs(disc) do olddata.disc[k] = true end
else
data.queue[#data.queue + 1] = pos
while #data.queue > 100 do table_remove(data.queue, 1) end
data.lookup[posstr] = newdata
end
save()
end
function nodecore.witness(pos, label, maxdist)
maxdist = maxdist or 16
label = type(label) == "table" and label or {label}
local disc = {}
for i = 1, #label do disc["witness:" .. label[i]] = true end
for _, player in pairs(minetest.get_connected_players()) do
local ppos = player:get_pos()
if vector.distance(ppos, pos) <= maxdist then
local data, save = witnessdata(player)
local newdata = {
node = minetest.get_node(pos).name,
stack = nodecore.stack_get(pos):get_name(),
label = label
}
local posstr = minetest.pos_to_string(pos)
local olddata = data.lookup[posstr]
if olddata and (olddata.node == newdata.node) and (olddata.stack
== newdata.stack) then
for i = 1, #label do
olddata.label[#olddata.label + 1] = label[i]
end
if canwitnessnow(player, pos) then
nodecore.player_discover(player, disc)
else
data.queue[#data.queue + 1] = pos
while #data.queue > 100 do table_remove(data.queue, 1) end
data.lookup[posstr] = newdata
witnesslater(player, pos, disc)
end
save()
end
end
end
@ -61,7 +109,5 @@ minetest.register_on_punchnode(function(pos, node, puncher)
node = node or minetest.get_node(pos)
if (found.node ~= node.name) or (nodecore.stack_get(pos):get_name()
~= found.stack) then return end
local disc = found.label
for i = 1, #found.label do disc["witness:" .. found.label[i]] = true end
return nodecore.player_discover(puncher, disc)
return nodecore.player_discover(puncher, found.disc)
end)