Packets

Packets are the data structures exchanged between clients and the server. Every packet implements IPacketBase and carries a MessageCode that identifies its type.

Packet Architecture

Altruist uses a layered packet system:

  1. IPacketBase — Your packet data (the payload)
  2. MessageEnvelope — Wraps the packet with a PacketHeader (sender, receiver, timestamp)

When a client sends data, the framework:

  1. Decodes the raw bytes into an AltruistPacket to read the event field
  2. Looks up the matching [Gate] handler
  3. Decodes the raw bytes again into the handler's specific packet type
  4. Calls the handler

Defining a Custom Packet

using System.Text.Json.Serialization;
using Altruist;
using MessagePack;

[MessagePackObject]
public struct ChatPacket : IPacketBase
{
    [Key(0)]
    public uint MessageCode { get; set; }

    [Key(1)]
    [JsonPropertyName("text")]
    public string Text { get; set; }

    public ChatPacket()
    {
        MessageCode = 1000;
        Text = string.Empty;
    }

    public ChatPacket(string text)
    {
        MessageCode = 1000;
        Text = text;
    }
}

Rules

  • MessageCode must always be at [Key(0)]
  • Framework packets use codes 0–999; user packets start at 1000+
  • Packets can be struct (recommended for small data) or class
  • Both [MessagePackObject] + [Key] (for MessagePack) and [JsonPropertyName] (for JSON) annotations are supported

MessageCode Constants

Organize your packet codes in a static class:

public static class PC
{
    // Auth & Login (1000-1099)
    public const uint Login = 1001;
    public const uint LoginSuccess = 1002;
    public const uint LoginFailure = 1003;

    // Chat (1300-1349)
    public const uint Chat = 1300;
    public const uint Whisper = 1301;

    // Movement (1200-1249)
    public const uint Move = 1200;
}

Built-in Framework Packets

PacketMessageCodeDescription
TextPacket1Simple text message
InterprocessPacket2Server-to-server communication
SyncPacket3Entity synchronization data
AltruistPacket4Generic event packet (has Event field for routing)
SuccessPacket5Success result with optional payload
FailedPacket6Failure result with error reason
HandshakeRequestPacket7Client handshake request
HandshakeResponsePacket8Server handshake response
JoinGamePacket9Join game session request
LeaveGamePacket10Leave game session request
RoomPacket11Room information
SessionAuthContext12Session authentication

PacketHeader

Every packet sent by the server is wrapped in a MessageEnvelope containing a PacketHeader:

public struct PacketHeader
{
    public long Timestamp { get; set; }    // Server timestamp (ticks)
    public string? Receiver { get; set; }  // Target client ID
    public string Sender { get; set; }     // "server" for server-sent packets
}

Sending Packets

Use IAltruistRouter to send packets from within a portal or service:

// Send to one client
await _router.Client.SendAsync(clientId, new ChatPacket("Hello!"));

// Send to a room
await _router.Room.SendAsync(roomId, new ChatPacket("Room message"));

// Broadcast to all
await _router.Broadcast.SendAsync(new ChatPacket("Server announcement"));

The router automatically wraps your packet in a MessageEnvelope and encodes it with the configured codec (JSON or MessagePack).

Client-Side: Sending Events

Clients send packets as the configured codec format (JSON shown here). The event field routes to the matching [Gate]:

{
  "messageCode": 4,
  "event": "chat",
  "text": "Hello world!"
}

The messageCode: 4 tells the framework this is a generic AltruistPacket. The event field routes it to the [Gate("chat")] handler, where the full payload is deserialized into the handler's packet type.

Result Packets

For standardized success/failure responses, use the built-in helpers:

// Success with payload
var result = ResultPacket.Success(TransportCode.Ok, new TextPacket("Player joined!"));

// Failure with reason
var result = ResultPacket.Failed(TransportCode.BadRequest, "Username is required");

Transport Codes

CodeMeaning
200Ok
201Created
400Bad Request
401Unauthorized
403Forbidden
404Not Found
409Conflict
500Internal Server Error