Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/ProwlEngine/Prowl.Echo/llms.txt

Use this file to discover all available pages before exploring further.

The Echo binary format is the primary serialization target for production use in Prowl.Echo. It preserves every EchoType value exactly during round-trips, produces compact output, and offers two distinct encoding modes so you can choose between maximum throughput and minimum file size.

Encoding modes

EchoBinaryFormat supports two modes, controlled by BinarySerializationOptions.EncodingMode:

Performance mode

Integers are written at their natural fixed width (1, 2, 4, or 8 bytes). Read and write operations are as fast as possible because no variable-length decoding is needed. Files are larger, but access times are minimized. This is the default mode.

Size mode

Integers are encoded using LEB128 (Little Endian Base 128), a variable-length encoding that uses fewer bytes for small values. String keys in compound tags are additionally compressed with LZW (Lempel-Ziv-Welch). Files are smaller, but encoding and decoding carry a small additional cost.
public enum BinaryEncodingMode
{
    /// <summary>
    /// Fixed-width integers — faster read/write, larger files.
    /// </summary>
    Performance,

    /// <summary>
    /// LEB128 encoding for integers — smaller files, slightly slower.
    /// </summary>
    Size
}

BinarySerializationOptions

Pass a BinarySerializationOptions instance to any write or read method to control the encoding mode. If you omit the options argument, BinaryEncodingMode.Performance is used.
var sizeOptions = new BinarySerializationOptions
{
    EncodingMode = BinaryEncodingMode.Size
};

var perfOptions = new BinarySerializationOptions
{
    EncodingMode = BinaryEncodingMode.Performance
};

// Or use the default (Performance)
var defaultOptions = BinarySerializationOptions.Default;
The reader must use the same BinaryEncodingMode as the writer. Writing with Size and reading with Performance (or vice versa) will produce corrupt or incorrect data.

Writing binary data

To a file

Use the EchoObject.WriteToBinary(FileInfo, BinarySerializationOptions?) overload to write directly to disk:
using Prowl.Echo;

// Serialize a .NET object to EchoObject
EchoObject echo = Serializer.Serialize(myGameState);

// Write to file with default (Performance) encoding
echo.WriteToBinary(new FileInfo("save.bin"));

// Write to file with Size encoding for smaller saves
var options = new BinarySerializationOptions { EncodingMode = BinaryEncodingMode.Size };
echo.WriteToBinary(new FileInfo("save.bin"), options);

To a stream via BinaryWriter

Use the EchoObject.WriteToBinary(BinaryWriter, BinarySerializationOptions?) overload to write into any stream, such as a network socket or a memory buffer:
using var stream = new MemoryStream();
using var writer = new BinaryWriter(stream);

echo.WriteToBinary(writer);

byte[] payload = stream.ToArray();

Via IFileFormat extension methods

The EchoBinaryFormat.Instance singleton exposes the full IFileFormat extension API. This is useful when you want to work with byte[] buffers directly without managing BinaryWriter yourself:
// Write to byte array
byte[] bytes = EchoBinaryFormat.Instance.WriteToBytes(echo);

// Write to file by path string
EchoBinaryFormat.Instance.WriteToFile(echo, "data.bin");

Reading binary data

From a file

// Read with default (Performance) encoding
EchoObject echo = EchoObject.ReadFromBinary(new FileInfo("save.bin"));

// Read with Size encoding (must match how the file was written)
var options = new BinarySerializationOptions { EncodingMode = BinaryEncodingMode.Size };
EchoObject echo = EchoObject.ReadFromBinary(new FileInfo("save.bin"), options);

From a stream via BinaryReader

using var stream = File.OpenRead("data.bin");
using var reader = new BinaryReader(stream);

EchoObject echo = EchoObject.ReadFromBinary(reader);

Via IFileFormat extension methods

byte[] bytes = File.ReadAllBytes("data.bin");
EchoObject echo = EchoBinaryFormat.Instance.ReadFromBytes(bytes);

Complete round-trip example

1

Serialize your object

var player = new Player { Name = "Aria", Level = 42, Health = 98.5f };
EchoObject echo = Serializer.Serialize(player);
2

Write to a binary file

var options = new BinarySerializationOptions
{
    EncodingMode = BinaryEncodingMode.Size
};
echo.WriteToBinary(new FileInfo("player.bin"), options);
3

Read back from the file

EchoObject loaded = EchoObject.ReadFromBinary(
    new FileInfo("player.bin"),
    new BinarySerializationOptions { EncodingMode = BinaryEncodingMode.Size }
);
4

Deserialize back to your type

Player restored = Serializer.Deserialize<Player>(loaded);

LEB128 and LZW compression internals

This section describes implementation details. You do not need to interact with these directly — BinarySerializationOptions handles everything.
In Size mode, integer types (short, int, long, ushort, uint, ulong) are encoded using LEB128 (Little Endian Base 128):
  • ULEB128 is used for unsigned types. Each byte carries 7 bits of data; the high bit signals that more bytes follow.
  • SLEB128 is used for signed types, with sign extension applied to the final byte.
Small integers (e.g., 0–127) compress to a single byte; larger values expand as needed, up to the type’s natural maximum width. In Size mode, string keys inside Compound tags are additionally compressed with LZW (Lempel-Ziv-Welch). LZW builds a shared dictionary during the encode pass (up to 4,096 entries), replacing repeated character sequences with short integer codes. This is particularly effective for structures with many repeated field names such as serialized component arrays. Float, double, and decimal values are always stored at their natural fixed width in both modes, since variable-length encoding provides no benefit for floating-point data.

Using EchoBinaryFormat.Instance directly

The singleton carries its own Options property, which lets you configure the format once and reuse it:
EchoBinaryFormat.Instance.Options = new BinarySerializationOptions
{
    EncodingMode = BinaryEncodingMode.Size
};

// Both calls now use Size encoding
byte[] a = EchoBinaryFormat.Instance.WriteToBytes(echoA);
byte[] b = EchoBinaryFormat.Instance.WriteToBytes(echoB);
The singleton is not thread-safe when its Options property is mutated concurrently. For parallel serialization workloads, construct separate EchoBinaryFormat instances or pass options explicitly through the static WriteTo / ReadFrom methods.

Build docs developers (and LLMs) love