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 ]]