Аннотация @ao_serialize управляет тем, какие поля сохраняются и доступны для редактирования в инспекторе.
@ao_serialize — это аннотация, которую вы помещаете на поля структур/классов, чтобы включить их в систему сериализации движка. Без неё поле существует только во время выполнения — оно не будет сохранено, не появится в инспекторе и не будет включено при записи сцены на диск.
Enemy::class:Component{// Сохраняется, отображается в инспекторе, включается в данные сценыmax_health:int @ao_serialize;patrol_radius:float @ao_serialize;// Только во время выполнения — не сохраняется, не отображается в инспектореcurrent_target:v2;aggro_timer:float;}
Что это делает
Когда вы помечаете поле с помощью @ao_serialize, движок будет:
Показывать его в инспекторе чтобы вы могли редактировать его у сущностей в редакторе.
Сохранять его вместе со сценой чтобы значение восстанавливалось при загрузке сцены.
Включать его в сериализацию JSON (Save.set_json / Save.try_get_json).
Поля без @ao_serialize существуют только в памяти во время выполнения. Каждый раз, когда компонент создаётся или сцена загружается, они начинают со своего значения по умолчанию (нулевого).
Поддерживаемые типы
@ao_serialize работает со всеми распространёнными типами CSL:
Тип
Пример
Целые числа
s8, s16, s32, s64 / int
Беззнаковые
u8, u16, u32, u64 / uint
Числа с плавающей точкой
f32 / float, f64
Булевы значения
bool
Строки
string
Векторы
v2, v3, v4
Перечисления
Любой пользовательский enum
Фиксированные массивы
[N]T
Динамические массивы
[..]T
Структуры / классы
Вложенные типы (их @ao_serialize поля включаются рекурсивно)
Для вложенных структур/классов сериализуются только поля, помеченные @ao_serialize внутри вложенного типа. Аннотация не наследуется — вы должны помечать каждое поле отдельно.
Использование с компонентами
Наиболее распространённое применение — поля компонентов. Они становятся редактируемыми в инспекторе редактора и сохраняются как часть сцены.
Вы можете задавать ёмкость, loot_table, и is_locked для каждой сущности в редакторе. Когда сцена загружается, эти значения автоматически восстанавливаются.
Использование с системой сохранений
@ao_serialize также управляет тем, какие поля включаются при использовании API сохранения JSON. В JSON записываются только помеченные поля.
Вы можете сериализовать любой аннотированный тип в/из строки JSON независимо от системы сохранений:
Значения по умолчанию и заполнение нулями
При десериализации поля, отсутствующие в данных (например, вы добавили новое поле после того, как у игроков уже появились сохранения), заполняются нулями:
Числа → 0
Булевы значения → false
Строки → ""
Массивы → пустые
Если ноль — неудачное значение по умолчанию, проверьте и задайте свои значения после загрузки:
Что НЕ следует сериализовать
Не каждое поле следует сериализовать. Оставляйте @ao_serialize выключенными поля, которые:
Выводятся во время выполнения (позиции, вычисляемые каждый кадр, кэшированные запросы)
Временное состояние (таймеры, счётчики перезарядки, флаги, локальные для кадра)
Большие данные, которые изменяются каждый кадр (лишние накладные расходы на сохранение)
Хорошее правило: если значение задаётся один раз (в редакторе или при загрузке) и редко меняется, сериализуйте его. Если оно пересчитывается каждый кадр — не сериализуйте.
Распространённые шаблоны
Перечисления для выбора режима
Вложенные структуры
Ссылки на ассеты
Некоторые поля ссылаются на ассеты движка (текстуры, префабы, звуки). Они сериализуются как идентификаторы ассетов и автоматически разрешаются при загрузке. См. встроенные компоненты (например, Sprite_Renderer) для примеров.
Chest :: class : Component {
capacity: int @ao_serialize;
loot_table: string @ao_serialize;
is_locked: bool @ao_serialize;
// Состояние во время выполнения — не нужно сериализовать
has_been_opened: bool;
}
Player_Progress :: class {
version: s64 @ao_serialize;
xp: s64 @ao_serialize;
level: s64 @ao_serialize;
unlocked_skins: [..]string @ao_serialize;
}
// Сохранить
Save.set_json(player, "progress", ref progress);
// Загрузить
progress: Player_Progress;
if !Save.try_get_json(player, "progress", ref progress) {
// Новый игрок — задать значения по умолчанию
progress.version = 1;
progress.level = 1;
}
config: My_Config;
config.difficulty = 3;
json_str := JSON.serialize(ref config);
// json_str содержит только поля @ao_serialize
loaded: My_Config;
JSON.try_deserialize(json_str, ref loaded);
if !Save.try_get_json(player, "stats", ref stats) {
stats.version = 1;
stats.max_health = 100; // ноль был бы плохим значением по умолчанию
}