diff --git a/hud.lua b/hud.lua index cea5bca..c14231e 100644 --- a/hud.lua +++ b/hud.lua @@ -1,6 +1,23 @@ local default_node_name_offset_y = -100 local default_rotation_offset_y = -135 +--- Initialises a brand-new info table for the given player name. +-- @param player_name string The name of the player to initialise a new info table for. +-- @returns table The newly generated info table for convenience (note that tables are passed by reference in Lua). +function worldedit_hud_helper.initialise_info(player_name) + worldedit_hud_helper.info[player_name] = { + -- Persistable + enabled = true, + node_name_offset_y = default_node_name_offset_y, + rotation_offset_y = default_rotation_offset_y, + + -- Dynamic + node_name = nil, + rotation = nil + } + return worldedit_hud_helper.info[player_name] +end + --- Initialises the HUD for a given player. -- May be called multiple times. -- If called more than once, this has the effect of cycling the HUD registration @@ -12,14 +29,7 @@ function worldedit_hud_helper.initialise_hud(player) local player_info = worldedit_hud_helper.info[player_name] if not player_info then - player_info = { - enabled = true, - node_name = nil, - rotation = nil, - node_name_offset_y = default_node_name_offset_y, - rotation_offset_y = default_rotation_offset_y - } - worldedit_hud_helper.info[player_name] = player_info + player_info = worldedit_hud_helper.initialise_info(player_name) end player_info.id_node_name = player:hud_add({ @@ -58,12 +68,18 @@ function worldedit_hud_helper.hide_hud(player) player_info.node_name = nil player_info.rotation = nil + + worldedit_hud_helper.save_defer() end --- Deletes the HUD for a player. +-- Caution: This will also wipe all customised settings with no way to recover +-- them! -- @param player Player The player object (as returned by minetest.get_player_by_name(player_name: string)). function worldedit_hud_helper.delete_hud(player) worldedit_hud_helper.info[player:get_player_name()] = nil + + worldedit_hud_helper.save_defer() end --- Updates the HUD offset in pixels. @@ -87,9 +103,13 @@ function worldedit_hud_helper.update_hud_offset(player, new_offset) worldedit_hud_helper.hide_hud(player) worldedit_hud_helper.initialise_hud(player) + -- Save the new setting(s) to disk + worldedit_hud_helper.save_defer() + return true end minetest.register_on_joinplayer(worldedit_hud_helper.initialise_hud) -minetest.register_on_leaveplayer(worldedit_hud_helper.delete_hud) +-- Don't delete the HUD when the player leaves anymore, since we now persist it to disk +-- minetest.register_on_leaveplayer(worldedit_hud_helper.delete_hud) diff --git a/init.lua b/init.lua index 89f0875..6f869ad 100644 --- a/init.lua +++ b/init.lua @@ -20,3 +20,7 @@ dofile(mod_path .. "/raycast_polyfill.lua") dofile(mod_path .. "/hud.lua") dofile(mod_path .. "/hud_info.lua") dofile(mod_path .. "/commands.lua") +dofile(mod_path .. "/io.lua") + + +worldedit_hud_helper.load() diff --git a/io.lua b/io.lua new file mode 100644 index 0000000..3875ab0 --- /dev/null +++ b/io.lua @@ -0,0 +1,88 @@ + +local filepath_data = minetest.get_worldpath().."/worldedit_hud_helper_data.tsv" + +-- Splits a string using a given delimiter. +-- @source https://stackoverflow.com/a/7615129/1460422 +-- @param inputstr string The string to split. +-- @param sep string The delimiter. +-- @returns string[] A table of substrings split out of the input string. +local function split(inputstr, sep) + if sep == nil then + sep = "%s" + end + local t = {} + for str in string.gmatch(inputstr, "([^"..sep.."]+)") do + table.insert(t, str) + end + return t +end + + +--- Serialises and saves the settings for all players to disk. +-- Settings are saved to a file in the world's directory called +-- 'worldedit_hud_helper_data.tsv'. +-- @returns nil +function worldedit_hud_helper.save() + local result = { + table.concat({ + "player_name", + "enabled", + "node_name_offset_y", + "rotation_offset_y" + }, "\t") + } + + for player_name, player_info in pairs(worldedit_hud_helper.info) do + print("DEBUG player_name", player_name) + local next = table.concat({ + player_name, + tostring(player_info.enabled), + tostring(player_info.node_name_offset_y), + tostring(player_info.rotation_offset_y), + }, "\t") + print("DEBUG next", next) + table.insert(result, next) + end + + local handle = io.open(filepath_data, "w+") + handle:write(table.concat(result, "\n")) + handle:close() +end + +--- Calls worldedit_hud_helper.save(), but pushes the call to the end of the +-- function queue. +function worldedit_hud_helper.save_defer() + minetest.after(0, function() + worldedit_hud_helper.save() + end) +end + +--- Loads all the settings for all players from disk. +-- CAUTION: This should only be called ONCE on server start when no players are +-- connected! +-- Note that this does NOT reinitialise any player's HUDs, since it is expected +-- that they are not connected yet when this function is called. +-- Note also that if no settings have yet been saved to disk (i.e. the settings +-- file doesn't exist), then this function silently returns. +-- @returns nil +function worldedit_hud_helper.load() + local handle = io.open(filepath_data, "r") + if handle == nil then return end + + local i = 0 + for line in handle:lines() do + if i > 0 then + local parts = split(line) + local player_name = parts[1] + local player_info = worldedit_hud_helper.initialise_info(player_name) + + player_info.enabled = parts[2] + player_info.node_name_offset_y = parts[3] + player_info.rotation_offset_y = parts[4] + end + + i = i + 1 + end + + minetest.log("info", "[worldedit_hud_helper] Loaded per-world settings for "..i.." players.") +end