Сохранение и загрузка - 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()- быстрое сохранение.
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().
Суть в том, что этот класс вообще не сохраняет своих свойств и загружается "чистым".
Это бывает удобным, если идёт работа с файлами, сетью и кучей связанных с ними переменных и функций, сохранять которые нельзя.