Use player meta for waypoints

This commit is contained in:
SmallJoker 2021-07-17 12:24:22 +02:00 committed by SmallJoker
parent aeb9841e3a
commit d39dd78cb5
3 changed files with 167 additions and 66 deletions

@ -15,7 +15,8 @@ Unified Inventory replaces the default survival and creative inventory.
* Recipe search function by ingredients * Recipe search function by ingredients
* Up to four bags with up to 24 slots each * Up to four bags with up to 24 slots each
* Home function to teleport * Home function to teleport
* Trash slot * Trash slot and refill slot for creative
* Waypoints to keep track of important locations
* Lite mode: reduces the item browser width * Lite mode: reduces the item browser width
* `minetest.conf` setting `unified_inventory_lite = true` * `minetest.conf` setting `unified_inventory_lite = true`
* Mod API for modders: see [mod_api.txt](doc/mod_api.txt) * Mod API for modders: see [mod_api.txt](doc/mod_api.txt)
@ -27,7 +28,7 @@ Unified Inventory replaces the default survival and creative inventory.
* Minetest 5.4.0+ * Minetest 5.4.0+
* Mod `default` for category filters (contained in Minetest Game) * Mod `default` for category filters (contained in Minetest Game)
* Mod `farming` for craftable bags (contained in Minetest Game) * Mod `farming` for craftable bags (contained in Minetest Game)
* Mod `datastorage` for waypoints (deprecated) * For waypoint migration: `datastorage`
# Licenses # Licenses

@ -166,7 +166,4 @@ if minetest.settings:get_bool("unified_inventory_bags") ~= false then
end end
dofile(modpath.."/item_names.lua") dofile(modpath.."/item_names.lua")
dofile(modpath.."/waypoints.lua")
if minetest.get_modpath("datastorage") then
dofile(modpath.."/waypoints.lua")
end

