reckfellENGINE

Binary slots and Variant serialization

Save Vector3 and integers with a header, length and type validation.

On this page

When binary data helps

FileAccess.StoreVar() preserves Variant types, including Vector3, arrays and dictionaries. GetVar() reads one such record. This suits a local slot; JSON with an explicit schema is usually simpler for a web service or another program. Neither format automatically restores live C# objects or level references.

Complete slot code

Add BinarySlot.cs to the C# project. Call Save("user://binary-slot.dat", new Vector3(2, 1, -3), 80), check Error.Ok, then Load() with the same path. Expect the same coordinates and health 80. The parent directory must already exist; the application creates the user:// root.

BinarySlot.cs
C#
using Reckfell;

public static class BinarySlot
{
    private const uint Magic = 0x52465331;
    private const uint Format = 1;
    private const ulong MaxBytes = 64 * 1024;

    public static Error Save(string path, Vector3 position, int health)
    {
        if (!position.IsFinite() || health < 0 || health > 100)
            return Error.InvalidData;
        using var file = FileAccess.Open(path, FileAccess.ModeFlags.Write);
        if (file is null)
            return FileAccess.GetOpenError();
        var payload = new Reckfell.Collections.Dictionary
        {
            ["position"] = position,
            ["health"] = health
        };
        return file.Store32(Magic) && file.Store32(Format) &&
            file.StoreVar(payload, fullObjects: false)
            ? file.GetError() : Error.FileCantWrite;
    }

    public static Error Load(string path, out Vector3 position, out int health)
    {
        position = Vector3.Zero;
        health = 0;
        using var file = FileAccess.Open(path, FileAccess.ModeFlags.Read);
        if (file is null)
            return FileAccess.GetOpenError();
        if (file.GetLength() < 12 || file.GetLength() > MaxBytes)
            return Error.FileCorrupt;
        if (file.Get32() != Magic || file.Get32() != Format)
            return Error.InvalidData;
        uint payloadLength = file.Get32();
        if (payloadLength != file.GetLength() - 12)
            return Error.FileCorrupt;
        file.Seek(8);
        Variant value = file.GetVar(allowObjects: false);
        if (value.VariantType != Variant.Type.Dictionary)
            return Error.InvalidData;
        var data = value.AsReckfellDictionary();
        if (!data.TryGetValue("position", out Variant p) ||
            !data.TryGetValue("health", out Variant h) ||
            p.VariantType != Variant.Type.Vector3 || h.VariantType != Variant.Type.Int)
            return Error.InvalidData;
        Vector3 loadedPosition = p.AsVector3();
        long loadedHealth = h.AsInt64();
        if (!loadedPosition.IsFinite() || loadedHealth < 0 || loadedHealth > 100)
            return Error.InvalidData;
        position = loadedPosition;
        health = (int)loadedHealth;
        return Error.Ok;
    }
}

The methods assign restored out values only after validation. On failure these are Vector3.Zero and 0; apply them only after Error.Ok. This writes the file directly. Add a temporary file and backup to preserve the last working progress.

File layout

OffsetContents
0–3Our signature 0x52465331
4–7Schema version 1
8–11The record length added by StoreVar()
From 12Encoded Variant dictionary

A new FileAccess uses little-endian for Store32(). Variant encoding has its own rules; BigEndian does not turn it into an arbitrary network protocol. Do not guess its layout or equate the save schema with the engine version.

Checking length before GetVar() avoids reading a huge declared outer block or silently accepting a suffix. Next, validate the dictionary root, required fields, exact types and ranges. This slot's limit is 64 KiB. It is not a general decoder for arbitrary untrusted input; corrupt internal content can produce a decoder diagnostic.

Objects and buffer framing

Keep fullObjects: false and allowObjects: false. Object-enabled variants can instantiate objects while decoding; they are unsuitable for persistent game references or files of unknown origin. Store IDs and resolve references explicitly.

ReckfellApi.VarToBytes() and BytesToVar() handle one in-memory record. StoreVar() prefixes that record with a 4-byte length, so do not pass its whole file to BytesToVar() without removing the framing. The extra 8-byte header above belongs to our slot, not the API.

Do not parse an unsupported version as the current schema. Keep it available for recovery and perform explicit migration. Test loading after a complete process restart, not only immediately after Save().

Reckfell Engine documentationBack to top ↑
QUICK LINKSGetting startedEntity hierarchyC# & .NET 10Scenes and prefabs
Reckfell guides and full API K
reckfellENGINE
RECKFELL ACCOUNT

Sign in

Sign in to your Reckfell account.

One account for the entire Reckfell platform.