Create your AI Cum Slut -70% for Mother's Day
x

Ren'Py (SOLVED) Using lens(array) increasing the array... how I can fix it?

megalono

Member
Game Developer
Dec 2, 2020
225
785
Problem was solved !!
Thank you all for the help !!!




I found that every time I use the len(array) it appends the list and with time it gets huge.
I have:
mcInventoryQuantity = [0, 0, 0, 0, 0, 0, 0, 1]

if i use even in console command:
len(mcInventoryQuantity)

the array increments.

Clipboard-1.jpg


I have no idea how to fix it ... or why is doing it.
I really need help because I can't find anything similar in Internet

Thank you in advance
 
Last edited:

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,639
2,306
I just tried the same thing at the console, using RenPy 8.1.3.

This was my result:

1736075208398.png

I repeated the same commands using RenPy 7.4.5 - exactly the same results.

A lot of screen interactions generate a lot of (usually) unexpected executions of code you might only expect to run once (or never).
The fact that you are using len() at all implies that you adding elements to your list.

My guess is that you've got a screen somewhere that is adding to the list, in a way that is being invoked a LOT more than you're expecting. Even with the console open.

I'd suggest making a save. Load that save and repeat your len(mcInventoryQuantity) command every 5 or so seconds for a minute. Note how much the values go up by.
Re-load that same save, but repeat the command once every 30 seconds. (Keep moving the mouse around while you wait).

If the numbers are mostly the same, despite using len() twice rather than 12 times, that points to it being nothing at all to do with the use of len().

At that point, I'd be commenting out any code that adds items to the list. Then rerunning the test, adding each line back in one at a time until you find the culprit.

If it consistently goes up by 8 each time, regardless of how often you use the command - I'd have to guess it is something to do with the constructor of the object/list. Or some other code that is invoked any time you reference the variable at all.

Another option you could use to test. When you open the console, use these two commands, then return to the game:
watch len(mcInventoryList)
watch len(mcInventoryQuantity)

It'll add both to the onscreen watch list. You can see if the value changes, without needing to keep reopening the console.

All of which is speculation - but it's the only thing that comes to mind, without see the whole code.
(sadly a common theme of forum posts is that the author simplifies their code to post it here on the forums, and in the process excludes the actual bug that's causing their problem... I know, I've done it myself).

Edit:
I'm guessing you are responding to this post in your game thread.

I have a question about game inventory system. I am using 0x52 URM so I can take look at game variables and mcInventory have 88200 items in it. A lot of duplicate items. I wonder if it is supposed to have that many items because a lot of dupes and I wonder if it would speed up game if it was not a case.

Given this it's something happening within the released version of the game, I'll download it and see if I can think of something more now I can see the actual code.

Edit2:

I'm not seeing it happening (though I've only played about 5 minutes and haven't seen the inventory yet).
Do you have a save file where the problem is happening?
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
11,785
18,243
My guess is that you've got a screen somewhere that is adding to the list, in a way that is being invoked a LOT more than you're expecting. Even with the console open.
It's exactly that.

The console refresh screens, and the only way I was able to found to replicate his bug was with this:
Python:
default AON = [0, 1, 2, 3, 4]
screen myTest():

    $ AON.append( 1 )
    text "Blablabla"

label start:
    show screen myTest
    "open the console and look at the list size increase."
    pause
    "Open the console again, and look at the list size."
    "END"
Be noted that the bug do not come from the console, nor from len(), but from the code itself.

Even without using the console, the list would grow anyway since screens are predicted more than once before being shown/called, and, when displayed, they are refreshed around 5 times every seconds.
Inline Python code in screens should be handled with extra cautions and in fact avoided as much as possible.
 
  • Like
Reactions: megalono

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,639
2,306
If you haven't figured it out yourself, wrap all .rpy files in a small zip. If I have the time, I might look into it.

It's an already published game:
https://f95zone.to/threads/simple-days-v0-19-1-full-mega-lono.61893/

You'd just need to convert the .rpyc files back to .rpy using something like UnRen.

So far, I've not seen any problems upto day6.
I'm going to guess it's something that kicks in during the openworld segment later on. I'm still digging (though I did get a little distracted by actually playing it).
 
  • Like
Reactions: megalono

megalono

Member
Game Developer
Dec 2, 2020
225
785
Thank you, everyone, for your help.
It is indeed the screen that was used in Chapter 2.

Code:
$ inventTemp = len(mcInventoryList)
if inventTemp < 5:
        $ mcInventoryList.append ("Blue Pill")
        $ mcInventoryList.append ("VIP Pass")
        $ mcInventoryList.append ("BDSM Pass")
        $ mcInventoryList.append ("Phone")
        $ mcInventoryPrice.append (5000)
        $ mcInventoryPrice.append (2000)
        $ mcInventoryPrice.append (10000)
        $ mcInventoryPrice.append (2000)
        $ mcInventoryQuantity.append (0)
        $ mcInventoryQuantity.append (0)
        $ mcInventoryQuantity.append (0)
        $ mcInventoryQuantity.append (1)

