Exemple #1
0
def open_tl_file(fn):

    if fn in tl_file_cache:
        return tl_file_cache[fn]

    if not os.path.exists(fn):
        dn = os.path.dirname(fn)

        try:
            os.makedirs(dn)
        except:
            pass

        f = open(fn, "a", encoding="utf-8")
        f.write(u"\ufeff")

    else:
        f = open(fn, "a", encoding="utf-8")

    if todo:
        f.write(u"# TO" + "DO: Translation updated at {}\n".format(
            time.strftime("%Y-%m-%d %H:%M")))

    f.write(u"\n")

    tl_file_cache[fn] = f

    return f
Exemple #2
0
def init():
    """
    Creates the editor object, based on the contents of the RENPY_EDIT_PY
    file.
    """

    global editor
    editor = SystemEditor()

    path = os.environ.get("RENPY_EDIT_PY", None)

    if path is None:
        return

    with open(path, "r") as f:
        source = f.read()

    code = compile(source, path, "exec")

    scope = {"__file__": path}
    exec(code, scope, scope)

    if "Editor" in scope:
        editor = scope["Editor"]()  # type: ignore
        return

    raise Exception("{0} did not define an Editor class.".format(path))
Exemple #3
0
    def save_persistent(self, data):
        """
        Saves `data` as the persistent data. Data is a binary string giving
        the persistent data in python format.
        """

        with disk_lock:

            if not self.active:
                return

            fn = self.persistent
            fn_tmp = fn + tmp
            fn_new = fn + ".new"

            with open(fn_tmp, "wb") as f:
                f.write(data)

            safe_rename(fn_tmp, fn_new)
            safe_rename(fn_new, fn)

            # Prevent persistent from unpickle just after save
            self.persistent_mtime = os.path.getmtime(fn)

            renpy.util.expose_file(fn)

            self.sync()
Exemple #4
0
def load(filename):
    """
    Loads persistence data from `filename`. Returns None if the data
    could not be loaded, or a Persistent object if it could be
    loaded.
    """

    if not os.path.exists(filename):
        return None

    # Unserialize the persistent data.
    try:
        with open(filename, "rb") as f:
            s = zlib.decompress(f.read())
        persistent = loads(s)
    except:
        import renpy.display

        try:
            renpy.display.log.write("Loading persistent.")
            renpy.display.log.exception()
        except:
            pass

        return None

    persistent._update()

    return persistent
Exemple #5
0
def scandirfiles_from_remote_file(add, seen):
    """
    Fills out game_files from renpyweb_remote_files.txt.
    """

    # HTML5 remote files
    index_filename = os.path.join(renpy.config.gamedir,
                                  'renpyweb_remote_files.txt')
    if os.path.exists(index_filename):
        files = game_files
        with open(index_filename, 'r') as remote_index:
            while True:
                f = remote_index.readline()
                metadata = remote_index.readline()
                if f == '' or metadata == '':  # end of file
                    break

                f = f.rstrip("\r\n")
                metadata = metadata.rstrip("\r\n")
                (entry_type, entry_size) = metadata.split(' ')
                if entry_type == 'image':
                    entry_size = [int(i) for i in entry_size.split(',')]

                add('/game', f, files, seen)
                remote_files[f] = {'type': entry_type, 'size': entry_size}
Exemple #6
0
    def __init__(self, directory):
        self.directory = directory

        # Make the save directory.
        try:
            os.makedirs(self.directory)
        except:
            pass

        renpy.util.expose_directory(self.directory)

        # Try to write a test file.
        try:
            fn = os.path.join(self.directory, "text.txt")

            with open(fn, "w") as f:
                f.write("Test.")

            os.unlink(fn)

            self.active = True
        except:
            self.active = False

        # A map from slotname to the mtime of that slot.
        self.mtimes = {}

        # The persistent file.
        self.persistent = os.path.join(self.directory, "persistent")

        # The mtime of the persistent file.
        self.persistent_mtime = 0

        # The data loaded from the persistent file.
        self.persistent_data = None
