From d65c1f11bad1c26d961d8b55e8dbdb24757f3ba1 Mon Sep 17 00:00:00 2001 From: Dirk Sohler Date: Sat, 29 Jul 2017 16:36:07 +0200 Subject: [PATCH] switch to player based configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Before all variables and “constants” (configuration variables) were stored in one single global table. Now the players get custom attributes set. This allows player-based displaying of the timer information. This will be done in subsequent commits. Tracking issue: https://github.com/dsohler/mtimer/issues/1 --- init.lua | 145 +++++++++++++++----------------------- settingtypes.txt | 12 ++-- system/timer_function.lua | 76 ++++++++++++++++++++ 3 files changed, 141 insertions(+), 92 deletions(-) create mode 100644 system/timer_function.lua diff --git a/init.lua b/init.lua index 37f65e9..28858a5 100644 --- a/init.lua +++ b/init.lua @@ -1,95 +1,64 @@ --- Convert a given x,y string into a table {x=given_x, y=given_y} and return --- it to be used of the screen location parameters in the HUD definition -local mtimer_location_value = function (o) - local given_x = o:gsub(',[^,]+$', '') - local given_y = o:gsub('^[^,]+,', '') +-- Load default configuration andf functions +local modpath = minetest.get_modpath(minetest.get_current_modname())..DIR_DELIM +local config = dofile(modpath..'system'..DIR_DELIM..'get_options.lua') +dofile(modpath..'system'..DIR_DELIM..'timer_function.lua') + + +-- Set custom player attribute if not set +-- +-- Sets a custom player attribute if the attribute is not set already. +-- +-- @param player The player opbject of the player to set the attribute for +-- @param attribute The attribute to set if not present +-- @param value The value to be set if the attribute does not exist +local set_if_unset = function(player, attribute, value) + local current_value = player:get_attribute(attribute) + if current_value == nil then player:set_attribute(attribute, value) end +end + + +-- Get a position table from a comma-separated position string +-- +-- @param position_string The desired position in `x,y` format +-- +-- @return table The position table +mtimer_position = function (position_string) + local given_x = position_string:gsub(',[^,]+$', '') + local given_y = position_string:gsub('^[^,]+,', '') return {x=given_x, y=given_y} end -local modpath = minetest.get_modpath(minetest.get_current_modname())..DIR_DELIM -local options = dofile(modpath..'system'..DIR_DELIM..'get_options.lua') - -local interval = options['mtimer_update_interval'] -local placeholder = options['mtimer_placeholder'] -local font_color = options['mtimer_font_color'] - -local format = { - locale = options['mtimer_locale'], - start = options['mtimer_session_start'], - runtime = options['mtimer_session_runtime'], - current = options['mtimer_current_time'], - ingame = options['mtimer_ingame_time'], - output = options['mtimer_output_format'] -} - -local location = { - position = mtimer_location_value(options['mtimer_position']), - alignment = mtimer_location_value(options['mtimer_alignment']), - offset = mtimer_location_value(options['mtimer_offset']) -} - -local player_data = {} - minetest.register_on_joinplayer(function(player) - minetest.after(1, function(player) - local player_name = player:get_player_name() - local _hud_id = player:hud_add({ - hud_elem_type = 'text', - position = location.position, - alignment = location.alignment, - offset = location.offset, - text = placeholder, - number = '0x'..font_color - }) - player_data[player_name] = { - start_time = os.time(), - hud_id = _hud_id - } - minetest.after(5, change_text, player) - end, player) + -- Set default values if not present + set_if_unset(player, 'mtimer:runtime', config['mtimer_runtime']) + set_if_unset(player, 'mtimer:offset', config['mtimer_offset']) + set_if_unset(player, 'mtimer:ingame_time', config['mtimer_ingame_time']) + set_if_unset(player, 'mtimer:current_time', config['mtimer_current_time']) + set_if_unset(player, 'mtimer:font_color', config['mtimer_font_color']) + set_if_unset(player, 'mtimer:start', config['mtimer_start']) + set_if_unset(player, 'mtimer:show', config['mtimer_show']) + set_if_unset(player, 'mtimer:locale', config['mtimer_locale']) + set_if_unset(player, 'mtimer:position', config['mtimer_position']) + set_if_unset(player, 'mtimer:format', config['mtimer_format']) + set_if_unset(player, 'mtimer:alignment', config['mtimer_alignment']) + + -- Set join timestamp for later calculations + player:set_attribute('mtimer:joined_timestamp', os.time()) + + -- Set the hud element ID for later usage and set text to the placeholder + player:set_attribute('mtimer:hud_id', player:hud_add({ + hud_elem_type = 'text', + position = mtimer_position(player:get_attribute('mtimer:position')), + alignment = mtimer_position(player:get_attribute('mtimer:alignment')), + offset = mtimer_position(player:get_attribute('mtimer:offset')), + text = config['mtimer_placeholder'], + number = '0x'..player:get_attribute('mtimer:font_color') + })) + + -- Run inital update for the player + minetest.after(1, mtimer_update, player) end) - -minetest.register_on_leaveplayer(function(player) - local player_name = player:get_player_name() - player_data[player_name] = nil -end) - - -function change_text(player) - local player_name = player:get_player_name() - if player_name == '' then return end - - -- Save the game-detected locale. Fun fact: changing the locale on runtime - -- from within a mod causes the UI to glitch out completely. - local current_locale = os.setlocale(nil) - os.setlocale(format.locale) - - local start_time = player_data[player_name].start_time - local hud_id = player_data[player_name].hud_id - - local time = 24*60*minetest.get_timeofday() - local h = tostring((math.floor(time/60) % 60)) - local m = tostring((math.floor(time) % 60)) - - local res = format.output:gsub('(+.)', { - ['+s'] = os.date(format.start, start_time), - ['+c'] = os.date(format.current), - ['+r'] = os.date('!'..format.runtime:gsub('(+.)', { - ['+h'] = '%H', - ['+m'] = '%M', - ['+s'] = '%S' - }), os.time() - start_time), - ['+i'] = format.ingame:gsub('(+.)', { - ['+h'] = string.rep('0', 2-#h)..h, - ['+m'] = string.rep('0', 2-#m)..m - }), - ['+n'] = "\n" - }) - - os.setlocale(current_locale) -- Restore game-detected locale - - player:hud_change(hud_id, 'text', res) - minetest.after(interval, change_text, player) -end +-- Start iteration after 5 seconds +minetest.after(5, mtimer_iterate, tonumber(config['mtimer_update_interval'])) diff --git a/settingtypes.txt b/settingtypes.txt index c18d39f..9bcea3a 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -12,11 +12,11 @@ mtimer_update_interval (Seconds between updates) int 30 # +r = Runtime of the current session # +i = Current ingame time in 24h format # +n = Following output will be in a new line -mtimer_output_format (Output string formatting) string Session from +s+nCurrent time: +c+nPlaytime: +r, Ingame time: +i +mtimer_format (Output string formatting) string Session from +s+nCurrent time: +c+nPlaytime: +r, Ingame time: +i # A placeholder text that is shown before the timer # function gets executed the first time -mtimer_placeholder (Placeholder for the timer) string [MTimer ...] +mtimer_placeholder (Placeholder for the timer) string [Initializing MTimer] # The font color for the timer text # @@ -34,7 +34,7 @@ mtimer_font_color (Font color for the timer text) string babdb6 # Time when the current session was started. The session # is based on when the user connected to the world. The # format is this: https://www.lua.org/pil/22.1.html -mtimer_session_start ([+s] Session start time) string %c +mtimer_start ([+s] Session start time) string %c # A hours:minutes timer that allows tracking of the # current play time. The timer breaks if game time @@ -43,7 +43,7 @@ mtimer_session_start ([+s] Session start time) string %c # +h = Hours # +m = Minutes # +s = Seconds -mtimer_session_runtime ([+r] Session runtime) string +h:+m +mtimer_runtime ([+r] Session runtime) string +h:+m # The current real-world time according to what the OS # provides. Formatting this string is quite easy by using @@ -66,6 +66,10 @@ mtimer_locale (Format output locale) string C [Positioning] +# Regardless of all other configuration: Show the timer +# in the GUI of the players - or do noit show it. +mtimer_show (Show at all) bool true + # "To account for differing resolutions, the position # coordinates are the percentage of the screen, ranging # in value from 0 to 1. 0 means left/top, 1 means diff --git a/system/timer_function.lua b/system/timer_function.lua new file mode 100644 index 0000000..0bfc334 --- /dev/null +++ b/system/timer_function.lua @@ -0,0 +1,76 @@ +-- Update an idividual player’s timer display +-- +-- When running the function the player data will be read from the player’s +-- `player` object and the output will be generated +-- +-- @param player the player object to update +mtimer_update = function (player) + -- Formatting options + local runtime = player:get_attribute('mtimer:runtime') + local offset = mtimer_position(player:get_attribute('mtimer:offset')) + local ingame_time = player:get_attribute('mtimer:ingame_time') + local current_time = player:get_attribute('mtimer:current_time') + local font_color = player:get_attribute('mtimer:font_color') + local start = player:get_attribute('mtimer:start') + local show = player:get_attribute('mtimer:show') + local locale = player:get_attribute('mtimer:locale') + local position = mtimer_position(player:get_attribute('mtimer:position')) + local format = player:get_attribute('mtimer:format') + local alignment = mtimer_position(player:get_attribute('mtimer:alignment')) + + -- Settings + local joined_timestamp = player:get_attribute('mtimer:joined_timestamp') + local hud_id = tonumber(player:get_attribute('mtimer:hud_id')) + + -- Calculate ingame time + local ingame_timestamp = 24*60*minetest.get_timeofday() + local ingame_h = tostring((math.floor(ingame_timestamp/60) % 60)) + local ingame_m = tostring((math.floor(ingame_timestamp) % 60)) + + -- Replace variables in output format if wanted by the user + local rendered_output_format = '' + if show == 'true' then + rendered_output_format = format:gsub('+.', { + ['+s'] = os.date(start, joined_timestamp), + ['+c'] = os.date(current_time), + ['+r'] = os.date('!'..runtime:gsub('(+.)', { + ['+h'] = '%H', + ['+m'] = '%M', + ['+s'] = '%S' + }), os.time() - joined_timestamp), + ['+i'] = ingame_time:gsub('(+.)', { + ['+h'] = string.rep('0', 2-#ingame_h)..ingame_h, + ['+m'] = string.rep('0', 2-#ingame_m)..ingame_m + }), + ['+n'] = "\n" + }) + end + + -- Render the output format as HUD element + player:hud_change(hud_id, 'text', rendered_output_format) + player:hud_change(hud_id, 'number', '0x'..font_color) + player:hud_change(hud_id, 'position', position) + player:hud_change(hud_id, 'alignment', alignment) + player:hud_change(hud_id, 'offset', offset) +end + + + +-- Self-calling iteration function +-- +-- The function iterates of all currentlz logged on players, checks if they +-- have the custom attribute `mtimer:hud_id` set (this is the last value that +-- will be set when a player joins so the player is set up completely if +-- `mtimer:hud_id` is present in the custom player attributes) and then runs +-- the function to update the timer display. After that the function calls +-- itself again, using the set interval. +-- +-- @param interval The intervall used to self-calling again after execution +mtimer_iterate = function(interval) + for _,player in pairs(minetest.get_connected_players()) do + if player:get_attribute('mtimer:hud_id') ~= nil then + mtimer_update(player) + end + end + minetest.after(interval, mtimer_iterate, interval) +end