However, there is no reason for the effect on the console, and it should only trigger once because $inventTemp should be > 5 afterward.

I simply removed the code, and the "bug" disappeared.

Thank you again for your quick help!
You are all the best of the best !!!!
 

megalono

Member
Game Developer
Dec 2, 2020
225
785
Have fun! Maybe he's promoting the game after all... :ROFLMAO:

The game is impressively big and unfortunately my internet speed is low.
:oops: :D
I didn't mention my game, but someone found it anyway.

I solved the problem, and it is indeed, as others pointed out, related to one screen.
However, it could just be a Ren'Py bug.
Thank you all!
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,639
2,306
You, sir, are very clever. If inventTemp isn't defaulted in renpy, it will treated as a falsy value inside renpy's scope and so...

It's not ideal for every circumstance.
In this case too, inventTemp is a temporary variable within the screen scope. It wouldn't exist outside the screen.

But going back to the inventory, it's messy.
Remember variables changed while the script is running (or using default) are saved to the player's save files.
If the default was changed from 4 items to 8 items, that'd work for new players. But existing players would load their save files, and the values would be loaded from there - overwriting the default values. So a returning player could load their save and only have 4 inventory items, even though the script default has been changed to up it to 8.

mcInventoryList and mcInventoryPrice wouldn't (under normal circumstances) be changed by player actions. Therefore I'd normally recommend those to be initialized using define. To my mind, they are constants, not variables.
NOTE: They can't be changed to define now without renaming them, as their values are saved within player's save files.

mcInventoryQuantity IS something that will change as a result of player actions, therefore something I would expect to use default instead.
This problem being that (if my assumption that the original list was only 4 items is correct) then adding those extra 4 quantities would need to be included somewhere.

(without changing it beyond all recognition)... IF this had been my code, I would have coded it like this...

Python:
define mc_inventory_item = ["Condom", "Gun", "MiniVan Car", "SUV Car"]
define mc_inventory_price = [10, 1500, 50000, 50000]

default mc_inventory_qty = [0, 0, 0, 0]

Then I'd later update it to:

Python:
define mc_inventory_item = ["Condom", "Gun", "MiniVan Car", "SUV Car", "Blue Pill", "VIP Pass", "BDSM Pass", "Phone"]
define mc_inventory_price = [10, 1500, 50000, 50000, 1000, 4000, 10000, 2000]

default mc_inventory_qty = [0, 0, 0, 0, 0, 0, 0 , 1]

label after_load():

    if len(mc_inventory_qty) <= 4:
        $mc_inventory_qty.extend([0, 0, 0, 1])

    return

label start:

    # blah, blah, blah

is invoked after a save game is loaded.
It's generally a good place to "fix" variables from previous releases.
You just have to be VERY careful of what you put in there - as it will continue to be run EVERYTIME a save is loaded. Effectively, you just need to be careful to "fix" things once rather than lots of times.

Realistically, if it were my code it would be a lot different. Probably including dictionaries instead of lists and making use of classes too. Thankfully, I only diagnose other people's games... and don't have plans to write my own.
 
Last edited:

megalono

Member
Game Developer
Dec 2, 2020
225
785
...
If the default was changed from 4 items to 8 items, that'd work for new players. But existing players would load their save files, and the values would be loaded from there - overwriting the default values. So a returning player could load their save and only have 4 inventory items, even though the script default has been changed to up it to 8.


Code:
if 1 > 999:
        $ mcInventoryList.append("Broken iPad")
Clearly 1 is never greater than 999, yet the Broken iPad is still added to the inventory list (repeatedly).
You are absolutely right about everything. I was just looking for a way to prevent old saves from causing errors when users check the inventory screen, but I still can’t figure out why the code executes when "clearly 1 is never greater than 999, yet…."

When the code is outside the screen, there’s no issue with the logic—it would never process something like "if 1 > 999:" However, when it’s used inside screens .... , I still believe it’s a Ren'Py bug.

I’m not very advanced in this area, and eventually, players won’t be using such old save files anymore. For now, simply removing the problematic code works fine.

Thanks to your help, the game is now optimized because I’ve implemented a one-time fix to shrink the hundred of thousands records in the inventory!
This code is used outside the screens and will work as intended.

