Ren'Py Script/code to output labels/scenes onto a textfile?

m24nub

Newbie
Aug 25, 2017
29
3
Hi, does anyone know a script/code I can use to output labels onto a text file? Ideally, each label is separated by a new line. The way each label is listed using renpy.get_all_labels() is impossible to use and would like them printed on a text file so I can search them more easily. Thanks!
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
Start the game.
Open the developer console (SHIFT+O).
Use these 3 commands:

Python:
f=open(os.path.join(renpy.config.gamedir, "mylabels.txt"), "w")
for i in renpy.get_all_labels(): f.write("{}\n".format(i))
f.close()

It might be possible to combine things into a single line, but not knowing python - this was the closest I could get to work at short notice.
You could also put these commands into a .rpy script file, perhaps as a custom function and either execute the function from the console or have it executed during RenPy startup. I chose to do everything at the console for simplicity sake.

The full list of labels written to the file include "internal" labels used only by RenPy itself. I assume you can ignore any entry that starts with an underscore ( _ ).

If it would help to have the list of labels sorted alphabetically and look like the actual RenPy statements, then there is:

Python:
f=open(os.path.join(renpy.config.gamedir, "mylabels.txt"), "w")
for i in sorted(renpy.get_all_labels()): f.write("label {}:\n".format(i))
f.close()

RenPy only allows you to open a file for writing (mode "w") when the file is within the /game/ folder or any sub-folders... and it's easier to let RenPy figure that out for your using os.path.join(renpy.config.gamedir, [...]).

Note: This will definitely NOT work on Android, where even the /game/ folder can not be written to. It works on PC, I can't speak to MacOS or Linux.


Edit:

[...] so I can search them more easily.

If you are using the recommended editor (Atom), you can do this a lot easier by using Find in Project (CTRL+SHIFT+F). Then just search for "label" within all *.rpy files). The only quirk I can think of would be those games that combine label: and menu: into a single menu: statement. But 99% of the time, it shouldn't be a problem.
 
Last edited:
  • Like
Reactions: m24nub

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
Ok, next time m24nub don't post the same question twice in two different parts of the forum. It would avoid people wasting their time answering something that already received a valid answer...
 

m24nub

Newbie
Aug 25, 2017
29
3
Start the game.
Open the developer console (SHIFT+O).
Use these 3 commands:

Python:
f=open(os.path.join(renpy.config.gamedir, "mylabels.txt"), "w")
for i in renpy.get_all_labels(): f.write("{}\n".format(i))
f.close()

It might be possible to combine things into a single line, but not knowing python - this was the closest I could get to work at short notice.
You could also put these commands into a .rpy script file, perhaps as a custom function and either execute the function from the console or have it executed during RenPy startup. I chose to do everything at the console for simplicity sake.

The full list of labels written to the file include "internal" labels used only by RenPy itself. I assume you can ignore any entry that starts with an underscore ( _ ).

If it would help to have the list of labels sorted alphabetically and look like the actual RenPy statements, then there is:

Python:
f=open(os.path.join(renpy.config.gamedir, "mylabels.txt"), "w")
for i in sorted(renpy.get_all_labels()): f.write("label {}:\n".format(i))
f.close()

RenPy only allows you to open a file for writing (mode "w") when the file is within the /game/ folder or any sub-folders... and it's easier to let RenPy figure that out for your using os.path.join(renpy.config.gamedir, [...]).

Note: This will definitely NOT work on Android, where even the /game/ folder can not be written to. It works on PC, I can't speak to MacOS or Linux.


Edit:
Thanks! I merged some of your code with anne O'nymous and found the perfect solution:

Code:
  f=open( renpy.os.path.join( config.basedir, '_Labels.txt' ), "w")
  for i in sorted(renpy.get_all_labels()): f.write("{}:\n".format(i))
  f.close()
Do you know why I don't get all the variables when I replace renpy.get_all_labels() with dir() ?

