I shouldn't be logging to nlog
[QuestHelper.git] / collect.lua
blob079cdd3350c16cc27566a648e113ed2906c4eed1
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 = 6
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
21 v(...)
22 end
23 QH_Timeslice_Increment(GetTime() - tstart, "collect_event")
24 end
26 frame:UnregisterAllEvents()
27 frame:SetScript("OnEvent", OnEvent)
29 frame:Show()
31 function EventHookRegistrar(event, func)
32 QuestHelper:Assert(func)
33 if not EventRegistrar[event] then
34 frame:RegisterEvent(event)
35 EventRegistrar[event] = {}
36 end
37 table.insert(EventRegistrar[event], func)
38 end
40 function OnUpdateHookRegistrar(func)
41 QuestHelper:Assert(func)
42 table.insert(OnUpdateRegistrar, func)
43 end
45 local suppress = false
47 -- real tooltips don't use this function
48 local SetTextScript = GameTooltip.SetText
49 GameTooltip.SetText = function (...)
50 suppress = true
51 SetTextScript(...)
52 suppress = false
53 end
55 local OriginalScript = GameTooltip:GetScript("OnShow")
56 GameTooltip:SetScript("OnShow", function (self, ...)
57 if suppress then return end
59 if not self then self = GameTooltip end
61 local tstart = GetTime()
62 for k, v in pairs(TooltipRegistrar) do
63 v(self, ...)
64 end
65 QH_Timeslice_Increment(GetTime() - tstart, "collect_tooltip") -- anything past here is not my fault
66 if OriginalScript then
67 return OriginalScript(self, ...)
68 end
69 end)
71 function TooltipHookRegistrar(func)
72 QuestHelper:Assert(func)
73 table.insert(TooltipRegistrar, func)
74 end
76 local API = {
77 Registrar_EventHook = EventHookRegistrar,
78 Registrar_OnUpdateHook = OnUpdateHookRegistrar,
79 Registrar_TooltipHook = TooltipHookRegistrar,
80 Callback_RawLocation = function () return QuestHelper:RetrieveRawLocation() end,
83 local CompressCollection
85 function QH_Collector_Init()
86 QH_Collector_UpgradeAll(QuestHelper_Collector)
88 for _, v in pairs(QuestHelper_Collector) do
89 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.
90 end
92 QuestHelper_Collector_Version = QuestHelper_Collector_Version_Current
94 local sig = string.format("%s on %s/%s/%d", GetAddOnMetadata("QuestHelper", "Version"), GetBuildInfo(), GetLocale(), QuestHelper:PlayerFaction())
95 if not QuestHelper_Collector[sig] or QuestHelper_Collector[sig].compressed then QuestHelper_Collector[sig] = {version = QuestHelper_Collector_Version} end -- fuckin' bullshit, man
96 local QHCData = QuestHelper_Collector[sig]
97 QuestHelper: Assert(not QHCData.compressed)
98 QuestHelper: Assert(QHCData.version == QuestHelper_Collector_Version_Current)
99 QHCData.modified = time()
101 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.
102 QH_Collect_Merger_Init(nil, API)
103 QH_Collect_Bitstream_Init(nil, API)
105 QH_Collect_Location_Init(nil, API)
106 QH_Collect_Patterns_Init(nil, API)
107 QH_Collect_Notifier_Init(nil, API)
108 QH_Collect_Spec_Init(nil, API)
110 QH_Collect_LZW_Init(nil, API)
112 QH_Collect_Achievement_Init(QHCData, API)
113 QH_Collect_Traveled_Init(QHCData, API)
114 QH_Collect_Zone_Init(QHCData, API)
115 QH_Collect_Monster_Init(QHCData, API)
116 QH_Collect_Item_Init(QHCData, API)
117 QH_Collect_Object_Init(QHCData, API)
118 QH_Collect_Flight_Init(QHCData, API)
119 QH_Collect_Quest_Init(QHCData, API)
120 QH_Collect_Warp_Init(QHCData, API)
122 QH_Collect_Loot_Init(QHCData, API)
123 QH_Collect_Equip_Init(QHCData, API)
124 QH_Collect_Merchant_Init(QHCData, API)
126 if not QHCData.realms then QHCData.realms = {} end
127 QHCData.realms[GetRealmName()] = (QHCData.realms[GetRealmName()] or 0) + 1 -- I'm not entirely sure why I'm counting
129 -- So, why do we delay it?
130 -- 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!
131 -- 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.
132 -- Want QH to work better? Just make that "30 * 60" bit into "0" instead.
133 API.Utility_Notifier(GetTime() + 30 * 60, function() CompressCollection(QHCData, API.Utility_Merger, API.Utility_LZW.Compress) end)
136 function QH_Collector_OnUpdate()
137 local tstart = GetTime()
138 for _, v in pairs(OnUpdateRegistrar) do
141 QH_Timeslice_Increment(GetTime() - tstart, "collect_update")
146 --- 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.)
148 local noncompressible = {
149 modified = true,
150 version = true,
153 local squarify
155 local seritem
157 local serializers = {
158 ["nil"] = function(item, add)
159 add("nil")
160 end,
161 ["number"] = function(item, add)
162 add(tostring(item))
163 end,
164 ["string"] = function(item, add)
165 add(string.format("%q", item))
166 end,
167 ["boolean"] = function(item, add)
168 add(item and "true" or "false")
169 end,
170 ["table"] = function(item, add)
171 add("{")
172 local first = true
173 for k, v in pairs(item) do
174 if not first then add(",") end
175 first = false
176 add("[")
177 seritem(k, add)
178 add("]=")
179 seritem(v, add)
181 add("}")
182 end,
185 seritem = function(item, add)
186 QH_Timeslice_Yield()
187 serializers[type(item)](item, add)
190 local function DoCompress(item, merger, comp)
191 if debug_output then QuestHelper: TextOut("Item condensing") end
192 local ts = GetTime()
194 local target = {}
195 for k, v in pairs(item) do
196 if not noncompressible[k] then
197 target[k] = v
201 local mg = {}
202 seritem(target, function(dat) merger.Add(mg, dat) end)
204 local tg = merger.Finish(mg)
205 if debug_output then QuestHelper: TextOut(string.format("Item condensed to %d bytes, %f taken so far", #tg, GetTime() - ts)) end
206 mg = nil
208 local cmp = comp(tg, 256, 8)
210 for k, v in pairs(target) do
211 if not noncompressible[k] then
212 item[k] = nil
215 item.compressed = cmp
217 if debug_output then QuestHelper: TextOut(string.format("Item compressed to %d bytes (previously %d), %f taken", #cmp, #tg, GetTime() - ts)) end
220 CompressCollection = function(active, merger, comp)
221 for _, v in pairs(QuestHelper_Collector) do
222 if v ~= active and not v.compressed then
223 QH_Timeslice_Add(function ()
224 DoCompress(v, merger, comp)
225 CompressCollection(active, merger, comp)
226 end, "compress")
227 break