From 3be51bfc1b4eab99755137b83b6d08a178cb3786 Mon Sep 17 00:00:00 2001 From: FFNeko Date: Sun, 19 Jul 2026 09:56:18 -0400 Subject: [PATCH 1/5] GilTracker: add separator setting and periodic refresh Adds a configurable thousands separator and periodically refreshes the displayed gil value to catch deductions that do not trigger the existing inventory update handlers. --- addons/giltracker/giltracker.lua | 46 ++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 8 deletions(-) diff --git a/addons/giltracker/giltracker.lua b/addons/giltracker/giltracker.lua index 3612a0e927..9802de6310 100644 --- a/addons/giltracker/giltracker.lua +++ b/addons/giltracker/giltracker.lua @@ -28,7 +28,7 @@ _addon.name = 'giltracker' _addon.author = 'sylandro' -_addon.version = '1.0.0' +_addon.version = '1.0.1' _addon.language = 'English' config = require('config') @@ -51,6 +51,7 @@ local is_hidden_by_key = false defaults = {} defaults.hideKey = SCROLL_LOCK_KEY +defaults.thousandsSeparator = ',' defaults.gilText = {} defaults.gilText.bg = {} defaults.gilText.bg.alpha = 100 @@ -163,6 +164,12 @@ windower.register_event('keyboard', function(dik, down, _flags, _blocked) toggle_display_if_hide_key_is_pressed(dik, down) end) +windower.register_event('time change', function() + if inventory_loaded then + update_gil() + end +end) + function ready_if_valid_treasure_packet(packet_data) local p = packets.parse('incoming',packet_data) if (p.Count > 0) then ready = true end @@ -192,7 +199,7 @@ end function update_gil() local gil = windower.ffxi.get_items('gil') - gil_text:text(comma_value(gil)) + gil_text:text(format_value(gil)) end function show() @@ -205,13 +212,36 @@ function hide() gil_image:hide() end -function comma_value(amount) - local formatted = tostring(amount) - while true do - formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') - if (k==0) then break end +function format_value(amount) + local value = tostring(amount) + local separator = settings.thousandsSeparator + + if separator == 'space' then + separator = ' ' + elseif separator == 'none' then + separator = '' + elseif separator == nil or separator == '' then + separator = ',' + end + + local sign = '' + if value:sub(1, 1) == '-' then + sign = '-' + value = value:sub(2) end - return formatted + + local first_group = #value % 3 + if first_group == 0 then + first_group = 3 + end + + local formatted = value:sub(1, first_group) + + for index = first_group + 1, #value, 3 do + formatted = formatted..separator..value:sub(index, index + 2) + end + + return sign..formatted end function is_cutscene(status_id) From 2893e66e47f7b488f24e77e42dd7ce746d9a0e9c Mon Sep 17 00:00:00 2001 From: FFNeko Date: Sun, 19 Jul 2026 15:35:08 -0400 Subject: [PATCH 2/5] GilTracker: remove unnecessary negative value handling --- addons/giltracker/giltracker.lua | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/addons/giltracker/giltracker.lua b/addons/giltracker/giltracker.lua index 9802de6310..4fe183799f 100644 --- a/addons/giltracker/giltracker.lua +++ b/addons/giltracker/giltracker.lua @@ -224,12 +224,6 @@ function format_value(amount) separator = ',' end - local sign = '' - if value:sub(1, 1) == '-' then - sign = '-' - value = value:sub(2) - end - local first_group = #value % 3 if first_group == 0 then first_group = 3 @@ -241,7 +235,7 @@ function format_value(amount) formatted = formatted..separator..value:sub(index, index + 2) end - return sign..formatted + return formatted end function is_cutscene(status_id) From 1016fa30e3d1dcc7655c0f2bc45e926c06af5655 Mon Sep 17 00:00:00 2001 From: FFNeko Date: Sun, 19 Jul 2026 21:58:24 -0400 Subject: [PATCH 3/5] Updated per dev feedback --- addons/giltracker/giltracker.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/addons/giltracker/giltracker.lua b/addons/giltracker/giltracker.lua index 4fe183799f..14ea85689b 100644 --- a/addons/giltracker/giltracker.lua +++ b/addons/giltracker/giltracker.lua @@ -216,11 +216,13 @@ function format_value(amount) local value = tostring(amount) local separator = settings.thousandsSeparator - if separator == 'space' then + if separator == 'none' then + return value + elseif separator == 'space' then separator = ' ' - elseif separator == 'none' then - separator = '' - elseif separator == nil or separator == '' then + elseif separator == 'period' then + separator = '.' + elseif separator == 'comma' or separator == '' or not separator then separator = ',' end From 36a5200199dc0117ef2fdd66dbe4c8565f879a4f Mon Sep 17 00:00:00 2001 From: FFNeko Date: Mon, 20 Jul 2026 17:19:21 -0400 Subject: [PATCH 4/5] Address separator, refresh, and documentation feedback --- addons/giltracker/README.md | 12 ++++++ addons/giltracker/giltracker.lua | 64 +++++++++++++++++++------------- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/addons/giltracker/README.md b/addons/giltracker/README.md index 2c6e98dfc4..e8b3f5f7c6 100644 --- a/addons/giltracker/README.md +++ b/addons/giltracker/README.md @@ -3,6 +3,18 @@ This addon displays the current gil, similar to the FFXIV Gil HUD widget. ![Imgur](https://i.imgur.com/vZ8NkDr.png) +## Settings + +- `thousandsSeparator`: Separator used when displaying gil. Defaults to `,`. + Named values are `comma`, `period`, `space`, and `none`. Literal and custom + separators such as `.`, `,`, or `○` are also supported. Custom values must + be valid XML text. +- `refreshInterval`: Seconds between periodic gil updates. Defaults to `5`. + Values below `1` are treated as `1`. + +Custom separators must be valid XML text. XML-reserved characters must be +escaped, such as `&` for `&` and `<` for `<`. + ## How to edit the settings 1. Login to your character in FFXI 2. Edit the addon settings file: **_Windower4\addons\giltracker\data\settings.xml_** diff --git a/addons/giltracker/giltracker.lua b/addons/giltracker/giltracker.lua index 14ea85689b..7a333140fd 100644 --- a/addons/giltracker/giltracker.lua +++ b/addons/giltracker/giltracker.lua @@ -45,6 +45,14 @@ local LOGIN_ZONE_PACKET = 0x0A local ITEM_UPDATE_PACKET = 0x20 local ITEM_MODIFY_PACKET = 0x1F +local separator_map = { + none = '', + space = ' ', + period = '.', + comma = ',', + [''] = ',', +} + local hideKey = SCROLL_LOCK_KEY local is_hidden_by_cutscene = false local is_hidden_by_key = false @@ -52,6 +60,7 @@ local is_hidden_by_key = false defaults = {} defaults.hideKey = SCROLL_LOCK_KEY defaults.thousandsSeparator = ',' +defaults.refreshInterval = 5 defaults.gilText = {} defaults.gilText.bg = {} defaults.gilText.bg.alpha = 100 @@ -93,6 +102,16 @@ defaults.gilImage.visible = true local settings = config.load(defaults) config.save(settings) +function get_separator() + local separator = separator_map[settings.thousandsSeparator] or settings.thousandsSeparator + + if type(separator) ~= 'string' then + return defaults.thousandsSeparator + end + + return separator +end + settings.gilImage.texture = {} settings.gilImage.texture.path = windower.addon_path..'gil.png' settings.gilImage.texture.fit = true @@ -109,6 +128,15 @@ local gil_text = texts.new(settings.gilText) local inventory_loaded = false local ready = false +local function refresh_gil_loop() + while true do + coroutine.sleep(math.max(tonumber(settings.refreshInterval) or defaults.refreshInterval, 1)) + if inventory_loaded then + update_gil() + end + end +end + config.register(settings, function(settings) hideKey = settings.hideKey local windower_settings = windower.get_windower_settings() @@ -122,6 +150,7 @@ windower.register_event('load',function() if windower.ffxi.get_info().logged_in then initialize() end + coroutine.schedule(refresh_gil_loop, 0) end) windower.register_event('login',function() @@ -164,12 +193,6 @@ windower.register_event('keyboard', function(dik, down, _flags, _blocked) toggle_display_if_hide_key_is_pressed(dik, down) end) -windower.register_event('time change', function() - if inventory_loaded then - update_gil() - end -end) - function ready_if_valid_treasure_packet(packet_data) local p = packets.parse('incoming',packet_data) if (p.Count > 0) then ready = true end @@ -213,28 +236,19 @@ function hide() end function format_value(amount) - local value = tostring(amount) - local separator = settings.thousandsSeparator - - if separator == 'none' then - return value - elseif separator == 'space' then - separator = ' ' - elseif separator == 'period' then - separator = '.' - elseif separator == 'comma' or separator == '' or not separator then - separator = ',' - end + local formatted = tostring(amount) + local separator = get_separator() + local k - local first_group = #value % 3 - if first_group == 0 then - first_group = 3 + if separator == '' then + return formatted end - local formatted = value:sub(1, first_group) - - for index = first_group + 1, #value, 3 do - formatted = formatted..separator..value:sub(index, index + 2) + while true do + formatted, k = string.gsub(formatted, '^(%d+)(%d%d%d)', function(prefix, group) + return prefix..separator..group + end) + if k == 0 then break end end return formatted From 39fd31f6360039b0313c71270b48f0f97b42dfd3 Mon Sep 17 00:00:00 2001 From: FFNeko Date: Mon, 20 Jul 2026 20:02:06 -0400 Subject: [PATCH 5/5] Address follow-up review feedback --- addons/giltracker/giltracker.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/addons/giltracker/giltracker.lua b/addons/giltracker/giltracker.lua index 7a333140fd..c6dd692b31 100644 --- a/addons/giltracker/giltracker.lua +++ b/addons/giltracker/giltracker.lua @@ -28,7 +28,7 @@ _addon.name = 'giltracker' _addon.author = 'sylandro' -_addon.version = '1.0.1' +_addon.version = '1.1.0' _addon.language = 'English' config = require('config') @@ -244,10 +244,10 @@ function format_value(amount) return formatted end + local replacement = '%1'..separator:gsub('%%', '%%%%')..'%2' + while true do - formatted, k = string.gsub(formatted, '^(%d+)(%d%d%d)', function(prefix, group) - return prefix..separator..group - end) + formatted, k = string.gsub(formatted, '^(%d+)(%d%d%d)', replacement) if k == 0 then break end end