switch to player based configuration

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
This commit is contained in:
Dirk Sohler 2017-07-29 16:36:07 +02:00
parent 9e4d98d896
commit d65c1f11ba
3 changed files with 141 additions and 92 deletions

143
init.lua

@ -1,95 +1,64 @@
-- Convert a given x,y string into a table {x=given_x, y=given_y} and return -- Load default configuration andf functions
-- it to be used of the screen location parameters in the HUD definition local modpath = minetest.get_modpath(minetest.get_current_modname())..DIR_DELIM
local mtimer_location_value = function (o) local config = dofile(modpath..'system'..DIR_DELIM..'get_options.lua')
local given_x = o:gsub(',[^,]+$', '') dofile(modpath..'system'..DIR_DELIM..'timer_function.lua')
local given_y = o:gsub('^[^,]+,', '')
-- 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} return {x=given_x, y=given_y}
end 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.register_on_joinplayer(function(player)
minetest.after(1, function(player) -- Set default values if not present
local player_name = player:get_player_name() set_if_unset(player, 'mtimer:runtime', config['mtimer_runtime'])
local _hud_id = player:hud_add({ 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', hud_elem_type = 'text',
position = location.position, position = mtimer_position(player:get_attribute('mtimer:position')),
alignment = location.alignment, alignment = mtimer_position(player:get_attribute('mtimer:alignment')),
offset = location.offset, offset = mtimer_position(player:get_attribute('mtimer:offset')),
text = placeholder, text = config['mtimer_placeholder'],
number = '0x'..font_color number = '0x'..player:get_attribute('mtimer:font_color')
}) }))
player_data[player_name] = {
start_time = os.time(), -- Run inital update for the player
hud_id = _hud_id minetest.after(1, mtimer_update, player)
}
minetest.after(5, change_text, player)
end, player)
end) end)
-- Start iteration after 5 seconds
minetest.register_on_leaveplayer(function(player) minetest.after(5, mtimer_iterate, tonumber(config['mtimer_update_interval']))
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

@ -12,11 +12,11 @@ mtimer_update_interval (Seconds between updates) int 30
# +r = Runtime of the current session # +r = Runtime of the current session
# +i = Current ingame time in 24h format # +i = Current ingame time in 24h format
# +n = Following output will be in a new line # +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 # A placeholder text that is shown before the timer
# function gets executed the first time # 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 # 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 # Time when the current session was started. The session
# is based on when the user connected to the world. The # is based on when the user connected to the world. The
# format is this: https://www.lua.org/pil/22.1.html # 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 # A hours:minutes timer that allows tracking of the
# current play time. The timer breaks if game time # current play time. The timer breaks if game time
@ -43,7 +43,7 @@ mtimer_session_start ([+s] Session start time) string %c
# +h = Hours # +h = Hours
# +m = Minutes # +m = Minutes
# +s = Seconds # +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 # The current real-world time according to what the OS
# provides. Formatting this string is quite easy by using # provides. Formatting this string is quite easy by using
@ -66,6 +66,10 @@ mtimer_locale (Format output locale) string C
[Positioning] [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 # "To account for differing resolutions, the position
# coordinates are the percentage of the screen, ranging # coordinates are the percentage of the screen, ranging
# in value from 0 to 1. 0 means left/top, 1 means # in value from 0 to 1. 0 means left/top, 1 means

76
system/timer_function.lua Normal file

@ -0,0 +1,76 @@
-- Update an idividual players timer display
--
-- When running the function the player data will be read from the players
-- `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