diff --git a/README.md b/README.md index 69ad233..fc5b041 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,20 @@ ## Warning -This is mostly useless now, as this requires a `/mrkr` command to exist on the -server. You probably want the (nicer) -[non-CSM](https://git.minetest.land/luk3yx/advmarkers) mod. *This CSM does not -co-operate with the server-side mod except for the fact that it provides a -`/mrkr` command, if you play on a server with the server-side mod you don't -need this.* +This is mostly useless if you use Minetest 0.4, as without the CSM HUD API this +CSM requires a `/mrkr` command to exist on the server. You probably want the +(nicer) [non-CSM](https://git.minetest.land/luk3yx/advmarkers) mod instead. + +*This CSM does not co-operate with the server-side mod except for the fact that +it provides a `/mrkr` command, if you play on a server with the server-side mod +you don't need this.* ## Original README A marker/waypoint CSM for Minetest, designed for use with the (now-defunct) marker mod. -To display markers, the server currently needs the advmarkers server-side mod (or the marker mod) installed, -otherwise "command not found" errors will be displayed, as CSMs cannot currently -create HUDs on their own. +This CSM works by itself on Minetest 5.0.0+, and with the server-side mod +installed on Minetest 0.4. ## How to use @@ -28,6 +28,7 @@ create HUDs on their own. - `.mrkr_upload`: Uploads your markers to your current server's advmarkers [server-side mod]. - `.mrkrthere`: Sets a marker at the last `.coords` position. + - `.clrmrkr`: Hides the currently displayed waypoint. If you die, a marker is automatically added at your death position, and will update the last `.coords` position. diff --git a/init.lua b/init.lua index 51daf4a..3bd50ff 100644 --- a/init.lua +++ b/init.lua @@ -30,50 +30,78 @@ local function string_to_pos(pos) end -- Set the HUD position --- TODO: Make this entirely client-side or allow the command to be changed. -function advmarkers.set_hud_pos(pos) +local hud_id +function advmarkers.set_hud_pos(pos, title) pos = string_to_pos(pos) if not pos then return end - minetest.run_server_chatcommand('mrkr', tostring(pos.x) .. ' ' .. - tostring(pos.y) .. ' ' .. tostring(pos.z)) + + -- Fall back to /mrkr if hud_add doesn't exist (Minetest 0.4). + if not minetest.localplayer or not minetest.localplayer.hud_add or + not minetest.localplayer.hud_change then + minetest.run_server_chatcommand('mrkr', tostring(pos.x) .. ' ' .. + tostring(pos.y) .. ' ' .. tostring(pos.z)) + end + + if not title then + title = pos.x .. ', ' .. pos.y .. ', ' .. pos.z + end + if hud_id then + minetest.localplayer:hud_change(hud_id, 'name', title) + minetest.localplayer:hud_change(hud_id, 'world_pos', pos) + else + hud_id = minetest.localplayer:hud_add({ + hud_elem_type = 'waypoint', + name = title, + text = 'm', + number = 0x00ffff, + world_pos = pos + }) + end + minetest.display_chat_message('Waypoint set to ' .. + minetest.colorize('#00ffff', title)) return true end --- Add a marker -function advmarkers.set_marker(pos, name) +-- Add a waypoint +function advmarkers.set_waypoint(pos, name) pos = pos_to_string(pos) if not pos then return end storage:set_string('marker-' .. tostring(name), pos) return true end +advmarkers.set_marker = advmarkers.set_waypoint --- Delete a marker -function advmarkers.delete_marker(name) +-- Delete a waypoint +function advmarkers.delete_waypoint(name) storage:set_string('marker-' .. tostring(name), '') end +advmarkers.delete_marker = advmarkers.delete_waypoint --- Get a marker -function advmarkers.get_marker(name) +-- Get a waypoint +function advmarkers.get_waypoint(name) return string_to_pos(storage:get_string('marker-' .. tostring(name))) end +advmarkers.get_marker = advmarkers.get_waypoint --- Rename a marker and re-interpret the position. -function advmarkers.rename_marker(oldname, newname) +-- Rename a waypoint and re-interpret the position. +function advmarkers.rename_waypoint(oldname, newname) oldname, newname = tostring(oldname), tostring(newname) - local pos = advmarkers.get_marker(oldname) - if not pos or not advmarkers.set_marker(pos, newname) then return end + local pos = advmarkers.get_waypoint(oldname) + if not pos or not advmarkers.set_waypoint(pos, newname) then return end if oldname ~= newname then - advmarkers.delete_marker(oldname) + advmarkers.delete_waypoint(oldname) end return true end +advmarkers.rename_marker = advmarkers.rename_waypoint --- Display a marker -function advmarkers.display_marker(name) - return advmarkers.set_hud_pos(advmarkers.get_marker(name)) +-- Display a waypoint +function advmarkers.display_waypoint(name) + return advmarkers.set_hud_pos(advmarkers.get_waypoint(name), name) end +advmarkers.display_marker = advmarkers.display_waypoint --- Export markers +-- Export waypoints function advmarkers.export(raw) local s = storage:to_table().fields if raw == 'M' then @@ -86,7 +114,7 @@ function advmarkers.export(raw) return s end --- Import markers +-- Import waypoints function advmarkers.import(s) if type(s) ~= 'table' then local ver = s:sub(1, 1) @@ -101,7 +129,7 @@ function advmarkers.import(s) end end - -- Iterate over markers to preserve existing ones and check for errors. + -- Iterate over waypoints to preserve existing ones and check for errors. if type(s) == 'table' then for name, pos in pairs(s) do if type(name) == 'string' and type(pos) == 'string' and @@ -124,92 +152,126 @@ function advmarkers.import(s) end end --- Get the markers formspec +-- Get the waypoints formspec local formspec_list = {} local selected_name = false function advmarkers.display_formspec() local formspec = 'size[5.25,8]' .. - 'label[0,0;Marker list]' .. + 'label[0,0;Waypoint list]' .. 'button_exit[0,7.5;1.3125,0.5;display;Display]' .. 'button[1.3125,7.5;1.3125,0.5;teleport;Teleport]' .. 'button[2.625,7.5;1.3125,0.5;rename;Rename]' .. 'button[3.9375,7.5;1.3125,0.5;delete;Delete]' .. 'textlist[0,0.75;5,6;marker;' - -- Iterate over all the markers - local id = 0 + -- Iterate over all the waypoints local selected = 1 formspec_list = {} - for name, pos in pairs(storage:to_table().fields) do + + local waypoints = {} + for name, _ in pairs(storage:to_table().fields) do if name:sub(1, 7) == 'marker-' then - id = id + 1 - if id > 1 then - formspec = formspec .. ',' - end - name = name:sub(8) - if not selected_name then - selected_name = name - end - if name == selected_name then - selected = id - end - formspec_list[#formspec_list + 1] = name - formspec = formspec .. '##' .. minetest.formspec_escape(name) + table.insert(waypoints, name:sub(8)) end end + table.sort(waypoints) - -- Close the text list and display the selected marker position + for id, name in ipairs(waypoints) do + if id > 1 then + formspec = formspec .. ',' + end + if not selected_name then + selected_name = name + end + if name == selected_name then + selected = id + end + formspec_list[#formspec_list + 1] = name + formspec = formspec .. '##' .. minetest.formspec_escape(name) + end + + -- Close the text list and display the selected waypoint position formspec = formspec .. ';' .. tostring(selected) .. ']' if selected_name then - local pos = advmarkers.get_marker(selected_name) + local pos = advmarkers.get_waypoint(selected_name) if pos then pos = minetest.formspec_escape(tostring(pos.x) .. ', ' .. tostring(pos.y) .. ', ' .. tostring(pos.z)) - pos = 'Marker position: ' .. pos + pos = 'Waypoint position: ' .. pos formspec = formspec .. 'label[0,6.75;' .. pos .. ']' end else -- Draw over the buttons formspec = formspec .. 'button_exit[0,7.5;5.25,0.5;quit;Close dialog]' .. - 'label[0,6.75;No markers. Add one with ".add_mrkr".]' + 'label[0,6.75;No waypoints. Add one with ".add_mrkr".]' end -- Display the formspec return minetest.show_formspec('advmarkers-csm', formspec) end --- Open the markers GUI +function advmarkers.get_chatcommand_pos(pos) + if pos == 'h' or pos == 'here' then + pos = minetest.localplayer:get_pos() + elseif pos == 't' or pos == 'there' then + if not advmarkers.last_coords then + return false, 'No-one has used ".coords" and you have not died!' + end + pos = advmarkers.last_coords + else + pos = string_to_pos(pos) + if not pos then + return false, 'Invalid position!' + end + end + return pos +end + +local function register_chatcommand_alias(old, ...) + local def = assert(minetest.registered_chatcommands[old]) + def.name = nil + for i = 1, select('#', ...) do + minetest.register_chatcommand(select(i, ...), table.copy(def)) + end +end + +-- Open the waypoints GUI minetest.register_chatcommand('mrkr', { params = '', description = 'Open the advmarkers GUI', - func = advmarkers.display_formspec + func = function(param) + if param == '' then + advmarkers.display_formspec() + else + local pos, err = advmarkers.get_chatcommand_pos(param) + if not pos then + return false, err + end + if not advmarkers.set_hud_pos(pos) then + return false, 'Error setting the waypoint!' + end + end + end }) --- Add a marker +register_chatcommand_alias('mrkr', 'wp', 'wps', 'waypoint', 'waypoints') + +-- Add a waypoint minetest.register_chatcommand('add_mrkr', { params = ' ', - description = 'Adds a marker.', + description = 'Adds a waypoint.', func = function(param) local s, e = param:find(' ') if not s or not e then return false, 'Invalid syntax! See .help add_mrkr for more info.' end - local pos = param:sub(1, s - 1) + local pos = param:sub(1, s - 1) local name = param:sub(e + 1) -- Validate the position - if pos == 'here' then - pos = minetest.localplayer:get_pos() - elseif pos == 'there' then - if not advmarkers.last_coords then - return false, 'No-one has used ".coords" and you have not died!' - end - pos = advmarkers.last_coords - else - pos = string_to_pos(pos) - if not pos then - return false, 'Invalid position!' - end + local pos, err = advmarkers.get_chatcommand_pos(pos) + if not pos then + return false, err end -- Validate the name @@ -217,11 +279,13 @@ minetest.register_chatcommand('add_mrkr', { return false, 'Invalid name!' end - -- Set the marker - return advmarkers.set_marker(pos, name), 'Done!' + -- Set the waypoint + return advmarkers.set_waypoint(pos, name), 'Done!' end }) +register_chatcommand_alias('add_mrkr', 'add_wp', 'add_waypoint') + -- Set the HUD minetest.register_on_formspec_input(function(formname, fields) if formname == 'advmarkers-ignore' then @@ -241,22 +305,22 @@ minetest.register_on_formspec_input(function(formname, fields) if name then if fields.display then - if not advmarkers.display_marker(name) then - minetest.display_chat_message('Error displaying marker!') + if not advmarkers.display_waypoint(name) then + minetest.display_chat_message('Error displaying waypoint!') end elseif fields.rename then minetest.show_formspec('advmarkers-csm', 'size[6,3]' .. - 'label[0.35,0.2;Rename marker]' .. + 'label[0.35,0.2;Rename waypoint]' .. 'field[0.3,1.3;6,1;new_name;New name;' .. minetest.formspec_escape(name) .. ']' .. 'button[0,2;3,1;cancel;Cancel]' .. 'button[3,2;3,1;rename_confirm;Rename]') elseif fields.rename_confirm then if fields.new_name and #fields.new_name > 0 then - if advmarkers.rename_marker(name, fields.new_name) then + if advmarkers.rename_waypoint(name, fields.new_name) then selected_name = fields.new_name else - minetest.display_chat_message('Error renaming marker!') + minetest.display_chat_message('Error renaming waypoint!') end advmarkers.display_formspec() else @@ -267,7 +331,7 @@ minetest.register_on_formspec_input(function(formname, fields) elseif fields.teleport then minetest.show_formspec('advmarkers-csm', 'size[6,2.2]' .. 'label[0.35,0.25;' .. minetest.formspec_escape( - 'Teleport to a marker\n - ' .. name + 'Teleport to a waypoint\n - ' .. name ) .. ']' .. 'button[0,1.25;2,1;cancel;Cancel]' .. 'button_exit[2,1.25;1,1;teleport_tpj;/tpj]' .. @@ -275,7 +339,7 @@ minetest.register_on_formspec_input(function(formname, fields) 'button_exit[4,1.25;2,1;teleport_confirm;/teleport]') elseif fields.teleport_tpj then -- Teleport with /tpj - local pos = advmarkers.get_marker(name) + local pos = advmarkers.get_waypoint(name) if pos and minetest.localplayer then local cpos = minetest.localplayer:get_pos() for _, dir in ipairs({'x', 'y', 'z'}) do @@ -284,11 +348,11 @@ minetest.register_on_formspec_input(function(formname, fields) tostring(distance)) end else - minetest.display_chat_message('Error teleporting to marker!') + minetest.display_chat_message('Error teleporting to waypoint!') end elseif fields.teleport_confirm or fields.teleport_tpc then -- Teleport with /teleport - local pos = advmarkers.get_marker(name) + local pos = advmarkers.get_waypoint(name) local cmd if fields.teleport_confirm then cmd = 'teleport' @@ -299,15 +363,15 @@ minetest.register_on_formspec_input(function(formname, fields) minetest.run_server_chatcommand(cmd, pos.x .. ',' .. pos.y .. ',' .. pos.z) else - minetest.display_chat_message('Error teleporting to marker!') + minetest.display_chat_message('Error teleporting to waypoint!') end elseif fields.delete then minetest.show_formspec('advmarkers-csm', 'size[6,2]' .. - 'label[0.35,0.25;Are you sure you want to delete this marker?]' .. + 'label[0.35,0.25;Are you sure you want to delete this waypoint?]' .. 'button[0,1;3,1;cancel;Cancel]' .. 'button[3,1;3,1;delete_confirm;Delete]') elseif fields.delete_confirm then - advmarkers.delete_marker(name) + advmarkers.delete_waypoint(name) selected_name = false advmarkers.display_formspec() elseif fields.cancel then @@ -317,19 +381,19 @@ minetest.register_on_formspec_input(function(formname, fields) advmarkers.display_formspec() end elseif fields.display or fields.delete then - minetest.display_chat_message('Please select a marker.') + minetest.display_chat_message('Please select a waypoint.') end return true end) --- Auto-add markers on death. +-- Auto-add waypoints on death. minetest.register_on_death(function() if minetest.localplayer then - local name = os.date('Death on %Y-%m-%d %H:%M:%S') + local name = 'Death waypoint' local pos = minetest.localplayer:get_pos() advmarkers.last_coords = pos - advmarkers.set_marker(pos, name) - minetest.display_chat_message('Added marker "' .. name .. '".') + advmarkers.set_waypoint(pos, name) + minetest.display_chat_message('Added waypoint "' .. name .. '".') end end) @@ -345,11 +409,13 @@ minetest.register_chatcommand('mrkr_export', { export = advmarkers.export() end minetest.show_formspec('advmarkers-ignore', - 'field[_;Your marker export string;' .. + 'field[_;Your waypoint export string;' .. minetest.formspec_escape(export) .. ']') end }) +register_chatcommand_alias('mrkr_export', 'wp_export', 'waypoint_export') + -- String importing minetest.register_chatcommand('mrkr_import', { params = '', @@ -357,23 +423,27 @@ minetest.register_chatcommand('mrkr_import', { 'existing markers that have the same name.', func = function(param) if advmarkers.import(param) then - return true, 'Markers imported!' + return true, 'Waypoints imported!' else return false, 'Invalid advmarkers string!' end end }) --- Upload markers to the advmarkers server-side mod. +register_chatcommand_alias('mrkr_export', 'wp_import', 'waypoint_import') + +-- Upload waypoints to the advmarkers server-side mod. minetest.register_chatcommand('mrkr_upload', { params = '', - description = 'Uploads all markers to this server\'s advmarkers storage.', + description = 'Uploads all waypoints to this server\'s advmarkers storage.', func = function(param) local data = advmarkers.export() minetest.run_server_chatcommand('mrkr_import', data) end }) +register_chatcommand_alias('mrkr_export', 'wp_upload', 'waypoint_upload') + -- Chat channels .coords integration. -- You do not need to have chat channels installed for this to work. if not minetest.registered_on_receiving_chat_message then @@ -394,12 +464,32 @@ end) -- Add '.mrkrthere' minetest.register_chatcommand('mrkrthere', { params = '', - description = 'Adds a (temporary) marker at the last ".coords" position.', + description = 'Adds a (temporary) waypoint at the last ".coords" position.', func = function(param) if not advmarkers.last_coords then return false, 'No-one has used ".coords" and you have not died!' elseif not advmarkers.set_hud_pos(advmarkers.last_coords) then - return false, 'Error setting the marker!' + return false, 'Error setting the waypoint!' end end }) + +minetest.register_chatcommand('clrmrkr', { + params = '', + description = 'Hides the displayed waypoint.', + func = function(param) + if hud_id then + minetest.localplayer:hud_remove(hud_id) + hud_id = nil + return true, 'Hidden the currently displayed waypoint.' + elseif not minetest.localplayer.hud_add then + minetest.run_server_chatcommand('clrmrkr') + return + elseif not hud_id then + return false, 'No waypoint is currently being displayed!' + end + end, +}) + +register_chatcommand_alias('clrmrkr', 'clear_marker', 'clrwp', + 'clear_waypoint')