PSO2SERVER/Server/Protocol/PacketWriter.cs

308 lines
8.7 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 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 终结符
Write((byte)0);
// 填充 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
{
int size = Marshal.SizeOf(structure);
//Logger.Write($"写入 {size} 字节,结构体: {structure}");
var strArr = new byte[size];
fixed (byte* ptr = strArr)
{
Marshal.StructureToPtr(structure, (IntPtr)ptr, false);
}
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;
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 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>(List<T> list) where T : struct
{
foreach (var item in list)
{
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]);
}
}
}
}
}