RevertableList object has no attribute visit_all

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
Geistbas
Regular
Posts: 34
Joined: Mon Jan 25, 2016 4:02 pm
Projects: Flow of Phantasmagory
Deviantart: Geistbas
Skype: geistbas
Location: Czech Republic
Contact:

RevertableList object has no attribute visit_all

#1 Post by Geistbas »

I'm almost there... Only one step to actually finish individual field location drawing in my board game engine.

Here's the deal -- I want my engine to draw four layers of graphics on every field in the dice game environment, so far I successfully managed to make the engine draw two of them, but that was absolutely easy, since those take their render from a single variable.

But, what if I want to take data from a list, and render multiple graphics in a for loop?

I store graphics paths in a list, like this:

Code: Select all

 def bgMapData():
        
        Vbg[0] = "images/bg/dgs1_1.jpg"
        Vbg[1] = "images/bg/dgs1_1b.png"
        Vbg[2] = "images/bg/dgs1_2.jpg"
        Vbg[3] = "images/bg/dgs1_2b.png"
        Vbg[4] = "images/bg/dgs1_3.jpg"
        Vbg[5] = "images/bg/dgs1_3b.png"
        Vbg[6] = "images/bg/dgs1_4.jpg"
        Vbg[7] = "images/bg/dgs1_5.jpg"
        Vbg[8] = "images/bg/dgs1_6.jpg"
        Vbg[9] = "images/bg/dgs1_7.jpg"
        Vbg[10] = "images/bg/dgs1_8.jpg"
        Vbg[11] = "images/bg/dgs1_9.jpg"

        Vlib[0] = "images/bg/component0.png"
        Vlib[1] = "images/bg/component1.png"
Then, I use this to map every field on the game board, layerA = 0 means that layerA of field 0 will use the background from the list Vbg, particularly [0], layerB is above layer A, and it uses [1].

Code: Select all

 def bgFieldData():
        
        diceGameStage[1].fldEnv[0].layerA = 0
        diceGameStage[1].fldEnv[0].layerB = 1
        diceGameStage[1].fldEnv[0].layerC[1].decorIndex = 0
        diceGameStage[1].fldEnv[0].layerC[1].pos = 20, 20
        diceGameStage[1].fldEnv[0].layerC[2].decorIndex = 1
        diceGameStage[1].fldEnv[0].layerC[2].pos = 700, 20
layerC (and also layerD, though not used yet) are supposed to be decorations, the object has the following variables:

Code: Select all

def __init__(self):
            
            self.decorIndex = None
            self.pos = 0, 0
            self.size = 1.0
decorIndex is the number of Vlib image that should be used, size is supposed to work with a Transform, to render a boulder, rock, grass, decorative mushrooms, planks, anything at a size, default being 1.0 - those are decorations - layerC and layerD, to make every field look different, only that layerC is above layerA and layerD is above layerB, like this:

layerA - Background
layerC - Decorations above background
layerB - Overlay
layerD - Decorations above overlay
Screenshot_1.jpg
grass is layerA, trees are layerB, layerC would render its graphics below the trees, while layerD would render above the trees

However clunky this may seem(and my friend told me that Python lists are slower than other ways), I successfuly adopted this method and it works with non-list rendering, here's how the rendering works:

Code: Select all

class drawLocation(renpy.Displayable):
            
            def __init__(self, loc, fld, **kwargs):
                
                super(drawLocation, self).__init__(**kwargs)
                
                self.loc = loc
                self.fld = fld

                self.loc_bg = None
                self.loc_over = None
                
            def render(self, width, height, st, at):
                
                render = renpy.Render(width, height)
                
                if diceGameStage[self.loc].fldEnv[self.fld].layerA != None:
                    bgpath = Vbg[diceGameStage[self.loc].fldEnv[self.fld].layerA]
                else:
                    bgpath = None
                    
                if diceGameStage[self.loc].fldEnv[self.fld].layerB != None:
                    ovpath = Vbg[diceGameStage[self.loc].fldEnv[self.fld].layerB]
                else:
                    ovpath = None
                
                if bgpath != None:
                    self.loc_bg = renpy.displayable(Image(bgpath))
                if ovpath != None:
                    self.loc_over = renpy.displayable(Image(ovpath))
                
                if bgpath != None:
                    bgimg = renpy.render(self.loc_bg, width, height, st, at)
                if ovpath != None:
                    overlay = renpy.render(self.loc_over, width, height, st, at)
                
                if bgpath != None:
                    render.blit(bgimg, (0, 0))
                if ovpath != None:
                    render.blit(overlay, (0, 0))

                
                return render
                
            def visit(self):
                return [ self.loc_bg, self.loc_over ]
