Mercurial > wow > askmrrobot
comparison AskMrRobot-Serializer/AskMrRobot-Serializer.lua @ 81:0515882856f1 v38
updated for 7.0
author | yellowfive |
---|---|
date | Tue, 19 Jul 2016 10:05:32 -0700 |
parents | a892c863c86a |
children | af2474d28bb4 |
comparison
equal
deleted
inserted
replaced
80:8f235b016212 | 81:0515882856f1 |
---|---|
1 -- AskMrRobot-Serializer will serialize and communicate character data between users. | 1 -- AskMrRobot-Serializer will serialize and communicate character data between users. |
2 -- This is used primarily to associate character information to logs uploaded to askmrrobot.com. | 2 -- This is used primarily to associate character information to logs uploaded to askmrrobot.com. |
3 | 3 |
4 local MAJOR, MINOR = "AskMrRobot-Serializer", 32 | 4 local MAJOR, MINOR = "AskMrRobot-Serializer", 38 |
5 local Amr, oldminor = LibStub:NewLibrary(MAJOR, MINOR) | 5 local Amr, oldminor = LibStub:NewLibrary(MAJOR, MINOR) |
6 | 6 |
7 if not Amr then return end -- already loaded by something else | 7 if not Amr then return end -- already loaded by something else |
8 | 8 |
9 -- event and comm used for player snapshotting on entering combat | 9 -- event and comm used for player snapshotting on entering combat |
50 | 50 |
51 Amr.SpecIds = { | 51 Amr.SpecIds = { |
52 [250] = 1, -- DeathKnightBlood | 52 [250] = 1, -- DeathKnightBlood |
53 [251] = 2, -- DeathKnightFrost | 53 [251] = 2, -- DeathKnightFrost |
54 [252] = 3, -- DeathKnightUnholy | 54 [252] = 3, -- DeathKnightUnholy |
55 [102] = 4, -- DruidBalance | 55 [577] = 4, -- DemonHunterHavoc |
56 [103] = 5, -- DruidFeral | 56 [581] = 5, -- DemonHunterVengeance |
57 [104] = 6, -- DruidGuardian | 57 [102] = 6, -- DruidBalance |
58 [105] = 7, -- DruidRestoration | 58 [103] = 7, -- DruidFeral |
59 [253] = 8, -- HunterBeastMastery | 59 [104] = 8, -- DruidGuardian |
60 [254] = 9, -- HunterMarksmanship | 60 [105] = 9, -- DruidRestoration |
61 [255] = 10, -- HunterSurvival | 61 [253] = 10, -- HunterBeastMastery |
62 [62] = 11, -- MageArcane | 62 [254] = 11, -- HunterMarksmanship |
63 [63] = 12, -- MageFire | 63 [255] = 12, -- HunterSurvival |
64 [64] = 13, -- MageFrost | 64 [62] = 13, -- MageArcane |
65 [268] = 14, -- MonkBrewmaster | 65 [63] = 14, -- MageFire |
66 [270] = 15, -- MonkMistweaver | 66 [64] = 15, -- MageFrost |
67 [269] = 16, -- MonkWindwalker | 67 [268] = 16, -- MonkBrewmaster |
68 [65] = 17, -- PaladinHoly | 68 [270] = 17, -- MonkMistweaver |
69 [66] = 18, -- PaladinProtection | 69 [269] = 18, -- MonkWindwalker |
70 [70] = 19, -- PaladinRetribution | 70 [65] = 19, -- PaladinHoly |
71 [256] = 20, -- PriestDiscipline | 71 [66] = 20, -- PaladinProtection |
72 [257] = 21, -- PriestHoly | 72 [70] = 21, -- PaladinRetribution |
73 [258] = 22, -- PriestShadow | 73 [256] = 22, -- PriestDiscipline |
74 [259] = 23, -- RogueAssassination | 74 [257] = 23, -- PriestHoly |
75 [260] = 24, -- RogueCombat | 75 [258] = 24, -- PriestShadow |
76 [261] = 25, -- RogueSubtlety | 76 [259] = 25, -- RogueAssassination |
77 [262] = 26, -- ShamanElemental | 77 [260] = 26, -- RogueOutlaw |
78 [263] = 27, -- ShamanEnhancement | 78 [261] = 27, -- RogueSubtlety |
79 [264] = 28, -- ShamanRestoration | 79 [262] = 28, -- ShamanElemental |
80 [265] = 29, -- WarlockAffliction | 80 [263] = 29, -- ShamanEnhancement |
81 [266] = 30, -- WarlockDemonology | 81 [264] = 30, -- ShamanRestoration |
82 [267] = 31, -- WarlockDestruction | 82 [265] = 31, -- WarlockAffliction |
83 [71] = 32, -- WarriorArms | 83 [266] = 32, -- WarlockDemonology |
84 [72] = 33, -- WarriorFury | 84 [267] = 33, -- WarlockDestruction |
85 [73] = 34 -- WarriorProtection | 85 [71] = 34, -- WarriorArms |
86 [72] = 35, -- WarriorFury | |
87 [73] = 36 -- WarriorProtection | |
86 } | 88 } |
87 | 89 |
88 Amr.ClassIds = { | 90 Amr.ClassIds = { |
89 ["NONE"] = 0, | 91 ["NONE"] = 0, |
90 ["DEATHKNIGHT"] = 1, | 92 ["DEATHKNIGHT"] = 1, |
91 ["DRUID"] = 2, | 93 ["DEMONHUNTER"] = 2, |
92 ["HUNTER"] = 3, | 94 ["DRUID"] = 3, |
93 ["MAGE"] = 4, | 95 ["HUNTER"] = 4, |
94 ["MONK"] = 5, | 96 ["MAGE"] = 5, |
95 ["PALADIN"] = 6, | 97 ["MONK"] = 6, |
96 ["PRIEST"] = 7, | 98 ["PALADIN"] = 7, |
97 ["ROGUE"] = 8, | 99 ["PRIEST"] = 8, |
98 ["SHAMAN"] = 9, | 100 ["ROGUE"] = 9, |
99 ["WARLOCK"] = 10, | 101 ["SHAMAN"] = 10, |
100 ["WARRIOR"] = 11, | 102 ["WARLOCK"] = 11, |
103 ["WARRIOR"] = 12, | |
101 } | 104 } |
102 | 105 |
103 Amr.ProfessionIds = { | 106 Amr.ProfessionIds = { |
104 ["None"] = 0, | 107 ["None"] = 0, |
105 ["Mining"] = 1, | 108 ["Mining"] = 1, |
169 --[1358] = true, | 172 --[1358] = true, |
170 [1228] = true, | 173 [1228] = true, |
171 [1205] = true, | 174 [1205] = true, |
172 [1448] = true | 175 [1448] = true |
173 } | 176 } |
174 | |
175 Amr.SPEC_WARRIORPROTECTION = 34 | |
176 Amr.SUBSPEC_WARRIORPROTECTION = 38 | |
177 Amr.SUBSPEC_WARRIORPROTECTIONGLAD = 39 | |
178 Amr.SPELL_ID_GLADIATOR_STANCE = 156291 | |
179 Amr.SPELL_ID_DEFENSIVE_STANCE = 71 | |
180 | 177 |
181 -- IDs of set tokens that we would care about in a player's inventory | 178 -- IDs of set tokens that we would care about in a player's inventory |
182 Amr.SetTokenIds = { | 179 Amr.SetTokenIds = { |
183 [127970] = true, | 180 [127970] = true, |
184 [127969] = true, | 181 [127969] = true, |
577 | 574 |
578 ---------------------------------------------------------------------------------------- | 575 ---------------------------------------------------------------------------------------- |
579 -- Public Utility Methods | 576 -- Public Utility Methods |
580 ---------------------------------------------------------------------------------------- | 577 ---------------------------------------------------------------------------------------- |
581 | 578 |
579 local function readBonusIdList(parts, first, last) | |
580 local ret = {} | |
581 for i = first, last do | |
582 table.insert(ret, tonumber(parts[i])) | |
583 end | |
584 table.sort(ret) | |
585 return ret | |
586 end | |
587 | |
588 local function setRelicId(item, index, relicBonuses) | |
589 local relicId = item.gemIds[index] .. "" | |
590 for i = 1, #relicBonuses do | |
591 relicId = relicId .. "." .. relicBonuses[i] | |
592 end | |
593 local list = item.gemItemIds or {} | |
594 list[i] = relicId | |
595 end | |
596 | |
597 --|color|Hitem:135820:enchant:gem1:gem2:gem3:gem4:suffixID:uniqueID:playerlevel:spec?:flags:11:numBonusIDs:bonusID1:bonusID2...:playerlevelwhengotitem, 296 for warrior artifact:upgrade ID?:num artifact bonuses?:artifact bonus 1:artifact bonus 2:artifact bonus 3:[item name] | |
598 -- 133004 for relic on my warrior, gem2 | |
599 -- 296::3:767:1507:1809:[item name] this is for warrior artifact with the above relic in storm slot, for parts after the bonus IDs | |
600 | |
601 --|cffa335ee|Hitem:itemID:enchant:gem1:gem2:gem3:gem4:suffixID:uniqueID:level:unknown:unknown:instanceDifficultyID:numBonusIDs:bonusID1:bonusID2...|h[item name]|h|r | |
602 | |
582 -- item link format: |cffa335ee|Hitem:itemID:enchant:gem1:gem2:gem3:gem4:suffixID:uniqueID:level:unknown:unknown:instanceDifficultyID:numBonusIDs:bonusID1:bonusID2...|h[item name]|h|r | 603 -- item link format: |cffa335ee|Hitem:itemID:enchant:gem1:gem2:gem3:gem4:suffixID:uniqueID:level:unknown:unknown:instanceDifficultyID:numBonusIDs:bonusID1:bonusID2...|h[item name]|h|r |
583 -- get an object with all of the parts of the item link format that we care about | 604 -- get an object with all of the parts of the item link format that we care about |
584 function Amr.ParseItemLink(itemLink) | 605 function Amr.ParseItemLink(itemLink) |
585 if not itemLink then return nil end | 606 if not itemLink then return nil end |
586 | 607 |
588 if not str then return nil end | 609 if not str then return nil end |
589 | 610 |
590 local parts = { strsplit(":", str) } | 611 local parts = { strsplit(":", str) } |
591 | 612 |
592 local item = {} | 613 local item = {} |
593 item.id = tonumber(parts[1]) | 614 item.id = tonumber(parts[1]) or 0 |
594 item.enchantId = tonumber(parts[2]) | 615 item.enchantId = tonumber(parts[2]) or 0 |
595 item.gemIds = { tonumber(parts[3]), tonumber(parts[4]), tonumber(parts[5]), tonumber(parts[6]) } | 616 item.gemIds = { tonumber(parts[3]) or 0, tonumber(parts[4]) or 0, tonumber(parts[5]) or 0, tonumber(parts[6]) or 0 } |
596 item.suffixId = math.abs(tonumber(parts[7])) -- convert suffix to positive number, that's what we use in our code | 617 item.suffixId = math.abs(tonumber(parts[7]) or 0) -- convert suffix to positive number, that's what we use in our code |
597 --item.uniqueId = tonumber(parts[8]) | 618 -- part 8 is some unique ID... we never really used it |
598 --item.level = tonumber(parts[9]) | 619 -- part 9 is current player level |
599 -- part 10 is unknown atm | 620 -- part 10 is player spec |
600 -- part 11 is unknown atm | 621 local upgradeIdType = tonumber(parts[11]) or 0 -- part 11 indicates what kind of upgrade ID is just after the bonus IDs |
601 --item.difficultyId = tonumber(parts[12]) | 622 -- part 12 is instance difficulty id |
602 | 623 |
603 local numBonuses = tonumber(parts[13]) | 624 local numBonuses = tonumber(parts[13]) or 0 |
604 if numBonuses and numBonuses > 0 then | 625 local offset = numBonuses |
605 item.bonusIds = {} | 626 if numBonuses > 0 then |
606 for i = 14, 13 + numBonuses do | 627 item.bonusIds = readBonusIdList(parts, 14, 13 + numBonuses) |
607 table.insert(item.bonusIds, tonumber(parts[i])) | 628 end |
629 | |
630 item.upgradeId = 0 | |
631 item.level = 0 | |
632 | |
633 -- the next part after bonus IDs depends on the upgrade id type; is either the "drop level" or upgrade ID, or not sure for artifacts | |
634 if upgradeIdType == 4 then | |
635 item.upgradeId = tonumber(parts[14 + offset]) or 0 | |
636 elseif upgradeIdType == 512 then | |
637 item.level = tonumber(parts[14 + offset]) or 0 | |
638 end | |
639 | |
640 -- ignore relic stuff in the item link for now, we read the relic information directly and save it with artifact power info | |
641 --[[ | |
642 -- the next part is the number of bonus IDs on the first relic slot of the artifact | |
643 numBonuses = tonumber(parts[15 + offset]) or 0 | |
644 if numBonuses > 0 then | |
645 local relicBonuses = readBonusIdList(16 + offset, 15 + offset + numBonuses, parts) | |
646 setRelicId(item, 1, relicBonuses) | |
647 end | |
648 | |
649 -- second relic slot bonus IDs | |
650 offset = offset + numBonuses | |
651 numBonuses = tonumber(parts[16 + offset]) or 0 | |
652 if numBonuses > 0 then | |
653 local relicBonuses = readBonusIdList(17 + offset, 16 + offset + numBonuses, parts) | |
654 setRelicId(item, 2, relicBonuses) | |
655 end | |
656 | |
657 -- third relic slot bonus IDs | |
658 offset = offset + numBonuses | |
659 numBonuses = tonumber(parts[17 + offset]) or 0 | |
660 if numBonuses > 0 then | |
661 local relicBonuses = readBonusIdList(18 + offset, 17 + offset + numBonuses, parts) | |
662 setRelicId(item, 3, relicBonuses) | |
663 end | |
664 ]] | |
665 | |
666 return item | |
667 end | |
668 | |
669 function Amr.GetItemUniqueId(item, noUpgrade) | |
670 if not item then return "" end | |
671 local ret = item.id .. "" | |
672 if item.bonusIds then | |
673 for i = 1, #item.bonusIds do | |
674 ret = ret .. "b" .. item.bonusIds[i] | |
608 end | 675 end |
609 table.sort(item.bonusIds) | 676 end |
610 end | 677 if item.suffixId ~= 0 then |
611 | 678 ret = ret .. "s" .. item.suffixId |
612 -- if there is another part after bonus ids, that is the upgrade id | 679 end |
613 if numBonuses and #parts >= 14 + numBonuses then | 680 if not noUpgrade and item.upgradeId ~= 0 then |
614 local upgradeId = tonumber(parts[14 + numBonuses]) | 681 ret = ret .. "u" .. item.upgradeId |
615 item.upgradeId = upgradeId and upgradeId or 0 | 682 end |
616 else | 683 if item.level ~= 0 then |
617 item.upgradeId = 0 | 684 ret = ret .. "v" .. item.level |
618 end | 685 end |
619 | 686 return ret |
620 return item | |
621 end | 687 end |
622 | 688 |
623 -- returns true if this is an instance that AskMrRobot supports for logging | 689 -- returns true if this is an instance that AskMrRobot supports for logging |
624 function Amr.IsSupportedInstanceId(instanceMapID) | 690 function Amr.IsSupportedInstanceId(instanceMapID) |
625 if Amr.SupportedInstanceIds[tonumber(instanceMapID)] then | 691 if Amr.SupportedInstanceIds[tonumber(instanceMapID)] then |
633 function Amr.IsSupportedInstance() | 699 function Amr.IsSupportedInstance() |
634 local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo() | 700 local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo() |
635 return Amr.IsSupportedInstanceId(instanceMapID) | 701 return Amr.IsSupportedInstanceId(instanceMapID) |
636 end | 702 end |
637 | 703 |
704 -- helper to iterate over a table in order by its keys | |
705 local function spairs(t, order) | |
706 -- collect the keys | |
707 local keys = {} | |
708 for k in pairs(t) do keys[#keys+1] = k end | |
709 | |
710 -- if order function given, sort by it by passing the table and keys a, b, | |
711 -- otherwise just sort the keys | |
712 if order then | |
713 table.sort(keys, function(a,b) return order(t, a, b) end) | |
714 else | |
715 table.sort(keys) | |
716 end | |
717 | |
718 -- return the iterator function | |
719 local i = 0 | |
720 return function() | |
721 i = i + 1 | |
722 if keys[i] then | |
723 return keys[i], t[keys[i]] | |
724 end | |
725 end | |
726 end | |
727 | |
728 -- scanning tooltip b/c for some odd reason the api has no way to get basic item properties... | |
729 -- so you have to generate a fake item tooltip and search for pre-defined strings in the display text | |
730 local _scanTt | |
731 function Amr.GetScanningTooltip() | |
732 if not _scanTt then | |
733 _scanTt = CreateFrame("GameTooltip", "AmrUiScanTooltip", nil, "GameTooltipTemplate") | |
734 _scanTt:SetOwner(UIParent, "ANCHOR_NONE") | |
735 end | |
736 return _scanTt | |
737 end | |
738 | |
739 -- get the item tooltip for the specified item in one of your bags, or if bagId is nil, an equipped item, or if slotId is also nil, the specified item link | |
740 function Amr.GetItemTooltip(bagId, slotId, link) | |
741 local tt = Amr.GetScanningTooltip() | |
742 tt:ClearLines() | |
743 if bagId then | |
744 tt:SetBagItem(bagId, slotId) | |
745 elseif slotId then | |
746 tt:SetInventoryItem("player", slotId) | |
747 else | |
748 tt:SetHyperlink(link) | |
749 end | |
750 return tt | |
751 end | |
752 | |
753 function Amr.GetItemLevel(bagId, slotId, link) | |
754 local itemLevelPattern = _G["ITEM_LEVEL"]:gsub("%%d", "(%%d+)") | |
755 local tt = Amr.GetItemTooltip(bagId, slotId, link) | |
756 | |
757 local regions = { tt:GetRegions() } | |
758 for i, region in ipairs(regions) do | |
759 if region and region:GetObjectType() == "FontString" then | |
760 local text = region:GetText() | |
761 if text then | |
762 ilvl = tonumber(text:match(itemLevelPattern)) | |
763 if ilvl then | |
764 return ilvl | |
765 end | |
766 end | |
767 end | |
768 end | |
769 | |
770 -- 0 means we couldn't find it for whatever reason | |
771 return 0 | |
772 end | |
773 | |
638 | 774 |
639 ---------------------------------------------------------------------------------------- | 775 ---------------------------------------------------------------------------------------- |
640 -- Character Reading | 776 -- Character Reading |
641 ---------------------------------------------------------------------------------------- | 777 ---------------------------------------------------------------------------------------- |
642 | 778 |
647 ret.Professions[Amr.ProfessionSkillLineToName[skillLine]] = skillLevel; | 783 ret.Professions[Amr.ProfessionSkillLineToName[skillLine]] = skillLevel; |
648 end | 784 end |
649 end | 785 end |
650 end | 786 end |
651 | 787 |
652 local function getSpecId(specGroup) | 788 --[[ |
653 local spec = GetSpecialization(false, false, specGroup); | 789 local function getTalents(specPos) |
654 return spec and GetSpecializationInfo(spec); | |
655 end | |
656 | |
657 local function getTalents(specGroup) | |
658 local talentInfo = {} | 790 local talentInfo = {} |
659 local maxTiers = 7 | 791 local maxTiers = 7 |
660 for tier = 1, maxTiers do | 792 for tier = 1, maxTiers do |
661 for col = 1, 3 do | 793 for col = 1, 3 do |
662 local id, name, texture, selected, available = GetTalentInfo(tier, col, specGroup) | 794 local id, name, _, _, _, spellId, _, t, c, selected = GetTalentInfoBySpecialization(specPos, tier, col) |
663 if selected then | 795 if selected then |
664 talentInfo[tier] = col | 796 talentInfo[tier] = col |
665 end | 797 end |
666 end | 798 end |
667 end | 799 end |
675 end | 807 end |
676 end | 808 end |
677 | 809 |
678 return str | 810 return str |
679 end | 811 end |
680 | 812 ]] |
813 | |
814 --[[ | |
681 local function getGlyphs(specGroup) | 815 local function getGlyphs(specGroup) |
682 local glyphs = {} | 816 local glyphs = {} |
683 for i = 1, NUM_GLYPH_SLOTS do | 817 for i = 1, NUM_GLYPH_SLOTS do |
684 local _, _, _, glyphSpellID, _, glyphID = GetGlyphSocketInfo(i, specGroup) | 818 local _, _, _, glyphSpellID, _, glyphID = GetGlyphSocketInfo(i, specGroup) |
685 if (glyphID) then | 819 if (glyphID) then |
686 table.insert(glyphs, glyphSpellID) | 820 table.insert(glyphs, glyphSpellID) |
687 end | 821 end |
688 end | 822 end |
689 return glyphs; | 823 return glyphs; |
690 end | 824 end |
691 | 825 ]] |
692 -- get specs, talents, and glyphs | 826 |
693 local function readSpecs(ret, subspecs) | 827 -- get specs and talents |
694 | 828 local function readSpecs(ret) |
695 for group = 1, GetNumSpecGroups() do | 829 |
830 for pos = 1, 4 do | |
696 -- spec, convert game spec id to one of our spec ids | 831 -- spec, convert game spec id to one of our spec ids |
697 local specId = getSpecId(group) | 832 local specId = GetSpecializationInfo(pos) |
698 if specId then | 833 if specId then |
699 ret.Specs[group] = Amr.SpecIds[specId] | 834 ret.Specs[pos] = Amr.SpecIds[specId] |
700 | 835 -- TODO: figure out how to read inactive spec talents if possible... used to be able to but they changed it |
701 -- if this is a protection warrior, use buffs to determine subspec | 836 --ret.Talents[pos] = getTalents(pos) |
702 if ret.Specs[group] == Amr.SPEC_WARRIORPROTECTION then | |
703 local subspec = 0 | |
704 | |
705 if ret.ActiveSpec ~= group then | |
706 -- this spec isn't active, so we can't use current buffs to determine spec, see if any old data is compatible | |
707 if subspecs and (subspecs[group] == Amr.SUBSPEC_WARRIORPROTECTION or subspecs[group] == Amr.SUBSPEC_WARRIORPROTECTIONGLAD) then | |
708 subspec = subspecs[group] | |
709 end | |
710 else | |
711 for i=1,40 do | |
712 local name,_,_,_,_,_,_,_,_,_,spellId = UnitAura("player", i, "HELPFUL") | |
713 if not name then break end | |
714 | |
715 if spellId == Amr.SPELL_ID_DEFENSIVE_STANCE then | |
716 subspec = Amr.SUBSPEC_WARRIORPROTECTION | |
717 break | |
718 elseif spellId == Amr.SPELL_ID_GLADIATOR_STANCE then | |
719 subspec = Amr.SUBSPEC_WARRIORPROTECTIONGLAD | |
720 break | |
721 end | |
722 end | |
723 end | |
724 | |
725 if subspec == 0 then | |
726 ret.SubSpecs[group] = nil | |
727 else | |
728 ret.SubSpecs[group] = subspec | |
729 end | |
730 end | |
731 else | |
732 ret.Specs[group] = 0 | |
733 end | 837 end |
734 | 838 end |
735 ret.Talents[group] = getTalents(group) | 839 end |
736 ret.Glyphs[group] = getGlyphs(group) | 840 |
737 end | 841 -- TODO: hopefully we can read artifact here when there is an API to get info when the artifact UI is not open |
842 -- get artifact info | |
843 local function readArtifact() | |
844 | |
738 end | 845 end |
739 | 846 |
740 -- get currently equipped items, store with currently active spec | 847 -- get currently equipped items, store with currently active spec |
741 local function readEquippedItems(ret) | 848 local function readEquippedItems(ret) |
742 local equippedItems = {}; | 849 local equippedItems = {}; |
747 equippedItems[slotId] = itemLink | 854 equippedItems[slotId] = itemLink |
748 end | 855 end |
749 end | 856 end |
750 | 857 |
751 -- store last-seen equipped gear for each spec | 858 -- store last-seen equipped gear for each spec |
752 ret.Equipped[GetActiveSpecGroup()] = equippedItems | 859 ret.Equipped[GetSpecialization()] = equippedItems |
753 end | 860 end |
754 | 861 |
755 -- Get all data about the player as an object, includes: | 862 -- Get all data about the player as an object, includes: |
756 -- serializer version | 863 -- serializer version |
757 -- region/realm/name | 864 -- region/realm/name |
758 -- guild | 865 -- guild |
759 -- race | 866 -- race |
760 -- faction | 867 -- faction |
761 -- level | 868 -- level |
762 -- professions | 869 -- professions |
763 -- spec/talent/glyphs for both specs | 870 -- spec/talent for all specs |
871 -- artifact for current spec | |
764 -- equipped gear for the current spec | 872 -- equipped gear for the current spec |
765 -- | 873 -- |
766 function Amr:GetPlayerData(subspecs) | 874 function Amr:GetPlayerData() |
767 | 875 |
768 local ret = {} | 876 local ret = {} |
769 | 877 |
770 ret.Region = Amr.RegionNames[GetCurrentRegion()] | 878 ret.Region = Amr.RegionNames[GetCurrentRegion()] |
771 ret.Realm = GetRealmName() | 879 ret.Realm = GetRealmName() |
772 ret.Name = UnitName("player") | 880 ret.Name = UnitName("player") |
773 ret.Guild = GetGuildInfo("player") | 881 ret.Guild = GetGuildInfo("player") |
774 ret.ActiveSpec = GetActiveSpecGroup() | 882 ret.ActiveSpec = GetSpecialization() |
775 ret.Level = UnitLevel("player"); | 883 ret.Level = UnitLevel("player"); |
776 | 884 |
777 local cls, clsEn = UnitClass("player") | 885 local cls, clsEn = UnitClass("player") |
778 ret.Class = clsEn; | 886 ret.Class = clsEn; |
779 | 887 |
789 readProfessionInfo(fishing, ret) | 897 readProfessionInfo(fishing, ret) |
790 readProfessionInfo(cooking, ret) | 898 readProfessionInfo(cooking, ret) |
791 readProfessionInfo(firstAid, ret) | 899 readProfessionInfo(firstAid, ret) |
792 | 900 |
793 ret.Specs = {} | 901 ret.Specs = {} |
794 ret.SubSpecs = {} -- only filled in for ambiguous cases, right now just prot/glad warrior | |
795 ret.Talents = {} | 902 ret.Talents = {} |
796 ret.Glyphs = {} | 903 readSpecs(ret) |
797 readSpecs(ret, subspecs) | 904 |
905 ret.Artifacts = {} | |
906 readArtifact() | |
798 | 907 |
799 ret.Equipped = {} | 908 ret.Equipped = {} |
800 readEquippedItems(ret) | 909 readEquippedItems(ret) |
801 | 910 |
802 return ret | 911 return ret |
841 local prevItemId = 0 | 950 local prevItemId = 0 |
842 local prevGemId = 0 | 951 local prevGemId = 0 |
843 local prevEnchantId = 0 | 952 local prevEnchantId = 0 |
844 local prevUpgradeId = 0 | 953 local prevUpgradeId = 0 |
845 local prevBonusId = 0 | 954 local prevBonusId = 0 |
955 local prevLevel = 0 | |
846 for i, itemData in ipairs(itemObjects) do | 956 for i, itemData in ipairs(itemObjects) do |
847 local itemParts = {} | 957 local itemParts = {} |
848 | 958 |
959 -- for now export the item level of artifacts as the "drop level" because it is a pain in the ass to figure it out from the bonus IDs | |
960 --local _, _, quality = GetItemInfo(itemData.link) | |
961 --if quality == 6 then | |
962 -- itemData.level = Amr.GetItemLevel(nil, nil, itemData.link) | |
963 --end | |
964 | |
849 table.insert(itemParts, itemData.id - prevItemId) | 965 table.insert(itemParts, itemData.id - prevItemId) |
850 prevItemId = itemData.id | 966 prevItemId = itemData.id |
851 | 967 |
852 if itemData.slot ~= nil then table.insert(itemParts, "s" .. itemData.slot) end | 968 if itemData.slot ~= nil then table.insert(itemParts, "s" .. itemData.slot) end |
853 if itemData.suffixId ~= 0 then table.insert(itemParts, "f" .. itemData.suffixId) end | 969 if itemData.suffixId ~= 0 then table.insert(itemParts, "f" .. itemData.suffixId) end |
854 if itemData.upgradeId ~= 0 then | 970 if itemData.upgradeId ~= 0 then |
855 table.insert(itemParts, "u" .. (itemData.upgradeId - prevUpgradeId)) | 971 table.insert(itemParts, "u" .. (itemData.upgradeId - prevUpgradeId)) |
856 prevUpgradeId = itemData.upgradeId | 972 prevUpgradeId = itemData.upgradeId |
857 end | 973 end |
974 if itemData.level ~= 0 then | |
975 table.insert(itemParts, "v" .. (itemData.level - prevLevel)) | |
976 prevLevel = itemData.level | |
977 end | |
858 if itemData.bonusIds then | 978 if itemData.bonusIds then |
859 for bIndex, bValue in ipairs(itemData.bonusIds) do | 979 for bIndex, bValue in ipairs(itemData.bonusIds) do |
860 table.insert(itemParts, "b" .. (bValue - prevBonusId)) | 980 table.insert(itemParts, "b" .. (bValue - prevBonusId)) |
861 prevBonusId = bValue | 981 prevBonusId = bValue |
862 end | 982 end |
863 end | |
864 if itemData.gemIds[1] ~= 0 then | |
865 table.insert(itemParts, "x" .. (itemData.gemIds[1] - prevGemId)) | |
866 prevGemId = itemData.gemIds[1] | |
867 end | 983 end |
868 if itemData.gemIds[2] ~= 0 then | 984 |
869 table.insert(itemParts, "y" .. (itemData.gemIds[2] - prevGemId)) | 985 if itemData.gemIds[1] ~= 0 then |
870 prevGemId = itemData.gemIds[2] | 986 table.insert(itemParts, "x" .. (itemData.gemIds[1] - prevGemId)) |
871 end | 987 prevGemId = itemData.gemIds[1] |
872 if itemData.gemIds[3] ~= 0 then | 988 end |
873 table.insert(itemParts, "z" .. (itemData.gemIds[3] - prevGemId)) | 989 if itemData.gemIds[2] ~= 0 then |
874 prevGemId = itemData.gemIds[3] | 990 table.insert(itemParts, "y" .. (itemData.gemIds[2] - prevGemId)) |
875 end | 991 prevGemId = itemData.gemIds[2] |
992 end | |
993 if itemData.gemIds[3] ~= 0 then | |
994 table.insert(itemParts, "z" .. (itemData.gemIds[3] - prevGemId)) | |
995 prevGemId = itemData.gemIds[3] | |
996 end | |
997 | |
876 if itemData.enchantId ~= 0 then | 998 if itemData.enchantId ~= 0 then |
877 table.insert(itemParts, "e" .. (itemData.enchantId - prevEnchantId)) | 999 table.insert(itemParts, "e" .. (itemData.enchantId - prevEnchantId)) |
878 prevEnchantId = itemData.enchantId | 1000 prevEnchantId = itemData.enchantId |
879 end | 1001 end |
880 | 1002 |
946 | 1068 |
947 table.insert(fields, table.concat(profs, ",")) | 1069 table.insert(fields, table.concat(profs, ",")) |
948 | 1070 |
949 -- export specs | 1071 -- export specs |
950 table.insert(fields, data.ActiveSpec) | 1072 table.insert(fields, data.ActiveSpec) |
951 for spec = 1, 2 do | 1073 for spec = 1, 4 do |
952 if data.Specs[spec] and (complete or spec == data.ActiveSpec) then | 1074 if data.Specs[spec] and (complete or spec == data.ActiveSpec) then |
953 table.insert(fields, ".s" .. spec) -- indicates the start of a spec block | 1075 table.insert(fields, ".s" .. spec) -- indicates the start of a spec block |
1076 table.insert(fields, data.Specs[spec]) | |
1077 table.insert(fields, data.Talents[spec]) | |
954 | 1078 |
955 -- we use subspec for some ambiguous specs like prot/glad warrior | 1079 local powerids = {} |
956 if data.SubSpecs[spec] then | 1080 local powerranks = {} |
957 table.insert(fields, string.format("s%s", data.SubSpecs[spec])) | 1081 local reliclinks = {} |
958 else | 1082 |
959 table.insert(fields, data.Specs[spec]) | 1083 local artifactInfo = data.Artifacts and data.Artifacts[spec] |
1084 if artifactInfo and artifactInfo.Powers then | |
1085 for k, v in spairs(artifactInfo.Powers) do | |
1086 table.insert(powerids, k) | |
1087 table.insert(powerranks, v) | |
1088 end | |
1089 end | |
1090 if artifactInfo and artifactInfo.Relics then | |
1091 for i, link in ipairs(artifactInfo.Relics) do | |
1092 local relic = Amr.ParseItemLink(link) | |
1093 table.insert(reliclinks, Amr.GetItemUniqueId(relic) or "") | |
1094 end | |
960 end | 1095 end |
961 | 1096 |
962 table.insert(fields, data.Talents[spec]) | 1097 table.insert(fields, toCompressedNumberList(powerids)) |
963 table.insert(fields, toCompressedNumberList(data.Glyphs[spec])) | 1098 table.insert(fields, table.concat(powerranks, ",")) |
1099 table.insert(fields, table.concat(reliclinks, ",")) | |
1100 | |
1101 --table.insert(fields, toCompressedNumberList(data.Glyphs[spec])) | |
964 end | 1102 end |
965 end | 1103 end |
966 | 1104 |
967 -- export equipped gear | 1105 -- export equipped gear |
968 if data.Equipped then | 1106 if data.Equipped then |
969 for spec = 1, 2 do | 1107 for spec = 1, 4 do |
970 if data.Equipped[spec] and (complete or spec == data.ActiveSpec) then | 1108 if data.Equipped[spec] and (complete or spec == data.ActiveSpec) then |
971 table.insert(fields, ".q" .. spec) -- indicates the start of an equipped gear block | 1109 table.insert(fields, ".q" .. spec) -- indicates the start of an equipped gear block |
972 | 1110 |
973 local itemObjects = {} | 1111 local itemObjects = {} |
974 for k, v in pairs(data.Equipped[spec]) do | 1112 for k, v in pairs(data.Equipped[spec]) do |
975 local itemData = Amr.ParseItemLink(v) | 1113 local itemData = Amr.ParseItemLink(v) |
976 itemData.slot = k | 1114 itemData.slot = k |
1115 itemData.link = v | |
977 table.insert(itemObjects, itemData) | 1116 table.insert(itemObjects, itemData) |
978 end | 1117 end |
979 | 1118 |
980 appendItemsToExport(fields, itemObjects) | 1119 appendItemsToExport(fields, itemObjects) |
981 end | 1120 end |
1005 local itemObjects = {} | 1144 local itemObjects = {} |
1006 if data.BagItems then | 1145 if data.BagItems then |
1007 for i, v in ipairs(data.BagItems) do | 1146 for i, v in ipairs(data.BagItems) do |
1008 local itemData = Amr.ParseItemLink(v) | 1147 local itemData = Amr.ParseItemLink(v) |
1009 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then | 1148 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then |
1149 itemData.link = v | |
1010 table.insert(itemObjects, itemData) | 1150 table.insert(itemObjects, itemData) |
1011 end | 1151 end |
1012 end | 1152 end |
1013 end | 1153 end |
1014 if data.BankItems then | 1154 if data.BankItems then |
1015 for i, v in ipairs(data.BankItems) do | 1155 for i, v in ipairs(data.BankItems) do |
1016 local itemData = Amr.ParseItemLink(v) | 1156 local itemData = Amr.ParseItemLink(v) |
1017 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then | 1157 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then |
1158 itemData.link = v | |
1018 table.insert(itemObjects, itemData) | 1159 table.insert(itemObjects, itemData) |
1019 end | 1160 end |
1020 end | 1161 end |
1021 end | 1162 end |
1022 if data.VoidItems then | 1163 if data.VoidItems then |
1023 for i, v in ipairs(data.VoidItems) do | 1164 for i, v in ipairs(data.VoidItems) do |
1024 local itemData = Amr.ParseItemLink(v) | 1165 local itemData = Amr.ParseItemLink(v) |
1025 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then | 1166 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then |
1167 itemData.link = v | |
1026 table.insert(itemObjects, itemData) | 1168 table.insert(itemObjects, itemData) |
1027 end | 1169 end |
1028 end | 1170 end |
1029 end | 1171 end |
1030 | 1172 |
1040 function Amr:SerializePlayer() | 1182 function Amr:SerializePlayer() |
1041 local data = self:GetPlayerData() | 1183 local data = self:GetPlayerData() |
1042 return self:SerializePlayerData(data) | 1184 return self:SerializePlayerData(data) |
1043 end | 1185 end |
1044 | 1186 |
1045 | 1187 --[[ |
1046 ---------------------------------------------------------------------------------------------------------------------- | 1188 ---------------------------------------------------------------------------------------------------------------------- |
1047 -- Character Snapshots | 1189 -- Character Snapshots |
1048 -- This feature snapshots a player's gear/talents/glyphs when entering combat. It is enabled by default. Consumers | 1190 -- This feature snapshots a player's gear/talents/artifact when entering combat. It is enabled by default. Consumers |
1049 -- of this library can create a setting to enable/disable it as desired per a user setting. | 1191 -- of this library can create a setting to enable/disable it as desired per a user setting. |
1050 -- | 1192 -- |
1051 -- You should register for the AMR_SNAPSHOT_STATE_CHANGED message (sent via AceEvent-3.0 messaging) to ensure that | 1193 -- You should register for the AMR_SNAPSHOT_STATE_CHANGED message (sent via AceEvent-3.0 messaging) to ensure that |
1052 -- your addon settings stay in sync with any other addon that may also be trying to control the enabled state. | 1194 -- your addon settings stay in sync with any other addon that may also be trying to control the enabled state. |
1053 -- | 1195 -- |
1087 end | 1229 end |
1088 end | 1230 end |
1089 | 1231 |
1090 Amr:RegisterEvent("PLAYER_REGEN_DISABLED") | 1232 Amr:RegisterEvent("PLAYER_REGEN_DISABLED") |
1091 --Amr:RegisterEvent("GARRISON_MISSION_NPC_OPENED") -- for debugging, fire this event when open mission table | 1233 --Amr:RegisterEvent("GARRISON_MISSION_NPC_OPENED") -- for debugging, fire this event when open mission table |
1234 ]] |