继续修正数据包结构

This commit is contained in:
Sancaros 2024-12-06 19:47:18 +08:00
parent ecc9ebe098
commit d7edf84277
27 changed files with 689 additions and 349 deletions

View File

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

View File

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

View File

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

29
Server/Models/Orders.cs Normal file
View File

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

View File

@ -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); // 写入填充部分

View File

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

View File

@ -9,7 +9,8 @@ namespace PSO2SERVER.Models
Online,
Busy,
Full,
Offline
Offline,
Undefined = 0xFFFF
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]

View File

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

View File

@ -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 和类型,方便调试

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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(); // 返回整个数据包字节数组
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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