use waypoint_lib
68
init.lua
@ -5,7 +5,10 @@ local TARGET_ABOVE = false -- place waypoint inside the block or above it
|
||||
local POINT_TO_OBJECTS = false -- unimplemented
|
||||
local POINT_TO_LIQUIDS = true
|
||||
local COMPASS_RANGE = 180
|
||||
local WAYPOINT_ICON = "waypoint.png"
|
||||
local WAYPOINT_SCALE = {x=-1/16*9,y=-1}
|
||||
|
||||
local waypoint_lib = dofile(minetest.get_modpath("waypoint_announce") .. "/waypoint_lib.lua")
|
||||
|
||||
-- internal mod state
|
||||
local player_waypoints = {} -- store a current player waypoint to see if it needs to be updated
|
||||
@ -66,16 +69,6 @@ local function get_compass_meta_owner(meta)
|
||||
end
|
||||
|
||||
|
||||
-- local function set_compass_meta_pos(meta, pos)
|
||||
-- local pos_hash = minetest.hash_node_position(pos)
|
||||
-- meta:set_int("waypoint_compass:position", pos_hash)
|
||||
-- end
|
||||
|
||||
|
||||
-- local function get_compass_meta_pos(meta)
|
||||
-- return minetest.get_position_from_hash(meta:get_int("waypoint_compass:position"))
|
||||
-- end
|
||||
|
||||
local function set_waypoint_at_pointed_place(itemstack, pointed_thing)
|
||||
if pointed_thing and pointed_thing.type == "node" then
|
||||
local pointed_pos = TARGET_ABOVE and pointed_thing.above or pointed_thing.under
|
||||
@ -90,27 +83,11 @@ local function set_waypoint_at_pointed_place(itemstack, pointed_thing)
|
||||
end
|
||||
|
||||
|
||||
-- return first thing player is pointing at
|
||||
local function raycast_crosshair(player, range)
|
||||
local p_pos = player:get_pos()
|
||||
local p_eye_height = player:get_properties().eye_height
|
||||
local p_eye_pos = { x = p_pos.x, y = p_pos.y + p_eye_height, z = p_pos.z }
|
||||
local to = vector.add(p_eye_pos, vector.multiply(player:get_look_dir(), range))
|
||||
local ray = minetest.raycast(p_eye_pos, to, POINT_TO_OBJECTS, POINT_TO_LIQUIDS)
|
||||
local pointed_thing = ray:next()
|
||||
return pointed_thing
|
||||
-- while pointed_thing do
|
||||
-- print(pointed_thing.type, minetest.pos_to_string(pointed_thing.under))
|
||||
-- pointed_thing = ray:next()
|
||||
-- end
|
||||
end
|
||||
|
||||
|
||||
local function hide_hud_waypoint(player)
|
||||
local player_name = player:get_player_name()
|
||||
local hud_id = player_waypoints[player_name].hud_id
|
||||
local hud = player_waypoints[player_name]
|
||||
player_waypoints[player_name] = nil
|
||||
player:hud_remove(hud_id)
|
||||
hud:hide(player)
|
||||
end
|
||||
|
||||
|
||||
@ -121,24 +98,29 @@ local function show_hud_waypoint(player, compass_item_meta)
|
||||
-- do not show unset compass position
|
||||
return
|
||||
end
|
||||
|
||||
-- Show this waypoint
|
||||
local waypoint_name = get_compass_meta_label(compass_item_meta)
|
||||
local waypoint_color = get_compass_meta_color(compass_item_meta)
|
||||
local hud_id = player:hud_add({
|
||||
hud_elem_type = "waypoint",
|
||||
name = waypoint_name,
|
||||
text = "m",
|
||||
precision= COMPASS_PRECISION,
|
||||
number = waypoint_color,
|
||||
world_pos = waypoint_pos,
|
||||
})
|
||||
local hexcolor = ("#%06X"):format(waypoint_color)
|
||||
|
||||
local size = {x=-9, y=-16}
|
||||
local alignment = {x=100/9*1.47,y=100/16*1.63} -- near compass in your hand
|
||||
|
||||
local waypoint = waypoint_lib.WaypointHUD:new(player, waypoint_pos,
|
||||
waypoint_name, waypoint_color,
|
||||
WAYPOINT_ICON, WAYPOINT_SCALE, hexcolor,
|
||||
size, alignment, "arrow_%03d.png", hexcolor, 9,
|
||||
true)
|
||||
|
||||
waypoint:show(player)
|
||||
-- store HUD elemnt id to remove it later
|
||||
if not player_waypoints[player_name] then
|
||||
player_waypoints[player_name] = {}
|
||||
if player_waypoints[player_name] then
|
||||
minetest.log("error","[MOD] waypoint_compass: " ..
|
||||
player:get_player_name() ..
|
||||
" got their HUD stuck on screen?")
|
||||
end
|
||||
--print("hud_id add", hud_id)
|
||||
player_waypoints[player_name].pos = waypoint_pos
|
||||
player_waypoints[player_name].hud_id = hud_id
|
||||
player_waypoints[player_name] = waypoint
|
||||
end
|
||||
|
||||
|
||||
@ -155,7 +137,7 @@ local function update_hud_waypoint(player, itemstack, force)
|
||||
local waypoint_pos = get_compass_meta_pos(meta)
|
||||
-- remove different waypoint if it exists
|
||||
if player_waypoints[player_name] and
|
||||
(player_waypoints[player_name].pos ~= waypoint_pos
|
||||
(player_waypoints[player_name].point_pos ~= waypoint_pos
|
||||
or force
|
||||
or not get_compass_meta_is_set(meta)) then
|
||||
|
||||
@ -260,7 +242,7 @@ local function compass_use_callback(itemstack, user, pointed_thing)
|
||||
if user:get_player_control()["sneak"] then
|
||||
if pointed_thing.type == "nothing" then
|
||||
if user and user:is_player() then
|
||||
pointed_thing = raycast_crosshair(user, COMPASS_RANGE)
|
||||
pointed_thing = waypoint_lib.raycast_crosshair(user, COMPASS_RANGE, POINT_TO_OBJECTS, POINT_TO_LIQUIDS)
|
||||
end
|
||||
end
|
||||
set_waypoint_at_pointed_place(itemstack, pointed_thing)
|
||||
|
BIN
textures/arrow_000.png
Normal file
After Width: | Height: | Size: 801 B |
BIN
textures/arrow_010.png
Normal file
After Width: | Height: | Size: 932 B |
BIN
textures/arrow_020.png
Normal file
After Width: | Height: | Size: 933 B |
BIN
textures/arrow_030.png
Normal file
After Width: | Height: | Size: 900 B |
BIN
textures/arrow_040.png
Normal file
After Width: | Height: | Size: 939 B |
BIN
textures/arrow_050.png
Normal file
After Width: | Height: | Size: 925 B |
BIN
textures/arrow_060.png
Normal file
After Width: | Height: | Size: 935 B |
BIN
textures/arrow_070.png
Normal file
After Width: | Height: | Size: 887 B |
BIN
textures/arrow_080.png
Normal file
After Width: | Height: | Size: 898 B |
BIN
textures/waypoint.png
Normal file
After Width: | Height: | Size: 501 B |
68
waypoint.svg
Normal file
@ -0,0 +1,68 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="16.0px"
|
||||
height="16.0px"
|
||||
viewBox="0 0 16.0 16.0"
|
||||
version="1.1"
|
||||
id="SVGRoot"
|
||||
sodipodi:docname="waypoint.svg"
|
||||
inkscape:version="1.0.2 (e86c870879, 2021-01-15)">
|
||||
<defs
|
||||
id="defs18" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="44.8"
|
||||
inkscape:cx="5.8765185"
|
||||
inkscape:cy="9.7673965"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
inkscape:document-rotation="0"
|
||||
showgrid="true"
|
||||
inkscape:window-width="2556"
|
||||
inkscape:window-height="1436"
|
||||
inkscape:window-x="1280"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid27"
|
||||
dotted="true"
|
||||
originx="0.5"
|
||||
originy="0.5" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata21">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1">
|
||||
<circle
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-opacity:1"
|
||||
id="path42"
|
||||
cx="8"
|
||||
cy="8"
|
||||
r="7.5" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
255
waypoint_lib.lua
Normal file
@ -0,0 +1,255 @@
|
||||
local WAYPOINT_PRECISION = 1 -- set to 1 to show whole number or 10 for 1 decimal
|
||||
local UPDATE_INTERVAL = 0.22
|
||||
|
||||
|
||||
-- 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 = minetest.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
|
||||
|
||||
|
||||
-- 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 function round(x)
|
||||
local f = math.floor(x)
|
||||
if (x == f) or (x % 2.0 == 0.5) then
|
||||
return f
|
||||
else
|
||||
return math.floor(x + 0.5)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function get_texture_rotation_for_direction(dir, quad_steps)
|
||||
-- angle relative to player position
|
||||
local angle = math.atan2(dir.x, dir.z)
|
||||
local pi = math.pi
|
||||
-- snap/round to increments and convert to degrees
|
||||
local bias = 1/quad_steps/2 -- add bias to floor into correct quardant
|
||||
local angle_quad = math.floor(angle/(2*pi) * 4 + bias) * (360 / 4) % 360
|
||||
local angle_quad_map = {[0] = "I", [90] = "R270", [180] = "R180", [270] = "R90"}
|
||||
local step_size = 90/quad_steps
|
||||
local angle_quad_step = (round((math.deg(angle) - angle_quad)/step_size) * step_size) % 90
|
||||
return angle_quad_step, angle_quad_map[angle_quad]
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [[ Waypoint HUD element with distance, label an icon above it ]] --
|
||||
local IconWaypointHUD = {}
|
||||
function IconWaypointHUD:new(point_pos, label, label_color, icon, icon_scale, icon_color)
|
||||
local w = {
|
||||
hud_id_label = nil,
|
||||
hud_id_icon = nil,
|
||||
}
|
||||
self.__index = self
|
||||
setmetatable(w, self)
|
||||
|
||||
w.huddef_label = {
|
||||
hud_elem_type = "waypoint",
|
||||
name = label,
|
||||
text = "m", -- distance suffix
|
||||
precision = WAYPOINT_PRECISION, -- TODO make this configurable?
|
||||
number = label_color,
|
||||
world_pos = point_pos,
|
||||
offset = {x=0,y=0},
|
||||
alignment = {x=0, y=1}, -- move down
|
||||
}
|
||||
|
||||
w.huddef_icon = {
|
||||
hud_elem_type = "image_waypoint",
|
||||
scale = icon_scale,
|
||||
text = icon .. "^[multiply:" .. icon_color,
|
||||
alignment = {x=0,y=-1},
|
||||
world_pos = point_pos,
|
||||
offset = {x=0,y=0},
|
||||
--name = name,
|
||||
--precision = WAYPOINT_PRECISION,
|
||||
--number = waypoint_color,
|
||||
}
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
|
||||
function IconWaypointHUD:show(player)
|
||||
--self.player_name = player:get_player_name()
|
||||
self.hud_id_label = player:hud_add(self.huddef_label)
|
||||
self.hud_id_icon = player:hud_add(self.huddef_icon)
|
||||
end
|
||||
|
||||
|
||||
function IconWaypointHUD:hide(player)
|
||||
player:hud_remove(self.hud_id_label)
|
||||
player:hud_remove(self.hud_id_icon)
|
||||
end
|
||||
|
||||
|
||||
function IconWaypointHUD:update(player)
|
||||
error("No reason to call IconWaypointHUD:update(), fix your code")
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
-- [[ Just an arrow HUD element. Can be turned any direction with update() ]] --
|
||||
local CompassHUD = {}
|
||||
function CompassHUD:new(size, alignment, direction, icon_format, icon_color, quad_steps)
|
||||
local c = {
|
||||
icon_format = icon_format,
|
||||
icon_color = icon_color,
|
||||
quad_steps = quad_steps,
|
||||
-- TODO have a callback to auto-update the direction?
|
||||
}
|
||||
self.__index = self
|
||||
setmetatable(c, self)
|
||||
|
||||
local texture = c:get_texture(direction)
|
||||
|
||||
c.huddef_compass = {
|
||||
hud_elem_type = "compass",
|
||||
size = size,
|
||||
text = texture,
|
||||
alignment = alignment,
|
||||
dir = 1,
|
||||
}
|
||||
|
||||
return c
|
||||
end
|
||||
|
||||
|
||||
function CompassHUD:get_texture(direction)
|
||||
local angle_quad_step, rotation_t = get_texture_rotation_for_direction(direction, self.quad_steps)
|
||||
|
||||
local texture = self.icon_format:format(angle_quad_step) .. "^[transform" .. rotation_t .. "^[multiply:" .. self.icon_color
|
||||
return texture
|
||||
end
|
||||
|
||||
|
||||
function CompassHUD:show(player)
|
||||
--self.player_name = player:get_player_name()
|
||||
self.hud_id_compass = player:hud_add(self.huddef_compass)
|
||||
end
|
||||
|
||||
|
||||
function CompassHUD:hide(player)
|
||||
player:hud_remove(self.hud_id_compass)
|
||||
end
|
||||
|
||||
|
||||
function CompassHUD:update(player, direction)
|
||||
player:hud_change(self.hud_id_compass, "text", self:get_texture(direction))
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
local WaypointHUD = {}
|
||||
function WaypointHUD:new(player, point_pos,
|
||||
label, label_color,
|
||||
point_icon, point_icon_scale, point_color,
|
||||
size, alignment, arrow_icon_format, arrow_icon_color, quad_steps,
|
||||
do_auto_update)
|
||||
local w = {
|
||||
point_pos = point_pos,
|
||||
do_auto_update = do_auto_update,
|
||||
auto_update_job = nil,
|
||||
}
|
||||
self.__index = self
|
||||
setmetatable(w, self)
|
||||
|
||||
w.waypoint_hud = IconWaypointHUD:new(point_pos, label, label_color, point_icon, point_icon_scale, point_color)
|
||||
|
||||
local d = vector.subtract(point_pos, player:get_pos())
|
||||
w.compass_hud = CompassHUD:new(size, alignment, d, arrow_icon_format, arrow_icon_color, quad_steps)
|
||||
|
||||
return w
|
||||
end
|
||||
|
||||
|
||||
function WaypointHUD:show(player)
|
||||
self.waypoint_hud:show(player)
|
||||
self.compass_hud:show(player)
|
||||
self:update(player) -- FIXME? needed to start auto update
|
||||
end
|
||||
|
||||
|
||||
function WaypointHUD:hide(player)
|
||||
self.waypoint_hud:hide(player)
|
||||
self.compass_hud:hide(player)
|
||||
if self.auto_update_job then
|
||||
self.auto_update_job.cancel()
|
||||
self.auto_update_job = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function WaypointHUD:update(player)
|
||||
local direction = vector.subtract(self.point_pos, player:get_pos())
|
||||
self.compass_hud:update(player, direction)
|
||||
if self.do_auto_update then
|
||||
local player_name = player:get_player_name()
|
||||
local job = minetest.after(UPDATE_INTERVAL,
|
||||
function()
|
||||
local player = minetest.get_player_by_name(player_name)
|
||||
if player then
|
||||
self:update(player)
|
||||
end
|
||||
end
|
||||
)
|
||||
self.auto_update_job = job
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
waypoint_lib = {
|
||||
raycast_crosshair = raycast_crosshair,
|
||||
get_pointed_position = get_pointed_position,
|
||||
player_hud_add_waypoint_compass = player_hud_add_waypoint_compass,
|
||||
player_hud_update_waypoint_compass = player_hud_update_waypoint_compass,
|
||||
IconWaypointHUD = IconWaypointHUD,
|
||||
CompassHUD = CompassHUD,
|
||||
WaypointHUD = WaypointHUD,
|
||||
}
|
||||
|
||||
return waypoint_lib
|