Exemple #7
0
    def open_file(name, mode):
        f = open(name, mode)

        f.seek(0, 2)
        length = f.tell()
        f.seek(0, 0)

        return SubFile(f, 0, length, b'')
Exemple #8
0
    def save(self):

        fn = self._filename
        with open(fn + ".new", "wb") as f:
            dump(self, f)

        try:
            os.rename(fn + ".new", fn)
        except:
            os.unlink(fn)
            os.rename(fn + ".new", fn)
Exemple #9
0
def extract_strings_core(language, destination, merge=False, force=False):

    if (not force) and (language not in renpy.game.script.translator.strings
                        ):  # @UndefinedVariable
        raise Exception("Language %r does not have any translations." %
                        language)

    st = renpy.game.script.translator.strings[language]  # @UndefinedVariable

    result = {}

    if merge:
        with open(destination, "r") as f:
            result.update(json.load(f, encoding="utf-8"))

    for k, v in st.translations.items():
        if v and v != k:
            result[k] = v

    with open(destination, "w") as f:
        json.dump(result, f, ensure_ascii=True)
Exemple #10
0
def enable_trace(level):
    global trace_file
    global trace_local

    trace_file = open("trace.txt", "w", buffering=1, encoding="utf-8")

    if level > 1:
        trace_local = trace_function
    else:
        trace_local = None

    sys.settrace(trace_function)
Exemple #11
0
    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
Exemple #12
0
def process_file(fn):
    """
    Adds missing from clauses to `fn`.
    """

    if not os.path.exists(fn):
        return

    edits = missing[fn]
    edits.sort()

    with open(fn, "rb") as f:
        data = f.read().decode("utf-8")

    # How much of the input has been consumed.
    consumed = 0

    # The output.
    output = u""

    for position, target in edits:
        output += data[consumed:position]
        consumed = position

        output += " from {}".format(generate_label(target))

    output += data[consumed:]

    with open(fn + ".new", "wb") as f:
        f.write(output.encode("utf-8"))

    try:
        os.unlink(fn + ".bak")
    except Exception:
        pass

    os.rename(fn, fn + ".bak")
    os.rename(fn + ".new", fn)
Exemple #13
0
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
Exemple #14
0
def dialogue_command():
    """
    The dialogue command. This updates dialogue.txt, a file giving all the dialogue
    in the game.
    """

    ap = renpy.arguments.ArgumentParser(description="Generates or updates translations.")
    ap.add_argument("language", help="The language to extract dialogue for.")
    ap.add_argument("--text", help="Output the dialogue as plain text, instead of a tab-delimited file.", dest="text", action="store_true")
    ap.add_argument("--strings", help="Output all translatable strings, not just dialogue.", dest="strings", action="store_true")
    ap.add_argument("--notags", help="Strip text tags from the dialogue.", dest="notags", action="store_true")
    ap.add_argument("--escape", help="Escape quotes and other special characters.", dest="escape", action="store_true")
    args = ap.parse_args()

    tdf = not args.text
    if tdf:
        output = os.path.join(renpy.config.basedir, "dialogue.tab")
    else:
        output = os.path.join(renpy.config.basedir, "dialogue.txt")

    with open(output, "w") as f:
        if tdf:
            line = [
                "Identifier",
                "Character",
                "Dialogue",
                "Filename",
                "Line Number",
                "Ren'Py Script",
                ]

            f.write("\t".join(line) + "\n")

    for dirname, filename in renpy.loader.listdirfiles():
        if dirname is None:
            continue

        filename = os.path.join(dirname, filename)

        if not (filename.endswith(".rpy") or filename.endswith(".rpym")):
            continue

        filename = os.path.normpath(filename)
        language = args.language
        if language in ("None", ""):
            language = None
        DialogueFile(filename, output, tdf=tdf, strings=args.strings,
                     notags=args.notags, escape=args.escape, language=language)

    return False
