yellowfive@57: -- AskMrRobot-Serializer will serialize and communicate character data between users. yellowfive@57: -- This is used primarily to associate character information to logs uploaded to askmrrobot.com. yellowfive@57: yellowfive@77: local MAJOR, MINOR = "AskMrRobot-Serializer", 31 yellowfive@57: local Amr, oldminor = LibStub:NewLibrary(MAJOR, MINOR) yellowfive@57: yellowfive@57: if not Amr then return end -- already loaded by something else yellowfive@57: yellowfive@57: -- event and comm used for player snapshotting on entering combat yellowfive@57: LibStub("AceEvent-3.0"):Embed(Amr) yellowfive@57: LibStub("AceComm-3.0"):Embed(Amr) yellowfive@57: yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: -- Constants yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: yellowfive@57: -- prefix used for communicating gear snapshots created by the AMR serializer yellowfive@57: Amr.ChatPrefix = "_AMRS" yellowfive@57: yellowfive@57: -- map of region ids to AMR region names yellowfive@57: Amr.RegionNames = { yellowfive@57: [1] = "US", yellowfive@57: [2] = "KR", yellowfive@57: [3] = "EU", yellowfive@57: [4] = "TW", yellowfive@57: [5] = "CN" yellowfive@57: } yellowfive@57: yellowfive@57: -- map of the skillLine returned by profession API to the AMR profession name yellowfive@57: Amr.ProfessionSkillLineToName = { yellowfive@57: [794] = "Archaeology", yellowfive@57: [171] = "Alchemy", yellowfive@57: [164] = "Blacksmithing", yellowfive@57: [185] = "Cooking", yellowfive@57: [333] = "Enchanting", yellowfive@57: [202] = "Engineering", yellowfive@57: [129] = "First Aid", yellowfive@57: [356] = "Fishing", yellowfive@57: [182] = "Herbalism", yellowfive@57: [773] = "Inscription", yellowfive@57: [755] = "Jewelcrafting", yellowfive@57: [165] = "Leatherworking", yellowfive@57: [186] = "Mining", yellowfive@57: [393] = "Skinning", yellowfive@57: [197] = "Tailoring" yellowfive@57: } yellowfive@57: yellowfive@57: -- all slot IDs that we care about, ordered in AMR standard display order yellowfive@57: Amr.SlotIds = { 16, 17, 1, 2, 3, 15, 5, 9, 10, 6, 7, 8, 11, 12, 13, 14 } yellowfive@57: yellowfive@57: Amr.SpecIds = { yellowfive@57: [250] = 1, -- DeathKnightBlood yellowfive@57: [251] = 2, -- DeathKnightFrost yellowfive@57: [252] = 3, -- DeathKnightUnholy yellowfive@57: [102] = 4, -- DruidBalance yellowfive@57: [103] = 5, -- DruidFeral yellowfive@57: [104] = 6, -- DruidGuardian yellowfive@57: [105] = 7, -- DruidRestoration yellowfive@57: [253] = 8, -- HunterBeastMastery yellowfive@57: [254] = 9, -- HunterMarksmanship yellowfive@57: [255] = 10, -- HunterSurvival yellowfive@57: [62] = 11, -- MageArcane yellowfive@57: [63] = 12, -- MageFire yellowfive@57: [64] = 13, -- MageFrost yellowfive@57: [268] = 14, -- MonkBrewmaster yellowfive@57: [270] = 15, -- MonkMistweaver yellowfive@57: [269] = 16, -- MonkWindwalker yellowfive@57: [65] = 17, -- PaladinHoly yellowfive@57: [66] = 18, -- PaladinProtection yellowfive@57: [70] = 19, -- PaladinRetribution yellowfive@57: [256] = 20, -- PriestDiscipline yellowfive@57: [257] = 21, -- PriestHoly yellowfive@57: [258] = 22, -- PriestShadow yellowfive@57: [259] = 23, -- RogueAssassination yellowfive@57: [260] = 24, -- RogueCombat yellowfive@57: [261] = 25, -- RogueSubtlety yellowfive@57: [262] = 26, -- ShamanElemental yellowfive@57: [263] = 27, -- ShamanEnhancement yellowfive@57: [264] = 28, -- ShamanRestoration yellowfive@57: [265] = 29, -- WarlockAffliction yellowfive@57: [266] = 30, -- WarlockDemonology yellowfive@57: [267] = 31, -- WarlockDestruction yellowfive@57: [71] = 32, -- WarriorArms yellowfive@57: [72] = 33, -- WarriorFury yellowfive@57: [73] = 34 -- WarriorProtection yellowfive@57: } yellowfive@57: yellowfive@57: Amr.ClassIds = { yellowfive@57: ["NONE"] = 0, yellowfive@57: ["DEATHKNIGHT"] = 1, yellowfive@57: ["DRUID"] = 2, yellowfive@57: ["HUNTER"] = 3, yellowfive@57: ["MAGE"] = 4, yellowfive@57: ["MONK"] = 5, yellowfive@57: ["PALADIN"] = 6, yellowfive@57: ["PRIEST"] = 7, yellowfive@57: ["ROGUE"] = 8, yellowfive@57: ["SHAMAN"] = 9, yellowfive@57: ["WARLOCK"] = 10, yellowfive@57: ["WARRIOR"] = 11, yellowfive@57: } yellowfive@57: yellowfive@57: Amr.ProfessionIds = { yellowfive@57: ["None"] = 0, yellowfive@57: ["Mining"] = 1, yellowfive@57: ["Skinning"] = 2, yellowfive@57: ["Herbalism"] = 3, yellowfive@57: ["Enchanting"] = 4, yellowfive@57: ["Jewelcrafting"] = 5, yellowfive@57: ["Engineering"] = 6, yellowfive@57: ["Blacksmithing"] = 7, yellowfive@57: ["Leatherworking"] = 8, yellowfive@57: ["Inscription"] = 9, yellowfive@57: ["Tailoring"] = 10, yellowfive@57: ["Alchemy"] = 11, yellowfive@57: ["Fishing"] = 12, yellowfive@57: ["Cooking"] = 13, yellowfive@57: ["First Aid"] = 14, yellowfive@57: ["Archaeology"] = 15 yellowfive@57: } yellowfive@57: yellowfive@57: Amr.RaceIds = { yellowfive@57: ["None"] = 0, yellowfive@57: ["BloodElf"] = 1, yellowfive@57: ["Draenei"] = 2, yellowfive@57: ["Dwarf"] = 3, yellowfive@57: ["Gnome"] = 4, yellowfive@57: ["Human"] = 5, yellowfive@57: ["NightElf"] = 6, yellowfive@57: ["Orc"] = 7, yellowfive@57: ["Tauren"] = 8, yellowfive@57: ["Troll"] = 9, yellowfive@57: ["Scourge"] = 10, yellowfive@57: ["Undead"] = 10, yellowfive@57: ["Goblin"] = 11, yellowfive@57: ["Worgen"] = 12, yellowfive@57: ["Pandaren"] = 13 yellowfive@57: } yellowfive@57: yellowfive@57: Amr.FactionIds = { yellowfive@57: ["None"] = 0, yellowfive@57: ["Alliance"] = 1, yellowfive@57: ["Horde"] = 2 yellowfive@57: } yellowfive@57: yellowfive@57: Amr.InstanceIds = { yellowfive@57: Auchindoun = 1182, yellowfive@57: BloodmaulSlagMines = 1175, yellowfive@57: GrimrailDepot = 1208, yellowfive@57: IronDocks = 1195, yellowfive@57: ShadowmoonBurialGrounds = 1176, yellowfive@57: Skyreach = 1209, yellowfive@57: TheEverbloom = 1279, yellowfive@57: UpperBlackrockSpire = 1358, yellowfive@57: Highmaul = 1228, yellowfive@61: BlackrockFoundry = 1205, yellowfive@61: HellfireCitadel = 1448 yellowfive@57: } yellowfive@57: yellowfive@57: -- instances that AskMrRobot currently supports logging for yellowfive@57: Amr.SupportedInstanceIds = { yellowfive@57: --[1182] = true, yellowfive@57: --[1175] = true, yellowfive@57: --[1208] = true, yellowfive@57: --[1195] = true, yellowfive@57: --[1176] = true, yellowfive@57: --[1209] = true, yellowfive@57: --[1279] = true, yellowfive@57: --[1358] = true, yellowfive@57: [1228] = true, yellowfive@61: [1205] = true, yellowfive@61: [1448] = true yellowfive@57: } yellowfive@57: yellowfive@57: Amr.SPEC_WARRIORPROTECTION = 34 yellowfive@57: Amr.SUBSPEC_WARRIORPROTECTION = 38 yellowfive@57: Amr.SUBSPEC_WARRIORPROTECTIONGLAD = 39 yellowfive@57: Amr.SPELL_ID_GLADIATOR_STANCE = 156291 yellowfive@57: Amr.SPELL_ID_DEFENSIVE_STANCE = 71 yellowfive@57: yellowfive@57: -- IDs of set tokens that we would care about in a player's inventory yellowfive@57: Amr.SetTokenIds = { yellowfive@63: [127970] = true, yellowfive@63: [127969] = true, yellowfive@63: [127968] = true, yellowfive@63: [127967] = true, yellowfive@63: [127966] = true, yellowfive@63: [127965] = true, yellowfive@63: [127964] = true, yellowfive@63: [127963] = true, yellowfive@63: [127962] = true, yellowfive@63: [127961] = true, yellowfive@63: [127960] = true, yellowfive@63: [127959] = true, yellowfive@63: [127958] = true, yellowfive@63: [127957] = true, yellowfive@63: [127956] = true, yellowfive@63: [127955] = true, yellowfive@63: [127954] = true, yellowfive@63: [127953] = true, yellowfive@57: [120285] = true, yellowfive@57: [120284] = true, yellowfive@57: [120283] = true, yellowfive@57: [120282] = true, yellowfive@57: [120281] = true, yellowfive@57: [120280] = true, yellowfive@57: [120279] = true, yellowfive@57: [120278] = true, yellowfive@57: [120277] = true, yellowfive@57: [120256] = true, yellowfive@57: [120255] = true, yellowfive@57: [120254] = true, yellowfive@57: [120253] = true, yellowfive@57: [120252] = true, yellowfive@57: [120251] = true, yellowfive@57: [120250] = true, yellowfive@57: [120249] = true, yellowfive@57: [120248] = true, yellowfive@57: [120247] = true, yellowfive@57: [120246] = true, yellowfive@57: [120245] = true, yellowfive@57: [120244] = true, yellowfive@57: [120243] = true, yellowfive@57: [120242] = true, yellowfive@57: [120241] = true, yellowfive@57: [120240] = true, yellowfive@57: [120239] = true, yellowfive@57: [120238] = true, yellowfive@57: [120237] = true, yellowfive@57: [120236] = true, yellowfive@57: [120235] = true, yellowfive@57: [120234] = true, yellowfive@57: [120233] = true, yellowfive@57: [120232] = true, yellowfive@57: [120231] = true, yellowfive@57: [120230] = true, yellowfive@57: [120229] = true, yellowfive@57: [120228] = true, yellowfive@57: [120227] = true, yellowfive@57: [120226] = true, yellowfive@57: [120225] = true, yellowfive@57: [120224] = true, yellowfive@57: [120223] = true, yellowfive@57: [120222] = true, yellowfive@57: [120221] = true, yellowfive@57: [120220] = true, yellowfive@57: [120219] = true, yellowfive@57: [120218] = true, yellowfive@57: [120217] = true, yellowfive@57: [120216] = true, yellowfive@57: [120215] = true, yellowfive@57: [120214] = true, yellowfive@57: [120213] = true, yellowfive@57: [120212] = true, yellowfive@57: [120211] = true, yellowfive@57: [120210] = true, yellowfive@57: [120209] = true, yellowfive@57: [120208] = true, yellowfive@57: [120207] = true, yellowfive@57: [120206] = true, yellowfive@57: [119323] = true, yellowfive@57: [119322] = true, yellowfive@57: [119321] = true, yellowfive@57: [119320] = true, yellowfive@57: [119319] = true, yellowfive@57: [119318] = true, yellowfive@57: [119316] = true, yellowfive@57: [119315] = true, yellowfive@57: [119314] = true, yellowfive@57: [119313] = true, yellowfive@57: [119312] = true, yellowfive@57: [119311] = true, yellowfive@57: [119310] = true, yellowfive@57: [119309] = true, yellowfive@57: [119308] = true, yellowfive@57: [119307] = true, yellowfive@57: [119306] = true, yellowfive@57: [119305] = true, yellowfive@57: [105868] = true, yellowfive@57: [105867] = true, yellowfive@57: [105866] = true, yellowfive@57: [105865] = true, yellowfive@57: [105864] = true, yellowfive@57: [105863] = true, yellowfive@57: [105862] = true, yellowfive@57: [105861] = true, yellowfive@57: [105860] = true, yellowfive@57: [105859] = true, yellowfive@57: [105858] = true, yellowfive@57: [105857] = true, yellowfive@57: [99756] = true, yellowfive@57: [99755] = true, yellowfive@57: [99754] = true, yellowfive@57: [99753] = true, yellowfive@57: [99752] = true, yellowfive@57: [99751] = true, yellowfive@57: [99750] = true, yellowfive@57: [99749] = true, yellowfive@57: [99748] = true, yellowfive@57: [99747] = true, yellowfive@57: [99746] = true, yellowfive@57: [99745] = true, yellowfive@57: [99744] = true, yellowfive@57: [99743] = true, yellowfive@57: [99742] = true, yellowfive@57: [99740] = true, yellowfive@57: [99739] = true, yellowfive@57: [99738] = true, yellowfive@57: [99737] = true, yellowfive@57: [99736] = true, yellowfive@57: [99735] = true, yellowfive@57: [99734] = true, yellowfive@57: [99733] = true, yellowfive@57: [99732] = true, yellowfive@57: [99731] = true, yellowfive@57: [99730] = true, yellowfive@57: [99729] = true, yellowfive@57: [99728] = true, yellowfive@57: [99727] = true, yellowfive@57: [99726] = true, yellowfive@57: [99725] = true, yellowfive@57: [99724] = true, yellowfive@57: [99723] = true, yellowfive@57: [99722] = true, yellowfive@57: [99721] = true, yellowfive@57: [99720] = true, yellowfive@57: [99719] = true, yellowfive@57: [99718] = true, yellowfive@57: [99717] = true, yellowfive@57: [99716] = true, yellowfive@57: [99715] = true, yellowfive@57: [99714] = true, yellowfive@57: [99713] = true, yellowfive@57: [99712] = true, yellowfive@57: [99711] = true, yellowfive@57: [99710] = true, yellowfive@57: [99709] = true, yellowfive@57: [99708] = true, yellowfive@57: [99707] = true, yellowfive@57: [99706] = true, yellowfive@57: [99705] = true, yellowfive@57: [99704] = true, yellowfive@57: [99703] = true, yellowfive@57: [99702] = true, yellowfive@57: [99701] = true, yellowfive@57: [99700] = true, yellowfive@57: [99699] = true, yellowfive@57: [99698] = true, yellowfive@57: [99697] = true, yellowfive@57: [99696] = true, yellowfive@57: [99695] = true, yellowfive@57: [99694] = true, yellowfive@57: [99693] = true, yellowfive@57: [99692] = true, yellowfive@57: [99691] = true, yellowfive@57: [99690] = true, yellowfive@57: [99689] = true, yellowfive@57: [99688] = true, yellowfive@57: [99687] = true, yellowfive@57: [99686] = true, yellowfive@57: [99685] = true, yellowfive@57: [99684] = true, yellowfive@57: [99683] = true, yellowfive@57: [99682] = true, yellowfive@57: [99681] = true, yellowfive@57: [99680] = true, yellowfive@57: [99679] = true, yellowfive@57: [99678] = true, yellowfive@57: [99677] = true, yellowfive@57: [99676] = true, yellowfive@57: [99675] = true, yellowfive@57: [99674] = true, yellowfive@57: [99673] = true, yellowfive@57: [99672] = true, yellowfive@57: [99671] = true, yellowfive@57: [99670] = true, yellowfive@57: [99669] = true, yellowfive@57: [99668] = true, yellowfive@57: [99667] = true, yellowfive@57: [96701] = true, yellowfive@57: [96700] = true, yellowfive@57: [96699] = true, yellowfive@57: [96633] = true, yellowfive@57: [96632] = true, yellowfive@57: [96631] = true, yellowfive@57: [96625] = true, yellowfive@57: [96624] = true, yellowfive@57: [96623] = true, yellowfive@57: [96601] = true, yellowfive@57: [96600] = true, yellowfive@57: [96599] = true, yellowfive@57: [96568] = true, yellowfive@57: [96567] = true, yellowfive@57: [96566] = true, yellowfive@57: [95957] = true, yellowfive@57: [95956] = true, yellowfive@57: [95955] = true, yellowfive@57: [95889] = true, yellowfive@57: [95888] = true, yellowfive@57: [95887] = true, yellowfive@57: [95881] = true, yellowfive@57: [95880] = true, yellowfive@57: [95879] = true, yellowfive@57: [95857] = true, yellowfive@57: [95856] = true, yellowfive@57: [95855] = true, yellowfive@57: [95824] = true, yellowfive@57: [95823] = true, yellowfive@57: [95822] = true, yellowfive@57: [95583] = true, yellowfive@57: [95582] = true, yellowfive@57: [95581] = true, yellowfive@57: [95580] = true, yellowfive@57: [95579] = true, yellowfive@57: [95578] = true, yellowfive@57: [95577] = true, yellowfive@57: [95576] = true, yellowfive@57: [95575] = true, yellowfive@57: [95574] = true, yellowfive@57: [95573] = true, yellowfive@57: [95572] = true, yellowfive@57: [95571] = true, yellowfive@57: [95570] = true, yellowfive@57: [95569] = true, yellowfive@57: [89278] = true, yellowfive@57: [89277] = true, yellowfive@57: [89276] = true, yellowfive@57: [89275] = true, yellowfive@57: [89274] = true, yellowfive@57: [89273] = true, yellowfive@57: [89272] = true, yellowfive@57: [89271] = true, yellowfive@57: [89270] = true, yellowfive@57: [89269] = true, yellowfive@57: [89268] = true, yellowfive@57: [89267] = true, yellowfive@57: [89266] = true, yellowfive@57: [89265] = true, yellowfive@57: [89264] = true, yellowfive@57: [89263] = true, yellowfive@57: [89262] = true, yellowfive@57: [89261] = true, yellowfive@57: [89260] = true, yellowfive@57: [89259] = true, yellowfive@57: [89258] = true, yellowfive@57: [89257] = true, yellowfive@57: [89256] = true, yellowfive@57: [89255] = true, yellowfive@57: [89254] = true, yellowfive@57: [89253] = true, yellowfive@57: [89252] = true, yellowfive@57: [89251] = true, yellowfive@57: [89250] = true, yellowfive@57: [89249] = true, yellowfive@57: [89248] = true, yellowfive@57: [89247] = true, yellowfive@57: [89246] = true, yellowfive@57: [89245] = true, yellowfive@57: [89244] = true, yellowfive@57: [89243] = true, yellowfive@57: [89242] = true, yellowfive@57: [89241] = true, yellowfive@57: [89240] = true, yellowfive@57: [89239] = true, yellowfive@57: [89238] = true, yellowfive@57: [89237] = true, yellowfive@57: [89236] = true, yellowfive@57: [89235] = true, yellowfive@57: [89234] = true, yellowfive@57: [78876] = true, yellowfive@57: [78875] = true, yellowfive@57: [78874] = true, yellowfive@57: [78873] = true, yellowfive@57: [78872] = true, yellowfive@57: [78871] = true, yellowfive@57: [78867] = true, yellowfive@57: [78866] = true, yellowfive@57: [78865] = true, yellowfive@57: [78864] = true, yellowfive@57: [78863] = true, yellowfive@57: [78862] = true, yellowfive@57: [78861] = true, yellowfive@57: [78860] = true, yellowfive@57: [78859] = true, yellowfive@57: [78858] = true, yellowfive@57: [78857] = true, yellowfive@57: [78856] = true, yellowfive@57: [78855] = true, yellowfive@57: [78854] = true, yellowfive@57: [78853] = true, yellowfive@57: [78849] = true, yellowfive@57: [78848] = true, yellowfive@57: [78847] = true, yellowfive@57: [78184] = true, yellowfive@57: [78183] = true, yellowfive@57: [78181] = true, yellowfive@57: [78180] = true, yellowfive@57: [78179] = true, yellowfive@57: [78178] = true, yellowfive@57: [78176] = true, yellowfive@57: [78175] = true, yellowfive@57: [78174] = true, yellowfive@57: [78173] = true, yellowfive@57: [78171] = true, yellowfive@57: [78170] = true, yellowfive@57: [71687] = true, yellowfive@57: [71686] = true, yellowfive@57: [71685] = true, yellowfive@57: [71683] = true, yellowfive@57: [71682] = true, yellowfive@57: [71680] = true, yellowfive@57: [71679] = true, yellowfive@57: [71678] = true, yellowfive@57: [71676] = true, yellowfive@57: [71675] = true, yellowfive@57: [71673] = true, yellowfive@57: [71672] = true, yellowfive@57: [71671] = true, yellowfive@57: [71669] = true, yellowfive@57: [71668] = true, yellowfive@57: [67431] = true, yellowfive@57: [67430] = true, yellowfive@57: [67429] = true, yellowfive@57: [67428] = true, yellowfive@57: [67427] = true, yellowfive@57: [67426] = true, yellowfive@57: [67425] = true, yellowfive@57: [67424] = true, yellowfive@57: [67423] = true, yellowfive@57: [66998] = true, yellowfive@57: [65089] = true, yellowfive@57: [65088] = true, yellowfive@57: [65087] = true, yellowfive@57: [63684] = true, yellowfive@57: [63683] = true, yellowfive@57: [63682] = true, yellowfive@63: [51320] = true, yellowfive@57: [45652] = true, yellowfive@57: [45651] = true, yellowfive@57: [45650] = true, yellowfive@57: [45649] = true, yellowfive@57: [45648] = true, yellowfive@57: [45647] = true, yellowfive@57: [45643] = true, yellowfive@57: [45642] = true, yellowfive@57: [45641] = true, yellowfive@57: [40630] = true, yellowfive@57: [40629] = true, yellowfive@57: [40628] = true, yellowfive@57: [40621] = true, yellowfive@57: [40620] = true, yellowfive@57: [40619] = true, yellowfive@57: [40618] = true, yellowfive@57: [40617] = true, yellowfive@57: [40616] = true, yellowfive@57: [34544] = true, yellowfive@57: [31100] = true, yellowfive@57: [31099] = true, yellowfive@57: [31098] = true, yellowfive@57: [31097] = true, yellowfive@57: [31096] = true, yellowfive@57: [31095] = true, yellowfive@57: [30247] = true, yellowfive@57: [30246] = true, yellowfive@57: [30245] = true, yellowfive@57: [30244] = true, yellowfive@57: [30243] = true, yellowfive@57: [30242] = true, yellowfive@57: [29767] = true, yellowfive@57: [29766] = true, yellowfive@57: [29765] = true, yellowfive@57: [29761] = true, yellowfive@57: [29760] = true, yellowfive@57: [29759] = true yellowfive@57: } yellowfive@57: yellowfive@57: yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: -- Public Utility Methods yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: yellowfive@69: -- 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 yellowfive@57: -- get an object with all of the parts of the item link format that we care about yellowfive@57: function Amr.ParseItemLink(itemLink) yellowfive@57: if not itemLink then return nil end yellowfive@57: yellowfive@57: local str = string.match(itemLink, "|Hitem:([\-%d:]+)|") yellowfive@57: if not str then return nil end yellowfive@57: yellowfive@57: local parts = { strsplit(":", str) } yellowfive@57: yellowfive@57: local item = {} yellowfive@57: item.id = tonumber(parts[1]) yellowfive@57: item.enchantId = tonumber(parts[2]) yellowfive@57: item.gemIds = { tonumber(parts[3]), tonumber(parts[4]), tonumber(parts[5]), tonumber(parts[6]) } yellowfive@57: item.suffixId = math.abs(tonumber(parts[7])) -- convert suffix to positive number, that's what we use in our code yellowfive@57: --item.uniqueId = tonumber(parts[8]) yellowfive@57: --item.level = tonumber(parts[9]) yellowfive@65: -- part 10 is unknown atm yellowfive@69: -- part 11 is unknown atm yellowfive@63: --item.difficultyId = tonumber(parts[12]) yellowfive@57: yellowfive@63: local numBonuses = tonumber(parts[13]) yellowfive@57: if numBonuses and numBonuses > 0 then yellowfive@57: item.bonusIds = {} yellowfive@63: for i = 14, 13 + numBonuses do yellowfive@57: table.insert(item.bonusIds, tonumber(parts[i])) yellowfive@57: end yellowfive@57: table.sort(item.bonusIds) yellowfive@57: end yellowfive@69: yellowfive@73: -- if there is another part after bonus ids, that is the upgrade id yellowfive@75: if numBonuses and #parts >= 14 + numBonuses then yellowfive@73: local upgradeId = tonumber(parts[14 + numBonuses]) yellowfive@69: item.upgradeId = upgradeId and upgradeId or 0 yellowfive@69: else yellowfive@69: item.upgradeId = 0 yellowfive@69: end yellowfive@57: yellowfive@57: return item yellowfive@57: end yellowfive@57: yellowfive@57: -- returns true if this is an instance that AskMrRobot supports for logging yellowfive@57: function Amr.IsSupportedInstanceId(instanceMapID) yellowfive@57: if Amr.SupportedInstanceIds[tonumber(instanceMapID)] then yellowfive@57: return true yellowfive@57: else yellowfive@57: return false yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- returns true if currently in a supported instance for logging yellowfive@57: function Amr.IsSupportedInstance() yellowfive@57: local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo() yellowfive@57: return Amr.IsSupportedInstanceId(instanceMapID) yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: -- Character Reading yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: yellowfive@57: local function readProfessionInfo(prof, ret) yellowfive@57: if prof then yellowfive@57: local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(prof); yellowfive@57: if Amr.ProfessionSkillLineToName[skillLine] ~= nil then yellowfive@57: ret.Professions[Amr.ProfessionSkillLineToName[skillLine]] = skillLevel; yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: local function getSpecId(specGroup) yellowfive@57: local spec = GetSpecialization(false, false, specGroup); yellowfive@57: return spec and GetSpecializationInfo(spec); yellowfive@57: end yellowfive@57: yellowfive@57: local function getTalents(specGroup) yellowfive@57: local talentInfo = {} yellowfive@57: local maxTiers = 7 yellowfive@57: for tier = 1, maxTiers do yellowfive@57: for col = 1, 3 do yellowfive@57: local id, name, texture, selected, available = GetTalentInfo(tier, col, specGroup) yellowfive@57: if selected then yellowfive@57: talentInfo[tier] = col yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: local str = "" yellowfive@57: for i = 1, maxTiers do yellowfive@57: if talentInfo[i] then yellowfive@57: str = str .. talentInfo[i] yellowfive@57: else yellowfive@57: str = str .. '0' yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: return str yellowfive@57: end yellowfive@57: yellowfive@57: local function getGlyphs(specGroup) yellowfive@57: local glyphs = {} yellowfive@57: for i = 1, NUM_GLYPH_SLOTS do yellowfive@57: local _, _, _, glyphSpellID, _, glyphID = GetGlyphSocketInfo(i, specGroup) yellowfive@57: if (glyphID) then yellowfive@57: table.insert(glyphs, glyphSpellID) yellowfive@57: end yellowfive@57: end yellowfive@57: return glyphs; yellowfive@57: end yellowfive@57: yellowfive@57: -- get specs, talents, and glyphs yellowfive@57: local function readSpecs(ret, subspecs) yellowfive@57: yellowfive@57: for group = 1, GetNumSpecGroups() do yellowfive@57: -- spec, convert game spec id to one of our spec ids yellowfive@57: local specId = getSpecId(group) yellowfive@57: if specId then yellowfive@57: ret.Specs[group] = Amr.SpecIds[specId] yellowfive@57: yellowfive@57: -- if this is a protection warrior, use buffs to determine subspec yellowfive@57: if ret.Specs[group] == Amr.SPEC_WARRIORPROTECTION then yellowfive@57: local subspec = 0 yellowfive@57: yellowfive@57: if ret.ActiveSpec ~= group then yellowfive@57: -- this spec isn't active, so we can't use current buffs to determine spec, see if any old data is compatible yellowfive@57: if subspecs and (subspecs[group] == Amr.SUBSPEC_WARRIORPROTECTION or subspecs[group] == Amr.SUBSPEC_WARRIORPROTECTIONGLAD) then yellowfive@57: subspec = subspecs[group] yellowfive@57: end yellowfive@57: else yellowfive@57: for i=1,40 do yellowfive@57: local name,_,_,_,_,_,_,_,_,_,spellId = UnitAura("player", i, "HELPFUL") yellowfive@57: if not name then break end yellowfive@57: yellowfive@57: if spellId == Amr.SPELL_ID_DEFENSIVE_STANCE then yellowfive@57: subspec = Amr.SUBSPEC_WARRIORPROTECTION yellowfive@57: break yellowfive@57: elseif spellId == Amr.SPELL_ID_GLADIATOR_STANCE then yellowfive@57: subspec = Amr.SUBSPEC_WARRIORPROTECTIONGLAD yellowfive@57: break yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: if subspec == 0 then yellowfive@57: ret.SubSpecs[group] = nil yellowfive@57: else yellowfive@57: ret.SubSpecs[group] = subspec yellowfive@57: end yellowfive@57: end yellowfive@57: else yellowfive@57: ret.Specs[group] = 0 yellowfive@57: end yellowfive@57: yellowfive@57: ret.Talents[group] = getTalents(group) yellowfive@57: ret.Glyphs[group] = getGlyphs(group) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- get currently equipped items, store with currently active spec yellowfive@57: local function readEquippedItems(ret) yellowfive@57: local equippedItems = {}; yellowfive@57: for slotNum = 1, #Amr.SlotIds do yellowfive@57: local slotId = Amr.SlotIds[slotNum] yellowfive@57: local itemLink = GetInventoryItemLink("player", slotId) yellowfive@57: if itemLink then yellowfive@57: equippedItems[slotId] = itemLink yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- store last-seen equipped gear for each spec yellowfive@57: ret.Equipped[GetActiveSpecGroup()] = equippedItems yellowfive@57: end yellowfive@57: yellowfive@57: -- Get all data about the player as an object, includes: yellowfive@57: -- serializer version yellowfive@57: -- region/realm/name yellowfive@57: -- guild yellowfive@57: -- race yellowfive@57: -- faction yellowfive@57: -- level yellowfive@57: -- professions yellowfive@57: -- spec/talent/glyphs for both specs yellowfive@57: -- equipped gear for the current spec yellowfive@57: -- yellowfive@57: function Amr:GetPlayerData(subspecs) yellowfive@57: yellowfive@57: local ret = {} yellowfive@57: yellowfive@57: ret.Region = Amr.RegionNames[GetCurrentRegion()] yellowfive@57: ret.Realm = GetRealmName() yellowfive@57: ret.Name = UnitName("player") yellowfive@57: ret.Guild = GetGuildInfo("player") yellowfive@57: ret.ActiveSpec = GetActiveSpecGroup() yellowfive@57: ret.Level = UnitLevel("player"); yellowfive@57: yellowfive@57: local cls, clsEn = UnitClass("player") yellowfive@57: ret.Class = clsEn; yellowfive@57: yellowfive@57: local race, raceEn = UnitRace("player") yellowfive@57: ret.Race = raceEn; yellowfive@57: ret.Faction = UnitFactionGroup("player") yellowfive@57: yellowfive@57: ret.Professions = {}; yellowfive@57: local prof1, prof2, archaeology, fishing, cooking, firstAid = GetProfessions(); yellowfive@57: readProfessionInfo(prof1, ret) yellowfive@57: readProfessionInfo(prof2, ret) yellowfive@57: readProfessionInfo(archaeology, ret) yellowfive@57: readProfessionInfo(fishing, ret) yellowfive@57: readProfessionInfo(cooking, ret) yellowfive@57: readProfessionInfo(firstAid, ret) yellowfive@57: yellowfive@57: ret.Specs = {} yellowfive@57: ret.SubSpecs = {} -- only filled in for ambiguous cases, right now just prot/glad warrior yellowfive@57: ret.Talents = {} yellowfive@57: ret.Glyphs = {} yellowfive@57: readSpecs(ret, subspecs) yellowfive@57: yellowfive@57: ret.Equipped = {} yellowfive@57: readEquippedItems(ret) yellowfive@57: yellowfive@57: return ret yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: -- Serialization yellowfive@57: ---------------------------------------------------------------------------------------- yellowfive@57: yellowfive@57: local function toCompressedNumberList(list) yellowfive@57: -- ensure the values are numbers, sorted from lowest to highest yellowfive@57: local nums = {} yellowfive@57: for i, v in ipairs(list) do yellowfive@57: table.insert(nums, tonumber(v)) yellowfive@57: end yellowfive@57: table.sort(nums) yellowfive@57: yellowfive@57: local ret = {} yellowfive@57: local prev = 0 yellowfive@57: for i, v in ipairs(nums) do yellowfive@57: local diff = v - prev yellowfive@57: table.insert(ret, diff) yellowfive@57: prev = v yellowfive@57: end yellowfive@57: yellowfive@57: return table.concat(ret, ",") yellowfive@57: end yellowfive@57: yellowfive@57: -- make this utility publicly available yellowfive@57: function Amr:ToCompressedNumberList(list) yellowfive@57: return toCompressedNumberList(list) yellowfive@57: end yellowfive@57: yellowfive@57: -- appends a list of items to the export yellowfive@57: local function appendItemsToExport(fields, itemObjects) yellowfive@57: yellowfive@57: -- sort by item id so we can compress it more easily yellowfive@57: table.sort(itemObjects, function(a, b) return a.id < b.id end) yellowfive@57: yellowfive@57: -- append to the export string yellowfive@57: local prevItemId = 0 yellowfive@57: local prevGemId = 0 yellowfive@57: local prevEnchantId = 0 yellowfive@57: local prevUpgradeId = 0 yellowfive@57: local prevBonusId = 0 yellowfive@57: for i, itemData in ipairs(itemObjects) do yellowfive@57: local itemParts = {} yellowfive@57: yellowfive@57: table.insert(itemParts, itemData.id - prevItemId) yellowfive@57: prevItemId = itemData.id yellowfive@57: yellowfive@57: if itemData.slot ~= nil then table.insert(itemParts, "s" .. itemData.slot) end yellowfive@57: if itemData.suffixId ~= 0 then table.insert(itemParts, "f" .. itemData.suffixId) end yellowfive@57: if itemData.upgradeId ~= 0 then yellowfive@57: table.insert(itemParts, "u" .. (itemData.upgradeId - prevUpgradeId)) yellowfive@57: prevUpgradeId = itemData.upgradeId yellowfive@57: end yellowfive@57: if itemData.bonusIds then yellowfive@57: for bIndex, bValue in ipairs(itemData.bonusIds) do yellowfive@57: table.insert(itemParts, "b" .. (bValue - prevBonusId)) yellowfive@57: prevBonusId = bValue yellowfive@57: end yellowfive@57: end yellowfive@57: if itemData.gemIds[1] ~= 0 then yellowfive@57: table.insert(itemParts, "x" .. (itemData.gemIds[1] - prevGemId)) yellowfive@57: prevGemId = itemData.gemIds[1] yellowfive@57: end yellowfive@57: if itemData.gemIds[2] ~= 0 then yellowfive@57: table.insert(itemParts, "y" .. (itemData.gemIds[2] - prevGemId)) yellowfive@57: prevGemId = itemData.gemIds[2] yellowfive@57: end yellowfive@57: if itemData.gemIds[3] ~= 0 then yellowfive@57: table.insert(itemParts, "z" .. (itemData.gemIds[3] - prevGemId)) yellowfive@57: prevGemId = itemData.gemIds[3] yellowfive@57: end yellowfive@57: if itemData.enchantId ~= 0 then yellowfive@57: table.insert(itemParts, "e" .. (itemData.enchantId - prevEnchantId)) yellowfive@57: prevEnchantId = itemData.enchantId yellowfive@57: end yellowfive@57: yellowfive@57: table.insert(fields, table.concat(itemParts, "")) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- Serialize just the identity portion of a player (region/realm/name) in the same format used by the full serialization yellowfive@57: function Amr:SerializePlayerIdentity(data) yellowfive@57: local fields = {} yellowfive@57: table.insert(fields, MINOR) yellowfive@57: table.insert(fields, data.Region) yellowfive@57: table.insert(fields, data.Realm) yellowfive@57: table.insert(fields, data.Name) yellowfive@57: return "$" .. table.concat(fields, ";") .. "$" yellowfive@57: end yellowfive@57: yellowfive@57: -- Serialize player data gathered by GetPlayerData. This can be augmented with extra data if desired (augmenting used mainly by AskMrRobot addon). yellowfive@57: -- Pass complete = true to do a complete export of this extra information, otherwise it is ignored. yellowfive@57: -- Extra data can include: yellowfive@57: -- equipped gear for the player's inactive spec, slot id to item link dictionary yellowfive@57: -- Reputations yellowfive@57: -- BagItems, BankItems, VoidItems, lists of item links yellowfive@57: -- yellowfive@57: function Amr:SerializePlayerData(data, complete) yellowfive@57: yellowfive@57: local fields = {} yellowfive@57: yellowfive@57: -- compressed string uses a fixed order rather than inserting identifiers yellowfive@57: table.insert(fields, MINOR) yellowfive@57: table.insert(fields, data.Region) yellowfive@57: table.insert(fields, data.Realm) yellowfive@57: table.insert(fields, data.Name) yellowfive@57: yellowfive@57: -- guild name yellowfive@57: if data.Guild == nil then yellowfive@57: table.insert(fields, "") yellowfive@57: else yellowfive@57: table.insert(fields, data.Guild) yellowfive@57: end yellowfive@57: yellowfive@57: -- race, default to pandaren if we can't read it for some reason yellowfive@57: local raceval = Amr.RaceIds[data.Race] yellowfive@57: if raceval == nil then raceval = 13 end yellowfive@57: table.insert(fields, raceval) yellowfive@57: yellowfive@57: -- faction, default to alliance if we can't read it for some reason yellowfive@57: raceval = Amr.FactionIds[data.Faction] yellowfive@57: if raceval == nil then raceval = 1 end yellowfive@57: table.insert(fields, raceval) yellowfive@57: yellowfive@57: table.insert(fields, data.Level) yellowfive@57: yellowfive@57: local profs = {} yellowfive@57: local noprofs = true yellowfive@57: if data.Professions then yellowfive@57: for k, v in pairs(data.Professions) do yellowfive@57: local profval = Amr.ProfessionIds[k] yellowfive@57: if profval ~= nil then yellowfive@57: noprofs = false yellowfive@57: table.insert(profs, profval .. ":" .. v) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: if noprofs then yellowfive@57: table.insert(profs, "0:0") yellowfive@57: end yellowfive@57: yellowfive@57: table.insert(fields, table.concat(profs, ",")) yellowfive@57: yellowfive@57: -- export specs yellowfive@57: table.insert(fields, data.ActiveSpec) yellowfive@57: for spec = 1, 2 do yellowfive@57: if data.Specs[spec] and (complete or spec == data.ActiveSpec) then yellowfive@57: table.insert(fields, ".s" .. spec) -- indicates the start of a spec block yellowfive@57: yellowfive@57: -- we use subspec for some ambiguous specs like prot/glad warrior yellowfive@57: if data.SubSpecs[spec] then yellowfive@57: table.insert(fields, string.format("s%s", data.SubSpecs[spec])) yellowfive@57: else yellowfive@57: table.insert(fields, data.Specs[spec]) yellowfive@57: end yellowfive@57: yellowfive@57: table.insert(fields, data.Talents[spec]) yellowfive@57: table.insert(fields, toCompressedNumberList(data.Glyphs[spec])) yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- export equipped gear yellowfive@57: if data.Equipped then yellowfive@57: for spec = 1, 2 do yellowfive@57: if data.Equipped[spec] and (complete or spec == data.ActiveSpec) then yellowfive@57: table.insert(fields, ".q" .. spec) -- indicates the start of an equipped gear block yellowfive@57: yellowfive@57: local itemObjects = {} yellowfive@57: for k, v in pairs(data.Equipped[spec]) do yellowfive@57: local itemData = Amr.ParseItemLink(v) yellowfive@57: itemData.slot = k yellowfive@57: table.insert(itemObjects, itemData) yellowfive@57: end yellowfive@57: yellowfive@57: appendItemsToExport(fields, itemObjects) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: -- if doing a complete export, include reputations and bank/bag items too yellowfive@57: if complete then yellowfive@57: yellowfive@57: -- export reputations yellowfive@57: local reps = {} yellowfive@57: local noreps = true yellowfive@57: if data.Reputations then yellowfive@57: for k, v in pairs(data.Reputations) do yellowfive@57: noreps = false yellowfive@57: table.insert(reps, k .. ":" .. v) yellowfive@57: end yellowfive@57: end yellowfive@57: if noreps then yellowfive@57: table.insert(reps, "_") yellowfive@57: end yellowfive@57: yellowfive@57: table.insert(fields, ".r") yellowfive@57: table.insert(fields, table.concat(reps, ",")) yellowfive@57: yellowfive@57: -- export bag and bank yellowfive@57: local itemObjects = {} yellowfive@57: if data.BagItems then yellowfive@57: for i, v in ipairs(data.BagItems) do yellowfive@57: local itemData = Amr.ParseItemLink(v) yellowfive@57: if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then yellowfive@57: table.insert(itemObjects, itemData) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: if data.BankItems then yellowfive@57: for i, v in ipairs(data.BankItems) do yellowfive@57: local itemData = Amr.ParseItemLink(v) yellowfive@57: if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then yellowfive@57: table.insert(itemObjects, itemData) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: if data.VoidItems then yellowfive@57: for i, v in ipairs(data.VoidItems) do yellowfive@57: local itemData = Amr.ParseItemLink(v) yellowfive@57: if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then yellowfive@57: table.insert(itemObjects, itemData) yellowfive@57: end yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: table.insert(fields, ".inv") yellowfive@57: appendItemsToExport(fields, itemObjects) yellowfive@57: end yellowfive@57: yellowfive@57: return "$" .. table.concat(fields, ";") .. "$" yellowfive@57: yellowfive@57: end yellowfive@57: yellowfive@57: -- Shortcut for the common use case: serialize the player's currently active setup with no extras. yellowfive@57: function Amr:SerializePlayer() yellowfive@57: local data = self:GetPlayerData() yellowfive@57: return self:SerializePlayerData(data) yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: ---------------------------------------------------------------------------------------------------------------------- yellowfive@57: -- Character Snapshots yellowfive@57: -- This feature snapshots a player's gear/talents/glyphs when entering combat. It is enabled by default. Consumers yellowfive@57: -- of this library can create a setting to enable/disable it as desired per a user setting. yellowfive@57: -- yellowfive@57: -- You should register for the AMR_SNAPSHOT_STATE_CHANGED message (sent via AceEvent-3.0 messaging) to ensure that yellowfive@57: -- your addon settings stay in sync with any other addon that may also be trying to control the enabled state. yellowfive@57: -- yellowfive@57: -- Note that if a user has the main AMR addon installed, it will always enable snapshotting, and override any attempt yellowfive@57: -- to disable it by immediately re-enabling it and thus re-triggering AMR_SNAPSHOT_STATE_CHANGED. yellowfive@57: ---------------------------------------------------------------------------------------------------------------------- yellowfive@57: Amr._snapshotEnabled = true yellowfive@57: yellowfive@57: -- Enable snapshotting of character data when entering combat. Sends this player's character data to anyone logging with the AskMrRobot addon. yellowfive@57: function Amr:EnableSnapshots() yellowfive@57: self._snapshotEnabled = true yellowfive@57: self:SendMessage("AMR_SNAPSHOT_STATE_CHANGED", self._snapshotEnabled) yellowfive@57: end yellowfive@57: yellowfive@57: -- Disable snapshotting of character data when entering combat. yellowfive@57: function Amr:DisableSnapshots() yellowfive@57: self._snapshotEnabled = false yellowfive@57: self:SendMessage("AMR_SNAPSHOT_STATE_CHANGED", self._snapshotEnabled) yellowfive@57: end yellowfive@57: yellowfive@57: function Amr:IsSnapshotEnabled() yellowfive@57: return self._snapshotEnabled yellowfive@57: end yellowfive@57: yellowfive@57: yellowfive@57: function Amr:PLAYER_REGEN_DISABLED() yellowfive@57: --function Amr:GARRISON_MISSION_NPC_OPENED() yellowfive@57: yellowfive@57: -- send data about this character when a player enters combat in a supported zone yellowfive@57: if self._snapshotEnabled and Amr.IsSupportedInstance() then yellowfive@57: local t = time() yellowfive@57: local player = self:GetPlayerData() yellowfive@57: local msg = self:SerializePlayerData(player) yellowfive@57: msg = string.format("%s\r%s\n%s\n%s\n%s\n%s", MINOR, t, player.Region, player.Realm, player.Name, msg) yellowfive@57: yellowfive@57: self:SendCommMessage(Amr.ChatPrefix, msg, "RAID") yellowfive@57: end yellowfive@57: end yellowfive@57: yellowfive@57: Amr:RegisterEvent("PLAYER_REGEN_DISABLED") yellowfive@57: --Amr:RegisterEvent("GARRISON_MISSION_NPC_OPENED") -- for debugging, fire this event when open mission table