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
= 8
9 QuestHelper_Collector
= {}
10 QuestHelper_Collector_Version
= QuestHelper_Collector_Version_Current
12 local OnUpdateRegistrar
= {}
13 local TooltipRegistrar
= {}
15 local function OnUpdateHookRegistrar(func
)
16 QuestHelper
: Assert(func
)
17 table.insert(OnUpdateRegistrar
, func
)
20 local suppress
= false
22 -- real tooltips don't use this function
23 local SetTextScript
= GameTooltip
.SetText
24 GameTooltip
.SetText
= function (...)
30 local function CollectTooltippery(self
)
31 if not self
then self
= GameTooltip
end
33 for k
, v
in pairs(TooltipRegistrar
) do
37 -- anything past here is not my fault
40 local ottsu
= GameTooltip
:GetScript("OnTooltipSetUnit")
41 QH_Hook(GameTooltip
, "OnTooltipSetUnit", function (self
, ...)
42 CollectTooltippery(self
)
43 if ottsu
then return QH_Hook_NotMyFault(ottsu
, self
, ...) end
44 end, "collection OnTooltipSetUnit")
46 local ottsi
= GameTooltip
:GetScript("OnTooltipSetItem")
47 QH_Hook(GameTooltip
, "OnTooltipSetItem", function (self
, ...)
48 CollectTooltippery(self
)
49 if ottsi
then return QH_Hook_NotMyFault(ottsi
, self
, ...) end
50 end, "collection OnTooltipSetItem")
53 local function TooltipHookRegistrar(func
)
54 QuestHelper
: Assert(func
)
55 table.insert(TooltipRegistrar
, func
)
59 Registrar_OnUpdateHook
= OnUpdateHookRegistrar
,
60 Registrar_TooltipHook
= TooltipHookRegistrar
,
61 Callback_Location_Raw
= function () return QuestHelper
:Location_RawRetrieve() end,
62 Callback_Location_Absolute
= function () return QuestHelper
:Location_AbsoluteRetrieve() end,
65 -- 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.)
66 -- TODO: Make a common collect/mainmodule system, then rely on that better.
67 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.
68 QH_Collect_Merger_Init(nil, API
)
69 QH_Collect_Bitstream_Init(nil, API
)
70 QH_Collect_Location_Init(nil, API
)
71 QH_Collect_Patterns_Init(nil, API
)
72 QH_Collect_Notifier_Init(nil, API
)
73 QH_Collect_Spec_Init(nil, API
)
74 QH_Collect_LZW_Init(nil, API
)
76 local CompressCollection
78 function QH_Collector_Init()
79 QH_Collector_UpgradeAll(QuestHelper_Collector
)
81 for _
, v
in pairs(QuestHelper_Collector
) do
82 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.
85 QuestHelper_Collector_Version
= QuestHelper_Collector_Version_Current
87 local sig
= string.format("%s on %s/%s/%d", GetAddOnMetadata("QuestHelper", "Version"), GetBuildInfo(), GetLocale(), QuestHelper
:PlayerFaction())
88 local sig_altfaction
= string.format("%s on %s/%s/%d", GetAddOnMetadata("QuestHelper", "Version"), GetBuildInfo(), GetLocale(), (QuestHelper
:PlayerFaction() == 1) and 2 or 1)
89 if not QuestHelper_Collector
[sig
] or QuestHelper_Collector
[sig
].compressed
then QuestHelper_Collector
[sig
] = {version
= QuestHelper_Collector_Version
} end -- fuckin' bullshit, man
90 local QHCData
= QuestHelper_Collector
[sig
]
91 QuestHelper
: Assert(not QHCData
.compressed
)
92 QuestHelper
: Assert(QHCData
.version
== QuestHelper_Collector_Version_Current
)
93 QHCData
.modified
= time()
95 QH_Collect_Achievement_Init(QHCData
, API
)
96 QH_Collect_Traveled_Init(QHCData
, API
)
97 QH_Collect_Zone_Init(QHCData
, API
)
98 QH_Collect_Monster_Init(QHCData
, API
)
99 QH_Collect_Item_Init(QHCData
, API
)
100 QH_Collect_Object_Init(QHCData
, API
)
101 QH_Collect_Flight_Init(QHCData
, API
)
102 QH_Collect_Quest_Init(QHCData
, API
)
103 QH_Collect_Warp_Init(QHCData
, API
)
105 QH_Collect_Loot_Init(QHCData
, API
)
106 QH_Collect_Equip_Init(QHCData
, API
)
107 QH_Collect_Merchant_Init(QHCData
, API
)
109 if not QHCData
.realms
then QHCData
.realms
= {} end
110 QHCData
.realms
[GetRealmName()] = (QHCData
.realms
[GetRealmName()] or 0) + 1 -- I'm not entirely sure why I'm counting
112 if false then -- this will be disabled in most public releases, or set to a very rare probabalistic thing
113 if not QHCData
.routing_dump
then QHCData
.routing_dump
= {} end
115 table.insert(QHCData
.routing_dump
, nt
)
116 QH_Collect_Routing_Dump
= nt
119 do -- Clean some stuff up!
120 local obliterate
= {}
121 for k
, v
in pairs(QuestHelper_Collector
) do
122 if not v
.modified
or v
.modified
+ 30 * 24 * 60 * 60 < GetTime() then
123 table.insert(obliterate
, k
)
127 for _
, v
in ipairs(obliterate
) do
128 QuestHelper_Collector
[v
] = nil
132 -- So, why do we delay it?
133 -- 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!
134 -- 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.
135 -- addendum: yeah naturally I'm getting all sorts of panicked comments about how bloated qh has gotten, sigh
136 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)
139 QH_OnUpdate(function ()
140 local tstart
= GetTime()
141 for _
, v
in pairs(OnUpdateRegistrar
) do
144 QH_Timeslice_Increment(GetTime() - tstart
, "collect_update")
149 --- 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.)
151 local noncompressible
= {
160 local serializers
= {
161 ["nil"] = function(item
, add
)
164 ["number"] = function(item
, add
)
167 ["string"] = function(item
, add
)
168 add(string.format("%q", item
))
170 ["boolean"] = function(item
, add
)
171 add(item
and "true" or "false")
173 ["table"] = function(item
, add
)
176 for k
, v
in pairs(item
) do
177 if not first
then add(",") end
188 seritem
= function(item
, add
)
190 serializers
[type(item
)](item
, add
)
193 local function DoCompress(item
, merger
, comp
)
194 if debug_output
then QuestHelper
: TextOut("Item condensing") end
198 for k
, v
in pairs(item
) do
199 if not noncompressible
[k
] then
205 seritem(target
, function(dat
) merger
.Add(mg
, dat
) end)
207 local tg
= merger
.Finish(mg
)
208 if debug_output
then QuestHelper
: TextOut(string.format("Item condensed to %d bytes, %f taken so far", #tg
, GetTime() - ts
)) end
214 local doublecheck
= ""
215 for chunk
= 1, #tg
, 1048576 do
216 local fragment
= tg
:sub(chunk
, chunk
+ 1048575)
217 doublecheck
= doublecheck
.. fragment
218 local ite
= comp(fragment
, 256, 8)
219 cmptot
= cmptot
+ #ite
220 table.insert(cmp
, ite
)
222 QuestHelper
: Assert(doublecheck
== tg
)
224 if #cmp
== 1 then cmp
= cmp
[1] end
226 for k
, v
in pairs(target
) do
227 if not noncompressible
[k
] then
231 item
.compressed
= cmp
233 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
236 CompressCollection
= function(active
, active2
, merger
, comp
)
237 for _
, v
in pairs(QuestHelper_Collector
) do
238 if v
~= active
and v
~= active2
and not v
.compressed
then
239 QH_Timeslice_Add(function ()
240 DoCompress(v
, merger
, comp
)
241 CompressCollection(active
, active2
, merger
, comp
)