Error with saving/loading.

Discuss how to use the Ren'Py engine to create visual novels and story-based games. New releases are announced in this section.
Forum rules
This is the right place for Ren'Py help. Please ask one question per thread, use a descriptive subject like 'NotFound error in option.rpy' , and include all the relevant information - especially any relevant code and traceback messages. Use the code tag to format scripts.
Post Reply
Message
Author
User avatar
wakagana
Veteran
Posts: 374
Joined: Mon May 14, 2012 1:27 am
Projects: Flash Q
Organization: Team Bread
Contact:

Error with saving/loading.

#1 Post by wakagana »

Heyo.

So, I'm in the process of programming and for some reason after a series of force-reloading the game, I've found the game no longer loads or saves correctly.

Here's an image of the error itself, and below that is the code in bulk. If anyone can figure out the issue and give me a fix - I'll be happy to give them a buck or two on paypal. This is beyond my level of skill >.<

It seems as thought my load/save files are corrupted - I can save new save files and load them, but not previous ones from a few days ago.

http://i.imgur.com/mn2zyJW.png

Code: Select all

# Copyright 2004-2015 Tom Rothamel <pytom@bishoujo.us>
#
# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

init -1500 python:


    ##########################################################################
    # File functions

    config.linear_saves_page_size = None
    config.quicksave_slots = 10

    # The number of file pages per
    config.file_pages_per_folder = 100

    if persistent._file_page is None:
        persistent._file_page = "1"

    if persistent._file_folder is None:
        persistent._file_folder = 0

    def __slotname(name, page=None):

        if page is None:
            page = persistent._file_page

        try:
            page = int(page)
            page = page + persistent._file_folder * config.file_pages_per_folder
        except ValueError:
            pass

        if config.linear_saves_page_size is not None:
            try:
                page = int(page)
                name = int(name)
                return str((page - 1) * config.linear_saves_page_size + name)
            except ValueError:
                pass

        return str(page) + "-" + str(name)

    def __newest_slot():
        """
        Returns the name of the newest slot.
        """

        return renpy.newest_slot(r'\d+')

    def __unused_slot_name(page):
        """
        Returns an unused name of a slot on the current page. (This will
        likely be a very big number, as it's based on the current unix time.)
        """

        import time

        rv = int(time.time())

        while True:
            if not renpy.can_load(__slotname(str(rv), page)):
                return str(rv)

            rv += 1

    def FileCurrentPage():
        """
        :doc: file_action_function

        Returns the current file page as a string.
        """

        return str(persistent._file_page)

    def FileUsedSlots(page=None, highest_first=True):
        """
        :doc: file_action_function

        Returns a list of used numeric file slots on the page.

        `page`
            The name of the page that will be scanned. If None, the current page
            is used.

        `highest_first`
            If true, the highest-numbered file slot is listed first.
            Otherwise, the lowest-numbered slot is listed first.
        """

        regexp = __slotname(r'\d+', page)

        rv = [ ]

        for fn in renpy.list_slots(regexp=regexp):
            _page, _, slot = fn.partition('-')

            rv.append(int(slot))

        rv.sort()
        if highest_first:
            rv.reverse()

        return rv

    def FileLoadable(name, page=None):
        """
         :doc: file_action_function

         This is a function that returns true
         if the file is loadable, and false otherwise.
         """

        return renpy.can_load(__slotname(name, page))

    def FileScreenshot(name, empty=None, page=None):
        """
         :doc: file_action_function

         Returns the screenshot associated with the given file. If the
         file is not loadable, then `empty` is returned, unless it's None,
         in which case, a Null displayable is created.

         The return value is a displayable.
         """

        screenshot = renpy.slot_screenshot(__slotname(name, page))

        if screenshot is not None:
            return screenshot

        if empty is not None:
            return empty
        else:
            return Null(config.thumbnail_width, config.thumbnail_height)


    def FileTime(name, format=_("%b %d, %H:%M"), empty="", page=None):
        """
         :doc: file_action_function

         Returns the time the file was saved, formatted according
         to the supplied `format`. If the file is not found, `empty` is
         returned.

         The return value is a string.
         """

        mtime = renpy.slot_mtime(__slotname(name, page))

        if mtime is None:
            return empty

        import time

        format = renpy.translation.translate_string(format)
        return time.strftime(format.encode("utf-8"), time.localtime(mtime)).decode("utf-8")

    def FileJson(name, key=None, empty=None, missing=None, page=None):
        """
        :doc: file_action_function

        Accesses the Json information associated with `name`.

        If `key` is None, returns the entire Json other object, or `empty` if the slot
        is empty.

        Otherwise, this returns json[key] if `key` is defined on the json object of the save,
        `missing` if there is a save with the given name, but it does not contain `key`, or
        `empty` if the save slot is empty.

        Json is added to a save slot by callbacks registered using :var:`config.save_json_callbacks`.
        """

        json = renpy.slot_json(__slotname(name, page))

        if json is None:
            return empty

        if key is None:
            return json

        return json.get(key, missing)


    def FileSaveName(name, empty="", page=None):
        """
         :doc: file_action_function

         Return the save_name that was in effect when the file was saved,
         or `empty` if the file does not exist.
         """

        return FileJson(name, "_save_name", empty=empty, missing=empty, page=page)

    def FileNewest(name, page=None):
        """
        :doc: file_action_function

        Returns True if this is the newest file slot, or False otherwise.
        """

        return __newest_slot() == __slotname(name, page)

    class FileSave(Action, DictEquality):
        """
         :doc: file_action

         Saves the file.

         The button with this slot is selected if it's marked as the
         newest save file.

         `name`
             The name of the slot to save to. If None, an unused slot
             (a large number based on the current time) will be used.

         `confirm`
             If true, then we will prompt before overwriting a file.

         `newest`
             Ignored.

         `page`
             The name of the page that the slot is on. If None, the current
             page is used.

         `cycle`
             If true, then saves on the supplied page will be cycled before
             being shown to the user. :var:`config.quicksave_slots` slots are
             used in the cycle.
         """

        alt = "Save slot [text]"

        def __init__(self, name, confirm=True, newest=True, page=None, cycle=False):
            if name is None:
                name = __unused_slot_name(page)

            self.name = name
            self.confirm = confirm
            self.page = page
            self.cycle = cycle

        def __call__(self):

            if not self.get_sensitive():
                return

            fn = __slotname(self.name, self.page)

            if renpy.scan_saved_game(fn):
                if self.confirm:
                    layout.yesno_screen(layout.OVERWRITE_SAVE, FileSave(self.name, False, False, self.page, cycle=self.cycle))
                    return

            if self.cycle:
                renpy.renpy.loadsave.cycle_saves(self.page + "-", config.quicksave_slots)

            renpy.save(fn, extra_info=save_name)

            renpy.restart_interaction()

        def get_sensitive(self):
            if _in_replay:
                return False
            elif main_menu:
                return False
            elif (self.page or persistent._file_page) == "auto":
                return False
            else:
                return True

        def get_selected(self):
            if not self.confirm:
                return False

            return __newest_slot() == __slotname(self.name, self.page)

    class FileLoad(Action, DictEquality):
        """
         :doc: file_action

         Loads the file.

         `name`
             The name of the slot to load from. If None, an unused slot
             the file will not be loadable.

         `confirm`
             If true and not at the main menu, prompt for confirmation before loading the file.

         `page`
             The page that the file will be loaded from. If None, the
             current page is used.

         `newest`
             If true, the button is selected if this is the newest file.

         `cycle`
             Ignored.
         """

        alt = "Load slot [text]"

        def __init__(self, name, confirm=True, page=None, newest=True):

            if name is None:
                name = __unused_slot_name(page)

            self.name = name
            self.confirm = confirm
            self.page = page
            self.newest = newest

        def __call__(self):

            if not self.get_sensitive():
                return

            fn = __slotname(self.name, self.page)

            if not main_menu:
                if self.confirm:
                    if config.autosave_on_quit and not fn.startswith("auto-"):
                        renpy.loadsave.force_autosave()
                    layout.yesno_screen(layout.LOADING, FileLoad(self.name, False, self.page))
                    return

            renpy.load(fn)

        def get_sensitive(self):
            if _in_replay:
                return False

            return renpy.can_load(__slotname(self.name, self.page))

        def get_selected(self):
            if not self.confirm or not self.newest:
                return False

            return __newest_slot() == __slotname(self.name, self.page)

    @renpy.pure
    class FileDelete(Action, DictEquality):
        """
         :doc: file_action

         Deletes the file.

         `confirm`
             If true, prompts before deleting a file.
         """

        alt = "Delete slot [text]"

        def __init__(self, name, confirm=True, page=None):
            self.name = name
            self.confirm = confirm
            self.page = page

        def __call__(self):

            if not self.get_sensitive():
                return

            fn = __slotname(self.name, self.page)

            if self.confirm:
                layout.yesno_screen(layout.DELETE_SAVE, FileDelete(self.name, False, self.page))
                return

            renpy.unlink_save(fn)

        def get_sensitive(self):
            return renpy.can_load(__slotname(self.name, self.page))

        def get_selected(self):
            return __newest_slot() == __slotname(self.name, self.page)


    def FileAction(name, page=None, **kwargs):
        """
         :doc: file_action

         "Does the right thing" with the file. This means loading it if the
         load screen is showing (current screen is named "load"), and saving
         otherwise.

         `name`
             The name of the slot to save to or load from. If None, an unused slot
             (a large number based on the current time) will be used.

         `page`
             The page that the file will be saved to or loaded from. If None, the
             current page is used.

         Other keyword arguments are passed to FileLoad or FileSave.
         """

        if renpy.current_screen().screen_name[0] == "load":
            return FileLoad(name, page=page, **kwargs)
        else:
            return FileSave(name, page=page, **kwargs)

    @renpy.pure
    class FilePage(Action, DictEquality):
        """
         :doc: file_action

         Sets the file page to `page`, which should be one of "auto", "quick",
         or an integer.
         """

        def __init__(self, page):
            self.page = str(page)
            self.alt = "File page [text]"

        def __call__(self):
            if not self.get_sensitive():
                return

            persistent._file_page = self.page
            renpy.restart_interaction()

        def get_selected(self):
            return self.page == persistent._file_page

    def FilePageName(auto="a", quick="q"):
        """
         :doc: file_action_function

         Returns the name of the current file page, as a string. If a normal
         page, this returns the page number. Otherwise, it returns
         `auto` or `quick`.
         """

        page = persistent._file_page

        if page == "quick":
            return quick
        elif page == "auto":
            return auto
        else:
            return page

    def FileSlotName(slot, slots_per_page, auto="a", quick="q", format="%s%d"):
        """
         :doc: file_action_function

         Returns the name of the numbered slot. This assumes that slots on
         normal pages are numbered in a linear order starting with 1, and
         that page numbers start with 1. When slot is 2, and slots_per_page
         is 10, and the other variables are the defaults:

         * When the first page is showing, this returns "2".
         * When the second page is showing, this returns "12".
         * When the auto page is showing, this returns "a2".
         * When the quicksave page is showing, this returns "q2".

         `slot`
             The number of the slot to access.

         `slots_per_page`
             The number of slots per page.

         `auto`
             A prefix to use for the auto page.

         `quick`
             A prefix to use for the quick page.

         `format`
             The formatting code to use. This is given two arguments: A string
             giving the page prefix, and an integer giving the slot number.
         """

        page = persistent._file_page

        if page == "quick":
            prefix = quick
            page = 0
        elif page == "auto":
            prefix = auto
            page = 0
        else:
            prefix = ""
            page = int(page) - 1

        return format % (prefix, page * slots_per_page + slot)


    class FilePageNext(Action, DictEquality):
        """
         :doc: file_action

         Goes to the next file page.

         `max`
             If set, this should be an integer that gives the number of
             the maximum file page we can go to.

         `wrap`
             If true, we can go to the first page when on the last file page if max is set.
         """

        alt = "Next file page"

        def __init__(self, max=None, wrap=False):

            page = persistent._file_page

            if page == "auto":
                if config.has_quicksave:
                    page = "quick"
                else:
                    page = "1"

            elif page == "quick":
                page = "1"

            else:
                page = int(page) + 1

                if max is not None:
                    if page > max:
                        if wrap:
                            if config.has_autosave:
                                page = "auto"
                            elif config.has_quicksave:
                                page = "quick"
                            else:
                                page = "1"
                        else:
                            page = None

                if page is not None:
                    page = str(page)

            self.page = page

        def __call__(self):
            if not self.get_sensitive():
                return

            persistent._file_page = self.page
            renpy.restart_interaction()

        def get_sensitive(self):
            return self.page is not None


    class FilePagePrevious(Action, DictEquality):
        """
         :doc: file_action

         Goes to the previous file page, if possible.

         `max`
             If set, this should be an integer that gives the number of
             the maximum file page we can go to. This is required to enable
             wrap.

         `wrap`
             If true, we can go to the last page when on the first file page if max is set.
         """

        alt = "Previous file page"

        def __init__(self, max=None, wrap=False):

            if wrap and max is not None:
                max = str(max)
            else:
                max = None


            page = persistent._file_page

            if page == "auto":
                page = max

            elif page == "quick":
                if config.has_autosave:
                    page = "auto"
                else:
                    page = max

            elif page == "1":
                if config.has_quicksave:
                    page = "quick"
                elif config.has_autosave:
                    page = "auto"
                else:
                    page = max

            else:
                page = str(int(page) - 1)

            self.page = page

        def __call__(self):
            if not self.get_sensitive():
                return

            persistent._file_page = self.page
            renpy.restart_interaction()

        def get_sensitive(self):
            return self.page

    @renpy.pure
    class FileTakeScreenshot(Action, DictEquality):
        """
         :doc: file_action

         Take a screenshot to be used when the game is saved. This can
         be used to ensure that the screenshot is accurate, by taking
         a picture of the screen before a file save screen is shown.
         """

        def __call__(self):
            renpy.take_screenshot()

    @renpy.pure
    def QuickSave(message=_("Quick save complete."), newest=False):
        """
        :doc: file_action

        Performs a quick save.

        `message`
            A message to display to the user when the quick save finishes.

        `newest`
            Set to true to mark the quicksave as the newest save.
         """

        rv = [
            FileSave(1, page="quick", confirm=False, cycle=True, newest=newest),
            Notify(message),
            ]

        rv[0].alt = "Quick save."

        if not getattr(renpy.context(), "_menu", False):
            rv.insert(0, FileTakeScreenshot())

        return rv

    @renpy.pure
    def QuickLoad(confirm=True):
        """
        :doc: file_action
        
        Performs a quick load.
        
        `confirm`
            If true and not at the main menu, prompt for confirmation before loading the file.
        """

        rv = FileLoad(1, page="quick", confirm=confirm, newest=False)
        rv.alt = "Quick load."
        return rv

