Problem with Renpy not correctly fetching stored variables?

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
E-l337
Regular
Posts: 49
Joined: Thu Jun 19, 2003 11:58 pm
Location: Internetopia
Contact:

Problem with Renpy not correctly fetching stored variables?

#1 Post by E-l337 » Tue Apr 04, 2017 9:46 pm

I've been working with Qirien over the last few weeks to track down a rather annoying bug in the game I've been developing, and came across some really weird behavior with the modified version of the Dating Sim Engine frameworks that seems to be a bug with Renpy not correctly fetching the right variables under incredibly specific circumstances.

Here is what is going on:

When loading the Day Planner for a specifically-modified day, the Evening and Late Evening acts of the day planner act as though they are the same thing, despite the fact that this does not occur at any other point in the game. Saving/reloading on the Day Planner causes it to work correctly, for some reason, despite the fact that nothing has actually changed.

Because I know how irritating it can be to replicate this (I had a nightmare of a time doing it myself), I've attached a copy of the build I sent to Qirien. Instructions for replicating are as follows:

1. Launch the game
2. Load Save File #5
3. Select choices to get through the entire day (there are no events that play out in the Office, so you can just select this for all of the periods to get through as quickly as possible)
4. Watch as the planner stops working as intended when not calling the Afternoon period.

Now, we have found a workaround for this, though we aren't sure if this is an actual bug, or just something incredibly specific to the way the DSE has been written over time.
Qirien wrote:The action of accessing the variable for the Notify action seems to fix it for the subsequent SetField action.
In the Day_Planner.rpy, on line 100-101, we have the following:

Code: Select all

                                    if enable:
                                        textbutton name action SetField(store, this_period.var, curr_val)
However, changing it to the following appears to fix this issue:

Code: Select all

                                    if enable:
                                        textbutton name action [SetField(store, this_period.var, curr_val)]
Which brings up a whole host of questions, like why this doesn't seem to come up at any other time.

To be absolutely clear: In this instance, without those brackets the code seems to think that setting the Evening act should also set the Late Evening at the same time, and vice versa, despite the fact that they are very different periods - just in this instance. But when reloading the state for any reason (or loading into the screen from a save), it works as intended.

The only time this bug shows up is after transitioning from the previous day.

For the record: I have updated to the latest build (6.99.12.4.2187), but this was also present in (6.99.12.2.2029).

I understand that the current build I have linked may take about 30 seconds or so to reproduce the bug. If this is too involved, I can throw together a new build to see if I can reduce the time, but with the current setup you can easily see what it should do, and what it doesn't do on the next day.

Is this a problem with the DSE code, or is it an issue with Renpy? At this point that's really the only question we'd like answered, I think.

Thanks in advance!

User avatar
PyTom
Ren'Py Creator
Posts: 15454
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: Problem with Renpy not correctly fetching stored variabl

#2 Post by PyTom » Wed Apr 05, 2017 8:18 am

This might be a bug report, and might not - it's hard to say. I'd like a build where the replication is down to a couple of clicks - if this is a bug, then I'll be running the game dozens of times to be able to fix it.

But the main thing is "Watch as the planner stops working as intended when not calling the Afternoon period." I don't really get what you mean by that. Could you give me a description of what's intended, and what's happening, and what you mean by "not calling the Afternoon period"?
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
"Silly and fun things are important." - Elon Musk
Software > Drama • https://www.patreon.com/renpytom

User avatar
qirien
Miko-Class Veteran
Posts: 504
Joined: Thu Jul 31, 2003 10:06 pm
Organization: Metasepia Games
Deviantart: qirien
Github: qirien
itch: qirien
Location: New Mexico, USA
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#3 Post by qirien » Wed Apr 05, 2017 12:10 pm

When one of the Evening buttons is clicked, SetField is run. It is supposed to change the evening event that is selected, but instead it changes the Late Evening event. Clicking on the Late Evening buttons also changes the Late Evening event, so there is no way to change the Evening event.

Doing a rollback/rollfoward or a save/load to come back to the screen makes it work as intended, where you can click on an Evening button to select an Evening event.

Changing the SetField action to be

Code: Select all

 [ Notify(this_period.var), SetField(store, this_period.var, curr_val) ] 
instead of just

Code: Select all

 SetField(store, this_period.var, curr_val) 
also fixes the problem, which makes it seem like a race condition with the store or something like that.

Or perhaps I'm doing something incorrectly in the DSE screen code?
He's using pretty much vanilla DSE; the code in question is here:
https://github.com/renpy/dse/blob/maste ... lanner.rpy

I haven't been able to replicate it with a simpler test case so far, unfortunately.
Finished games:
Image
Image
Image
In progress: Our Personal Space 2: Space to Grow

