Send the active character id, drain until the authoritative server confirmation, then emit retail's zero-sequence connection disconnect with the negotiated receiver iteration. The connected gate now waits for ACE to remove the exact UDP session before reconnecting, eliminating fixed-delay races.
31 lines
964 B
C#
31 lines
964 B
C#
namespace AcDream.Core.Net.Packets;
|
|
|
|
/// <summary>
|
|
/// Builds retail's connection-level disconnect packet.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <c>ClientNet::LogOffServer</c> at <c>0x00543EF0</c> creates the
|
|
/// <c>0x8000</c> optional header and sends it through
|
|
/// <c>SharedNet::SendOptionalHeader</c> at <c>0x00543160</c>. That path
|
|
/// zero-initializes the packet sequence and copies the receiver's network id
|
|
/// and iteration into the fixed header. The disconnect is cleartext and has
|
|
/// no body.
|
|
/// </remarks>
|
|
public static class TransportDisconnect
|
|
{
|
|
public static byte[] Build(ushort networkId, ushort iteration)
|
|
{
|
|
var header = new PacketHeader
|
|
{
|
|
Sequence = 0,
|
|
Flags = PacketHeaderFlags.Disconnect,
|
|
Id = networkId,
|
|
Iteration = iteration,
|
|
};
|
|
|
|
return PacketCodec.Encode(
|
|
header,
|
|
ReadOnlySpan<byte>.Empty,
|
|
outboundIsaac: null);
|
|
}
|
|
}
|