I just tried the same thing at the console, using RenPy 8.1.3.
This was my result:
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?
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.
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.
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).
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...
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.
...
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.
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.
And yeah... it's completely unintuitive.
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.
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.
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.
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.
Not totally correct, due to a possible ambiguity in what "defining" and "directly" can mean.
Defining variables in a screen is possible, through the
You must be registered to see the links
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
You must be registered to see the links
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.