forked from Joschasa/Elitist-Group
-
Notifications
You must be signed in to change notification settings - Fork 0
/
cache.lua
executable file
·254 lines (215 loc) · 8.88 KB
/
cache.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
local ElitistGroup = select(2, ...)
local Cache = ElitistGroup:NewModule("Cache", "AceEvent-3.0")
local CACHE_TIMEOUT = 30 * 60
local statCache, itemMetaTable, gemMetaTable, emptyGemMetaTable, enchantMetaTable = {}
local lastCache = GetTime() + CACHE_TIMEOUT
local ItemData = ElitistGroup.Items
function Cache:OnInitialize()
self:RegisterEvent("PLAYER_ENTERING_WORLD")
end
-- Item caching alone will result in 100 entries in ~7 summaries, auto inspecting a party makes this about once every two instances
-- once we do it for raids, it'll be even more so at a certain point we want to wipe our caches and let the garbage collector do it's job
function Cache:PLAYER_ENTERING_WORLD()
if( lastCache > GetTime() ) then return end
lastCache = GetTime() + CACHE_TIMEOUT
statCache = {}
ElitistGroup.ENCHANT_TALENTTYPE = setmetatable({}, enchantMetaTable)
ElitistGroup.GEM_TALENTTYPE = setmetatable({}, gemMetaTable)
ElitistGroup.EMPTY_GEM_SLOTS = setmetatable({}, emptyGemMetaTable)
ElitistGroup.ITEM_TALENTTYPE = setmetatable({}, itemMetaTable)
end
local tooltip = CreateFrame("GameTooltip", "ElitistGroupScanTooltip", UIParent, "GameTooltipTemplate")
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
local function parseText(text)
text = string.gsub(text, "%%d", "%%d+")
text = string.gsub(text, "%%s", ".+")
return string.lower(text)
end
local ITEM_SPELL_TRIGGER_ONEQUIP = parseText(ITEM_SPELL_TRIGGER_ONEQUIP)
local ITEM_SPELL_TRIGGER_ONPROC = parseText(ITEM_SPELL_TRIGGER_ONPROC)
local ITEM_SPELL_TRIGGER_ONUSE = parseText(ITEM_SPELL_TRIGGER_ONUSE)
local ITEM_ONEQUIP = "^" .. parseText(ITEM_SPELL_TRIGGER_ONEQUIP)
local RESILIENCE_MATCH = parseText(ITEM_MOD_RESILIENCE_RATING_SHORT)
-- Yay metatable caching, can only get gem totals via tooltip scanning, GetItemStats won't return a prismatic socketed item
emptyGemMetaTable = {
__index = function(tbl, link)
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
tooltip:SetHyperlink(link)
local total = 0
for i=1, MAX_NUM_SOCKETS do
local texture = _G["ElitistGroupScanTooltipTexture" .. i]
if( texture and texture:IsVisible() ) then
total = total + 1
end
end
rawset(tbl, link, total)
return total
end,
}
-- Find the item type based on stats used
local function matchStats(overrideType)
local totalStats = 0
for key in pairs(statCache) do totalStats = totalStats + 1 end
for i=1, #(ItemData.statTalents) do
local data = ItemData.statTalents[i]
-- Only use this if other (required) stats are present
if( not data.require or ( statCache[data.require] or ( data.require2 and statCache[data.require2] ) ) ) then
-- Only use this if it's the exclusive stat, for matching things like pure MP5 gems, not hybrids
if( not data.exclusive or totalStats == 1 ) then
-- Skip this if the stat is present
if( not data.skipOn or ( not statCache[data.skipOn] and ( not data.skipOn2 or not statCache[data.skipOn2] ) ) ) then
local statString = data.default or data[overrideType]
if( data[overrideType] and data.default ) then statString = statString .. data[overrideType] end
if( statString ) then
for statKey in string.gmatch(statString, "(.-)@") do
if( statCache[ItemData.statMap[statKey]] ) then
return data.type
end
end
end
end
end
end
end
return "unknown"
end
gemMetaTable = {
__index = function(tbl, link)
local itemID = link and tonumber(string.match(link, "item:(%d+)"))
if( itemID and ItemData.itemOverrides[itemID] ) then
rawset(tbl, link, ItemData.itemOverrides[itemID])
return ItemData.itemOverrides[itemID]
elseif( not itemID or not GetItemInfo(itemID) ) then
rawset(tbl, link, "unknown")
return "unknown"
end
local foundData
table.wipe(statCache)
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
tooltip:SetHyperlink(link)
-- Skip first Line (Itemname), since "Shadowspirit" contains "Spirit" and will be flagged as heal every time
for i=2, tooltip:NumLines() do
local text = string.lower(_G["ElitistGroupScanTooltipTextLeft" .. i]:GetText())
for i=1, #(ItemData.orderedStatMap) do
local key = ItemData.orderedStatMap[i]
if( string.match(text, ItemData.safeStatMatch[key]) ) then
foundData = true
statCache[key] = true
end
end
if( foundData ) then break end
end
if( not foundData ) then
rawset(tbl, link, "unknown")
return "unknown"
end
rawset(tbl, link, matchStats("gems"))
return rawget(tbl, link)
end,
}
-- Note: Regular enchants show up above sockets and below the items base stats. Engineering enchants are at the very bottom :|
-- Because of how engineering enchants are done, we cannot scan for them. They have to be manually overridden cause Blizzard are jerks.
enchantMetaTable = {
__index = function(tbl, link)
local enchantID = tonumber(link)
local type = not enchantID and "unknown" or enchantID == 0 and "none" or ItemData.enchantOverrides[enchantID]
if( type ) then
rawset(tbl, link, type)
return type
end
-- The reason for using a hardcoded item is it gives us a more consistent set of data to work off of
-- this means we can rely on the location of an enchant because we know 100% where they will be located.
-- I would actually rather use something like Worn Dagger, or another piece of gear that has zero green text on it except gems
-- but I'm worried there might be issues if the item is not immediately available due to not being cached, whereas Hearthstone is always available.
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
tooltip:SetHyperlink(string.format("item:6948:%d", enchantID))
local enchantText
for i=1, tooltip:NumLines() do
local text = string.lower(_G["ElitistGroupScanTooltipTextLeft" .. i]:GetText())
local r, g, b = _G["ElitistGroupScanTooltipTextLeft" .. i]:GetTextColor()
-- If we don't find the enchant up top, but we know one exists then it's an engineering enchant, which means the next line will have the enchant in it
if( string.match(text, ITEM_SPELL_TRIGGER_ONUSE) ) then
if( tooltip:NumLines() > i ) then
enchantText = string.lower(_G["ElitistGroupScanTooltipTextLeft" .. i + 1]:GetText())
end
break
-- First green text we find that isn't the Use: is the enchant
elseif( ( r >= 0.97 and g < 0.15 and b < 0.15 ) or ( r == 0 and g >= 0.97 and b == 0 ) ) then
enchantText = text
break
end
end
if( not enchantText ) then
rawset(tbl, link, "unknown")
return "unknown"
end
-- Parse out the stats
local foundData
table.wipe(statCache)
for i=1, #(ItemData.orderedStatMap) do
local key = ItemData.orderedStatMap[i]
if( string.match(enchantText, ItemData.safeStatMatch[key]) ) then
foundData = true
statCache[key] = true
end
end
if( not foundData ) then
rawset(tbl, link, "unknown")
return "unknown"
end
rawset(tbl, link, matchStats("enchants"))
return rawget(tbl, link)
end,
}
itemMetaTable = {
__index = function(tbl, link)
link = ElitistGroup:GetBaseItemLink(link)
local itemID = tonumber(string.match(link, "item:(%d+)"))
if( itemID and ItemData.itemOverrides[itemID] ) then
rawset(tbl, link, ItemData.itemOverrides[itemID])
return ItemData.itemOverrides[itemID]
end
local inventoryType = select(9, GetItemInfo(link))
local equipType = inventoryType and ItemData.equipToType[inventoryType]
if( not equipType ) then
rawset(tbl, link, "unknown")
return "unknown"
end
table.wipe(statCache)
GetItemStats(link, statCache)
-- Failed to identify the item, check everything
if( inventoryType == "INVTYPE_TRINKET" ) then
-- Basically. 99% of trinkets say the stat they increase, regardless of whether it's "chance to increase spell power by X every 20 seconds"
-- so will find that part of the text and scan it to try and identify what kind of item it is, we only do this if we failed to find it through the stats
tooltip:SetOwner(UIParent, "ANCHOR_NONE")
tooltip:SetHyperlink(link)
local statText
for i=tooltip:NumLines(), 1, -1 do
local row = _G["ElitistGroupScanTooltipTextLeft" .. i]
local r, g, b = row:GetTextColor()
if( r == 0 and g > 0.97 and b == 0 ) then
local text = string.lower(row:GetText())
if( string.match(text, ITEM_SPELL_TRIGGER_ONEQUIP) or string.match(text, ITEM_SPELL_TRIGGER_ONPROC) or string.match(text, ITEM_SPELL_TRIGGER_ONUSE) ) then
statText = text
break
end
end
end
-- Yay we found the enchant proc
if( statText ) then
for i=1, #(ItemData.orderedStatMap) do
local key = ItemData.orderedStatMap[i]
if( string.match(statText, ItemData.safeStatMatch[key]) ) then
statCache[key] = true
end
end
end
end
rawset(tbl, link, matchStats(equipType))
return rawget(tbl, link)
end,
}
ElitistGroup.ENCHANT_TALENTTYPE = setmetatable({}, enchantMetaTable)
ElitistGroup.GEM_TALENTTYPE = setmetatable({}, gemMetaTable)
ElitistGroup.EMPTY_GEM_SLOTS = setmetatable({}, emptyGemMetaTable)
ElitistGroup.ITEM_TALENTTYPE = setmetatable({}, itemMetaTable)