use waypoint_lib

This commit is contained in:
whosit 2021-05-27 08:46:57 +03:00
parent f3a39cba09
commit 037930fec0
13 changed files with 348 additions and 43 deletions

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 801 B

BIN
textures/arrow_010.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 932 B

BIN
textures/arrow_020.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

BIN
textures/arrow_030.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 900 B

BIN
textures/arrow_040.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 939 B

BIN
textures/arrow_050.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 925 B

BIN
textures/arrow_060.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 935 B

BIN
textures/arrow_070.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 887 B

BIN
textures/arrow_080.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

BIN
textures/waypoint.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 501 B

68
waypoint.svg Normal file
View 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
View 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