reckfellENGINE

Бинарный слот и сериализация Variant

Сохранение Vector3 и целых чисел с заголовком, проверкой длины и типов.

На этой странице

Когда нужен бинарный формат

FileAccess.StoreVar() сохраняет типы Variant, включая Vector3, массивы и словари. GetVar() читает одну такую запись. Это удобно для локального слота; для обмена с веб-сервисом или другой программой обычно проще JSON с явной схемой. Ни один формат сам по себе не восстанавливает живые C#-объекты и ссылки уровня.

Полный код слота

Добавьте BinarySlot.cs в C#-проект. Вызовите Save("user://binary-slot.dat", new Vector3(2, 1, -3), 80), проверьте Error.Ok, затем Load() с тем же путём. Ожидаются те же координаты и здоровье 80. Родительская папка должна уже существовать; сам корень user:// создаёт приложение.

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;
    }
}

Методы возвращают значения через out только после проверки. При ошибке это Vector3.Zero и 0; применять их к персонажу можно только после Error.Ok. Код записывает файл напрямую: для последнего рабочего прогресса добавьте временный файл и резервную копию.

Что лежит в файле

СмещениеСодержимое
0–3Собственная сигнатура 0x52465331
4–7Версия схемы 1
8–11Длина записи, которую добавляет StoreVar()
С 12Закодированный словарь Variant

Новый FileAccess использует little-endian для Store32(). Внутренний формат Variant имеет собственные правила; BigEndian не превращает его в произвольный сетевой протокол. Не разбирайте его по догадкам и не считайте номер схемы равным версии движка.

Проверка длины перед GetVar() не даёт прочитать заявленный огромный внешний блок или незаметно принять добавленный хвост. Затем проверяются корневой словарь, поля, точные типы и диапазоны. Лимит этого слота — 64 КиБ. Это не общий декодер произвольных недоверенных файлов: повреждённое внутреннее содержимое может вызвать диагностическое сообщение самого декодера.

Объекты и формат буфера

Оставьте fullObjects: false и allowObjects: false. Варианты с объектами могут создавать экземпляры при декодировании; они не подходят для сохранения постоянных ссылок игры или чтения файла неизвестного происхождения. Сохраняйте ID и восстанавливайте ссылки явно.

ReckfellApi.VarToBytes() и BytesToVar() работают с одной записью в памяти. У StoreVar() перед этой записью есть 4-байтовая длина; поэтому нельзя скормить BytesToVar() весь файл StoreVar() без снятия обрамления. Дополнительные 8 байт заголовка выше принадлежат нашему слоту, а не API.

При несовпадении версии не пытайтесь читать файл как текущую схему. Сохраните его для восстановления и выполните отдельную миграцию. Проверяйте загрузку после полного перезапуска процесса, а не только сразу после Save().

Документация Reckfell EngineНаверх ↑
БЫСТРЫЙ ПЕРЕХОДНачало работыEntity и иерархияC# & .NET 10Сцены и префабы
Руководства и полный API Reckfell K
reckfellENGINE
RECKFELL ACCOUNT

Вход в аккаунт

Войдите в аккаунт Reckfell.

Один аккаунт для всей платформы Reckfell.