Welcome to the sponsor-exclusive content for the Ren'Py Patreon. Sponsors like you ensure this page exists. Thank you.
One thing I like to do with these articles is highlight features of Ren’Py that I think might not be used as much as they could be, and today I’d like to talk about the ability to store metadata as part of the save slots. This metadata makes it easier for the player to figure out what’s stored in each save slot.
First, I’ll talk about what metadata is. Then I’ll show you two ways that you can use it to distinguish save slots from each other - a simple way that lets you give a name to each save slot, and a more complicated way that lets you associate all sorts of information with a slot.
Metadata is a word that means “data about data”. Probably the best way to think of it is when you’re looking at a physical book. A book is filled with quite a bit of data: the tens of thousands of words that fill its pages. If the only way we could tell two books apart was to read the two books, it would be hard to find the book that we want.
Instead, books have information on them. The spine of a book almost always includes the title and author, which lets us find the book we want. The library by me goes one step further for the genre fiction sections, giving books stickers so one can tell science fiction, fantasy, and mystery novels apart.
Ren’Py save slots have the same sort of information. By default, each slot has three pieces of information associated with it:
Beyond these, there are two other kinds of metadata that can be included, but aren’t by default.
The easiest form of metadata to include is a save name, which is a small amount of text that is displayed underneath the same slot. The default Ren’Py GUI is already set up to display the save name, so the only thing you’ll need to do is to choose one.
The way to do this is by setting the save_name variable, by writing:
label start:
$ save_name = "Chapter 1: The Dawn of the Third Age."
"It was our last, best hope for peace..."
At the start of each chapter, you can change the value of save_name,
and saves that occur inside that chapter will reflect the name. The
default GUI reserves two lines for these save names, so it’s probably
best to limit them to 12 or so words.
The other form of metadata we can add is JSON - the JavaScript Object Notation. Despite the name, JSON is a standard way of representing data. Ren’Py uses it here because it can be loaded very quickly, and because it doesn’t have the same sort of side effects that loading a saved game can have.
Translated into the Python terms that you might be more familiar with, a JSON document can consist of the following:
Any combination of these values can be added to the JSON metadata, though I’d recommend sticking with numbers and strings if you can, just because they’re simpler to reason about.
In Ren’Py, adding JSON metadata is done by adding a function you define to
config.save_json_callbacks. This function, which is called whenever the user
saves the game, takes a dictionary as its first and only parameter. You can change that dictionary by adding your own data to it.
Here’s an example:
default eileen_level = 0
default lucy_level = 0
init python:
def json_callback(d):
d["eileen_level"] = eileen_level
d["lucy_level"] = lucy_level
config.save_json_callbacks.append(json_callback)
We first create two variables that we might want to save, eileen_level and
lucy_level. We then create a Python function that adds them to a dictionary
that is passed to the function as its sole parameter. The function itself is
added to the list of callbacks that is run on a save.
Finally, in our game’s script, we’ll update the variables we created like this:
e "We just won the battle... and we're levelling up!"
$ eileen_level = eileen_level + 2
$ lucy_level = lucy_level + 1
l "Hey! Why did you get one more level than me?!"
Now, saves will include the current value of the level variables.
While we’re just using two numbers here, we could add True and False, strings, or lists. However, you’d get an error if you were to try to include a Python object.
Accessing the JSON metadata is done through FileJson(), which takes
a slot name and a field, and returns the field’s value. This function
is very fast - Ren’Py stores the information in memory - and so can be
used inside a screen.
Here’s an example of it in use. This is part of the file_slots screen,
which is part of gui.rpy in a Ren’Py game.
## The grid of file slots.
grid gui.file_slot_cols gui.file_slot_rows:
style_prefix "slot"
xalign 0.5
yalign 0.5
spacing gui.slot_spacing
for i in range(gui.file_slot_cols * gui.file_slot_rows):
$ slot = i + 1
button:
action FileAction(slot)
has vbox
# Instead of just a screenshot, we overlay the screenshot with
# some of the metadata.
fixed:
xalign 0.5
xysize (config.thumbnail_width, config.thumbnail_height)
add FileScreenshot(slot)
# Only include the metadata if we can load the slot.
if FileLoadable(slot):
# Retrieve the metadata.
$ eileen_level = FileJson(slot, "eileen_level")
$ lucy_level = FileJson(slot, "lucy_level")
# Place it into an appropriately formatted text displayable.
text "Eileen lv. [eileen_level], Lucy lv. [lucy_level]":
style "slot_name_text"
yalign 0.0
outlines [ (1, "#000", 0, 0) ]
text FileTime(slot, format=_("{#file_time}%A, %B %d %Y, %H:%M"), empty=_("empty slot")):
style "slot_time_text"
text FileSaveName(slot):
style "slot_name_text"
key "save_delete" action FileDelete(slot)
Note that this just the nuts and bolts way of formatting the metadata - the example above overlays the metadata on top of the file’s screenshot. Once the data is retrieved using FileJson, though, there are many things you can do in screen language to determine how it is displayed.
Adding metadata to your game is a nice extra, as it helps your player figure
out which save is which - something that can be useful when coming back to
a game from an extended absence, or trying to find a new route. For visual
novels, save_name provides a simple way of adding a chapter title.
For more complicated visual novels, RPGs, or life-simulation games, the JSON
metadata approach will let you produce nicely-formatted screens.
The title image is derived from https://commons.wikimedia.org/wiki/File:Children%27s_books_at_a_library.jpg, by the Wikipedia/Wikimedia user ProjectManhattan.