## Сохранение данных

Данные между запусками можно хранить в объекте `persistent`.

Простой пример использования: В главном меню игры откройте консоль (`Shift+O`) и введите (или скопируйте) код `persistent.my_var = 123`.
После перезапуска снова откройте консоль и введите `persistent.my_var` - консоль выдаст вам сохранённый результат `123`.

Также эту переменную можно изменять прямо на месте: `persistent.my_var += 1`.

`persistent` можно использовать для сохранения данных о каком-то событии (о прохождении определённой концовки, например), а потом узнавать в новой игре, происходило ли нужное событие ранее (особенно важно для игр с перемещениями во времени и подобными вещами).

## Некоторые технические подробности

Особенности `persistent`:

- Объект `persistent` сохраняется в файл `var/persistent`;
- Этот файл можно удалить вручную - тогда все хранимые данные тоже будут удалены;
- При сборке zip-архива из лаунчера папка `var` полностью игнорируется (не упаковывается);
- Объект `persistent` определяет необходимость сохранения по изменению одной из ссылок своего свойства, т. е. добавление нового элемента в список кодом `persistent.my_list.append(123)` будет проигнорировано (как и с `+=`), а создание нового из старых значений и нового - `persistent.my_list = persistent.my_list + [123]` - нет;

Общие подробности сохранений:

- Не каждый объект может быть сохранён - например, не сохраняются лямбды (анонимные функции), генераторы и итераторы (поэтому в сценариях доступен цикл `while`, но не доступен `for`), а также скомпилированный код (результат `compile(...)`);
- Функция `picklable(your_object)` позволяет узнать, можно ли сохранить ваш объект;
- Она часто используется - например, при проверках в системе сигналов и таймаутов;
- При создании или изменении любых своих классов проверяйте корректность сохранения и загрузки;
- Проверка на необходимость сохранения производится игрой после каждого кадра.

Также нельзя сохранить классы и функции, недоступные по своему имени, например:

    def f():
        return 123
    f2 = f
    del f # or f = 123

    print f2.__module__ # '__main__'
    print f2.func_name # 'f'
    print getattr(sys.modules[f2.__module__], f2.func_name) is f2 # False

При попытке сохранить несохраняемый объект вы получите сообщение об ошибке со ссылкой на него (относительно глобального пространства имён):

- В примере выше это будет просто `f2`;
- В примере вроде `my_list = [123, dict(a = f), 321]` путь будет `my_list.1.a` (т. е. без фигурных скобок и кавычек);
- Для получения внутренней структуры у нестандартных классов используется метод `__getstate__` (конечно же он реализован для класса `Object` и его потомков).

## Сохранение и загрузка игры

Функции сохранения и загрузки:

- `renpy.save(slot = None, page = None)` - сохранить,
- `renpy.load(slot = None, page = None)` - загрузить,
- `renpy.can_load(slot = None, page = None)` - вернёт `True`, если указанное сохранение существует и `False`, если нет.

Пример сохранения игры в слот `1` страницы `5`: `renpy.save(1, page = 5)`.
Отсчёт слотов и страниц идёт с `1` (т. е. нет слотов или страниц с названием `"0"`).

Кроме "цифровых" страниц есть ещё "строчные":

- `"auto"` - для авто-сохранений,
- `"quick"` - для быстрых сохранений.

При неуказании (`None`) страницы она берётся от `slots.get_page()`.
Установить её можно с помощью `slots.set_page(5)`.
Обычно это делается не вручную, а при переключении страниц в скринах сохранения и загрузки.
Указыние слота не обязательно по тем же причинам (если оставить `None`, то берётся выделенный слот).

О настройке кол-ва страниц и слотов в странице можно прочесть в соответствующем абзаце статьи Настройка интерфейса (gui).

При вызове функции сохранения всего лишь ставится отметка о необходимости сохранения, само же оно производится после обработки текущего кадра.

## Быстрые сохранение и загрузка

Быстрые сохранение и загрузка используют страницу `quick` и первый слот на ней (напоминание: отсчёт слотов - с `1`).
Перед сохранением слоты сортируются по времени создания сохранений, таким образом при полной "заполненности" будет удалёно наиболее старое сохранение, а остальные будут "сдвинуты".

Функции:

- `quick_load()` - быстрая загрузка,
- `quick_save()` - быстрое сохранение.

Действия (`callable` (вызываемые) объекты для свойства `action` объектов `key` и `textbutton`):

- `QuickLoad()` - быстрая загрузка,
- `QuickSave()` - быстрое сохранение.

## Функции от renpy

Ren-Engine поддерживает относительно большую совместимость с renpy, поэтому для желающих портировать игру с renpy и для желающих переписать стандартные скрины загрузки и сохранения есть большой набор функций и классов-действий

Функции:

- `renpy.list_slots(page = None)` - список слотов, доступных для загрузки с указанной страницы,
- `renpy.slot_mtime(slot = None, page = None)` - получить время создания для указанного сохранения (в `utc`-форме),
- `slots.mtime_formatted(slot = None, page = None)` - время в формате "день.месяц.год час:минуты" (нет в renpy),
- `renpy.slot_screenshot(slot = None, page = None)` - получить скриншот сохранения,
- `renpy.unlink_save(slot = None, page = None)` - удалить сохранение.

Классы-действия для кнопок:

- `FilePage(page)` - установить страницу `page`,
- `FileSave(slot = None, page = None)` - сохранить слот,
- `FileLoad(slot = None, page = None)` - загрузить,
- `FileDelete(slot = None, page = None)` - удалить.

Функции, именованные как классы (возможно, для единообразия сущностей, используемых в скринах сохранения и загрузки?):

- `FileCurrentPage()` - возвращает название текущей страницы (строку),
- `FileTime(slot = None, page = None, empty = '')` - возвращает форматированное время или `empty`, если сохранения нет,
- `FileScreenshot(slot = None, page = None)` - аналог для `renpy.slot_screenshot`,
- `FileLoadable(slot = None, page = None)` - аналог для `renpy.can_load`.

## Дополнительно

Есть ещё несколько вещей, без которых будет сложно переписать скрины сохранения и загрузки:

- `slots.pages` - список всех доступных страниц.
- `slots.slots` - список всех доступных слотов для каждой страницы.
- `slots.get(name)` - возвращает для слота `name` на текущей странице объект со след. свойствами:
  - `xsize`, `ysize` - размеры для слота,
  - `ground` - изображение (скриншот сохранения с наложенным `gui.slot_selected` или `gui.slot_hover`),
  - `mouse` - для свойства `mouse` кнопки слота (стоит ли менять курсор при наведении на кнопку),
  - `action` - действие при нажатии,
  - `desc` - описание (отформатированное время создания сохранения).
- `slots.check_update()` - вызывается в начале скрина `slots` для проверки и обновления слотов.

Скрин `slots` содержит общую часть скринов `load` и `save`, которые просто "используют" (`use`) его.

Примеры использования можно посмотреть в `rpy`-файлах `save`, `load` и `slots` папки `Ren-Engine/rpy/screens`.

## Не сохранять

Вы можете указать объекту (экземпляру класса `Object` или его наследнику) не сохранять некоторые свои свойства.
Это особенно полезно в `persistent`-объекте вроде `config` (напоминание: `config = persistent.config`), потому как там часто указываются настройки вроде `config.has_autosave` или `config.keymap`, и сохранять и перезаписывать их нет никакого смысла.

Пример: `config.set_prop_is_not_persistent('keymap')`.
Отмена: `config.set_prop_is_not_persistent('keymap', False)`.

Далее ->
<- Назад