User avatar
Saltome
Veteran
Posts: 234
Joined: Sun Oct 26, 2014 1:07 pm
Deviantart: saltome
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#4 Post by Saltome » Wed Apr 05, 2017 3:23 pm

Well I've been here for hours, and I can finally say I have something worth sharing. >_>

Just to be clear, the bug is very specific, but recurring. It causes the SetField action to put the value in the wrong variable.
Furthermore, Some actions, like Notify can also cancel out the bug. And it's very easy to recover from the bug. All it takes is refreshing the window. Reloading the project, loading before the dayplanner, reshowing the window, even simply opening the console and closing it.

I still have no idea what the hell makes it manifest under such specific conditions, or what exactly those conditions are.

So I decided to make a custom action, to set the value.

Code: Select all

class CustSetField(Action):
        def __init__(self, field, name, value):
            self.field = field
            self.name = name
            self.value = value
        def __call__(self):
            setattr(self.field, self.name, self.value)
            renpy.restart_interaction()
        def get_selected(self):
            return getattr(self.field, self.name) == self.value
In this state it negates the bug. And here's the interesting part... adding FieldEquality as a class parent for some reason reintroduces the bug.
You should be able to use this in your script. But I don't know what complications this might have, so don't blame me if everything blows up later. ^_^"
Deviant Art: Image

User avatar
PyTom
Ren'Py Creator
Posts: 15454
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: Problem with Renpy not correctly fetching stored variabl

#5 Post by PyTom » Wed Apr 05, 2017 10:10 pm

Question. What type is curr_val? If it's of a special type, does it override equality comparisons? Ren'Py uses those.
Supporting creators since 2004
(When was the last time you backed up your game?)
"Do good work." - Virgil Ivan "Gus" Grissom
"Silly and fun things are important." - Elon Musk
Software > Drama • https://www.patreon.com/renpytom

User avatar
Saltome
Veteran
Posts: 234
Joined: Sun Oct 26, 2014 1:07 pm
Deviantart: saltome
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#6 Post by Saltome » Thu Apr 06, 2017 6:39 am

Hmm, let's see...
It appears to be a unicode string.
I don't think that's the variable to look at though. The value is set properly.
The erroneous variable is the one that indicates the field.
That's

Code: Select all

this_period.var
But that is also an unicode string. At least at a cursory glance, it doesn't appear to be doing anything wrong. Unless for some reason the DSE itself sets the wrong period object, creating a duplication.

I'm digging a little deeper in renpy now.
Expanding my setup to the following.
It appears the problem only manifests if the result of __eq__ is True.
Does this mean renpy is off the hook?

Code: Select all

class CustFieldEquality(object):
        """
        Declares two objects equal if their types are the same, and
        the listed fields are equal.
        """

        # The lists of fields to use.
        equality_fields = [ ]
        identity_fields = [ ]

        def __eq__(self, o):
#            if self is o:
#                return True

#            if _type(self) is not _type(o):
#                return False

#            for k in self.equality_fields:
#                if self.__dict__[k] != o.__dict__[k]:
#                    return False

#            for k in self.identity_fields:
#                if self.__dict__[k] is not o.__dict__[k]:
#                    return False

            return True
            
    @renpy.pure
    class CustSetField(Action, CustFieldEquality):
        """
         :doc: data_action

         Causes the a field on an object to be set to a given value.
         `object` is the object, `field` is a string giving the name of the
         field to set, and `value` is the value to set it to.
         """

        identity_fields = [ "object", "value" ]
        equality_fields = [ "value" ]

        def __init__(self, object, field, value):
            self.object = object
            self.field = field
            self.value = value

        def __call__(self):
            setattr(self.object, self.field, self.value)
            renpy.restart_interaction()

        def get_selected(self):
            return getattr(self.object, self.field) == self.value
I'm having a hard time determining where __eq__ gets called in this circumstance.
Either way I'm getting the feeling something isn't updating variables properly. As soon as I try to print them out with the hovered notify action the bug miraculously disappears.
Deviant Art: Image

User avatar
E-l337
Regular
Posts: 49
Joined: Thu Jun 19, 2003 11:58 pm
Location: Internetopia
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#7 Post by E-l337 » Thu Apr 06, 2017 10:35 am

I've been playing around with trying to get this narrowed down even further by bypassing all of the events that occur on Day 13. Hopefully this will be of help to you.

This build bypasses all of the day events.

I've gotten this down to as far as I can get it I think, but now we're within 15 clicks of reproducing the bug at least. Disabled all transitions to make this as fast as possible too.

Instructions as follows:

- Boot game, load Save #5
- Select any of the locations for each Day Planner slot
- After clicking Done Planning, it will bypass the rest of the day and immediately go to the next day
- Once the Day Planner comes back up again, attempt to select options for each slot

