def __init__(self): # A map from (module, field) to the id of the object in that field. self.variables = {} # A map from id(object) to objects. This is discarded after being # pickled. self.objects = {} # A map from module to the set of names in that module. self.names = {} if mobile: return for m in sys.modules.values(): if m is None: continue self.backup_module(m) # A pickled version of self.objects. self.objects_pickle = pickle.dumps(self.objects, pickle.HIGHEST_PROTOCOL) self.objects = None
def save(): """ Saves the persistent data to disk. """ if not should_save_persistent: return try: data = zlib.compress(dumps(renpy.game.persistent), 3) renpy.loadsave.location.save_persistent(data) except Exception: if renpy.config.developer: raise global persistent_mtime # Prevent updates just after save mtime = persistent_mtime for mtime, _data in renpy.loadsave.location.load_persistent(): if mtime <= persistent_mtime: continue persistent_mtime = mtime
def backup_module(self, mod): """ Makes a backup of `mod`, which must be a Python module. """ try: name = mod.__name__ except: return if not name.startswith("renpy"): return if name in backup_blacklist: return if name.startswith("renpy.styledata"): return self.names[mod] = set(vars(mod).keys()) for k, v in vars(mod).items(): if k.startswith("__") and k.endswith("__"): continue if isinstance(v, type_blacklist): continue if name + "." + k in name_blacklist: continue idv = id(v) self.variables[mod, k] = idv self.objects[idv] = v # If we have a problem pickling things, uncomment the next block. try: pickle.dumps(v, pickle.HIGHEST_PROTOCOL) except: print("Cannot pickle", name + "." + k, "=", repr(v)) print("Reduce Ex is:", repr(v.__reduce_ex__(pickle.HIGHEST_PROTOCOL)))
def save_bytecode(self): if renpy.macapp: return if self.bytecode_dirty: try: fn = renpy.loader.get_path(BYTECODE_FILE) with open(fn, "wb") as f: data = (BYTECODE_VERSION, self.bytecode_newcache) f.write(zlib.compress(dumps(data), 3)) except Exception: pass
def save_cache(): if not ccache.updated: return if renpy.macapp: return try: data = zlib.compress(dumps(new_ccache, True), 3) with open(renpy.loader.get_path(CACHE_FILENAME), "wb") as f: f.write(data) except Exception: pass
def load_file(self, dir, fn): # @ReservedAssignment if fn.endswith(".rpy") or fn.endswith(".rpym"): if not dir: raise Exception("Cannot load rpy/rpym file %s from inside an archive." % fn) base, _, game = dir.rpartition("/") olddir = base + "/old-" + game fullfn = dir + "/" + fn rpycfn = fullfn + "c" oldrpycfn = olddir + "/" + fn + "c" stmts = renpy.parser.parse(fullfn) data = { } data['version'] = script_version data['key'] = self.key or 'unlocked' if stmts is None: return data, [ ] used_names = set() for mergefn in [ oldrpycfn, rpycfn ]: # See if we have a corresponding .rpyc file. If so, then # we want to try to upgrade our .rpy file with it. try: self.record_pycode = False with open(mergefn, "rb") as rpycf: bindata = self.read_rpyc_data(rpycf, 1) if bindata is not None: old_data, old_stmts = loads(bindata) self.merge_names(old_stmts, stmts, used_names) del old_data del old_stmts except Exception: pass finally: self.record_pycode = True self.assign_names(stmts, renpy.parser.elide_filename(fullfn)) pickle_data_before_static_transforms = dumps((data, stmts)) self.static_transforms(stmts) pickle_data_after_static_transforms = dumps((data, stmts)) if not renpy.macapp: try: with open(rpycfn, "wb") as f: self.write_rpyc_header(f) self.write_rpyc_data(f, 1, pickle_data_before_static_transforms) self.write_rpyc_data(f, 2, pickle_data_after_static_transforms) with open(fullfn, "rb") as fullf: rpydigest = hashlib.md5(fullf.read()).digest() self.write_rpyc_md5(f, rpydigest) except Exception: import traceback traceback.print_exc() self.loaded_rpy = True elif fn.endswith(".rpyc") or fn.endswith(".rpymc"): data = None stmts = None with renpy.loader.load(fn) as f: for slot in [ 2, 1 ]: try: bindata = self.read_rpyc_data(f, slot) if bindata: data, stmts = loads(bindata) break except Exception: pass f.seek(0) else: return None, None if data is None: print("Failed to load", fn) return None, None if not isinstance(data, dict): return None, None if self.key and data.get('key', 'unlocked') != self.key: return None, None if data['version'] != script_version: return None, None if slot < 2: self.static_transforms(stmts) else: return None, None return data, stmts
def dumps(o): if renpy.config.use_cpickle: return cPickle.dumps(o, cPickle.HIGHEST_PROTOCOL) else: return pickle.dumps(o, pickle.HIGHEST_PROTOCOL)
def load_file(self, dir, fn): # @ReservedAssignment if fn.endswith(".rpy") or fn.endswith(".rpym"): if not dir: raise Exception( "Cannot load rpy/rpym file %s from inside an archive." % fn) fullfn = dir + "/" + fn rpycfn = fullfn + "c" stmts = renpy.parser.parse(fullfn) data = {} data['version'] = script_version data['key'] = self.key or 'unlocked' if stmts is None: return data, [] # See if we have a corresponding .rpyc file. If so, then # we want to try to upgrade our .rpy file with it. try: self.record_pycode = False with open(rpycfn, "rb") as rpycf: bindata = self.read_rpyc_data(rpycf, 1) old_data, old_stmts = loads(bindata) self.merge_names(old_stmts, stmts) del old_data del old_stmts except: pass finally: self.record_pycode = True self.assign_names(stmts, renpy.parser.elide_filename(fullfn)) if not renpy.macapp: try: f = open(rpycfn, "wb") self.write_rpyc_header(f) self.write_rpyc_data(f, 1, dumps((data, stmts), 2)) except: pass self.static_transforms(stmts) if not renpy.macapp: try: self.write_rpyc_data(f, 2, dumps((data, stmts), 2)) with open(fullfn, "rU") as fullf: rpydigest = hashlib.md5(fullf.read()).digest() self.write_rpyc_md5(f, rpydigest) f.close() except: pass self.loaded_rpy = True elif fn.endswith(".rpyc") or fn.endswith(".rpymc"): data = None stmts = None f = renpy.loader.load(fn) try: for slot in [2, 1]: try: bindata = self.read_rpyc_data(f, slot) if bindata: data, stmts = loads(bindata) break except: pass f.seek(0) else: return None, None if data is None: print("Failed to load", fn) return None, None if not isinstance(data, dict): return None, None if self.key and data.get('key', 'unlocked') != self.key: return None, None if data['version'] != script_version: return None, None if slot < 2: self.static_transforms(stmts) finally: f.close() else: return None, None return data, stmts