Exemple #15
0
def open_error_file(fn, mode):
    """
    Opens an error/log/file. Returns the open file, and the filename that
    was opened.
    """

    try:
        new_fn = os.path.join(renpy.config.logdir, fn) # type: ignore
        f = open(new_fn, mode)
        return f, new_fn
    except Exception:
        pass

    try:
        f = open(fn, mode)
        return f, fn
    except Exception:
        pass

    import tempfile

    new_fn = os.path.join(tempfile.gettempdir(), "renpy-" + fn)
    return open(new_fn, mode), new_fn
Exemple #16
0
def load_face(fn):

    if fn in face_cache:
        return face_cache[fn]

    orig_fn = fn

    # Figure out the font index.
    index = 0

    if "@" in fn:
        index, fn = fn.split("@", 1)
        index = int(index)

    font_file = None

    try:
        font_file = renpy.loader.load(fn)
    except IOError:

        if (not renpy.config.developer) or renpy.config.allow_sysfonts:

            # Let's try to find the font on our own.
            fonts = [i.strip().lower() for i in fn.split(",")]

            pygame.sysfont.initsysfonts()

            for v in pygame.sysfont.Sysfonts.values():  # type: ignore
                if v is not None:
                    for _flags, ffn in v.items():
                        for i in fonts:
                            if ffn.lower().endswith(i):
                                font_file = open(ffn, "rb")
                                break

                        if font_file:
                            break

                if font_file:
                    break

    if font_file is None:
        raise Exception("Could not find font {0!r}.".format(orig_fn))

    rv = ftfont.FTFace(font_file, index, orig_fn)  # @UndefinedVariable

    face_cache[orig_fn] = rv

    return rv
Exemple #17
0
def load(fn):
    """
    Returns a file-like object for the given filename.
    """

    try:
        rv = renpy.loader.load(fn)
    except renpy.webloader.DownloadNeeded as exception:
        if exception.rtype == 'music':
            renpy.webloader.enqueue(exception.relpath, 'music', None)
        elif exception.rtype == 'voice':
            # prediction failed, too late
            pass
        # temporary 1s placeholder, will retry loading when looping:
        rv = open(os.path.join(renpy.config.commondir, '_dl_silence.ogg'), 'rb') # type: ignore
    return rv
Exemple #18
0
    def __init__(self):
        """
        Loads the script by parsing all of the given files, and then
        walking the various ASTs to initialize this Script object.
        """

        # Set us up as renpy.game.script, so things can use us while
        # we're loading.
        renpy.game.script = self

        if os.path.exists(renpy.config.renpy_base + "/lock.txt"):
            self.key = open(renpy.config.renpy_base + "/lock.txt", "rb").read()
        else:
            self.key = None

        self.namemap = { }
        self.all_stmts = [ ]
        self.all_pycode = [ ]
        self.all_pyexpr = [ ]

        # A list of statements that haven't been analyzed.
        self.need_analysis = [ ]

        self.record_pycode = True

        # Bytecode caches.
        self.bytecode_oldcache = { }
        self.bytecode_newcache = { }
        self.bytecode_dirty = False

        self.translator = renpy.translation.ScriptTranslator()
        self.init_bytecode()

        self.scan_script_files()

        self.translator.chain_translates()

        self.serial = 0

        self.digest = hashlib.md5(renpy.version_only.encode("utf-8"))

        self.loaded_rpy = False
        self.backup_list = [ ]

        self.duplicate_labels = [ ]
Exemple #19
0
def load_mappings():

    try:
        with renpy.loader.load("renpycontrollerdb.txt", False) as f:
            pygame_sdl2.controller.add_mappings(f)
    except Exception:
        pass

    try:
        with renpy.loader.load("gamecontrollerdb.txt", False) as f:
            pygame_sdl2.controller.add_mappings(f)
    except Exception:
        pass

    try:
        with open(os.path.join(renpy.config.renpy_base, "gamecontrollerdb.txt"), "rb") as f:
            pygame_sdl2.controller.add_mappings(f)
    except Exception:
        pass