Now, what's really interesting is that the first time I tried this, it didn't break as expected! I was actually able to select options in the Evening slot that weren't mirrored - only the Laboratory and Office options caused the mirroring to occur. This had the added effect of being able to have two Evening locations highlighted at the same time. Unfortunately, I haven't been able to reproduce that - once I loaded the game fresh again, it was broken in the normal manner. Oh well.

At least this should cut down on the amount of clicking you need to do.

Being that I can't be exactly sure what's causing this interaction, I am uncertain if I can really narrow this down any further.

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#8 Post by xela » Thu Apr 06, 2017 1:32 pm

There is a missing identity field in:
Saltome wrote: identity_fields = [ "object", "value" ]
this should be:

Code: Select all

identity_fields = [ "object", "field", "value" ]
Otherwise Ren'Py is pulling screen action from previous day, causing the bug. Because field is unchecked for equality, Ren'Py chooses to use previously created screen action (prolly created on previous day in the game and "cached" somehow internally). I suppose that "cache" is cleared when we open console or use rollback/load a savegame. In either case this seem to fixed by adding the last identity field for good.

*It could be something complete different... but I managed to crash this code:

Code: Select all

call screen day_planner(["Evening", "Evening", "Evening"])
with:

Code: Select all

    @renpy.pure
    class SetField(Action, FieldEquality):
        """
         :doc: data_action

         Causes the a field on an object to be set to a given value.
         `object` is the object, `field` is a string giving the name of the
         field to set, and `value` is the value to set it to.
         """

        identity_fields = [ "object", "value" ]
        equality_fields = [ "value" ]

        def __init__(self, object, field, value):
            if getattr(renpy.store, "day", None) == 14:
                if field == "late_act":
                    raise Exception("WTF?")
            self.object = object
            self.field = field
            self.value = value

        def __call__(self):
            if getattr(renpy.store, "day", None) == 14:
                if self.field == "late_act":
                    raise Exception("WTF? X2")
            setattr(self.object, self.field, self.value)
            renpy.restart_interaction()

        def get_selected(self):
            return getattr(self.object, self.field) == self.value
with exception being "WTF? X2" which leads me to believe that action is not created on day 14. Under the circumstances, it seems impossible that action comes from this screen. Watching the variables, dict holding the data is accessed correctly, however clicking the middle button still sets store.late_act (which is the single weirdest thing I've seen in Ren'Py so far) :D
Like what we're doing? Support us at:
Image

User avatar
Saltome
Veteran
Posts: 234
Joined: Sun Oct 26, 2014 1:07 pm
Deviantart: saltome
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#9 Post by Saltome » Thu Apr 06, 2017 1:47 pm

Hmm, that did cross my mind. shoulda tried it.
I wonder why it was missing in the first place, though.
And why does the bug occur so rarely.

I verified it too.
E, you guys can fix it yourselves by changing \renpy-6.99.12-sdk\renpy\common\00action_data.rpy
line 37
Keep in mind that changes in the core files don't take effect until you close the game and restart it.
Deviant Art: Image

User avatar
xela
Lemma-Class Veteran
Posts: 2481
Joined: Sun Sep 18, 2011 10:13 am
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#10 Post by xela » Thu Apr 06, 2017 2:00 pm

PyTom suggests that more accurate is:

Code: Select all

identity_fields = [ "object" ]
equality_fields = [ "field", "value" ]
Saltome wrote:And why does the bug occur so rarely.
It's a rare code setup... now that the issue is understood I managed to get just some buttons from one column to change variable from another :D Similar to what happened to `E-l337`. It's a really, really weird error.
Like what we're doing? Support us at:
Image

User avatar
qirien
Miko-Class Veteran
Posts: 504
Joined: Thu Jul 31, 2003 10:06 pm
Organization: Metasepia Games
Deviantart: qirien
Github: qirien
itch: qirien
Location: New Mexico, USA
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#11 Post by qirien » Fri Apr 07, 2017 3:57 pm

Wow, thanks for looking into this! That's really helpful.
Finished games:
Image
Image
Image
In progress: Our Personal Space 2: Space to Grow

User avatar
E-l337
Regular
Posts: 49
Joined: Thu Jun 19, 2003 11:58 pm
Location: Internetopia
Contact:

Re: Problem with Renpy not correctly fetching stored variabl

#12 Post by E-l337 » Sun Apr 09, 2017 7:08 pm

Saltome wrote: E, you guys can fix it yourselves by changing \renpy-6.99.12-sdk\renpy\common\00action_data.rpy
line 37
xela wrote:PyTom suggests that more accurate is:

Code: Select all

identity_fields = [ "object" ]
equality_fields = [ "field", "value" ]
I made the proposed changes, and now it works! Thanks so much to everyone for helping us chase this down - I know in my case it was driving me crazy for at least a month. You're all amazing.

Post Reply

Who is online

Users browsing this forum: Google [Bot]