Skip to content

Game.ReadSystem

Assembly: Assembly-CSharp
Namespace: Game.Serialization

Type: class

Base: GameSystemBase, IReadBufferProvider

Summary:
ReadSystem provides read-buffer provisioning for the game's deserialization pipeline. It reads raw or compressed buffer data from an asynchronous read descriptor (via StreamBinaryReader), handles optional decompression using CompressionUtils, and returns a ReadBuffer containing the uncompressed payload. The system also keeps track of read sizes in the SerializerSystem (m_SerializerSystem.totalSize) and manages the lifecycle of its StreamBinaryReader. Typical use is inside the save/load stack where the LoadGameSystem supplies the AsyncReadDescriptor to read from.


Fields

  • private struct BufferHeader
    BufferHeader is a small unmanaged structure used to store both the uncompressed size (size) and compressed size (compressedSize) when the stored buffer format is compressed.

  • private LoadGameSystem m_DeserializationSystem
    Reference to the LoadGameSystem from the world. Used to obtain the AsyncReadDescriptor (dataDescriptor) that points to the saved data source. If the descriptor is Invalid, GetBuffer returns null.

  • private SerializerSystem m_SerializerSystem
    Reference to the SerializerSystem used to accumulate statistics (totalSize) for reporting/metrics about how many bytes were read.

  • private StreamBinaryReader m_Reader
    StreamBinaryReader used to actually read bytes from the AsyncReadDescriptor. It is lazily created when a read is first requested, and disposed/cleared on destroy/update (Clear()).

Properties

  • No public properties are exposed by ReadSystem. It does implement IReadBufferProvider which requires the GetBuffer methods (see Methods).

Constructors

  • public ReadSystem()
    Default public constructor. Marked with [Preserve] to avoid stripping by build optimizers in deployment. The real initialization happens in OnCreate.

Methods

  • protected override void OnCreate()
    Initializes the system by resolving/creating the LoadGameSystem and SerializerSystem from the world. Marked with [Preserve]. Does not allocate the StreamBinaryReader here; that's created on first GetBuffer call.

  • protected override void OnDestroy()
    Calls Clear() to dispose the StreamBinaryReader if present, then calls base.OnDestroy(). Marked with [Preserve].

  • protected override void OnUpdate()
    Clears the StreamBinaryReader by calling Clear(). The system uses OnUpdate to ensure long-lived resources are released between updates.

  • public unsafe ReadBuffer GetBuffer(BufferFormat format)
    Primary synchronous buffer provider:

  • Returns null if LoadGameSystem.dataDescriptor is Invalid.
  • Lazily constructs the StreamBinaryReader when needed.
  • For compressed formats: reads a BufferHeader (size and compressedSize), increments SerializerSystem.totalSize, allocates a persistent NativeArray for the compressed data, reads compressed bytes into it, decompresses into the returned ReadBuffer.buffer (via CompressionUtils.Decompress) and disposes the temporary NativeArray.
  • For BufferFormat.Raw: reads an int size then reads that many bytes directly into the ReadBuffer.buffer.
  • Logs a warning for unsupported BufferFormat values.
  • Increments SerializerSystem.totalSize by the header size and payload size as appropriate.
  • The returned ReadBuffer holds the uncompressed data and must be disposed by the caller when no longer needed.

  • public unsafe ReadBuffer GetBuffer(BufferFormat format, out JobHandle dependency)
    Asynchronous-aware variant:

  • Behaves like the synchronous GetBuffer but attempts to read bytes into NativeArray or buffer without blocking; the StreamBinaryReader may return a JobHandle dependency when performing the read.
  • For compressed formats: reads compressed bytes and sets up a decompression job (CompressionUtils.Decompress) that returns a JobHandle; the caller receives the JobHandle in the out parameter and is responsible for ensuring the job completes (dependency.Complete()) before accessing the returned ReadBuffer.buffer.
  • The temporary NativeArray used to store compressed bytes is disposed with Dispose(dependency) so disposal happens after the dependency completes.
  • For raw format: ReadData may also return a dependency for the read of the raw bytes.

  • private void Clear()
    Disposes and clears the StreamBinaryReader if it exists (called from OnDestroy and OnUpdate).

  • private unsafe static void ReadData<T>(StreamBinaryReader reader, out T data) where T : unmanaged
    Generic helper that reads sizeof(T) bytes from the StreamBinaryReader directly into an unmanaged T instance using UnsafeUtility.AddressOf.

  • private unsafe static void ReadData(StreamBinaryReader reader, NativeArray<byte> data)
    Helper that reads data.Length bytes into the provided NativeArray synchronously.

  • private unsafe static void ReadData(StreamBinaryReader reader, NativeArray<byte> data, out JobHandle dependency)
    Helper that reads data.Length bytes into the provided NativeArray and returns a JobHandle dependency for asynchronous completion.

Usage Example

// Example: synchronous read (blocks until data read and decompressed)
ReadSystem readSystem = world.GetOrCreateSystemManaged<ReadSystem>();
using (ReadBuffer buffer = readSystem.GetBuffer(BufferFormat.Compressed))
{
    if (buffer != null)
    {
        // Access buffer.buffer (NativeArray<byte>) here.
        // Ensure lifetime: dispose ReadBuffer when done (the using above).
    }
}

// Example: asynchronous-aware read (returns a JobHandle dependency)
JobHandle dependency;
ReadBuffer asyncBuffer = readSystem.GetBuffer(BufferFormat.Compressed, out dependency);
if (asyncBuffer != null)
{
    // Ensure the async work (read/decompress) has completed before accessing the buffer
    dependency.Complete();

    try
    {
        // Use asyncBuffer.buffer here
    }
    finally
    {
        asyncBuffer.Dispose();
    }
}

Notes and important considerations: - Callers must Dispose the returned ReadBuffer to avoid native memory leaks. - When using the out JobHandle overload, always Complete() the returned JobHandle before accessing the ReadBuffer contents. - The system increments SerializerSystem.totalSize for both header and payload reads — this is used for tracking deserialization throughput and metrics. - Unsupported BufferFormat values are warned about in logs; only BufferFormat.Raw and compressible BufferFormat values are explicitly handled.