Exemple #20
0
def scan_comments(filename):

    rv = []

    if filename not in renpy.config.translate_comments:
        return rv

    comment = []
    start = 0

    with open(filename, "r", encoding="utf-8") as f:
        lines = [
            i.rstrip() for i in f.read().replace(u"\ufeff", "").split('\n')
        ]

    for i, l in enumerate(lines):

        if not comment:
            start = i + 1

        m = re.match(r'\s*## (.*)', l)

        if m:
            c = m.group(1)

            if comment:
                c = c.strip()

            comment.append(c)

        elif comment:
            s = "## " + " ".join(comment)

            if s.endswith("#"):
                s = s.rstrip("# ")

            comment = []

            rv.append((start, s))

    return rv
Exemple #21
0
def load_from_archive(name):
    """
    Returns an open python file object of the given type from an archive file.
    """

    for prefix, index in archives:
        if not name in index:
            continue

        afn = transfn(prefix)

        data = [ ]

        # Direct path.
        if len(index[name]) == 1:

            t = index[name][0]
            if len(t) == 2:
                offset, dlen = t
                start = b''
            else:
                offset, dlen, start = t

            rv = SubFile(afn, offset, dlen, start)

        # Compatibility path.
        else:
            with open(afn, "rb") as f:
                for offset, dlen in index[name]:
                    f.seek(offset)
                    data.append(f.read(dlen))

                rv = io.BytesIO(b''.join(data))

        return rv

    return None
Exemple #22
0
    def __init__(self, filename, output, tdf=True, strings=False, notags=True, escape=True, language=None): # @ReservedAssignment
        """
        `filename`
            The file we're extracting dialogue from.

        `tdf`
            If true, dialogue is extracted in tab-delimited format. If false,
            dialogue is extracted by itself.

        `strings`
            If true, extract all translatable strings, not just dialogue.

        `notags`
            If true, strip text tags from the extracted dialogue.

        `escape`
            If true, escape special characters in the dialogue.
        """

        self.filename = filename

        commondir = os.path.normpath(renpy.config.commondir) # type: ignore

        if filename.startswith(commondir):
            return

        self.tdf = tdf
        self.notags = notags
        self.escape = escape
        self.strings = strings
        self.language = language

        self.f = open(output, "a", encoding="utf-8")

        self.write_dialogue()

        self.f.close()
