Aaron Suen 7da2ed13df Fix crosshairs/looktips in the void
It seems like Minetest actually generates terrain
beyond the map limit boundaries and raycast
and get_node can retrieve them server-side, even
though they aren't rendered client-side and air is
still filled with ignores.  This causes players to see
"stone" with looktips looking thru the bottom of
the world.  Fix it with an explicit check for world
bounds.
2021-11-27 09:24:28 -05:00

108 lines
3.0 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local minetest, nodecore, type, vector
= minetest, nodecore, type, vector
-- LUALOCALS > ---------------------------------------------------------
local modname = minetest.get_current_modname()
local looktip_after = nodecore.setting_float(modname .. "_looktip_time", 0.4,
"LookTip Delay Time", [[The number of seconds a player must be
standing still, or focused on one node face, to trigger a LookTip.]])
local touched_faces = {}
local function nodeface(pt)
return vector.multiply(vector.add(
pt.under, pt.above), 0.5)
end
nodecore.register_on_punchnode("touchtip on punch", function(_, _, player, pt)
if not player then return end
local pname = player:get_player_name()
if not pname then return end
touched_faces[pname] = nodeface(pt)
end)
local function settip(player, pos, name)
if not pos then
return nodecore.hud_set_multiline(player, {
label = "looktip",
ttl = 0
}, nil, "name")
end
return nodecore.hud_set_multiline(player, {
label = "looktip",
hud_elem_type = "waypoint",
world_pos = pos,
name = name,
text = "",
precision = 0,
number = 0xffffff,
z_index = -250,
quick = true
}, nodecore.translate, "name")
end
local function checknode(player, pt, data)
if not nodecore.within_map_limits(pt.under) then return end
local face = nodeface(pt)
local pname = player:get_player_name()
local tp = touched_faces[pname]
if tp and vector.equals(tp, face) then return true end
if tp then touched_faces[pname] = nil end
local llu = nodecore.get_node_light(pt.under) or 0
local lla = nodecore.get_node_light(pt.above) or 0
local ll = (llu > lla) and llu or lla
if ll <= 0 then return end
if data.looktip_stoptime <= nodecore.gametime then return true end
local old = data.looktip_focus
data.looktip_focus = face
data.looktip_focustime = old and vector.equals(old, face)
and data.looktip_focustime or nodecore.gametime + looktip_after
return data.looktip_focustime <= nodecore.gametime
end
nodecore.register_playerstep({
label = "looktip",
priority = -100,
action = function(player, data)
local ctl = data.control
data.looktip_stoptime = (not (ctl.up or ctl.down or ctl.left
or ctl.right or ctl.jump)) and data.looktip_stoptime
or nodecore.gametime + looktip_after
local pt = data.raycast()
if not pt then return settip(player) end
if pt.type == "node" then
if checknode(player, pt, data) then
return settip(player, nodeface(pt),
nodecore.touchtip_node(
pt.under,
minetest.get_node(pt.under),
player,
pt))
end
elseif pt.type == "object" then
local ll = nodecore.get_node_light(
pt.ref:get_pos()) or 0
if ll <= 0 then return settip(player) end
local luent = pt.ref:get_luaentity()
local desc = luent and luent.description
if desc then
if type(desc) == "function" then
desc = desc(luent)
end
return settip(player,
pt.ref:get_pos(),
desc)
end
end
return settip(player)
end
})