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