context: using System;
  using WowPacketParser.Enums;
  using WowPacketParser.Enums.Version;
  using WowPacketParser.Misc;
  using WowPacketParser.Store;
  using WowPacketParser.Store.Objects;
  
  namespace WowPacketParser.Parsing.Parsers
  {
      public static class CharacterHandler
      {
          [Parser(Opcode.CMSG_STAND_STATE_CHANGE)]
          public static void HandleStandStateChange(Packet packet)
          {
              packet.ReadInt32E<StandState>("StandState");
          }
  
          [Parser(Opcode.SMSG_STAND_STATE_UPDATE)]
          public static void HandleStandStateUpdate(Packet packet)
          {
              packet.ReadByteE<StandState>("State");
          }
  
          [Parser(Opcode.CMSG_CREATE_CHARACTER)]
          public static void HandleClientCharCreate(Packet packet)
          {
              packet.ReadCString("Name");
              packet.ReadByteE<Race>("Race");
              packet.ReadByteE<Class>("Class");
              packet.ReadByteE<Gender>("Gender");
              packet.ReadByte("Skin");
              packet.ReadByte("Face");
              packet.ReadByte("Hair Style");
              packet.ReadByte("Hair Color");
              packet.ReadByte("Facial Hair");
              packet.ReadByte("Outfit Id");
          }
  
          [Parser(Opcode.CMSG_CHAR_DELETE)]
          public static void HandleClientCharDelete(Packet packet)
          {
              packet.ReadGuid("GUID");
          }
  
          [Parser(Opcode.CMSG_CHARACTER_RENAME_REQUEST)]
          public static void HandleClientCharRename(Packet packet)
          {
              packet.ReadGuid("GUID");
              packet.ReadCString("New Name");
          }
  
          [Parser(Opcode.SMSG_CHARACTER_RENAME_RESULT)]
          public static void HandleServerCharRename(Packet packet)
          {
              if (packet.ReadByteE<ResponseCode>("Race") != ResponseCode.RESPONSE_SUCCESS)
                  return;
  
              var guid = packet.ReadGuid("GUID");
              var name = packet.ReadCString("Name");
              StoreGetters.AddName(guid, name);
          }
  
          [Parser(Opcode.SMSG_CREATE_CHAR)]
          [Parser(Opcode.SMSG_DELETE_CHAR)]
          public static void HandleCharResponse(Packet packet)
          {
              packet.ReadByteE<ResponseCode>("Response");
          }
  
          [Parser(Opcode.CMSG_ALTER_APPEARANCE)]
          public static void HandleAlterAppearance(Packet packet)
          {
              // In some ancient version, this could be ReadByte
              packet.ReadInt32("Hair Style");
              packet.ReadInt32("Hair Color");
              packet.ReadInt32("Facial Hair");
              packet.ReadInt32("Skin Color");
          }
  
          [Parser(Opcode.SMSG_BARBER_SHOP_RESULT)]
          public static void HandleBarberShopResult(Packet packet)
          {
              packet.ReadInt32E<BarberShopResult>("Result");
          }
  
          [Parser(Opcode.CMSG_CHAR_CUSTOMIZE)]
          public static void HandleClientCharCustomize(Packet packet)
          {
              packet.ReadGuid("GUID");
              packet.ReadCString("New Name");
              packet.ReadByteE<Gender>("Gender");
              packet.ReadByte("Skin");
              packet.ReadByte("Face");
              packet.ReadByte("Hair Style");
              packet.ReadByte("Hair Color");
              packet.ReadByte("Facial Hair");
          }
  
          [Parser(Opcode.SMSG_CHAR_CUSTOMIZE)]
          public static void HandleServerCharCustomize(Packet packet)
          {
              if (packet.ReadByteE<ResponseCode>("Response") != ResponseCode.RESPONSE_SUCCESS)
                  return;
  
              var guid = packet.ReadGuid("GUID");
              var name = packet.ReadCString("Name");
  
              StoreGetters.AddName(guid, name);
  
              packet.ReadByteE<Gender>("Gender");
              packet.ReadByte("Skin");
              packet.ReadByte("Face");
              packet.ReadByte("Hair Style");
              packet.ReadByte("Hair Color");
              packet.ReadByte("Facial Hair");
          }
  
          [Parser(Opcode.SMSG_ENUM_CHARACTERS_RESULT, ClientVersionBuild.Zero, ClientVersionBuild.V4_2_2_14545)]
          public static void HandleCharEnum(Packet packet)
          {
              var count = packet.ReadByte("Count");
  
              for (var i = 0; i < count; i++)
              {
                  var guid = packet.ReadGuid("GUID");
                  var name = packet.ReadCString("Name");
                  StoreGetters.AddName(guid, name);
                  var race = packet.ReadByteE<Race>("Race");
                  var klass = packet.ReadByteE<Class>("Class");
                  packet.ReadByteE<Gender>("Gender");
  
                  packet.ReadByte("Skin");
                  packet.ReadByte("Face");
                  packet.ReadByte("Hair Style");
                  packet.ReadByte("Hair Color");
                  packet.ReadByte("Facial Hair");
  
                  var level = packet.ReadByte("Level");
                  var zone = packet.ReadUInt32<ZoneId>("Zone Id");
                  var mapId = packet.ReadInt32<MapId>("Map Id");
  
                  var pos = packet.ReadVector3("Position");
                  if (ClientVersion.AddedInVersion(ClientVersionBuild.V4_0_3_13329))
                      packet.ReadGuid("Guild GUID");
                  else
                      packet.ReadInt32("Guild Id");
                  packet.ReadInt32E<CharacterFlag>("Character Flags");
  
                  if (ClientVersion.AddedInVersion(ClientVersionBuild.V3_0_2_9056))
                      packet.ReadInt32E<CustomizationFlag>("Customization Flags");
  
                  var firstLogin = packet.ReadBool("First Login");
                  packet.ReadInt32("Pet Display Id");
                  packet.ReadInt32("Pet Level");
                  packet.ReadInt32E<CreatureFamily>("Pet Family");
  
                  for (var j = 0; j < 19; j++)
                  {
                      packet.ReadInt32("Equip Display Id");
                      packet.ReadByteE<InventoryType>("Equip Inventory Type");
                      packet.ReadInt32("Equip Aura Id");
                  }
  
                  int bagCount = ClientVersion.AddedInVersion(ClientVersionBuild.V3_3_3_11685) ? 4 : 1;
                  for (var j = 0; j < bagCount; j++)
                  {
                      packet.ReadInt32("Bag Display Id");
                      packet.ReadByteE<InventoryType>("Bag Inventory Type");
                      packet.ReadInt32("Bag Aura Id");
                  }
  
                  if (firstLogin)
                  {
                      PlayerCreateInfo startPos = new PlayerCreateInfo { Race = race, Class = klass, Map = (uint)mapId, Zone = zone, Position = pos, Orientation = 0 };
                      Storage.StartPositions.Add(startPos, packet.TimeSpan);
                  }
  
                  var playerInfo = new Player {Race = race, Class = klass, Name = name, FirstLogin = firstLogin, Level = level};
  
                  if (Storage.Objects.ContainsKey(guid))
                      Storage.Objects[guid] = new Tuple<WoWObject, TimeSpan?>(playerInfo, packet.TimeSpan);
                  else
                      Storage.Objects.Add(guid, playerInfo, packet.TimeSpan);
                  StoreGetters.AddName(guid, name);
              }
          }
  
          [Parser(Opcode.SMSG_ENUM_CHARACTERS_RESULT, ClientVersionBuild.V4_2_2_14545, ClientVersionBuild.V4_3_0_15005)]
          public static void HandleCharEnum422(Packet packet)
          {
              packet.ReadByte("Unk Flag");
              int count = packet.ReadInt32("Char Count");
              packet.ReadInt32("Unk Count");
              var firstLogin = new bool[count];
              var playerGuid = new byte[count][];
              var guildGuid = new byte[count][];
  
              for (int c = 0; c < count; c++)
              {
                  playerGuid[c] = new byte[8];
                  guildGuid[c] = new byte[8];
  
                  guildGuid[c][5] = packet.ReadBit();//0
                  playerGuid[c][4] = packet.ReadBit();//1
                  guildGuid[c][3] = packet.ReadBit();//2
                  guildGuid[c][7] = packet.ReadBit();//3
                  guildGuid[c][1] = packet.ReadBit();//4
                  guildGuid[c][6] = packet.ReadBit();//5
                  playerGuid[c][5] = packet.ReadBit();//6
                  playerGuid[c][6] = packet.ReadBit();//7
                  playerGuid[c][3] = packet.ReadBit();//8
                  playerGuid[c][2] = packet.ReadBit();//9
                  guildGuid[c][4] = packet.ReadBit();//10
                  playerGuid[c][0] = packet.ReadBit();//11
                  playerGuid[c][1] = packet.ReadBit();//12
                  guildGuid[c][2] = packet.ReadBit();//13
                  playerGuid[c][7] = packet.ReadBit();//14
                  guildGuid[c][0] = packet.ReadBit();//15
                  firstLogin[c] = packet.ReadBit();//16
              }
  
              for (int c = 0; c < count; c++)
              {
                  var name = packet.ReadCString("Name", c);
  
                  packet.ReadXORByte(guildGuid[c], 5);
  
                  packet.ReadByte("Face", c);
                  var mapId = packet.ReadInt32("Map", c);
  
                  packet.ReadXORByte(playerGuid[c], 1);
                  packet.ReadXORByte(playerGuid[c], 4);
                  packet.ReadXORByte(guildGuid[c], 4);
                  packet.ReadXORByte(guildGuid[c], 0);
  
                  var pos = packet.ReadVector3("Position", c);
  
                  packet.ReadXORByte(playerGuid[c], 0);
  
                  var zone = packet.ReadInt32<ZoneId>("Zone Id", c);
                  packet.ReadInt32("Pet Level", c);
  
                  packet.ReadXORByte(playerGuid[c], 3);
  
                  packet.ReadXORByte(playerGuid[c], 7);
  
                  packet.ReadByte("Facial Hair", c);
                  packet.ReadByte("Skin", c);
                  var klass = packet.ReadByteE<Class>("Class", c);
                  packet.ReadInt32("Pet Family", c);
                  packet.ReadInt32E<CharacterFlag>("CharacterFlag", c);
  
                  packet.ReadXORByte(playerGuid[c], 2);
  
                  packet.ReadInt32("Pet Display ID", c);
  
                  packet.ReadXORByte(guildGuid[c], 7);
  
                  var level = packet.ReadByte("Level", c);
  
                  packet.ReadXORByte(playerGuid[c], 6);
  
                  packet.ReadByte("Hair Style", c);
  
                  packet.ReadXORByte(guildGuid[c], 2);
  
                  var race = packet.ReadByteE<Race>("Race", c);
                  packet.ReadByte("Hair Color", c);
  
                  packet.ReadXORByte(guildGuid[c], 6);
  
                  packet.ReadByteE<Gender>("Gender", c);
  
                  packet.ReadXORByte(playerGuid[c], 5);
  
                  packet.ReadXORByte(guildGuid[c], 3);
  
                  packet.ReadByte("List Order", c);
  
                  for (int itm = 0; itm < 19; itm++)
                  {
                      packet.ReadInt32("Item EnchantID", c, itm);
                      packet.ReadByteE<InventoryType>("Item InventoryType", c, itm);
                      packet.ReadInt32("Item DisplayID", c, itm);
                  }
  
                  for (int itm = 0; itm < 4; itm++)
                  {
                      packet.ReadInt32("Bag EnchantID", c, itm);
                      packet.ReadByteE<InventoryType>("Bag InventoryType", c, itm);
                      packet.ReadInt32("Bag DisplayID", c, itm);
                  }
  
                  packet.ReadUInt32E<CustomizationFlag>("CustomizationFlag", c);
  
                  packet.ReadXORByte(guildGuid[c], 1);
  
                  var guidPlayer = new WowGuid64(BitConverter.ToUInt64(playerGuid[c], 0));
  
                  packet.WriteGuid("Character Guid", playerGuid[c],c);
                  packet.WriteGuid("Guild Guid", guildGuid[c],c);
  
  
                  if (firstLogin[c])
                  {
                      PlayerCreateInfo startPos = new PlayerCreateInfo { Race = race, Class = klass, Map = (uint)mapId, Zone = (uint)zone, Position = pos, Orientation = 0 };
                      Storage.StartPositions.Add(startPos, packet.TimeSpan);
                  }
  
                  var playerInfo = new Player { Race = race, Class = klass, Name = name, FirstLogin = firstLogin[c], Level = level };
                  if (Storage.Objects.ContainsKey(guidPlayer))
                      Storage.Objects[guidPlayer] = new Tuple<WoWObject, TimeSpan?>(playerInfo, packet.TimeSpan);
                  else
                      Storage.Objects.Add(guidPlayer, playerInfo, packet.TimeSpan);
                  StoreGetters.AddName(guidPlayer, name);
              }
          }
  
          [Parser(Opcode.SMSG_ENUM_CHARACTERS_RESULT, ClientVersionBuild.V4_3_0_15005, ClientVersionBuild.V4_3_3_15354)]
          public static void HandleCharEnum430(Packet packet)
          {
              var count = packet.ReadBits("Char count", 17);
  
              var charGuids = new byte[count][];
              var guildGuids = new byte[count][];
              var firstLogins = new bool[count];
              var nameLenghts = new uint[count];
  
              for (var c = 0; c < count; ++c)
              {
                  charGuids[c] = new byte[8];
                  guildGuids[c] = new byte[8];
  
                  guildGuids[c][2] = packet.ReadBit();
                  charGuids[c][2] = packet.ReadBit();
                  charGuids[c][6] = packet.ReadBit();
                  charGuids[c][5] = packet.ReadBit();
                  charGuids[c][4] = packet.ReadBit();
                  guildGuids[c][4] = packet.ReadBit();
                  guildGuids[c][3] = packet.ReadBit();
                  guildGuids[c][7] = packet.ReadBit();
                  nameLenghts[c] = packet.ReadBits(7);
                  guildGuids[c][0] = packet.ReadBit();
                  charGuids[c][0] = packet.ReadBit();
                  charGuids[c][3] = packet.ReadBit();
                  charGuids[c][1] = packet.ReadBit();
                  firstLogins[c] = packet.ReadBit();
                  guildGuids[c][5] = packet.ReadBit();
                  charGuids[c][7] = packet.ReadBit();
                  guildGuids[c][6] = packet.ReadBit();
                  guildGuids[c][1] = packet.ReadBit();
              }
  
              var unkCounter = packet.ReadBits("Unk Counter", 23);
              packet.ReadBit(); // no idea, not used in client
  
              for (int c = 0; c < count; ++c)
              {
                  Vector3 pos = new Vector3();
  
                  for (var itm = 0; itm < 19; ++itm)
                  {
                      packet.ReadByteE<InventoryType>("Item InventoryType", c, itm);
                      packet.ReadInt32("Item DisplayID", c, itm);
                      packet.ReadInt32("Item EnchantID", c, itm);
                  }
  
                  for (var itm = 0; itm < 4; ++itm)
                  {
                      packet.ReadByteE<InventoryType>("Bag InventoryType", c, itm);
                      packet.ReadInt32("Bag DisplayID", c, itm);
                      packet.ReadInt32("Bag EnchantID", c, itm);
                  }
  
                  packet.ReadXORByte(guildGuids[c], 0);
                  packet.ReadXORByte(guildGuids[c], 1);
  
                  packet.ReadByte("Face", c);
                  packet.ReadInt32("Pet Display ID", c);
                  packet.ReadXORByte(guildGuids[c], 7);
  
                  packet.ReadByteE<Gender>("Gender", c);
                  var level = packet.ReadByte("Level", c);
                  packet.ReadInt32("Pet Level", c);
                  var zone = packet.ReadUInt32<ZoneId>("Zone Id", c);
                  pos.Y = packet.ReadSingle("Position Y", c);
                  packet.ReadInt32("Pet Family", c);
                  packet.ReadByte("Hair Style", c);
                  packet.ReadXORByte(charGuids[c], 1);
  
                  var name = packet.ReadWoWString("Name", (int)nameLenghts[c], c);
                  packet.ReadXORByte(charGuids[c], 0);
  
                  var race = packet.ReadByteE<Race>("Race", c);
                  packet.ReadByte("List Order", c);
                  packet.ReadXORByte(charGuids[c], 7);
  
                  pos.Z = packet.ReadSingle("Position Z", c);
                  var mapId = packet.ReadInt32("Map", c);
                  packet.ReadXORByte(guildGuids[c], 4);
  
                  packet.ReadByte("Hair Color", c);
                  packet.ReadXORByte(charGuids[c], 3);
  
                  packet.ReadInt32E<CharacterFlag>("CharacterFlag", c);
                  packet.ReadByte("Skin", c);
                  packet.ReadXORByte(charGuids[c], 4);
                  packet.ReadXORByte(charGuids[c], 5);
                  packet.ReadXORByte(guildGuids[c], 5);
  
                  packet.ReadUInt32E<CustomizationFlag>("CustomizationFlag", c);
                  pos.X = packet.ReadSingle("Position X", c);
                  packet.ReadByte("Facial Hair", c);
                  packet.ReadXORByte(charGuids[c], 6);
                  packet.ReadXORByte(guildGuids[c], 3);
                  packet.ReadXORByte(charGuids[c], 2);
  
                  var klass = packet.ReadByteE<Class>("Class", c);
                  packet.ReadXORByte(guildGuids[c], 6);
                  packet.ReadXORByte(guildGuids[c], 2);
  
                  var playerGuid = new WowGuid64(BitConverter.ToUInt64(charGuids[c], 0));
  
                  packet.WriteGuid("Character GUID", charGuids[c], c);
                  packet.WriteGuid("Guild GUID", guildGuids[c], c);
  
                  if (firstLogins[c])
                  {
                      PlayerCreateInfo startPos = new PlayerCreateInfo { Race = race, Class = klass, Map = (uint)mapId, Zone = zone, Position = pos, Orientation = 0 };
                      Storage.StartPositions.Add(startPos, packet.TimeSpan);
                  }
  
                  var playerInfo = new Player{Race = race, Class = klass, Name = name, FirstLogin = firstLogins[c], Level = level};
                  if (Storage.Objects.ContainsKey(playerGuid))
                      Storage.Objects[playerGuid] = new Tuple<WoWObject, TimeSpan?>(playerInfo, packet.TimeSpan);
                  else
                      Storage.Objects.Add(playerGuid, playerInfo, packet.TimeSpan);
                  StoreGetters.AddName(playerGuid, name);
              }
  
              for (var c = 0; c < unkCounter; c++)
              {
                  packet.ReadUInt32("Unk1", c);
                  packet.ReadByte("Unk2", c);
              }
          }
  
          [Parser(Opcode.SMSG_ENUM_CHARACTERS_RESULT, ClientVersionBuild.V4_3_3_15354, ClientVersionBuild.V4_3_4_15595)]
          public static void HandleCharEnum433(Packet packet)
          {
              var unkCounter = packet.ReadBits("Unk Counter", 23);
              var count = packet.ReadBits("Char count", 17);
  
              var charGuids = new byte[count][];
              var guildGuids = new byte[count][];
              var firstLogins = new bool[count];
              var nameLenghts = new uint[count];
  
              for (var c = 0; c < count; ++c)
              {
                  charGuids[c] = new byte[8];
                  guildGuids[c] = new byte[8];
                  //100%  pozition, and flag
                  //%50   flag
                  //20    nothing
  
                  charGuids[c][0] = packet.ReadBit(); //100%
                  guildGuids[c][0] = packet.ReadBit();//50%
                  charGuids[c][2] = packet.ReadBit(); //100%
                  guildGuids[c][2] = packet.ReadBit();//50%
                  firstLogins[c] = packet.ReadBit();                  //100%
                  charGuids[c][3] = packet.ReadBit(); //100%
                  charGuids[c][6] = packet.ReadBit(); //100%
                  guildGuids[c][2] = packet.ReadBit();//20%
  
                  charGuids[c][4] = packet.ReadBit(); //20%
                  charGuids[c][5] = packet.ReadBit(); //20%
                  nameLenghts[c] = packet.ReadBits(4);                //100%
                  guildGuids[c][3] = packet.ReadBit();//20%
                  guildGuids[c][4] = packet.ReadBit();//50%
  
                  guildGuids[c][5] = packet.ReadBit();//20%
                  charGuids[c][1] = packet.ReadBit(); //100%
                  packet.ReadBit();                                   //20%
                  guildGuids[c][6] = packet.ReadBit();//20%
                  charGuids[c][7] = packet.ReadBit(); //100%
                  guildGuids[c][7] = packet.ReadBit();//50%
                  packet.ReadBit();                                   //20%
                  packet.ReadBit();                                   //20%
              }
  
              // no idea, not used in client
              packet.ReadByte();
  
              for (int c = 0; c < count; ++c)
              {
                  Vector3 pos = new Vector3();
  
                  for (var itm = 0; itm < 19; ++itm)
                  {
                      packet.ReadInt32("Item EnchantID", c, itm);
                      packet.ReadInt32("Item DisplayID", c, itm);
                      packet.ReadByteE<InventoryType>("Item InventoryType", c, itm);
                  }
  
                  for (var itm = 0; itm < 4; ++itm)
                  {
                      packet.ReadInt32("Bag EnchantID", c, itm);
                      packet.ReadInt32("Bag DisplayID", c, itm);
                      packet.ReadByteE<InventoryType>("Bag InventoryType", c, itm);
                  }
  
                  var zone = packet.ReadUInt32<ZoneId>("Zone Id", c);
                  packet.ReadInt32("Pet Level", c);
                  packet.ReadInt32E<CharacterFlag>("CharacterFlag", c);
  
                  packet.ReadByte("Facial Hair", c);
  
                  packet.ReadXORByte(guildGuids[c], 0);
                      packet.ReadXORByte(charGuids[c], 0);
  
                  packet.ReadXORByte(charGuids[c], 2);
                  if (guildGuids[c][2] != 0)
                      //  guildGuids[c][2] ^= packet.ReadByte();
  
                      if (charGuids[c][7] != 0)
                          charGuids[c][7] ^= packet.ReadByte();
                  if (guildGuids[c][7] != 0)
                      // guildGuids[c][7] ^= packet.ReadByte();
  
                      packet.ReadByte("List Order", c);
                  packet.ReadInt32("Pet Display ID", c);
  
                  // no ideal //////////////////////////////
                  if (charGuids[c][4] != 0)
                      charGuids[c][4] ^= packet.ReadByte();
  
                  if (guildGuids[c][4] != 0)
                      // guildGuids[c][4] ^= packet.ReadByte();
  
                  if (charGuids[c][5] != 0)
                          // charGuids[c][5] ^= packet.ReadByte();
  
                  if (guildGuids[c][5] != 0)
                              // guildGuids[c][5] ^= packet.ReadByte();
  
                  if (guildGuids[c][1] != 0)
                                  // guildGuids[c][1] ^= packet.ReadByte();
  
                                  if (guildGuids[c][3] != 0)
                                      // guildGuids[c][3] ^= packet.ReadByte();
  
                                      if (guildGuids[c][6] != 0)
                                          // guildGuids[c][6] ^= packet.ReadByte();
  
                                          //////////////////////////////////////////
  
                                          if (charGuids[c][3] != 0)
                                              charGuids[c][3] ^= packet.ReadByte();
  
                  var klass = packet.ReadByteE<Class>("Class", c);
  
                  if (charGuids[c][6] != 0)
                      charGuids[c][6] ^= packet.ReadByte();
  
                  pos.X = packet.ReadSingle("Position X", c);
  
                  if (charGuids[c][1] != 0)
                      charGuids[c][1] ^= packet.ReadByte();
  
                  var race = packet.ReadByteE<Race>("Race", c);
                  packet.ReadInt32("Pet Family", c);
                  pos.Y = packet.ReadSingle("Position Y", c);
                  packet.ReadByteE<Gender>("Gender", c);
                  packet.ReadByte("Hair Style", c);
                  var level = packet.ReadByte("Level", c);
  
gt:                 pos.Z = packet.ReadSingle("Position Z", c);