context: // Copyright (c) Tartarus Dev Team, licensed under GNU GPL.
  // See the LICENSE file
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using common;
  using common.DES;
  using common.Utilities;
  
  namespace game
  {
  	public static class ClientPacketHandler
  	{
  		private static XDes Des;
  		private static Dictionary<short, Packets.Packet> packet_db;
  
  		internal static void Start()
  		{
  			Des = new XDes();
  			Des.Init(Globals.DESKey);
  
  			packet_db = Packets.LoadClientPackets();
  		}
  
  		/* ******************************
  		 * Will we continue to use offsets to read these packets?
  		 * At one of the last commits I've added functions to
  		 * read continuously instead of by offset, is it better?
  		 *
  		 * Currently most of these packets doesn't have targets
  		 * At one of the last commits I added target support,
  		 * everything must have targets in the future.
  		 * ******************************/
  
  		internal static void PacketReceived(Player player, PacketStream stream)
  		{
  			// Header
  			// [Size:4]
  			// [ID:2]
  			// [Checksum(?):1]
  			short PacketId = stream.GetId();
  
  			if (!packet_db.ContainsKey(PacketId))
  			{
  				ConsoleUtils.HexDump(stream.ToArray(), "Unknown Packet Received", PacketId, stream.GetSize());
  				return;
  			}
  
  			ConsoleUtils.HexDump(
  				stream.ToArray(),
  				"Packet Received",
  				PacketId,
  				stream.GetSize()
  			);
  			packet_db[PacketId].func(player, ref stream, packet_db[PacketId].pos);
  
  			return;
  		}
  
  		#region General Uses
  
  		/// [0x0000] 0000 -> (GC) Sends the result of a packet
  		/// <packet id>.W <result>.L <0>.W
  		internal static void send_PacketResponse(Player player, short packetId, short response = 0, uint parameter = 0)
  		{
  			PacketStream data = new PacketStream((short)0x0000);
  
  			data.WriteInt16(packetId);
  			data.WriteInt16(response);
  			data.WriteUInt32(parameter);
  
  			ClientManager.Instance.Send(player, data);
  		}
  
  		#endregion
  
  		#region Character Selection Screen
  
  		/// [0x07D1] 2001 -> Requests the list of characters
  		/// <user id>.60S
  		internal static void parse_CharListRequest(Player player, ref PacketStream stream, short[] pos)
  		{
  			string userId = stream.ReadString(pos[0], 60);
  
  			player.SendCharacterList();
  		}
  
  		/// [0x07D2] 2002 -> (CS) Requests the creation of a new character
  		/// <sex>.L <race>.L <hair id>.L <face id>.L <body id>.L <hands id>.L
  		/// <feet id>.L <hair color>.L <face detail>.L <clothes id>.L 
  		/// <char name>.19S <skin color>.L
  		internal static void parse_CreateCharacter(Player player, ref PacketStream stream, short[] pos)
  		{
  			int sex = stream.ReadInt32(pos[0]);
  			int race = stream.ReadInt32(pos[1]);
  			int hairId = stream.ReadInt32(pos[2]);
  			int faceId = stream.ReadInt32(pos[3]);
  			int bodyId = stream.ReadInt32(pos[4]);
  			int handsId = stream.ReadInt32(pos[5]);
  			int feetId = stream.ReadInt32(pos[6]);
  			int hairColor = stream.ReadInt32(pos[7]);
  
  			int faceDetail = stream.ReadInt32(pos[8]);
  
  			int clothesId = stream.ReadInt32(pos[9]);
  
  			string name = stream.ReadString(pos[10], 19);
  			int skinColor = stream.ReadInt32(pos[11]);
  
  			player.CreateCharacter(name, sex, race, hairId, faceId, bodyId, handsId, feetId, hairColor, faceDetail, clothesId, skinColor);
  		}
  
  		/// [0x07D3] 2003 -> Requests the deletion of a character
  		/// <char name>.19S
  		internal static void parse_DeleteCharacter(Player player, ref PacketStream stream, short[] pos)
  		{
  			string charName = stream.ReadString(pos[0], 19);
  
  			player.DeleteCharacter(charName);
  		}
  
  		/// [0x07D4] 2004 -> Sends the list of account characters
  		/// <00>.6B <char count>.W { <sex>.L <race>.L <hair id>.L <face id>.L
  		/// <body id>.L <hands id>.L <feet id>.L <hair color>.L <00>.Q 
  		/// <0x05, 0x00, 0x00, 0x00> <right hand>.L <>.L <armor id>.L
  		/// <4>.L <8>.L <12>.L <16>.L <20>.L <24>.L <28>.L <32>.L
  		/// <36>.L <40>.L <44>.L <48>.L <52>.L <56>.L <60>.L <64>.L
  		/// <68>.L <72>.L <76>.L <80>.L <bag id>.L <level>.L <job>.L
  		/// <job level>.L <0>.17B <char name>.19S <skin color>.L
  		/// <create date>.30S <delete date>.30S
  		/// <0x14>.B <0>7B <0x14>.B
  		/// <0>.87B <0x0A>.B <0>.7B <0x0A>.B <0>.7B
  		/// <0>.83B <0x01>.B <0>.123B
  		internal static void send_CharacterList(Player player, CharacterListEntry[] characters)
  		{
  			PacketStream data = new PacketStream(0x07D4);
  			data.Write(new byte[6], 0, 6);
  			data.WriteInt16((short)characters.Length);
  			for (short i = 0; i < characters.Length; i++)
  			{
  				data.WriteInt32(characters[i].Sex);
  				data.WriteInt32(characters[i].Race);
  				data.WriteInt32(characters[i].HairId);
  				data.WriteInt32(characters[i].FaceId);
  				data.WriteInt32(characters[i].BodyId);
  				data.WriteInt32(characters[i].HandsId);
  				data.WriteInt32(characters[i].FeetId);
  				data.WriteInt32(characters[i].HairColor);
  
  				data.Write(new byte[8], 0, 8);
  				data.Write(new byte[4] { 0x05, 0x00, 0x00, 0x00 }, 0, 4);
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.RightHand]); // Right Hand Item
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.LeftHand]); // 
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Armor]); // Armor ID
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Helm]); // 4
  				
  				int temp = characters[i].Equip[(int)Item.WearType.Glove];
  				if (temp == 0)
  					temp = characters[i].HandsId;
  				data.WriteInt32(temp); // 8
  				
  				temp = characters[i].Equip[(int)Item.WearType.Boots];
  				if (temp == 0)
  					temp = characters[i].FeetId;
  				data.WriteInt32(temp); // 12
  				
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Belt]); // 16
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Mantle]); // 20
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Necklace]); // 24
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Ring]); // 28
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.SecondRing]); // 32
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Ear]); // 36
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.Face]); // 40
  				data.WriteInt32(0); // 44
  				data.WriteInt32(0); // 48
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.DecoShield]); // 52
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.DecoArmor]); // 56
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.DecoHelm]); // 60
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.DecoGlove]); // 64
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.DecoBoots]); // 68
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.DecoMantle]); // 72
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.DecoShoulder]); // 76
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.RideItem]); // 80
  				data.WriteInt32(characters[i].Equip[(int)Item.WearType.BagSlot]); // Bag ID
  				data.WriteInt32(characters[i].Level); // Level
  				data.WriteInt32(characters[i].Job); // Job
  				data.WriteInt32(characters[i].JobLevel); // Job Level
  				data.Write(new byte[17], 0, 17);
  				data.WriteString(characters[i].Name, 19);
  				data.WriteInt32(characters[i].SkinColor);
  				data.WriteString(TimeUtils.GetDateTime(characters[i].CreateDate).ToString("yyyy/MM/dd"), 30); // Create Date
  				// Deleted characters doesn't even get to this function
  				// so there's no point in sending a different delete date
  				data.WriteString("9999/12/31", 30); // Delete Date
  				//data.Write(new byte[312], 0, 312);
  				// Unknown
  				data.Write(new byte[1] { 0x14 }, 0, 1);
  				data.Write(new byte[7], 0, 7);
  				data.Write(new byte[1] { 0x14 }, 0, 1);
  				data.Write(new byte[87], 0, 87);
  				data.Write(new byte[1] { 0x0A }, 0, 1);
  				data.Write(new byte[7], 0, 7);
  				data.Write(new byte[1] { 0x0A }, 0, 1);
  				data.Write(new byte[83], 0, 83);
  
gt: 				data.Write(new byte[1] { 0x01 }, 0, 1);