public static void Test_ConvertUnitFieldPlayer_Converts_All_Values([Range((int)EObjectFields_Vanilla.OBJECT_END, (int)EUnitFields_Vanilla.PLAYER_END - 1)] int fieldNumber) { //arrange EUnitFields_Vanilla vanillaUnitField = (EUnitFields_Vanilla)fieldNumber; //act bool?result = null; int shiftValue = 0; Assert.DoesNotThrow(() => result = VanillaToWotlkConverter.ConvertUpdateFieldsPlayer(vanillaUnitField, out shiftValue), $"Field: {fieldNumber}:{vanillaUnitField}:{fieldNumber:X} is not converted."); int newFieldNumber = (shiftValue + fieldNumber); //Assert Assert.NotNull(result); Assert.True(newFieldNumber >= (int)EObjectFields.OBJECT_END && newFieldNumber <= (int)EUnitFields.PLAYER_END); }
private static void InitializeUnitFields(UpdateFieldValueCollection updateCollection, Dictionary <int, int> valuesDictionary, ref int valueIndex, EUnitFields_Vanilla endField = EUnitFields_Vanilla.PLAYER_END) { //subtract 1 from the length size because it's PlayerEnd for (int i = (int)EObjectFields.OBJECT_END; i < updateCollection.UpdateMask.Length && i < (int)endField; i++) { //TODO: Blacklist these fields //UNIT_FIELD_PERSUADED and UNIT_FIELD_PERSUADED +1 //UNIT_CHANNEL_SPELL bool shouldWrite = VanillaToWotlkConverter.ConvertUpdateFieldsPlayer((EUnitFields_Vanilla)i, out int shiftAmount); //We need to track the index of nonwritten to wotlk, but written to the vanilla update block, //so that we may remove the byte chunk that represents the indicies if (updateCollection.UpdateMask[i]) { if (shouldWrite) { try { //We store in a dictionary with the value so that it may be written //TODO: Store only index so we can do quick memcpy to new values array in the future for perf valuesDictionary.Add(i + shiftAmount, updateCollection.UpdateDiffValues.Reinterpret <int>(valueIndex * sizeof(int))); } catch (Exception e) { throw new InvalidOperationException($"Failed to insert: i:{i}:{((EUnitFields_Vanilla)i).ToString()} [{i + shiftAmount}] [{((EUnitFields)(i + shiftAmount)).ToString()}] {updateCollection.UpdateDiffValues.Reinterpret<int>(valueIndex * sizeof(int))} into dictionary. \n\n Exception: {e.Message}", e); } } //no matter what the value index should increase. Because //otherwise it will get descyned from the new values valueIndex++; } } }
/// <summary> /// Produces a shift value offset that can be used to /// map the provided <see cref="unitFieldValue"/> to the /// <see cref="EUnitFields"/> for wotlk. /// </summary> /// <param name="unitFieldValue">The unit field value to shift.</param> /// <param name="shiftValue">The value of the shift.</param> /// <returns>Indicates if the value should be written. This return is important. Don't write it if this returns false.</returns> public static bool ConvertUpdateFieldsPlayer(EUnitFields_Vanilla unitFieldValue, out int shiftValue) { //TODO: Do we need this initial shift anymore? int shiftAmount = 2; bool shouldWrite = true; int i = (int)unitFieldValue; //This is aligned if (i == (int)EUnitFields_Vanilla.UNIT_FIELD_CHANNEL_OBJECT || i == ((int)EUnitFields_Vanilla.UNIT_FIELD_CHANNEL_OBJECT + 1)) { shiftAmount = 0; } else if (i == (int)EUnitFields_Vanilla.UNIT_FIELD_BYTES_0) { //-13 shiftAmount = (int)EUnitFields.UNIT_FIELD_BYTES_0 - (int)EUnitFields_Vanilla.UNIT_FIELD_BYTES_0; } else if (i == (int)EUnitFields_Vanilla.UNIT_CHANNEL_SPELL) { //-122 shiftAmount = 0x0010 - 0x8a; } else if (i < (int)EUnitFields.UNIT_FIELD_CRITTER) { //TODO: This is kinda hacky, it was added after the default shift value shiftAmount = 0; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_CHARMEDBY && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_TARGET + 1) //is a 2 byte field { shiftAmount = (int)EUnitFields.UNIT_FIELD_CHARMEDBY - (int)EUnitFields_Vanilla.UNIT_FIELD_CHARMEDBY; } else if (i == (int)EUnitFields_Vanilla.UNIT_FIELD_PERSUADED || i == (int)EUnitFields_Vanilla.UNIT_FIELD_PERSUADED + 1) //it is a 2 index field { //TODO: What even is this? shouldWrite = false; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_HEALTH && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_POWER5) { shiftAmount = (int)EUnitFields.UNIT_FIELD_HEALTH - (int)EUnitFields_Vanilla.UNIT_FIELD_HEALTH; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_MAXHEALTH && i < (int)EUnitFields_Vanilla.UNIT_FIELD_LEVEL) //keep less than { //4 shiftAmount = (int)EUnitFields.UNIT_FIELD_MAXHEALTH - (int)EUnitFields_Vanilla.UNIT_FIELD_MAXHEALTH; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_LEVEL && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_FACTIONTEMPLATE) { //20 shiftAmount = (int)EUnitFields.UNIT_FIELD_LEVEL - (int)EUnitFields_Vanilla.UNIT_FIELD_LEVEL; } else if (i >= (int)EUnitFields_Vanilla.UNIT_VIRTUAL_ITEM_SLOT_DISPLAY && i < (int)EUnitFields_Vanilla.UNIT_VIRTUAL_ITEM_INFO) { shiftAmount = (int)EUnitFields.UNIT_VIRTUAL_ITEM_SLOT_ID - (int)EUnitFields_Vanilla.UNIT_VIRTUAL_ITEM_SLOT_DISPLAY; } else if (i >= (int)EUnitFields_Vanilla.UNIT_VIRTUAL_ITEM_INFO && i <= (int)EUnitFields_Vanilla.UNIT_VIRTUAL_ITEM_INFO_05) { //Wotlk doesn't have this. shouldWrite = false; } else if (i == (int)EUnitFields_Vanilla.UNIT_FIELD_FLAGS) { //13 shiftAmount = (int)EUnitFields.UNIT_FIELD_FLAGS - (int)EUnitFields_Vanilla.UNIT_FIELD_FLAGS; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_AURA && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_AURAAPPLICATIONS_LAST) { //Wotlk does not have all this aura stuff //It DOES have aura state though. shouldWrite = false; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_AURASTATE && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_BASEATTACKTIME) { //-64 shiftAmount = (int)EUnitFields.UNIT_FIELD_AURASTATE - (int)EUnitFields_Vanilla.UNIT_FIELD_AURASTATE; } else if (i == (int)EUnitFields_Vanilla.UNIT_FIELD_OFFHANDATTACKTIME) { shouldWrite = false; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_RANGEDATTACKTIME && i <= (int)EUnitFields_Vanilla.UNIT_DYNAMIC_FLAGS) { //-64 shiftAmount = 0x003A - 0x7a; } else if (i >= (int)EUnitFields_Vanilla.UNIT_MOD_CAST_SPEED && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_STAT4) { //-65 shiftAmount = (int)EUnitFields.UNIT_MOD_CAST_SPEED - (int)EUnitFields_Vanilla.UNIT_MOD_CAST_SPEED; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_RESISTANCES && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_RESISTANCES_06) { //-56 shiftAmount = (int)EUnitFields.UNIT_FIELD_RESISTANCES - (int)EUnitFields_Vanilla.UNIT_FIELD_RESISTANCES; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_BASE_MANA && i <= (int)EUnitFields_Vanilla.UNIT_FIELD_POWER_COST_MULTIPLIER_06) { //-42 shiftAmount = (int)EUnitFields.UNIT_FIELD_BASE_MANA - (int)EUnitFields_Vanilla.UNIT_FIELD_BASE_MANA; } else if (i >= (int)EUnitFields_Vanilla.UNIT_FIELD_PADDING && i <= (int)EUnitFields_Vanilla.PLAYER_GUILD_TIMESTAMP) { //-40 shiftAmount = (int)EUnitFields.UNIT_FIELD_PADDING - (int)EUnitFields_Vanilla.UNIT_FIELD_PADDING; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_QUEST_LOG_1_1 && i <= (int)EUnitFields_Vanilla.PLAYER_QUEST_LOG_LAST_3) { //TC quests: /*SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET, quest_id); * SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_STATE_OFFSET, 0); * SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET, 0); * SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNTS_OFFSET + 1, 0); * SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET, timer);*/ //Mangos quests: /*SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_ID_OFFSET, quest_id); * SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_COUNT_STATE_OFFSET, 0); * SetUInt32Value(PLAYER_QUEST_LOG_1_1 + slot * MAX_QUEST_OFFSET + QUEST_TIME_OFFSET, timer);*/ //TODO: Handle quests shouldWrite = false; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_VISIBLE_ITEM_1_CREATOR && i <= (int)EUnitFields_Vanilla.PLAYER_VISIBLE_ITEM_LAST_PAD) { //TODO: Handle visible items shouldWrite = false; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_INV_SLOT_HEAD && i <= (int)EUnitFields_Vanilla.PLAYER_FIELD_BANK_SLOT_LAST + 1) //added an extra 1 because it is a 2 slot field { //-162 //Only until the last bank slot. Wotlk doesn't have the same bankslot count. shiftAmount = (int)EUnitFields.PLAYER_FIELD_INV_SLOT_HEAD - (int)EUnitFields_Vanilla.PLAYER_FIELD_INV_SLOT_HEAD; } //TODO: Change this back to EUnitFields_Vanilla.PLAYER_FIELD_BANKBAG_SLOT_LAST after the value is fixed in Mangos/Cmangos else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_BANKBAG_SLOT_1 && i <= (int)EUnitFields_Vanilla.PLAYER_FIELD_BANKBAG_SLOT_LAST + 1) //added an extra 1 beacause it is a 2 slot field { //wotlk has more bank banks so we only send the vanilla data //-154 shiftAmount = (int)EUnitFields.PLAYER_FIELD_BANKBAG_SLOT_1 - (int)EUnitFields_Vanilla.PLAYER_FIELD_BANKBAG_SLOT_1; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_VENDORBUYBACK_SLOT_1 && i <= (int)EUnitFields_Vanilla.PLAYER_FARSIGHT + 1) //farsight is a 2 slot field { //-152 shiftAmount = (int)EUnitFields.PLAYER_FIELD_VENDORBUYBACK_SLOT_1 - (int)EUnitFields_Vanilla.PLAYER_FIELD_VENDORBUYBACK_SLOT_1; } else if (i == (int)EUnitFields_Vanilla.PLAYER_FIELD_COMBO_TARGET || i == (int)EUnitFields_Vanilla.PLAYER_FIELD_COMBO_TARGET + 1) //2 slot field { //TODO: Where is this on 3.3.5?? How is it communicated? shouldWrite = false; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_XP && i <= (int)EUnitFields_Vanilla.PLAYER_PARRY_PERCENTAGE) { //Only until parry. Because after that wotlk expects expertise which vanilla doesn't have //-82 shiftAmount = (int)EUnitFields.PLAYER_XP - (int)EUnitFields_Vanilla.PLAYER_XP; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_CRIT_PERCENTAGE && i <= (int)EUnitFields_Vanilla.PLAYER_RANGED_CRIT_PERCENTAGE) { //Only until PLAYER_RANGED_CRIT_PERCENTAGE, wotlk has a couple of extra crit fields //-80 shiftAmount = (int)EUnitFields.PLAYER_CRIT_PERCENTAGE - (int)EUnitFields_Vanilla.PLAYER_CRIT_PERCENTAGE; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_EXPLORED_ZONES_1 && i < (int)EUnitFields_Vanilla.PLAYER_REST_STATE_EXPERIENCE) { //TODO: Handle explored zones shouldWrite = false; //Don't include rested //We must map the explored //Explored for Wotlk is UNIT_END + 0x037D //but in vanilla it is 0x39b + UNIT_END //-70 shiftAmount = (int)EUnitFields.PLAYER_EXPLORED_ZONES_1 - (int)EUnitFields_Vanilla.PLAYER_EXPLORED_ZONES_1; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_REST_STATE_EXPERIENCE && i <= (int)EUnitFields_Vanilla.PLAYER_FIELD_COINAGE) { //-6 shiftAmount = (int)EUnitFields.PLAYER_REST_STATE_EXPERIENCE - (int)EUnitFields_Vanilla.PLAYER_REST_STATE_EXPERIENCE; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_POSSTAT0 && i <= (int)EUnitFields_Vanilla.PLAYER_FIELD_NEGSTAT4) { //in vanilla these are player only fields //but in trinitycore these are unit fields //so we need to go WAY back and insert these //Don't write pos/neg resist buffs or else a field will be overwritten. //-1088 shiftAmount = (int)EUnitFields.UNIT_FIELD_POSSTAT0 - (int)EUnitFields_Vanilla.PLAYER_FIELD_POSSTAT0; Console.WriteLine($"****Shift for POSSTAT: {shiftAmount}********"); } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_RESISTANCEBUFFMODSPOSITIVE && i < (int)EUnitFields_Vanilla.PLAYER_FIELD_MOD_DAMAGE_DONE_POS) //keep less than: PLAYER_FIELD_RESISTANCEBUFFMODSNEGATIVE is 7 indices { //-1081 shiftAmount = (int)EUnitFields.UNIT_FIELD_RESISTANCEBUFFMODSPOSITIVE - (int)EUnitFields_Vanilla.PLAYER_FIELD_RESISTANCEBUFFMODSPOSITIVE; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_MOD_DAMAGE_DONE_POS && i < (int)EUnitFields_Vanilla.PLAYER_FIELD_BYTES) //keep less than, we need all 6 indicies after PCT { //-30 //Stop after DONE_PCT because healing fields are next in wotlk but vanilla doesn't have them. shiftAmount = (int)EUnitFields.PLAYER_FIELD_MOD_DAMAGE_DONE_POS - (int)EUnitFields_Vanilla.PLAYER_FIELD_MOD_DAMAGE_DONE_POS; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_BYTES && i < (int)EUnitFields_Vanilla.PLAYER_FIELD_SESSION_KILLS) //keep less than { //-25 shiftAmount = (int)EUnitFields.PLAYER_FIELD_BYTES - (int)EUnitFields_Vanilla.PLAYER_FIELD_BYTES; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_SESSION_KILLS && i <= (int)EUnitFields_Vanilla.PLAYER_FIELD_LAST_WEEK_RANK) { //TODO: How should we handle Honor and stuff? shouldWrite = false; } else if (i >= (int)EUnitFields_Vanilla.PLAYER_FIELD_BYTES2 && i < (int)EUnitFields_Vanilla.PLAYER_END) { //This is the last fields we will write because it goes all the way to combat_rating_20 //The issue after this, and it may or may not be handled by the time you read this, is that //there are many potentially important player fields after this in wotlk. //TODO: /* * * PLAYER_FIELD_ARENA_TEAM_INFO_1_1 = UNIT_END + 0x0454, // Size: 21, Type: INT, Flags: PRIVATE * PLAYER_FIELD_HONOR_CURRENCY = UNIT_END + 0x0469, // Size: 1, Type: INT, Flags: PRIVATE * PLAYER_FIELD_ARENA_CURRENCY = UNIT_END + 0x046A, // Size: 1, Type: INT, Flags: PRIVATE * PLAYER_FIELD_MAX_LEVEL = UNIT_END + 0x046B, // Size: 1, Type: INT, Flags: PRIVATE * PLAYER_FIELD_DAILY_QUESTS_1 = UNIT_END + 0x046C, // Size: 25, Type: INT, Flags: PRIVATE * PLAYER_RUNE_REGEN_1 = UNIT_END + 0x0485, // Size: 4, Type: FLOAT, Flags: PRIVATE * PLAYER_NO_REAGENT_COST_1 = UNIT_END + 0x0489, // Size: 3, Type: INT, Flags: PRIVATE * PLAYER_FIELD_GLYPH_SLOTS_1 = UNIT_END + 0x048C, // Size: 6, Type: INT, Flags: PRIVATE * PLAYER_FIELD_GLYPHS_1 = UNIT_END + 0x0492, // Size: 6, Type: INT, Flags: PRIVATE * PLAYER_GLYPHS_ENABLED = UNIT_END + 0x0498, // Size: 1, Type: INT, Flags: PRIVATE * PLAYER_PET_SPELL_POWER = UNIT_END + 0x0499, // Size: 1, Type: INT, Flags: PRIVATE * PLAYER_END */ //-31 shiftAmount = (int)EUnitFields.PLAYER_FIELD_BYTES2 - (int)EUnitFields_Vanilla.PLAYER_FIELD_BYTES2; } else { throw new InvalidOperationException($"Unhandled field: {((EUnitFields_Vanilla)i).ToString()}:{i}:{i:X}"); } shiftValue = shiftAmount; return(shouldWrite); }