Exemple #23
0
def lint():
    """
    The master lint function, that's responsible for staging all of the
    other checks.
    """

    ap = renpy.arguments.ArgumentParser(
        description=
        "Checks the script for errors and prints script statistics.",
        require_command=False)
    ap.add_argument("filename",
                    nargs='?',
                    action="store",
                    help="The file to write to.")
    ap.add_argument(
        "--error-code",
        action="store_true",
        help=
        "If given, the error code is 0 if the game has no lint errros, 1 if lint errors are found."
    )

    args = ap.parse_args()

    if args.filename:
        f = open(args.filename, "w", encoding="utf-8")
        sys.stdout = f

    renpy.game.lint = True

    print("\ufeff" + renpy.version + " lint report, generated at: " +
          time.ctime())

    # This supports check_hide.
    global image_prefixes
    image_prefixes = {}

    for k in renpy.display.image.images:
        image_prefixes[k[0]] = True

    # Iterate through every statement in the program, processing
    # them. We sort them in filename, linenumber order.

    all_stmts = list(renpy.game.script.all_stmts)
    all_stmts.sort(key=lambda n: n.filename)

    # The current count.
    counts = collections.defaultdict(Count)

    charastats = collections.defaultdict(int)

    # The current language.
    language = None

    menu_count = 0
    screen_count = 0
    image_count = 0

    global report_node

    for node in all_stmts:
        if isinstance(node, (renpy.ast.Show, renpy.ast.Scene)):
            precheck_show(node)

    for node in all_stmts:

        if common(node):
            continue

        report_node = node

        if isinstance(node, renpy.ast.Image):
            image_count += 1
            check_image(node)

        elif isinstance(node, renpy.ast.Show):
            check_show(node, False)

        elif isinstance(node, renpy.ast.Scene):
            check_show(node, True)

        elif isinstance(node, renpy.ast.Hide):
            check_hide(node)

        elif isinstance(node, renpy.ast.With):
            check_with(node)

        elif isinstance(node, renpy.ast.Say):
            check_say(node)

            counts[language].add(node.what)
            if language is None:
                charastats[node.who if node.who else 'narrator'] += 1

        elif isinstance(node, renpy.ast.Menu):
            check_menu(node)
            menu_count += 1

        elif isinstance(node, renpy.ast.Jump):
            check_jump(node)

        elif isinstance(node, renpy.ast.Call):
            check_call(node)

        elif isinstance(node, renpy.ast.While):
            check_while(node)

        elif isinstance(node, renpy.ast.If):
            check_if(node)

        elif isinstance(node, renpy.ast.UserStatement):
            check_user(node)

        elif isinstance(node, renpy.ast.Label):
            check_label(node)

        elif isinstance(node, renpy.ast.Translate):
            language = node.language

        elif isinstance(node, renpy.ast.EndTranslate):
            language = None

        elif isinstance(node, renpy.ast.Screen):
            screen_count += 1
            check_screen(node)

        elif isinstance(node, renpy.ast.Define):
            check_define(node, "define")
            check_redefined(node, "define")

        elif isinstance(node, renpy.ast.Default):
            check_define(node, "default")
            check_redefined(node, "default")

    report_node = None

    check_styles()
    check_filename_encodings()

    for f in renpy.config.lint_hooks:
        f()

    lines = []

    def report_language(language):

        count = counts[language]

        if count.blocks <= 0:
            return

        if language is None:
            s = "The game"
        else:
            s = "The {0} translation".format(language)

        s += """ contains {0} dialogue blocks, containing {1} words
and {2} characters, for an average of {3:.1f} words and {4:.0f}
characters per block. """.format(humanize(count.blocks), humanize(count.words),
                                 humanize(count.characters),
                                 1.0 * count.words / count.blocks,
                                 1.0 * count.characters / count.blocks)

        lines.append(s)

    print("")
    print("")
    print("Statistics:")
    print("")

    languages = list(counts)
    languages.sort(key=lambda a: "" if not a else a)
    for i in languages:
        report_language(i)

    lines.append(
        "The game contains {0} menus, {1} images, and {2} screens.".format(
            humanize(menu_count), humanize(image_count),
            humanize(screen_count)))

    if renpy.config.developer and renpy.config.lint_character_statistics:
        lines.append(report_character_stats(charastats))

    # Format the lines and lists of lines.
    for l in lines:
        if not isinstance(l, (tuple, list)):
            l = (l, )

        for ll in l:

            if ll.startswith(" * "):
                prefix = " * "
                altprefix = "   "
                ll = ll[3:]
            else:
                prefix = ""
                altprefix = ""

            for lll in textwrap.wrap(ll, 78 - len(prefix)):
                print(prefix + lll)
                prefix = altprefix

        print("")

    for i in renpy.config.lint_stats_callbacks:
        i()

    print("")
    if renpy.config.developer and (renpy.config.original_developer != "auto"):
        print("Remember to set config.developer to False before releasing.")
        print("")

    print(
        "Lint is not a substitute for thorough testing. Remember to update Ren'Py"
    )
    print("before releasing. New releases fix bugs and improve compatibility.")

    if error_reported and args.error_code:
        renpy.exports.quit(status=1)

    return False
Exemple #24
0
 def __init__(self):
     self.buffer = ''
     self.log = open("log", developer=False, append=False, flush=True)
