local player_waypoints = {} local update_interval = 1.31415 local compass_precision = 10 -- set to 1 to show whole number or 10 for 1 decimal local waypoint_color = 0xFC7D0A 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 -- lua metatables? what is that? :P -- local function get_compass_meta_id(meta) -- return meta:get_string("waypoint_compass:id") ~= "" or "default_id" -- end local function get_compass_meta_label(meta) local label = meta:get_string("waypoint_compass:label") return label ~= "" and label or "destination" end local function set_compass_meta_label(meta, label) meta:set_string("waypoint_compass:label", label) end local function set_compass_meta_pos(meta, pos) local pos_str = minetest.serialize(pos) meta:set_string("waypoint_compass:position", pos_str) end local function get_compass_meta_pos(meta) return minetest.deserialize(meta:get_string("waypoint_compass:position")) 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 local meta = itemstack:get_meta() meta:set_string("description", string.format("Waypoint compass %s", minetest.pos_to_string(pointed_pos))) set_compass_meta_pos(meta, pointed_pos) set_compass_meta_label(meta, minetest.pos_to_string(pointed_pos)) return itemstack end -- TODO handle entities? 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 player_waypoints[player_name] = nil player:hud_remove(hud_id) end local function show_hud_waypoint(player, compass_item_meta) local player_name = player:get_player_name() -- Show this waypoint local waypoint_name = get_compass_meta_label(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 = get_compass_meta_pos(compass_item_meta), }) -- store HUD elemnt id to remove it later if not player_waypoints[player_name] then player_waypoints[player_name] = {} end --print("hud_id add", hud_id) player_waypoints[player_name].pos = get_compass_meta_pos(compass_item_meta) player_waypoints[player_name].hud_id = hud_id end -- if item is a compass, then show stored waypoint local function update_hud_waypoint(player, itemstack) if not player:is_player() then return end local player_name = player:get_player_name() -- player is holding compass if (itemstack and itemstack:get_name() == "waypoint_compass:compass") then local meta = itemstack:get_meta() 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) then hide_hud_waypoint(player) end -- show new waypoint if not player_waypoints[player_name] then show_hud_waypoint(player, meta) end else -- not holding it anymore if player_waypoints[player_name] then hide_hud_waypoint(player) end end end local timer = 0 minetest.register_globalstep(function(dtime) timer = timer + dtime if timer > update_interval then for _,player in pairs(minetest.get_connected_players()) do local itemstack = player:get_wielded_item() update_hud_waypoint(player, itemstack) end timer = 0 end end) local function compass_use_callback(itemstack, user, pointed_thing) if pointed_thing.type == "nothing" then if user and user:is_player() then pointed_thing = raycast_crosshair(user, compass_range) end end set_waypoint_at_pointed_place(itemstack, pointed_thing) update_hud_waypoint(user, itemstack) end minetest.register_tool( "waypoint_compass:compass", { description = "Waypoint compass", short_description = "Waypoint compass", inventory_image = "Waypoint_compass_inventory_image.png", wield_scale = {x = 0.5, y = 0.5, z = 0.5}, range = 2.0, -- TODO what's the good range? on_place = function(itemstack, placer, pointed_thing) compass_use_callback(itemstack, placer, pointed_thing) return itemstack end, on_secondary_use = function(itemstack, user, pointed_thing) compass_use_callback(itemstack, user, pointed_thing) return itemstack end, })