# saveimport.rpy # Save import/export functionality. Allows you to 'export' your saves to other games, so they can 'import' your variables. Both games must include this file. # Only tested in Ren'Py v6.14.1. # Copyright (C) 2013 Shiz. # Released under the WTFPL: see http://sam.zoy.org/wtfpl/COPYING for details. # # Usage: # At the end of your game, call renpy.export_save() to export that save file. # In the other game, call renpy.list_exported_saves(game), where game is the config.save_directory of the game you want to import from. # This will provide you with a list of (name, extra_info, time) tuples to choose from. # Call renpy.load_exported_save(game, name, destination) to load a save, where game is the same as before, name is the name returned by renpy.list_exported_saves, # and destination is in which sub-object to place the values. (e.g., 'ep1' will allow you to access the variables via ep1.variable_name in your game) python early: config.exported_savegame_suffix = '.ers' init python: if persistent.exported_savegame_count is None: persistent.exported_savegame_count = 0 import os from os import path import zipfile import StringIO import renpy.exports as renpy def list_exported_saves(name): """ Give a tuple of exported saves from the game named by `name`. `name` should be the config.save_directory of said game. """ savedir = config.savedir.replace(config.save_directory, name) saves = [] for file in os.listdir(savedir): if not file.endswith(config.exported_savegame_suffix): continue savezip = zipfile.ZipFile(path.join(savedir, file), 'r') extra_info = savezip.read('extra_info').decode('utf-8') savezip.close() time = path.getmtime(path.join(savedir, file)) saves.append((file.replace(config.exported_savegame_suffix, ''), extra_info, time)) return saves renpy.list_exported_saves = list_exported_saves def export_save(extra_info = '', filename = str(persistent.exported_savegame_count)): """ Export current state as a savegame importable by the other functions in this module. """ filename = filename + config.exported_savegame_suffix persistent.exported_savegame_count += 1 try: os.unlink(path.join(renpy.config.savedir, filename)) except: pass roots = renpy.game.log.freeze(None) logfile = StringIO.StringIO() renpy.loadsave.dump(roots, logfile) savefile = file(path.join(renpy.config.savedir, filename), "wb") savezip = zipfile.ZipFile(savefile, "w", zipfile.ZIP_DEFLATED) savezip.writestr("extra_info", extra_info.encode("utf-8")) savezip.writestr("renpy_version", renpy.version()) savezip.writestr("log", logfile.getvalue()) savezip.close() savefile.close() logfile.close() renpy.export_save = export_save def load_exported_save(game, file, destination): """ Load named save `file` from `game` in the store object `destination`. """ savedir = config.savedir.replace(config.save_directory, game) savefile = path.join(savedir, file) + config.exported_savegame_suffix # Get save data. savezip = zipfile.ZipFile(savefile, 'r') logdata = savezip.read('log') savezip.close() # Create store if not available. store_destination = 'store.' + destination if not store_destination in renpy.python.store_dicts.keys(): renpy.python.create_store(store_destination) # Process save data. roots = renpy.loadsave.loads(logdata) for name, value in roots.iteritems(): # Get store name and value name. if '.' in name: store_name, name = name.rsplit('.', 1) else: store_name = 'store' # Set appropriate name. if store_name == 'store': setattr(getattr(store, destination), name, value) else: # Create sub-store if nonexistant. raw_store_name = store_destination + '.' + store_name if not raw_store_name in renpy.python.store_dicts.keys(): renpy.python.create_store(raw_store_name) renpy.python.store_dicts[store_destination][store_name] = sys.modules[raw_store_name] renpy.store_dicts[raw_store_name][name] = value renpy.store_dicts[raw_store_name].ever_been_changed.add(name) renpy.load_exported_save = load_exported_save class LoadExportedSave(object): def __init__(self, *args): self.args = args def __call__(self): renpy.load_exported_save(*args)