Exemple #25
0
    def load_appropriate_file(self, compiled, source, dir, fn, initcode): # @ReservedAssignment
        data = None

        # This can only be a .rpyc file, since we're loading it
        # from an archive.
        if dir is None:

            rpyfn = fn + source
            lastfn = fn + compiled
            data, stmts = self.load_file(dir, fn + compiled)

            if data is None:
                raise Exception("Could not load from archive %s." % (lastfn,))

            with renpy.loader.load(fn + compiled) as f:
                f.seek(-hashlib.md5().digest_size, 2)
                digest = f.read(hashlib.md5().digest_size)

        else:

            # Otherwise, we're loading from disk. So we need to decide if
            # we want to load the rpy or the rpyc file.
            rpyfn = dir + "/" + fn + source
            rpycfn = dir + "/" + fn + compiled

            renpy.loader.add_auto(rpyfn)

            if os.path.exists(rpyfn):
                with open(rpyfn, "rb") as f:
                    rpydigest = hashlib.md5(f.read()).digest()
            else:
                rpydigest = None

            try:
                if os.path.exists(rpycfn):
                    with open(rpycfn, "rb") as f:
                        f.seek(-hashlib.md5().digest_size, 2)
                        rpycdigest = f.read(hashlib.md5().digest_size)
                else:
                    rpycdigest = None
            except Exception:
                rpycdigest = None

            digest = None

            if os.path.exists(rpyfn) and os.path.exists(rpycfn):

                # Are we forcing a compile?
                force_compile = renpy.game.args.compile # type: ignore

                # Use the source file here since it'll be loaded if it exists.
                lastfn = rpyfn

                data, stmts = None, None

                try:

                    if rpydigest == rpycdigest and not force_compile:

                        data, stmts = self.load_file(dir, fn + compiled)

                        if data is None:
                            print("Could not load " + rpycfn)

                except Exception:
                    renpy.display.log.write("While loading %r", rpycfn)
                    renpy.display.log.exception()

                    if "RENPY_RPYC_EXCEPTIONS" in os.environ:
                        print("While loading", rpycfn)
                        raise

                if data is None:
                    data, stmts = self.load_file(dir, fn + source)

                digest = rpydigest

            elif os.path.exists(rpycfn):
                lastfn = rpycfn
                data, stmts = self.load_file(dir, fn + compiled)

                digest = rpycdigest

            elif os.path.exists(rpyfn):
                lastfn = rpyfn
                data, stmts = self.load_file(dir, fn + source)

                digest = rpydigest

            if digest is not None:
                self.backup_list.append((rpyfn, digest))

        if data is None:
            raise Exception("Could not load file %s." % lastfn) # type: ignore

        # Check the key.
        if self.key is None:
            self.key = data['key']
        elif self.key != data['key']:
            raise Exception(fn + " does not share a key with at least one .rpyc file. To fix, delete all .rpyc files, or rerun Ren'Py with the --lock option.")

        self.finish_load(stmts, initcode, filename=lastfn) # type: ignore

        self.digest.update(digest) # type: ignore
Exemple #26
0
    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
