diff --git a/Server/Client.cs b/Server/Client.cs index 7ca1082..888929b 100644 --- a/Server/Client.cs +++ b/Server/Client.cs @@ -321,49 +321,6 @@ namespace PSO2SERVER } } - public class NetInterface - { - /// <summary> - /// Interface status. - /// </summary> - public uint State { get; set; } - - /// <summary> - /// Interface MAC address. - /// </summary> - public string Mac { get; set; } = new string('\0', 0x18); // 以字符串形式存储 - - public void ReadFromStream(PacketReader reader) - { - State = reader.ReadUInt32(); - Mac = Encoding.ASCII.GetString(reader.ReadBytes(0x18)).TrimEnd('\0'); - } - - public override string ToString() - { - return $"状态: {State}, MAC: {Mac}"; - } - - public void UpdateNetInterface(int id, int accountid, NetInterface updatedInterface) - { - using (var db = new ServerEf()) - { - var existingInterface = db.AccountsNetInterFaces - .FirstOrDefault(x => x.AccountId == accountid && x.id == id); - - if (existingInterface != null) - { - // 更新其他字段 - existingInterface.State = (int)updatedInterface.State; - existingInterface.Mac = updatedInterface.Mac; - - // 保存更改 - db.SaveChanges(); - } - } - } - } - public enum Language : uint { Japanese = 0, diff --git a/Server/Models/FixedPackets.cs b/Server/Models/FixedPackets.cs index 7d3675f..8a33068 100644 --- a/Server/Models/FixedPackets.cs +++ b/Server/Models/FixedPackets.cs @@ -1,4 +1,5 @@ using System; +using System.Net.Sockets; using System.Runtime.InteropServices; namespace PSO2SERVER.Models @@ -20,6 +21,10 @@ namespace PSO2SERVER.Models this.Flags2 = flags2; } + public PacketHeader(int size, byte type, byte subtype, PacketFlags flags1, PacketFlags flags2) : this(size, type, subtype, (byte)flags1, (byte)flags1) + { + } + public PacketHeader(byte type, byte subtype) : this(type, subtype, (byte)0) { } @@ -31,6 +36,24 @@ namespace PSO2SERVER.Models public PacketHeader(byte type, byte subtype, PacketFlags packetFlags) : this(type, subtype, (byte)packetFlags) { } + + // ToBytes 方法的实现 + public byte[] ToBytes() + { + byte[] bytes = new byte[sizeof(UInt32) + sizeof(byte) * 4]; // 计算结构体的总大小 + int index = 0; + + // 将结构体每个字段转换为字节 + Array.Copy(BitConverter.GetBytes(Size), 0, bytes, index, sizeof(UInt32)); + index += sizeof(UInt32); + + bytes[index++] = Type; + bytes[index++] = Subtype; + bytes[index++] = Flags1; + bytes[index++] = Flags2; + + return bytes; + } } /// Packet flags. diff --git a/Server/Models/NetInterface.cs b/Server/Models/NetInterface.cs new file mode 100644 index 0000000..e3f7be8 --- /dev/null +++ b/Server/Models/NetInterface.cs @@ -0,0 +1,54 @@ +using PSO2SERVER.Database; +using PSO2SERVER.Protocol; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PSO2SERVER.Models +{ + public class NetInterface + { + /// <summary> + /// Interface status. + /// </summary> + public uint State { get; set; } + + /// <summary> + /// Interface MAC address. + /// </summary> + public string Mac { get; set; } = new string('\0', 0x18); // 以字符串形式存储 + + public void ReadFromStream(PacketReader reader) + { + State = reader.ReadUInt32(); + Mac = Encoding.ASCII.GetString(reader.ReadBytes(0x18)).TrimEnd('\0'); + } + + public override string ToString() + { + return $"状态: {State}, MAC: {Mac}"; + } + + public void UpdateNetInterface(int id, int accountid, NetInterface updatedInterface) + { + using (var db = new ServerEf()) + { + var existingInterface = db.AccountsNetInterFaces + .FirstOrDefault(x => x.AccountId == accountid && x.id == id); + + if (existingInterface != null) + { + // 更新其他字段 + existingInterface.State = (int)updatedInterface.State; + existingInterface.Mac = updatedInterface.Mac; + + // 保存更改 + db.SaveChanges(); + } + } + } + } + +} diff --git a/Server/Models/Orders.cs b/Server/Models/Orders.cs new file mode 100644 index 0000000..fa40f77 --- /dev/null +++ b/Server/Models/Orders.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PSO2SERVER.Models +{ + public class Orders + { + public struct ClientOrder + { + public uint unk1; + public uint id; + public uint status; + public uint finish_date; + } + + public struct OrderStatus + { + public uint unk1; + public uint unk2; + public uint unk3; + public uint unk4; + public uint unk5; + public uint unk6; + } + } +} diff --git a/Server/Models/PSOData.cs b/Server/Models/PSOData.cs index ee60521..bfb5604 100644 --- a/Server/Models/PSOData.cs +++ b/Server/Models/PSOData.cs @@ -53,7 +53,7 @@ namespace PSO2SERVER.Models } // 从数据流中读取数据并填充到当前结构体 - public void ReadFromStream(PacketReader reader) + public void ReadObjectHeaderFromStream(PacketReader reader) { ID = reader.ReadUInt32(); // 读取对象ID padding = reader.ReadUInt32(); // 读取填充部分 @@ -62,7 +62,7 @@ namespace PSO2SERVER.Models } // 将当前结构体的数据写入到数据流 - public void WriteToStream(PacketWriter writer) + public void WriteObjectHeaderToStream(PacketWriter writer) { writer.Write(ID); // 写入对象ID writer.Write(padding); // 写入填充部分 diff --git a/Server/Models/RevealedRegions.cs b/Server/Models/RevealedRegions.cs new file mode 100644 index 0000000..759aa38 --- /dev/null +++ b/Server/Models/RevealedRegions.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace PSO2SERVER.Models +{ + /// <summary> + /// Revealed minimap regions + /// </summary> + public class RevealedRegions + { + // 内部实现: + // 该结构体由一个大小为[10]的字节数组组成,表示一个 8x10 的已揭示区域网格 + // (即 10 列 8 行)。每一位(bit)表示一个区域是否已揭示。 + // 位是从右到左索引的(即从 LSB 到 MSB),字节是从左到右索引的(arr[0]表示区域A1-8)。 + // 获取该数组中的某个值可以通过如下方式: + // + // 示例代码: + // bool GetBit(byte[] arr, int row, int col) + // { + // // 确保行和列的范围有效 + // if (row < 0 || row >= 8 || col < 0 || col >= 10) + // throw new ArgumentOutOfRangeException(); + // + // // 计算对应位置的位偏移 + // int offset = row * 10 + col; + // int byteOffset = offset / 8; + // int bitOffset = offset % 8; + // + // // 获取相应的位值 + // return (arr[byteOffset] >> bitOffset & 1) == 1; + // } + + // 使用一个长度为 10 的字节数组,表示 8 行 10 列的区域位图。 + // Lsb0 表示最低有效位在字节的最右侧。 + public byte[] zones = new byte[10]; + + // 默认构造函数 + public RevealedRegions() + { + } + + // 构造函数 - 用指定数据初始化 + public RevealedRegions(byte[] data) + { + // 如果传入的 unk2 长度小于 10,则填充剩余部分为 0 + if (data.Length <= 10) + { + zones = data.Concat(new byte[10 - data.Length]).ToArray(); + } + else + { + // 如果传入的 unk2 长度大于 10,则截取前 10 字节 + zones = data.Take(10).ToArray(); + } + } + + /// <summary> + /// 获取指定行列位置的位值 + /// </summary> + /// <param name="row">行索引(0 到 7)</param> + /// <param name="col">列索引(0 到 9)</param> + /// <returns>该位置的位值(true = 已揭示,false = 未揭示)</returns> + public bool GetBit(int row, int col) + { + // 确保行列值在有效范围内 + if (row < 0 || row >= 8 || col < 0 || col >= 10) + { + throw new ArgumentOutOfRangeException(); + } + + // 计算对应位置的偏移 + int offset = row * 10 + col; + int byteOffset = offset / 8; + int bitOffset = offset % 8; + + // 获取并返回该位置的位值 + return (zones[byteOffset] >> bitOffset & 1) == 1; + } + + /// <summary> + /// 设置指定行列位置的位值 + /// </summary> + /// <param name="row">行索引(0 到 7)</param> + /// <param name="col">列索引(0 到 9)</param> + /// <param name="value">设置的值(true = 设置为已揭示,false = 设置为未揭示)</param> + public void SetBit(int row, int col, bool value) + { + // 确保行列值在有效范围内 + if (row < 0 || row >= 8 || col < 0 || col >= 10) + { + throw new ArgumentOutOfRangeException(); + } + + // 计算对应位置的偏移 + int offset = row * 10 + col; + int byteOffset = offset / 8; + int bitOffset = offset % 8; + + // 设置对应位置的位值 + if (value) + { + // 设置为1 + zones[byteOffset] |= (byte)(1 << bitOffset); + } + else + { + // 设置为0 + zones[byteOffset] &= (byte)~(1 << bitOffset); + } + } + // 读取数据 + public static RevealedRegions Read(BinaryReader reader) + { + try + { + byte[] data = reader.ReadBytes(10); + if (data.Length != 10) + throw new InvalidDataException("Failed to read 10 bytes for zones data."); + + return new RevealedRegions(data); + } + catch (Exception ex) + { + throw new PacketError("RevealedRegions", "zone_bits", ex); + } + } + + // 写入数据 + public void Write(BinaryWriter writer) + { + try + { + writer.Write(zones); + } + catch (Exception ex) + { + throw new PacketError("RevealedRegions", "zone_bits", ex); + } + } + + // 索引操作,获取指定行的 10 位数据 + public BitSlice GetRow(int index) + { + if (index < 0 || index >= 8) + throw new ArgumentOutOfRangeException(); + + byte[] row = new byte[10]; + Array.Copy(zones, index * 10, row, 0, 10); + return new BitSlice(row); + } + + // 用于调试输出 + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + sb.Append("["); + for (int i = 0; i < 8; i++) + { + sb.Append(GetRow(i).ToString()); + if (i < 7) sb.Append(", "); + } + sb.Append("]"); + return sb.ToString(); + } + + // Helper class to represent a slice of bits + public class BitSlice + { + private byte[] data; + + public BitSlice(byte[] data) + { + this.data = data; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + foreach (byte b in data) + { + sb.Append(Convert.ToString(b, 2).PadLeft(8, '0')); + } + return sb.ToString(); + } + } + + // Error handling class for packet-related errors + public class PacketError : Exception + { + public string PacketName { get; } + public string FieldName { get; } + public new Exception InnerException { get; } + + public PacketError(string packetName, string fieldName, Exception innerException) + : base($"Error in packet '{packetName}', field '{fieldName}'", innerException) + { + PacketName = packetName; + FieldName = fieldName; + InnerException = innerException; + } + } + } +} diff --git a/Server/Models/ShipData.cs b/Server/Models/ShipData.cs index 143a1d8..c1a5f2c 100644 --- a/Server/Models/ShipData.cs +++ b/Server/Models/ShipData.cs @@ -9,7 +9,8 @@ namespace PSO2SERVER.Models Online, Busy, Full, - Offline + Offline, + Undefined = 0xFFFF } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] diff --git a/Server/Models/block.cs b/Server/Models/block.cs index 8d3dc77..f09f9a3 100644 --- a/Server/Models/block.cs +++ b/Server/Models/block.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace PSO2SERVER.Models { - public class block + public class Block { public uint unk1 { get; set; } public byte unk2 { get; set; } diff --git a/Server/Protocol/Handlers/0B-QuestHandler/0B-19-QuestDifficultyRequestHandler.cs b/Server/Protocol/Handlers/0B-QuestHandler/0B-19-QuestDifficultyRequestHandler.cs index 0c56813..c690ef5 100644 --- a/Server/Protocol/Handlers/0B-QuestHandler/0B-19-QuestDifficultyRequestHandler.cs +++ b/Server/Protocol/Handlers/0B-QuestHandler/0B-19-QuestDifficultyRequestHandler.cs @@ -22,7 +22,7 @@ namespace PSO2SERVER.Protocol.Handlers for (uint i = 0; i < questCount; i++) { var qobj = new ObjectHeader(); - qobj.ReadFromStream(reader); + qobj.ReadObjectHeaderFromStream(reader); Quests.Add(qobj); // 打印每个任务的 ID 和类型,方便调试 diff --git a/Server/Protocol/Handlers/11-ClientHandler/11-00-SegaIDLogin.cs b/Server/Protocol/Handlers/11-ClientHandler/11-00-SegaIDLogin.cs index d2d2aa5..be97d65 100644 --- a/Server/Protocol/Handlers/11-ClientHandler/11-00-SegaIDLogin.cs +++ b/Server/Protocol/Handlers/11-ClientHandler/11-00-SegaIDLogin.cs @@ -204,20 +204,20 @@ namespace PSO2SERVER.Protocol.Handlers } //TODO 方便GM测试 - if (Password != user.Password) - { - if (Password == "") - { - error = "密碼為空 #2."; - user = null; - } - else - if (!BCrypt.Net.BCrypt.Verify(Password, user.Password)) - { - error = "密碼錯誤."; - user = null; - } - } + //if (Password != user.Password) + //{ + // if (Password == "") + // { + // error = "密碼為空 #2."; + // user = null; + // } + // else + // if (!BCrypt.Net.BCrypt.Verify(Password, user.Password)) + // { + // error = "密碼錯誤."; + // user = null; + // } + //} } context.SendPacket(new LoginDataPacket("夢幻之星2", error, (user == null) ? (uint)0 : (uint)user.AccountId)); diff --git a/Server/Protocol/Handlers/11-ClientHandler/11-14-BlockLogin.cs b/Server/Protocol/Handlers/11-ClientHandler/11-14-BlockLogin.cs index 0f074e5..a4d9544 100644 --- a/Server/Protocol/Handlers/11-ClientHandler/11-14-BlockLogin.cs +++ b/Server/Protocol/Handlers/11-ClientHandler/11-14-BlockLogin.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using PSO2SERVER.Models; using PSO2SERVER.Protocol.Packets; @@ -7,10 +8,38 @@ namespace PSO2SERVER.Protocol.Handlers [PacketHandlerAttr(0x11, 0x14)] public class BlockLogin : PacketHandler { + // Player ID + public ulong PlayerId { get; set; } + + // Unknown fields + public byte Unk1 { get; set; } + public byte Unk2 { get; set; } + public ushort Unk3 { get; set; } + public uint Unk4 { get; set; } + public uint Unk5 { get; set; } + + // Version ID (32 bytes) + public byte[] VerId { get; set; } = new byte[0x20]; + + // Clients' active network interfaces + public List<NetInterface> Interfaces { get; set; } + + // Login challenge + public uint Challenge { get; set; } + + // Unknown data, fixed length (196 bytes) + public byte[] Unk6 { get; set; } = new byte[0xC4]; + + // Unknown field, 16 bytes + public byte[] Unk7 { get; set; } = new byte[0x10]; + 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); + } } } diff --git a/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-01-TakenOrdersRequest.cs b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-01-TakenOrdersRequest.cs new file mode 100644 index 0000000..4f04db9 --- /dev/null +++ b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-01-TakenOrdersRequest.cs @@ -0,0 +1,29 @@ +using System; +using PSO2SERVER.Models; +using PSO2SERVER.Protocol.Packets; + +namespace PSO2SERVER.Protocol.Handlers +{ + [PacketHandlerAttr(0x1F, 0x01)] + public class TakenOrdersRequest : PacketHandler + { + public struct TakenOrdersRequestPacket + { + public uint unk1; + public uint unk2; + public uint unk3; + public uint unk4; + } + + 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 packet = reader.ReadStruct<TakenOrdersRequestPacket>(); + + Logger.Write($"unk1 = {packet.unk1},unk2 = {packet.unk2},unk3 = {packet.unk3},unk4 = {packet.unk4}"); + } + } +} diff --git a/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-02-OrderListRequest.cs b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-02-OrderListRequest.cs new file mode 100644 index 0000000..a1e6b00 --- /dev/null +++ b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-02-OrderListRequest.cs @@ -0,0 +1,41 @@ +using System; +using PSO2SERVER.Models; +using PSO2SERVER.Protocol.Packets; + +namespace PSO2SERVER.Protocol.Handlers +{ + [PacketHandlerAttr(0x1F, 0x02)] + public class OrderListRequest : PacketHandler + { + public struct OrderListRequestPacket + { + public uint unk1; + public string source; + public uint unk3; + public uint unk4; + public uint unk5; + public uint unk6; + } + + 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 packet = new OrderListRequestPacket + { + unk1 = reader.ReadUInt32(), + source = reader.ReadAscii(0x70B2, 0x9E), + unk3 = reader.ReadUInt32(), + unk4 = reader.ReadUInt32(), + unk5 = reader.ReadUInt32(), + unk6 = reader.ReadUInt32(), + }; + + Logger.Write($"unk1 = {packet.unk1},source = {packet.source},unk3 = {packet.unk3},unk4 = {packet.unk4},unk5 = {packet.unk5},unk6 = {packet.unk6}"); + + context.SendPacket(new OrderListPacket()); + } + } +} diff --git a/Server/Protocol/Handlers/1F-UNKHandler/1F-09-UNK1F09.cs b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-09-UNK1F09.cs similarity index 56% rename from Server/Protocol/Handlers/1F-UNKHandler/1F-09-UNK1F09.cs rename to Server/Protocol/Handlers/1F-ClientOrderHandler/1F-09-UNK1F09.cs index 5c73948..5eb60ea 100644 --- a/Server/Protocol/Handlers/1F-UNKHandler/1F-09-UNK1F09.cs +++ b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-09-UNK1F09.cs @@ -7,10 +7,20 @@ namespace PSO2SERVER.Protocol.Handlers [PacketHandlerAttr(0x1F, 0x09)] public class _1F_09_UNK : PacketHandler { + public uint unk1 { get; set; } + public string source { get; set; } 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); + //unk1 = reader.ReadUInt32(); + //source = reader.ReadAscii(0x1875, 0x1F); + + //// 打印日志 + //Logger.Write($"unk1: {unk1}"); + //Logger.Write($"source: {source}"); } } } diff --git a/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-0F-UNK.cs b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-0F-UNK.cs new file mode 100644 index 0000000..a3788d9 --- /dev/null +++ b/Server/Protocol/Handlers/1F-ClientOrderHandler/1F-0F-UNK.cs @@ -0,0 +1,27 @@ +using System; +using PSO2SERVER.Models; +using PSO2SERVER.Protocol.Packets; + +namespace PSO2SERVER.Protocol.Handlers +{ + [PacketHandlerAttr(0x1F, 0x0F)] + public class _1F_0F_UNK : PacketHandler + { + public struct Unk1F0FPacket + { + public uint unk1; + public uint unk2; + } + + 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 packet = reader.ReadStruct<Unk1F0FPacket>(); + + Logger.Write($"unk1 = {packet.unk1}, unk2 = {packet.unk2}"); + } + } +} diff --git a/Server/Protocol/Packet.cs b/Server/Protocol/Packet.cs index 8e4adfb..6b9dc24 100644 --- a/Server/Protocol/Packet.cs +++ b/Server/Protocol/Packet.cs @@ -1,4 +1,5 @@ using PSO2SERVER.Models; +using System.Collections.Generic; namespace PSO2SERVER.Protocol { @@ -6,5 +7,26 @@ namespace PSO2SERVER.Protocol { public abstract byte[] Build(); public abstract PacketHeader GetHeader(); + + // 新增:获取整体数据包字节表示 + public byte[] GetPacketBytes() + { + var header = GetHeader(); // 获取包头 + var packetBody = Build(); // 获取包体 + + // 如果包头的大小为0,则重新计算 + if (header.Size == 0) + { + // 包头(包括固定的前四个字节)的大小加上包体的大小 + header.Size = (uint)(header.ToBytes().Length + packetBody.Length); + } + + // 将包头与包体合并 + var totalPacket = new List<byte>(); + totalPacket.AddRange(header.ToBytes()); // 包头转换为字节并加入 + totalPacket.AddRange(packetBody); // 包体加入 + + return totalPacket.ToArray(); // 返回整个数据包字节数组 + } } } \ No newline at end of file diff --git a/Server/Protocol/PacketReader.cs b/Server/Protocol/PacketReader.cs index 5be226f..cbe64d9 100644 --- a/Server/Protocol/PacketReader.cs +++ b/Server/Protocol/PacketReader.cs @@ -37,27 +37,6 @@ namespace PSO2SERVER.Protocol return (ReadUInt32() ^ xor) - sub; } - // 示例方法:读取 ASCII 字符串 - public string ReadAsciiForPosition(int start, int length) - { - try - { - if (_position + length > _size) - { - throw new ArgumentOutOfRangeException(nameof(start), $"Reading beyond data boundary in {nameof(ReadAsciiForPosition)}"); - } - - var result = Encoding.ASCII.GetString(_data, _position, length); - _position += length; - return result; - } - catch (Exception ex) - { - Logger.WriteException(nameof(ReadAsciiForPosition), ex); - throw; - } - } - public string ReadAscii(uint xor, uint sub) { var magic = ReadMagic(xor, sub); diff --git a/Server/Protocol/PacketWriter.cs b/Server/Protocol/PacketWriter.cs index 9768ae9..ea3caf0 100644 --- a/Server/Protocol/PacketWriter.cs +++ b/Server/Protocol/PacketWriter.cs @@ -174,6 +174,24 @@ namespace PSO2SERVER.Protocol Write(strArr); } + // 新增的 WriteStructArray 方法 + public unsafe void WriteStructArray<T>(T[] structures) where T : struct + { + int totalSize = Marshal.SizeOf(typeof(T)) * structures.Length; + var strArr = new byte[totalSize]; + + fixed (byte* ptr = strArr) + { + for (int i = 0; i < structures.Length; i++) + { + byte* currentPtr = ptr + (i * Marshal.SizeOf(typeof(T))); + Marshal.StructureToPtr(structures[i], (IntPtr)currentPtr, false); + } + } + + Write(strArr); + } + public byte[] ToArray() { var ms = (MemoryStream) BaseStream; diff --git a/Server/Protocol/Packets/0B-QuestPacket/0B-13-MinimapRevealPacket.cs b/Server/Protocol/Packets/0B-QuestPacket/0B-13-MinimapRevealPacket.cs index 88ec131..effbae2 100644 --- a/Server/Protocol/Packets/0B-QuestPacket/0B-13-MinimapRevealPacket.cs +++ b/Server/Protocol/Packets/0B-QuestPacket/0B-13-MinimapRevealPacket.cs @@ -8,32 +8,21 @@ namespace PSO2SERVER.Protocol.Packets { public class MinimapRevealPacket : Packet { - private ObjectHeader unk1 { get; set; } + /// World object where revealing was done. + private ObjectHeader world { get; set; } + /// Receivers party object (?). private ObjectHeader party { get; set; } private uint zone_id { get; set; } - private byte[] unk2 { get; set; } = new byte[10]; + /// Bitset of revealed regions. + private RevealedRegions revealed_zones { get; set; } = new RevealedRegions(); // 构造函数,允许在创建时初始化字段 - public MinimapRevealPacket(ObjectHeader unk1, ObjectHeader party, uint zone_id, byte[] unk2) + public MinimapRevealPacket(ObjectHeader world, ObjectHeader party, uint zone_id, byte[] revealed_zones) { - this.unk1 = unk1; + this.world = world; this.party = party; this.zone_id = zone_id; - - // 如果传入的 unk2 长度小于 10,则填充剩余部分为 0 - if (unk2.Length <= 10) - { - this.unk2 = unk2.Concat(new byte[10 - unk2.Length]).ToArray(); - } - else - { - // 如果传入的 unk2 长度大于 10,则截取前 10 字节 - this.unk2 = unk2.Take(10).ToArray(); - } - } - - public MinimapRevealPacket() - { + this.revealed_zones = new RevealedRegions(revealed_zones); } #region implemented abstract members of Packet @@ -41,11 +30,10 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); - pkt.WriteStruct(unk1); + pkt.WriteStruct(world); pkt.WriteStruct(party); pkt.Write(zone_id); - for (var i = 0; i < 10; i++) - pkt.Write(unk2[i]); + revealed_zones.Write(pkt); return pkt.ToArray(); } diff --git a/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs b/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs index 01b641f..e4fc395 100644 --- a/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs +++ b/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs @@ -1,16 +1,11 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using Mysqlx; -using PSO2SERVER.Models; +using PSO2SERVER.Models; +using System; namespace PSO2SERVER.Protocol.Packets { class LoginDataPacket : Packet { - public enum LoginStatus : UInt32 + public enum LoginStatus : uint { /// <summary> /// Login was successful. @@ -31,7 +26,7 @@ namespace PSO2SERVER.Protocol.Packets public LoginStatus Status; public string Error; public ObjectHeader Player; - public string BlockName; + public string BlockName = new string(' ', 0x20); public float Unk1; public uint Unk2; public uint LevelCap; @@ -45,235 +40,130 @@ namespace PSO2SERVER.Protocol.Packets public uint Unk11; public float Unk12; public uint Unk13; - public float[] Unk14; // Length: 10 - public float[] Unk15; // Length: 21 + public float[] Unk14 = new float[10]; // Length: 10 + public float[] Unk15 = new float[21]; // Length: 21 public float Unk16; public float Unk17; - public float[] Unk18; // Length: 9 - public uint[] Unk19; // Length: 2 + public float[] Unk18 = new float[9]; // Length: 9 + public uint[] Unk19 = new uint[2]; // Length: 2 public uint Unk20; public uint Unk21; - public float[] Unk22; // Length: 3 + public float[] Unk22 = new float[3]; // Length: 3 public uint Unk23; public float Unk24; public float Unk25; public uint Unk26; - public byte[] Unk27; // Length: 12 - public string Unk28; + public byte[] Unk27 = new byte[12]; // Length: 12 + public string Unk28 = new string(' ', 0x20); public uint Unk29; - public string Unk30; + public string Unk30 = new string(' ', 0x20); public uint Unk31; - private string ReadFixedString(PacketReader reader, int length) - { - byte[] bytes = reader.ReadBytes(length); - return Encoding.UTF8.GetString(bytes).TrimEnd('\0'); - } - public void ReadFromStream(PacketReader reader) - { - Status = (LoginStatus)reader.ReadInt32(); - Error = ReadFixedString(reader, 32); // 0x20 = 32 - Player.ReadFromStream(reader); - BlockName = ReadFixedString(reader, 32); - Unk1 = reader.ReadSingle(); - Unk2 = reader.ReadUInt32(); - LevelCap = reader.ReadUInt32(); - LevelCap2 = reader.ReadUInt32(); - Unk5 = reader.ReadUInt32(); - Unk6 = reader.ReadSingle(); - Unk7 = reader.ReadSingle(); - Unk8 = reader.ReadUInt32(); - Unk9 = reader.ReadSingle(); - Unk10 = reader.ReadSingle(); - Unk11 = reader.ReadUInt32(); - Unk12 = reader.ReadSingle(); - Unk13 = reader.ReadUInt32(); - - Unk14 = new float[10]; - for (int i = 0; i < Unk14.Length; i++) - { - Unk14[i] = reader.ReadSingle(); - } - - Unk15 = new float[21]; - for (int i = 0; i < Unk15.Length; i++) - { - Unk15[i] = reader.ReadSingle(); - } - - Unk16 = reader.ReadSingle(); - Unk17 = reader.ReadSingle(); - - Unk18 = new float[9]; - for (int i = 0; i < Unk18.Length; i++) - { - Unk18[i] = reader.ReadSingle(); - } - - Unk19 = new uint[2]; - for (int i = 0; i < Unk19.Length; i++) - { - Unk19[i] = reader.ReadUInt32(); - } - - Unk20 = reader.ReadUInt32(); - Unk21 = reader.ReadUInt32(); - - Unk22 = new float[3]; - for (int i = 0; i < Unk22.Length; i++) - { - Unk22[i] = reader.ReadSingle(); - } - - Unk23 = reader.ReadUInt32(); - Unk24 = reader.ReadSingle(); - Unk25 = reader.ReadSingle(); - Unk26 = reader.ReadUInt32(); - Unk27 = reader.ReadBytes(12); - Unk28 = ReadFixedString(reader, 32); - Unk29 = reader.ReadUInt32(); - Unk30 = ReadFixedString(reader, 32); - Unk31 = reader.ReadUInt32(); - } - - private void WriteFixedString(PacketWriter writer, string str, int length) - { - byte[] bytes = new byte[length]; - byte[] strBytes = Encoding.UTF8.GetBytes(str); - Array.Copy(strBytes, bytes, Math.Min(strBytes.Length, length)); - writer.Write(bytes); - } - - public void WriteToStream(PacketWriter writer) - { - writer.Write((int)Status); - writer.WriteUtf16(Error, 0x8BA4, 0xB6); - - if (Player.ID == 0) - { - for (var i = 0; i < 0xEC; i++) - writer.Write((byte)0); - } - else - { - //WriteFixedString(writer, Error, 32); - Player.WriteToStream(writer); - WriteFixedString(writer, BlockName, 32); - writer.Write(Unk1); - writer.Write(Unk2); - writer.Write(LevelCap); - writer.Write(LevelCap2); - writer.Write(Unk5); - writer.Write(Unk6); - writer.Write(Unk7); - writer.Write(Unk8); - writer.Write(Unk9); - writer.Write(Unk10); - writer.Write(Unk11); - writer.Write(Unk12); - writer.Write(Unk13); - - foreach (var val in Unk14) - { - writer.Write(val); - } - - foreach (var val in Unk15) - { - writer.Write(val); - } - - writer.Write(Unk16); - writer.Write(Unk17); - - foreach (var val in Unk18) - { - writer.Write(val); - } - - foreach (var val in Unk19) - { - writer.Write(val); - } - - writer.Write(Unk20); - writer.Write(Unk21); - - foreach (var val in Unk22) - { - writer.Write(val); - } - - writer.Write(Unk23); - writer.Write(Unk24); - writer.Write(Unk25); - writer.Write(Unk26); - writer.Write(Unk27); - WriteFixedString(writer, Unk28, 32); - writer.Write(Unk29); - WriteFixedString(writer, Unk30, 32); - writer.Write(Unk31); - } - } - public LoginDataPacket(string blockName, string error, uint userid) { Status = (userid == 0) ? LoginStatus.Failure : LoginStatus.Success; Error = error; - Player.ID = userid; - Player.ObjectType = ObjectType.Player; + Player = new ObjectHeader(userid, ObjectType.Player); BlockName = blockName; + Unk1 = 0x42700000; + Unk2 = 7; + LevelCap = 0x0A; + LevelCap2 = 1; + Unk5 = 0x41200000; + Unk6 = 0x40A00000; + Unk7 = 11; + Unk8 = 0x3F800000; + Unk9 = 0x42960000; + Unk10 = 40; + Unk11 = 0x41200000; + Unk12 = 1; + Unk13 = 1120403456; + + //WHAT + for (int i = 0; i < Unk14.Length; i++) + { + Unk14[i] = 1065353216; + } + + //ARE + for (int i = 0; i < Unk15.Length; i++) + { + Unk15[i] = 1120403456; + } } public override byte[] Build() { - var resp = new PacketWriter(); - resp.Write((uint)Status); // Status flag: 0=success, 1=error - resp.WriteUtf16(Error, 0x8BA4, 0xB6); + var pkt = new PacketWriter(); + pkt.Write((uint)Status); + pkt.WriteUtf16(Error, 0x8BA4, 0xB6); if (Player.ID == 0) { for (var i = 0; i < 0xEC; i++) - resp.Write((byte)0); - return resp.ToArray(); + pkt.Write((byte)0); } - - // TODO: Explore this data! Some if it seems really important. (May contain level cap setting + more) - - resp.WriteStruct(Player); - resp.WriteFixedLengthUtf16(BlockName, 0x20); // This is right - // Set things to "default" values; Dunno these purposes yet. - resp.Write(0x42700000); //0 - resp.Write(7); //4 - resp.Write(0xA); //8 - Level Cap! - resp.Write(1); //C - resp.Write(0x41200000); //10 - resp.Write(0x40A00000); //14 - resp.Write(11); //18 - resp.Write(0x3F800000); //1C (1 as a float) - resp.Write(0x42960000); //20 - resp.Write(40); //24 - resp.Write(0x41200000); //28 - resp.Write(1); //2C? - resp.Write(1120403456); //30 - - //WHAT - for (int i = 0; i < 10; i++) + else { - resp.Write(1065353216); - } - //ARE - for (int i = 0; i < 21; i++) - { - resp.Write(1120403456); - } - //THESE? - resp.Write(0x91A2B); //B0 - resp.Write(0x91A2B); //B4 + Player.WriteObjectHeaderToStream(pkt); + pkt.WriteFixedLengthUtf16(BlockName, 0x20); + pkt.Write(Unk1); + pkt.Write(Unk2); + pkt.Write(LevelCap); + pkt.Write(LevelCap2); + pkt.Write(Unk5); + pkt.Write(Unk6); + pkt.Write(Unk7); + pkt.Write(Unk8); + pkt.Write(Unk9); + pkt.Write(Unk10); + pkt.Write(Unk11); + pkt.Write(Unk12); + pkt.Write(Unk13); - resp.WriteBytes(0, 12); + foreach (var val in Unk14) + { + pkt.Write(val); + } - return resp.ToArray(); + foreach (var val in Unk15) + { + pkt.Write(val); + } + + pkt.Write(Unk16); + pkt.Write(Unk17); + + foreach (var val in Unk18) + { + pkt.Write(val); + } + + foreach (var val in Unk19) + { + pkt.Write(val); + } + + pkt.Write(Unk20); + pkt.Write(Unk21); + + foreach (var val in Unk22) + { + pkt.Write(val); + } + + pkt.Write(Unk23); + pkt.Write(Unk24); + pkt.Write(Unk25); + pkt.Write(Unk26); + pkt.Write(Unk27); + pkt.WriteFixedLengthUtf16(Unk28, 0x20); + pkt.Write(Unk29); + pkt.WriteFixedLengthUtf16(Unk30, 0x20); + pkt.Write(Unk31); + } + + return pkt.ToArray(); } public override PacketHeader GetHeader() diff --git a/Server/Protocol/Packets/11-ClientPacket/11-2C-BlockBalancePacket.cs b/Server/Protocol/Packets/11-ClientPacket/11-2C-BlockBalancePacket.cs index 5d10346..f3361a6 100644 --- a/Server/Protocol/Packets/11-ClientPacket/11-2C-BlockBalancePacket.cs +++ b/Server/Protocol/Packets/11-ClientPacket/11-2C-BlockBalancePacket.cs @@ -15,9 +15,11 @@ namespace PSO2SERVER.Protocol.Packets public byte[] data { get; set; } = new byte[0x11A]; - public BlockBalancePacket() + public BlockBalancePacket(string blockname, ushort port) { + this.blockname = blockname; ip = ServerApp.BindAddress.GetAddressBytes(); + this.port = port; } #region implemented abstract members of Packet @@ -28,8 +30,8 @@ namespace PSO2SERVER.Protocol.Packets pkt.Write(unk1); pkt.WriteFixedLengthUtf16(blockname, 0x20); pkt.Write(ip); - pkt.Write((UInt16)12205); - pkt.Write(new byte[0x90 - 0x6A]); + pkt.Write(port); + pkt.Write(new byte[0x11A]); return pkt.ToArray(); } diff --git a/Server/Protocol/Packets/11-ClientPacket/11-3D-ShipListPacket.cs b/Server/Protocol/Packets/11-ClientPacket/11-3D-ShipListPacket.cs index 7d4b175..9c6ed5e 100644 --- a/Server/Protocol/Packets/11-ClientPacket/11-3D-ShipListPacket.cs +++ b/Server/Protocol/Packets/11-ClientPacket/11-3D-ShipListPacket.cs @@ -3,14 +3,21 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using static PSO2SERVER.Models.CharacterStruct; namespace PSO2SERVER.Protocol.Packets { public class ShipListPacket : Packet { + public List<ShipEntry> shipEntries { get; set; } = new List<ShipEntry>(); + public int timestamp { get; set; } + public uint unk { get; set; } - public ShipListPacket() + public ShipListPacket(List<ShipEntry> entries, int timestamp, uint unk) { + shipEntries = entries; + this.timestamp = timestamp; + this.unk = unk; } #region implemented abstract members of Packet @@ -18,12 +25,19 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.WriteMagic((uint)shipEntries.Count, 0xE418, 0x51); + + foreach (var entry in shipEntries) + pkt.WriteStruct(entry); + + pkt.Write(timestamp); + pkt.Write(unk); return pkt.ToArray(); } public override PacketHeader GetHeader() { - return new PacketHeader(0x11, 0x3D, PacketFlags.None); + return new PacketHeader(0x11, 0x3D, PacketFlags.PACKED); } #endregion diff --git a/Server/Protocol/Packets/1F-DailyOrderPacket/1F-03-OrderListPacket.cs b/Server/Protocol/Packets/1F-DailyOrderPacket/1F-03-OrderListPacket.cs index cde8ce1..dfa3d4f 100644 --- a/Server/Protocol/Packets/1F-DailyOrderPacket/1F-03-OrderListPacket.cs +++ b/Server/Protocol/Packets/1F-DailyOrderPacket/1F-03-OrderListPacket.cs @@ -3,11 +3,16 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using static PSO2SERVER.Models.Orders; namespace PSO2SERVER.Protocol.Packets { public class OrderListPacket : Packet { + public ObjectHeader user { get; set; } = new ObjectHeader(); + public ClientOrder[] orders { get; set; } = new ClientOrder[100]; + public uint unk1 { get; set; } + public uint unk2 { get; set; } public OrderListPacket() { @@ -18,6 +23,10 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.WriteObjectHeader(user); + pkt.WriteStructArray(orders); + pkt.Write(unk1); + pkt.Write(unk2); return pkt.ToArray(); } diff --git a/Server/Protocol/Packets/1F-DailyOrderPacket/1F-08-TakenOrdersPacket.cs b/Server/Protocol/Packets/1F-DailyOrderPacket/1F-08-TakenOrdersPacket.cs index 797b7c0..b69f027 100644 --- a/Server/Protocol/Packets/1F-DailyOrderPacket/1F-08-TakenOrdersPacket.cs +++ b/Server/Protocol/Packets/1F-DailyOrderPacket/1F-08-TakenOrdersPacket.cs @@ -3,11 +3,18 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text; +using static PSO2SERVER.Models.Orders; namespace PSO2SERVER.Protocol.Packets { public class TakenOrdersPacket : Packet { + public ObjectHeader user { get; set; } = new ObjectHeader(); + public ClientOrder[] orders { get; set; } = new ClientOrder[50]; + public OrderStatus[] statues { get; set; } = new OrderStatus[50]; + public uint unk1 { get; set; } + public uint unk2 { get; set; } + public uint unk3 { get; set; } public TakenOrdersPacket() { @@ -18,6 +25,12 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.WriteObjectHeader(user); + pkt.WriteStructArray(orders); + pkt.WriteStructArray(statues); + pkt.Write(unk1); + pkt.Write(unk2); + pkt.Write(unk3); return pkt.ToArray(); } diff --git a/Server/Protocol/Packets/23-FlagPackets/23-0E-Unk230EPacket.cs b/Server/Protocol/Packets/23-FlagPackets/23-0E-Unk230EPacket.cs index 4886578..b510cd0 100644 --- a/Server/Protocol/Packets/23-FlagPackets/23-0E-Unk230EPacket.cs +++ b/Server/Protocol/Packets/23-FlagPackets/23-0E-Unk230EPacket.cs @@ -8,6 +8,15 @@ namespace PSO2SERVER.Protocol.Packets { public class Unk230EPacket : Packet { + public struct Unk230EThing + { + public ushort unk1; + public ushort unk2; + public uint unk3; + public ObjectHeader unk4; + } + + public List<Unk230EThing> unk = new List<Unk230EThing>(); public Unk230EPacket() { @@ -18,6 +27,11 @@ namespace PSO2SERVER.Protocol.Packets public override byte[] Build() { var pkt = new PacketWriter(); + pkt.WriteMagic((uint)unk.Count, 0xAC40, 0x99); + + foreach (var entry in unk) + pkt.WriteStruct(entry); + return pkt.ToArray(); } diff --git a/Server/QueryServer.cs b/Server/QueryServer.cs index 627928e..b8d4c9d 100644 --- a/Server/QueryServer.cs +++ b/Server/QueryServer.cs @@ -9,6 +9,7 @@ using System.Threading; using PSO2SERVER.Models; using PSO2SERVER.Protocol; using System.Threading.Tasks; +using PSO2SERVER.Protocol.Packets; namespace PSO2SERVER { @@ -78,7 +79,6 @@ namespace PSO2SERVER private async Task DoShipListAsync(Socket socket) { - var writer = new PacketWriter(); var entries = new List<ShipEntry>(); for (var i = 1; i <= 10; i++) @@ -95,25 +95,10 @@ namespace PSO2SERVER entries.Add(entry); } - // Assuming header size: 8 bytes + (size of ShipEntry * number of entries) + 12 bytes - int headerSize = 8; - int shipEntrySize = Marshal.SizeOf(typeof(ShipEntry)); - int totalSize = headerSize + (shipEntrySize * entries.Count) + 12; - PacketHeader header = new PacketHeader(totalSize, 0x11, 0x3D, 0x04, 0x00); - - writer.WriteStruct(header); - writer.WriteMagic((uint)entries.Count, 0xE418, 81); - - foreach (var entry in entries) - writer.WriteStruct(entry); - - writer.Write((Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds); - writer.Write(1); - - var buffer = writer.ToArray(); + var shiplistpacket = new ShipListPacket(entries, (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds, 1).GetPacketBytes(); await Task.Factory.FromAsync( - (cb, state) => socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, cb, state), + (cb, state) => socket.BeginSend(shiplistpacket, 0, shiplistpacket.Length, SocketFlags.None, cb, state), socket.EndSend, null); socket.Close(); @@ -121,17 +106,10 @@ namespace PSO2SERVER private async Task DoBlockBalanceAsync(Socket socket) { - var writer = new PacketWriter(); - writer.WriteStruct(new PacketHeader(0x90, 0x11, 0x2C, 0x0, 0x0)); - writer.Write(new byte[0x20]); - writer.Write(new byte[0x40]); - writer.Write(ServerApp.BindAddress.GetAddressBytes()); - writer.Write((UInt16)12205); - writer.Write(new byte[0x11A]); + var balancepacket = new BlockBalancePacket("test", 12205).GetPacketBytes(); - var buffer = writer.ToArray(); await Task.Factory.FromAsync( - (cb, state) => socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, cb, state), + (cb, state) => socket.BeginSend(balancepacket, 0, balancepacket.Length, SocketFlags.None, cb, state), socket.EndSend, null); socket.Close(); diff --git a/Server/Server.csproj b/Server/Server.csproj index d34bc1f..aa37493 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -165,14 +165,17 @@ <Compile Include="ConsoleSystem.cs" /> <Compile Include="Crypto\KeyLoader.cs" /> <Compile Include="Logger.cs" /> - <Compile Include="Models\block.cs" /> + <Compile Include="Models\Block.cs" /> <Compile Include="Models\Flags.cs" /> <Compile Include="Models\Mission.cs" /> + <Compile Include="Models\NetInterface.cs" /> + <Compile Include="Models\Orders.cs" /> <Compile Include="Models\PSO2Item.cs" /> <Compile Include="Models\PSOData.cs" /> <Compile Include="Models\PSOObject.cs" /> <Compile Include="Models\PSOPalette.cs" /> <Compile Include="Models\Quest.cs" /> + <Compile Include="Models\RevealedRegions.cs" /> <Compile Include="Network\PortChecker.cs" /> <Compile Include="Object\ObjectManager.cs" /> <Compile Include="Protocol\Handlers\0B-QuestHandler\0B-20-AcceptQuest.cs" /> @@ -186,7 +189,10 @@ <Compile Include="Protocol\Handlers\1C-CharacterInfoHandler\1C-46-UNK.cs" /> <Compile Include="Protocol\Handlers\1C-CharacterInfoHandler\1C-0E-UNK.cs" /> <Compile Include="Protocol\Handlers\1C-CharacterInfoHandler\1C-1E-CharacterInfoRequest.cs" /> - <Compile Include="Protocol\Handlers\1F-UNKHandler\1F-09-UNK1F09.cs" /> + <Compile Include="Protocol\Handlers\1F-ClientOrderHandler\1F-02-OrderListRequest.cs" /> + <Compile Include="Protocol\Handlers\1F-ClientOrderHandler\1F-01-TakenOrdersRequest.cs" /> + <Compile Include="Protocol\Handlers\1F-ClientOrderHandler\1F-0F-UNK.cs" /> + <Compile Include="Protocol\Handlers\1F-ClientOrderHandler\1F-09-UNK1F09.cs" /> <Compile Include="Protocol\Handlers\23-FlagHandler\23-0B-SkitItemAddRequest.cs" /> <Compile Include="Protocol\Handlers\03-ServerHandler\03-03-InitialLoad.cs" /> <Compile Include="Protocol\Handlers\03-ServerHandler\03-0C-ServerPong.cs" />