init 1050 python hide:

    if not config.has_quicksave and persistent._file_page == "quick":
        persistent._file_page = "1"

    if not config.has_autosave and persistent._file_page == "auto":
        persistent._file_page = "1"

User avatar
PyTom
Ren'Py Creator
Posts: 16096
Joined: Mon Feb 02, 2004 10:58 am
Completed: Moonlight Walks
Projects: Ren'Py
IRC Nick: renpytom
Github: renpytom
itch: renpytom
Location: Kings Park, NY
Contact:

Re: Error with saving/loading.

#2 Post by PyTom »

Do you still have your old .rpyc files around? It looks like, for whatever reason, they might have gone away, causing this problem. If you can find the old .rpyc files and drop them over the new ones, Ren'Py _might_ be able to resolve things. On the other hand, if you changed the files too drastically, it might not. Loading saves into a modified game is an inherently hard problem.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
Software > Drama • https://www.patreon.com/renpytom

User avatar
wakagana
Veteran
Posts: 374
Joined: Mon May 14, 2012 1:27 am
Projects: Flash Q
Organization: Team Bread
Contact:

Re: Error with saving/loading.

#3 Post by wakagana »

I ended up saving over each of the files with new saves and the save/load function works perfectly fine now, but I'm more so confused as to what could have happened to the files to begin with.

Is there any big issue that might have caused them to disappear, IE reloading the game, adding in images/files into the game folders, or is it more so just on my end with my computer deleting files randomly?

Either way, thanks for the help, Tom!

Post Reply

Who is online

Users browsing this forum: No registered users