Exemple #27
0
def bootstrap(renpy_base):

    global renpy # W0602

    import renpy.log # @UnusedImport

    # Remove a legacy environment setting.
    if os.environ.get("SDL_VIDEODRIVER", "") == "windib":
        del os.environ["SDL_VIDEODRIVER"]

    if not isinstance(renpy_base, str):
        renpy_base = str(renpy_base, FSENCODING)

    # If environment.txt exists, load it into the os.environ dictionary.
    if os.path.exists(renpy_base + "/environment.txt"):
        evars = { }
        with open(renpy_base + "/environment.txt", "r") as f:
            code = compile(f.read(), renpy_base + "/environment.txt", 'exec')
            exec(code, evars)
        for k, v in evars.items():
            if k not in os.environ:
                os.environ[k] = str(v)

    # Also look for it in an alternate path (the path that contains the
    # .app file.), if on a mac.
    alt_path = os.path.abspath("renpy_base")
    if ".app" in alt_path:
        alt_path = alt_path[:alt_path.find(".app") + 4]

        if os.path.exists(alt_path + "/environment.txt"):
            evars = { }
            with open(alt_path + "/environment.txt", "rb") as f:
                code = compile(f.read(), alt_path + "/environment.txt", 'exec')
                exec(code, evars)
            for k, v in evars.items():
                if k not in os.environ:
                    os.environ[k] = str(v)

    # Get a working name for the game.
    name = os.path.basename(sys.argv[0])

    if name.find(".") != -1:
        name = name[:name.find(".")]

    # Parse the arguments.
    import renpy.arguments
    args = renpy.arguments.bootstrap()

    if args.trace:
        enable_trace(args.trace)

    if args.basedir:
        basedir = os.path.abspath(args.basedir)
        if not isinstance(basedir, str):
            basedir = basedir.decode(FSENCODING)
    else:
        basedir = renpy_base

    if not os.path.exists(basedir):
        sys.stderr.write("Base directory %r does not exist. Giving up.\n" % (basedir,))
        sys.exit(1)

    # Make game/ on Android.
    if renpy.android:
        if not os.path.exists(basedir + "/game"):
            os.mkdir(basedir + "/game", 0o777)

    gamedirs = [ name ]
    game_name = name

    while game_name:
        prefix = game_name[0]
        game_name = game_name[1:]

        if prefix == ' ' or prefix == '_':
            gamedirs.append(game_name)

    gamedirs.extend([ 'game', 'data', 'launcher/game' ])

    for i in gamedirs:

        if i == "renpy":
            continue

        gamedir = basedir + "/" + i
        if os.path.isdir(gamedir):
            break
    else:
        gamedir = basedir

    sys.path.insert(0, basedir)

    if renpy.macintosh:
        # If we're on a mac, install our own os.start.
        os.startfile = mac_start # type: ignore

        # Are we starting from inside a mac app resources directory?
        if basedir.endswith("Contents/Resources/autorun"):
            renpy.macapp = True

    # Check that we have installed pygame properly. This also deals with
    # weird cases on Windows and Linux where we can't import modules. (On
    # windows ";" is a directory separator in PATH, so if it's in a parent
    # directory, we won't get the libraries in the PATH, and hence pygame
    # won't import.)
    try:
        import pygame_sdl2
        if not ("pygame" in sys.modules):
            pygame_sdl2.import_as_pygame()
    except:
        print("""\
Could not import pygame_sdl2. Please ensure that this program has been built
and unpacked properly. Also, make sure that the directories containing
this program do not contain : or ; in their names.

You may be using a system install of python. Please run {0}.sh,
{0}.exe, or {0}.app instead.
""".format(name), file=sys.stderr)

        raise

    # If we're not given a command, show the presplash.
    if args.command == "run" and not renpy.mobile:
        import renpy.display.presplash # @Reimport
        renpy.display.presplash.start(basedir, gamedir)

    # Ditto for the Ren'Py module.
    try:
        import _renpy; _renpy
    except:
        print("""\
Could not import _renpy. Please ensure that this program has been built
and unpacked properly.

You may be using a system install of python. Please run {0}.sh,
{0}.exe, or {0}.app instead.
""".format(name), file=sys.stderr)
        raise

    # Load the rest of Ren'Py.
    import renpy
    renpy.import_all()

    renpy.loader.init_importer()

    exit_status = None

    try:
        while exit_status is None:
            exit_status = 1

            try:
                renpy.game.args = args
                renpy.config.renpy_base = renpy_base
                renpy.config.basedir = basedir
                renpy.config.gamedir = gamedir
                renpy.config.args = [ ] # type: ignore

                if renpy.android:
                    renpy.config.logdir = os.environ['ANDROID_PUBLIC']
                else:
                    renpy.config.logdir = basedir

                if not os.path.exists(renpy.config.logdir):
                    os.makedirs(renpy.config.logdir, 0o777)

                renpy.main.main()

                exit_status = 0

            except KeyboardInterrupt:
                raise

            except renpy.game.UtterRestartException:

                # On an UtterRestart, reload Ren'Py.
                renpy.reload_all()

                exit_status = None

            except renpy.game.QuitException as e:
                exit_status = e.status

                if e.relaunch:
                    if hasattr(sys, "renpy_executable"):
                        subprocess.Popen([sys.renpy_executable] + sys.argv[1:]) # type: ignore
                    else:
                        subprocess.Popen([sys.executable, "-EO"] + sys.argv)

            except renpy.game.ParseErrorException:
                pass

            except Exception as e:
                renpy.error.report_exception(e)
                pass

        sys.exit(exit_status)

    finally:

        if "RENPY_SHUTDOWN_TRACE" in os.environ:
            enable_trace(int(os.environ["RENPY_SHUTDOWN_TRACE"]))

        renpy.display.tts.tts(None)

        renpy.display.im.cache.quit()

        if renpy.display.draw:
            renpy.display.draw.quit()

        renpy.audio.audio.quit()

        # Prevent subprocess from throwing errors while trying to run it's
        # __del__ method during shutdown.
        if not renpy.emscripten:
            subprocess.Popen.__del__ = popen_del # type: ignore