I'm sorry, but I deleted my unsuccessful code with layer C and layer D, but the error was 'RevertableList object has no attribute visit_all .... Now, I got this error(other than RevertableList, this is the first time i am getting this one) almost everytime i tried to write a renpy displayable, but I mysteriously solved it by reorganizing the order of the code, but when I tried rendering graphics from a list, using for loops and all, assigning variables through loops, including a list declaration in the __init__ method, it gives me this error, and I fear that I don't know much about renpy.Displayable to be able to make this work.

Thus, I decided to ask about it here. Whether I'll be suggested a different way of rendering a set of graphics as decorations than using lists, I'd be happy to learn. Other than that, any helpful points as to why this error happens would be greatly appreciated, as I don't have an idea what it could mean, and I got it almost everytime when I was beginning to learn how to render displayables.

Thank you for your time.

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

Re: RevertableList object has no attribute visit_all

#2 Post by xela »

What error(s) are you getting (exactly)? Revertible list thing was prolly to weird predicts but you wrote that you got around it by rearranging the code?

You UDD seems ok, simpler is:

Code: Select all

init python:
    class DrawLocation(renpy.Displayable):   
        def __init__(self, loc, fld, **kwargs):
           
            super(drawLocation, self).__init__(**kwargs)
           
            self.loc = loc
            self.fld = fld

            self.loc_bg = None
            self.loc_over = None
           
        def render(self, width, height, st, at):
           
            render = renpy.Render(width, height)
           
            if diceGameStage[self.loc].fldEnv[self.fld].layerA != None:
                render.blit(Image(Vbg[diceGameStage[self.loc].fldEnv[self.fld].layerA]).render(width, height, st, at), (0, 0))
            if diceGameStage[self.loc].fldEnv[self.fld].layerB != None:
                render.blit(Image(diceGameStage[self.loc].fldEnv[self.fld].layerB]).render(width, height, st, at), (0, 0))
            return render
           
        def visit(self):
            return [ self.loc_bg, self.loc_over ]
if you're willing to mess with UDDs but you can just use a Fixed/screen/DD/LiveComposite or almost anything else. Showing images behind one another is by no means difficult and you shouldn't worry about access speed, it'll be lightning fast no matter what you use. You list structure is unreadable (to me), there are too many abbreviation and levels. I'd prolly cooked up a simple class with normal names and access methods, you could prolly get it to build the required graphics in the correct order as well.

I am not sure you even want to predict this btw, since you're resolving the images inside of the render method, I doubt that Ren'Py will predict something other than two None.
Like what we're doing? Support us at:
Image

User avatar
Geistbas
Regular
Posts: 34
Joined: Mon Jan 25, 2016 4:02 pm
Projects: Flow of Phantasmagory
Deviantart: Geistbas
Skype: geistbas
Location: Czech Republic
Contact:

Re: RevertableList object has no attribute visit_all

#3 Post by Geistbas »

Code: Select all

I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/data/script.rpy", line 138, in script
    e "You've created a new Ren'Py game."
AttributeError: 'RevertableList' object has no attribute 'visit_all'

-- Full Traceback ------------------------------------------------------------

Full traceback:
  File "game/data/script.rpy", line 138, in script
    e "You've created a new Ren'Py game."
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\ast.py", line 603, in execute
    renpy.exports.say(who, what, interact=self.interact)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\exports.py", line 1121, in say
    who(what, interact=interact)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\character.py", line 828, in __call__
    self.do_display(who, what, cb_args=self.cb_args, **display_args)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\character.py", line 690, in do_display
    **display_args)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\character.py", line 493, in display_say
    rv = renpy.ui.interact(mouse='say', type=type, roll_forward=roll_forward)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\ui.py", line 277, in interact
    rv = renpy.game.interface.interact(roll_forward=roll_forward, **kwargs)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\core.py", line 2424, in interact
    repeat, rv = self.interact_core(preloads=preloads, **kwargs)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\core.py", line 2684, in interact_core
    root_widget.visit_all(lambda i : i.per_interact())
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\core.py", line 396, in visit_all
    d.visit_all(callback)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\core.py", line 396, in visit_all
    d.visit_all(callback)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\core.py", line 396, in visit_all
    d.visit_all(callback)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\screen.py", line 390, in visit_all
    self.child.visit_all(callback)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\core.py", line 396, in visit_all
    d.visit_all(callback)
  File "C:\Users\Kubs\Desktop\renpy-6.99.8-sdk\renpy\display\core.py", line 396, in visit_all
    d.visit_all(callback)
