[Solved] Game saves from previous versions when adding new variables

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
Adrian_DVL
Regular
Posts: 141
Joined: Fri Mar 15, 2019 8:46 am
Completed: Clockwork Poison
Projects: Melodic Dates, Clockwork Poison: Salvation
Contact:

[Solved] Game saves from previous versions when adding new variables

#1 Post by Adrian_DVL »

Hi guys!

So I know this is the same old problem as always, but it gets worse and worse as you update your long sandbox game over and over and you have to warn your players not to use previous versions saves.

Let's say you have a sandbox project with a short updating period, and the MC has an inventory and a quest list, but you don't know what kind of quest or items you'll need to add to the code in future updates, so you can't add them onto your code in advance. Yes, you can set a lot of flags at once in order to use it later when you need it, but you can't set "item slots" or "quest slots" because they're objects from classes and also they're displayables: you can't set a "default item1 = Item("name", "pic.png")" or this is what your players will see loading the code on their brand new version of the game, even if you change it in the new version...

So, my question is: is there a way to avoid these variables updates problems, or to make RenPy update classes and variables from old saves when players load them in new versions of the game?

I know Renpy does not have an iterative update system and does not manage well this kind of things, but I'd apreciate any help on this!

PD: Someone might think declaring objects of a class with a "define" instead of a "default" would solve the problem, since "define" loads the new code everytime, but this way the objects won't load properly if the player saves and then loads the game, and will get a crash because of the object not being in the class.
Last edited by Adrian_DVL on Mon Apr 08, 2019 7:03 pm, edited 1 time in total.

rames44
Veteran
Posts: 233
Joined: Sun May 29, 2016 4:38 pm
Contact:

Re: Game saves from previous versions when adding new variables

#2 Post by rames44 »

There are a couple of aspects to this.

First, if necessary, you can use “after_load” to fix up an old save in a new game. Store a variable that will tell you what version of the game created the save, and you can write “conversion code” if necessary.

Second, and this is just personal style, I try to avoid saving class instances as part of my game. I create my classes and then create class instances using “define” so they’re not part of the save. All the save data is formatted as Python dictionaries and lists, etc. that the classes then reference as required. Essentially, the data is external to the classes themselves. That way, I can rewrite the classes as necessary as long as they’re compatible with the save format (or with a rewritten save format per the above)

Once you start saving class instances as part of your save, as you’ve found out, you’re more restricted on backwards save compatibility.

Adrian_DVL
Regular
Posts: 141
Joined: Fri Mar 15, 2019 8:46 am
Completed: Clockwork Poison
Projects: Melodic Dates, Clockwork Poison: Salvation
Contact:

Re: Game saves from previous versions when adding new variables

#3 Post by Adrian_DVL »

rames44 wrote: Mon Apr 08, 2019 11:45 am There are a couple of aspects to this.

First, if necessary, you can use “after_load” to fix up an old save in a new game. Store a variable that will tell you what version of the game created the save, and you can write “conversion code” if necessary.

Second, and this is just personal style, I try to avoid saving class instances as part of my game. I create my classes and then create class instances using “define” so they’re not part of the save. All the save data is formatted as Python dictionaries and lists, etc. that the classes then reference as required. Essentially, the data is external to the classes themselves. That way, I can rewrite the classes as necessary as long as they’re compatible with the save format (or with a rewritten save format per the above)

Once you start saving class instances as part of your save, as you’ve found out, you’re more restricted on backwards save compatibility.
As per the second point, I understand what you mean. In fact, I can "define" auxiliar instances of, for example, my "Item" class, and then update them with new items as new versions are released, and those instances do change in-game even in old saves, but this does not work on, for example, my "Quest" class, since, like I've said above, if I create quests with "define", they seem to be missed when the player saves the game and loads it again (even when my Quest class have the same format as the Item one)... I guess that's because I'm constantly appending and removing Quest instances through labels. So I can only create them using "default" in order for them to work.

