Packet Serialization
On this page
Namespace: Nalix.Codec.Serialization
Assembly: Nalix.Codec
This page explains how SerializeFormatterGenerator, LiteSerializer, and FormatterProvider serialize and deserialize packet classes, structs, and nested collections.
Source Mapping
analyzers/Nalix.Analyzers.Generators/SerializeFormatterGenerator.cssrc/Nalix.Codec/Serialization/LiteSerializer.cssrc/Nalix.Codec/Serialization/FormatterProvider.cssrc/Nalix.Codec/DataFrames/PacketBase.cs
Supported Type Groups
- Unmanaged primitives & structs:
char,byte,sbyte,short,ushort,int,uint,long,ulong,float,double,decimal,bool,Guid,DateOnly,DateTime,TimeOnly,TimeSpan,DateTimeOffset,Bytes32,PacketHeader, and custom unmanagedstructtypes. - Strings:
stringandstring[](StringFormatter,StringArrayFormatter). - Nullable value types:
T?andT?[](NullableFormatter<T>,NullableArrayFormatter<T>,NullableValueListFormatter<T>). - Enums: Any
enumbacked bybyte,sbyte,short,ushort,int,uint,long, orulong(EnumFormatter<T>). - Collections:
T[](ArrayFormatter<T>for unmanagedT,ReferenceArrayFormatter<T>for reference types)List<T>(ListFormatter<T>for unmanagedT,ReferenceListFormatter<T>for reference types)Dictionary<TKey, TValue>(DictionaryFormatter<TKey, TValue>)Queue<T>,Stack<T>,HashSet<T>(supported for unmanagedTandstring)Memory<T>andReadOnlyMemory<T>(supported for unmanagedT)
- Tuples:
ValueTupleof arity 2 through 5 (ValueTupleFormatter<...>). - Complex classes & structs: Any class or struct annotated with
[GenerateFormatter](including allPacketBase<TSelf>subclasses).
Compile-Time Member Model ([GenerateFormatter])
Nalix does not use runtime reflection or System.Reflection.Emit to serialize objects. Instead, SerializeFormatterGenerator inspects types marked with [GenerateFormatter] at compile time:
SerializeLayout.Explicit(Default for[SerializePackable(SerializeLayout.Explicit)]):- Only fields and properties annotated with
[SerializeOrder(n)](or[SerializeHeader]) are serialized, sorted in ascending order ofOrder. PacketBase<TSelf>placesHeader(PacketHeader) at order0via[SerializeHeader(0)]. User fields onPacketBase<TSelf>subclasses also start their[SerializeOrder]at0(the generator always emitsHeaderfirst before user members).- Public members without
[SerializeOrder]or[SerializeIgnore]trigger analyzer warningNALIX013.
- Only fields and properties annotated with
SerializeLayout.Sequential([SerializePackable(SerializeLayout.Sequential)]):- Serializes all accessible instance fields and auto-properties in declaration order across the inheritance hierarchy, skipping
[SerializeIgnore]members.
- Serializes all accessible instance fields and auto-properties in declaration order across the inheritance hierarchy, skipping
- Reference Type Pooling (
Create()andIFillableFormatter<T>):- Reference types marked with
[GenerateFormatter]must expose a staticCreate()method (enforced by errorNALIX059; provided automatically byPacketBase<TSelf>.Create()). - Generated class formatters implement both
IFormatter<T>andIFillableFormatter<T>, allowingPacketBase<TSelf>.DeserializeandLiteSerializer.Fillto populate pooled packet instances in place without allocating.
- Reference types marked with
Resolution Flow
flowchart LR
A["PacketBase<TSelf>.Serialize / Deserialize"] --> B["LiteSerializer"]
B --> C["RootFormatterCache<T>"]
C --> D["FormatterProvider.Get<T>()"]
D --> E["Pre-registered / Source-Generated IFormatter<T>"]
E --> F["DataWriter / DataReader"]Example: Packet with Nested Struct and Collection
using System.Collections.Generic;
using Nalix.Abstractions.Networking.Packets;
using Nalix.Abstractions.Serialization;
using Nalix.Codec.DataFrames;
[GenerateFormatter]
[SerializePackable(SerializeLayout.Sequential)]
public partial struct InventoryItem
{
public uint ItemId { get; set; }
public ushort Quantity { get; set; }
}
[Packet]
[GenerateFormatter]
[SerializePackable(SerializeLayout.Explicit)]
public sealed partial class InventorySyncPacket : PacketBase<InventorySyncPacket>, IPacketStaticOpcode
{
public static ushort StaticOpCode => 0x2010;
[SerializeOrder(0)]
public ulong AccountId { get; set; }
[SerializeOrder(1)]
public List<InventoryItem> Items { get; set; } = [];
}