From 936ef8a40a0bf05b06d84dc394ee2a06a80b824f Mon Sep 17 00:00:00 2001 From: Longfeng Qin Date: Wed, 11 Dec 2024 14:07:19 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=83=A8=E5=88=86=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=8C=85=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Server/Logger.cs | 90 +++++++++++++++++- Server/Models/Mail.cs | 68 ++++++++++++++ Server/Models/PartyQuest.cs | 3 + Server/Party/Party.cs | 37 ++++++-- .../0E-PartyHandler/0E-0C-NewPartySettings.cs | 84 +++++++++++++++++ .../0E-0C-QuestCounterHandler.cs | 93 ------------------- .../1A-MailHandler/1A-00-MailListRequest.cs | 38 ++++++++ .../1A-MailHandler/1A-02-DeleteMailRequest.cs | 37 ++++++++ Server/Protocol/PacketWriter.cs | 40 ++++++++ .../0E-0D-PartySettingsPacket.cs | 59 +++++++++++- .../0E-PartyPacket/0E-1A-Unk0E1APacket.cs | 11 ++- .../0E-PartyPacket/0E-1B-PartyInfoPacket.cs | 12 ++- .../0E-1C-PartyInfoStopperPacker.cs | 5 +- .../1A-MailPacket/1A-01-MailListPacket.cs | 45 ++++++++- .../1A-MailPacket/1A-03-DeletedMailPacket.cs | 11 ++- Server/Server.csproj | 7 +- 16 files changed, 528 insertions(+), 112 deletions(-) create mode 100644 Server/Models/Mail.cs create mode 100644 Server/Protocol/Handlers/0E-PartyHandler/0E-0C-NewPartySettings.cs delete mode 100644 Server/Protocol/Handlers/0E-PartyHandler/0E-0C-QuestCounterHandler.cs create mode 100644 Server/Protocol/Handlers/1A-MailHandler/1A-00-MailListRequest.cs create mode 100644 Server/Protocol/Handlers/1A-MailHandler/1A-02-DeleteMailRequest.cs diff --git a/Server/Logger.cs b/Server/Logger.cs index 14fbc1c..5b2f6cd 100644 --- a/Server/Logger.cs +++ b/Server/Logger.cs @@ -1,7 +1,10 @@ using System; using System.IO; +using System.Linq; using System.Reflection; using System.Runtime.InteropServices; +using System.Runtime.Serialization.Formatters.Binary; +using System.Text; using PSO2SERVER.Protocol.Packets; namespace PSO2SERVER @@ -47,7 +50,31 @@ namespace PSO2SERVER foreach (var field in fields) { var value = field.GetValue(obj); - Write($"{field.Name}: {value}"); + // 检查值的类型并转换为十六进制字符串 + string hex; + switch (value) + { + case byte b: + hex = b.ToString("X2"); // 2-digit hex for byte + break; + case short s: + hex = s.ToString("X4"); // 4-digit hex for short + break; + case int i: + hex = i.ToString("X8"); // 8-digit hex for int + break; + case long l: + hex = l.ToString("X16"); // 16-digit hex for long + break; + case uint ui: + hex = ui.ToString("X8"); // 8-digit hex for uint + break; + default: + hex = value.ToString(); // Default: fallback to regular ToString + break; + } + + Write($"{field.Name}: {value} - 0x{hex}"); } } @@ -275,5 +302,66 @@ namespace PSO2SERVER return byteArray; } + + // 用于将不同类型的值转换为字节流的方法 + public static byte[] ConvertToByteArray(object value) + { + if (value == null) + { + return new byte[0]; // 如果 value 为 null,返回空字节数组 + } + + if (value is byte b) + { + return new byte[] { b }; // byte 转为字节数组 + } + else if (value is short s) + { + return BitConverter.GetBytes(s); // short 转为字节数组 + } + else if (value is int i) + { + return BitConverter.GetBytes(i); // int 转为字节数组 + } + else if (value is long l) + { + return BitConverter.GetBytes(l); // long 转为字节数组 + } + else if (value is float f) + { + return BitConverter.GetBytes(f); // float 转为字节数组 + } + else if (value is double d) + { + return BitConverter.GetBytes(d); // double 转为字节数组 + } + else if (value is string str) + { + return Encoding.UTF8.GetBytes(str); // string 转为字节数组 + } + else if (value is bool bval) + { + return BitConverter.GetBytes(bval); // bool 转为字节数组 + } + else if (value is decimal dec) + { + return BitConverter.GetBytes(decimal.ToDouble(dec)); // decimal 转为字节数组 + } + else + { + return SerializeObject(value); // 对象(如自定义类)转为字节数组 + } + } + + // 如果是自定义对象,使用二进制序列化转为字节流 + public static byte[] SerializeObject(object value) + { + using (var memoryStream = new MemoryStream()) + { + var formatter = new BinaryFormatter(); + formatter.Serialize(memoryStream, value); // 将对象序列化 + return memoryStream.ToArray(); // 获取字节流 + } + } } } \ No newline at end of file diff --git a/Server/Models/Mail.cs b/Server/Models/Mail.cs new file mode 100644 index 0000000..578374b --- /dev/null +++ b/Server/Models/Mail.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PSO2SERVER.Models +{ + public struct MailId + { + /// Mail ID. + public uint MailIdValue; + public uint Unk1; + public uint Unk2; + + // Constructor for easier initialization + public MailId(uint mailId, uint unk1, uint unk2) + { + MailIdValue = mailId; + Unk1 = unk1; + Unk2 = unk2; + } + } + + public unsafe struct MailHeader + { + /// Mail ID. + public uint MailIdValue; + public uint Unk2; + /// Sender player ID (?). + public uint UserId; + public fixed byte Unk3[0x14]; // byte[0x14] + public uint Unk4; + public uint Unk5; + /// Mail receive timestamp. + public TimeSpan ReceiveTime; + public uint Unk6; + /// Sender name (0x22 length). + public string Sender; + /// Mail subject (0x2A length). + public string Subject; + + // Constructor for easier initialization + public MailHeader(uint mailId, uint unk2, uint userId, byte[] unk3, uint unk4, uint unk5, TimeSpan receiveTime, uint unk6, string sender, string subject) + { + MailIdValue = mailId; + Unk2 = unk2; + UserId = userId; + //Unk3 = 0; + Unk4 = unk4; + Unk5 = unk5; + ReceiveTime = receiveTime; + Unk6 = unk6; + Sender = sender.Length > 0x22 ? sender.Substring(0, 0x22) : sender.PadRight(0x22, '\0'); + Subject = subject.Length > 0x2A ? subject.Substring(0, 0x2A) : subject.PadRight(0x2A, '\0'); + } + } + + [Flags] + public enum MailType : uint + { + ALL = 0x00000065, + SYSTEM = 0x0000000A, + CHAR = 0x00000009, + FRIENDANDGUILD = 0x00000001, + MAILSENDED = 0x00000006 + } +} diff --git a/Server/Models/PartyQuest.cs b/Server/Models/PartyQuest.cs index b79ad3e..f4286a0 100644 --- a/Server/Models/PartyQuest.cs +++ b/Server/Models/PartyQuest.cs @@ -392,6 +392,9 @@ namespace PSO2SERVER.Models public QuestData Quest { get; set; } public ushort Diff { get; set; } = 0; + public PartyQuest() + { + } public PartyQuest(string name) { diff --git a/Server/Party/Party.cs b/Server/Party/Party.cs index 55e0943..e6ff545 100644 --- a/Server/Party/Party.cs +++ b/Server/Party/Party.cs @@ -22,12 +22,17 @@ namespace PSO2SERVER.Party private List members; private Client host; public PartyQuest currentQuest; + public PartySettingsPacket partySetting; + public string questname; public Party(string name, Client host) { this.name = name; this.host = host; - this.members = new List(); + members = new List(); + currentQuest = new PartyQuest(); + partySetting = new PartySettingsPacket(); + questname = string.Empty; addClientToParty(host); } @@ -47,7 +52,7 @@ namespace PSO2SERVER.Party public void removeClientFromParty(Client c) { - if(!members.Contains(c)) + if (!members.Contains(c)) { Logger.WriteWarning("[PTY] Client {0} was trying to be removed from {1}, but he was never in {1}!", c._account.Username, name); return; @@ -78,20 +83,36 @@ namespace PSO2SERVER.Party } } + [Serializable] + public unsafe struct PartyInfo + { + public fixed byte unk1[0x0C]; + public ObjectHeader party_object; // Assuming ObjectHeader is another class + public string name; // Name of the party 0xE7E8, 0xFF + public fixed byte unk2[0x09]; + public fixed byte unk3[0x03]; + public uint unk4; // 32-bit unsigned integer + public uint invite_time; // Time when the player was invited + public uint unk6; // 32-bit unsigned integer + } + [Flags] public enum PartyFlags : byte { /// Is the party only for friends. - FRIENDS_ONLY = 1 << 0, // 0x01 + FRIENDS_ONLY = 1 << 0, // 1 /// Is the party only for alliance members. - ALLIANCE_ONLY = 1 << 1, // 0x02 + ALLIANCE_ONLY = 1 << 1, // 2 /// Limit multiplayer requests from other parties. - LIMIT_OTHERS = 1 << 2, // 0x04 + LIMIT_OTHERS = 1 << 2, // 4 /// Is the party only for a single run. - SINGLE_RUN = 1 << 3, // 0x08 + SINGLE_RUN = 1 << 3, // 8 /// Is the party actively looking for members. - OPEN = 1 << 4, // 0x10 + OPEN = 1 << 4, // 16 /// Is the party voice chat focused. - VC_FOCUS = 1 << 6 // 0x40 + VC_FOCUS = 1 << 6, // 64 + + // This flag would represent an invalid state (all bits set). + _ = byte.MaxValue, // 255 (all flags set) } } diff --git a/Server/Protocol/Handlers/0E-PartyHandler/0E-0C-NewPartySettings.cs b/Server/Protocol/Handlers/0E-PartyHandler/0E-0C-NewPartySettings.cs new file mode 100644 index 0000000..2c73bb0 --- /dev/null +++ b/Server/Protocol/Handlers/0E-PartyHandler/0E-0C-NewPartySettings.cs @@ -0,0 +1,84 @@ +using System; +using PSO2SERVER.Models; +using PSO2SERVER.Protocol.Packets; +using PSO2SERVER.Party; +using PSO2SERVER.Json; +using System.Collections.Generic; + +namespace PSO2SERVER.Protocol.Handlers +{ + [PacketHandlerAttr(0x0E, 0x0C)] + public class NewPartySettings : PacketHandler + { + public string name { get; set; } = string.Empty; + public string password { get; set; } = string.Empty; + public string comments { get; set; } = string.Empty; + public string questname { get; set; } = string.Empty; + public byte min_level { get; set; } = 0; + public byte max_level { get; set; } = 0; + public byte playstyle { get; set; } = 0; + public PartyFlags partyFlags { get; set; } = 0; + public ulong unk { get; set; } = 0; + + public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size) + { + var info = string.Format("[<--] 接收到的数据 (hex): {0}字节", data.Length); + Logger.WriteHex(info, data); + + var reader = new PacketReader(data, position, size); + name = reader.ReadUtf16(0x11CB, 0x98); + password = reader.ReadUtf16(0x11CB, 0x98); + comments = reader.ReadUtf16(0x11CB, 0x98); + questname = reader.ReadUtf16(0x11CB, 0x98); + min_level = reader.ReadByte(); + max_level = reader.ReadByte(); + playstyle = reader.ReadByte(); + partyFlags = (PartyFlags)reader.ReadByte(); + unk = reader.ReadUInt64(); + // 打印输出 + Logger.Write($"name: {name}"); + Logger.Write($"Password: {password}"); + Logger.Write($"Comments: {comments}"); + Logger.Write($"PartyQuest name: {questname}"); + Logger.Write($"Min Level: {min_level}"); + Logger.Write($"Max Level: {max_level}"); + Logger.Write($"Playstyle: {playstyle}"); + Logger.Write($"Party Flags: {partyFlags}"); // 如果 PartyFlags 是枚举类型 + Logger.Write($"Unknown Value: {unk}"); + + context.currentParty.partySetting = new PartySettingsPacket + { + name = name, + password = password, + comments = comments, + min_level = min_level, + max_level = max_level, + playstyle = playstyle, + flags = partyFlags, + unk = unk, + }; + + context.SendPacket(new PartySettingsPacket(context.currentParty.partySetting)); + + if (questname != "") + { + + context.currentParty.questname = questname; + + //TODO questname + string jsonFilePath4 = "data\\quests\\Story Quests\\EP1\\700000 - An Encounter with Xion\\data.json"; + + var quest = JsonRead.DeserializeJson(jsonFilePath4); + + var quests = new List(); + + quests.Add(quest); + + context.currentParty.currentQuest.Quest = quest; + context.SendPacket(new SetQuestInfoPacket(quest.QuestDefiniton, 0, (uint)context._account.AccountId)); + context.SendPacket(new PartySetQuestPacket(0x753A, 0, quest, (uint)context._account.AccountId)); + } + + } + } +} diff --git a/Server/Protocol/Handlers/0E-PartyHandler/0E-0C-QuestCounterHandler.cs b/Server/Protocol/Handlers/0E-PartyHandler/0E-0C-QuestCounterHandler.cs deleted file mode 100644 index 5f5e33a..0000000 --- a/Server/Protocol/Handlers/0E-PartyHandler/0E-0C-QuestCounterHandler.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using PSO2SERVER.Models; -using PSO2SERVER.Protocol.Packets; -using PSO2SERVER.Party; -using PSO2SERVER.Json; -using System.Collections.Generic; - -namespace PSO2SERVER.Protocol.Handlers -{ - [PacketHandlerAttr(0x0E, 0x0C)] - public class QuestDifficultyStartHandler : PacketHandler - { - public string name { get; set; } - public string password { get; set; } - public string comments { get; set; } - public string questname { get; set; } - public byte min_level { get; set; } - public byte max_level { get; set; } - public byte playstyle { get; set; } - public PartyFlags partyFlags { get; set; } - public ulong unk { get; set; } - // Go go maximum code duplication (for now) - public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size) - { - var info = string.Format("[<--] 接收到的数据 (hex): {0}字节", data.Length); - Logger.WriteHex(info, data); - - var reader = new PacketReader(data, position, size); - name = reader.ReadUtf16(0x11CB, 0x98); - password = reader.ReadUtf16(0x11CB, 0x98); - comments = reader.ReadUtf16(0x11CB, 0x98); - questname = reader.ReadUtf16(0x11CB, 0x98); - min_level = reader.ReadByte(); - max_level = reader.ReadByte(); - playstyle = reader.ReadByte(); - partyFlags = (PartyFlags)reader.ReadByte(); - unk = reader.ReadUInt64(); - // 打印输出 - Logger.Write($"name: {name}"); - Logger.Write($"Password: {password}"); - Logger.Write($"Comments: {comments}"); - Logger.Write($"PartyQuest name: {questname}"); - Logger.Write($"Min Level: {min_level}"); - Logger.Write($"Max Level: {max_level}"); - Logger.Write($"Playstyle: {playstyle}"); - Logger.Write($"Party Flags: {partyFlags}"); // 如果 PartyFlags 是枚举类型 - Logger.Write($"Unknown Value: {unk}"); - - //QuestDefiniton def = new QuestDefiniton - //{ - // dateOrSomething = "2012/01/05", - // quest_obj = new ObjectHeader(0x20, ObjectType.PartyQuest), - // questNameid = 30010, - // playTime = QuestEstimatedTime.Short, - // partyType = QuestPartyType.SingleParty, - // difficulties = QuestDifficultyType.NORMAL | QuestDifficultyType.HARD | QuestDifficultyType.VERY_HARD | QuestDifficultyType.SUPER_HARD, - // sub_class_req_level = 1, - // // Not sure why but these need to be set for the quest to be enabled - // quest_type = (QuestType)0xF1, - // field_101 = 1 - //}; - - //QuestDifficulty diff = new QuestDifficulty - //{ - // dateOrSomething = "2012/01/05", - // quest_obj = new ObjectHeader(0x20, ObjectType.PartyQuest), - // name_id = 30010, - // // These are likely bitfields - // area = 0x01, - // planet = 0x03, - // unk1 = 0x03, - // unk2 = 0x00 - //}; - - //var quest = new PartyQuest("arks_010120") - //{ - // questDef = def - //}; - string jsonFilePath4 = "data\\quests\\Story Quests\\EP1\\700000 - An Encounter with Xion\\data.json"; - - var quest = JsonRead.DeserializeJson(jsonFilePath4); - - var quests = new List(); - - quests.Add(quest); - - context.currentParty.currentQuest.Quest = quest; - context.SendPacket(new SetQuestInfoPacket(quest.QuestDefiniton, 0, (uint)context._account.AccountId)); - context.SendPacket(new PartySetQuestPacket(0x753A, 0, quest, (uint)context._account.AccountId)); - - } - } -} diff --git a/Server/Protocol/Handlers/1A-MailHandler/1A-00-MailListRequest.cs b/Server/Protocol/Handlers/1A-MailHandler/1A-00-MailListRequest.cs new file mode 100644 index 0000000..ee6c6d4 --- /dev/null +++ b/Server/Protocol/Handlers/1A-MailHandler/1A-00-MailListRequest.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using PSO2SERVER.Models; +using PSO2SERVER.Protocol.Packets; + +namespace PSO2SERVER.Protocol.Handlers +{ + [PacketHandlerAttr(0x1A, 0x00)] + public class MailListRequest : PacketHandler + { + public struct MailListRequestPacket + { + public uint unk1; + public MailType unk2;//mail type + public uint unk3; + } + + public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size) + { + var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length); + Logger.WriteHex(info, data); + + var reader = new PacketReader(data, position, size); + var pkt = reader.ReadStruct(); + + Logger.WriteObj(pkt); + + List Headers = new List + { + new MailHeader(1234, 5678, 1001, new byte[0x14], 1111, 2222, TimeSpan.FromDays(1), 3333, "SenderName", "MailSubject") + }; + + MailListPacket packet = new MailListPacket(1, 2, 3, 4, new byte[0x4], 100, "PlayerName", "CharacterName", Headers); + + context.SendPacket(packet); + } + } +} diff --git a/Server/Protocol/Handlers/1A-MailHandler/1A-02-DeleteMailRequest.cs b/Server/Protocol/Handlers/1A-MailHandler/1A-02-DeleteMailRequest.cs new file mode 100644 index 0000000..3787b2c --- /dev/null +++ b/Server/Protocol/Handlers/1A-MailHandler/1A-02-DeleteMailRequest.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using PSO2SERVER.Models; +using PSO2SERVER.Protocol.Packets; + +namespace PSO2SERVER.Protocol.Handlers +{ + [PacketHandlerAttr(0x1A, 0x02)] + public class DeleteMailRequest : PacketHandler + { + public struct DeleteMailRequestPacket + { + public List ids; + } + + public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size) + { + var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length); + Logger.WriteHex(info, data); + + var reader = new PacketReader(data, position, size); + var pkt = new DeleteMailRequestPacket(); + pkt.ids = new List(); + + var count = reader.ReadMagic(0xBC5F, 0x0B); + for (int i = 0; i < count; i++) + { + var id = reader.ReadStruct(); + pkt.ids.Add(id); + } + + Logger.WriteObj(pkt); + + context.SendPacket(new DeletedMailPacket(pkt.ids)); + } + } +} diff --git a/Server/Protocol/PacketWriter.cs b/Server/Protocol/PacketWriter.cs index 7a221a3..6568375 100644 --- a/Server/Protocol/PacketWriter.cs +++ b/Server/Protocol/PacketWriter.cs @@ -360,5 +360,45 @@ namespace PSO2SERVER.Protocol { Write(Half.GetBytes(value)); // 写入 2 个字节 } + + // 自动识别并写入枚举类型 + public void WriteEnum(object value) + { + // 确保传入的是枚举类型 + if (value is Enum enumValue) + { + // 获取枚举的底层类型(byte、int 等) + Type underlyingType = Enum.GetUnderlyingType(value.GetType()); + + // 将枚举值转换为底层类型的数值 + object underlyingValue = Convert.ChangeType(enumValue, underlyingType); + + // 根据底层类型进行写入 + if (underlyingType == typeof(byte)) + { + Write((byte)underlyingValue); + } + else if (underlyingType == typeof(short)) + { + Write((short)underlyingValue); + } + else if (underlyingType == typeof(int)) + { + Write((int)underlyingValue); + } + else if (underlyingType == typeof(long)) + { + Write((long)underlyingValue); + } + else + { + throw new InvalidOperationException("Unsupported enum underlying type."); + } + } + else + { + throw new ArgumentException("The value is not an enum type."); + } + } } } \ No newline at end of file diff --git a/Server/Protocol/Packets/0E-PartyPacket/0E-0D-PartySettingsPacket.cs b/Server/Protocol/Packets/0E-PartyPacket/0E-0D-PartySettingsPacket.cs index bc0d8a7..ab51c75 100644 --- a/Server/Protocol/Packets/0E-PartyPacket/0E-0D-PartySettingsPacket.cs +++ b/Server/Protocol/Packets/0E-PartyPacket/0E-0D-PartySettingsPacket.cs @@ -1,4 +1,5 @@ using PSO2SERVER.Models; +using PSO2SERVER.Party; using System; using System.Collections.Generic; using System.Linq; @@ -8,9 +9,57 @@ namespace PSO2SERVER.Protocol.Packets { public class PartySettingsPacket : Packet { + // Name of the party + public string name { get; set; } = string.Empty; + + // Party password + public string password { get; set; } = string.Empty; + + // Party comments + public string comments { get; set; } = string.Empty; + + // Minimum acceptable level + public byte min_level { get; set; } = 0; + + // Maximum acceptable level + public byte max_level { get; set; } = 0; + + // Party playstyle + public byte playstyle { get; set; } = 0; + + // Party flags + public PartyFlags flags { get; set; } = new PartyFlags(); + + // Unknown field, presumably a 64-bit unsigned integer + public ulong unk { get; set; } = 0; public PartySettingsPacket() { + // 初始化默认值 + } + + public PartySettingsPacket(PartySettingsPacket packet) + { + name = packet.name; + password = packet.password; + comments = packet.comments; + min_level = packet.min_level; + max_level = packet.max_level; + playstyle = packet.playstyle; + flags = packet.flags; + unk = packet.unk; + } + + public PartySettingsPacket(string name, string password, string comments, byte minLevel, byte maxLevel, byte playstyle, PartyFlags flags, ulong unk) + { + this.name = name; + this.password = password; + this.comments = comments; + min_level = minLevel; + max_level = maxLevel; + this.playstyle = playstyle; + this.flags = flags; + this.unk = unk; } #region implemented abstract members of Packet @@ -18,12 +67,20 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.WriteUtf16(name, 0x9789, 0xE3); + pkt.WriteUtf16(password, 0x9789, 0xE3); + pkt.WriteUtf16(comments, 0x9789, 0xE3); + pkt.Write(min_level); + pkt.Write(max_level); + pkt.Write(playstyle); + pkt.WriteEnum(flags); + pkt.Write(unk); return pkt.ToArray(); } public override PacketHeader GetHeader() { - return new PacketHeader(0x0E, 0x0D, PacketFlags.None); + return new PacketHeader(0x0E, 0x0D, PacketFlags.PACKED); } #endregion diff --git a/Server/Protocol/Packets/0E-PartyPacket/0E-1A-Unk0E1APacket.cs b/Server/Protocol/Packets/0E-PartyPacket/0E-1A-Unk0E1APacket.cs index 5272a0a..639827f 100644 --- a/Server/Protocol/Packets/0E-PartyPacket/0E-1A-Unk0E1APacket.cs +++ b/Server/Protocol/Packets/0E-PartyPacket/0E-1A-Unk0E1APacket.cs @@ -8,9 +8,15 @@ namespace PSO2SERVER.Protocol.Packets { public class Unk0E1APacket : Packet { + public uint Unk1 { get; set; } = 0; + public uint Unk2 { get; set; } = 0; + public uint Unk3 { get; set; } = 0; - public Unk0E1APacket() + public Unk0E1APacket(uint unk1, uint unk2, uint unk3) { + Unk1 = unk1; + Unk2 = unk2; + Unk3 = unk3; } #region implemented abstract members of Packet @@ -18,6 +24,9 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.Write(Unk1); + pkt.Write(Unk2); + pkt.Write(Unk3); return pkt.ToArray(); } diff --git a/Server/Protocol/Packets/0E-PartyPacket/0E-1B-PartyInfoPacket.cs b/Server/Protocol/Packets/0E-PartyPacket/0E-1B-PartyInfoPacket.cs index 274578f..d7a4ab0 100644 --- a/Server/Protocol/Packets/0E-PartyPacket/0E-1B-PartyInfoPacket.cs +++ b/Server/Protocol/Packets/0E-PartyPacket/0E-1B-PartyInfoPacket.cs @@ -1,4 +1,5 @@ using PSO2SERVER.Models; +using PSO2SERVER.Party; using System; using System.Collections.Generic; using System.Linq; @@ -8,9 +9,14 @@ namespace PSO2SERVER.Protocol.Packets { public class PartyInfoPacket : Packet { + /// Number of populated party infos. + public uint num_of_infos { get; set; } = 0; + public PartyInfo[] partyInfos { get; set; } = new PartyInfo[10]; - public PartyInfoPacket() + public PartyInfoPacket(PartyInfo[] partyInfos) { + num_of_infos = (uint)partyInfos.Length; + this.partyInfos = partyInfos; } #region implemented abstract members of Packet @@ -18,12 +24,14 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.WriteMagic(num_of_infos, 0xE7E8, 0xFF); + pkt.WriteStructArray(partyInfos); return pkt.ToArray(); } public override PacketHeader GetHeader() { - return new PacketHeader(0x0E, 0x1B, PacketFlags.None); + return new PacketHeader(0x0E, 0x1B, PacketFlags.PACKED); } #endregion diff --git a/Server/Protocol/Packets/0E-PartyPacket/0E-1C-PartyInfoStopperPacker.cs b/Server/Protocol/Packets/0E-PartyPacket/0E-1C-PartyInfoStopperPacker.cs index 158e2ec..84a5a79 100644 --- a/Server/Protocol/Packets/0E-PartyPacket/0E-1C-PartyInfoStopperPacker.cs +++ b/Server/Protocol/Packets/0E-PartyPacket/0E-1C-PartyInfoStopperPacker.cs @@ -8,9 +8,11 @@ namespace PSO2SERVER.Protocol.Packets { public class PartyInfoStopperPacker : Packet { + public uint unk { get; set; } = 0; - public PartyInfoStopperPacker() + public PartyInfoStopperPacker(uint unk) { + this.unk = unk; } #region implemented abstract members of Packet @@ -18,6 +20,7 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.Write(unk); return pkt.ToArray(); } diff --git a/Server/Protocol/Packets/1A-MailPacket/1A-01-MailListPacket.cs b/Server/Protocol/Packets/1A-MailPacket/1A-01-MailListPacket.cs index 6b33f31..d8516be 100644 --- a/Server/Protocol/Packets/1A-MailPacket/1A-01-MailListPacket.cs +++ b/Server/Protocol/Packets/1A-MailPacket/1A-01-MailListPacket.cs @@ -8,9 +8,43 @@ namespace PSO2SERVER.Protocol.Packets { public class MailListPacket : Packet { + // Unk1 to Unk6 fields - Assuming these are some form of metadata + public ushort Unk1 { get; set; } = 0; + public ushort Unk2 { get; set; } = 0; + public ushort Unk3 { get; set; } = 0; + public ushort Unk4 { get; set; } = 0; + public byte[] Unk5 { get; set; } = new byte[4]; // byte[4] for unk5 + public uint Unk6 { get; set; } = 0; + // Player name (?) + public string Name { get; set; } = string.Empty; + + // Character name (?) + public string Nickname { get; set; } = string.Empty; + + // Mail headers (List of MailHeader objects) + public List Headers { get; set; } = new List(); + + // Default constructor public MailListPacket() { + // Initialize properties with default values + Unk5 = new byte[4]; // assuming it's a byte array of size 4 + Headers = new List(); + } + + // Custom constructor to initialize values + public MailListPacket(ushort unk1, ushort unk2, ushort unk3, ushort unk4, byte[] unk5, uint unk6, string name, string nickname, List headers) + { + Unk1 = unk1; + Unk2 = unk2; + Unk3 = unk3; + Unk4 = unk4; + Unk5 = unk5; + Unk6 = unk6; + Name = name; + Nickname = nickname; + Headers = headers; } #region implemented abstract members of Packet @@ -18,12 +52,21 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.Write(Unk1); + pkt.Write(Unk2); + pkt.Write(Unk3); + pkt.Write(Unk4); + pkt.Write(Unk5); + pkt.WriteUtf16(Name, 0x36A1, 0xBF); + pkt.WriteUtf16(Nickname, 0x36A1, 0xBF); + pkt.WriteMagic(Headers.Count, 0x36A1, 0xBF); + foreach (var header in Headers) { pkt.WriteStruct(header); } return pkt.ToArray(); } public override PacketHeader GetHeader() { - return new PacketHeader(0x1A, 0x01, PacketFlags.None); + return new PacketHeader(0x1A, 0x01, PacketFlags.PACKED); } #endregion diff --git a/Server/Protocol/Packets/1A-MailPacket/1A-03-DeletedMailPacket.cs b/Server/Protocol/Packets/1A-MailPacket/1A-03-DeletedMailPacket.cs index 3cc22e3..4875e8b 100644 --- a/Server/Protocol/Packets/1A-MailPacket/1A-03-DeletedMailPacket.cs +++ b/Server/Protocol/Packets/1A-MailPacket/1A-03-DeletedMailPacket.cs @@ -8,9 +8,13 @@ namespace PSO2SERVER.Protocol.Packets { public class DeletedMailPacket : Packet { + public List Ids { get; set; } = new List(); + public uint unk { get; set; } = 0;//maybe delete status - public DeletedMailPacket() + public DeletedMailPacket(List ids) { + Ids = ids; + unk = 1; } #region implemented abstract members of Packet @@ -18,12 +22,15 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.WriteMagic(Ids.Count, 0x421C, 0x56); + foreach (MailId id in Ids) {pkt.WriteStruct(id);} + pkt.Write(unk); return pkt.ToArray(); } public override PacketHeader GetHeader() { - return new PacketHeader(0x1A, 0x03, PacketFlags.None); + return new PacketHeader(0x1A, 0x03, PacketFlags.PACKED); } #endregion diff --git a/Server/Server.csproj b/Server/Server.csproj index 9ba2479..5998040 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -14,6 +14,7 @@ v4.8 + false publish\ true Disk @@ -26,7 +27,6 @@ true 0 1.0.0.%2a - false false true @@ -323,6 +323,7 @@ + @@ -352,6 +353,8 @@ + + @@ -399,7 +402,7 @@ - +