Code:
if currgamever < 192:
    $mcInventoryList.clear()
    $mcInventoryPrice.clear()
    $ mcInventoryList = ["Condom", "Gun", "MiniVan car", "SUV car", "Blue Pill", "VIP Pass", "BDSM Pass", "Phone"]
    $ mcInventoryPrice = [10, 1500, 50000, 50000, 1000, 4000, 10000, 2000]
    $ EventTemp = mcInventoryQuantity[0]
    $ EventTemp1 = mcInventoryQuantity[1]
    $ EventTemp2 = mcInventoryQuantity[2]
    $ EventTemp3 = mcInventoryQuantity[3]
    $ EventTemp4 = mcInventoryQuantity[4]
    $ EventTemp5 = mcInventoryQuantity[5]
    $ EventTemp6 = mcInventoryQuantity[6]
    $mcInventoryQuantity.clear()
    $ mcInventoryQuantity = [EventTemp, EventTemp1, EventTemp2, EventTemp3, EventTemp4, EventTemp5, EventTemp6, 1]
$ currgamever = 192
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,639
2,306
[...] but I still can’t figure out why the code executes when "clearly 1 is never greater than 999, yet…."

The over-simple answer is that RenPy is expecting screen language statements within screens, not python statements.

So when you do if ..., it's then looking for other screen language code. It finds $ instead, even though they are indented correctly, it ignores them. Except, they are executed independently of where they are in the screen definition during a "screen interaction" (ie all the time, whether you are expecting them or not).

For example:

Python:
screen MyTestScreen():

    if len(mcInventoryList) <=4:
        $ store.mytestvar = True
        text "This is a test"

"This is a test" will only appear when the list is less than 5 items. But the mytestvar variable will be set to True every single time the screen triggers a screen interaction.

The simple answer is to never use $ within screens, because it's hardly ever the right place to do code like that.

It's less a bug, and more a feature. :devilish:
And yeah... it's completely unintuitive.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
11,785
18,243
However, there is no reason for the effect on the console, and it should only trigger once because $inventTemp should be > 5 afterward.
Therefore, welcome to the marvelous world of variables scope, mixed to the way statements are handled and screen refreshed.

Once again there's no bug, just a misunderstanding on how Ren'Py works. And, to be honest, this one is really tricky.
While not 100% natural, such behavior is to expect. But honestly I will not explain it in detail, because it's not as easy as this.

To summarize, if being a statement, it will not be evaluated systematically, while the inline Python will be processed most of the time.
There should be few words regarding this in the doc, but I have a headache and not really the courage to search for it right now.
 
  • Star-struck
Reactions: megalono

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
11,785
18,243
[Redacted due to reasons]

Python statements within if conditions in screens are only executed if the condition evaluates to True. [...]
Will it seem true, and is true most of the time, there's an exception to this.

Ren'Py predict screens, this to ensure that most (if not all) the images possibly used will be loaded in the cache before they are needed. And during this prediction, inline Python and Python blocks will be processed, even is put behind an if statement that isn't, or can't, be True.

You don't have permission to view the spoiler content. Log in or register now.


# Renpy treats undefined variables as falsy (equivalent to 0 in this context).
Python's variables are unmutable. To simplify, this mean that each time you assign a new value to a variable, the variable will be recreated. This have a side effect, variables can not be undefined. Either it have exist, or it don't exist.
And if a variable do not exist, Ren'Py will throw the expected NameError exception.

You don't have permission to view the spoiler content. Log in or register now.


Temporary Python Variables: When you use $ inventTemp = ..., the variable exists only within that Python block unless explicitly saved to Renpy’s scope (through default or define inventTemp = ... somewhere in the Renpy code).
Ren'Py have temporary variables, but unrelated to this.
When used in labels, or init blocks, inline variable assignation will create the variable in the global scope. And when it happen in a label, it will also add it in all save files.

You don't have permission to view the spoiler content. Log in or register now.

As for the temporary variables, they are a bit difficult to use since you need to declare the variable, then use .

You don't have permission to view the spoiler content. Log in or register now.


Avoid defining or changing variables directly in screens to prevent unwanted calculations during frequent re-evaluations.
Not totally correct, due to a possible ambiguity in what "defining" and "directly" can mean.

Defining variables in a screen is possible, through the screen statement.
But by doing this, said variable will only exist in the scope local to this screen and the screen(s) it will possibly use. What is precisely the behavior expected, to protect the variables defined outside of the game, and limits the side effects due to variable use in a screen.

As for changing variables values, it's doing it through inline Python or a Python block that must be avoided.
But there's specially dedicated to this. The value will only change when the related action will be triggered, what, once again, prevent side effects while still offering the possibility to change variables from a screen.
Yet, please, keep in mind that those variable change will not be included in the save file before a new interaction occurred. Therefore, do not base your game, or a portion of your game, on a called screen that will never return, or only return once in a while.
 
Last edited:
  • Like
Reactions: megalono