comparison core.lua @ 147:e1a90e398231

Add unique seconds to history timestamp. Rewrite :format_timestamp to suck less. Include seconds in the formatted history timestamp, because preening fails horribly when the same person has received multiple pieces of loot within the same "minute". Ensure the timestamps are unique if needed; fast looting easily results in multiple loot events per second. Tweak wording of some GUI warnings.
author Farmbuyer of US-Kilrogg <farmbuyer@gmail.com>
date Tue, 30 Dec 2014 20:26:41 -0500
parents 543fcf15add7
children 113dd7c86222
comparison
equal deleted inserted replaced
146:543fcf15add7 147:e1a90e398231
26 26
27 Common g_loot entry indices: 27 Common g_loot entry indices:
28 - kind time/boss/loot 28 - kind time/boss/loot
29 - hour 0-23, on the *physical instance server*, not the realm server 29 - hour 0-23, on the *physical instance server*, not the realm server
30 - minute 0-59, ditto 30 - minute 0-59, ditto
31 - stamp time_t on the local computer 31 - stamp time_t on the local computer, possibly tweaked for uniqueness
32 32
33 Time specific g_loot indices: 33 Time specific g_loot indices:
34 - startday table with month/day/year/text fields from makedate() 34 - startday table with month/day/year/text fields from makedate()
35 text is always "dd Month yyyy" 35 text is always "dd Month yyyy"
36 36
177 --['heirloom'] = 7, 177 --['heirloom'] = 7,
178 } 178 }
179 local my_name = UnitName('player') 179 local my_name = UnitName('player')
180 local comm_cleanup_ttl = 4 -- seconds in the communications cache 180 local comm_cleanup_ttl = 4 -- seconds in the communications cache
181 local version_large = nil -- defaults to 1, possibly changed by version 181 local version_large = nil -- defaults to 1, possibly changed by version
182 local timestamp_fmt_unique = '%Y/%m/%dT%H:%M:%S'
183 local timestamp_fmt_history = '%Y/%m/%d %H:%M:%S'
182 local g_LOOT_ITEM_ss, g_LOOT_ITEM_MULTIPLE_sss, g_LOOT_ITEM_SELF_s 184 local g_LOOT_ITEM_ss, g_LOOT_ITEM_MULTIPLE_sss, g_LOOT_ITEM_SELF_s
183 local g_LOOT_ITEM_SELF_MULTIPLE_ss, g_LOOT_ITEM_WHILE_PLAYER_INELIGIBLE_ss 185 local g_LOOT_ITEM_SELF_MULTIPLE_ss, g_LOOT_ITEM_WHILE_PLAYER_INELIGIBLE_ss
184 186
185 187
186 ------ Addon member data 188 ------ Addon member data
1818 person = match(person,"|c%x%x%x%x%x%x%x%x(%S+)") or person 1820 person = match(person,"|c%x%x%x%x%x%x%x%x(%S+)") or person
1819 else 1821 else
1820 person = my_name -- UNIT_YOU / You 1822 person = my_name -- UNIT_YOU / You
1821 end 1823 end
1822 1824
1823 return _do_loot (self, --[[override=]]false, person, unique, 1825 return _do_loot (self, --[[override=]]false, person, --[[unique=]]nil,
1824 match(itemlink,"item[%-?%d:]+"), count) 1826 match(itemlink,"item[%-?%d:]+"), count)
1825 1827
1826 elseif event == "broadcast" then 1828 elseif event == "broadcast" then
1827 return _do_loot (self, --[[override=]]false, ...) 1829 return _do_loot (self, --[[override=]]false, ...)
1828 1830
2615 end 2617 end
2616 end 2618 end
2617 2619
2618 -- Adding entries to the loot record, and tracking the corresponding timestamp. 2620 -- Adding entries to the loot record, and tracking the corresponding timestamp.
2619 do 2621 do
2620 local rawget, setmetatable = rawget, setmetatable 2622 local date, time, rawget, setmetatable = date, time, rawget, setmetatable
2621 2623
2622 --@debug@ 2624 --@debug@
2623 local tos = {} 2625 local tos = {}
2624 tos.time = function (e) 2626 tos.time = function (e)
2625 return e.startday.text 2627 return e.startday.text
2672 i = i - 1 2674 i = i - 1
2673 end 2675 end
2674 end 2676 end
2675 2677
2676 -- format_timestamp (["format_string"], Day, [Loot]) 2678 -- format_timestamp (["format_string"], Day, [Loot])
2679 -- FORMAT_STRING may contain $x (x in TmdHMS) tokens, with the same
2680 -- meanings as in Lua/strftime but restricted formatting:
2681 -- Y year, 4 digit
2682 -- m month, 2 digit
2683 -- d day, 2 digit
2684 -- H hour, 2 digit, 24-hour clock
2685 -- M minute
2686 -- S second
2677 -- DAY is a loot entry with kind=='time', and controls the date printed. 2687 -- DAY is a loot entry with kind=='time', and controls the date printed.
2678 -- LOOT may be any kind of entry in the g_loot table. If present, it 2688 -- LOOT may be any kind of entry in the g_loot table. If present, it
2679 -- overrides the hour and minute printed; if absent, those values are 2689 -- overrides the clock values printed; if absent, those values are
2680 -- taken from the DAY entry. 2690 -- taken from the DAY entry.
2681 -- FORMAT_STRING may contain $x (x in Y/M/D/h/m) tokens.
2682 -- FIXME this is horribabble
2683 local format_timestamp_values, point2dee = {}, "%.2d" 2691 local format_timestamp_values, point2dee = {}, "%.2d"
2684 function addon:format_timestamp (fmt_opt, day_entry, time_entry_opt) 2692 function addon:format_timestamp (fmt_opt, day_entry, time_entry_opt)
2685 if not time_entry_opt then 2693 if not time_entry_opt then
2686 if type(fmt_opt) == 'table' then -- Two entries, default format 2694 if type(fmt_opt) == 'table' then -- Two entries, default format
2687 time_entry_opt, day_entry = day_entry, fmt_opt 2695 time_entry_opt, day_entry = day_entry, fmt_opt
2688 fmt_opt = "$Y/$M/$D $h:$m" 2696 fmt_opt = "$Y/$m/$d $H:$M"
2689 --elseif type(fmt_opt) == "string" then -- Day entry only, caller-specified format 2697 --elseif type(fmt_opt) == "string" then -- Day entry only, caller-specified format
2690 end 2698 end
2691 end 2699 end
2692 --format_timestamp_values.Y = point2dee:format (day_entry.startday.year % 100)
2693 format_timestamp_values.Y = ("%.4d"):format (day_entry.startday.year) 2700 format_timestamp_values.Y = ("%.4d"):format (day_entry.startday.year)
2694 format_timestamp_values.M = point2dee:format (day_entry.startday.month) 2701 format_timestamp_values.m = ("%.2d"):format (day_entry.startday.month)
2695 format_timestamp_values.D = point2dee:format (day_entry.startday.day) 2702 format_timestamp_values.d = ("%.2d"):format (day_entry.startday.day)
2696 format_timestamp_values.h = point2dee:format ((time_entry_opt or day_entry).hour) 2703 format_timestamp_values.H = ("%.2d"):format ((time_entry_opt or day_entry).hour)
2697 format_timestamp_values.m = point2dee:format ((time_entry_opt or day_entry).minute) 2704 format_timestamp_values.M = ("%.2d"):format ((time_entry_opt or day_entry).minute)
2698 return fmt_opt:gsub ('%$([YMDhm])', format_timestamp_values) 2705 format_timestamp_values.S = date ("%S", (time_entry_opt or day_entry).stamp)
2706 return fmt_opt:gsub ('%$([YmdHMS])', format_timestamp_values)
2699 end 2707 end
2700 2708
2701 local done_todays_date 2709 local done_todays_date
2702 function addon:_reset_timestamps() 2710 function addon:_reset_timestamps()
2703 done_todays_date = nil 2711 done_todays_date = nil
2731 function addon._addLootEntry (e) 2739 function addon._addLootEntry (e)
2732 setmetatable(e,loot_entry_mt) 2740 setmetatable(e,loot_entry_mt)
2733 2741
2734 if not done_todays_date then do_todays_date() end 2742 if not done_todays_date then do_todays_date() end
2735 2743
2744 -- All kinds of things go awry (especially history preening) if two
2745 -- entries share the exact same timestamp, and we can't get any better
2746 -- than one second resolution.
2747 --
2748 -- Well, the only API in-game with finer precision is GetTime but the
2749 -- computer uptime doesn't help us. Stripping the fractional part off
2750 -- and gluing it to time_t would be too risky as they don't cycle at
2751 -- the same time. We could do something involving a count incrementing
2752 -- with the refresh rate, but... blech.
2753 --
2754 -- So we sort of cheat. New entries are pushed into the future one
2755 -- second at a time, if needed, so that no two time_t's are equal.
2736 local h, m = GetGameTime() 2756 local h, m = GetGameTime()
2737 --local localuptime = math.floor(GetTime())
2738 local time_t = time() 2757 local time_t = time()
2758 local index = #g_loot -- note, previous entry
2739 e.hour = h 2759 e.hour = h
2740 e.minute = m 2760 e.minute = m
2741 e.stamp = time_t --localuptime 2761 if index > 0 and g_loot[index].stamp >= time_t then
2742 local index = #g_loot + 1 2762 time_t = g_loot[index].stamp + 1
2763 addon.dprint('flow', "bumping timestamp to", time_t)
2764 end
2765 e.stamp = time_t
2766
2767 index = index + 1
2743 if e.kind == 'loot' then 2768 if e.kind == 'loot' then
2744 if (not e.unique) or (#e.unique==0) then 2769 if (not e.unique) or (#e.unique==0) then
2745 e.unique = e.id .. (e.disposition or e.person) .. date("%Y/%m/%d %H:%M",e.stamp) 2770 e.unique = e.id .. (e.disposition or e.person) .. date (timestamp_fmt_unique, e.stamp)
2746 end 2771 end
2747 addon:Fire ('NewLootEntry', e, index) 2772 addon:Fire ('NewLootEntry', e, index)
2748 end 2773 end
2749 g_loot[index] = e 2774 g_loot[index] = e
2750 g_gui.g_dloot[index] = nil 2775 g_gui.g_dloot[index] = nil
3160 -- ["name"] = "Farmbuyer", 3185 -- ["name"] = "Farmbuyer",
3161 -- ["person_class"] = "PRIEST", -- may be missing, used in display only 3186 -- ["person_class"] = "PRIEST", -- may be missing, used in display only
3162 -- -- sorted array: 3187 -- -- sorted array:
3163 -- ["unique"] = { most_recent_tag, previous_tag, .... }, 3188 -- ["unique"] = { most_recent_tag, previous_tag, .... },
3164 -- -- these are indexed by unique tags, and 'count' may be missing: 3189 -- -- these are indexed by unique tags, and 'count' may be missing:
3165 -- ["when"] = { ["tag"] = "formatted timestamp for displaying loot" }, 3190 -- ["when"] = { ["tag"] = "formatted timestamp for displaying loot history" },
3166 -- ["id"] = { ["tag"] = 11111 }, 3191 -- ["id"] = { ["tag"] = 11111 },
3167 -- ["count"] = { ["tag"] = "x3", .... }, 3192 -- ["count"] = { ["tag"] = "x3", .... },
3168 -- }, 3193 -- },
3169 -- [2] = { 3194 -- [2] = {
3170 -- ["name"] = "OtherPlayer", 3195 -- ["name"] = "OtherPlayer",
3191 return L > R -- reverse of normal order, newest first 3216 return L > R -- reverse of normal order, newest first
3192 end 3217 end
3193 local function sort_player (p) 3218 local function sort_player (p)
3194 local new_uniques, uniques_bywhen, when_array = {}, new(), new() 3219 local new_uniques, uniques_bywhen, when_array = {}, new(), new()
3195 for u,tstamp in pairs(p.when) do 3220 for u,tstamp in pairs(p.when) do
3221 -- XXX multiple identical tstamps
3196 uniques_bywhen[tstamp] = u 3222 uniques_bywhen[tstamp] = u
3197 when_array[#when_array+1] = tstamp 3223 when_array[#when_array+1] = tstamp
3198 end 3224 end
3199 table.sort (when_array, compare_timestamps) 3225 table.sort (when_array, compare_timestamps)
3200 for i,tstamp in ipairs(when_array) do 3226 for i,tstamp in ipairs(when_array) do
3382 -- be the most recent entry). If g_today has not been set, then falls 3408 -- be the most recent entry). If g_today has not been set, then falls
3383 -- back on formatting LOOTINDEX's time_t 'stamp' field. 3409 -- back on formatting LOOTINDEX's time_t 'stamp' field.
3384 -- 3410 --
3385 -- If RESORT_P is true-valued, then re-sorts the player's history based on 3411 -- If RESORT_P is true-valued, then re-sorts the player's history based on
3386 -- formatted timestmps, instead of leaving the new entry as the latest. 3412 -- formatted timestmps, instead of leaving the new entry as the latest.
3413 local tfmt_hist = timestamp_fmt_history:gsub('%%','$')
3387 function addon:_addHistoryEntry (lootindex, resort_p) 3414 function addon:_addHistoryEntry (lootindex, resort_p)
3388 local e = g_loot[lootindex] 3415 local e = g_loot[lootindex]
3389 if e.kind ~= 'loot' then return end 3416 if e.kind ~= 'loot' then return end
3390 3417
3391 if e.person_realm and opts.history_ignore_xrealm then 3418 if e.person_realm and opts.history_ignore_xrealm then
3394 3421
3395 local i,h = self:get_loot_history(e.person) 3422 local i,h = self:get_loot_history(e.person)
3396 -- If we've added anything at all into g_loot this session, g_today 3423 -- If we've added anything at all into g_loot this session, g_today
3397 -- will be set. If we've logged on simply to manipulate history, then 3424 -- will be set. If we've logged on simply to manipulate history, then
3398 -- try and fake a timestamp (it'll be "close enough"). 3425 -- try and fake a timestamp (it'll be "close enough").
3399 local when = g_today and self:format_timestamp (g_today,e) 3426 -- (WoD: This logic may be backwards now that loot entries track time_t.)
3400 or date("%Y/%m/%d %H:%M",e.stamp) 3427 local when = g_today
3428 and self:format_timestamp (tfmt_hist, g_today, e)
3429 or date (timestamp_fmt_history, e.stamp)
3401 assert(h.name==e.person) 3430 assert(h.name==e.person)
3402 3431
3403 -- Should rarely happen anymore: 3432 -- Should rarely happen anymore:
3404 if (not e.unique) or (#e.unique==0) then 3433 if (not e.unique) or (#e.unique==0) then
3405 e.unique = e.id .. e.person .. when 3434 e.unique = e.id .. e.person .. when