comparison Export.lua @ 124:e31b02b24488

Updated for 8.0 pre-patch and BfA.
author yellowfive
date Tue, 17 Jul 2018 09:57:39 -0700
parents 5cb881417bbf
children 65c285394049
comparison
equal deleted inserted replaced
123:7a6364917f86 124:e31b02b24488
5 local _lastExport = nil 5 local _lastExport = nil
6 local _txt = nil 6 local _txt = nil
7 7
8 local function createLabel(container, text, width) 8 local function createLabel(container, text, width)
9 local lbl = AceGUI:Create("AmrUiLabel") 9 local lbl = AceGUI:Create("AmrUiLabel")
10 container:AddChild(lbl)
10 lbl:SetWidth(width or 800) 11 lbl:SetWidth(width or 800)
11 lbl:SetText(text) 12 lbl:SetText(text)
12 lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.Text)) 13 lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.Text))
13 container:AddChild(lbl)
14 return lbl 14 return lbl
15 end 15 end
16 16
17 local function onSplashClose() 17 local function onSplashClose()
18 Amr:HideCover() 18 Amr:HideCover()
48 48
49 lbl2 = createLabel(panel, L.ExportSplash2, 650) 49 lbl2 = createLabel(panel, L.ExportSplash2, 650)
50 lbl2:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.Text)) 50 lbl2:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.Text))
51 lbl2:SetPoint("TOPLEFT", lbl.frame, "BOTTOMLEFT", 0, -15) 51 lbl2:SetPoint("TOPLEFT", lbl.frame, "BOTTOMLEFT", 0, -15)
52 52
53 lbl = createLabel(panel, L.ExportSplash3, 650)
54 lbl:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.Text))
55 lbl:SetPoint("TOPLEFT", lbl2.frame, "BOTTOMLEFT", 0, -15)
56
57 lbl2 = createLabel(panel, L.ExportSplash4, 650)
58 lbl2:SetFont(Amr.CreateFont("Regular", 14, Amr.Colors.Text))
59 lbl2:SetPoint("TOPLEFT", lbl.frame, "BOTTOMLEFT", 0, -15)
60
61 local btn = AceGUI:Create("AmrUiButton") 53 local btn = AceGUI:Create("AmrUiButton")
62 btn:SetText(L.ExportSplashClose) 54 btn:SetText(L.ExportSplashClose)
63 btn:SetBackgroundColor(Amr.Colors.Green) 55 btn:SetBackgroundColor(Amr.Colors.Green)
64 btn:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White)) 56 btn:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White))
65 btn:SetWidth(120) 57 btn:SetWidth(120)
66 btn:SetHeight(28) 58 btn:SetHeight(28)
67 btn:SetPoint("BOTTOM", panel.content, "BOTTOM", 0, 20)
68 btn:SetCallback("OnClick", onSplashClose) 59 btn:SetCallback("OnClick", onSplashClose)
69 panel:AddChild(btn) 60 panel:AddChild(btn)
61 btn:SetPoint("BOTTOM", panel.content, "BOTTOM", 0, 20)
70 end 62 end
71 63
72 -- renders the main UI for the Export tab 64 -- renders the main UI for the Export tab
73 function Amr:RenderTabExport(container) 65 function Amr:RenderTabExport(container)
74 66
86 lbl2:SetPoint("TOPLEFT", lbl.frame, "BOTTOMLEFT", 0, -10) 78 lbl2:SetPoint("TOPLEFT", lbl.frame, "BOTTOMLEFT", 0, -10)
87 79
88 _txt = AceGUI:Create("AmrUiTextarea") 80 _txt = AceGUI:Create("AmrUiTextarea")
89 _txt:SetWidth(800) 81 _txt:SetWidth(800)
90 _txt:SetHeight(300) 82 _txt:SetHeight(300)
91 _txt:SetPoint("TOP", lbl2.frame, "BOTTOM", 0, -20)
92 _txt:SetFont(Amr.CreateFont("Regular", 12, Amr.Colors.Text)) 83 _txt:SetFont(Amr.CreateFont("Regular", 12, Amr.Colors.Text))
93 _txt:SetCallback("OnTextChanged", onTextChanged) 84 _txt:SetCallback("OnTextChanged", onTextChanged)
94 container:AddChild(_txt) 85 container:AddChild(_txt)
86 _txt:SetPoint("TOP", lbl2.frame, "BOTTOM", 0, -20)
95 87
96 local data = self:ExportCharacter() 88 local data = self:ExportCharacter()
97 local txt = Amr.Serializer:SerializePlayerData(data, true) 89 local txt = Amr.Serializer:SerializePlayerData(data, true)
98 _txt:SetText(txt) 90 _txt:SetText(txt)
99 _txt:SetFocus(true) 91 _txt:SetFocus(true)
117 109
118 110
119 -- use some local variables to deal with the fact that a user can close the bank before a scan completes 111 -- use some local variables to deal with the fact that a user can close the bank before a scan completes
120 local _lastBankBagId = nil 112 local _lastBankBagId = nil
121 local _lastBankSlotId = nil 113 local _lastBankSlotId = nil
114 local _bankOpen = false
122 115
123 local function scanBag(bagId, isBank, bagTable, bagItemsWithCount) 116 local function scanBag(bagId, isBank, bagTable, bagItemsWithCount)
124 local numSlots = GetContainerNumSlots(bagId) 117 local numSlots = GetContainerNumSlots(bagId)
118 local loc = ItemLocation.CreateEmpty()
125 for slotId = 1, numSlots do 119 for slotId = 1, numSlots do
126 local _, itemCount, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId) 120 local _, itemCount, _, _, _, _, itemLink = GetContainerItemInfo(bagId, slotId)
127 if itemLink ~= nil then 121 if itemLink ~= nil then
128 local itemData = Amr.Serializer.ParseItemLink(itemLink) 122 local itemData = Amr.Serializer.ParseItemLink(itemLink)
129 if itemData ~= nil then 123 if itemData ~= nil then
130 124
131 -- only add equippable items to bag data 125 -- see if this is an azerite item and read azerite power ids
132 --if IsEquippableItem(itemLink) or Amr.SetTokenIds[itemData.id] then 126 loc:SetBagAndSlot(bagId, slotId)
133 if isBank then 127 if C_AzeriteEmpoweredItem.IsAzeriteEmpoweredItem(loc) then
134 _lastBankBagId = bagId 128 local powers = Amr.ReadAzeritePowers(loc)
135 _lastBankSlotId = slotId 129 if powers then
136 end 130 itemData.azerite = powers
131 end
132 end
133
134 if isBank then
135 _lastBankBagId = bagId
136 _lastBankSlotId = slotId
137 end
137 138
138 table.insert(bagTable, itemLink) 139 table.insert(bagTable, itemData)
139 --end
140 140
141 -- all items and counts, used for e.g. shopping list and reagents, etc. 141 -- all items and counts, used for e.g. shopping list and reagents, etc.
142 if bagItemsWithCount then 142 if bagItemsWithCount then
143 if bagItemsWithCount[itemData.id] then 143 if bagItemsWithCount[itemData.id] then
144 bagItemsWithCount[itemData.id] = bagItemsWithCount[itemData.id] + itemCount 144 bagItemsWithCount[itemData.id] = bagItemsWithCount[itemData.id] + itemCount
149 end 149 end
150 end 150 end
151 end 151 end
152 end 152 end
153 153
154 -- get the player's current gear and save it, also returns the data from GetPlayerData for efficiency 154 -- cache the currently equipped gear for this spec
155 local function getEquipped() 155 local function cacheEquipped()
156 local data = Amr.Serializer:GetPlayerData() 156 local data = Amr.Serializer:GetEquipped()
157 local spec = GetSpecialization() 157
158 158 local spec = GetSpecialization()
159 Amr.db.char.Equipped[spec] = data.Equipped[spec] 159 Amr.db.char.Equipped[spec] = data.Equipped[spec]
160
161 return data
162 end 160 end
163 161
164 local function scanBags() 162 local function scanBags()
165 163
166 local bagItems = {} 164 local bagItems = {}
182 local itemsAndCounts = {} 180 local itemsAndCounts = {}
183 181
184 scanBag(BANK_CONTAINER, true, bankItems, itemsAndCounts) 182 scanBag(BANK_CONTAINER, true, bankItems, itemsAndCounts)
185 scanBag(REAGENTBANK_CONTAINER, true, bankItems, itemsAndCounts) 183 scanBag(REAGENTBANK_CONTAINER, true, bankItems, itemsAndCounts)
186 for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do 184 for bagId = NUM_BAG_SLOTS + 1, NUM_BAG_SLOTS + NUM_BANKBAGSLOTS do
187 scanBag(bagId, true, bankItems, itemsAndCounts) 185 local bagItems = {}
186 local bagItemsAndCounts = {}
187 scanBag(bagId, true, bagItems, bagItemsAndCounts)
188
189 bankItems[bagId] = bagItems
190 itemsAndCounts[bagId] = bagItemsAndCounts
188 end 191 end
189 192
190 -- see if the scan completed before the window closed, otherwise we don't overwrite with partial data 193 -- see if the scan completed before the window closed, otherwise we don't overwrite with partial data
191 if _lastBankBagId ~= nil then 194 if _bankOpen and _lastBankBagId then
192 local itemLink = GetContainerItemLink(_lastBankBagId, _lastBankSlotId) 195 local itemLink = GetContainerItemLink(_lastBankBagId, _lastBankSlotId)
193 if itemLink ~= nil then --still open 196 if itemLink then --still open
194 Amr.db.char.BankItems = bankItems 197 Amr.db.char.BankItems = bankItems
195 Amr.db.char.BankItemsAndCounts = itemsAndCounts 198 Amr.db.char.BankItemsAndCounts = itemsAndCounts
196 end 199 end
197 end 200 end
198 201 end
199 end 202
200 203 local function onBankOpened()
204 _bankOpen = true
205 scanBank()
206 end
207
208 local function onBankClosed()
209 _bankOpen = false
210 end
211
212 -- if a bank bag is updated while the bank is open, re-scan that bag
213 local function onBankUpdated(bagID)
214 if _bankOpen and (bagID == BANK_CONTAINER or bagID == REAGENTBANK_CONTAINER or (bagID >= NUM_BAG_SLOTS + 1 and bagID <= NUM_BAG_SLOTS + NUM_BANKBAGSLOTS)) then
215 local bagItems = {}
216 local bagItemsAndCounts = {}
217 scanBag(bagID, true, bagItems, bagItemsAndCounts)
218
219 -- see if the scan completed before the window closed, otherwise we don't overwrite with partial data
220 if _bankOpen and _lastBankBagId == bagID then
221 local itemLink = GetContainerItemLink(_lastBankBagId, _lastBankSlotId)
222 if itemLink then
223 Amr.db.char.BankItems[bagID] = bagItems
224 Amr.db.char.BankItemsAndCounts[bagID] = bagItemsAndCounts
225 end
226 end
227 end
228 end
229
230 --[[
201 -- scan the player's void storage and save the contents, must be at void storage 231 -- scan the player's void storage and save the contents, must be at void storage
202 local function scanVoid() 232 local function scanVoid()
203 233
204 if IsVoidStorageReady() then 234 if IsVoidStorageReady() then
205 local voidItems = {} 235 local voidItems = {}
220 250
221 Amr.db.char.VoidItems = voidItems 251 Amr.db.char.VoidItems = voidItems
222 end 252 end
223 253
224 end 254 end
225 255 ]]
226 local function getRepStanding(factionId)
227 local name, description, standingId, _ = GetFactionInfoByID(factionId)
228 return standingId - 1; -- our rep enum correspond to what the armory returns, are 1 less than what the game returns
229 end
230
231 local function getReputations()
232 local reps = {}
233
234 local repList = {1375,1376,1270,1269,1341,1337,1387,1388,1435}
235 for i, repId in pairs(repList) do
236 local standing = getRepStanding(repId)
237 if standing >= 0 then
238 reps[repId] = standing
239 end
240 end
241
242 return reps
243 end
244 256
245 local function scanTalents() 257 local function scanTalents()
246 local specPos = GetSpecialization() 258 local specPos = GetSpecialization()
247 if not specPos or specPos < 1 or specPos > 4 then return end 259 if not specPos or specPos < 1 or specPos > 4 then return end
248 260
267 end 279 end
268 280
269 Amr.db.char.Talents[specPos] = str 281 Amr.db.char.Talents[specPos] = str
270 end 282 end
271 283
272 local function scanCrucible()
273 if not Amr.db or not Amr.db.char or not Amr.db.char.Artifacts or not C_ArtifactRelicForgeUI or not C_ArtifactRelicForgeUI.GetSocketedRelicTalents then return end
274
275 local equipped = {}
276 local preview = nil
277
278 for i = 1,4 do
279 local talents = nil
280 if i == 4 then
281 talents = C_ArtifactRelicForgeUI.GetPreviewRelicTalents()
282 --talents = nil
283 else
284 talents = C_ArtifactRelicForgeUI.GetSocketedRelicTalents(i)
285
286 --[[
287 -- test data
288 if i == 1 then
289 talents = {}
290 table.insert(talents, {
291 powerID = 1739,
292 isChosen = true
293 })
294 table.insert(talents, {
295 powerID = 1781,
296 isChosen = true
297 })
298 table.insert(talents, {
299 powerID = 1770,
300 isChosen = false
301 })
302 table.insert(talents, {
303 powerID = 791,
304 isChosen = false
305 })
306 table.insert(talents, {
307 powerID = 786,
308 isChosen = false
309 })
310 table.insert(talents, {
311 powerID = 1537,
312 isChosen = false
313 })
314 end
315 ]]
316 end
317
318 if talents then
319 local obj = {
320 Powers = {},
321 Active = {}
322 }
323
324 if i == 4 then
325 obj.ItemLink = C_ArtifactRelicForgeUI.GetPreviewRelicItemLink()
326 if not obj.ItemLink then
327 talents = nil
328 else
329 preview = obj
330 end
331 else
332 table.insert(equipped, obj)
333 end
334
335 if talents then
336 for k,v in ipairs(talents) do
337 table.insert(obj.Powers, v.powerID)
338 table.insert(obj.Active, v.isChosen)
339 end
340 end
341
342 elseif i ~= 4 then
343 table.insert(equipped, {})
344 end
345 end
346
347
348 local itemID = C_ArtifactUI.GetArtifactInfo()
349 local spec = Amr.ArtifactIdToSpecNumber[itemID]
350
351 if spec then
352
353 -- sometimes this event can fire when no crucible data is available, don't overwrite non-blank crucible data with blank crucible data
354 local badEquipped = false
355 if Amr.db.char.Artifacts[spec] then
356 local oldCrucible = Amr.db.char.Artifacts[spec].Crucible
357 if oldCrucible then
358 if #oldCrucible.Equipped > 0 and oldCrucible.Equipped[1] and not equipped[1] then
359 badEquipped = true
360 end
361 end
362 end
363
364 local dataz = Amr.db.char.Artifacts[spec]
365 if not dataz then
366 dataz = {}
367 Amr.db.char.Artifacts[spec] = dataz
368 end
369
370 if not dataz.Crucible then
371 dataz.Crucible = {
372 Equipped = {},
373 Previewed = {}
374 }
375 end
376
377 local crucible = dataz.Crucible
378
379 if not badEquipped then
380 crucible.Equipped = equipped
381 end
382
383 if preview then
384 local previewKey = {}
385 table.insert(previewKey, preview.ItemLink)
386 for i,v in ipairs(preview.Powers) do
387 table.insert(previewKey, v .. "=" .. tostring(preview.Active[i]))
388 end
389 previewKey = table.concat(previewKey, "_")
390
391 if not crucible.Previewed then
392 crucible.Previewed = {}
393 end
394 crucible.Previewed[previewKey] = preview
395 end
396 end
397 end
398
399 local function pruneCrucible()
400 if not Amr.db or not Amr.db.char or not Amr.db.char.Artifacts then return end
401
402 local spec = GetSpecialization()
403 local dataz = Amr.db.char.Artifacts[spec]
404 if not dataz or not dataz.Crucible then return end
405
406 local crucible = dataz.Crucible
407
408 -- this was old format, transform to new format
409 if crucible.Inventory then
410 if not crucible.Previewed then
411 crucible.Previewed = {}
412 end
413
414 for link,preview in pairs(crucible.Inventory) do
415 local previewKey = {}
416 table.insert(previewKey, preview.ItemLink)
417 for i,v in ipairs(preview.Powers) do
418 table.insert(previewKey, v .. "=" .. tostring(preview.Active[i]))
419 end
420 previewKey = table.concat(previewKey, "_")
421
422 crucible.Previewed[previewKey] = preview
423 end
424
425 crucible.Inventory = nil
426 end
427
428 -- get a hash of every owned, but not-equipped item
429 local ownedItems = {}
430 if Amr.db.char.BagItems then
431 for i,link in ipairs(Amr.db.char.BagItems) do
432 ownedItems[link] = true
433 end
434 end
435 if Amr.db.char.BankItems then
436 for i,link in ipairs(Amr.db.char.BankItems) do
437 ownedItems[link] = true
438 end
439 end
440 if Amr.db.char.VoidItems then
441 for i,link in ipairs(Amr.db.char.VoidItems) do
442 ownedItems[link] = true
443 end
444 end
445
446 -- prune out any previewed relics that the player no longer owns
447 if crucible.Previewed then
448 local toRemove = {}
449 for k,v in pairs(crucible.Previewed) do
450 if not ownedItems[v.ItemLink] then
451 table.insert(toRemove, k)
452 end
453 end
454 for i,v in ipairs(toRemove) do
455 crucible.Previewed[v] = nil
456 end
457 end
458
459 end
460
461 local function scanArtifact()
462 if not Amr.db or not Amr.db.char or not Amr.db.char.Artifacts then return end
463
464 local powers = C_ArtifactUI.GetPowers()
465 if not powers then return end
466
467 local powerRanks = {}
468 for k,v in pairs(powers) do
469 local powerInfo = C_ArtifactUI.GetPowerInfo(v)
470 if powerInfo.currentRank - powerInfo.bonusRanks > 0 then
471 powerRanks[v] = powerInfo.currentRank - powerInfo.bonusRanks
472 end
473 end
474
475 local relicInfo = {}
476 for i = 1,3 do
477 local _, _, _, link = C_ArtifactUI.GetRelicInfo(i);
478 table.insert(relicInfo, link or "")
479 end
480
481 -- make sure that the artifact UI didn't get closed while we were reading it, GetPowers seems to return nil unless it is open
482 powers = C_ArtifactUI.GetPowers()
483 if not powers then return end
484
485 -- use the artifact item ID to figure out which spec this is for, since you can open your artifact on any spec
486 local itemID = C_ArtifactUI.GetArtifactInfo()
487 local spec = Amr.ArtifactIdToSpecNumber[itemID]
488 --local spec = GetSpecialization()
489
490 if spec then
491
492 -- sometimes this event can fire when no relic data is available, don't overwrite non-blank relic data with blank relic data
493 if Amr.db.char.Artifacts[spec] then
494 local oldRelics = Amr.db.char.Artifacts[spec].Relics
495 if oldRelics then
496 for i = 1,3 do
497 if oldRelics[i] and oldRelics[i] ~= "" and (not relicInfo[i] or relicInfo[i] == "") then
498 relicInfo[i] = oldRelics[i]
499 end
500 end
501 end
502 end
503
504 local dataz = Amr.db.char.Artifacts[spec]
505 if not dataz then
506 dataz = {}
507 Amr.db.char.Artifacts[spec] = dataz
508 end
509
510 if not dataz.Crucible then
511 dataz.Crucible = {
512 Equipped = {},
513 Inventory = {}
514 }
515 end
516
517 dataz.Powers = powerRanks
518 dataz.Relics = relicInfo
519
520 end
521
522 --scanCrucible()
523 end
524
525 -- Returns a data object containing all information about the current player needed for an export: 284 -- Returns a data object containing all information about the current player needed for an export:
526 -- gear, spec, reputations, bag, bank, and void storage items. 285 -- gear, spec, reputations, bag, bank, and void storage items.
527 function Amr:ExportCharacter() 286 function Amr:ExportCharacter()
528 287
529 local data = getEquipped() 288 -- get all necessary player data
289 local data = Amr.Serializer:GetPlayerData()
290
291 -- cache latest-seen equipped gear for current spec
292 local spec = GetSpecialization()
293 Amr.db.char.Equipped[spec] = data.Equipped[spec]
294
295 -- scan current inventory just before export so that it is always fresh
530 scanBags() 296 scanBags()
531 297
532 -- scan current spec's talents just before exporting 298 -- scan current spec's talents just before exporting
533 scanTalents() 299 scanTalents()
534 300
535 -- prune crucible info just before each time we export 301 data.Talents = Amr.db.char.Talents
536 pruneCrucible() 302 data.Equipped = Amr.db.char.Equipped
537
538 data.Talents = Amr.db.char.Talents
539 data.Artifacts = Amr.db.char.Artifacts
540 data.Equipped = Amr.db.char.Equipped
541 data.Reputations = getReputations()
542 data.BagItems = Amr.db.char.BagItems 303 data.BagItems = Amr.db.char.BagItems
543 data.BankItems = Amr.db.char.BankItems 304
544 data.VoidItems = Amr.db.char.VoidItems 305 -- flatten bank data (which is stored by bag for more efficient updating)
306 data.BankItems = {}
307 for k,v in pairs(Amr.db.char.BankItems) do
308 for i,v2 in ipairs(v) do
309 table.insert(data.BankItems, v2)
310 end
311 end
312
313 --data.VoidItems = Amr.db.char.VoidItems
545 314
546 return data 315 return data
547 end 316 end
548 317
549 function Amr:InitializeExport() 318 function Amr:InitializeExport()
550 Amr:AddEventHandler("UNIT_INVENTORY_CHANGED", function(unitID) 319 Amr:AddEventHandler("UNIT_INVENTORY_CHANGED", function(unitID)
551 if unitID and unitID ~= "player" then return end 320 if unitID and unitID ~= "player" then return end
552 getEquipped() 321 cacheEquipped()
553 end) 322 end)
554 end 323 end
555 324
556 Amr:AddEventHandler("BANKFRAME_OPENED", scanBank) 325 Amr:AddEventHandler("BANKFRAME_OPENED", onBankOpened)
557 Amr:AddEventHandler("PLAYERBANKSLOTS_CHANGED", scanBank) 326 Amr:AddEventHandler("BANKFRAME_CLOSED", onBankClosed)
558 327 Amr:AddEventHandler("BAG_UPDATE", onBankUpdated)
559 Amr:AddEventHandler("VOID_STORAGE_OPEN", scanVoid) 328
560 Amr:AddEventHandler("VOID_STORAGE_CONTENTS_UPDATE", scanVoid) 329 --Amr:AddEventHandler("VOID_STORAGE_OPEN", scanVoid)
561 Amr:AddEventHandler("VOID_STORAGE_DEPOSIT_UPDATE", scanVoid) 330 --Amr:AddEventHandler("VOID_STORAGE_CONTENTS_UPDATE", scanVoid)
562 Amr:AddEventHandler("VOID_STORAGE_UPDATE", scanVoid) 331 --Amr:AddEventHandler("VOID_STORAGE_DEPOSIT_UPDATE", scanVoid)
332 --Amr:AddEventHandler("VOID_STORAGE_UPDATE", scanVoid)
563 333
564 Amr:AddEventHandler("PLAYER_TALENT_UPDATE", scanTalents) 334 Amr:AddEventHandler("PLAYER_TALENT_UPDATE", scanTalents)
565 Amr:AddEventHandler("ARTIFACT_UPDATE", scanArtifact)
566 Amr:AddEventHandler("ARTIFACT_RELIC_FORGE_UPDATE", scanCrucible)
567 Amr:AddEventHandler("ARTIFACT_RELIC_FORGE_PREVIEW_RELIC_CHANGED", scanCrucible)