Сохранение и загрузка - TrueCat17/Ren-Engine GitHub Wiki

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

Данные между запусками можно хранить в объекте 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).

Кроме того, есть более простой и радикальный способ не сохранять объекты - использовать экземпляр класса DontSave.
Можно использовать уже готовый (dont_save) или создать свой dont_save_my_props = DontSave().
Суть в том, что этот класс вообще не сохраняет своих свойств и загружается "чистым".
Это бывает удобным, если идёт работа с файлами, сетью и кучей связанных с ними переменных и функций, сохранять которые нельзя.


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

⚠️ **GitHub.com Fallback** ⚠️