Что это: SaveManager — синглтон модуля Save, который регистрирует компоненты с ISaveableComponent, находит поля с атрибутом SaveField, сериализует их в общий JSON-контейнер и восстанавливает значения при загрузке. Файл: Scripts/Save/SaveManager.cs, пространство имён: Neo.Save.
Как использовать:
- Добавьте
SaveManagerна сцену один раз. - Наследуйте сохраняемые компоненты от
SaveableBehaviourили реализуйтеISaveableComponentвручную. - Пометьте нужные поля атрибутом
SaveField. - Если объекту нужен собственный стабильный ключ, реализуйте
ISaveIdentityProvider. - При необходимости вызывайте
SaveManager.Save()иSaveManager.Load()вручную.
- При инициализации находит все активные и неактивные
MonoBehaviour, реализующиеISaveableComponent. - Кэширует только те поля, которые помечены
[SaveField]. - Сохраняет значения в единый JSON под ключом
SaveData_AllчерезSaveProvider. - После загрузки вызывает
OnDataLoaded()на каждом успешно обработанном компоненте. - После загрузки новой сцены регистрирует только новые объекты и очищает разрушенные регистрации.
Раньше для ключа компонента использовался GetInstanceID(), но такой идентификатор не подходит для межсессионного сохранения.
Текущая схема:
- сначала используется пользовательский
SaveIdentity, если компонент реализуетISaveIdentityProvider; - иначе ключ строится через
SaveIdentityUtilityиз пути сцены, пути объекта в иерархии и индекса компонента одного типа; - итоговый
ComponentKeyвключаетFullNameтипа и стабильную identity-часть.
Это делает загрузку устойчивой между перезапусками игры, если объект остаётся в той же сцене и не меняет своё место в иерархии.
SaveableBehaviour.OnEnable()вызываетSaveManager.Register(this).SaveManagerсобирает список полей с[SaveField].- В
Init()менеджер вызываетLoad()для всех зарегистрированных компонентов. - На
OnApplicationQuit()вызываетсяSave(). - На
sceneLoadedменеджер повторно сканирует сцену и подгружает только новые компоненты.
SaveManager.Save(monoObj)сохраняет один компонент.SaveManager.Load(monoObj)загружает один компонент.Register()иUnregister()можно вызывать вручную, если компонент не наследуется отSaveableBehaviour.
| API | Описание |
|---|---|
bool IsLoad |
Показывает, завершил ли менеджер начальную загрузку. |
Register(MonoBehaviour monoObj) |
Регистрирует компонент и кэширует его сохраняемые поля. |
Unregister(MonoBehaviour monoObj) |
Удаляет компонент из текущего реестра. |
Save() |
Сохраняет все зарегистрированные компоненты. |
Load(List<MonoBehaviour> componentsToLoad = null) |
Загружает переданный список компонентов или все зарегистрированные компоненты. |
Save(MonoBehaviour monoObj, bool isSave = false) |
Сохраняет только один компонент в общий контейнер. |
Load(MonoBehaviour monoObj) |
Загружает только один компонент. |
- Не полагайтесь на auto-save как на единственный сценарий. Для важных пользовательских действий полезно вызывать
SaveManager.Save()явно. - Если объект создаётся динамически и должен иметь предсказуемый ключ между сессиями, дайте ему собственный
SaveIdentity. - Если вы меняете структуру сцены, проверьте, не сломает ли это scene-based identity для уже выпущенных сохранений.
- Для глобальных данных, не привязанных к конкретному компоненту сцены, используйте
GlobalSave, а неSaveManager.
using Neo.Save;
using UnityEngine;
public class PlayerStats : SaveableBehaviour, ISaveIdentityProvider
{
[SaveField("health")] [SerializeField] private int _health = 100;
[SaveField("coins")] [SerializeField] private int _coins;
public string SaveIdentity => "player-main";
public override void OnDataLoaded()
{
Debug.Log($"Loaded stats: health={_health}, coins={_coins}");
}
}