AttributeError: 'RevertableList' object has no attribute 'visit_all'

Windows-7-6.1.7601-SP1
Ren'Py 6.99.8.959
Cyan Code Mirage 0.0
@xela
I wrote the C and D layers again from scratch, using the way you did, same error, now traceback is above.

Here's the code:

Code: Select all

class drawLocation(renpy.Displayable):
            
            def __init__(self, loc, fld, **kwargs):
                
                super(drawLocation, self).__init__(**kwargs)
                
                self.loc = loc
                self.fld = fld

                self.loc_bg = None
                self.loc_bgd = [None for i in range(0, max_decor)]
                self.loc_over = None
                self.loc_overd = [None for i in range(0, max_decor)]
                
            def render(self, width, height, st, at):
                
                render = renpy.Render(width, height)
                
                
                if diceGameStage[self.loc].fldEnv[self.fld].layerA != None:
                    render.blit(Image(Vbg[diceGameStage[self.loc].fldEnv[self.fld].layerA]).render(width, height, st, at), (0, 0))
                
                for i in range(0, max_decor):
                    
                    if diceGameStage[self.loc].fldEnv[self.fld].layerC[i].decorIndex != None:
                        
                        if diceGameStage[self.loc].fldEnv[self.fld].layerC[i].size != 1.0:
                            t = Transform(child=Image(Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerC[i].decorIndex]), zoom=diceGameStage[self.loc].fldEnv[self.fld].layerC[i].size)
                        else:
                            t = Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerC[i].decorIndex]
                            
                        px, py = diceGameStage[self.loc].fldEnv[self.fld].layerC[i].pos
                        render.blit(t).render(width, height, st, at), (px, py)
                    
                if diceGameStage[self.loc].fldEnv[self.fld].layerB != None:
                    render.blit(Image(Vbg[diceGameStage[self.loc].fldEnv[self.fld].layerB]).render(width, height, st, at), (0, 0))
                        
                for i in range(0, max_decor):
                    
                    if diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex != None:
                        
                        if diceGameStage[self.loc].fldEnv[self.fld].layerD[i].size != 1.0:
                            t = Transform(child=Image(Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex]), zoom=diceGameStage[self.loc].fldEnv[self.fld].layerD[i].size)
                        else:
                            t = Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex]
                            
                        px, py = diceGameStage[self.loc].fldEnv[self.fld].layerD[i].pos
                        render.blit(t).render(width, height, st, at), (px, py)
      
                return render
                
            def visit(self):
                return [ self.loc_bg, self.loc_bgd, self.loc_over, self.loc_overd ]
The shorter way to render A and B worked perfectly though. (had to fix a syntax error but otherwise really nice)

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

Re: RevertableList object has no attribute visit_all

#4 Post by xela »

Code: Select all

self.loc_bgd = [None for i in range(0, max_decor)]
You never posted this in the front post, this is your error (weird prediction I mentioned), try:

Code: Select all

            def visit(self):
                return [ self.loc_bg, self.loc_bgd ] + self.loc_bgd + self.loc_overd
This is not likely to work btw:

Code: Select all

render.blit(t).render(width, height, st, at), (px, py)
recheck the whole code for correct render/blitting order.
Like what we're doing? Support us at:
Image

User avatar
Geistbas
Regular
Posts: 34
Joined: Mon Jan 25, 2016 4:02 pm
Projects: Flow of Phantasmagory
Deviantart: Geistbas
Skype: geistbas
Location: Czech Republic
Contact:

Re: RevertableList object has no attribute visit_all

#5 Post by Geistbas »

EDIT: posted this after your edit.
Doesn't change a thing I fear.... As mentioned, I'd love to learn something new, and quite honestly I don't know a lot about prediction.

