38 lines
1.4 KiB
C#
38 lines
1.4 KiB
C#
using System.Buffers.Binary;
|
|
using AcDream.Core.Net.Packets;
|
|
|
|
namespace AcDream.Core.Net.Messages;
|
|
|
|
/// <summary>
|
|
/// Retail character-logoff request and server confirmation (opcode
|
|
/// <c>0xF653</c>).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Retail <c>Proto_UI::LogOffCharacter</c> at <c>0x00546A20</c> sends the
|
|
/// opcode followed by the active character id. The server confirmation uses
|
|
/// the same opcode with no trailing payload. <c>CPlayerSystem::RequestLogOff</c>
|
|
/// at <c>0x00562DD0</c> waits for that confirmation; its inbound dispatch calls
|
|
/// <c>CPlayerSystem::ExecuteLogOff</c> at <c>0x0055D780</c>, which only then
|
|
/// disconnects the world connection.
|
|
/// </remarks>
|
|
public static class CharacterLogOff
|
|
{
|
|
public const uint Opcode = 0xF653u;
|
|
|
|
/// <summary>Builds retail's eight-byte client request.</summary>
|
|
public static byte[] BuildRequestBody(uint characterId)
|
|
{
|
|
var writer = new PacketWriter(8);
|
|
writer.WriteUInt32(Opcode);
|
|
writer.WriteUInt32(characterId);
|
|
return writer.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns whether a complete game-message body is the server's logoff
|
|
/// confirmation. ACE emits the canonical four-byte opcode-only form.
|
|
/// </summary>
|
|
public static bool IsConfirmation(ReadOnlySpan<byte> body) =>
|
|
body.Length == sizeof(uint) &&
|
|
BinaryPrimitives.ReadUInt32LittleEndian(body) == Opcode;
|
|
}
|