[SOLVED]Is it possible to delete specific parts of the code when making the build?

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.
Message
Author
User avatar
Adabelitoo
Regular
Posts: 141
Joined: Sat Apr 13, 2019 2:32 pm
Contact:

[SOLVED]Is it possible to delete specific parts of the code when making the build?

#1 Post by Adabelitoo »

My game has some sort of fighting scenes with a combat system and all that. When making the game, I added a ton of dev tools to make developing and testing easier, but I don't want the players to have access to those tools because of how easy it would be to bug/break the game, so what I've beein doing is this:

Code: Select all

label start:    
    NPC1 "Do you want to fight?"
    MC "Bring it on!"
    NPC1 "You'll regret this!"
    jump label fight1:

label fight1:
    if dev_mode == True:
        #Show X developer screen
        #Do X developer action
        #Show X developer stats
        #Show X developer menu ---> Choices the winner and entirely skips the fight
    else:
        #Show X normal player screen
        #Show X normal player menu
        #Do X normal player action ---> Starts the fight
        
    #The story continues
I would like if, when making the build for the player, the game deletes the if part of that if/else statement. Not only to make the player unable to reach those tools, but to completely delete any traces of the dev_mode when making the player's build, because otherwise it only takes one people to open the code, find this, change dev_mode to true with the console, and spread the voice to others.

Code: Select all

label start:    
    NPC1 "Do you want to fight?"
    MC "Bring it on!"
    NPC1 "You'll regret this!"
    jump label fight1:

label fight1:
    #Show X normal player screen
    #Show X normal player menu
    #Do X normal player action ---> Starts the fight
        
    #The story continues
All the dev actions are in another .rpy file so I can simply delete that file before making the build, but those if/else are part of the in-game events, I can't delete that .rpy file, it would be like deleting the content of the game. Also in addition to that, I'd like to do the opposite as well, delete the else part to delete the "normal" part of the game.

Code: Select all

label start:    
    NPC1 "Do you want to fight?"
    MC "Bring it on!"
    NPC1 "You'll regret this!"
    jump label fight1:

label fight1:
    #Show X developer screen
    #Do X developer action
    #Show X developer stats
    #Show X developer menu ---> Choices the winner and entirely skips the fight
        
    #The story continues
This is because, in the future I'd like to work with people, for example working with an artist to polish the graphics, and in case things get ugly and don't work for whatever reason, and said person decides to leak the game, at least his build of the game woulnd't have the normal gameplay so normal players wouldn't have much to do. Hopefully this is just me being paranoic but I've heard of some situations like that.

So in short, what I want is to delete the IF or the ELSE and its indentation when making the build. Thanks for reading.
Last edited by Adabelitoo on Sat Jan 11, 2025 11:16 pm, edited 3 times in total.

User avatar
jeffster
Miko-Class Veteran
Posts: 954
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#2 Post by jeffster »

Adabelitoo wrote: Sat Jan 04, 2025 8:41 pm All the dev actions are in another .rpy file so I can simply delete that file before making the build
It is possible to define builds of custom type (e.g. "-dev")
https://renpy.org/doc/html/build.html#packages

and not include some files in a build
https://renpy.org/doc/html/build.html#c ... ring-files

=> No need to delete those files manually.

Adabelitoo wrote: Sat Jan 04, 2025 8:41 pm to delete the IF or the ELSE and its indentation when making the build.
Ren'Py doesn't seem to have a standard way to process script files like that.
You could use some "external" tool to do that, e.g. write a little Python script which would read .rpy files line by line, and for each line
(1) check if it is (when stripped of whitespaces) == if dev_mode == True:.
(2) In that case, set a couple of variables like "current_indent" and "current_mode"...
(3) etc.

In other words, that script could write the output files (the scripts modified as you want them) e.g. in sub-folders like "scripts_p" for player build, and "scripts_d" for dev build.
Then with build.classify() you could include only scripts from those folders into respective builds.
If the problem is solved, please edit the original post and add [SOLVED] to the title. 8)

User avatar
Adabelitoo
Regular
Posts: 141
Joined: Sat Apr 13, 2019 2:32 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#3 Post by Adabelitoo »

jeffster wrote: Sat Jan 04, 2025 10:36 pm Ren'Py doesn't seem to have a standard way to process script files like that.
You could use some "external" tool to do that, e.g. write a little Python script which would read .rpy files line by line, and for each line
(1) check if it is (when stripped of whitespaces) == if dev_mode == True:.
(2) In that case, set a couple of variables like "current_indent" and "current_mode"...
(3) etc.

