ace/Source/ACE.Server/Network/ClientPacket.cs
Mag-nus c2ed2eab9a
Performance improvements with the help of Claude (#4472)
* Network performance improvements, limit boxing

* Polygon comment out redundant test code

* Transition remove duplicate Init()

* Creature_BodyPart and Monster_Melee comment out unused var
2026-08-03 11:48:37 +00:00

172 lines
4.8 KiB
C#

using System;
using System.IO;
using log4net;
using ACE.Common.Cryptography;
namespace ACE.Server.Network
{
public class ClientPacket : Packet
{
private static readonly ILog packetLog = LogManager.GetLogger(System.Reflection.Assembly.GetEntryAssembly(), "Packets");
public static int MaxPacketSize { get; } = 1024;
public BinaryReader DataReader { get; private set; }
public PacketHeaderOptional HeaderOptional { get; } = new PacketHeaderOptional();
/// <summary>
/// If you pass in a shared buffer, be sure to ReleaseBuffer() after you've processed the packet, and before you use the buffer again for the next job.
/// </summary>
public bool Unpack(byte[] buffer, int bufferSize)
{
try
{
if (bufferSize < PacketHeader.HeaderSize)
return false;
Header.Unpack(buffer);
if (Header.Size > bufferSize - PacketHeader.HeaderSize)
return false;
Data = new MemoryStream(buffer, PacketHeader.HeaderSize, Header.Size, false, true);
DataReader = new BinaryReader(Data);
HeaderOptional.Unpack(DataReader, Header);
if (!HeaderOptional.IsValid)
return false;
if (!ReadFragments())
return false;
return true;
}
catch (Exception ex)
{
packetLog.Error("Invalid packet data", ex);
return false;
}
}
private bool ReadFragments()
{
if (Header.HasFlag(PacketHeaderFlags.BlobFragments))
{
while (DataReader.BaseStream.Position != DataReader.BaseStream.Length)
{
try
{
var fragment = new ClientPacketFragment();
if (!fragment.Unpack(DataReader)) return false;
Fragments.Add(fragment);
}
catch (Exception)
{
// corrupt packet
return false;
}
}
}
return true;
}
public void ReleaseBuffer()
{
Data = null;
DataReader = null;
}
private uint? _fragmentChecksum;
private uint fragmentChecksum
{
get
{
if (_fragmentChecksum == null)
{
uint fragmentChecksum = 0u;
foreach (ClientPacketFragment fragment in Fragments)
fragmentChecksum += fragment.CalculateHash32();
_fragmentChecksum = fragmentChecksum;
}
return _fragmentChecksum.Value;
}
}
private uint? _headerChecksum;
private uint headerChecksum
{
get
{
if (_headerChecksum == null)
_headerChecksum = Header.CalculateHash32();
return _headerChecksum.Value;
}
}
private uint? _headerOptionalChecksum;
private uint headerOptionalChecksum
{
get
{
if (_headerOptionalChecksum == null)
_headerOptionalChecksum = HeaderOptional.CalculateHash32();
return _headerOptionalChecksum.Value;
}
}
private uint? _payloadChecksum;
private uint payloadChecksum
{
get
{
if (_payloadChecksum == null)
_payloadChecksum = headerOptionalChecksum + fragmentChecksum;
return _payloadChecksum.Value;
}
}
public bool VerifyCRC(CryptoSystem fq)
{
if (Header.HasFlag(PacketHeaderFlags.EncryptedChecksum))
{
var key = ((Header.Checksum - headerChecksum) ^ payloadChecksum);
if (fq.Search(key))
{
fq.ConsumeKey(key);
return true;
}
}
else
{
if (headerChecksum + payloadChecksum == Header.Checksum)
{
if (packetLog.IsDebugEnabled)
packetLog.DebugFormat("{0}", this);
return true;
}
if (packetLog.IsDebugEnabled)
packetLog.DebugFormat("{0}, Checksum Failed", this);
}
NetworkStatistics.C2S_CRCErrors_Aggregate_Increment();
return false;
}
public override string ToString()
{
return $"<<< {Header} {HeaderOptional}".TrimEnd();
}
}
}