Packet Schema Generator
On this page
PacketSchemaGenerator (analyzers/Nalix.Analyzers.Generators/PacketSchemaGenerator.cs) is an incremental Roslyn source generator that inspects every class inheriting from PacketBase<TSelf> and generates Length overrides, zero-allocation ResetForPool() implementations, and public static int Size (when implementing IFixedSizeSerializable).
Source Mapping
analyzers/Nalix.Analyzers.Generators/PacketSchemaGenerator.csanalyzers/Nalix.Analyzers.Generators/Internal/GeneratorDiagnosticDescriptors.cs
What It Generates
For every partial class inheriting from PacketBase<TSelf>:
public override int Length { get; }:- Computes the exact serialized byte length of the packet (
PacketConstants.HeaderSize= 6 bytes plus all serialized fields/properties across the inheritance hierarchy). - For dynamic members (
string,byte[],T[],List<T>), adds a 4-byte length prefix (4bytes per dynamic member) plusEncoding.UTF8.GetByteCount(...)for strings orcount * elementSizefor collections.
- Computes the exact serialized byte length of the packet (
public override void ResetForPool()(unless manually overridden by the user):- Calls
base.ResetForPool(). - Resets
stringmembers tostring.Empty, clearsList<T>collections (?.Clear()), resetsArraySegment<T>/Memory<T>/ReadOnlyMemory<T>todefault, calls.ResetForPool()on nestedIPoolablemembers, and resets value types and arrays todefault. - Respects
[SkipClean]: Any field or property decorated with[SkipClean]is left untouched duringResetForPool().
- Calls
public static int Size => <totalFixedBytes>;(emitted when the packet implementsIFixedSizeSerializable):- Provides the compile-time constant wire size required by
IFixedSizeSerializable.Size.
- Provides the compile-time constant wire size required by
Example
Source Packet Definition
using Nalix.Abstractions;
using Nalix.Abstractions.Networking.Packets;
using Nalix.Abstractions.Serialization;
using Nalix.Codec.DataFrames;
[Packet(0x1005)]
[GenerateFormatter]
[SerializePackable(SerializeLayout.Explicit)]
public sealed partial class PlayerChatPacket : PacketBase<PlayerChatPacket>, IPacketStaticOpcode
{
public static ushort StaticOpCode => 0x1005;
[SerializeOrder(0)]
public ulong PlayerId { get; set; }
[SerializeOrder(1)]
public string Message { get; set; } = string.Empty;
[SkipClean]
[SerializeIgnore]
public int CachedChannelId { get; set; }
}
Generated Companion (PlayerChatPacket_Schema.g.cs)
public partial class PlayerChatPacket
{
public override int Length
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
int size = 14; // Header (6B) + PlayerId (8B)
size += 4 + (this.Message is null ? 0 : System.Text.Encoding.UTF8.GetByteCount(this.Message));
return size;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void ResetForPool()
{
base.ResetForPool();
this.PlayerId = default;
this.Message = string.Empty;
// CachedChannelId is skipped because it is marked [SkipClean]
}
}
Diagnostic Emitted
| ID | Title | Severity | Cause |
|---|---|---|---|
NALIX060 | Packet class must be partial | Error | A class inherits from PacketBase<TSelf> but is missing the partial modifier. |