145 lines
4.3 KiB
Lua
145 lines
4.3 KiB
Lua
local fmt = string.format
|
|
|
|
|
|
-- get actual eye_pos of the player (including eye_offset)
|
|
local function player_get_eye_pos(player)
|
|
local p_pos = player:get_pos()
|
|
local p_eye_height = player:get_properties().eye_height
|
|
p_pos.y = p_pos.y + p_eye_height
|
|
local p_eye_pos = p_pos
|
|
local p_eye_offset = vector.multiply(player:get_eye_offset(), 0.1)
|
|
local yaw = player:get_look_horizontal()
|
|
p_eye_pos = vector.add(p_eye_pos, vector.rotate_around_axis(p_eye_offset, {x=0,y=1,z=0}, yaw))
|
|
return p_eye_pos
|
|
end
|
|
|
|
|
|
-- return first thing player is pointing at
|
|
local function raycast_crosshair(player, range, point_to_objects, point_to_liquids)
|
|
local p_eye_pos = player_get_eye_pos(player)
|
|
local to = vector.add(p_eye_pos, vector.multiply(player:get_look_dir(), range))
|
|
local ray = core.raycast(p_eye_pos, to, point_to_objects, point_to_liquids)
|
|
local pointed_thing = ray:next()
|
|
while pointed_thing do
|
|
if pointed_thing.type == "object" and pointed_thing.ref == player then
|
|
-- exclude the player themselves from the raycast
|
|
pointed_thing = ray:next()
|
|
else
|
|
return pointed_thing
|
|
end
|
|
end
|
|
-- FIXME return "nothing" pointed thing?
|
|
return nil
|
|
end
|
|
|
|
|
|
-- return first object
|
|
local function raycast_crosshair_to_object(player, range)
|
|
local p_eye_pos = player_get_eye_pos(player)
|
|
local to = vector.add(p_eye_pos, vector.multiply(player:get_look_dir(), range))
|
|
-- point_to_objects = true, point_to_liquids = false
|
|
local ray = core.raycast(p_eye_pos, to, true, false)
|
|
local pointed_thing = ray:next()
|
|
while pointed_thing do
|
|
if pointed_thing.type == "object" then
|
|
if pointed_thing.ref ~= player then
|
|
return pointed_thing
|
|
end
|
|
end
|
|
pointed_thing = ray:next()
|
|
end
|
|
-- FIXME return "nothing" pointed thing?
|
|
return nil
|
|
end
|
|
|
|
|
|
|
|
|
|
-- get position and thing that player is pointing at or nil
|
|
local function get_pointed_position(player, range, point_to_objects, point_to_liquids)
|
|
local pointed_thing = raycast_crosshair(player, range, point_to_objects, point_to_liquids)
|
|
local pointed_pos = nil
|
|
if pointed_thing then
|
|
if pointed_thing.type == "node" then
|
|
-- middle between "above" and "under"
|
|
pointed_pos = vector.multiply(vector.add(pointed_thing.above, pointed_thing.under), 0.5)
|
|
elseif pointed_thing.type == "object" then
|
|
-- TODO point at the middle of collision box? (or not, ground may be better)
|
|
pointed_pos = pointed_thing.ref:get_pos()
|
|
end
|
|
end
|
|
return pointed_pos, pointed_thing
|
|
end
|
|
|
|
local escapes = {
|
|
['\a'] = '\\a',
|
|
['\b'] = '\\b',
|
|
['\f'] = '\\f',
|
|
['\n'] = '\\n',
|
|
['\r'] = '\\r',
|
|
['\t'] = '\\t',
|
|
['\v'] = '\\v',
|
|
['\\'] = '\\\\',
|
|
['"'] = '\\"',
|
|
}
|
|
|
|
local unescapes = {
|
|
['\\a'] = '\a',
|
|
['\\b'] = '\b',
|
|
['\\f'] = '\f',
|
|
['\\n'] = '\n',
|
|
['\\r'] = '\r',
|
|
['\\t'] = '\t',
|
|
['\\v'] = '\v',
|
|
['\\\\'] = '\\',
|
|
['\\"'] = '"',
|
|
}
|
|
|
|
local function escape_nonascii(c)
|
|
return escapes[c] or string.format('\\x%02x', string.byte(c))
|
|
end
|
|
|
|
|
|
local function ascii(str)
|
|
str = str:gsub('[%c\r\n\\"\128-\255]', escape_nonascii)
|
|
return str
|
|
end
|
|
|
|
|
|
local function unescape_hex(backslashes, hex)
|
|
if #backslashes % 2 == 0 then
|
|
-- Even number of backslashes, they escape each other, not the digits.
|
|
-- Return them so that next step can treat them.
|
|
return backslashes .. 'x' .. hex
|
|
else
|
|
-- Remove the odd backslash, which escapes the hex code.
|
|
-- The rest will be processed by the next step.
|
|
backslashes = backslashes:sub(1, -2)
|
|
end
|
|
local c = string.char(tonumber(hex, 16))
|
|
if c == '\\' then
|
|
-- will be unsecaped by the next step ("\x5cb" --> "\\b")
|
|
c = '\\\\'
|
|
end
|
|
return backslashes .. c
|
|
end
|
|
|
|
|
|
local function unascii(str)
|
|
--str = str:gsub('(\\+)(%d%d%d)', unescape_digits)
|
|
str = str:gsub('(\\+)x(%x%x)', unescape_hex)
|
|
str = str:gsub('\\[abfnrtv\\"]', unescapes)
|
|
return str
|
|
end
|
|
|
|
|
|
local util = {
|
|
player_get_eye_pos = player_get_eye_pos,
|
|
raycast_crosshair = raycast_crosshair,
|
|
raycast_crosshair_to_object = raycast_crosshair_to_object,
|
|
get_pointed_position = get_pointed_position,
|
|
ascii = ascii,
|
|
unascii = unascii,
|
|
}
|
|
return util
|