@ -1,6 +1,7 @@
local S = minetest.get_translator("unified_inventory") local S = minetest.get_translator("unified_inventory")
local F = minetest.formspec_escape local F = minetest.formspec_escape
local ui = unified_inventory local ui = unified_inventory
local COUNT = 5
local hud_colors = { local hud_colors = {
{"#FFFFFF", 0xFFFFFF, S("White")}, {"#FFFFFF", 0xFFFFFF, S("White")},
@ -10,11 +11,97 @@ local hud_colors = {
{"#2c4df1", 0x2c4df1, S("Blue")}, {"#2c4df1", 0x2c4df1, S("Blue")},
} }
local hud_colors_max = #hud_colors -- Storage compatibility code
-- Stores temporary player data (persists until player leaves) --[[
Stores temporary player data (persists until player leaves)
[player_name] = {
[<waypoint index>] = {
edit = <edit current waypoint?>,
hud = <hud ID>,
},
[<waypoint index>] = { ... },
...
}
]]
local waypoints_temp = {} local waypoints_temp = {}
--[[
Datastorage format (per-player):
{
selected = <waypoint index>,
[<waypoint index>] = {
name = <name or nil>
world_pos = <coordinates vector>,
color = <"hud_colors" index>,
active = <hud show waypoint?>,
display_pos = <hud display coorinates?>,
},
[<waypoint index>] = { ... },
...
}
Player metadata format:
{
selected = <selected number>,
-- Cannot mix integer/string keys in JSON
data = {
[<waypoint index>] = { same as above },
...
}
}
]]
local function set_waypoint_data(player, waypoints)
local meta = player:get_meta()
if not next(waypoints.data or {}) then
-- Empty data. Do not save anything, or delete
meta:set_string("ui_waypoints", "")
else
meta:set_string("ui_waypoints", minetest.write_json(waypoints))
end
end
local function migrate_datastorage(player, waypoints)
-- Copy values from old table
local new_data = {
selected = waypoints.selected,
data = {}
}
for i = 1, COUNT do
new_data.data[i] = waypoints[i]
end
set_waypoint_data(player, new_data)
-- Delete values, but keep one entry so that it's saved by datastorage
for k, _ in pairs(waypoints) do
waypoints[k] = nil
end
waypoints[1] = 1
end
local have_datastorage = minetest.get_modpath("datastorage") ~= nil
local function get_waypoint_data(player)
local player_name = player:get_player_name()
-- Migration step
if have_datastorage then
local waypoints = datastorage.get(player_name, "waypoints")
if waypoints.selected then
migrate_datastorage(player, waypoints)
minetest.log("action", "[unified_inventory] " ..
"Migrated waypoints of player: " .. player_name)
end
end
-- Get directly from metadata
local waypoints = player:get_meta():get("ui_waypoints")
waypoints = waypoints and minetest.parse_json(waypoints) or {}
waypoints.data = waypoints.data or {}
return waypoints
end
ui.register_page("waypoints", { ui.register_page("waypoints", {
get_formspec = function(player) get_formspec = function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
@ -24,73 +111,83 @@ ui.register_page("waypoints", {
local wp_buttons_rj = ui.style_full.std_inv_x + 10.1 - ui.style_full.btn_spc local wp_buttons_rj = ui.style_full.std_inv_x + 10.1 - ui.style_full.btn_spc
local wp_edit_w = ui.style_full.btn_spc * 4 - 0.1 local wp_edit_w = ui.style_full.btn_spc * 4 - 0.1
-- build a "fake" temp entry if the server took too long local waypoints = get_waypoint_data(player)
-- during sign-on and returned an empty entry local sel = waypoints.selected or 1
if not waypoints_temp[player_name] then waypoints_temp[player_name] = {hud = 1} end
local waypoints = datastorage.get(player_name, "waypoints") local formspec = {
local formspec = { ui.style_full.standard_inv_bg, ui.style_full.standard_inv_bg,
string.format("label[%f,%f;%s]", string.format("label[%f,%f;%s]",
ui.style_full.form_header_x, ui.style_full.form_header_y, ui.style_full.form_header_x, ui.style_full.form_header_y, F(S("Waypoints"))),
F(S("Waypoints"))),
"image["..wp_info_x..","..wp_info_y..";1,1;ui_waypoints_icon.png]" "image["..wp_info_x..","..wp_info_y..";1,1;ui_waypoints_icon.png]"
} }
local n=4 local n=4
-- Tabs buttons: -- Tabs buttons:
for i = 1, 5 do for i = 1, COUNT do
local sw="select_waypoint"..i local sw="select_waypoint"..i
formspec[n] = string.format("image_button[%f,%f;%f,%f;%sui_%i_icon.png;%s;]", formspec[n] = string.format("image_button[%f,%f;%f,%f;%sui_%i_icon.png;%s;]",
ui.style_full.main_button_x, wp_bottom_row - (5-i) * ui.style_full.btn_spc, ui.style_full.main_button_x, wp_bottom_row - (5-i) * ui.style_full.btn_spc,
ui.style_full.btn_size, ui.style_full.btn_size, ui.style_full.btn_size, ui.style_full.btn_size,
(i == waypoints.selected) and "ui_blue_icon_background.png^" or "", (i == sel) and "ui_blue_icon_background.png^" or "",
i, sw) i, sw)
formspec[n+1] = "tooltip["..sw..";"..S("Select Waypoint #@1", i).."]" formspec[n+1] = "tooltip["..sw..";"..S("Select Waypoint #@1", i).."]"
n = n + 2 n = n + 2
end end
local i = waypoints.selected or 1 local waypoint = waypoints.data[sel] or {}
local waypoint = waypoints[i] or {} local temp = waypoints_temp[player_name][sel] or {}
local temp = waypoints_temp[player_name][i] or {} local default_name = S("Waypoint @1", sel)
local default_name = S("Waypoint @1", i)
-- Main buttons: -- Main buttons:
local btnlist = { local btnlist = {
{ "ui_waypoint_set_icon.png", "set_waypoint", S("Set waypoint to current location") }, set_waypoint = {
{ waypoint.active and "ui_on_icon.png" or "ui_off_icon.png", "toggle_waypoint", S("Make waypoint @1", waypoint.active and "invisible" or "visible") }, "ui_waypoint_set_icon.png",
{ waypoint.display_pos and "ui_green_icon_background.png^ui_xyz_icon.png" or "ui_red_icon_background.png^ui_xyz_icon.png^(ui_no.png^[transformR90)", "toggle_display_pos", S("@1 display of waypoint coordinates", waypoint.display_pos and "Disable" or "Enable") }, S("Set waypoint to current location")
{ "ui_circular_arrows_icon.png", "toggle_color", S("Change color of waypoint display") }, },
{ "ui_pencil_icon.png", "rename_waypoint", S("Edit waypoint name") } toggle_waypoint = {
waypoint.active and "ui_on_icon.png" or "ui_off_icon.png",
waypoint.active and S("Hide waypoint") or S("Show waypoint")
},
toggle_display_pos = {
waypoint.display_pos and "ui_green_icon_background.png^ui_xyz_icon.png" or "ui_red_icon_background.png^ui_xyz_icon.png^(ui_no.png^[transformR90)",
waypoint.display_pos and S("Hide coordinates") or S("Show coordinates")
},
toggle_color = {
"ui_circular_arrows_icon.png",
S("Change color of waypoint display")
},
rename_waypoint = {
"ui_pencil_icon.png",
S("Edit waypoint name")
}
} }
local x = 4 local x = 4
for _, b in pairs(btnlist) do for name, def in pairs(btnlist) do
formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s%i;]", formspec[n] = string.format("image_button[%f,%f;%f,%f;%s;%s%i;]",
wp_buttons_rj - ui.style_full.btn_spc * x, wp_bottom_row, wp_buttons_rj - ui.style_full.btn_spc * x, wp_bottom_row,
ui.style_full.btn_size, ui.style_full.btn_size, ui.style_full.btn_size, ui.style_full.btn_size,
b[1], b[2], i) def[1], name, sel)
formspec[n+1] = "tooltip["..b[2]..i..";"..F(b[3]).."]" formspec[n+1] = "tooltip["..name..sel..";"..F(def[2]).."]"
x = x - 1 x = x - 1
n = n + 2 n = n + 2
end end
-- Waypoint's info: -- Waypoint's info:
formspec[n] = "label["..wp_info_x..","..(wp_info_y+1.1)..";" formspec[n] = ("label[%f,%f;%s]"):format(
if waypoint.active then wp_info_x, wp_info_y + 1.1,
formspec[n+1] = F(S("Waypoint active")).."]" F(waypoint.active and S("Waypoint active") or S("Waypoint inactive"))
else )
formspec[n+1] = F(S("Waypoint inactive")).."]" n = n + 1
end
n = n + 2
if temp.edit then if temp.edit then
formspec[n] = string.format("field[%f,%f;%f,%f;rename_box%i;;%s]", formspec[n] = string.format("field[%f,%f;%f,%f;rename_box%i;;%s]",
wp_buttons_rj - wp_edit_w - 0.1, wp_bottom_row - ui.style_full.btn_spc, wp_buttons_rj - wp_edit_w - 0.1, wp_bottom_row - ui.style_full.btn_spc,
wp_edit_w, ui.style_full.btn_size, i, (waypoint.name or default_name)) wp_edit_w, ui.style_full.btn_size, sel, (waypoint.name or default_name))
formspec[n+1] = string.format("image_button[%f,%f;%f,%f;ui_ok_icon.png;confirm_rename%i;]", formspec[n+1] = string.format("image_button[%f,%f;%f,%f;ui_ok_icon.png;confirm_rename%i;]",
wp_buttons_rj, wp_bottom_row - ui.style_full.btn_spc, wp_buttons_rj, wp_bottom_row - ui.style_full.btn_spc,
ui.style_full.btn_size, ui.style_full.btn_size, i) ui.style_full.btn_size, ui.style_full.btn_size, sel)
formspec[n+2] = "tooltip[confirm_rename"..i..";"..F(S("Finish editing")).."]" formspec[n+2] = "tooltip[confirm_rename"..sel..";"..F(S("Finish editing")).."]"
n = n + 3 n = n + 3
end end
@ -114,10 +211,12 @@ ui.register_button("waypoints", {
}) })
local function update_hud(player, waypoints, temp, i) local function update_hud(player, waypoints, temp, i)
local waypoint = waypoints[i] local waypoint = waypoints.data[i]
if not waypoint then return end if not waypoint then return end
temp[i] = temp[i] or {} temp[i] = temp[i] or {}
temp = temp[i] temp = temp[i]
local pos = waypoint.world_pos or vector.new() local pos = waypoint.world_pos or vector.new()
local name local name
if waypoint.display_pos then if waypoint.display_pos then
@ -126,10 +225,13 @@ local function update_hud(player, waypoints, temp, i)
name = name..", "..waypoint.name name = name..", "..waypoint.name
end end
else else
name = waypoint.name or "Waypoint "..i name = waypoint.name or S("Waypoint @1", i)
end end
-- Perform HUD updates
if temp.hud then if temp.hud then
player:hud_remove(temp.hud) player:hud_remove(temp.hud)
temp.hud = nil
end end
if waypoint.active then if waypoint.active then
temp.hud = player:hud_add({ temp.hud = player:hud_add({
@ -139,8 +241,6 @@ local function update_hud(player, waypoints, temp, i)
text = "m", text = "m",
world_pos = pos world_pos = pos
}) })
else
temp.hud = nil
end end
end end
@ -152,9 +252,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local need_update_hud = false local need_update_hud = false
local hit = false local hit = false
local waypoints = datastorage.get(player_name, "waypoints") local waypoints = get_waypoint_data(player)
local temp = waypoints_temp[player_name] local temp = waypoints_temp[player_name]
for i = 1, 5, 1 do for i = 1, COUNT do
local waypoint = waypoints.data[i] or {}
if fields["select_waypoint"..i] then if fields["select_waypoint"..i] then
hit = true hit = true
waypoints.selected = i waypoints.selected = i
@ -163,20 +265,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields["toggle_waypoint"..i] then if fields["toggle_waypoint"..i] then
hit = true hit = true
waypoints[i] = waypoints[i] or {} waypoint.active = not (waypoint.active)
waypoints[i].active = not (waypoints[i].active)
need_update_hud = true need_update_hud = true
update_formspec = true update_formspec = true
end end
if fields["set_waypoint"..i] then if fields["set_waypoint"..i] then
hit = true hit = true
local pos = player:get_pos() local pos = vector.round(player:get_pos())
pos.x = math.floor(pos.x) waypoint.world_pos = pos
pos.y = math.floor(pos.y)
pos.z = math.floor(pos.z)
waypoints[i] = waypoints[i] or {}
waypoints[i].world_pos = pos
need_update_hud = true need_update_hud = true
update_formspec = true update_formspec = true
end end
@ -190,39 +287,45 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields["toggle_display_pos"..i] then if fields["toggle_display_pos"..i] then
hit = true hit = true
waypoints[i] = waypoints[i] or {} waypoint.display_pos = not waypoint.display_pos
waypoints[i].display_pos = not waypoints[i].display_pos
need_update_hud = true need_update_hud = true
update_formspec = true update_formspec = true
end end
if fields["toggle_color"..i] then if fields["toggle_color"..i] then
hit = true hit = true
waypoints[i] = waypoints[i] or {} local color = waypoint.color or 0
local color = waypoints[i].color or 1
color = color + 1 color = color + 1
if color > hud_colors_max then if color > #hud_colors then
color = 1 color = 1
end end
waypoints[i].color = color waypoint.color = color
need_update_hud = true need_update_hud = true
update_formspec = true update_formspec = true
end end
if fields["confirm_rename"..i] then if fields["confirm_rename"..i] then
hit = true hit = true
waypoints[i] = waypoints[i] or {} temp[i] = temp[i] or {}
temp[i].edit = false temp[i].edit = false
waypoints[i].name = fields["rename_box"..i] waypoint.name = fields["rename_box"..i]
need_update_hud = true need_update_hud = true
update_formspec = true update_formspec = true
end end
if hit then
-- Save first
waypoints.data[i] = waypoint
set_waypoint_data(player, waypoints)
end
-- Update after
if need_update_hud then if need_update_hud then
update_hud(player, waypoints, temp, i) update_hud(player, waypoints, temp, i)
end end
if update_formspec then if update_formspec then
ui.set_inventory_formspec(player, "waypoints") ui.set_inventory_formspec(player, "waypoints")
end end
if hit then return end if hit then return end
end end
end) end)
@ -230,11 +333,11 @@ end)
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
local player_name = player:get_player_name() local player_name = player:get_player_name()
local waypoints = datastorage.get(player_name, "waypoints") local waypoints = get_waypoint_data(player)
local temp = {}
waypoints_temp[player_name] = temp waypoints_temp[player_name] = {}
for i = 1, 5 do for i = 1, COUNT do
update_hud(player, waypoints, temp, i) update_hud(player, waypoints, waypoints_temp[player_name], i)
end end
end) end)