1 QuestHelper_File
["collect.lua"] = "Development Version"
2 QuestHelper_Loadtime
["collect.lua"] = GetTime()
4 local debug_output
= false
5 if QuestHelper_File
["collect.lua"] == "Development Version" then debug_output
= true end
7 local QuestHelper_Collector_Version_Current
= 7
9 QuestHelper_Collector
= {}
10 QuestHelper_Collector_Version
= QuestHelper_Collector_Version_Current
12 local EventRegistrar
= {}
13 local OnUpdateRegistrar
= {}
14 local TooltipRegistrar
= {}
16 local frame
= CreateFrame("Frame")
18 local function OnEvent(_
, event
, ...)
19 local tstart
= GetTime()
20 for _
, v
in pairs(EventRegistrar
[event
]) do
23 QH_Timeslice_Increment(GetTime() - tstart
, "collect_event")
26 frame
:UnregisterAllEvents()
27 frame
:SetScript("OnEvent", OnEvent
)
31 function EventHookRegistrar(event
, func
)
32 QuestHelper
:Assert(func
)
33 if not EventRegistrar
[event
] then
34 frame
:RegisterEvent(event
)
35 EventRegistrar
[event
] = {}
37 table.insert(EventRegistrar
[event
], func
)
40 function OnUpdateHookRegistrar(func
)
41 QuestHelper
:Assert(func
)
42 table.insert(OnUpdateRegistrar
, func
)
45 local suppress
= false
47 -- real tooltips don't use this function
48 local SetTextScript
= GameTooltip
.SetText
49 GameTooltip
.SetText
= function (...)
55 local OriginalScript
= GameTooltip
:GetScript("OnShow")
56 GameTooltip
:SetScript("OnShow", function (self
, ...)
58 if not self
then self
= GameTooltip
end
60 local tstart
= GetTime()
61 for k
, v
in pairs(TooltipRegistrar
) do
64 QH_Timeslice_Increment(GetTime() - tstart
, "collect_tooltip")
67 -- anything past here is not my fault
69 if OriginalScript
then
70 return OriginalScript(self
, ...)
74 function TooltipHookRegistrar(func
)
75 QuestHelper
:Assert(func
)
76 table.insert(TooltipRegistrar
, func
)
80 Registrar_EventHook
= EventHookRegistrar
,
81 Registrar_OnUpdateHook
= OnUpdateHookRegistrar
,
82 Registrar_TooltipHook
= TooltipHookRegistrar
,
83 Callback_Location_Raw
= function () return QuestHelper
:Location_RawRetrieve() end,
84 Callback_Location_Absolute
= function () return QuestHelper
:Location_AbsoluteRetrieve() end,
87 local CompressCollection
89 function QH_Collector_Init()
90 QH_Collector_UpgradeAll(QuestHelper_Collector
)
92 for _
, v
in pairs(QuestHelper_Collector
) do
93 if not v
.modified
then v
.modified
= time() - 7 * 24 * 60 * 60 end -- eugh. Yeah, we set it to be a week ago. It's pretty grim.
96 QuestHelper_Collector_Version
= QuestHelper_Collector_Version_Current
98 local sig
= string.format("%s on %s/%s/%d", GetAddOnMetadata("QuestHelper", "Version"), GetBuildInfo(), GetLocale(), QuestHelper
:PlayerFaction())
99 local sig_altfaction
= string.format("%s on %s/%s/%d", GetAddOnMetadata("QuestHelper", "Version"), GetBuildInfo(), GetLocale(), (QuestHelper
:PlayerFaction() == 1) and 2 or 1)
100 if not QuestHelper_Collector
[sig
] or QuestHelper_Collector
[sig
].compressed
then QuestHelper_Collector
[sig
] = {version
= QuestHelper_Collector_Version
} end -- fuckin' bullshit, man
101 local QHCData
= QuestHelper_Collector
[sig
]
102 QuestHelper
: Assert(not QHCData
.compressed
)
103 QuestHelper
: Assert(QHCData
.version
== QuestHelper_Collector_Version_Current
)
104 QHCData
.modified
= time()
106 QH_Collect_Util_Init(nil, API
) -- Some may actually add their own functions to the API, and should go first. There's no real formalized order, I just know which depend on others, and it's heavily asserted so it will break if it goes in the wrong order.
107 QH_Collect_Merger_Init(nil, API
)
108 QH_Collect_Bitstream_Init(nil, API
)
110 QH_Collect_Location_Init(nil, API
)
111 QH_Collect_Patterns_Init(nil, API
)
112 QH_Collect_Notifier_Init(nil, API
)
113 QH_Collect_Spec_Init(nil, API
)
115 QH_Collect_LZW_Init(nil, API
)
117 QH_Collect_Achievement_Init(QHCData
, API
)
118 QH_Collect_Traveled_Init(QHCData
, API
)
119 QH_Collect_Zone_Init(QHCData
, API
)
120 QH_Collect_Monster_Init(QHCData
, API
)
121 QH_Collect_Item_Init(QHCData
, API
)
122 QH_Collect_Object_Init(QHCData
, API
)
123 QH_Collect_Flight_Init(QHCData
, API
)
124 QH_Collect_Quest_Init(QHCData
, API
)
125 QH_Collect_Warp_Init(QHCData
, API
)
127 QH_Collect_Loot_Init(QHCData
, API
)
128 QH_Collect_Equip_Init(QHCData
, API
)
129 QH_Collect_Merchant_Init(QHCData
, API
)
131 if not QHCData
.realms
then QHCData
.realms
= {} end
132 QHCData
.realms
[GetRealmName()] = (QHCData
.realms
[GetRealmName()] or 0) + 1 -- I'm not entirely sure why I'm counting
134 do -- Clean some stuff up!
135 local obliterate
= {}
136 for k
, v
in pairs(QuestHelper_Collector
) do
137 if not v
.modified
or v
.modified
+ 30 * 24 * 60 * 60 < GetTime() then
138 table.insert(obliterate
, k
)
142 for _
, v
in ipairs(obliterate
) do
143 QuestHelper_Collector
[k
] = nil
147 -- So, why do we delay it?
148 -- It's simple. People are gonna update to this version, and then they're going to look at the memory usage. Then they will panic because omg this version uses so much more memory, I bet that will somehow hurt my framerates in a way which is not adequately explained!
149 -- So instead, we just wait half an hour before compressing. Compression will still get done, and I won't have to deal with panicked comments about how bloated QH has gotten.
150 API
.Utility_Notifier(GetTime() + (debug_output
and 0 or (30 * 60)), function() CompressCollection(QHCData
, QuestHelper_Collector
[sig_altfaction
], API
.Utility_Merger
, API
.Utility_LZW
.Compress
) end)
153 function QH_Collector_OnUpdate()
154 local tstart
= GetTime()
155 for _
, v
in pairs(OnUpdateRegistrar
) do
158 QH_Timeslice_Increment(GetTime() - tstart
, "collect_update")
163 --- I've tossed the compression stuff down here just 'cause I don't feel like making an entire file for it (even though I probably should.)
165 local noncompressible
= {
174 local serializers
= {
175 ["nil"] = function(item
, add
)
178 ["number"] = function(item
, add
)
181 ["string"] = function(item
, add
)
182 add(string.format("%q", item
))
184 ["boolean"] = function(item
, add
)
185 add(item
and "true" or "false")
187 ["table"] = function(item
, add
)
190 for k
, v
in pairs(item
) do
191 if not first
then add(",") end
202 seritem
= function(item
, add
)
204 serializers
[type(item
)](item
, add
)
207 local function DoCompress(item
, merger
, comp
)
208 if debug_output
then QuestHelper
: TextOut("Item condensing") end
212 for k
, v
in pairs(item
) do
213 if not noncompressible
[k
] then
219 seritem(target
, function(dat
) merger
.Add(mg
, dat
) end)
221 local tg
= merger
.Finish(mg
)
222 if debug_output
then QuestHelper
: TextOut(string.format("Item condensed to %d bytes, %f taken so far", #tg
, GetTime() - ts
)) end
228 local doublecheck
= ""
229 for chunk
= 1, #tg
, 1048576 do
230 local fragment
= tg
:sub(chunk
, chunk
+ 1048575)
231 doublecheck
= doublecheck
.. fragment
232 local ite
= comp(fragment
, 256, 8)
233 cmptot
= cmptot
+ #ite
234 table.insert(cmp
, ite
)
236 QuestHelper
: Assert(doublecheck
== tg
)
238 if #cmp
== 1 then cmp
= cmp
[1] end
240 for k
, v
in pairs(target
) do
241 if not noncompressible
[k
] then
245 item
.compressed
= cmp
247 if debug_output
then QuestHelper
: TextOut(string.format("Item compressed to %d bytes in %d shards (previously %d), %f taken", cmptot
, type(cmp
) == "table" and #cmp
or 1, #tg
, GetTime() - ts
)) end
250 CompressCollection
= function(active
, active2
, merger
, comp
)
251 for _
, v
in pairs(QuestHelper_Collector
) do
252 if v
~= active
and v
~= active2
and not v
.compressed
then
253 QH_Timeslice_Add(function ()
254 DoCompress(v
, merger
, comp
)
255 CompressCollection(active
, active2
, merger
, comp
)