Problem "after finishing" a project

xWhiteNinjax

Member
Jun 9, 2017
173
49
After finishing a project, there will be images inside the "\game\images"-directory (and the subdirs, too), not touched by any written scripts. Especially, if there are thousands of images after a long time of coding.

The developer menu will show a list of all images inside the mentioned directories ... but is it possible to receive a list of "not used" images inside the created scripts? I don't know, if ren'py itself is possible to delete such images or if it is possible to create a tool for "atom" to do this... If anyone has a solution, please help out (documents, existing tools or other means).
Thank you in advance.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,407
15,312
After finishing a project, there will be images inside the "\game\images"-directory (and the subdirs, too), not touched by any written scripts.
Why ?

No, seriously, why would there be something in the "images" directory that isn't used ?
Don't you have a working space, separated to the project or, at least, not in the "game" directory, where you proceed your images ? Don't you delete, or at least move on a dedicated directory, an image that you replaced by another ?


If anyone has a solution, please help out (documents, existing tools or other means).
Not being messy ? It's a solution that works 99% of the time.

While coding can be entertaining and really enjoyable, it still need to be rigorous. And this starts by having a bit of organization when it come to your project.
 
  • Like
Reactions: The Rogue Trader

apologetik

Newbie
Apr 7, 2022
24
16
If you're facing this issue, it's probably best to just script something to a) list all files and b) search scripts for used images. Diff that.

My use is probably wrong - working on my first game - so I end up with two lines of code for showing an image:

Python:
image i_name = im.Scale('images/blahblah.webp', 1920, 1080)
scene i_name
Using a regexp like im\.Scale\('([^']+)' gets me all of the lines using images, and cross-referencing that with the file list lets me know if anything is unused.
 

TDoddery

Member
Apr 28, 2020
170
160
Why ?

No, seriously, why would there be something in the "images" directory that isn't used ?
Don't you have a working space, separated to the project or, at least, not in the "game" directory, where you proceed your images ? Don't you delete, or at least move on a dedicated directory, an image that you replaced by another ?




Not being messy ? It's a solution that works 99% of the time.

While coding can be entertaining and really enjoyable, it still need to be rigorous. And this starts by having a bit of organization when it come to your project.

Yeah it shouldn't happen but it does - lol

In case it helps, and of course everyone might deal with things in a different way, for me the main challenge is how to catch redundant images "on the fly" without too much interruption to work flow (more specifically brain-flow), because leaving it for a clean up later very often means something gets forgotten. That also includes not throwing out an image and then later realizing you still need it, or you want it back again, and then being all "where the fuck did that go?"

I used to create a folder within each of my image directories called "obs" (standing for "obselete"), and when I thought I had an image that was not going to be used I could quickly just drag it into there and then remove that folder at the end. Plenty of times I would need to pull images out again further down the code road, but at least I knew exactly where to find them.

However, since Ren'py looks in every folder under the top images directory, that system was not foolproof because Ren'py could still be using images which I had consigned to my "obs" folder, and I might not be aware unless I checked every possible route after removing the "obs" folder.

So these days, when an image appears to me to be surplus to requirements, I just quickly prefix the image file name with "obs" and leave it where it is. Obviously I also never use "obs" for any image in the code. Then at the end, or whenever I feel like it, I just list the folder contents by name and remove all of the "obs" images in one hit.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,407
15,312
Python:
image i_name = im.Scale('images/blahblah.webp', 1920, 1080)
scene i_name
Do you really need to resize your images in-game ?

It's not too heavy for the system, but the image will be resized each time it will be loaded. Since it happen during the prediction phase, it will also be relatively insensible for the player.

But in the same time it triple the size needed by the core to identify the image:
  • The image object by Ren'Py ;
  • The Scale object ;
  • The image object declared internally by the Scale object.
Once again, it's not something dramatic, but at the end of your project, when you'll have thousands of images declared, it will starts to be a bit heavy for the core.

And of course there's the size issue.
Downloading a 1GB archive to discover in the end that half the size would have suffice, because each image is downsized, is probably not something pleasant. Especially in the US where you've a monthly bandwidth usage limit.


Using a regexp like im\.Scale\('([^']+)' gets me all of the lines using images, and cross-referencing that with the file list lets me know if anything is unused.
No, it will tell you if an image is not declared, but not that the declared image will not be used.


Yeah it shouldn't happen but it does - lol
One image time to time perhaps, but so far I've seen way more forgotten images, than none used one.


However, since Ren'py looks in every folder under the top images directory, that system was not foolproof because Ren'py could still be using images which I had consigned to my "obs" folder, and I might not be aware unless I checked every possible route after removing the "obs" folder.
Then, just pick the one you prefer:
  1. Put it outside of the project directory ;
  2. Put it outside of the "game" directory, and use built.classify( "obs/**", None ) to exclude this directory from the build ;
  3. Keep it in the "images" directory, and use built.classify( "game/images/obs/**", None ) to exclude this directory from the build.

