- Jun 25, 2017
- 2,577
- 7,443
OK, I couldn't resist. Here's some code that will dump a persistent file. It's raw Python 3.x (I don't have Python 2.x installed), so you'd have to have Python 3 installed on your computer, but, using that, you could run it as:Personally I quit. It's near midnight here, I had a fucking hard day and lost enough time with this, especially since I don't need it.
Code:
python dump_persistent.py PATH_TO_A_PERSISTENT_FILE > output.txt
Code:
import io
import pickle
import pprint
import sys
import zlib
class RevertableDict(dict):
pass
class RevertableList(list):
pass
class RevertableSet(set):
def __setstate__(self, state):
if isinstance(state, tuple):
self.update(state[0].keys())
else:
self.update(state)
class MyUnpickler(pickle.Unpickler):
def find_class(self, module: str, name: str) -> type:
if name == "RevertableDict":
return RevertableDict
if name == "RevertableList":
return RevertableList
if name == "RevertableSet":
return RevertableSet
if name == "set":
return set
return type(name, (object,), {})
class DumpPersistent:
def __init__(self, file_path: str) -> None:
self._file_path = file_path
def run(self) -> None:
with open(self._file_path, "rb") as file:
file_bytes = file.read()
decompressed_bytes = zlib.decompress(file_bytes)
file_like_object = io.BytesIO(decompressed_bytes)
unpickler = MyUnpickler(file_like_object)
result = unpickler.load()
pprint.pprint(result.__dict__)
if __name__ == "__main__":
if len(sys.argv) != 2:
print("Usage: python dump_persistent.py path_to_file")
sys.exit(1)
file_path = sys.argv[1]
dumper = DumpPersistent(file_path)
dumper.run()
Unpickler
class, but with find_class
overridden to handle the fact that the pickle will be looking for Ren'py-specific classes.Now, having said, that, I don't know what this will do if you have managed to save a class of your own into the persistent file - might work, might blow chunks. But it was an interesting exercise.
What I've been able to determine is the following:
The
Persistent
object will have an attribute for each persistent variable you've set. No surprise whatsoever there.Beyond that, it has the following attributes, some of which I've decoded, others of which I haven't:
- _achievement_progress - a dict. Use unknown
- _achievements - a set. Use unknown
- _changed - a dict that seems to record the last time any of the persistent items were changed. Key is the attribute name, value appears to be a timestamp as a floating point number.
- _character_volume - a dict. Use unknown.
- _chosen - a dict. Appears to record every menu entry in the game, along with whether or not you've taken that choice.
- _console_history - a list of tuples. All the lines that have been output to the console
- _console_line_history - a list of lists. Appears to have all the commands you've typed into the console
- _console_short - boolean. Meaning unknown
- _console_traced_short - boolean. Meaning unknown
- _console_unicode_escaping - boolean. Meaning unknown
- _director_bottom - boolean. Meaning unknown
- _file_folder - int. Meaning unknown
- _file_page - int. Meaning unknown
- _file_page_name - dict. Meaning unknown.
- _gl2 - bolean. Meaning unknown
- _gui_preference - dict. Meaning unknown.
- _gui_preference_default - dict. Meaning unknown.
- _iap_purchases - dict. Meaning unknown.
- _preference_default - dict. Appears to store default values for preferences
- _preferences - Preferences object, storing the user's preferences.
- _seen_audio - dict. Key is every audio or movie file, value is whether or not the user has seen it.
- _seen_ever - dict. Key is every label (ones you provide, or the ones Ren'py generates for every line) and whether or not the user has seen it.
- _seen_images - dict. Key is a tuple for every image, and value is whether or not the user has seen it.
- _seen_translates - set. Probably related to the translation system - not sure exactly what the contents are
- _set_preferences - boolean. Use unknown.
- _style_preferences - dict. Probably related to the style preference system.
- _update_last_checked - dict. Use unknown
- _update_version - dict. Use unknown
- _virtual_size - tuple that appears to contain the (width,height) of the game.
- _voice_mute - RevertableSet. Use unknown
I'm sure I could figure out what the rest of those attributes contains if I wanted to spend time poking through the Ren'py code, but now, like anne O'nymous, it's late and I feel I've done my duty for the day.
anne O'nymous, have fun with this - I know you won't be able to resist...