If you are using the recommended editor (Atom), you can do this a lot easier by using Find in Project (CTRL+SHIFT+F). Then just search for "label" within all *.rpy files). The only quirk I can think of would be those games that combine label: and menu: into a single menu: statement. But 99% of the time, it shouldn't be a problem.
Would you recommend using Atom over Notepad++? I only use Notepad++ because the multiple file tabs and "find all" features are pretty useful.
 
Last edited:

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
Would you recommend using Atom over Notepad++? I only use Notepad++ because the multiple file tabs and "find all" features are pretty useful.

It's pretty much personal preference. If you already use Notepad++ a lot - stick with it.

Atom will do all the same things. Plus more (I think). But I can't give you a good reason to swap.

The only thing I would say, is that if you do try Atom - make sure to only install it from the RenPy SDK launcher preferences (Default Editor). Doing that will automatically download a preconfigured and optimized version of Atom and the appropriate addons. Newer versions direct from Atom removed support for showing the whole project folder at all - which makes it a pain with RenPy. But the version shipped by RenPy works flawlessly (except you need to tweak a setting to switch spell checking back on by default - see my tagline links).
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
Do you know why I don't get all the variables when I replace renpy.get_all_labels() with dir() ?
You get all the variables... that exist at this moment. If you don't see a variable, then it's that it haven't been created yet.

But anyway it's not what you should use, because you got way too many variables:
Code:
len( dir() )
669
len( renpy.python.store_dicts["store"].ever_been_changed )
14
The first one show you all the variables used by Ren'py, including the internal ones. The second show you the variables that will be saved, and therefore the ones that really matters.

By the way, I'm sure that there's a tool somewhere to see the variables. It's maintained by a lazy ass who should be working harder on it, but it exist and still works for versions prior to the 7.4.x branch.
 

m24nub

Newbie
Aug 25, 2017
29
3
It's pretty much personal preference. If you already use Notepad++ a lot - stick with it.

Atom will do all the same things. Plus more (I think). But I can't give you a good reason to swap.

The only thing I would say, is that if you do try Atom - make sure to only install it from the RenPy SDK launcher preferences (Default Editor). Doing that will automatically download a preconfigured and optimized version of Atom and the appropriate addons. Newer versions direct from Atom removed support for showing the whole project folder at all - which makes it a pain with RenPy. But the version shipped by RenPy works flawlessly (except you need to tweak a setting to switch spell checking back on by default - see my tagline links).
Thanks! I tried playing around with Atom for a little bit and I really like the interface. However, I can't seem to find the labels using your method even after installing language-renpy and using the settings you suggested in your newbie post. I'm trying everything in this thread on Being a DIK v0.8.0.

Code:
len( dir() )
669
len( renpy.python.store_dicts["store"].ever_been_changed )
14
The first one show you all the variables used by Ren'py, including the internal ones. The second show you the variables that will be saved, and therefore the ones that really matters.
I can't seem to get this to work when I replace renpy.get_all_labels(). My game doesn't launch and I get this error:

Code:
I'm sorry, but an uncaught exception occurred.

While running game code:
  File "game/_cheats.rpy", line 1, in script
    init 999 python:
  File "game/_cheats.rpy", line 1, in script
    init 999 python:
  File "game/_cheats.rpy", line 38, in <module>
    for i in sorted(len( renpy.python.store_dicts["store"].ever_been_changed )): f.write("{}\n".format(i))
TypeError: 'int' object is not iterable

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

Full traceback:
  File "renpy/bootstrap.py", line 331, in bootstrap
    renpy.main.main()
  File "renpy/main.py", line 550, in main
    renpy.game.context().run(node)
  File "game/_cheats.rpy", line 1, in script
    init 999 python:
  File "game/_cheats.rpy", line 1, in script
    init 999 python:
  File "renpy/ast.py", line 928, in execute
    renpy.python.py_exec_bytecode(self.code.bytecode, self.hide, store=self.store)
  File "renpy/python.py", line 2245, in py_exec_bytecode
    exec(bytecode, globals, locals)
  File "game/_cheats.rpy", line 38, in <module>
    for i in sorted(len( renpy.python.store_dicts["store"].ever_been_changed )): f.write("{}\n".format(i))
  File "renpy/python.py", line 1056, in revertable_sorted
    return RevertableList(sorted(*args, **kwargs))
