Make CSM standalone and add new features.

The CSM is now standalone on Minetest 5.0.0 and later, and new features
from the server side mod have been backported.
master
luk3yx 2020-02-13 18:16:36 +13:00
parent 0f4bdfe805
commit 405ebac2fb
2 changed files with 185 additions and 94 deletions

View File

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

260
init.lua
View File

@ -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 = '<pos / "here" / "there"> <name>',
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 = '<advmarkers string>',
@ -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')