In other words, that script could write the output files (the scripts modified as you want them) e.g. in sub-folders like "scripts_p" for player build, and "scripts_d" for dev build.
Then with build.classify() you could include only scripts from those folders into respective builds.
What kind of external tool do you mean? It's been ages since I did anything remotely serious with Python, I don't think I'll be able to get it done but I'll at least give it a try. Deleting the file manually isn't an issue, but manually deleting every single IF or ELSE every time I need to make a build will be painful.

User avatar
jeffster
Miko-Class Veteran
Posts: 954
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#4 Post by jeffster »

Adabelitoo wrote: Sat Jan 04, 2025 11:29 pm What kind of external tool do you mean? It's been ages since I did anything remotely serious with Python, I don't think I'll be able to get it done but I'll at least give it a try. Deleting the file manually isn't an issue, but manually deleting every single IF or ELSE every time I need to make a build will be painful.
I mean "external" that is a script that you run outside of Ren'Py. Here's a rough example script. It takes file names as arguments from command line and outputs 2 new files for each, *.dev and *.user:

Code: Select all

#!/bin/env python

import sys

for arg in range(1, len(sys.argv)):
    fname = sys.argv[arg]           # Files to process
    print(fname)                    # Debug
    with open(fname, "r") as f:
        lines = f.read().splitlines()

    dev = []                        # Output strings for DEV file
    user = []                       # Output strings for USER file
    current_mode = None

    for l in lines:
        if current_mode is None:
            if l.strip().startswith('if dev_mode == True:'):
                current_mode = "dev"
                current_indent = l.index('if dev_mode == True:')

        elif current_mode == "dev":
            l_indent = len(l) - len(l.lstrip(' '))
            if l_indent > current_indent:
                dev.append('\n'.join((l[4:], '')))

            elif l_indent == current_indent:
                if l.strip().startswith('else:'):
                    current_mode = "user"
                else:
                    current_mode = None

            else:
                current_mode = None

        elif current_mode == "user":
            l_indent = len(l) - len(l.lstrip(' '))
            if l_indent > current_indent:
                user.append('\n'.join((l[4:], '')))
            else:
                current_mode = None

        if current_mode is None:
            dev.append('\n'.join((l, '')))
            user.append('\n'.join((l, '')))


    with open('.'.join((fname, 'dev')), "w") as f:
        f.writelines(dev)

    with open('.'.join((fname, 'user')), "w") as f:
        f.writelines(user)

sys.exit()
If the problem is solved, please edit the original post and add [SOLVED] to the title. 8)

User avatar
Adabelitoo
Regular
Posts: 141
Joined: Sat Apr 13, 2019 2:32 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#5 Post by Adabelitoo »

jeffster wrote: Sun Jan 05, 2025 1:42 am I mean "external" that is a script that you run outside of Ren'Py. Here's a rough example script. It takes file names as arguments from command line and outputs 2 new files for each, *.dev and *.user:
I got that you meant outside of Ren'Py, but if it isn't in Ren'Py, then in what kind of tool do you mean? Where should I copy-paste your script? Any recommendation of what tool/software to use?

User avatar
enaielei
Veteran
Posts: 433
Joined: Fri Sep 17, 2021 2:09 am
Organization: enaielei
Tumblr: enaielei
Deviantart: enaielei
Github: enaielei
Skype: enaielei
Soundcloud: enaielei
itch: enaielei
Discord: enaielei#7487
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#6 Post by enaielei »

Adabelitoo wrote: Sat Jan 04, 2025 8:41 pm My game has some sort of fighting scenes with a combat system and all that. When making the game, I added a ton of dev tools to make developing and testing easier, but I don't want the players to have access to those tools because of how easy it would be to bug/break the game, so what I've beein doing is this:

Code: Select all

label start:    
    NPC1 "Do you want to fight?"
    MC "Bring it on!"
    NPC1 "You'll regret this!"
    jump label fight1:

label fight1:
    if dev_mode == True:
        #Show X developer screen
        #Do X developer action
        #Show X developer stats
        #Show X developer menu ---> Choices the winner and entirely skips the fight
    else:
        #Show X normal player screen
        #Show X normal player menu
        #Do X normal player action ---> Starts the fight
        
    #The story continues
I would like if, when making the build for the player, the game deletes the if part of that if/else statement. Not only to make the player unable to reach those tools, but to completely delete any traces of the dev_mode when making the player's build, because otherwise it only takes one people to open the code, find this, change dev_mode to true with the console, and spread the voice to others.
What I would suggest is in your main script define the dev_mode variable there.