I found a thread where someone had a problem with the example in Creator-defined Displayables in the documentation:

viewtopic.php?f=8&t=12086

The solution was to put a renpy.displayable in the __init__ method, is this what you mean, in my case, as weird prediction?

Anyhow, I have about 6 other renpy displayable classes which don't have their child declared in the __init__ this way, which is what I meant by solving it by rearranging the code(the render), but with lists and for loops i don't even know how to rearrange it, and if it would even work.

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

Re: RevertableList object has no attribute visit_all

#6 Post by xela »

I think that the error means that you have a list in the visit method. Can you try commenting out visit method completely and check if it works then? For all of your custom UDD classes.
Like what we're doing? Support us at:
Image

User avatar
Geistbas
Regular
Posts: 34
Joined: Mon Jan 25, 2016 4:02 pm
Projects: Flow of Phantasmagory
Deviantart: Geistbas
Skype: geistbas
Location: Czech Republic
Contact:

Re: RevertableList object has no attribute visit_all

#7 Post by Geistbas »

Code: Select all


While running game code:
  File "game/data/script.rpy", line 138, in script
    e "You've created a new Ren'Py game."
Exception: Unknown drawing type. <Transform at 682af90>

I'm basically thinking if using https://www.renpy.org/doc/html/sprites.html#sprites would be better, since the sprite system has zorder, and with zorder, the various decorations would have specific layers which I could specify, but with UDD I don't know how zorder would be accomplished.

I'm somewhat derailing the topic though.

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

Re: RevertableList object has no attribute visit_all

#8 Post by xela »

New error is prolly this line, you need to render first, then blit.

Code: Select all

render.blit(t).render(width, height, st, at), (px, py)
Zorder is higher than UDDs. In UDD, whatever you blit last will be on top. UDD you use when you require complete control/best performance. You feed zorder to show/hide/screen/layers mechanics, for every displayable that you show.

Edit: And you shouldn't use Sprites, this is not what they were made for and will make your task even more complicated.
Like what we're doing? Support us at:
Image

User avatar
Geistbas
Regular
Posts: 34
Joined: Mon Jan 25, 2016 4:02 pm
Projects: Flow of Phantasmagory
Deviantart: Geistbas
Skype: geistbas
Location: Czech Republic
Contact:

Re: RevertableList object has no attribute visit_all

#9 Post by Geistbas »

The error was actually caused by this line:

Code: Select all

self.loc_overd[i] = Transform(child=Image(Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex]), zoom=diceGameStage[self.loc].fldEnv[self.fld].layerD[i].size)
I had to change it to this:

Code: Select all

renov = [None for i in range(0, max_decor)]
                for i in range(0, max_decor):
                    
                    if diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex != None:
                        self.loc_overd[i] = Transform(child=Image(Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex]), zoom=diceGameStage[self.loc].fldEnv[self.fld].layerD[i].size)
                        renov[i] = renpy.render(self.loc_overd[i], width, height, st, at)
there is also "renbg" above this, the whole code is like this:

Code: Select all

class drawLocation(renpy.Displayable):
            
            def __init__(self, loc, fld, **kwargs):
                
                super(drawLocation, self).__init__(**kwargs)
                
                self.loc = loc
                self.fld = fld

                self.loc_bg = None
                self.loc_bgd = [None for i in range(0, max_decor)]
                self.loc_over = None
                self.loc_overd = [None for i in range(0, max_decor)]
                
            def render(self, width, height, st, at):
                
                render = renpy.Render(width, height)
                
                renbg = [None for i in range(0, max_decor)]
                for i in range(0, max_decor):
                    
                    if diceGameStage[self.loc].fldEnv[self.fld].layerC[i].decorIndex != None:
                        self.loc_bgd[i] = Transform(child=Image(Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerC[i].decorIndex]), zoom=diceGameStage[self.loc].fldEnv[self.fld].layerC[i].size)
                        renbg[i] = renpy.render(self.loc_bgd[i], width, height, st, at)
                
                renov = [None for i in range(0, max_decor)]
                for i in range(0, max_decor):
                    
                    if diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex != None:
                        self.loc_overd[i] = Transform(child=Image(Vlib[diceGameStage[self.loc].fldEnv[self.fld].layerD[i].decorIndex]), zoom=diceGameStage[self.loc].fldEnv[self.fld].layerD[i].size)
                        renov[i] = renpy.render(self.loc_overd[i], width, height, st, at)
                        
                        
                if diceGameStage[self.loc].fldEnv[self.fld].layerA != None:
                    render.blit(Image(Vbg[diceGameStage[self.loc].fldEnv[self.fld].layerA]).render(width, height, st, at), (0, 0))
                    
                for i in range(0, max_decor):
                    if self.loc_bgd[i] != None:
                        px, py = diceGameStage[self.loc].fldEnv[self.fld].layerC[i].pos
                        render.blit(renbg[i], (px, py))
                    
                if diceGameStage[self.loc].fldEnv[self.fld].layerB != None:
                    render.blit(Image(Vbg[diceGameStage[self.loc].fldEnv[self.fld].layerB]).render(width, height, st, at), (0, 0))
                    
                for i in range(0, max_decor):
                    if self.loc_overd[i] != None:
                        px, py = diceGameStage[self.loc].fldEnv[self.fld].layerD[i].pos
                        render.blit(renov[i], (px, py))
      
                return render
