Mercurial > wow > askmrrobot
comparison AskMrRobot-Serializer/AskMrRobot-Serializer.lua @ 57:01b63b8ed811 v21
total rewrite to version 21
| author | yellowfive |
|---|---|
| date | Fri, 05 Jun 2015 11:05:15 -0700 |
| parents | |
| children | ee701ce45354 |
comparison
equal
deleted
inserted
replaced
| 56:75431c084aa0 | 57:01b63b8ed811 |
|---|---|
| 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. | |
| 3 | |
| 4 local MAJOR, MINOR = "AskMrRobot-Serializer", 21 | |
| 5 local Amr, oldminor = LibStub:NewLibrary(MAJOR, MINOR) | |
| 6 | |
| 7 if not Amr then return end -- already loaded by something else | |
| 8 | |
| 9 -- event and comm used for player snapshotting on entering combat | |
| 10 LibStub("AceEvent-3.0"):Embed(Amr) | |
| 11 LibStub("AceComm-3.0"):Embed(Amr) | |
| 12 | |
| 13 ---------------------------------------------------------------------------------------- | |
| 14 -- Constants | |
| 15 ---------------------------------------------------------------------------------------- | |
| 16 | |
| 17 -- prefix used for communicating gear snapshots created by the AMR serializer | |
| 18 Amr.ChatPrefix = "_AMRS" | |
| 19 | |
| 20 -- map of region ids to AMR region names | |
| 21 Amr.RegionNames = { | |
| 22 [1] = "US", | |
| 23 [2] = "KR", | |
| 24 [3] = "EU", | |
| 25 [4] = "TW", | |
| 26 [5] = "CN" | |
| 27 } | |
| 28 | |
| 29 -- map of the skillLine returned by profession API to the AMR profession name | |
| 30 Amr.ProfessionSkillLineToName = { | |
| 31 [794] = "Archaeology", | |
| 32 [171] = "Alchemy", | |
| 33 [164] = "Blacksmithing", | |
| 34 [185] = "Cooking", | |
| 35 [333] = "Enchanting", | |
| 36 [202] = "Engineering", | |
| 37 [129] = "First Aid", | |
| 38 [356] = "Fishing", | |
| 39 [182] = "Herbalism", | |
| 40 [773] = "Inscription", | |
| 41 [755] = "Jewelcrafting", | |
| 42 [165] = "Leatherworking", | |
| 43 [186] = "Mining", | |
| 44 [393] = "Skinning", | |
| 45 [197] = "Tailoring" | |
| 46 } | |
| 47 | |
| 48 -- all slot IDs that we care about, ordered in AMR standard display order | |
| 49 Amr.SlotIds = { 16, 17, 1, 2, 3, 15, 5, 9, 10, 6, 7, 8, 11, 12, 13, 14 } | |
| 50 | |
| 51 Amr.SpecIds = { | |
| 52 [250] = 1, -- DeathKnightBlood | |
| 53 [251] = 2, -- DeathKnightFrost | |
| 54 [252] = 3, -- DeathKnightUnholy | |
| 55 [102] = 4, -- DruidBalance | |
| 56 [103] = 5, -- DruidFeral | |
| 57 [104] = 6, -- DruidGuardian | |
| 58 [105] = 7, -- DruidRestoration | |
| 59 [253] = 8, -- HunterBeastMastery | |
| 60 [254] = 9, -- HunterMarksmanship | |
| 61 [255] = 10, -- HunterSurvival | |
| 62 [62] = 11, -- MageArcane | |
| 63 [63] = 12, -- MageFire | |
| 64 [64] = 13, -- MageFrost | |
| 65 [268] = 14, -- MonkBrewmaster | |
| 66 [270] = 15, -- MonkMistweaver | |
| 67 [269] = 16, -- MonkWindwalker | |
| 68 [65] = 17, -- PaladinHoly | |
| 69 [66] = 18, -- PaladinProtection | |
| 70 [70] = 19, -- PaladinRetribution | |
| 71 [256] = 20, -- PriestDiscipline | |
| 72 [257] = 21, -- PriestHoly | |
| 73 [258] = 22, -- PriestShadow | |
| 74 [259] = 23, -- RogueAssassination | |
| 75 [260] = 24, -- RogueCombat | |
| 76 [261] = 25, -- RogueSubtlety | |
| 77 [262] = 26, -- ShamanElemental | |
| 78 [263] = 27, -- ShamanEnhancement | |
| 79 [264] = 28, -- ShamanRestoration | |
| 80 [265] = 29, -- WarlockAffliction | |
| 81 [266] = 30, -- WarlockDemonology | |
| 82 [267] = 31, -- WarlockDestruction | |
| 83 [71] = 32, -- WarriorArms | |
| 84 [72] = 33, -- WarriorFury | |
| 85 [73] = 34 -- WarriorProtection | |
| 86 } | |
| 87 | |
| 88 Amr.ClassIds = { | |
| 89 ["NONE"] = 0, | |
| 90 ["DEATHKNIGHT"] = 1, | |
| 91 ["DRUID"] = 2, | |
| 92 ["HUNTER"] = 3, | |
| 93 ["MAGE"] = 4, | |
| 94 ["MONK"] = 5, | |
| 95 ["PALADIN"] = 6, | |
| 96 ["PRIEST"] = 7, | |
| 97 ["ROGUE"] = 8, | |
| 98 ["SHAMAN"] = 9, | |
| 99 ["WARLOCK"] = 10, | |
| 100 ["WARRIOR"] = 11, | |
| 101 } | |
| 102 | |
| 103 Amr.ProfessionIds = { | |
| 104 ["None"] = 0, | |
| 105 ["Mining"] = 1, | |
| 106 ["Skinning"] = 2, | |
| 107 ["Herbalism"] = 3, | |
| 108 ["Enchanting"] = 4, | |
| 109 ["Jewelcrafting"] = 5, | |
| 110 ["Engineering"] = 6, | |
| 111 ["Blacksmithing"] = 7, | |
| 112 ["Leatherworking"] = 8, | |
| 113 ["Inscription"] = 9, | |
| 114 ["Tailoring"] = 10, | |
| 115 ["Alchemy"] = 11, | |
| 116 ["Fishing"] = 12, | |
| 117 ["Cooking"] = 13, | |
| 118 ["First Aid"] = 14, | |
| 119 ["Archaeology"] = 15 | |
| 120 } | |
| 121 | |
| 122 Amr.RaceIds = { | |
| 123 ["None"] = 0, | |
| 124 ["BloodElf"] = 1, | |
| 125 ["Draenei"] = 2, | |
| 126 ["Dwarf"] = 3, | |
| 127 ["Gnome"] = 4, | |
| 128 ["Human"] = 5, | |
| 129 ["NightElf"] = 6, | |
| 130 ["Orc"] = 7, | |
| 131 ["Tauren"] = 8, | |
| 132 ["Troll"] = 9, | |
| 133 ["Scourge"] = 10, | |
| 134 ["Undead"] = 10, | |
| 135 ["Goblin"] = 11, | |
| 136 ["Worgen"] = 12, | |
| 137 ["Pandaren"] = 13 | |
| 138 } | |
| 139 | |
| 140 Amr.FactionIds = { | |
| 141 ["None"] = 0, | |
| 142 ["Alliance"] = 1, | |
| 143 ["Horde"] = 2 | |
| 144 } | |
| 145 | |
| 146 Amr.InstanceIds = { | |
| 147 Auchindoun = 1182, | |
| 148 BloodmaulSlagMines = 1175, | |
| 149 GrimrailDepot = 1208, | |
| 150 IronDocks = 1195, | |
| 151 ShadowmoonBurialGrounds = 1176, | |
| 152 Skyreach = 1209, | |
| 153 TheEverbloom = 1279, | |
| 154 UpperBlackrockSpire = 1358, | |
| 155 Highmaul = 1228, | |
| 156 BlackrockFoundry = 1205 | |
| 157 } | |
| 158 | |
| 159 -- instances that AskMrRobot currently supports logging for | |
| 160 Amr.SupportedInstanceIds = { | |
| 161 --[1182] = true, | |
| 162 --[1175] = true, | |
| 163 --[1208] = true, | |
| 164 --[1195] = true, | |
| 165 --[1176] = true, | |
| 166 --[1209] = true, | |
| 167 --[1279] = true, | |
| 168 --[1358] = true, | |
| 169 [1228] = true, | |
| 170 [1205] = true | |
| 171 } | |
| 172 | |
| 173 Amr.SPEC_WARRIORPROTECTION = 34 | |
| 174 Amr.SUBSPEC_WARRIORPROTECTION = 38 | |
| 175 Amr.SUBSPEC_WARRIORPROTECTIONGLAD = 39 | |
| 176 Amr.SPELL_ID_GLADIATOR_STANCE = 156291 | |
| 177 Amr.SPELL_ID_DEFENSIVE_STANCE = 71 | |
| 178 | |
| 179 -- IDs of set tokens that we would care about in a player's inventory | |
| 180 Amr.SetTokenIds = { | |
| 181 [120285] = true, | |
| 182 [120284] = true, | |
| 183 [120283] = true, | |
| 184 [120282] = true, | |
| 185 [120281] = true, | |
| 186 [120280] = true, | |
| 187 [120279] = true, | |
| 188 [120278] = true, | |
| 189 [120277] = true, | |
| 190 [120256] = true, | |
| 191 [120255] = true, | |
| 192 [120254] = true, | |
| 193 [120253] = true, | |
| 194 [120252] = true, | |
| 195 [120251] = true, | |
| 196 [120250] = true, | |
| 197 [120249] = true, | |
| 198 [120248] = true, | |
| 199 [120247] = true, | |
| 200 [120246] = true, | |
| 201 [120245] = true, | |
| 202 [120244] = true, | |
| 203 [120243] = true, | |
| 204 [120242] = true, | |
| 205 [120241] = true, | |
| 206 [120240] = true, | |
| 207 [120239] = true, | |
| 208 [120238] = true, | |
| 209 [120237] = true, | |
| 210 [120236] = true, | |
| 211 [120235] = true, | |
| 212 [120234] = true, | |
| 213 [120233] = true, | |
| 214 [120232] = true, | |
| 215 [120231] = true, | |
| 216 [120230] = true, | |
| 217 [120229] = true, | |
| 218 [120228] = true, | |
| 219 [120227] = true, | |
| 220 [120226] = true, | |
| 221 [120225] = true, | |
| 222 [120224] = true, | |
| 223 [120223] = true, | |
| 224 [120222] = true, | |
| 225 [120221] = true, | |
| 226 [120220] = true, | |
| 227 [120219] = true, | |
| 228 [120218] = true, | |
| 229 [120217] = true, | |
| 230 [120216] = true, | |
| 231 [120215] = true, | |
| 232 [120214] = true, | |
| 233 [120213] = true, | |
| 234 [120212] = true, | |
| 235 [120211] = true, | |
| 236 [120210] = true, | |
| 237 [120209] = true, | |
| 238 [120208] = true, | |
| 239 [120207] = true, | |
| 240 [120206] = true, | |
| 241 [119323] = true, | |
| 242 [119322] = true, | |
| 243 [119321] = true, | |
| 244 [119320] = true, | |
| 245 [119319] = true, | |
| 246 [119318] = true, | |
| 247 [119316] = true, | |
| 248 [119315] = true, | |
| 249 [119314] = true, | |
| 250 [119313] = true, | |
| 251 [119312] = true, | |
| 252 [119311] = true, | |
| 253 [119310] = true, | |
| 254 [119309] = true, | |
| 255 [119308] = true, | |
| 256 [119307] = true, | |
| 257 [119306] = true, | |
| 258 [119305] = true, | |
| 259 [105868] = true, | |
| 260 [105867] = true, | |
| 261 [105866] = true, | |
| 262 [105865] = true, | |
| 263 [105864] = true, | |
| 264 [105863] = true, | |
| 265 [105862] = true, | |
| 266 [105861] = true, | |
| 267 [105860] = true, | |
| 268 [105859] = true, | |
| 269 [105858] = true, | |
| 270 [105857] = true, | |
| 271 [99756] = true, | |
| 272 [99755] = true, | |
| 273 [99754] = true, | |
| 274 [99753] = true, | |
| 275 [99752] = true, | |
| 276 [99751] = true, | |
| 277 [99750] = true, | |
| 278 [99749] = true, | |
| 279 [99748] = true, | |
| 280 [99747] = true, | |
| 281 [99746] = true, | |
| 282 [99745] = true, | |
| 283 [99744] = true, | |
| 284 [99743] = true, | |
| 285 [99742] = true, | |
| 286 [99740] = true, | |
| 287 [99739] = true, | |
| 288 [99738] = true, | |
| 289 [99737] = true, | |
| 290 [99736] = true, | |
| 291 [99735] = true, | |
| 292 [99734] = true, | |
| 293 [99733] = true, | |
| 294 [99732] = true, | |
| 295 [99731] = true, | |
| 296 [99730] = true, | |
| 297 [99729] = true, | |
| 298 [99728] = true, | |
| 299 [99727] = true, | |
| 300 [99726] = true, | |
| 301 [99725] = true, | |
| 302 [99724] = true, | |
| 303 [99723] = true, | |
| 304 [99722] = true, | |
| 305 [99721] = true, | |
| 306 [99720] = true, | |
| 307 [99719] = true, | |
| 308 [99718] = true, | |
| 309 [99717] = true, | |
| 310 [99716] = true, | |
| 311 [99715] = true, | |
| 312 [99714] = true, | |
| 313 [99713] = true, | |
| 314 [99712] = true, | |
| 315 [99711] = true, | |
| 316 [99710] = true, | |
| 317 [99709] = true, | |
| 318 [99708] = true, | |
| 319 [99707] = true, | |
| 320 [99706] = true, | |
| 321 [99705] = true, | |
| 322 [99704] = true, | |
| 323 [99703] = true, | |
| 324 [99702] = true, | |
| 325 [99701] = true, | |
| 326 [99700] = true, | |
| 327 [99699] = true, | |
| 328 [99698] = true, | |
| 329 [99697] = true, | |
| 330 [99696] = true, | |
| 331 [99695] = true, | |
| 332 [99694] = true, | |
| 333 [99693] = true, | |
| 334 [99692] = true, | |
| 335 [99691] = true, | |
| 336 [99690] = true, | |
| 337 [99689] = true, | |
| 338 [99688] = true, | |
| 339 [99687] = true, | |
| 340 [99686] = true, | |
| 341 [99685] = true, | |
| 342 [99684] = true, | |
| 343 [99683] = true, | |
| 344 [99682] = true, | |
| 345 [99681] = true, | |
| 346 [99680] = true, | |
| 347 [99679] = true, | |
| 348 [99678] = true, | |
| 349 [99677] = true, | |
| 350 [99676] = true, | |
| 351 [99675] = true, | |
| 352 [99674] = true, | |
| 353 [99673] = true, | |
| 354 [99672] = true, | |
| 355 [99671] = true, | |
| 356 [99670] = true, | |
| 357 [99669] = true, | |
| 358 [99668] = true, | |
| 359 [99667] = true, | |
| 360 [96701] = true, | |
| 361 [96700] = true, | |
| 362 [96699] = true, | |
| 363 [96633] = true, | |
| 364 [96632] = true, | |
| 365 [96631] = true, | |
| 366 [96625] = true, | |
| 367 [96624] = true, | |
| 368 [96623] = true, | |
| 369 [96601] = true, | |
| 370 [96600] = true, | |
| 371 [96599] = true, | |
| 372 [96568] = true, | |
| 373 [96567] = true, | |
| 374 [96566] = true, | |
| 375 [95957] = true, | |
| 376 [95956] = true, | |
| 377 [95955] = true, | |
| 378 [95889] = true, | |
| 379 [95888] = true, | |
| 380 [95887] = true, | |
| 381 [95881] = true, | |
| 382 [95880] = true, | |
| 383 [95879] = true, | |
| 384 [95857] = true, | |
| 385 [95856] = true, | |
| 386 [95855] = true, | |
| 387 [95824] = true, | |
| 388 [95823] = true, | |
| 389 [95822] = true, | |
| 390 [95583] = true, | |
| 391 [95582] = true, | |
| 392 [95581] = true, | |
| 393 [95580] = true, | |
| 394 [95579] = true, | |
| 395 [95578] = true, | |
| 396 [95577] = true, | |
| 397 [95576] = true, | |
| 398 [95575] = true, | |
| 399 [95574] = true, | |
| 400 [95573] = true, | |
| 401 [95572] = true, | |
| 402 [95571] = true, | |
| 403 [95570] = true, | |
| 404 [95569] = true, | |
| 405 [89278] = true, | |
| 406 [89277] = true, | |
| 407 [89276] = true, | |
| 408 [89275] = true, | |
| 409 [89274] = true, | |
| 410 [89273] = true, | |
| 411 [89272] = true, | |
| 412 [89271] = true, | |
| 413 [89270] = true, | |
| 414 [89269] = true, | |
| 415 [89268] = true, | |
| 416 [89267] = true, | |
| 417 [89266] = true, | |
| 418 [89265] = true, | |
| 419 [89264] = true, | |
| 420 [89263] = true, | |
| 421 [89262] = true, | |
| 422 [89261] = true, | |
| 423 [89260] = true, | |
| 424 [89259] = true, | |
| 425 [89258] = true, | |
| 426 [89257] = true, | |
| 427 [89256] = true, | |
| 428 [89255] = true, | |
| 429 [89254] = true, | |
| 430 [89253] = true, | |
| 431 [89252] = true, | |
| 432 [89251] = true, | |
| 433 [89250] = true, | |
| 434 [89249] = true, | |
| 435 [89248] = true, | |
| 436 [89247] = true, | |
| 437 [89246] = true, | |
| 438 [89245] = true, | |
| 439 [89244] = true, | |
| 440 [89243] = true, | |
| 441 [89242] = true, | |
| 442 [89241] = true, | |
| 443 [89240] = true, | |
| 444 [89239] = true, | |
| 445 [89238] = true, | |
| 446 [89237] = true, | |
| 447 [89236] = true, | |
| 448 [89235] = true, | |
| 449 [89234] = true, | |
| 450 [78876] = true, | |
| 451 [78875] = true, | |
| 452 [78874] = true, | |
| 453 [78873] = true, | |
| 454 [78872] = true, | |
| 455 [78871] = true, | |
| 456 [78867] = true, | |
| 457 [78866] = true, | |
| 458 [78865] = true, | |
| 459 [78864] = true, | |
| 460 [78863] = true, | |
| 461 [78862] = true, | |
| 462 [78861] = true, | |
| 463 [78860] = true, | |
| 464 [78859] = true, | |
| 465 [78858] = true, | |
| 466 [78857] = true, | |
| 467 [78856] = true, | |
| 468 [78855] = true, | |
| 469 [78854] = true, | |
| 470 [78853] = true, | |
| 471 [78849] = true, | |
| 472 [78848] = true, | |
| 473 [78847] = true, | |
| 474 [78184] = true, | |
| 475 [78183] = true, | |
| 476 [78181] = true, | |
| 477 [78180] = true, | |
| 478 [78179] = true, | |
| 479 [78178] = true, | |
| 480 [78176] = true, | |
| 481 [78175] = true, | |
| 482 [78174] = true, | |
| 483 [78173] = true, | |
| 484 [78171] = true, | |
| 485 [78170] = true, | |
| 486 [71687] = true, | |
| 487 [71686] = true, | |
| 488 [71685] = true, | |
| 489 [71683] = true, | |
| 490 [71682] = true, | |
| 491 [71680] = true, | |
| 492 [71679] = true, | |
| 493 [71678] = true, | |
| 494 [71676] = true, | |
| 495 [71675] = true, | |
| 496 [71673] = true, | |
| 497 [71672] = true, | |
| 498 [71671] = true, | |
| 499 [71669] = true, | |
| 500 [71668] = true, | |
| 501 [67431] = true, | |
| 502 [67430] = true, | |
| 503 [67429] = true, | |
| 504 [67428] = true, | |
| 505 [67427] = true, | |
| 506 [67426] = true, | |
| 507 [67425] = true, | |
| 508 [67424] = true, | |
| 509 [67423] = true, | |
| 510 [66998] = true, | |
| 511 [65089] = true, | |
| 512 [65088] = true, | |
| 513 [65087] = true, | |
| 514 [63684] = true, | |
| 515 [63683] = true, | |
| 516 [63682] = true, | |
| 517 [45652] = true, | |
| 518 [45651] = true, | |
| 519 [45650] = true, | |
| 520 [45649] = true, | |
| 521 [45648] = true, | |
| 522 [45647] = true, | |
| 523 [45643] = true, | |
| 524 [45642] = true, | |
| 525 [45641] = true, | |
| 526 [40630] = true, | |
| 527 [40629] = true, | |
| 528 [40628] = true, | |
| 529 [40621] = true, | |
| 530 [40620] = true, | |
| 531 [40619] = true, | |
| 532 [40618] = true, | |
| 533 [40617] = true, | |
| 534 [40616] = true, | |
| 535 [34544] = true, | |
| 536 [31100] = true, | |
| 537 [31099] = true, | |
| 538 [31098] = true, | |
| 539 [31097] = true, | |
| 540 [31096] = true, | |
| 541 [31095] = true, | |
| 542 [30247] = true, | |
| 543 [30246] = true, | |
| 544 [30245] = true, | |
| 545 [30244] = true, | |
| 546 [30243] = true, | |
| 547 [30242] = true, | |
| 548 [29767] = true, | |
| 549 [29766] = true, | |
| 550 [29765] = true, | |
| 551 [29761] = true, | |
| 552 [29760] = true, | |
| 553 [29759] = true | |
| 554 } | |
| 555 | |
| 556 | |
| 557 ---------------------------------------------------------------------------------------- | |
| 558 -- Public Utility Methods | |
| 559 ---------------------------------------------------------------------------------------- | |
| 560 | |
| 561 -- item link format: |cffa335ee|Hitem:itemID:enchant:gem1:gem2:gem3:gem4:suffixID:uniqueID:level:upgradeId:instanceDifficultyID:numBonusIDs:bonusID1:bonusID2...|h[item name]|h|r | |
| 562 -- get an object with all of the parts of the item link format that we care about | |
| 563 function Amr.ParseItemLink(itemLink) | |
| 564 if not itemLink then return nil end | |
| 565 | |
| 566 local str = string.match(itemLink, "|Hitem:([\-%d:]+)|") | |
| 567 if not str then return nil end | |
| 568 | |
| 569 local parts = { strsplit(":", str) } | |
| 570 | |
| 571 local item = {} | |
| 572 item.id = tonumber(parts[1]) | |
| 573 item.enchantId = tonumber(parts[2]) | |
| 574 item.gemIds = { tonumber(parts[3]), tonumber(parts[4]), tonumber(parts[5]), tonumber(parts[6]) } | |
| 575 item.suffixId = math.abs(tonumber(parts[7])) -- convert suffix to positive number, that's what we use in our code | |
| 576 --item.uniqueId = tonumber(parts[8]) | |
| 577 --item.level = tonumber(parts[9]) | |
| 578 item.upgradeId = tonumber(parts[10]) | |
| 579 --item.difficultyId = tonumber(parts[11]) | |
| 580 | |
| 581 local numBonuses = tonumber(parts[12]) | |
| 582 if numBonuses and numBonuses > 0 then | |
| 583 item.bonusIds = {} | |
| 584 for i = 13, 12 + numBonuses do | |
| 585 table.insert(item.bonusIds, tonumber(parts[i])) | |
| 586 end | |
| 587 table.sort(item.bonusIds) | |
| 588 end | |
| 589 | |
| 590 return item | |
| 591 end | |
| 592 | |
| 593 -- returns true if this is an instance that AskMrRobot supports for logging | |
| 594 function Amr.IsSupportedInstanceId(instanceMapID) | |
| 595 if Amr.SupportedInstanceIds[tonumber(instanceMapID)] then | |
| 596 return true | |
| 597 else | |
| 598 return false | |
| 599 end | |
| 600 end | |
| 601 | |
| 602 -- returns true if currently in a supported instance for logging | |
| 603 function Amr.IsSupportedInstance() | |
| 604 local zone, _, difficultyIndex, _, _, _, _, instanceMapID = GetInstanceInfo() | |
| 605 return Amr.IsSupportedInstanceId(instanceMapID) | |
| 606 end | |
| 607 | |
| 608 | |
| 609 ---------------------------------------------------------------------------------------- | |
| 610 -- Character Reading | |
| 611 ---------------------------------------------------------------------------------------- | |
| 612 | |
| 613 local function readProfessionInfo(prof, ret) | |
| 614 if prof then | |
| 615 local name, icon, skillLevel, maxSkillLevel, numAbilities, spelloffset, skillLine, skillModifier = GetProfessionInfo(prof); | |
| 616 if Amr.ProfessionSkillLineToName[skillLine] ~= nil then | |
| 617 ret.Professions[Amr.ProfessionSkillLineToName[skillLine]] = skillLevel; | |
| 618 end | |
| 619 end | |
| 620 end | |
| 621 | |
| 622 local function getSpecId(specGroup) | |
| 623 local spec = GetSpecialization(false, false, specGroup); | |
| 624 return spec and GetSpecializationInfo(spec); | |
| 625 end | |
| 626 | |
| 627 local function getTalents(specGroup) | |
| 628 local talentInfo = {} | |
| 629 local maxTiers = 7 | |
| 630 for tier = 1, maxTiers do | |
| 631 for col = 1, 3 do | |
| 632 local id, name, texture, selected, available = GetTalentInfo(tier, col, specGroup) | |
| 633 if selected then | |
| 634 talentInfo[tier] = col | |
| 635 end | |
| 636 end | |
| 637 end | |
| 638 | |
| 639 local str = "" | |
| 640 for i = 1, maxTiers do | |
| 641 if talentInfo[i] then | |
| 642 str = str .. talentInfo[i] | |
| 643 else | |
| 644 str = str .. '0' | |
| 645 end | |
| 646 end | |
| 647 | |
| 648 return str | |
| 649 end | |
| 650 | |
| 651 local function getGlyphs(specGroup) | |
| 652 local glyphs = {} | |
| 653 for i = 1, NUM_GLYPH_SLOTS do | |
| 654 local _, _, _, glyphSpellID, _, glyphID = GetGlyphSocketInfo(i, specGroup) | |
| 655 if (glyphID) then | |
| 656 table.insert(glyphs, glyphSpellID) | |
| 657 end | |
| 658 end | |
| 659 return glyphs; | |
| 660 end | |
| 661 | |
| 662 -- get specs, talents, and glyphs | |
| 663 local function readSpecs(ret, subspecs) | |
| 664 | |
| 665 for group = 1, GetNumSpecGroups() do | |
| 666 -- spec, convert game spec id to one of our spec ids | |
| 667 local specId = getSpecId(group) | |
| 668 if specId then | |
| 669 ret.Specs[group] = Amr.SpecIds[specId] | |
| 670 | |
| 671 -- if this is a protection warrior, use buffs to determine subspec | |
| 672 if ret.Specs[group] == Amr.SPEC_WARRIORPROTECTION then | |
| 673 local subspec = 0 | |
| 674 | |
| 675 if ret.ActiveSpec ~= group then | |
| 676 -- this spec isn't active, so we can't use current buffs to determine spec, see if any old data is compatible | |
| 677 if subspecs and (subspecs[group] == Amr.SUBSPEC_WARRIORPROTECTION or subspecs[group] == Amr.SUBSPEC_WARRIORPROTECTIONGLAD) then | |
| 678 subspec = subspecs[group] | |
| 679 end | |
| 680 else | |
| 681 for i=1,40 do | |
| 682 local name,_,_,_,_,_,_,_,_,_,spellId = UnitAura("player", i, "HELPFUL") | |
| 683 if not name then break end | |
| 684 | |
| 685 if spellId == Amr.SPELL_ID_DEFENSIVE_STANCE then | |
| 686 subspec = Amr.SUBSPEC_WARRIORPROTECTION | |
| 687 break | |
| 688 elseif spellId == Amr.SPELL_ID_GLADIATOR_STANCE then | |
| 689 subspec = Amr.SUBSPEC_WARRIORPROTECTIONGLAD | |
| 690 break | |
| 691 end | |
| 692 end | |
| 693 end | |
| 694 | |
| 695 if subspec == 0 then | |
| 696 ret.SubSpecs[group] = nil | |
| 697 else | |
| 698 ret.SubSpecs[group] = subspec | |
| 699 end | |
| 700 end | |
| 701 else | |
| 702 ret.Specs[group] = 0 | |
| 703 end | |
| 704 | |
| 705 ret.Talents[group] = getTalents(group) | |
| 706 ret.Glyphs[group] = getGlyphs(group) | |
| 707 end | |
| 708 end | |
| 709 | |
| 710 -- get currently equipped items, store with currently active spec | |
| 711 local function readEquippedItems(ret) | |
| 712 local equippedItems = {}; | |
| 713 for slotNum = 1, #Amr.SlotIds do | |
| 714 local slotId = Amr.SlotIds[slotNum] | |
| 715 local itemLink = GetInventoryItemLink("player", slotId) | |
| 716 if itemLink then | |
| 717 equippedItems[slotId] = itemLink | |
| 718 end | |
| 719 end | |
| 720 | |
| 721 -- store last-seen equipped gear for each spec | |
| 722 ret.Equipped[GetActiveSpecGroup()] = equippedItems | |
| 723 end | |
| 724 | |
| 725 -- Get all data about the player as an object, includes: | |
| 726 -- serializer version | |
| 727 -- region/realm/name | |
| 728 -- guild | |
| 729 -- race | |
| 730 -- faction | |
| 731 -- level | |
| 732 -- professions | |
| 733 -- spec/talent/glyphs for both specs | |
| 734 -- equipped gear for the current spec | |
| 735 -- | |
| 736 function Amr:GetPlayerData(subspecs) | |
| 737 | |
| 738 local ret = {} | |
| 739 | |
| 740 ret.Region = Amr.RegionNames[GetCurrentRegion()] | |
| 741 ret.Realm = GetRealmName() | |
| 742 ret.Name = UnitName("player") | |
| 743 ret.Guild = GetGuildInfo("player") | |
| 744 ret.ActiveSpec = GetActiveSpecGroup() | |
| 745 ret.Level = UnitLevel("player"); | |
| 746 | |
| 747 local cls, clsEn = UnitClass("player") | |
| 748 ret.Class = clsEn; | |
| 749 | |
| 750 local race, raceEn = UnitRace("player") | |
| 751 ret.Race = raceEn; | |
| 752 ret.Faction = UnitFactionGroup("player") | |
| 753 | |
| 754 ret.Professions = {}; | |
| 755 local prof1, prof2, archaeology, fishing, cooking, firstAid = GetProfessions(); | |
| 756 readProfessionInfo(prof1, ret) | |
| 757 readProfessionInfo(prof2, ret) | |
| 758 readProfessionInfo(archaeology, ret) | |
| 759 readProfessionInfo(fishing, ret) | |
| 760 readProfessionInfo(cooking, ret) | |
| 761 readProfessionInfo(firstAid, ret) | |
| 762 | |
| 763 ret.Specs = {} | |
| 764 ret.SubSpecs = {} -- only filled in for ambiguous cases, right now just prot/glad warrior | |
| 765 ret.Talents = {} | |
| 766 ret.Glyphs = {} | |
| 767 readSpecs(ret, subspecs) | |
| 768 | |
| 769 ret.Equipped = {} | |
| 770 readEquippedItems(ret) | |
| 771 | |
| 772 return ret | |
| 773 end | |
| 774 | |
| 775 | |
| 776 ---------------------------------------------------------------------------------------- | |
| 777 -- Serialization | |
| 778 ---------------------------------------------------------------------------------------- | |
| 779 | |
| 780 local function toCompressedNumberList(list) | |
| 781 -- ensure the values are numbers, sorted from lowest to highest | |
| 782 local nums = {} | |
| 783 for i, v in ipairs(list) do | |
| 784 table.insert(nums, tonumber(v)) | |
| 785 end | |
| 786 table.sort(nums) | |
| 787 | |
| 788 local ret = {} | |
| 789 local prev = 0 | |
| 790 for i, v in ipairs(nums) do | |
| 791 local diff = v - prev | |
| 792 table.insert(ret, diff) | |
| 793 prev = v | |
| 794 end | |
| 795 | |
| 796 return table.concat(ret, ",") | |
| 797 end | |
| 798 | |
| 799 -- make this utility publicly available | |
| 800 function Amr:ToCompressedNumberList(list) | |
| 801 return toCompressedNumberList(list) | |
| 802 end | |
| 803 | |
| 804 -- appends a list of items to the export | |
| 805 local function appendItemsToExport(fields, itemObjects) | |
| 806 | |
| 807 -- sort by item id so we can compress it more easily | |
| 808 table.sort(itemObjects, function(a, b) return a.id < b.id end) | |
| 809 | |
| 810 -- append to the export string | |
| 811 local prevItemId = 0 | |
| 812 local prevGemId = 0 | |
| 813 local prevEnchantId = 0 | |
| 814 local prevUpgradeId = 0 | |
| 815 local prevBonusId = 0 | |
| 816 for i, itemData in ipairs(itemObjects) do | |
| 817 local itemParts = {} | |
| 818 | |
| 819 table.insert(itemParts, itemData.id - prevItemId) | |
| 820 prevItemId = itemData.id | |
| 821 | |
| 822 if itemData.slot ~= nil then table.insert(itemParts, "s" .. itemData.slot) end | |
| 823 if itemData.suffixId ~= 0 then table.insert(itemParts, "f" .. itemData.suffixId) end | |
| 824 if itemData.upgradeId ~= 0 then | |
| 825 table.insert(itemParts, "u" .. (itemData.upgradeId - prevUpgradeId)) | |
| 826 prevUpgradeId = itemData.upgradeId | |
| 827 end | |
| 828 if itemData.bonusIds then | |
| 829 for bIndex, bValue in ipairs(itemData.bonusIds) do | |
| 830 table.insert(itemParts, "b" .. (bValue - prevBonusId)) | |
| 831 prevBonusId = bValue | |
| 832 end | |
| 833 end | |
| 834 if itemData.gemIds[1] ~= 0 then | |
| 835 table.insert(itemParts, "x" .. (itemData.gemIds[1] - prevGemId)) | |
| 836 prevGemId = itemData.gemIds[1] | |
| 837 end | |
| 838 if itemData.gemIds[2] ~= 0 then | |
| 839 table.insert(itemParts, "y" .. (itemData.gemIds[2] - prevGemId)) | |
| 840 prevGemId = itemData.gemIds[2] | |
| 841 end | |
| 842 if itemData.gemIds[3] ~= 0 then | |
| 843 table.insert(itemParts, "z" .. (itemData.gemIds[3] - prevGemId)) | |
| 844 prevGemId = itemData.gemIds[3] | |
| 845 end | |
| 846 if itemData.enchantId ~= 0 then | |
| 847 table.insert(itemParts, "e" .. (itemData.enchantId - prevEnchantId)) | |
| 848 prevEnchantId = itemData.enchantId | |
| 849 end | |
| 850 | |
| 851 table.insert(fields, table.concat(itemParts, "")) | |
| 852 end | |
| 853 end | |
| 854 | |
| 855 -- Serialize just the identity portion of a player (region/realm/name) in the same format used by the full serialization | |
| 856 function Amr:SerializePlayerIdentity(data) | |
| 857 local fields = {} | |
| 858 table.insert(fields, MINOR) | |
| 859 table.insert(fields, data.Region) | |
| 860 table.insert(fields, data.Realm) | |
| 861 table.insert(fields, data.Name) | |
| 862 return "$" .. table.concat(fields, ";") .. "$" | |
| 863 end | |
| 864 | |
| 865 -- Serialize player data gathered by GetPlayerData. This can be augmented with extra data if desired (augmenting used mainly by AskMrRobot addon). | |
| 866 -- Pass complete = true to do a complete export of this extra information, otherwise it is ignored. | |
| 867 -- Extra data can include: | |
| 868 -- equipped gear for the player's inactive spec, slot id to item link dictionary | |
| 869 -- Reputations | |
| 870 -- BagItems, BankItems, VoidItems, lists of item links | |
| 871 -- | |
| 872 function Amr:SerializePlayerData(data, complete) | |
| 873 | |
| 874 local fields = {} | |
| 875 | |
| 876 -- compressed string uses a fixed order rather than inserting identifiers | |
| 877 table.insert(fields, MINOR) | |
| 878 table.insert(fields, data.Region) | |
| 879 table.insert(fields, data.Realm) | |
| 880 table.insert(fields, data.Name) | |
| 881 | |
| 882 -- guild name | |
| 883 if data.Guild == nil then | |
| 884 table.insert(fields, "") | |
| 885 else | |
| 886 table.insert(fields, data.Guild) | |
| 887 end | |
| 888 | |
| 889 -- race, default to pandaren if we can't read it for some reason | |
| 890 local raceval = Amr.RaceIds[data.Race] | |
| 891 if raceval == nil then raceval = 13 end | |
| 892 table.insert(fields, raceval) | |
| 893 | |
| 894 -- faction, default to alliance if we can't read it for some reason | |
| 895 raceval = Amr.FactionIds[data.Faction] | |
| 896 if raceval == nil then raceval = 1 end | |
| 897 table.insert(fields, raceval) | |
| 898 | |
| 899 table.insert(fields, data.Level) | |
| 900 | |
| 901 local profs = {} | |
| 902 local noprofs = true | |
| 903 if data.Professions then | |
| 904 for k, v in pairs(data.Professions) do | |
| 905 local profval = Amr.ProfessionIds[k] | |
| 906 if profval ~= nil then | |
| 907 noprofs = false | |
| 908 table.insert(profs, profval .. ":" .. v) | |
| 909 end | |
| 910 end | |
| 911 end | |
| 912 | |
| 913 if noprofs then | |
| 914 table.insert(profs, "0:0") | |
| 915 end | |
| 916 | |
| 917 table.insert(fields, table.concat(profs, ",")) | |
| 918 | |
| 919 -- export specs | |
| 920 table.insert(fields, data.ActiveSpec) | |
| 921 for spec = 1, 2 do | |
| 922 if data.Specs[spec] and (complete or spec == data.ActiveSpec) then | |
| 923 table.insert(fields, ".s" .. spec) -- indicates the start of a spec block | |
| 924 | |
| 925 -- we use subspec for some ambiguous specs like prot/glad warrior | |
| 926 if data.SubSpecs[spec] then | |
| 927 table.insert(fields, string.format("s%s", data.SubSpecs[spec])) | |
| 928 else | |
| 929 table.insert(fields, data.Specs[spec]) | |
| 930 end | |
| 931 | |
| 932 table.insert(fields, data.Talents[spec]) | |
| 933 table.insert(fields, toCompressedNumberList(data.Glyphs[spec])) | |
| 934 end | |
| 935 end | |
| 936 | |
| 937 -- export equipped gear | |
| 938 if data.Equipped then | |
| 939 for spec = 1, 2 do | |
| 940 if data.Equipped[spec] and (complete or spec == data.ActiveSpec) then | |
| 941 table.insert(fields, ".q" .. spec) -- indicates the start of an equipped gear block | |
| 942 | |
| 943 local itemObjects = {} | |
| 944 for k, v in pairs(data.Equipped[spec]) do | |
| 945 local itemData = Amr.ParseItemLink(v) | |
| 946 itemData.slot = k | |
| 947 table.insert(itemObjects, itemData) | |
| 948 end | |
| 949 | |
| 950 appendItemsToExport(fields, itemObjects) | |
| 951 end | |
| 952 end | |
| 953 end | |
| 954 | |
| 955 -- if doing a complete export, include reputations and bank/bag items too | |
| 956 if complete then | |
| 957 | |
| 958 -- export reputations | |
| 959 local reps = {} | |
| 960 local noreps = true | |
| 961 if data.Reputations then | |
| 962 for k, v in pairs(data.Reputations) do | |
| 963 noreps = false | |
| 964 table.insert(reps, k .. ":" .. v) | |
| 965 end | |
| 966 end | |
| 967 if noreps then | |
| 968 table.insert(reps, "_") | |
| 969 end | |
| 970 | |
| 971 table.insert(fields, ".r") | |
| 972 table.insert(fields, table.concat(reps, ",")) | |
| 973 | |
| 974 -- export bag and bank | |
| 975 local itemObjects = {} | |
| 976 if data.BagItems then | |
| 977 for i, v in ipairs(data.BagItems) do | |
| 978 local itemData = Amr.ParseItemLink(v) | |
| 979 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then | |
| 980 table.insert(itemObjects, itemData) | |
| 981 end | |
| 982 end | |
| 983 end | |
| 984 if data.BankItems then | |
| 985 for i, v in ipairs(data.BankItems) do | |
| 986 local itemData = Amr.ParseItemLink(v) | |
| 987 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then | |
| 988 table.insert(itemObjects, itemData) | |
| 989 end | |
| 990 end | |
| 991 end | |
| 992 if data.VoidItems then | |
| 993 for i, v in ipairs(data.VoidItems) do | |
| 994 local itemData = Amr.ParseItemLink(v) | |
| 995 if itemData ~= nil and (IsEquippableItem(v) or Amr.SetTokenIds[itemData.id]) then | |
| 996 table.insert(itemObjects, itemData) | |
| 997 end | |
| 998 end | |
| 999 end | |
| 1000 | |
| 1001 table.insert(fields, ".inv") | |
| 1002 appendItemsToExport(fields, itemObjects) | |
| 1003 end | |
| 1004 | |
| 1005 return "$" .. table.concat(fields, ";") .. "$" | |
| 1006 | |
| 1007 end | |
| 1008 | |
| 1009 -- Shortcut for the common use case: serialize the player's currently active setup with no extras. | |
| 1010 function Amr:SerializePlayer() | |
| 1011 local data = self:GetPlayerData() | |
| 1012 return self:SerializePlayerData(data) | |
| 1013 end | |
| 1014 | |
| 1015 | |
| 1016 ---------------------------------------------------------------------------------------------------------------------- | |
| 1017 -- Character Snapshots | |
| 1018 -- This feature snapshots a player's gear/talents/glyphs when entering combat. It is enabled by default. Consumers | |
| 1019 -- of this library can create a setting to enable/disable it as desired per a user setting. | |
| 1020 -- | |
| 1021 -- You should register for the AMR_SNAPSHOT_STATE_CHANGED message (sent via AceEvent-3.0 messaging) to ensure that | |
| 1022 -- your addon settings stay in sync with any other addon that may also be trying to control the enabled state. | |
| 1023 -- | |
| 1024 -- Note that if a user has the main AMR addon installed, it will always enable snapshotting, and override any attempt | |
| 1025 -- to disable it by immediately re-enabling it and thus re-triggering AMR_SNAPSHOT_STATE_CHANGED. | |
| 1026 ---------------------------------------------------------------------------------------------------------------------- | |
| 1027 Amr._snapshotEnabled = true | |
| 1028 | |
| 1029 -- Enable snapshotting of character data when entering combat. Sends this player's character data to anyone logging with the AskMrRobot addon. | |
| 1030 function Amr:EnableSnapshots() | |
| 1031 self._snapshotEnabled = true | |
| 1032 self:SendMessage("AMR_SNAPSHOT_STATE_CHANGED", self._snapshotEnabled) | |
| 1033 end | |
| 1034 | |
| 1035 -- Disable snapshotting of character data when entering combat. | |
| 1036 function Amr:DisableSnapshots() | |
| 1037 self._snapshotEnabled = false | |
| 1038 self:SendMessage("AMR_SNAPSHOT_STATE_CHANGED", self._snapshotEnabled) | |
| 1039 end | |
| 1040 | |
| 1041 function Amr:IsSnapshotEnabled() | |
| 1042 return self._snapshotEnabled | |
| 1043 end | |
| 1044 | |
| 1045 | |
| 1046 function Amr:PLAYER_REGEN_DISABLED() | |
| 1047 --function Amr:GARRISON_MISSION_NPC_OPENED() | |
| 1048 | |
| 1049 -- send data about this character when a player enters combat in a supported zone | |
| 1050 if self._snapshotEnabled and Amr.IsSupportedInstance() then | |
| 1051 local t = time() | |
| 1052 local player = self:GetPlayerData() | |
| 1053 local msg = self:SerializePlayerData(player) | |
| 1054 msg = string.format("%s\r%s\n%s\n%s\n%s\n%s", MINOR, t, player.Region, player.Realm, player.Name, msg) | |
| 1055 | |
| 1056 self:SendCommMessage(Amr.ChatPrefix, msg, "RAID") | |
| 1057 end | |
| 1058 end | |
| 1059 | |
| 1060 Amr:RegisterEvent("PLAYER_REGEN_DISABLED") | |
| 1061 --Amr:RegisterEvent("GARRISON_MISSION_NPC_OPENED") -- for debugging, fire this event when open mission table |