Code: Select all

# script.rpy
define dev_mode = False
Then have a script that contains all of your dev codes.

Code: Select all

# dev.rpy
label fight1_dev:
    #Show X developer screen
    #Do X developer action
    #Show X developer stats
    #Show X developer menu ---> Choices the winner and entirely skips the fight
    return
Then in your game label use the not_dev function

Code: Select all

# script.rpy
define dev_mode = False

init python:
    def exec_if(expression, function=renpy.call, *args, **kwargs):
        if expression:
            if callable(function):
                function(*args, **kwargs)  # execute the alternative code
            return True
        else:
            return False

    def not_dev(*args, **kwargs):
        return not exec_if(dev_mode, *args, **kwargs)

label fight1:
    if not_dev(label="fight1_dev"): # execute the game below within the if block only if dev_mode = False, otherwise call the label specified
        #Show X normal player screen
        #Show X normal player menu
        #Do X normal player action ---> Starts the fight
        
    #The story continues
Then in your build.rpy exclude the traces of dev.rpy, so that if the player even manually set dev_mode to True, the label call will raise an exception due to the label not being present in the built game.

Your case is just a matter of code segregation. Isolate the game and dev codes so you can easily exclude from the built game the dev codes.

Btw, there's a built-in developer variable already it's called config.developer.

User avatar
jeffster
Miko-Class Veteran
Posts: 954
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#7 Post by jeffster »

Adabelitoo wrote: Sun Jan 05, 2025 5:48 pm Where should I copy-paste your script?
It is a Python script. Paste it as a Python file (e.g. pre_build.py) and run it e.g. from command line with the list of files to process. In Linux it would look like

[game]$ ./pre_build.py script.rpy ep1.rpy ep2.rpy

meaning "run file pre_build.py from the current folder" with arguments (files to process):

Code: Select all

script.rpy
ep1.rpy
ep2.rpy
In Windows it's something similar (search the internet for "run python script in Windows" if you wish).
Of course that command could be recorded as a command file (like .bat or something in Windows, or .sh in Linux), so you just launch it before making a build.
If the problem is solved, please edit the original post and add [SOLVED] to the title. 8)

User avatar
jeffster
Miko-Class Veteran
Posts: 954
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#8 Post by jeffster »

enaielei wrote: Sun Jan 05, 2025 6:31 pm

Code: Select all

init python:
    def exec_if(expression, function=renpy.call, *args, **kwargs):
        if expression:
            if callable(function):
                function(*args, **kwargs)  # execute the alternative code
            return True
        else:
            return False

    def not_dev(*args, **kwargs):
        return not exec_if(dev_mode, *args, **kwargs)

label fight1:
    if not_dev(label="fight1_dev"): # execute the game below within the if block only if dev_mode = False, otherwise call the label specified
...
Isolate the game and dev codes so you can easily exclude from the built game the dev codes.
This solution might be conceptually superior but the original way is easier to read and develop.

E.g. imagine that we hide not only dev parts from players but also player parts from devs.

Simply put:

Code: Select all

# script.rpy:
init python:
    def du(call_label):
        renpy.call(call_label + "ud"[dev_mode])

label start:
    $ du("label1")
    ...


# user.rpy:
label label1u:
    ...
    return


# dev.rpy:
label label1d:
    ...
    return
We would need to write the script into 3 different files, which is pretty inconvenient and harder to track. If there are many blocks to distinguish players' and dev modes, then it's almost the same as having 2 different script files, one for players' script and another for devs' script.
If the problem is solved, please edit the original post and add [SOLVED] to the title. 8)

User avatar
Adabelitoo
Regular
Posts: 141
Joined: Sat Apr 13, 2019 2:32 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#9 Post by Adabelitoo »

jeffster wrote: Mon Jan 06, 2025 7:03 am It is a Python script. Paste it as a Python file (e.g. pre_build.py) and run it e.g. from command line with the list of files to process. In Linux it would look like

[game]$ ./pre_build.py script.rpy ep1.rpy ep2.rpy

meaning "run file pre_build.py from the current folder" with arguments (files to process):

Code: Select all

script.rpy
ep1.rpy
ep2.rpy
In Windows it's something similar (search the internet for "run python script in Windows" if you wish).
Of course that command could be recorded as a command file (like .bat or something in Windows, or .sh in Linux), so you just launch it before making a build.
Sorry for the late reply, I had a bussy week. The code works perfectly, I've been trying to mess with it and find possible issues but so far I haven't found any. This will save me lots of time. Thanks!