TypeError: 'int' object is not iterable
 

gojira667

Member
Sep 9, 2019
272
255
How about grep?
Code:
grep -HnTIr 'label .*:' /path/install/folder/game > labels.log
That will give you the filename, line number and contents of the line separated by newlines. To be fair that will include any line that has the chars "label " followed by any char, IIRC except <CR> and/or <LF>, and a ":" char. E.G. this would be a false positive:
Code:
    mc "79flavors code to list any label in the game. Such as: ..."
You will find it on most *nix OSes, but a new enough Windows you can use WSL or there are actual Windows ports of Grep.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
remind me of a recent private discussion.

I can't seem to get this to work when I replace renpy.get_all_labels(). My game doesn't launch and I get this error:

Code:
    for i in sorted(len( renpy.python.store_dicts["store"].ever_been_changed )): f.write("{}\n".format(i))
TypeError: 'int' object is not iterable
It was a demonstration of the difference (expressed by their size) between dir and the list of variables that will be saved. What you need to use in replacement of renpy.get_all_labels() is renpy.python.store_dicts["store"].ever_been_changed.


This being said, and please don't take it badly it's not my intent, I don't know what you want to do, but are you sure that you need to do it ?
You aren't able to discriminate by yourself the len( [...] ) part, what show that you've 0 knowledge regarding coding. It's not a shame, there's tons of subjects for which I have a negative knowledge (they don't even works the way I think). But, well I let people who know more than me deal with them, specifically because of my lack of knowledge.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
Déjà vu

Okay. We seem to be jumping all over the place now.

1. Getting list of labels
2. Getting list of variables
3. Should I use Atom?
4. I type "{command}" and got an error.

I'm going to add a "0" to this... and ask "What is your goal?" - Because WHY you are doing some of this, might make it easier to offer you better advice.


So....

0. What is is your goal?

I initially assume you were writing a game and were losing track of your labels and therefore were just looking for a way to keep yourself organized.
But you specifically mentioned "Being a DIK", which is a huge lumbering monstrosity of a game that is particularly hard to follow.

So are you writing a walk through guide? Are you trying to see what content you might have missed during your playthrough?


1. Getting a list of labels.

I think this one is "asked and answered". You seem to be happy the text file contains what you needed. I'll consider this one dealt with.


2. Getting a list of variables

The problem with RenPy is that "variables" cover a LOT of ground. RenPy has a lot of things going on in the background, which are held in variables - even if you don't normally see them.

I think my initial answer would be to use the Developer Console (SHIFT+D), then pick "Variable Viewer" from the list of options. It'll mainly only show the variables a developer will care about (though some internal variables will get shown). But it's only a basic list. Things get trickier when you start dealing with reference variables (variable that are pointers to other variables), especially when they are references to custom classes or list/dictionary objects.

If you want to "drill down" into multilayered variables/references, then your going to need something especially written for that purpose - as it doesn't exist in the base game. Thankfully anne O'nymous wrote the Extended Variable Viewer almost 4 years ago now. It does what the basic variable viewer does, but with lots more bells and whistles. You can see the contents of lists and follow references to other classes.

But both of those are onscreen tools. They aren't writing anything to a file and they aren't giving you a simple bit of code you can type at the console to dump the list to a file. Except it's not clear to me WHY you want the list of variables and so I don't know what the answer is, beyond "Variable Viewer" and "Extended Variable Viewer".


3. Should I use Atom.

As I already suggested, if you're happy with Notepad++, keep on using it. I think Atom is better, but I can't really say why.


3b. I tried to use Atom, but it didn't do what you said it would.

Difficult for me to say.

Firstly, are you using the recommended version of Atom? (Click Help -> About). It should say version "1.35" or "1.35.1". Anything newer than 1.36.0 will not work properly with RenPy, even if you install the addons. If it's newer, it's likely you installed it yourself and didn't follow the recommendation in my previous post that explained using the RenPy launcher to install it's customized version for you (RenPy Launcher -> Preferences -> Text Editor -> [Select Atom]).

If you are on the correct version. Again, difficult for me to say. All I can offer is that if I press (CTRL+SHIFT+F) for "Find in Project", stick "label" in the search box and put *.rpy in the "File/Directory pattern" box, then click the "Find All" - I get a clickable list of all the places where "label" is mentioned, regardless of which file it's included within. I only limit things to *.rpy for speed, so it's not searching all the image files when the project could be 4GB+ in size. I suppose it's possible you've switched some of the filters on the right side inadvertently (above the Find All button), Case Sensitivity, Search using RegEx expressions and "Whole Word" searches only - but even so, I'd expect them to find text as simple as "label" regardless.

However, nobody is twisting your are to use Atom. If it's not working out for you... there's still Notepad++


4. I type "{command}" and got an error.

This one seems to be you copy/pasting answers without really understanding them.

In this case, len( renpy.python.store_dicts["store"].ever_been_changed ) became for i in sorted(len( renpy.python.store_dicts["store"].ever_been_changed )): f.write("{}\n".format(i)).

len() is pretty much "count the length of". And Anne was using it to show that there were a lot more (unnecessary) variables stored in dir() than there are in renpy.python.store_dicts["store"].ever_been_changed.

Breaking it down, you effectively ended up with for i in sorted( 14 ): f.write("{}\n".format(i)).
Renpy then sorted "14" to get "14" and threw an error to complain than you can iterate a for i in loop against a simple integer number (14).

The answer to your error is to remove the len() from the statement, to get for i in sorted( renpy.python.store_dicts["store"].ever_been_changed): f.write("{}\n".format(i)).

I guess our worry is that if you can't spot something as simple as len() being there - how much are we actually helping you. Potentially, we're giving you solutions that aren't really suitable for you.


Which links back to "what are your goals?"
I know from my own past that I sometimes decide to put lists together instead of focusing on what I should be doing. It's a delaying tactic so that I can procrastinate about how to create the list rather then actually just getting on with things - especially if I'm feeling out of my depth.
 

m24nub

Newbie
Aug 25, 2017
29
3
0. What is is your goal?

I'm just a filthy casual player who has no coding experience and wanted to jump to scenes I may have missed. Specifically, I wanted to play through Being a DIK's new update without waiting for the walkthrough mod. I usually use walkthroughs/Interactive Developer to identify variables I need to change in order to progress specific scenes, but I have noticed some games' Interactive Developers do not work which is why I needed a list of labels.

1. Getting a list of labels.

Yes, this is done and dusted. Thank you and anne O'nymous for the help.

2. Getting a list of variables

I normally use the "Variable Viewer" in the Developer Console to get a list of variables. This is perfectly fine for most games, but as some games are quite colossal, I wanted a simple way to search for variables that may pertain to a specific scene/character. I may just be ignorant, but as far as I am aware, there is no search functionality built into Ren'Py for variables or labels, but if there is, this entire thread would be redundant.

I took a look at anne O'nymous' beautiful Extended Variable Viewer but as you said, it is an onscreen tool, so I wouldn't be able to search the way I want to.

4. I type "{command}" and got an error.
I appreciate you taking the time to explain simple coding semantics to me. While I feel like you explained it well, it completely went over my head and I'm not sure how to respond to it. I just wanted some code that I could copy and paste into my little cheat.rpy file that I copy and paste into every Ren'Py game I play.

Finally, I just wanted to thank you for taking the time to respond to my posts. As I said, I am just a filthy consumer looking to enhance my own personal experience playing these games. I would probably become a modder if I had some coding experience, but I have no idea where to start and probably won't take the time to learn how to code unless there's a well-written edition of "Ren'Py Modding for Dummies". I do maintain an extensive Google Sheet that scrapes threads to check for updates, but I would definitely not call spreadsheet formulas "coding".
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
I'd need to go back and check, but I'm 99% sure the Extended Variable Viewer has a search/filter option for variable names.

As someone who plays in a similar way, my general solution is two monitors. I play the game on the left screen, while having the game's code open in Atom on the right. When I lose track (specially bad in a free movememt/open world game), I just search the source to find the matching line (you learn the words in a sentence that are "probably" unique to search by). That way, I can check the consequences of choices before I make them. And if the code reaches a branch I might otherwise miss, I save, then open the console to changes the variable values so it follows my preferred path.
 

m24nub

Newbie
Aug 25, 2017
29
3
I tried using Atom in this way with Being a DIK but I wouldn't get the right results when I searched for things. For example, when I searched for "label", I only got results in the generic Ren'Py files and no results for the game-specific files. I'm assuming the game-specific files are encrypted or the code has to be translated, but I did not dive very deeply into the issue.

I normally play with the game on my left screen and a walkthrough on my right. When I get stuck and Interactive Developer doesn't work, I usually open script.rpy and look for the specific line I'm at, or open gallery.rpy and look for the specific label I want to jump to. I also tend to save scum pretty often because I think(?) Interactive Developer creates bloat that can corrupt save files or disable saving entirely.
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
[...] but I wouldn't get the right results when I searched for things. For example, when I searched for "label", I only got results in the generic Ren'Py files and no results for the game-specific files. I'm assuming the game-specific files are encrypted or the code has to be translated [...]

It took me a little while to guess what you meant by that.
I think by "generic Renpy files", you mean the actual python/RenPy code that makes up RenPy itself. The stuff that sits in the /renpy/ folder itself.
Then by "game specific files", you meant the actual script files written by the developer(s).

Firstly, surely you get the same results when using Notepad++? Though now I think about it, I don't think you've been using that, except as your default text editor to look at the extracted text files you've been creating.
Secondly, you'd (well I'd) only normally search within the /game/ folder - since that is "the game".
Thirdly, if you'd used the Atom feature to limit searches to only *.rpy as I'd suggested - you shouldn't have received search results for the RenPy engine's *.py files - which are python code, not RenPy code.

