795 lines
25 KiB
Lua
795 lines
25 KiB
Lua
-- Marker GUI for Persistent Map Mod
|
|
-- Provides a list interface for managing markers with delete and teleport functionality
|
|
|
|
local modname = minetest.get_current_modname()
|
|
local S = minetest.get_translator(modname)
|
|
|
|
-- Store active waypoint HUDs for players
|
|
local active_waypoints = {}
|
|
|
|
-- GUI configuration
|
|
local marker_gui = {
|
|
formspec_version = 6,
|
|
window_width = 21,
|
|
window_height = 12,
|
|
padding = 0.5,
|
|
button_height = 0.8,
|
|
button_width = 3,
|
|
list_item_height = 1.2,
|
|
scroll_height = 8,
|
|
header_height = 1.5,
|
|
footer_height = 2,
|
|
}
|
|
|
|
-- Get marker list for a player
|
|
local function get_player_markers_list(player_name)
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if not player_data_entry then
|
|
return {}
|
|
end
|
|
|
|
local markers = player_data_entry.markers
|
|
local marker_list = {}
|
|
|
|
for marker_id, marker in pairs(markers) do
|
|
table.insert(marker_list, {
|
|
id = marker_id,
|
|
name = marker.name or "Unnamed",
|
|
x = marker.x,
|
|
y = marker.y,
|
|
z = marker.z,
|
|
color_index = marker.color_index,
|
|
timestamp = marker.timestamp
|
|
})
|
|
end
|
|
|
|
-- Sort by timestamp (newest first)
|
|
table.sort(marker_list, function(a, b)
|
|
return (a.timestamp or 0) > (b.timestamp or 0)
|
|
end)
|
|
|
|
return marker_list
|
|
end
|
|
|
|
-- Add waypoint HUD for a marker
|
|
local function addWaypointHud(player, marker)
|
|
local player_name = player:get_player_name()
|
|
local wayName = marker.name or "Unnamed"
|
|
local wayPos = vector.new(marker.x, marker.y, marker.z)
|
|
|
|
-- Remove existing waypoint if any
|
|
if active_waypoints[player_name] then
|
|
player:hud_remove(active_waypoints[player_name].hudId)
|
|
active_waypoints[player_name] = nil
|
|
end
|
|
|
|
-- Add new waypoint HUD
|
|
local hudId = player:hud_add({
|
|
hud_elem_type = "waypoint",
|
|
name = wayName,
|
|
text = "m",
|
|
number = 0xFFFFFF,
|
|
world_pos = wayPos,
|
|
})
|
|
|
|
-- Store waypoint info
|
|
active_waypoints[player_name] = {
|
|
hudId = hudId,
|
|
marker_id = marker.id,
|
|
name = wayName
|
|
}
|
|
|
|
return hudId
|
|
end
|
|
|
|
-- Remove waypoint HUD for a player
|
|
local function removeWaypointHud(player)
|
|
local player_name = player:get_player_name()
|
|
if active_waypoints[player_name] then
|
|
player:hud_remove(active_waypoints[player_name].hudId)
|
|
active_waypoints[player_name] = nil
|
|
return true
|
|
end
|
|
return false
|
|
end
|
|
|
|
-- Check if player has an active waypoint for a specific marker
|
|
local function hasWaypointForMarker(player_name, marker_id)
|
|
return active_waypoints[player_name] and active_waypoints[player_name].marker_id == marker_id
|
|
end
|
|
|
|
-- Check if player has teleport permission
|
|
local function can_teleport(player_name)
|
|
local player = minetest.get_player_by_name(player_name)
|
|
if not player then return false end
|
|
|
|
-- Check for teleport privilege or if player is admin
|
|
return minetest.check_player_privs(player_name, {teleport = true}) or
|
|
minetest.check_player_privs(player_name, {server = true})
|
|
end
|
|
|
|
-- Show marker management GUI
|
|
function persistent_map.show_marker_gui(player_name)
|
|
local player = minetest.get_player_by_name(player_name)
|
|
if not player then return end
|
|
|
|
local markers = get_player_markers_list(player_name)
|
|
local can_tp = can_teleport(player_name)
|
|
|
|
-- Calculate content height based on number of markers
|
|
local content_height = math.max(marker_gui.scroll_height, #markers * marker_gui.list_item_height)
|
|
|
|
local formspec = {}
|
|
formspec[1] = string.format("formspec_version[%d]", marker_gui.formspec_version)
|
|
formspec[2] = string.format("size[%.2f,%.2f]", marker_gui.window_width, marker_gui.window_height)
|
|
formspec[3] = "bgcolor[#00000080;true]"
|
|
|
|
-- Header
|
|
local header_y = marker_gui.padding
|
|
formspec[4] = string.format("label[%.2f,%.2f;Marker Management]",
|
|
marker_gui.window_width / 2 - 3, header_y)
|
|
formspec[5] = string.format("label[%.2f,%.2f;Total Markers: %d]",
|
|
marker_gui.padding, header_y + 0.5, #markers)
|
|
|
|
-- Scrollable container for marker list
|
|
local scroll_y = header_y + marker_gui.header_height
|
|
formspec[6] = string.format(
|
|
"scroll_container[%.2f,%.2f;%.2f,%.2f;marker_list;vertical;0.1]",
|
|
marker_gui.padding, scroll_y,
|
|
marker_gui.window_width - marker_gui.padding * 2,
|
|
marker_gui.scroll_height
|
|
)
|
|
|
|
local formspec_index = 7
|
|
|
|
-- List markers
|
|
if #markers == 0 then
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;No markers found. Create markers using the map interface (/map)]",
|
|
1, 1
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
else
|
|
for i, marker in ipairs(markers) do
|
|
local y_pos = (i - 1) * marker_gui.list_item_height
|
|
local color = persistent_map.marker_colors[marker.color_index] or persistent_map.marker_colors[1]
|
|
|
|
-- Marker color indicator
|
|
formspec[formspec_index] = string.format(
|
|
"box[%.2f,%.2f;%.2f,%.2f;%s]",
|
|
0.2, y_pos + 0.1, 0.6, 0.6, color.color
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Marker information
|
|
local coords_text = string.format("(%d, %d, %d)",
|
|
math.floor(marker.x), math.floor(marker.y), math.floor(marker.z))
|
|
local distance = ""
|
|
|
|
-- Calculate distance from player
|
|
local player_pos = player:get_pos()
|
|
if player_pos then
|
|
local marker_pos = vector.new(marker.x, marker.y, marker.z)
|
|
local dist = vector.distance(player_pos, marker_pos)
|
|
distance = string.format(" - %.1fm away", dist)
|
|
end
|
|
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;%s]",
|
|
1, y_pos + 0.1, minetest.formspec_escape(marker.name)
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;%s%s]",
|
|
1, y_pos + 0.4, coords_text, distance
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Action buttons
|
|
local has_waypoint = hasWaypointForMarker(player_name, marker.id)
|
|
local button_count = can_tp and 5 or 4 -- 5 buttons if teleport available, 4 otherwise
|
|
local buttons_start_x = marker_gui.window_width - marker_gui.padding * 2 - marker_gui.button_width * button_count - 0.8
|
|
|
|
-- Edit Name button
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;edit_name_%s;Edit Name]",
|
|
buttons_start_x,
|
|
y_pos + 0.1, marker_gui.button_width, marker_gui.button_height,
|
|
marker.id
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Edit Color button
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;edit_color_%s;Edit Color]",
|
|
buttons_start_x + marker_gui.button_width + 0.1,
|
|
y_pos + 0.1, marker_gui.button_width, marker_gui.button_height,
|
|
marker.id
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Waypoint button
|
|
local waypoint_button_text = has_waypoint and "Remove Waypoint" or "Show Waypoint"
|
|
local waypoint_action = has_waypoint and "remove_waypoint_" or "show_waypoint_"
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;%s%s;%s]",
|
|
buttons_start_x + marker_gui.button_width * 2 + 0.2,
|
|
y_pos + 0.1, marker_gui.button_width, marker_gui.button_height,
|
|
waypoint_action, marker.id, waypoint_button_text
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Delete button
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;delete_%s;Delete]",
|
|
buttons_start_x + marker_gui.button_width * 3 + 0.3,
|
|
y_pos + 0.1, marker_gui.button_width, marker_gui.button_height,
|
|
marker.id
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Teleport button (only if player has permission)
|
|
if can_tp then
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;teleport_%s;Teleport]",
|
|
buttons_start_x + marker_gui.button_width * 4 + 0.4,
|
|
y_pos + 0.1, marker_gui.button_width, marker_gui.button_height,
|
|
marker.id
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Separator line
|
|
if i < #markers then
|
|
formspec[formspec_index] = string.format(
|
|
"box[%.2f,%.2f;%.2f,%.2f;#404040]",
|
|
0, y_pos + marker_gui.list_item_height - 0.1,
|
|
marker_gui.window_width - marker_gui.padding * 2, 0.05
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Close scroll container
|
|
formspec[formspec_index] = "scroll_container_end[]"
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Add marker section
|
|
local add_marker_y = marker_gui.window_height - marker_gui.footer_height - 2.5
|
|
|
|
-- Add marker label
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;Add Marker by Coordinates:]",
|
|
marker_gui.padding, add_marker_y
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Coordinate input fields
|
|
local field_width = 2.5
|
|
local field_spacing = 0.2
|
|
local fields_start_x = marker_gui.padding
|
|
|
|
-- X coordinate field
|
|
formspec[formspec_index] = string.format(
|
|
"field[%.2f,%.2f;%.2f,%.2f;coord_x;;]",
|
|
fields_start_x, add_marker_y + 0.4, field_width, 0.8
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;X:]",
|
|
fields_start_x, add_marker_y + 0.2
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Y coordinate field
|
|
local y_field_x = fields_start_x + field_width + field_spacing
|
|
formspec[formspec_index] = string.format(
|
|
"field[%.2f,%.2f;%.2f,%.2f;coord_y;;]",
|
|
y_field_x, add_marker_y + 0.4, field_width, 0.8
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;Y:]",
|
|
y_field_x, add_marker_y + 0.2
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Z coordinate field
|
|
local z_field_x = y_field_x + field_width + field_spacing
|
|
formspec[formspec_index] = string.format(
|
|
"field[%.2f,%.2f;%.2f,%.2f;coord_z;;]",
|
|
z_field_x, add_marker_y + 0.4, field_width, 0.8
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;Z:]",
|
|
z_field_x, add_marker_y + 0.2
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Marker name field
|
|
local name_field_x = z_field_x + field_width + field_spacing
|
|
formspec[formspec_index] = string.format(
|
|
"field[%.2f,%.2f;%.2f,%.2f;marker_name;;]",
|
|
name_field_x, add_marker_y + 0.4, field_width, 0.8
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;Name:]",
|
|
name_field_x, add_marker_y + 0.2
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Add marker button
|
|
local add_button_x = name_field_x + field_width + field_spacing
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;add_marker;Add Marker]",
|
|
add_button_x, add_marker_y + 0.4, marker_gui.button_width, marker_gui.button_height
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Footer buttons
|
|
local footer_y = marker_gui.window_height - marker_gui.footer_height
|
|
|
|
-- Close button
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;close;Close]",
|
|
marker_gui.padding, footer_y,
|
|
marker_gui.button_width, marker_gui.button_height
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Open map button
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;open_map;Open Map]",
|
|
marker_gui.padding + marker_gui.button_width + 0.2, footer_y,
|
|
marker_gui.button_width, marker_gui.button_height
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Delete all button
|
|
if #markers > 0 then
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;delete_all_confirm;Delete All]",
|
|
marker_gui.window_width - marker_gui.padding - marker_gui.button_width, footer_y,
|
|
marker_gui.button_width, marker_gui.button_height
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Permission info
|
|
if not can_tp then
|
|
formspec[formspec_index] = string.format(
|
|
"label[%.2f,%.2f;Note: You need 'teleport' privilege to use teleport buttons]",
|
|
marker_gui.padding, footer_y + marker_gui.button_height + 0.2
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
minetest.show_formspec(player_name, "persistent_map:marker_gui", table.concat(formspec))
|
|
end
|
|
|
|
-- Show color selection dialog for a marker
|
|
local function show_color_selection_dialog(player_name, marker_id)
|
|
local player = minetest.get_player_by_name(player_name)
|
|
if not player then return end
|
|
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if not player_data_entry or not player_data_entry.markers[marker_id] then
|
|
minetest.chat_send_player(player_name, "Error: Marker not found")
|
|
return
|
|
end
|
|
|
|
local marker = player_data_entry.markers[marker_id]
|
|
local current_color_index = marker.color_index or 1
|
|
|
|
-- Create color selection formspec
|
|
local formspec = {}
|
|
formspec[1] = string.format("formspec_version[%d]", marker_gui.formspec_version)
|
|
formspec[2] = "size[8,6]"
|
|
formspec[3] = "bgcolor[#00000080;true]"
|
|
|
|
-- Header
|
|
formspec[4] = string.format("label[4,0.5;Select Color for '%s']",
|
|
minetest.formspec_escape(marker.name or "Unnamed"))
|
|
|
|
-- Color buttons in a 4x2 grid
|
|
local colors_per_row = 4
|
|
local button_size = 1.5
|
|
local button_spacing = 0.2
|
|
local start_x = 1
|
|
local start_y = 1.5
|
|
|
|
local formspec_index = 5
|
|
|
|
for i, color_info in ipairs(persistent_map.marker_colors) do
|
|
local row = math.floor((i - 1) / colors_per_row)
|
|
local col = (i - 1) % colors_per_row
|
|
local btn_x = start_x + col * (button_size + button_spacing)
|
|
local btn_y = start_y + row * (button_size + button_spacing)
|
|
|
|
-- Add colored background
|
|
formspec[formspec_index] = string.format(
|
|
"box[%.2f,%.2f;%.2f,%.2f;%s]",
|
|
btn_x, btn_y, button_size, button_size, color_info.color
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
-- Add selection indicator for current color
|
|
if i == current_color_index then
|
|
formspec[formspec_index] = string.format(
|
|
"box[%.2f,%.2f;%.2f,%.2f;#FFFFFF40]",
|
|
btn_x - 0.1, btn_y - 0.1, button_size + 0.2, button_size + 0.2
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Color selection button
|
|
formspec[formspec_index] = string.format(
|
|
"button[%.2f,%.2f;%.2f,%.2f;select_color_%d_%s;%s]",
|
|
btn_x, btn_y, button_size, button_size, i, marker_id, color_info.name
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
end
|
|
|
|
-- Cancel button
|
|
formspec[formspec_index] = string.format(
|
|
"button[2,4.5;2,0.8;cancel_color_edit;Cancel]"
|
|
)
|
|
formspec_index = formspec_index + 1
|
|
|
|
minetest.show_formspec(player_name, "persistent_map:color_selection", table.concat(formspec))
|
|
end
|
|
|
|
-- Show name editing dialog for a marker
|
|
local function show_name_edit_dialog(player_name, marker_id)
|
|
local player = minetest.get_player_by_name(player_name)
|
|
if not player then return end
|
|
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if not player_data_entry or not player_data_entry.markers[marker_id] then
|
|
minetest.chat_send_player(player_name, "Error: Marker not found")
|
|
return
|
|
end
|
|
|
|
local marker = player_data_entry.markers[marker_id]
|
|
local current_name = marker.name or "Unnamed"
|
|
|
|
-- Create name editing formspec
|
|
local formspec = {}
|
|
formspec[1] = string.format("formspec_version[%d]", marker_gui.formspec_version)
|
|
formspec[2] = "size[8,4]"
|
|
formspec[3] = "bgcolor[#00000080;true]"
|
|
|
|
-- Header
|
|
formspec[4] = string.format("label[4,0.5;Edit Marker Name]")
|
|
|
|
-- Current name label
|
|
formspec[5] = string.format("label[1,1.2;Current name: %s]",
|
|
minetest.formspec_escape(current_name))
|
|
|
|
-- Name input field
|
|
formspec[6] = string.format("field[1,1.8;6,0.8;new_marker_name;New name:;%s]",
|
|
minetest.formspec_escape(current_name))
|
|
|
|
-- Store marker ID for the handler
|
|
formspec[7] = string.format("field[0,0;0,0;marker_id_hidden;;%s]", marker_id)
|
|
|
|
-- Buttons
|
|
formspec[8] = "button[1,2.8;2,0.8;save_name;Save]"
|
|
formspec[9] = "button[4,2.8;2,0.8;cancel_name_edit;Cancel]"
|
|
|
|
minetest.show_formspec(player_name, "persistent_map:name_edit", table.concat(formspec))
|
|
end
|
|
|
|
-- Handle marker GUI input
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname ~= "persistent_map:marker_gui" then return end
|
|
|
|
local player_name = player:get_player_name()
|
|
|
|
-- Close button
|
|
if fields.close or fields.quit then
|
|
return
|
|
end
|
|
|
|
-- Open map button
|
|
if fields.open_map then
|
|
-- Reset view offset when opening map
|
|
persistent_map.set_map_view_offset(player_name, {x = 0, z = 0})
|
|
-- Initialize zoom level if not set
|
|
if not persistent_map.get_map_zoom_level(player_name) then
|
|
persistent_map.set_map_zoom_level(player_name, persistent_map.default_zoom_index)
|
|
end
|
|
persistent_map.show_map(player_name)
|
|
return
|
|
end
|
|
|
|
-- Delete all confirmation
|
|
if fields.delete_all_confirm then
|
|
local success, message = persistent_map.delete_all_markers_for_player(player_name)
|
|
minetest.chat_send_player(player_name, message)
|
|
if success then
|
|
persistent_map.show_marker_gui(player_name) -- Refresh the GUI
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Add marker by coordinates
|
|
if fields.add_marker then
|
|
local x_str = fields.coord_x or ""
|
|
local y_str = fields.coord_y or ""
|
|
local z_str = fields.coord_z or ""
|
|
local name_str = fields.marker_name or ""
|
|
|
|
-- Validate coordinates
|
|
local x = tonumber(x_str)
|
|
local y = tonumber(y_str)
|
|
local z = tonumber(z_str)
|
|
|
|
if not x or not y or not z then
|
|
minetest.chat_send_player(player_name, "Error: Please enter valid numeric coordinates for X, Y, and Z")
|
|
return
|
|
end
|
|
|
|
-- Use default name if none provided
|
|
if name_str == "" then
|
|
name_str = string.format("Marker at %d,%d,%d", math.floor(x), math.floor(y), math.floor(z))
|
|
end
|
|
|
|
-- Create the marker
|
|
local marker_pos = {x = x, y = y, z = z}
|
|
local success, message = persistent_map.add_marker_for_player(player_name, marker_pos, name_str)
|
|
|
|
minetest.chat_send_player(player_name, message)
|
|
|
|
if success then
|
|
-- Refresh the GUI to show the new marker
|
|
persistent_map.show_marker_gui(player_name)
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Check for individual marker actions
|
|
for field_name, _ in pairs(fields) do
|
|
-- Delete marker
|
|
local delete_match = field_name:match("^delete_(.+)$")
|
|
if delete_match then
|
|
local marker_id = delete_match
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if player_data_entry and player_data_entry.markers[marker_id] then
|
|
local marker = player_data_entry.markers[marker_id]
|
|
player_data_entry.markers[marker_id] = nil
|
|
persistent_map.save_markers_for_player(player_name, player_data_entry.markers)
|
|
minetest.chat_send_player(player_name,
|
|
string.format("Deleted marker '%s'", marker.name or "Unnamed"))
|
|
persistent_map.show_marker_gui(player_name) -- Refresh the GUI
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Teleport to marker
|
|
local teleport_match = field_name:match("^teleport_(.+)$")
|
|
if teleport_match then
|
|
local marker_id = teleport_match
|
|
|
|
-- Check permission
|
|
if not can_teleport(player_name) then
|
|
minetest.chat_send_player(player_name,
|
|
"You don't have permission to teleport. Need 'teleport' privilege.")
|
|
return
|
|
end
|
|
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if player_data_entry and player_data_entry.markers[marker_id] then
|
|
local marker = player_data_entry.markers[marker_id]
|
|
local pos = vector.new(marker.x, marker.y + 1, marker.z) -- +1 to avoid spawning in ground
|
|
|
|
-- Check if position is safe (not in solid blocks)
|
|
local node_at = minetest.get_node(pos)
|
|
local node_above = minetest.get_node(vector.add(pos, {x=0, y=1, z=0}))
|
|
|
|
-- If position is not safe, try to find a safe spot nearby
|
|
if node_at.name ~= "air" or node_above.name ~= "air" then
|
|
-- Try to find air space above the marker
|
|
for y_offset = 2, 10 do
|
|
local test_pos = vector.new(marker.x, marker.y + y_offset, marker.z)
|
|
local test_node = minetest.get_node(test_pos)
|
|
local test_above = minetest.get_node(vector.add(test_pos, {x=0, y=1, z=0}))
|
|
|
|
if test_node.name == "air" and test_above.name == "air" then
|
|
pos = test_pos
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
player:set_pos(pos)
|
|
minetest.chat_send_player(player_name,
|
|
string.format("Teleported to marker '%s' at %d, %d, %d",
|
|
marker.name or "Unnamed",
|
|
math.floor(marker.x), math.floor(marker.y), math.floor(marker.z)))
|
|
|
|
-- Close the GUI after teleporting
|
|
minetest.close_formspec(player_name, "persistent_map:marker_gui")
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Edit color for marker
|
|
local edit_color_match = field_name:match("^edit_color_(.+)$")
|
|
if edit_color_match then
|
|
local marker_id = edit_color_match
|
|
show_color_selection_dialog(player_name, marker_id)
|
|
return
|
|
end
|
|
|
|
-- Edit name for marker
|
|
local edit_name_match = field_name:match("^edit_name_(.+)$")
|
|
if edit_name_match then
|
|
local marker_id = edit_name_match
|
|
show_name_edit_dialog(player_name, marker_id)
|
|
return
|
|
end
|
|
|
|
-- Show waypoint for marker
|
|
local show_waypoint_match = field_name:match("^show_waypoint_(.+)$")
|
|
if show_waypoint_match then
|
|
local marker_id = show_waypoint_match
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if player_data_entry and player_data_entry.markers[marker_id] then
|
|
local marker = player_data_entry.markers[marker_id]
|
|
marker.id = marker_id -- Ensure marker has ID for waypoint tracking
|
|
addWaypointHud(player, marker)
|
|
minetest.chat_send_player(player_name,
|
|
string.format("Waypoint set for marker '%s'", marker.name or "Unnamed"))
|
|
persistent_map.show_marker_gui(player_name) -- Refresh the GUI
|
|
end
|
|
return
|
|
end
|
|
|
|
-- Remove waypoint for marker
|
|
local remove_waypoint_match = field_name:match("^remove_waypoint_(.+)$")
|
|
if remove_waypoint_match then
|
|
local marker_id = remove_waypoint_match
|
|
if removeWaypointHud(player) then
|
|
minetest.chat_send_player(player_name, "Waypoint removed")
|
|
else
|
|
minetest.chat_send_player(player_name, "No active waypoint found")
|
|
end
|
|
persistent_map.show_marker_gui(player_name) -- Refresh the GUI
|
|
return
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Handle name editing dialog input
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname ~= "persistent_map:name_edit" then return end
|
|
|
|
local player_name = player:get_player_name()
|
|
|
|
-- Cancel button
|
|
if fields.cancel_name_edit or fields.quit then
|
|
persistent_map.show_marker_gui(player_name) -- Return to marker GUI
|
|
return
|
|
end
|
|
|
|
-- Save button
|
|
if fields.save_name then
|
|
local new_name = fields.new_marker_name or ""
|
|
local marker_id = fields.marker_id_hidden or ""
|
|
|
|
-- Validate input
|
|
if marker_id == "" then
|
|
minetest.chat_send_player(player_name, "Error: Invalid marker ID")
|
|
persistent_map.show_marker_gui(player_name)
|
|
return
|
|
end
|
|
|
|
-- Trim whitespace and validate name
|
|
new_name = string.gsub(new_name, "^%s*(.-)%s*$", "%1")
|
|
if new_name == "" then
|
|
minetest.chat_send_player(player_name, "Error: Marker name cannot be empty")
|
|
return
|
|
end
|
|
|
|
-- Update marker name
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if player_data_entry and player_data_entry.markers[marker_id] then
|
|
local marker = player_data_entry.markers[marker_id]
|
|
local old_name = marker.name or "Unnamed"
|
|
|
|
marker.name = new_name
|
|
persistent_map.save_markers_for_player(player_name, player_data_entry.markers)
|
|
|
|
minetest.chat_send_player(player_name,
|
|
string.format("Renamed marker from '%s' to '%s'", old_name, new_name))
|
|
|
|
-- Return to marker GUI
|
|
persistent_map.show_marker_gui(player_name)
|
|
else
|
|
minetest.chat_send_player(player_name, "Error: Marker not found")
|
|
persistent_map.show_marker_gui(player_name)
|
|
end
|
|
return
|
|
end
|
|
end)
|
|
|
|
-- Handle color selection dialog input
|
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
|
if formname ~= "persistent_map:color_selection" then return end
|
|
|
|
local player_name = player:get_player_name()
|
|
|
|
-- Cancel button
|
|
if fields.cancel_color_edit or fields.quit then
|
|
persistent_map.show_marker_gui(player_name) -- Return to marker GUI
|
|
return
|
|
end
|
|
|
|
-- Check for color selection
|
|
for field_name, _ in pairs(fields) do
|
|
local color_match = field_name:match("^select_color_(%d+)_(.+)$")
|
|
if color_match then
|
|
local color_index = tonumber(color_match)
|
|
local marker_id = field_name:match("^select_color_%d+_(.+)$")
|
|
|
|
if color_index and marker_id then
|
|
local player_data_entry = persistent_map.get_player_data(player_name)
|
|
if player_data_entry and player_data_entry.markers[marker_id] then
|
|
local marker = player_data_entry.markers[marker_id]
|
|
local old_color = persistent_map.marker_colors[marker.color_index] or persistent_map.marker_colors[1]
|
|
local new_color = persistent_map.marker_colors[color_index] or persistent_map.marker_colors[1]
|
|
|
|
-- Update marker color
|
|
marker.color_index = color_index
|
|
persistent_map.save_markers_for_player(player_name, player_data_entry.markers)
|
|
|
|
minetest.chat_send_player(player_name,
|
|
string.format("Changed color of marker '%s' from %s to %s",
|
|
marker.name or "Unnamed", old_color.name, new_color.name))
|
|
|
|
-- Return to marker GUI
|
|
persistent_map.show_marker_gui(player_name)
|
|
end
|
|
end
|
|
return
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Register chat command to open marker GUI
|
|
minetest.register_chatcommand("markers", {
|
|
description = S("Open the marker management interface"),
|
|
func = function(name)
|
|
persistent_map.show_marker_gui(name)
|
|
return true, S("Marker GUI opened")
|
|
end,
|
|
})
|
|
|
|
-- Also register as /marker for convenience
|
|
minetest.register_chatcommand("marker", {
|
|
description = S("Open the marker management interface"),
|
|
func = function(name)
|
|
persistent_map.show_marker_gui(name)
|
|
return true, S("Marker GUI opened")
|
|
end,
|
|
})
|
|
|
|
-- Clean up waypoints when player leaves
|
|
minetest.register_on_leaveplayer(function(player)
|
|
local player_name = player:get_player_name()
|
|
if active_waypoints[player_name] then
|
|
active_waypoints[player_name] = nil
|
|
end
|
|
end)
|
|
|
|
minetest.log("action", "[persistent_map] Marker GUI loaded successfully")
|