Marked as solved.

User avatar
Adabelitoo
Regular
Posts: 141
Joined: Sat Apr 13, 2019 2:32 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#10 Post by Adabelitoo »

jeffster wrote: Mon Jan 06, 2025 7:03 am In Windows it's something similar (search the internet for "run python script in Windows" if you wish).
Of course that command could be recorded as a command file (like .bat or something in Windows, or .sh in Linux), so you just launch it before making a build.
And of course, soon after I marked it as solved, an issue shows up.

When testing it I used a simplified version of one of the files with only some if/else to test if the result was correct, but now I'm trying with the full file and I got this error:

Code: Select all

Traceback (most recent call last):
  File "C:\Users\Sebastian\Desktop\M1802\MLW4S\Esc\0.Patch maker\script_splitter2.py", line 9, in <module>
    lines = f.read().splitlines()
            ~~~~~~^^
  File "C:\Users\Sebastian\AppData\Local\Programs\Python\Python313\Lib\encodings\cp1252.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 23614: character maps to <undefined>

User avatar
jeffster
Miko-Class Veteran
Posts: 954
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#11 Post by jeffster »

Adabelitoo wrote: Sat Jan 11, 2025 12:00 am When testing it I used a simplified version of one of the files with only some if/else to test if the result was correct, but now I'm trying with the full file and I got this error:

Code: Select all

Traceback (most recent call last):
  File "C:\Users\Sebastian\Desktop\M1802\MLW4S\Esc\0.Patch maker\script_splitter2.py", line 9, in <module>
    lines = f.read().splitlines()
            ~~~~~~^^
  File "C:\Users\Sebastian\AppData\Local\Programs\Python\Python313\Lib\encodings\cp1252.py", line 23, in decode
    return codecs.charmap_decode(input,self.errors,decoding_table)[0]
           ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: 'charmap' codec can't decode byte 0x9d in position 23614: character maps to <undefined>
It's something related to files' encoding. Probably they are saved as Unicode, but Python is trying to read them in the system's encoding (Windows-1252 code page). Here's the solution:

https://stackoverflow.com/a/49562606
If the problem is solved, please edit the original post and add [SOLVED] to the title. 8)

User avatar
Adabelitoo
Regular
Posts: 141
Joined: Sat Apr 13, 2019 2:32 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#12 Post by Adabelitoo »

jeffster wrote: Sat Jan 11, 2025 2:01 pm It's something related to files' encoding. Probably they are saved as Unicode, but Python is trying to read them in the system's encoding (Windows-1252 code page). Here's the solution:

