2024-09-10 00:31:40 +08:00
|
|
|
|
using System;
|
2024-11-25 23:33:41 +08:00
|
|
|
|
using System.Collections.Generic;
|
2024-09-10 00:31:40 +08:00
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
|
using System.Text;
|
2024-09-10 01:13:20 +08:00
|
|
|
|
using PSO2SERVER.Models;
|
2024-12-03 18:17:43 +08:00
|
|
|
|
using PSO2SERVER.Zone;
|
2024-09-10 00:31:40 +08:00
|
|
|
|
|
2024-11-27 18:05:53 +08:00
|
|
|
|
namespace PSO2SERVER.Protocol
|
2024-09-10 00:31:40 +08:00
|
|
|
|
{
|
|
|
|
|
public class PacketWriter : BinaryWriter
|
|
|
|
|
{
|
|
|
|
|
public PacketWriter()
|
|
|
|
|
: base(new MemoryStream())
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public PacketWriter(Stream s)
|
|
|
|
|
: base(s)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteMagic(uint magic, uint xor, uint sub)
|
|
|
|
|
{
|
|
|
|
|
var encoded = (magic + sub) ^ xor;
|
|
|
|
|
Write(encoded);
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-11 02:24:51 +08:00
|
|
|
|
public void WriteMagic(int magic, uint xor, uint sub)
|
|
|
|
|
{
|
|
|
|
|
uint newmagic = (uint)magic;
|
|
|
|
|
WriteMagic(newmagic, xor, sub);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-10 00:31:40 +08:00
|
|
|
|
public void WriteAscii(string str, uint xor, uint sub)
|
|
|
|
|
{
|
2024-11-25 23:33:41 +08:00
|
|
|
|
if((str == null) || (str == "") || (str.Length == 0))
|
2024-09-10 00:31:40 +08:00
|
|
|
|
{
|
2024-09-12 02:14:42 +08:00
|
|
|
|
|
2024-09-10 00:31:40 +08:00
|
|
|
|
WriteMagic(0, xor, sub);
|
2024-09-12 02:14:42 +08:00
|
|
|
|
//if (str.Length == 0)
|
|
|
|
|
//{
|
|
|
|
|
//}
|
2024-09-10 00:31:40 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Magic, followed by string, followed by null terminator,
|
|
|
|
|
// followed by padding characters if needed.
|
|
|
|
|
var charCount = (uint) str.Length;
|
|
|
|
|
var padding = 4 - (charCount & 3);
|
|
|
|
|
|
|
|
|
|
WriteMagic(charCount + 1, xor, sub);
|
|
|
|
|
Write(Encoding.ASCII.GetBytes(str));
|
|
|
|
|
for (var i = 0; i < padding; i++)
|
|
|
|
|
Write((byte) 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-10 01:23:49 +08:00
|
|
|
|
//public void WriteAscii(AsciiString str, uint xor, uint sub)
|
|
|
|
|
//{
|
|
|
|
|
// if (str == null || str.Length == 0)
|
|
|
|
|
// {
|
|
|
|
|
// // 如果 AsciiString 为空或长度为 0,写入 magic,长度为 0
|
|
|
|
|
// WriteMagic(0, xor, sub);
|
|
|
|
|
// }
|
|
|
|
|
// else
|
|
|
|
|
// {
|
|
|
|
|
// // Magic, followed by string, followed by null terminator,
|
|
|
|
|
// // followed by padding characters if needed.
|
|
|
|
|
// var charCount = (uint)str.Length;
|
|
|
|
|
// var padding = (4 - (charCount + 1) % 4) % 4; // +1 用于计算 null 终结符的空间
|
|
|
|
|
|
|
|
|
|
// // 写入 Magic 值(charCount + 1:包括 null 终结符)
|
|
|
|
|
// WriteMagic(charCount + 1, xor, sub);
|
|
|
|
|
|
|
|
|
|
// // 写入字符串的字节数据
|
|
|
|
|
// Write(str.ToBytes());
|
|
|
|
|
|
|
|
|
|
// // 填充 null 字节以保证 4 字节对齐
|
|
|
|
|
// for (var i = 0; i < padding; i++)
|
|
|
|
|
// {
|
|
|
|
|
// Write((byte)0);
|
|
|
|
|
// }
|
|
|
|
|
// }
|
|
|
|
|
//}
|
2024-11-25 23:33:41 +08:00
|
|
|
|
|
2024-09-10 00:31:40 +08:00
|
|
|
|
public void WriteUtf16(string str, uint xor, uint sub)
|
|
|
|
|
{
|
2024-11-25 23:33:41 +08:00
|
|
|
|
if ((str == null) || (str == "") || (str.Length == 0))
|
2024-09-10 00:31:40 +08:00
|
|
|
|
{
|
|
|
|
|
WriteMagic(0, xor, sub);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// Magic, followed by string, followed by null terminator,
|
|
|
|
|
// followed by a padding character if needed.
|
|
|
|
|
var charCount = (uint) str.Length + 1;
|
|
|
|
|
var padding = (charCount & 1);
|
|
|
|
|
|
|
|
|
|
WriteMagic(charCount, xor, sub);
|
|
|
|
|
Write(Encoding.GetEncoding("UTF-16").GetBytes(str));
|
|
|
|
|
Write((ushort) 0);
|
|
|
|
|
if (padding != 0)
|
|
|
|
|
Write((ushort) 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteFixedLengthASCII(string str, int charCount)
|
|
|
|
|
{
|
|
|
|
|
var writeAmount = Math.Min(str.Length, charCount);
|
|
|
|
|
var paddingAmount = charCount - writeAmount;
|
|
|
|
|
|
|
|
|
|
if (writeAmount > 0)
|
|
|
|
|
{
|
|
|
|
|
var chopped = writeAmount != str.Length ? str.Substring(0, writeAmount) : str;
|
|
|
|
|
|
|
|
|
|
Write(Encoding.GetEncoding("ASCII").GetBytes(chopped));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (paddingAmount > 0)
|
|
|
|
|
{
|
|
|
|
|
for (var i = 0; i < paddingAmount; i++)
|
|
|
|
|
Write((byte) 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteFixedLengthUtf16(string str, int charCount)
|
|
|
|
|
{
|
|
|
|
|
var writeAmount = Math.Min(str.Length, charCount);
|
|
|
|
|
var paddingAmount = charCount - writeAmount;
|
|
|
|
|
|
|
|
|
|
if (writeAmount > 0)
|
|
|
|
|
{
|
|
|
|
|
var chopped = writeAmount != str.Length ? str.Substring(0, writeAmount) : str;
|
|
|
|
|
|
|
|
|
|
Write(Encoding.GetEncoding("UTF-16").GetBytes(chopped));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (paddingAmount > 0)
|
|
|
|
|
{
|
|
|
|
|
for (var i = 0; i < paddingAmount; i++)
|
|
|
|
|
Write((ushort) 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 03:42:25 +08:00
|
|
|
|
internal void WritePosition(PSOLocation location)
|
|
|
|
|
{
|
|
|
|
|
Write(Helper.FloatToHalfPrecision(location.RotX));
|
|
|
|
|
Write(Helper.FloatToHalfPrecision(location.RotY));
|
|
|
|
|
Write(Helper.FloatToHalfPrecision(location.RotZ));
|
|
|
|
|
Write(Helper.FloatToHalfPrecision(location.RotW));
|
|
|
|
|
Write(Helper.FloatToHalfPrecision(location.PosX));
|
|
|
|
|
Write(Helper.FloatToHalfPrecision(location.PosY));
|
|
|
|
|
Write(Helper.FloatToHalfPrecision(location.PosZ));
|
|
|
|
|
}
|
|
|
|
|
|
2024-11-29 10:01:28 +08:00
|
|
|
|
public void WriteAccountHeader(uint AccountId)
|
2024-09-10 00:31:40 +08:00
|
|
|
|
{
|
2024-11-29 10:01:28 +08:00
|
|
|
|
Write(AccountId);
|
2024-09-10 00:31:40 +08:00
|
|
|
|
Write((uint) 0);
|
2024-09-21 13:46:28 +08:00
|
|
|
|
Write((ushort)ObjectType.Player);
|
2024-09-10 00:31:40 +08:00
|
|
|
|
Write((ushort) 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public unsafe void WriteStruct<T>(T structure) where T : struct
|
|
|
|
|
{
|
2024-12-10 01:23:49 +08:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 获取结构体的大小
|
|
|
|
|
int size = Marshal.SizeOf<T>();
|
2024-09-20 16:10:43 +08:00
|
|
|
|
|
2024-12-10 01:23:49 +08:00
|
|
|
|
// 可以开启日志记录写入操作
|
|
|
|
|
//Logger.Write($"写入 {size} 字节, 结构体: {structure}");
|
2024-09-10 00:31:40 +08:00
|
|
|
|
|
2024-12-10 01:23:49 +08:00
|
|
|
|
// 创建字节数组用于存放结构体数据
|
|
|
|
|
var strArr = new byte[size];
|
|
|
|
|
|
|
|
|
|
// 固定字节数组,以便进行结构体转换
|
|
|
|
|
fixed (byte* ptr = strArr)
|
|
|
|
|
{
|
|
|
|
|
// 将结构体数据写入到字节数组
|
|
|
|
|
Marshal.StructureToPtr(structure, (IntPtr)ptr, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 将字节数组写入到目标位置,可能是文件、网络等
|
|
|
|
|
Write(strArr);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
2024-09-10 00:31:40 +08:00
|
|
|
|
{
|
2024-12-10 01:23:49 +08:00
|
|
|
|
// 处理错误,比如结构体转换异常或写入异常
|
|
|
|
|
// Logger.Error($"WriteStruct 处理异常: {ex.Message}");
|
|
|
|
|
throw new InvalidOperationException("结构体写入过程中发生错误", ex);
|
2024-09-10 00:31:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-10 01:23:49 +08:00
|
|
|
|
|
2024-12-06 19:47:18 +08:00
|
|
|
|
// 新增的 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);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-10 00:31:40 +08:00
|
|
|
|
public byte[] ToArray()
|
|
|
|
|
{
|
|
|
|
|
var ms = (MemoryStream) BaseStream;
|
|
|
|
|
return ms.ToArray();
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 03:42:25 +08:00
|
|
|
|
public void WriteBytes(byte b, uint count)
|
2024-09-10 00:31:40 +08:00
|
|
|
|
{
|
|
|
|
|
for(int i = 0; i < count; i++)
|
|
|
|
|
{
|
|
|
|
|
Write(b);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-06 03:42:25 +08:00
|
|
|
|
|
2024-12-11 20:47:36 +08:00
|
|
|
|
public void WriteIntArray(uint[] array)
|
2024-12-06 03:42:25 +08:00
|
|
|
|
{
|
|
|
|
|
foreach (var item in array)
|
|
|
|
|
{
|
|
|
|
|
Write(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteIntArray(int[] array)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in array)
|
|
|
|
|
{
|
|
|
|
|
Write(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-11 20:47:36 +08:00
|
|
|
|
public void WriteShortArray(ushort[] array)
|
2024-12-10 01:23:49 +08:00
|
|
|
|
{
|
|
|
|
|
foreach (var item in array)
|
|
|
|
|
{
|
|
|
|
|
Write(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteShortArray(short[] array)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in array)
|
|
|
|
|
{
|
|
|
|
|
Write(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-12-06 03:42:25 +08:00
|
|
|
|
public void WriteFloatArray(float[] array)
|
|
|
|
|
{
|
|
|
|
|
foreach (var item in array)
|
|
|
|
|
{
|
|
|
|
|
Write(item);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteObjectHeader(ObjectHeader obj)
|
|
|
|
|
{
|
|
|
|
|
Write(obj.ID);
|
2024-12-10 01:23:49 +08:00
|
|
|
|
Write(obj.Padding);
|
2024-12-06 03:42:25 +08:00
|
|
|
|
Write((ushort)obj.ObjectType);
|
|
|
|
|
Write(obj.MapID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteObjectHeaderArray(ObjectHeader[] objlist)
|
|
|
|
|
{
|
|
|
|
|
foreach (var obj in objlist)
|
|
|
|
|
{
|
|
|
|
|
WriteObjectHeader(obj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void WriteObjectHeaderList(List<ObjectHeader> objlist)
|
|
|
|
|
{
|
|
|
|
|
foreach (var obj in objlist)
|
|
|
|
|
{
|
|
|
|
|
WriteObjectHeader(obj); // 直接写入每个 ObjectHeader 对象
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 支持 Guid 类型
|
|
|
|
|
public void WriteGuid(Guid guid)
|
|
|
|
|
{
|
|
|
|
|
Write(guid.ToByteArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 支持 DateTime 类型
|
|
|
|
|
public void WriteDateTime(DateTime dateTime)
|
|
|
|
|
{
|
|
|
|
|
var timestamp = new DateTimeOffset(dateTime).ToUnixTimeSeconds();
|
|
|
|
|
Write(timestamp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 支持 List<T>
|
2024-12-10 01:23:49 +08:00
|
|
|
|
public void WriteList<T>(IEnumerable<T> collection) where T : struct
|
2024-12-06 03:42:25 +08:00
|
|
|
|
{
|
2024-12-10 01:23:49 +08:00
|
|
|
|
// 判断集合是否是 FixedList<T>
|
|
|
|
|
if (collection is FixedList<T> fixedList)
|
|
|
|
|
{
|
|
|
|
|
//Logger.Write($"{fixedList.Capacity}");
|
|
|
|
|
// 遍历 FixedList 的整个容量,即使它没有满
|
|
|
|
|
for (int i = 0; i < fixedList.Capacity; i++)
|
|
|
|
|
{
|
|
|
|
|
WriteStruct(fixedList[i]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2024-12-06 03:42:25 +08:00
|
|
|
|
{
|
2024-12-10 01:23:49 +08:00
|
|
|
|
// 如果是普通的 List<T> 或其他实现了 IEnumerable<T> 的集合,正常迭代
|
|
|
|
|
foreach (var item in collection)
|
|
|
|
|
{
|
|
|
|
|
WriteStruct(item);
|
|
|
|
|
}
|
2024-12-06 03:42:25 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 支持 2D 数组
|
|
|
|
|
public void Write2DIntArray(int[,] array)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < array.GetLength(0); i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < array.GetLength(1); j++)
|
|
|
|
|
{
|
|
|
|
|
Write(array[i, j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 支持 2D 数组
|
|
|
|
|
public void Write2DUIntArray(uint[,] array)
|
|
|
|
|
{
|
|
|
|
|
for (int i = 0; i < array.GetLength(0); i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < array.GetLength(1); j++)
|
|
|
|
|
{
|
|
|
|
|
Write(array[i, j]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-12-07 14:55:20 +08:00
|
|
|
|
|
|
|
|
|
// 写入 Half 类型(16 位浮动点数)
|
2024-12-07 15:45:09 +08:00
|
|
|
|
public void WriteHalf(Half value)
|
2024-12-07 14:55:20 +08:00
|
|
|
|
{
|
|
|
|
|
Write(Half.GetBytes(value)); // 写入 2 个字节
|
|
|
|
|
}
|
2024-12-11 14:07:19 +08:00
|
|
|
|
|
|
|
|
|
// 自动识别并写入枚举类型
|
|
|
|
|
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);
|
|
|
|
|
}
|
2024-12-11 20:47:36 +08:00
|
|
|
|
else if (underlyingType == typeof(short) || underlyingType == typeof(ushort))
|
2024-12-11 14:07:19 +08:00
|
|
|
|
{
|
|
|
|
|
Write((short)underlyingValue);
|
|
|
|
|
}
|
2024-12-11 20:47:36 +08:00
|
|
|
|
else if (underlyingType == typeof(Half) || underlyingType == typeof(Half))
|
|
|
|
|
{
|
|
|
|
|
WriteHalf((Half)underlyingValue);
|
|
|
|
|
}
|
|
|
|
|
else if (underlyingType == typeof(int) || underlyingType == typeof(uint))
|
2024-12-11 14:07:19 +08:00
|
|
|
|
{
|
|
|
|
|
Write((int)underlyingValue);
|
|
|
|
|
}
|
2024-12-11 20:47:36 +08:00
|
|
|
|
else if (underlyingType == typeof(float))
|
|
|
|
|
{
|
|
|
|
|
Write((float)underlyingValue);
|
|
|
|
|
}
|
|
|
|
|
else if (underlyingType == typeof(long) || underlyingType == typeof(ulong))
|
2024-12-11 14:07:19 +08:00
|
|
|
|
{
|
|
|
|
|
Write((long)underlyingValue);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new InvalidOperationException("Unsupported enum underlying type.");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
throw new ArgumentException("The value is not an enum type.");
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-09-10 00:31:40 +08:00
|
|
|
|
}
|
|
|
|
|
}
|