So, apart from creating instances using "define", which I can't, I can't see any other way to make new ones work in an old save.

On the other front, I've read a few times about the "after_load" thing but I'm afraid I don't know how it works. Is it a statement to use in a label? If that's the case, how is it supposed to fix up variables from an old save?

Adrian_DVL
Regular
Posts: 141
Joined: Fri Mar 15, 2019 8:46 am
Completed: Clockwork Poison
Projects: Melodic Dates, Clockwork Poison: Salvation
Contact:

Re: Game saves from previous versions when adding new variables

#4 Post by Adrian_DVL »

Ok, I'll try to be a bit more graphic (sorry for double post).

Here's what I have. These two classes, one of them for the quest, and the other one for the container, the quest list:

Code: Select all

    class Quest(renpy.store.object):
        def __init__(self, subj=".png", descr=""):
            self.subj = subj
            self.descr = descr

    class Qlist(renpy.store.object):
        def __init__(self):
            self.quests = []
        def add(self, quest):
            self.quests.append(quest)
        def ok(self, quest):
            self.quests.remove(quest)
And then I have the different instances created with a "default", like this:

Code: Select all

default hope1 = Quest("hope", "Meet Hope at the gym.")
default hope2 = Quest("hope", "Go to Hope's apartment.")
default hope3 = Quest("hope", "Go to the police station.")
Now, this way it works perfectly fine. Each time I need to add a quest to the list I do it by qlist.add(hope1), or replacing "add" by "ok" in order to remove it.
But this way I can't neither create new quests nor change which already exist and expect them to work in old save files, because they won't.
On the other hand, if I create them with "define" instead of "default", once the player saves the game with quests in his list and loads the game again, the player gets a crash about x instance not being in the list.

I don't have the same problem with items in the class "Inventory", and that's because, while I do append them through labels, I don't remove them through them, but from the inventory itself by clicking them with the mouse.

So neither I can create quests with default due to the "old saves" problems , nor I can create them with "define" because they're missing after loading the game.

rames44
Veteran
Posts: 233
Joined: Sun May 29, 2016 4:38 pm
Contact:

Re: Game saves from previous versions when adding new variables

#5 Post by rames44 »

If your game defines a label called “after_load”, Ren’py calls it after loading all the data from a save, but before executing any statements after the point where the save occurred. So you have access to all the data, and can make any changes you need to. When you “return”, then Ren’py resumes the game.

So, if I’m understanding your game logic, in the after_load block, you could add any new Quest objects that were introduced in that version of the game to your Qlist. Of course, you need some kind of logic to know which ones to add. One way might be a flag inside Quest that gets set when that Quest is added to a Qlist so that when it’s later removed, you know that it HAD been added at one point.

Adrian_DVL
Regular
Posts: 141
Joined: Fri Mar 15, 2019 8:46 am
Completed: Clockwork Poison
Projects: Melodic Dates, Clockwork Poison: Salvation
Contact:

Re: Game saves from previous versions when adding new variables

#6 Post by Adrian_DVL »

rames44 wrote: Mon Apr 08, 2019 6:14 pm If your game defines a label called “after_load”, Ren’py calls it after loading all the data from a save, but before executing any statements after the point where the save occurred. So you have access to all the data, and can make any changes you need to. When you “return”, then Ren’py resumes the game.

So, if I’m understanding your game logic, in the after_load block, you could add any new Quest objects that were introduced in that version of the game to your Qlist. Of course, you need some kind of logic to know which ones to add. One way might be a flag inside Quest that gets set when that Quest is added to a Qlist so that when it’s later removed, you know that it HAD been added at one point.
Oh, ok, I thought it was something different. So it's a label called in order to ensure the data inside it is loaded before the player does anything else in the game.

Alright, I've been messing around with after_load label and different old and new saves and now it seems it works perfectly: when I create new objects for Quest they're included in an old save without problems!

So thank you so much! Pretty useful, the after_load :D

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot]