Hey! Great topic, super useful for developers of all kinds and experience levels, thank you for putting so much time and effort into it.
I've been struggling with save compatibility in my game for a long time, and I finally found out what was wrong when I dug a little deeper into the RenPy core. So I want to chime in on this:
You can safely delete the .rpyc file, as long as you don't rename a label in this file ;
This particular point is not correct, at least, not fully so. If you delete .rpyc file, RenPy can and will generate new namemap/location entries for the lines within the blocks. If you use
from
clauses in your calls or just don't have a big return stack, this may not cause much harm, but at the same time, it just might wreck your saves.
For reference, RenPy call/return stacks are saved like this:
Code:
Return stack: [u'navigator_scripts.navigator_room_enter_helper', (u'game/scripts/repeatable_actions/cait/massage_sit/cait_massage_level_three.rpy', 1575100391, 28397), u'screen_utils.window_hide_pause']
Call location stack:[(u'game/scripts/navigation/navigator_scripts.rpy', 1575100391, 2322), (u'game/scripts/repeatable_actions/cait/massage_sit/cait_massage_level_three.rpy', 1575100391, 28396), u'screen_utils.window_hide_pause']
Note, the labels are stored as plain strings, but plain
call
directives are stored as opaque tuples.
And now to the .rpyc files. The thing is, .rpyc compilation is not deterministic. I will demonstrate the namemap dump diffs for one particular file. Namemap is the main index of all the addressable nodes in the RenPy script. Please note that the source .rpy file was not changed at all between runs.
First diff is between the .rpyc file that is currently stored in git and the one that was generated after I checked "force recompile" in the build dialog.
Note that while some lines are rearranged (diff viewer is not smart enough to align them), the indices are the same. This means that namemap stays consistent and if you take that return stack reference tuple from before, you will be able to find the corresponding node.
Now, I remove the
cait_massage_level_three.rpyc
file without changing anything in .rpy file and launch the game.
And all tuples (well, triples, but who's counting) are changed now. And that means that return stack is no longer valid and your players will be getting
Could not find return label
exception when they try to load the game!
And you can't really do anything about that if you don't have your old .rpyc files, because this line location generation is very state-dependent. You can try looking into the RenPy parser yourselves, I just had a cursory glance, but as far as I can see, it just increments a counter while going through the script and then slaps this number as a reference number for a node, along with the unixtime of compilation.
So, if you can at all help it,
do not delete your .rpyc files. Store them in your VCS, or at least back them up regularly if you don't use VCS (but you totally should).