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 local 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 local 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 function CollectTooltippery(self
)
56 if not self
then self
= GameTooltip
end
58 local tstart
= GetTime()
59 for k
, v
in pairs(TooltipRegistrar
) do
62 QH_Timeslice_Increment(GetTime() - tstart
, "collect_tooltip")
64 -- anything past here is not my fault
67 local ottsu
= GameTooltip
:GetScript("OnTooltipSetUnit")
68 GameTooltip
:SetScript("OnTooltipSetUnit", function (self
, ...)
69 CollectTooltippery(self
)
70 if ottsu
then return ottsu(self
, ...) end
73 local ottsi
= GameTooltip
:GetScript("OnTooltipSetItem")
74 GameTooltip
:SetScript("OnTooltipSetItem", function (self
, ...)
75 CollectTooltippery(self
)
76 if ottsi
then return ottsi(self
, ...) end
80 local function TooltipHookRegistrar(func
)
81 QuestHelper
: Assert(func
)
82 table.insert(TooltipRegistrar
, func
)
86 Registrar_EventHook
= EventHookRegistrar
,
87 Registrar_OnUpdateHook
= OnUpdateHookRegistrar
,
88 Registrar_TooltipHook
= TooltipHookRegistrar
,
89 Callback_Location_Raw
= function () return QuestHelper
:Location_RawRetrieve() end,
90 Callback_Location_Absolute
= function () return QuestHelper
:Location_AbsoluteRetrieve() end,
93 -- We do these early, because some things that aren't in collect may rely on these. Yes I realize that avoiding this was one of my main goals in the separate collect system, shut up go away I hate you (in all seriousness: crunch mode + lazy = some nasty bits.)
94 -- TODO: Make a common collect/mainmodule system, then rely on that better.
95 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.
96 QH_Collect_Merger_Init(nil, API
)
97 QH_Collect_Bitstream_Init(nil, API
)
98 QH_Collect_Location_Init(nil, API
)
99 QH_Collect_Patterns_Init(nil, API
)
100 QH_Collect_Notifier_Init(nil, API
)
101 QH_Collect_Spec_Init(nil, API
)
102 QH_Collect_LZW_Init(nil, API
)
104 local CompressCollection
106 function QH_Collector_Init()
107 QH_Collector_UpgradeAll(QuestHelper_Collector
)
109 for _
, v
in pairs(QuestHelper_Collector
) do
110 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.
113 QuestHelper_Collector_Version
= QuestHelper_Collector_Version_Current
115 local sig
= string.format("%s on %s/%s/%d", GetAddOnMetadata("QuestHelper", "Version"), GetBuildInfo(), GetLocale(), QuestHelper
:PlayerFaction())
116 local sig_altfaction
= string.format("%s on %s/%s/%d", GetAddOnMetadata("QuestHelper", "Version"), GetBuildInfo(), GetLocale(), (QuestHelper
:PlayerFaction() == 1) and 2 or 1)
117 if not QuestHelper_Collector
[sig
] or QuestHelper_Collector
[sig
].compressed
then QuestHelper_Collector
[sig
] = {version
= QuestHelper_Collector_Version
} end -- fuckin' bullshit, man
118 local QHCData
= QuestHelper_Collector
[sig
]
119 QuestHelper
: Assert(not QHCData
.compressed
)
120 QuestHelper
: Assert(QHCData
.version
== QuestHelper_Collector_Version_Current
)
121 QHCData
.modified
= time()
123 QH_Collect_Achievement_Init(QHCData
, API
)
124 QH_Collect_Traveled_Init(QHCData
, API
)
125 QH_Collect_Zone_Init(QHCData
, API
)
126 QH_Collect_Monster_Init(QHCData
, API
)
127 QH_Collect_Item_Init(QHCData
, API
)
128 QH_Collect_Object_Init(QHCData
, API
)
129 QH_Collect_Flight_Init(QHCData
, API
)
130 QH_Collect_Quest_Init(QHCData
, API
)
131 QH_Collect_Warp_Init(QHCData
, API
)
133 QH_Collect_Loot_Init(QHCData
, API
)
134 QH_Collect_Equip_Init(QHCData
, API
)
135 QH_Collect_Merchant_Init(QHCData
, API
)
137 if not QHCData
.realms
then QHCData
.realms
= {} end
138 QHCData
.realms
[GetRealmName()] = (QHCData
.realms
[GetRealmName()] or 0) + 1 -- I'm not entirely sure why I'm counting
140 if false then -- this will be disabled in most public releases, or set to a very rare probabalistic thing
141 if not QHCData
.routing_dump
then QHCData
.routing_dump
= {} end
143 table.insert(QHCData
.routing_dump
, nt
)
144 QH_Collect_Routing_Dump
= nt
147 do -- Clean some stuff up!
148 local obliterate
= {}
149 for k
, v
in pairs(QuestHelper_Collector
) do
150 if not v
.modified
or v
.modified
+ 30 * 24 * 60 * 60 < GetTime() then
151 table.insert(obliterate
, k
)
155 for _
, v
in ipairs(obliterate
) do
156 QuestHelper_Collector
[v
] = nil
160 -- So, why do we delay it?
161 -- 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!
162 -- 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.
163 -- addendum: yeah naturally I'm getting all sorts of panicked comments about how bloated qh has gotten, sigh
164 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)
167 function QH_Collector_OnUpdate()
168 local tstart
= GetTime()
169 for _
, v
in pairs(OnUpdateRegistrar
) do
172 QH_Timeslice_Increment(GetTime() - tstart
, "collect_update")
177 --- 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.)
179 local noncompressible
= {
188 local serializers
= {
189 ["nil"] = function(item
, add
)
192 ["number"] = function(item
, add
)
195 ["string"] = function(item
, add
)
196 add(string.format("%q", item
))
198 ["boolean"] = function(item
, add
)
199 add(item
and "true" or "false")
201 ["table"] = function(item
, add
)
204 for k
, v
in pairs(item
) do
205 if not first
then add(",") end
216 seritem
= function(item
, add
)
218 serializers
[type(item
)](item
, add
)
221 local function DoCompress(item
, merger
, comp
)
222 if debug_output
then QuestHelper
: TextOut("Item condensing") end
226 for k
, v
in pairs(item
) do
227 if not noncompressible
[k
] then
233 seritem(target
, function(dat
) merger
.Add(mg
, dat
) end)
235 local tg
= merger
.Finish(mg
)
236 if debug_output
then QuestHelper
: TextOut(string.format("Item condensed to %d bytes, %f taken so far", #tg
, GetTime() - ts
)) end
242 local doublecheck
= ""
243 for chunk
= 1, #tg
, 1048576 do
244 local fragment
= tg
:sub(chunk
, chunk
+ 1048575)
245 doublecheck
= doublecheck
.. fragment
246 local ite
= comp(fragment
, 256, 8)
247 cmptot
= cmptot
+ #ite
248 table.insert(cmp
, ite
)
250 QuestHelper
: Assert(doublecheck
== tg
)
252 if #cmp
== 1 then cmp
= cmp
[1] end
254 for k
, v
in pairs(target
) do
255 if not noncompressible
[k
] then
259 item
.compressed
= cmp
261 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
264 CompressCollection
= function(active
, active2
, merger
, comp
)
265 for _
, v
in pairs(QuestHelper_Collector
) do
266 if v
~= active
and v
~= active2
and not v
.compressed
then
267 QH_Timeslice_Add(function ()
268 DoCompress(v
, merger
, comp
)
269 CompressCollection(active
, active2
, merger
, comp
)