Screenshot_2.jpg
It works, thank you xela. I used placeholders since my bushes and wood logs are still not in .png with transparency, that blue crest is on layerC, and the red crest is on layerD, while, as said before, the trees are on layer B, which makes the red crest appear above the tree layer--- It is mapped like this:

Code: Select all

diceGameStage[1].fldEnv[0].layerA = 0
        diceGameStage[1].fldEnv[0].layerB = 1
        diceGameStage[1].fldEnv[0].layerC[1].decorIndex = 0
        diceGameStage[1].fldEnv[0].layerC[1].pos = 20, 20
        
        diceGameStage[1].fldEnv[0].layerD[1].decorIndex = 1
        diceGameStage[1].fldEnv[0].layerD[1].pos = 800, 400
        diceGameStage[1].fldEnv[0].layerD[1].size = 0.7
so the red crest is 70% size. Works nicely.

And you are right, this dice game stage has 41 fields:
Screenshot_3.jpg

Mapping every field of this game board will surely take some time. And that's not the only dice game stage in the whole game.

I just hope the visit method isn't gravely important to something. I am not planning to move the decorations in the game, they are just decorations that never move.

Also I hope I won't run into a similar problem when I begin writing the code for rendering monster sprites in my custom battle system.

So if there isn't any problem with leaving out the visit method, I guess it's case closed?

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

Re: RevertableList object has no attribute visit_all

#10 Post by xela »

Geistbas wrote:Also I hope I won't run into a similar problem when I begin writing the code for rendering monster sprites in my custom battle system.

So if there isn't any problem with leaving out the visit method, I guess it's case closed?
It is used to predict images, which you can do using a function or by making sure you don't add lists to the prediction list (making sure it only contains displayable).
Like what we're doing? Support us at:
Image

User avatar
Geistbas
Regular
Posts: 34
Joined: Mon Jan 25, 2016 4:02 pm
Projects: Flow of Phantasmagory
Deviantart: Geistbas
Skype: geistbas
Location: Czech Republic
Contact:

Re: RevertableList object has no attribute visit_all

#11 Post by Geistbas »

In other words, if there are 40+ fields, and every field is mapped like fldEnv[32], fldEnv[40] etc, and it spans across multiple dice game stages, for example, diceGameStage[4].fldEnv[12].layerD[4] would mean the 4th decoration(layer D), on field no. 12, in dice game stage 4 --- would there be any issues?

The displayable draws the currect actual field the player is on, it's called as a screen:

Code: Select all

python:
        ui.add(drawLocation(player.stageIn, player.fieldOn))
So this screen always supplies the displayable the variables player.stageIn and player.fieldOn, which are two variables which specify in which level the player currently is, and the exact field number the player is on.

Would that cause any problems with prediction? As the graphics change every time the player gets to another field by rolling the dice, because of those two variables.

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

Re: RevertableList object has no attribute visit_all

#12 Post by xela »

It'll be fine, as I've said, you can just predict images using a function before screen is shown if things get slow. You can just use add all the displayable to this screen, UDD doesn't seem very useful here.
Like what we're doing? Support us at:
Image

Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Bing [Bot], Google [Bot]