vanilla-wow-addons – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | |
2 | local vmajor, vminor = "1", tonumber(string.sub("$Revision: 2219 $", 12, -3)) |
||
3 | |||
4 | |||
5 | -- Check to see if an update is needed |
||
6 | -- if not then just return out now before we do anything |
||
7 | local libobj = PeriodicTableEmbed |
||
8 | if libobj and not libobj:NeedsUpgraded(vmajor, vminor) then return end |
||
9 | |||
10 | |||
11 | local stubobj = TekLibStub |
||
12 | if not stubobj then |
||
13 | stubobj = {} |
||
14 | TekLibStub = stubobj |
||
15 | |||
16 | |||
17 | -- Instance replacement method, replace contents of old with that of new |
||
18 | function stubobj:ReplaceInstance(old, new) |
||
19 | for k,v in pairs(old) do old[k]=nil end |
||
20 | for k,v in pairs(new) do old[k]=v end |
||
21 | end |
||
22 | |||
23 | |||
24 | -- Get a new copy of the stub |
||
25 | function stubobj:NewStub(name) |
||
26 | local newStub = {} |
||
27 | self:ReplaceInstance(newStub, self) |
||
28 | newStub.libName = name |
||
29 | newStub.lastVersion = '' |
||
30 | newStub.versions = {} |
||
31 | return newStub |
||
32 | end |
||
33 | |||
34 | |||
35 | -- Get instance version |
||
36 | function stubobj:NeedsUpgraded(vmajor, vminor) |
||
37 | local versionData = self.versions[vmajor] |
||
38 | if not versionData or versionData.minor < vminor then return true end |
||
39 | end |
||
40 | |||
41 | |||
42 | -- Get instance version |
||
43 | function stubobj:GetInstance(version) |
||
44 | if not version then version = self.lastVersion end |
||
45 | local versionData = self.versions[version] |
||
46 | if not versionData then print(string.format("<%s> Cannot find library version: %s", self.libName, version or "")) return end |
||
47 | return versionData.instance |
||
48 | end |
||
49 | |||
50 | |||
51 | -- Register new instance |
||
52 | function stubobj:Register(newInstance) |
||
53 | local version,minor = newInstance:GetLibraryVersion() |
||
54 | self.lastVersion = version |
||
55 | local versionData = self.versions[version] |
||
56 | if not versionData then |
||
57 | -- This one is new! |
||
58 | versionData = { |
||
59 | instance = newInstance, |
||
60 | minor = minor, |
||
61 | old = {}, |
||
62 | } |
||
63 | self.versions[version] = versionData |
||
64 | newInstance:LibActivate(self) |
||
65 | return newInstance |
||
66 | end |
||
67 | -- This is an update |
||
68 | local oldInstance = versionData.instance |
||
69 | local oldList = versionData.old |
||
70 | versionData.instance = newInstance |
||
71 | versionData.minor = minor |
||
72 | local skipCopy = newInstance:LibActivate(self, oldInstance, oldList) |
||
73 | table.insert(oldList, oldInstance) |
||
74 | if not skipCopy then |
||
75 | for i, old in ipairs(oldList) do self:ReplaceInstance(old, newInstance) end |
||
76 | end |
||
77 | return newInstance |
||
78 | end |
||
79 | end |
||
80 | |||
81 | |||
82 | if not libobj then |
||
83 | libobj = stubobj:NewStub("PeriodicTableEmbed") |
||
84 | PeriodicTableEmbed = libobj |
||
85 | end |
||
86 | |||
87 | local lib = {} |
||
88 | |||
89 | |||
90 | -- Return the library's current version |
||
91 | function lib:GetLibraryVersion() |
||
92 | return vmajor, vminor |
||
93 | end |
||
94 | |||
95 | |||
96 | -- Activate a new instance of this library |
||
97 | function lib:LibActivate(stub, oldLib, oldList) |
||
98 | local maj, min = self:GetLibraryVersion() |
||
99 | |||
100 | if oldLib then |
||
101 | local omaj, omin = oldLib:GetLibraryVersion() |
||
102 | self.compost = oldLib.compost or CompostLib and CompostLib:GetInstance("compost-1") |
||
103 | self.vars, self.k, self.loadstats = oldLib.vars, oldLib.k, oldLib.loadstats |
||
104 | else |
||
105 | self.vars = {numcustoms = 0} |
||
106 | self.k, self.loadstats = {}, {} |
||
107 | self.compost = CompostLib and CompostLib:GetInstance("compost-1") |
||
108 | end |
||
109 | -- nil return makes stub do object copy |
||
110 | end |
||
111 | |||
112 | |||
113 | ----------------------------------------------------------------- |
||
114 | -- *********************************************************** -- |
||
115 | -- ** Everything in this section is internal code ** -- |
||
116 | -- ** please see the API section for external use ** -- |
||
117 | -- *********************************************************** -- |
||
118 | ----------------------------------------------------------------- |
||
119 | |||
120 | |||
121 | function lib:Print(a1,a2,a3,a4,a5) |
||
122 | if not a1 then return end |
||
123 | ChatFrame1:AddMessage("|cffffff78Periodic Table: |r"..string.format(a1,a2,a3,a4,a5)) |
||
124 | end |
||
125 | |||
126 | |||
127 | -- Called internally, you probably shouldn't be calling it directly, but hey do what you want :P |
||
128 | function lib:CacheSet(set) |
||
129 | if not set then return end |
||
130 | |||
131 | local rset = self:GetSet(set) |
||
132 | if not rset or type(rset) ~= "string" then return end |
||
133 | |||
134 | if not self.vars.cache then self.vars.cache = {} end |
||
135 | if not self.vars.cache[set] then |
||
136 | self.vars.cache[set] = {} |
||
137 | for word in gfind(rset, "%S+") do |
||
138 | local _, _, id, val = string.find(word, "(%d+):(%d+)") |
||
139 | id, val = tonumber(id) or tonumber(word), tonumber(val) or 0 |
||
140 | self.vars.cache[set][id] = val |
||
141 | end |
||
142 | end |
||
143 | |||
144 | return true |
||
145 | end |
||
146 | |||
147 | |||
148 | function lib:GetID(item) |
||
149 | if type(item) == "number" then return item |
||
150 | elseif type(item) == "string" then |
||
151 | local _, _, id = string.find(item, "item:(%d+):%d+:%d+:%d+") |
||
152 | if id then return tonumber(id) end |
||
153 | end |
||
154 | end |
||
155 | |||
156 | |||
157 | function lib:GetSet(set) |
||
158 | if not set then return end |
||
159 | for i,vals in pairs(self.k) do if vals[set] then return vals[set] end end |
||
160 | end |
||
161 | |||
162 | |||
163 | function lib:GetSetModule(set) |
||
164 | if not set then return end |
||
165 | for i,vals in pairs(self.k) do if vals[set] then return i end end |
||
166 | end |
||
167 | |||
168 | |||
169 | function lib:GetSetString(set) |
||
170 | if type(set) == "string" then |
||
171 | return |
||
172 | elseif type(set) == "table" then |
||
173 | local retval |
||
174 | for i,val in pairs(set) do |
||
175 | if type(i) == "number" then |
||
176 | local valstr = (val > 0) and string.format("%s:%s", i, val) or tostring(i) |
||
177 | retval = retval and string.format("%s %s", retval, valstr) or valstr |
||
178 | end |
||
179 | end |
||
180 | |||
181 | return retval |
||
182 | end |
||
183 | end |
||
184 | |||
185 | |||
186 | function lib:CreateTrashTable(set, bosses) |
||
187 | local retval, t = {}, self:GetSetTable(set) |
||
188 | if not t then return end |
||
189 | for i,v in pairs(t) do if not self:ItemInSet(i, bosses) then retval[i] = v end end |
||
190 | return self:GetSetString(retval) |
||
191 | end |
||
192 | |||
193 | |||
194 | function lib:FindWorldDrops() |
||
195 | local t, retval = {}, {} |
||
196 | for _,set in self.k["Instance Loot"].instancezones do t = self:MergeSetToTable(t, set) end |
||
197 | for _,set in self.k["Raid Loot"].raidzones do t = self:MergeSetToTable(t, set) end |
||
198 | for item,val in t do if val > 1 then retval[item] = val end end |
||
199 | return self:GetSetString(retval) |
||
200 | end |
||
201 | |||
202 | |||
203 | function lib:MergeSetToTable(table, set) |
||
204 | local t = self:GetSetTable(set) |
||
205 | if t then |
||
206 | for item,val in t do |
||
207 | if table[item] then table[item] = table[item] + 1 |
||
208 | else table[item] = 1 end |
||
209 | end |
||
210 | end |
||
211 | return table |
||
212 | end |
||
213 | |||
214 | |||
215 | function lib:RemoveAllWorldDrops() |
||
216 | local retval = {instancezones = {}, raidzones = {}, instancebosses = {}, raidbosses = {}} |
||
217 | for _,set in self.k["Instance Loot"].instancezones do retval.instancezones[set] = self:RemoveWorldDrops(set) end |
||
218 | for _,set in self.k["Raid Loot"].raidzones do retval.raidzones[set] = self:RemoveWorldDrops(set) end |
||
219 | for _,set in self.k["Instance Loot"].instancebosses do retval.instancebosses[set] = self:RemoveWorldDrops(set) end |
||
220 | for _,set in self.k["Raid Loot"].raidbosses do retval.raidbosses[set] = self:RemoveWorldDrops(set) end |
||
221 | return retval |
||
222 | end |
||
223 | |||
224 | |||
225 | function lib:RemoveWorldDrops(set) |
||
226 | local t = self:GetSetTable(set) |
||
227 | if t then |
||
228 | local retval = "" |
||
229 | for item,val in t do |
||
230 | if not self:ItemInSet(item, {"worlddrops", "bossdrops", "NOTworlddrops"}) then |
||
231 | local v = item..(val > 0 and (":"..val) or "") |
||
232 | if retval == "" then retval = v else retval = retval.." "..v end |
||
233 | end |
||
234 | end |
||
235 | |||
236 | return retval |
||
237 | end |
||
238 | end |
||
239 | |||
240 | |||
241 | ----------------------------- |
||
242 | -- Module Loadup -- |
||
243 | ----------------------------- |
||
244 | |||
245 | function lib:AddModule(name, table, memory) |
||
246 | if not name or not table or not memory then return end |
||
247 | if self.k[name] and self.compost then self.compost:Reclaim(self.k[name]) end |
||
248 | self.k[name] = table |
||
249 | self.loadstats[name] = self.loadstats[name] or 0 + memory |
||
250 | end |
||
251 | |||
252 | |||
253 | --------------------------------- |
||
254 | -- *************************** -- |
||
255 | -- ** API Section ** -- |
||
256 | -- *************************** -- |
||
257 | --------------------------------- |
||
258 | |||
259 | |||
260 | |||
261 | -- item: ItemID (a number) or ItemLink (a string) |
||
262 | -- set: set to check (a string) or sets to check (a table of strings) |
||
263 | -- returns: value (a number) ~~~ 0 indicates no value defined |
||
264 | -- set (a string) ~~~ the set that the item was found in |
||
265 | -- *** it is up to you to make sure all sets passed share a common value, the first matching value is returned! |
||
266 | function lib:ItemInSet(item, set) |
||
267 | local item = self:GetID(item) |
||
268 | if not item then return end |
||
269 | |||
270 | if type(set) == "string" then |
||
271 | local rset = self:GetSet(set) |
||
272 | if rset and type(rset) == "string" then |
||
273 | local t = self:GetSetTable(set) |
||
274 | if t and t[item] then return t[item], set end |
||
275 | elseif type(rset) == "table" then |
||
276 | for _,s in rset do |
||
277 | local retval = self:ItemInSet(item, s) |
||
278 | if retval then return retval, s end |
||
279 | end |
||
280 | end |
||
281 | elseif type(set) == "table" then |
||
282 | for i,s in pairs(set) do |
||
283 | local retval = self:ItemInSet(item, s) |
||
284 | if retval then return retval, s end |
||
285 | end |
||
286 | end |
||
287 | end |
||
288 | |||
289 | |||
290 | -- item: ItemID (a number) or ItemLink (a string) |
||
291 | -- sets: sets to check (a table of strings) |
||
292 | -- returns: a table of the sets found, or nil if not found |
||
293 | -- ** key difference between this and ItemInSet, this wil check for every match |
||
294 | -- ** ItemInSet will just return the first one found. Also this func does not return the numeric values |
||
295 | function lib:ItemInSets(item, sets) |
||
296 | local item = self:GetID(item) |
||
297 | if not item then return end |
||
298 | |||
299 | if type(sets) == "string" then |
||
300 | local rset = self:GetSet(sets) |
||
301 | if type(rset) == "string" then |
||
302 | local inset = self:ItemInSet(item, sets) |
||
303 | if inset then return self.compost and self.compost:Acquire(sets) or {sets} end |
||
304 | elseif type(rset) == "table" then |
||
305 | return self:ItemInSets(item, rset) |
||
306 | end |
||
307 | elseif type(sets) == "table" then |
||
308 | local founds |
||
309 | |||
310 | for i,s in pairs(sets) do |
||
311 | if self:ItemInSet(item, s) then |
||
312 | if not founds then founds = self.compost and self.compost:Acquire() or {} end |
||
313 | table.insert(founds, s) |
||
314 | end |
||
315 | end |
||
316 | |||
317 | return founds |
||
318 | end |
||
319 | end |
||
320 | |||
321 | |||
322 | -- Iterator for scanning bags for set matches |
||
323 | -- Returns back bag, slot, value |
||
324 | function lib:BagIter(set) |
||
325 | if not set then return end |
||
326 | |||
327 | local bag, slot = 0, 1 |
||
328 | |||
329 | return function() |
||
330 | if slot > GetContainerNumSlots(bag) then bag, slot = bag + 1, 1 end |
||
331 | if bag > 4 then return end |
||
332 | |||
333 | for b=bag,4 do |
||
334 | for s=slot,GetContainerNumSlots(b) do |
||
335 | slot = s + 1 |
||
336 | |||
337 | local link = GetContainerItemLink(b,s) |
||
338 | local val = link and self:ItemInSet(link, set) |
||
339 | if val then return b, s, val end |
||
340 | end |
||
341 | |||
342 | bag, slot = b+1, 1 |
||
343 | end |
||
344 | end |
||
345 | end |
||
346 | |||
347 | |||
348 | -- Returns the bag/slot of the "best" item in the set, |
||
349 | -- if there are two "matching" items the first one in your bags is returned |
||
350 | -- By default this will just compare PT values, however, if comparefunc is passed this will be used as the evaluation function |
||
351 | -- Args: |
||
352 | -- set - the set you wish to match |
||
353 | -- comparefunc(optional) - a function to test two items against each other |
||
354 | -- this function must take 6 args (item1_bag, item1_slot, item1_value, item2_bag, item2_slot, item2_value) |
||
355 | -- and should return true if item1 is "better" than item2 |
||
356 | -- validatefunc (optional) - a function to check an item with, if it returns false/nil the item isn't used |
||
357 | -- Ideal for checking that an item is "good enough" or not too high of value |
||
358 | -- Returns: Bag, Slot and PT Value of best match, if a match is found |
||
359 | local defaultcomparefunc = function(abag, aslot, aval, bbag, bslot, bval) return aval > bval end |
||
360 | local defaultvalidatefunc = function(bag, slot, val) return true end |
||
361 | function lib:GetBest(set, comparefunc, validatefunc) |
||
362 | comparefunc = comparefunc or defaultcomparefunc |
||
363 | validatefunc = validatefunc or defaultvalidatefunc |
||
364 | local ibag, islot, ival |
||
365 | |||
366 | for bag,slot,val in self:BagIter(set) do |
||
367 | if validatefunc(bag,slot,val) and (not ival or comparefunc(bag, slot, val, ibag, islot, ival)) then |
||
368 | ibag, islot, ival = bag, slot, val |
||
369 | end |
||
370 | end |
||
371 | return ibag, islot, ival |
||
372 | end |
||
373 | |||
374 | |||
375 | -- Returns a reference to the set specified's expanded table |
||
376 | -- this is the table in the cache so don't go erasing it or anything! |
||
377 | -- **** This only works for atomic sets, not multisets **** |
||
378 | function lib:GetSetTable(set) |
||
379 | if self:CacheSet(set) then return self.vars.cache[set] end |
||
380 | end |
||
381 | |||
382 | |||
383 | -- Register a custom set |
||
384 | -- Args: |
||
385 | -- setcode (a string) - must be space-delimited itemid's of the format below |
||
386 | -- name (an optional string) - the name of the set |
||
387 | -- setcode format: |
||
388 | -- int or int:int where the first or only int is itemid, the second is a relative value |
||
389 | -- the relative value can be anything you wish, it is intended to aid in sorting |
||
390 | -- if the item's level isn't enough |
||
391 | -- Returns a string, the index/setname of your set, or nil if that setname already exists |
||
392 | function lib:RegisterCustomSet(setcode, name) |
||
393 | local setname = name or "customset"..self.vars.numcustoms |
||
394 | if not setcode then return end |
||
395 | if self:GetSetModule(setname) then return end |
||
396 | |||
397 | self.k.customsets = self.k.customsets or {} |
||
398 | self.k.customsets[setname] = setcode |
||
399 | if not name then self.vars.numcustoms = self.vars.numcustoms + 1 end |
||
400 | return setname |
||
401 | end |
||
402 | |||
403 | |||
404 | -- Loads up every module, dumps the memory used and time taken by each to chat |
||
405 | function lib:Benchmark() |
||
406 | self.vars.cache = {} |
||
407 | collectgarbage() |
||
408 | |||
409 | local loadsize, tt, tmem = 0, GetTime(), gcinfo() |
||
410 | for i,vals in self.k do |
||
411 | local t, mem = GetTime(), gcinfo() |
||
412 | for j,v in vals do |
||
413 | if (type(v) == "string") then self:CacheSet(j) end |
||
414 | end |
||
415 | |||
416 | local compsize = self.loadstats[i] or 0 |
||
417 | loadsize = loadsize + compsize |
||
418 | t, mem = (GetTime() - t), (gcinfo() - mem) |
||
419 | self:Print("|cff80ff80%d ms|r %s set |cffff8000(%d --> %d KiB)", t*1000, i, compsize, mem) |
||
420 | end |
||
421 | tt, tmem = (GetTime() - tt), (gcinfo() - tmem) |
||
422 | self:Print("|cff80ff80%d ms|r All sets |cffff8000(%d --> %d KiB)", tt*1000, loadsize, tmem) |
||
423 | end |
||
424 | |||
425 | |||
426 | -------------------------------- |
||
427 | -- Load this bitch! -- |
||
428 | -------------------------------- |
||
429 | libobj:Register(lib) |