I'm assuming the game-specific files are encrypted or the code has to be translated [...]

And now I think I see why you'd gone down the rabbit hole of using the console to extract the labels and variables to a text file.

I think you're missing that it's possible to see the source code of 99.99% of all RenPy games, even when it's not entirely obvious that you can.

When developers create the "distribution file" (the ZIP file most games are shipped as), it goes through a number of steps. One step is to merge all the *.rpy into single file (usually called archive.rpa or scripts.rpa. RPA stands for "RenPy Archive". It's an optional step, but most developers will switch it on. It does more than just the script files, including all the images, etc.

I'm guessing you are unaware of UnRen.

Option 1 of UnRen to unpack the .rpa archives. (it pretty much doubles the size of the game, so perhaps delete the *.rpa files afterward, as they are no longer needed).

95%* of the time, that will be enough. You'll be able to see the *.rpy source code and figure out everything you're looking for.
* 81.6% of all quoted statistics on the internet are made up on the spot by the author to convince the reader they are awesome.

BUT... 5% of the time the developer will have only shipped the game's *.rpyc files. These are the actual game files used by RenPy. They are effectively "Compiled RenPy" scripts. Thankfully "Option 2" of UnRen is to recreate the *.rpy files based on the *.rpyc files. If the .rpy files are missing, use option 2.

However you get there. UnRen should mean you can look at the source code... search for dialogue, labels, variables, whatever. Which is pretty much what the rest of us do, without extracting lists of labels and variables as text files.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
I'd need to go back and check, but I'm 99% sure the Extended Variable Viewer has a search/filter option for variable names.
It have, and you can even copy the name of the variable in the console stack, in order to access them easily after (using the arrow keys) when you're in the console.



As someone who plays in a similar way, my general solution is two monitors. I play the game on the left screen, while having the game's code open in Atom on the right. When I lose track (specially bad in a free movememt/open world game), I just search the source to find the matching line (you learn the words in a sentence that are "probably" unique to search by). That way, I can check the consequences of choices before I make them. And if the code reaches a branch I might otherwise miss, I save, then open the console to changes the variable values so it follows my preferred path.
Same, for me, with sometime a "watch-like" add-on to easily see the most significant changes or alter the values.

And obviously my extended variable viewer, since I initially wrote it to help me cheat :D
 

m24nub

Newbie
Aug 25, 2017
29
3
Thanks! I did try using Unren but got the same results (I think). I'll take a closer look at Atom/Extended Variable Viewer next week since I'll be working double shifts for the rest of this week. Happy holidays to you both!
 

FaceCrap

Active Member
Oct 1, 2020
885
619
sorry for jumping in on this thread...

many thanks for posting what lead me to use this to get a list of the variables...
Code:
        file = open("variables.txt","w")
        for i in sorted( renpy.python.store_dicts["store"].ever_been_changed ): file.write("{}\n".format(i))
Is there also a way to include the value with the variable ?

(I've been googling this to death but can't seem to find the right keyword(s) to make search results useful)
 

79flavors

Well-Known Member
Respected User
Jun 14, 2018
1,581
2,219
Is there also a way to include the value with the variable ?

The thing you are missing is , which retrieves the value of a variable from a store.
There is also which lets you set a value.
Finally there is which will tell you if a variable exists or not.

This is the bit of code I wrote just now to dump the list of variables...

Python:
    python:
        with open(renpy.os.path.join(config.basedir, "variables.txt"), "w") as varfile:
            for i in sorted(renpy.python.store_dicts["store"].ever_been_changed):
                if i[0] != "_":
                    varfile.write("{} = {}\n".format(i, getattr(store, i)))

There may be better/alternative ways to write it - but I'm a simple soul and this worked for me.

The renpy.os.path.join() is there to ensure the variables file is written to the game's base directory rather than the RenPy launcher's own home directory.

The renpy.python.store_dicts you've already come across and is effectively the variable store space.

The if i[0] != "_": is my way of excluding the internal RenPy variables, where the values can be huge lists of previous statements and other distracting values. It also avoids a problem where not all internal variables have a value stored in the store. I initially got around this by checking hasattr(), but then hated the huge lists that came with it.

Oh, and I used with open() rather than varvar = open() as with will automatically clean up after itself. In this case, it ensures varfile is closed when the commands are finished - without needing to code a close statement.

Hope this helps.
 
Last edited:

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Donor
Respected User
Jun 10, 2017
10,369
15,285
Code:
        file = open("variables.txt","w")
        for i in sorted( renpy.python.store_dicts["store"].ever_been_changed ): file.write("{}\n".format(i))
Is there also a way to include the value with the variable ?
Yes. Replace file.write( "{}"\n".format( i ) ) by file.write( "{}:\n\t{}"\n".format( i, getattr( store, i ) ) )
But be aware that you can get really big results, some games are a real mess. When I was making the first version of my Variable Viewer, I encountered a case where a list was made of nested lists for a "representation size" going further than 150 000 characters.
It will also not necessarily always give you what you expected. By example if a variable host an object you'll have something like <class 'CLASS NAME'> in place of what you can possible be expecting.

Therefore, it's probably better to use some tool for this ; i think that one was named on this thread :D

Edit: I need to type faster :D