add feature that scans chat for coords and allows navigating to it

Scan chat messages for coordinates and store N most recent.
Formspecs allows choosing one of the messages later and setting coords
to ones which were mentioned.
This commit is contained in:
whosit 2023-05-12 20:27:37 +03:00
parent 637a2b949f
commit 1193508202
1 changed files with 85 additions and 16 deletions

101
init.lua
View File

@ -274,24 +274,31 @@ local function coords_from_string(str)
end
end
local _format_recent_dropbox -- defined later
local function show_basic_dialog(itemstack, player)
local meta = itemstack:get_meta()
-- set focus to "close" button to preven accidental edting
local formspec_head = "formspec_version[4]size[14,3]set_focus[close;]"
-- set focus to "close" button to prevent accidental edting
local formspec_head = "formspec_version[4]size[14,4]set_focus[close;]"
local coords = coords_to_string(get_compass_meta_pos(meta))
local field_coords = ("field[0.5,0.6;4,0.8;coords;Coordinates;%s]"):format(minetest.formspec_escape(coords))
local label = get_compass_meta_label(meta) or "destination"
local field_destination = ("field[4.5,0.6;7,0.8;label;Label;%s]"):format(minetest.formspec_escape(label))
local color = ("%06X"):format(get_compass_meta_color(meta))
local field_color = ("field[11.5,0.6;2.0,0.8;color;Color;%s]"):format(minetest.formspec_escape(color))
minetest.show_formspec(player:get_player_name(), "waypoint_compass:basic",
formspec_head ..
field_coords ..
field_destination ..
field_color ..
"button_exit[3,1.7;3,0.8;save;save]" ..
"button_exit[8,1.7;3,0.8;close;close]")
local dropdown_recent = ("dropdown[2.0,1.7;11.5,0.5;recent;%s;1,false]"):format(_format_recent_dropbox())
local formspec = {
formspec_head,
field_coords,
field_destination,
field_color,
"button_exit[0.5,1.7;1.5,0.5;set_recent;copy:]",
dropdown_recent,
"button_exit[3,2.7;3,0.8;save;save]",
"button_exit[8,2.7;3,0.8;close;close]"}
minetest.show_formspec(player:get_player_name(),
"waypoint_compass:basic",
table.concat(formspec, ""))
local player_name = player:get_player_name()
compass_dialog_context[player_name] = itemstack
end
@ -332,7 +339,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if formname ~= "waypoint_compass:basic" then
return
end
if fields.save or (fields.key_enter_field and fields.quit) then
if fields.save or fields.set_recent or (fields.key_enter_field and fields.quit) then
local compass_item = compass_dialog_context[player:get_player_name()]
if not compass_item then
-- should not happen normally
@ -348,18 +355,26 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
color = math.max(math.min(color, 0xFFFFFF), 0x0) -- for some reason seems to work fine without this
set_compass_meta_color(meta, color)
-- print(dump(meta:to_table()))
end
end
local coords = coords_from_string(fields.coords)
local label = fields.label
-- player pressed "copy" button, ignore the "coordinates field"
if fields.set_recent then
local coord_string = fields.recent:match("%S+") or ""
coords = coords_from_string(coord_string)
label = fields.recent:match("(%S+ |[^>]+)>") or ""
end
if coords then
set_compass_meta_pos(meta, coords)
elseif fields.coords == "" then
-- assume player wants to reset compass
meta:set_string("waypoint_compass:position", "") -- TODO make unset()?
-- TODO reset label too? or keep it to be safe?
end
-- assume player wants to reset compass
meta:set_string("waypoint_compass:position", "") -- TODO make unset()?
-- TODO reset label too? or keep it to be safe?
end
local label = fields.label
set_compass_meta_label(meta, label)
-- Prevent overwriting random item if user switched before
@ -488,3 +503,57 @@ function waypoint_compass.make_compass(pos,owner_name, label, color)
return make_compass(pos,owner_name, label, color)
end
--------------------------------------------------------------------------------
-- TODO move chat scanner into separate file, make enabling optional
-- TODO API to add/rm "sticky" coordinates (that won't be pushed out of the list)?
local last_coords_log = {}
local last_coords_log_limit = 10 -- how many to keep
local function add_coords_log(pos, playername, message)
table.insert(last_coords_log, 1, {pos=pos, playername=playername, message=message})
last_coords_log[last_coords_log_limit] = nil
end
-- Trying to mach any three integer numbers separated at least by
-- spaces or punctuation.
--local FUZZY_COORD_PATTERN = ".-(%d+)%D?[%s.,:;]%D?(%d+)%D?[%s.,:;]%D?(%d+)"
local FUZZY_COORD_PATTERN = ".-(%d+)[^.%d]?[%s,:;]%D?(%d+)[^.%d]?[%s,:;]%D?(%d+)"
-- "usafe" means it may throw errors, use pcall()
local function fuzzy_parse_coords_unsafe(str)
-- find any 3 numbers in a string separated by punctuarion/spaces
local x,y,z = str:match(FUZZY_COORD_PATTERN)
x = clamp(tonumber(x), -32000, 32000)
y = clamp(tonumber(y), -32000, 32000)
z = clamp(tonumber(z), -32000, 32000)
return {x=x,y=y,z=z}
end
_format_recent_dropbox = function()
local out = {}
for k,v in ipairs(last_coords_log) do
local item = string.format("%d,%d,%d | %s> %s",
v.pos.x, v.pos.y, v.pos.z,
v.playername,
v.message:sub(1,50))
table.insert(out, minetest.formspec_escape(item))
end
return table.concat(out,",")
end
local function scan_chat_for_coords(name, message)
local success, coords = pcall(fuzzy_parse_coords_unsafe, message)
if success then
add_coords_log(coords, name, message)
end
return nil -- do not handle messages, just check them
end
minetest.register_on_chat_message(scan_chat_for_coords)