Now that aluigi wrote a pickle decoder I tried to modify the rpa extraction script to decode the new Ren'py persistent file format to something more user readable but after reading the documentation and experimenting with the code it seems my understanding of quickbms is not good enough to do it myself so I tough I'd ask for help someone more experienced than me.
What I know so far is that there are 2 types of persistent file formats (new cPickle and old pickle) and they are both zlib compressed.
I've attached an example of both file types if anyone is wiling to take a look.
Ren'py persistent file decoding
-
- Posts: 45
- Joined: Sun Oct 09, 2016 6:27 pm
Ren'py persistent file decoding
Last edited by bugmenot on Sat Mar 04, 2017 8:41 pm, edited 1 time in total.
-
- Site Admin
- Posts: 12984
- Joined: Wed Jul 30, 2014 9:32 pm
Re: Ren'py persistent file decoding
Where are used these formats? In savegames?
You should use python pickle to fully load the objects.
The pickle.bms script was created only for having an easy and quick (and python-less) access to the data.
You should use python pickle to fully load the objects.
The pickle.bms script was created only for having an easy and quick (and python-less) access to the data.
-
- Posts: 45
- Joined: Sun Oct 09, 2016 6:27 pm
Re: Ren'py persistent file decoding
They are used to store the game configuration and other types of data that is shared between player games that can't be stored in the save files.
For example for "Gallery" or "New Game +".
P.S. Is there a easy way to save unpickled version of the file with python?
For example for "Gallery" or "New Game +".
P.S. Is there a easy way to save unpickled version of the file with python?
Last edited by bugmenot on Sat Mar 11, 2017 12:22 pm, edited 1 time in total.
-
- Posts: 45
- Joined: Sun Oct 09, 2016 6:27 pm
Re: Ren'py persistent file decoding
The best i managed to do so far based on RPA archives is:
but it returns an error:
Code: Select all
# RenPy persistent unpickler 0.1
init python:
try:
import cPickle as pickle
except:
import pickle
import sys
import zlib
f = open("game/saves/persistent", "rb")
data = f.read().decode("zlib")
f.close()
index = pickle.loads(data)
f = open("game/saves/persistent.txt", "wb")
f.write(str(len(index.keys()))+"\\n")
for key in index.keys():
for offset, dlen, start in index[key]:
f.write(key+"\\n")
f.write(str(offset)+"\\n")
f.write(str(dlen)+"\\n")
f.write(str(start)+"\\n")
f.write("\\n")
f.close()
but it returns an error:
Code: Select all
Full traceback:
File "renpy/bootstrap.py", line 295, in bootstrap
renpy.main.main()
File "renpy/main.py", line 419, in main
game.context().run(node)
File "game/unpickle_persistent.rpy", line 3, in script
init python:
File "renpy/ast.py", line 814, in execute
renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
File "renpy/python.py", line 1719, in py_exec_bytecode
exec bytecode in globals, locals
File "game/unpickle_persistent.rpy", line 22, in <module>
f.write(str(len(index.keys()))+"\\n")
TypeError: 'NoneType' object is not callable
-
- Posts: 45
- Joined: Sun Oct 09, 2016 6:27 pm
Re: Ren'py persistent file decoding
And using python produces this error (the same if I manually unpack the file and use the unpacked version with the original code):
1.py code:
Code: Select all
python -O 1.py 1.dat 1.txt
Traceback (most recent call last):
File "1.py", line 18, in <module>
index = pickle.loads(data)
File "renpy/persistent.py", line 30, in <module>
from renpy.loadsave import dump, dumps, loads
File "renpy/loadsave.py", line 653, in <module>
unknown = renpy.object.Sentinel("unknown")
AttributeError: 'module' object has no attribute 'object'
1.py code:
Code: Select all
try:
import cPickle as pickle
except:
import pickle
#import io
#import os
import sys
import zlib
#import renpy
#import types
#import pickle
#from cStringIO import StringIO
f = open(sys.argv[1], "rb")
data = f.read().decode("zlib")
f.close()
index = pickle.loads(data)
f = open(sys.argv[2], "wb")
f.write(str(len(index.keys()))+"\\n")
for key in index.keys():
for offset, dlen, start in index[key]:
f.write(key+"\\n")
f.write(str(offset)+"\\n")
f.write(str(dlen)+"\\n")
f.write(str(start)+"\\n")
f.write("\\n")
f.close()