More people should read the page, there's too much trash in the archives ; including the configuration files for the text editor they use to write the scripts.
Among the things I've found that shouldn't have been there, and even less public, there's the personal notes of the author, giving the big lines for the three following updates, the draft of what seemed to be an insult email to a member of the team, and a two columns list of series of characters that seemed really close to a login/password list.


Then at the end, or whenever I feel like it, I just list the folder contents by name and remove all of the "obs" images in one hit.
Or you keep them and use built.classify( "obs_**.**", None ).
/!\ Not totally sure that Ren'Py would like the jokerized extension. /!\
 

coffeeaddicted

Well-Known Member
Apr 13, 2021
1,765
1,433
This is interesting.
Though i strictly separate what goes into the image folder or any other folder in the project itself.
I think there shouldn't be anything personal or unused since it will be packed and make the archive artificially bigger.

Configurations files are outside. But i think you probably have to use an external editor. I use Visual Studio but as external and not installed with RenPy.
I like it clean.

Though the build settings are a thing i should check myself. Very useful.
 

apologetik

Newbie
Apr 7, 2022
24
16
Do you really need to resize your images in-game ?
It's not too heavy for the system, but the image will be resized each time it will be loaded. Since it happen during the prediction phase, it will also be relatively insensible for the player.

But in the same time it triple the size needed by the core to identify the image:
  • The image object automatically declared by Ren'Py ;
  • The Scale object ;
  • The image object declared internally by the Scale object.
Once again, it's not something dramatic, but at the end of your project, when you'll have thousands of images declared, it will starts to be a bit heavy for the core.

And of course there's the size issue.
Downloading a 1GB archive to discover in the end that half the size would have suffice, because each image is downsized, is probably not something pleasant. Especially in the US where you've a monthly bandwidth usage limit.
Nah, not anymore. I run cwebp on the original hi-res and scale it down to 1920x1080, this is just an artifact of that - so it's not doing any resize, I've just been focused elsewhere than the lua->renpy script library. Size isn't an issue at the moment, and how I'm building things allows for content updates to be shipped incrementally rather than "just download 5gb again".

At any rate, I appreciate the tips on this, I will make some time to update things and get rid of the image/scale.

No, it will tell you if an image is not declared, but not that the declared image will not be used.
I understand where you're going with this - perhaps a scene is skipped. There's a tool called renpy-graphviz ( ) that could probably be used or forked to find unused labels (and thus any scenes underneath, unused).
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,407
15,312
There's a tool called renpy-graphviz ( ) that could probably be used or forked to find unused labels (and thus any scenes underneath, unused).
This tool is purely useless outside of really basic visual novels. It don't detect the branching coming from a screen, nor the ones built in real time by expressions, even when they are basic.

This said, basically speaking, what you need is to know what images are effectively used.
As long as you stay on the basis, a simple text parser to get the scene .* and show [^screen] .* would already give you a list to diff with the file names.
Images used in screens would still be missing, and more difficult to catch.
For add it would be easy. But it would starts to be tricky with imagebutton that can use either some of the state attributes or auto. But while the last one is a built expression, you can build it from the parsed.
But it starts to be more complicate since image can also be defined through the styles, whatever inline in the screen, or through the style definition.

And of course, all this would just catch basic use. Once you starts using expressions (scene expression "images/girls/{}/iddle_{}.jpg".format( actualGirls.name, actualGirls.clothes )) it become really tricky and you need to manually provide the possible values to the diff script for it to not flag as not used images that are in fact used.

Even relying on Ren'Py itself wouldn't be enough. , or more precisely on the set it use internally, can tell you what image have been seen. But for it to be reliable, you need to have play the whole game and followed all the possible path.


In the end, the only solution is still to plan correctly your game and to be consistent in your development. You write the draft code for the scene, and move the images from their temporary location only when it's done. You'll know exactly which ones are used, and are to move. Then when you'll polish the scene, you import/remove each image in parallel to your changes.
Couple this with consistent folder names and image names, to find everything easily, and you shouldn't have more than a dozen unused image at the end of your project.
 

TDoddery

Member
Apr 28, 2020
170
160
Then, just pick the one you prefer:
  1. Put it outside of the project directory ;
  2. Put it outside of the "game" directory, and use built.classify( "obs/**", None ) to exclude this directory from the build ;
  3. Keep it in the "images" directory, and use built.classify( "game/images/obs/**", None ) to exclude this directory from the build.
Yeah I know, but I think we are talking cross purposes. What I do is basically the same as your option 1, except I don't do it every time for every image, I just batch move them all at the end.