PSO2SERVER/Server/Protocol/PacketWriter.cs

404 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using PSO2SERVER.Models;
using PSO2SERVER.Zone;
namespace PSO2SERVER.Protocol
{
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);
}
public void WriteMagic(int magic, uint xor, uint sub)
{
uint newmagic = (uint)magic;
WriteMagic(newmagic, xor, sub);
}
public void WriteAscii(string str, uint xor, uint sub)
{
if((str == null) || (str == "") || (str.Length == 0))
{
WriteMagic(0, xor, sub);
//if (str.Length == 0)
//{
//}
}
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);
}
}
//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);
// }
// }
//}
public void WriteUtf16(string str, uint xor, uint sub)
{
if ((str == null) || (str == "") || (str.Length == 0))
{
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);
}
}
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));
}
public void WriteAccountHeader(uint AccountId)
{
Write(AccountId);
Write((uint) 0);
Write((ushort)ObjectType.Player);
Write((ushort) 0);
}
public unsafe void WriteStruct<T>(T structure) where T : struct
{
try
{
// 获取结构体的大小
int size = Marshal.SizeOf<T>();
// 可以开启日志记录写入操作
//Logger.Write($"写入 {size} 字节, 结构体: {structure}");
// 创建字节数组用于存放结构体数据
var strArr = new byte[size];
// 固定字节数组,以便进行结构体转换
fixed (byte* ptr = strArr)
{
// 将结构体数据写入到字节数组
Marshal.StructureToPtr(structure, (IntPtr)ptr, false);
}
// 将字节数组写入到目标位置,可能是文件、网络等
Write(strArr);
}
catch (Exception ex)
{
// 处理错误,比如结构体转换异常或写入异常
// Logger.Error($"WriteStruct 处理异常: {ex.Message}");
throw new InvalidOperationException("结构体写入过程中发生错误", ex);
}
}
// 新增的 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;
return ms.ToArray();
}
public void WriteBytes(byte b, uint count)
{
for(int i = 0; i < count; i++)
{
Write(b);
}
}
public void WriteByteArray(byte[] b)
{
Write(b);
}
public void WriteUintArray(uint[] array)
{
foreach (var item in array)
{
Write(item);
}
}
public void WriteIntArray(int[] array)
{
foreach (var item in array)
{
Write(item);
}
}
public void WriteUshortArray(ushort[] array)
{
foreach (var item in array)
{
Write(item);
}
}
public void WriteShortArray(short[] array)
{
foreach (var item in array)
{
Write(item);
}
}
public void WriteFloatArray(float[] array)
{
foreach (var item in array)
{
Write(item);
}
}
public void WriteObjectHeader(ObjectHeader obj)
{
Write(obj.ID);
Write(obj.Padding);
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>
public void WriteList<T>(IEnumerable<T> collection) where T : struct
{
// 判断集合是否是 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
{
// 如果是普通的 List<T> 或其他实现了 IEnumerable<T> 的集合,正常迭代
foreach (var item in collection)
{
WriteStruct(item);
}
}
}
// 支持 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]);
}
}
}
// 写入 Half 类型16 位浮动点数)
public void WriteHalf(Half value)
{
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.");
}
}
}
}