https://stackoverflow.com/a/49562606
I hardly understand anything in that post, but the little I understand is that I have to add "open" or "encoding='utf8'" somewhere (and that many people think that hiding an error is the same as fixing it, like WTF?). After trying to figure it out, I replaced the "r" from line 7 for "encoding='utf8'" and the script worked but the final results replaces a bunch of characters (mostly the character ' ) by a � symbol, and while trying to run the game I got this error.

Code: Select all

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 3051: invalid continuation byte

User avatar
jeffster
Miko-Class Veteran
Posts: 954
Joined: Wed Feb 03, 2021 9:55 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#13 Post by jeffster »

Adabelitoo wrote: Sat Jan 11, 2025 5:57 pm After trying to figure it out, I replaced the "r" from line 7 for "encoding='utf8'" and the script worked but the final results replaces a bunch of characters (mostly the character ' ) by a � symbol, and while trying to run the game I got this error.

Code: Select all

UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 3051: invalid continuation byte
Yes, the file opening should be changed from

Code: Select all

    with open(fname, "r") as f:
to

Code: Select all

    with open(fname, "r", encoding="utf-8") as f:
https://docs.python.org/3/library/functions.html#open

And perhaps writing should be changed like that too. From:

Code: Select all

    with open('.'.join((fname, 'dev')), "w") as f:
        f.writelines(dev)

    with open('.'.join((fname, 'user')), "w") as f:
        f.writelines(user)
to

Code: Select all

    with open('.'.join((fname, 'dev')), "w", encoding="utf-8") as f:
        f.writelines(dev)

    with open('.'.join((fname, 'user')), "w", encoding="utf-8") as f:
        f.writelines(user)

Here's another version of the script (a few lines shorter & with more modern syntax), already patched:

Code: Select all

#!/bin/env python
import sys

for arg in range(1, len(sys.argv)):
    fname = sys.argv[arg]           # Files to process
    print(fname)                    # Debug
    with open(fname, "r", encoding="utf-8") as f:
        lines = f.read().splitlines()

    dev = []                        # Output strings for DEV file
    user = []                       # Output strings for USER file
    pattern = 'if dev_mode == True:'
    current_mode = None

    for l in lines:
        skip = False                # Detect if/else for "dev_mode"

        if current_mode is None:
            if l.strip().startswith(pattern):
                current_indent = l.index(pattern)
                current_mode = "dev"
                skip = True

        else:
            shift_indent = len(l) - len(l.lstrip(' ')) - current_indent

            if current_mode == "dev" and not shift_indent\
                                     and l.strip().startswith('else:'):
                current_mode = "user"
                skip = True
            else:
                if shift_indent <= 0:
                    current_mode = None
                else:
                    globals()[current_mode].append(f'{l[4:]}\n')

        if current_mode is None and not skip:
            dev.append(f'{l}\n')
            user.append(f'{l}\n')


    with open(f'{fname}.dev', "w", encoding="utf-8") as f:
        f.writelines(dev)

    with open(f'{fname}.user', "w", encoding="utf-8") as f:
        f.writelines(user)
It should work, provided that the script files are saved in the editor as Unicode (utf-8).
If the problem is solved, please edit the original post and add [SOLVED] to the title. 8)

User avatar
Adabelitoo
Regular
Posts: 141
Joined: Sat Apr 13, 2019 2:32 pm
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#14 Post by Adabelitoo »

jeffster wrote: Sat Jan 11, 2025 8:10 pm Here's another version of the script (a few lines shorter & with more modern syntax), already patched:
I tested it and checked the results as much as I could think of, and everything seems to be working fine. This is big time saver for me. Thank you so much.

Marked as solved, hopefully for real this time.

DeVNCraft
Regular
Posts: 37
Joined: Fri Dec 13, 2024 7:54 am
Projects: The Shadow Over Willowtown
Organization: VNCraft
Location: US
Contact:

Re: Is it possible to delete specific parts of the code when making the build?

#15 Post by DeVNCraft »

Adabelitoo wrote: Sat Jan 11, 2025 11:16 pm
jeffster wrote: Sat Jan 11, 2025 8:10 pm Here's another version of the script (a few lines shorter & with more modern syntax), already patched:
I tested it and checked the results as much as I could think of, and everything seems to be working fine. This is big time saver for me. Thank you so much.

Marked as solved, hopefully for real this time.
Just wanted to chime in here...why are you not using ren'py config.developer as the variable first off? Then you set one and not only access ren'py default debugging but your own menus.

Also if you want to hide the code entirely just make a single python function that takes an argument with if else statements that you call as a function in that single rpy file like renpy.end_replay() where it simply exits if developer mode isnt enabled and if not you could pass it an enum or a string telling it which calls in the same file to run by calling the function.

I.E.

Code: Select all

### in debug.rpy
init python:
    from enum import Enum
    
    class DEV_DEBUG_FUNCTION(Enum):
        dev_debug_menu = 0
        dev_debug_run_this = 1
        etc = 3
        
    def dev_run_debug(debug_type)
        if config.developer == True:
            if debug_type == DEV_DEBUG_FUNCTUON.debug_menu:
                renpy.call(debug_menu_screen)
                renpy.jump(continue_game)
            elif debug_type == DEV_DEBUG_FUNCTION.etc:
                set fight win variable and jump to end fight
                # do whatever
        else:
            return
                   
label debug_menu_screen:
     # show menu

### script.rpy
label start:    
    NPC1 "Do you want to fight?"
    MC "Bring it on!"
    NPC1 "You'll regret this!"
    jump label fight1:

label fight1:
    $ dev_run_debug(dev_debug_menu)
    #Show X developer screen
    #Do X developer action
    #Show X developer stats
    #Show X developer menu ---> Choices the winner and entirely skips the fight
contumue_story:  
    #The story continues
I'm on my cell phone so I apologize if the code spacing is incorrect, but this seems like its getting extremely overcomplicated for a simple task.

renpy.end_replay() which does nothong if your not in a replay is the best example I could give...I do this myself with a debug.rpy file actually, entirely different reasoning...but the same concept. although I suggest a shorter name for the enum and types I didnt want to use built in variables on accident.

Be warned its totally untested and meant just as a concept to suggest a way to go about it.
▪︎ C/TC++/VC++ ▪︎ Q/V/Basic ▪︎ Python/Ren'Py (noob)

I blame the other guy for being here 8)

Post Reply

Who is online

Users browsing this forum: Bing [Bot], isah1221