Exemple #28
0
def MultiPersistent(name, save_on_quit=False):

    name = renpy.exports.fsdecode(name)

    if not renpy.game.context().init_phase:
        raise Exception(
            "MultiPersistent objects must be created during the init phase.")

    if renpy.android or renpy.ios:
        # Due to the security policy of mobile devices, we store MultiPersistent
        # in the same place as common persistent.
        # This is better than not working at all.
        files = [renpy.config.savedir]

    elif renpy.windows:
        files = [os.path.expanduser("~/RenPy/Persistent")]

        if 'APPDATA' in os.environ:
            files.append(
                renpy.exports.fsdecode(os.environ['APPDATA']) +
                "/RenPy/persistent")

    elif renpy.macintosh:
        files = [
            os.path.expanduser("~/.renpy/persistent"),
            os.path.expanduser("~/Library/RenPy/persistent")
        ]
    else:
        files = [os.path.expanduser("~/.renpy/persistent")]

    if "RENPY_MULTIPERSISTENT" in os.environ:
        files = [renpy.exports.fsdecode(os.environ["RENPY_MULTIPERSISTENT"])]

    # Make the new persistent directory, why not?
    try:
        os.makedirs(files[-1])  # type: ignore
    except:
        pass

    fn = ""  # prevent a warning from happening.
    data = None

    # Find the first file that actually exists. Otherwise, use the last
    # file.
    for fn in files:
        fn = os.path.join(fn, name)  # type: ignore
        if os.path.isfile(fn):
            try:
                data = open(fn, "rb").read()
                break
            except:
                pass

    rv = _MultiPersistent()

    if data is not None:
        try:
            rv = loads(data)
        except:
            renpy.display.log.write("Loading MultiPersistent at %r:" % fn)
            renpy.display.log.exception()

    rv._filename = fn

    if save_on_quit:
        save_MP_instances.add(rv)

    return rv
Exemple #29
0
def index_archives():
    """
    Loads in the indexes for the archive files. Also updates the lower_map.
    """

    # Index the archives.

    global old_config_archives

    if old_config_archives == renpy.config.archives:
        return

    old_config_archives = renpy.config.archives[:]

    # Update lower_map.
    lower_map.clear()

    cleardirfiles()

    global archives
    archives = [ ]

    max_header_length = 0
    for handler in archive_handlers:
        for header in handler.get_supported_headers():
            header_len = len(header)
            if header_len > max_header_length:
                max_header_length = header_len

    archive_extensions = [ ]
    for handler in archive_handlers:
        for ext in handler.get_supported_extensions():
            if not (ext in archive_extensions):
                archive_extensions.append(ext)

    for prefix in renpy.config.archives:
        for ext in archive_extensions:
            fn = None
            f = None
            try:
                fn = transfn(prefix + ext)
                f = open(fn, "rb")
            except Exception:
                continue
            with f:
                file_header = f.read(max_header_length)
                for handler in archive_handlers:
                    archive_handled = False
                    for header in handler.get_supported_headers():
                        if file_header.startswith(header):
                            f.seek(0, 0)
                            index = handler.read_index(f)
                            archives.append((prefix + ext, index))
                            archive_handled = True
                            break
                    if archive_handled == True:
                        break

    for dir, fn in listdirfiles(): # @ReservedAssignment
        lower_map[unicodedata.normalize('NFC', fn.lower())] = fn

    for fn in remote_files:
        lower_map[unicodedata.normalize('NFC', fn.lower())] = fn
Exemple #30
0
 def open(self):
     self.f = open(self.fn, "rb")
     self.f.seek(self.base)