新增部分数据包修正

This commit is contained in:
Longfeng Qin 2024-12-11 14:07:19 +08:00
parent 9f16542f51
commit 936ef8a40a
16 changed files with 528 additions and 112 deletions

View File

@ -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(); // 获取字节流
}
}
}
}

68
Server/Models/Mail.cs Normal file
View File

@ -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
}
}

View File

@ -392,6 +392,9 @@ namespace PSO2SERVER.Models
public QuestData Quest { get; set; }
public ushort Diff { get; set; } = 0;
public PartyQuest()
{
}
public PartyQuest(string name)
{

View File

@ -22,12 +22,17 @@ namespace PSO2SERVER.Party
private List<Client> 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<Client>();
members = new List<Client>();
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)
}
}

View File

@ -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<QuestData>(jsonFilePath4);
var quests = new List<QuestData>();
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));
}
}
}
}

View File

@ -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<QuestData>(jsonFilePath4);
var quests = new List<QuestData>();
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));
}
}
}

View File

@ -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<MailListRequestPacket>();
Logger.WriteObj(pkt);
List<MailHeader> Headers = new List<MailHeader>
{
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);
}
}
}

View File

@ -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<MailId> 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<MailId>();
var count = reader.ReadMagic(0xBC5F, 0x0B);
for (int i = 0; i < count; i++)
{
var id = reader.ReadStruct<MailId>();
pkt.ids.Add(id);
}
Logger.WriteObj(pkt);
context.SendPacket(new DeletedMailPacket(pkt.ids));
}
}
}

View File

@ -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.");
}
}
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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();
}

View File

@ -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<MailHeader> Headers { get; set; } = new List<MailHeader>();
// 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<MailHeader>();
}
// Custom constructor to initialize values
public MailListPacket(ushort unk1, ushort unk2, ushort unk3, ushort unk4, byte[] unk5, uint unk6, string name, string nickname, List<MailHeader> 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

View File

@ -8,9 +8,13 @@ namespace PSO2SERVER.Protocol.Packets
{
public class DeletedMailPacket : Packet
{
public List<MailId> Ids { get; set; } = new List<MailId>();
public uint unk { get; set; } = 0;//maybe delete status
public DeletedMailPacket()
public DeletedMailPacket(List<MailId> 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

View File

@ -14,6 +14,7 @@
</NuGetPackageImportStamp>
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
<TargetFrameworkProfile />
<IsWebBootstrapper>false</IsWebBootstrapper>
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
@ -26,7 +27,6 @@
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
@ -323,6 +323,7 @@
<Compile Include="Models\Inventory.cs" />
<Compile Include="Models\ItemAttributes.cs" />
<Compile Include="Models\ItemsAdditional.cs" />
<Compile Include="Models\Mail.cs" />
<Compile Include="Models\Mission.cs" />
<Compile Include="Models\NetInterface.cs" />
<Compile Include="Models\Orders.cs" />
@ -352,6 +353,8 @@
<Compile Include="Protocol\Handlers\11-ClientHandler\11-EB-NicknameCheckRequest - 复制.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-52-CreateCharacterInviteNickname.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-C7-CharacterShipInfoRequest.cs" />
<Compile Include="Protocol\Handlers\1A-MailHandler\1A-02-DeleteMailRequest.cs" />
<Compile Include="Protocol\Handlers\1A-MailHandler\1A-00-MailListRequest.cs" />
<Compile Include="Protocol\Handlers\1C-CharacterInfoHandler\1C-64-UNK.cs" />
<Compile Include="Protocol\Handlers\1C-CharacterInfoHandler\1C-46-UNK.cs" />
<Compile Include="Protocol\Handlers\1C-CharacterInfoHandler\1C-0E-UNK.cs" />
@ -399,7 +402,7 @@
<Compile Include="Protocol\Handlers\11-ClientHandler\11-2B-LogOutRequest.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-3E-CharacterSpawn.cs" />
<Compile Include="Protocol\Handlers\04-ObjectHandler\04-14-ObjectInteract.cs" />
<Compile Include="Protocol\Handlers\0E-PartyHandler\0E-0C-QuestCounterHandler.cs" />
<Compile Include="Protocol\Handlers\0E-PartyHandler\0E-0C-NewPartySettings.cs" />
<Compile Include="Protocol\Handlers\03-ServerHandler\03-34-TeleportCasinoToLobby.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-41-CreateCharacterOne.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-2D-SystemInformation.cs" />