Ren'Py Don't use 'if renpy.loadable("patch.rpy"):' in your games

U

User_920791

Guest
Guest
This code makes the incest patch not work in android versions. By including all "extra content" directly in the game code, you are also violating Patreon's ToS.

Suggestion:
Python:
## patch.rpy
$ Family_Friendly = True


label Family_Friendly_Scene1:
    ...
    jump Family_Friendly_Scene2


label Family_Friendly_Scene2:
    ...
   jump Family_Friendly_SceneN
Python:
## vanilla.rpy
label Vanilla_Scene1:
    ...
    jump Vanilla_Scene2


label Vanilla_Scene2:
    ...
   jump Vanilla_SceneN
Python:
## script.rpy
label start:

    if Family_Friendly:
        jump Family_Friendly_Scene1
    else:
        jump Vanilla_Scene1
 
  • Like
Reactions: Maid Lain

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,787
This code makes the incest patch not work in android versions.
Er... If renpy.loadable don't return a True value when the file is effectively located in Ren'py's game folder, then it's a bug. And if the file is not in the Ren'py's game folder, then it's normal that it return a False value.


Suggestion:
[...]
Python:
## script.rpy
label start:

    if Family_Friendly:
        jump Family_Friendly_Scene1
    else:
        jump Vanilla_Scene1
Which is still a violation of Patreon's ToS. You can't use their service to fund a game including a banned content. This whatever the way this content is included and the way/place the game is distributed.

The only way to effectively patch a game without being in violation of the said ToS is to use and/or . Simply because they are the only way to effectively change the code/text without having this change planned, in a way or another, in the original code.
 
  • Like
  • Love
Reactions: walfeds and Phlexxx
U

User_920791

Guest
Guest
Er... If renpy.loadable don't return a True value when the file is effectively located in Ren'py's game folder, then it's a bug. And if the file is not in the Ren'py's game folder, then it's normal that it return a False value.
'renpy.loadable("patch.rpy")' requires that the rpy file (not the compiled version) exist in the game folder, something "impossible" in the android versions, even if the patch file is included in the project:


Which is still a violation of Patreon's ToS. You can't use their service to fund a game including a banned content. This whatever the way this content is included and the way/place the game is distributed.

The only way to effectively patch a game without being in violation of the said ToS is to use and/or . Simply because they are the only way to effectively change the code/text without having this change planned, in a way or another, in the original code.
The patch structure I suggested does not necessarily imply that the developer created the incest patch or that it is making it easy to create. This mechanism can be used to offer a more complete version of the game (without any banned content) to certain supporters, for example.
 

Rich

Old Fart
Modder
Respected User
Donor
Game Developer
Jun 25, 2017
2,461
6,925
The only way to effectively patch a game without being in violation of the said ToS is to use and/or . Simply because they are the only way to effectively change the code/text without having this change planned, in a way or another, in the original code.
One addition to that - as a possible alternative to using config.say_menu_text_filter, it would be possible to add "banned text" to a game as a translation that is applied after the fact (by the "patch") and then also invoked by patched-in code.

But, yes, if you're going to produce a game that, upon inspection of the source code, is 100% totally clear of any hint of the author even having thought about banned content being inserted into it, then you definitely have to play some very careful games. That being said, there are some bits of code that might facilitate the addition of banned content but which could be structured to provide "plausible deniability." For example, having character names as variables could be justified as "well, we originally wanted to have the player provide the character names, but changed our mind later on." It'd be hard for anyone to prove otherwise.

But, yes, having a game that already includes all the banned content and just has it "switched off" via a true/false flag of any mechanism definitely exposes you if somebody with a moral mindset decides to decompile your game and then turn you in to the Patreon Police.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,787
deniability." For example, having character names as variables could be justified as "well, we originally wanted to have the player provide the character names, but changed our mind later on." It'd be hard for anyone to prove otherwise.
Same for the relationship. You weren't sure what will works the best, landlady, friend of MC's mother, mother of MC's friend, girlfriend, friend, roommate... So you used a variable to be able to easily change everything if effectively you didn't picked the best option. Good luck if they want to prove otherwise.

On a side note, there's something that always amazed me. It's the devs who use "sis" or "mom" in their variable names. Whatever how they'll patch the game, the obvious is obvious.
 
  • Like
Reactions: Phlexxx and Rich

Rich

Old Fart
Modder
Respected User
Donor
Game Developer
Jun 25, 2017
2,461
6,925
The only way to effectively patch a game without being in violation of the said ToS is to use and/or . Simply because they are the only way to effectively change the code/text without having this change planned, in a way or another, in the original code.
The upcoming Ren'py 7.1.4 (in prerelease now) has a new option:
The config.allow_duplicate_labels variable can be defined or set in an init python block to allow duplicate labels to be defined in a game.


The documentation for this isn't up on the Ren'py site yet, but I would presume that this would allow you to override a label in a patch. (Probably, "last one loaded wins", using Ren'py's standard loading sequence.)
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,787
The upcoming Ren'py 7.1.4 (in prerelease now) has a new option:

The config.allow_duplicate_labels variable can be defined or set in an init python block to allow duplicate labels to be defined in a game.
I understand how it can be useful for patches, and so why you mentioned it, but I fail to understand why PyTom added it. There's already a virtual flag for this, config.developer. If it's value is False, Ren'py will not complain about duplicated labels and probably use the last one loaded ; therefore, it will do what I suppose being the meaning of this new configuration variable.
This while the config.label_overrides offer a more precise control since the label used can be changed at any time during the game.

It can also do more than just patch. I don't think that it's used in one of the game available here, but you can have something like :
Python:
label start:

    [...]

    menu:
        "Easy game":
            $ config.label_overrides["dayUpdate"] = "easyDayUpdate"
        "Regular game":
            $ config.label_overrides["dayUpdate"] = "regularDayUpdate"
        "Hard game":
            pass
    [...]

    "Time to sleep."
    call dayUpdate
    [...]
which is easier than something like :
Python:
label start:

    [...]

    menu:
        "Easy game":
            $ gameLevel = 0
        "Regular game":
            $ gameLevel = 1
        "Hard game":
            $ gameLevel = 2
    [...]

    "Time to sleep."
    if gameLevel == 0:
        call easyDayUpdate
    elif gameLevel == 1:
        call regularDayUpdate
    else:
        call dayUpdate
    [...]
especially if dayUpdate is called from more than one place.

It can also works for the games with some scenes that change according to previous decision. Just redirect the label(s) when the decision is made, and you don't have to care about the decision when the time will come.
It's probably a good way to prevent the usual errors, like inverting the meaning of True and False because the decision was made few update ago and you don't remember correctly.
Same for games allowing to define the sex of the MC. Especially for a game like @Nottravis one. There's a female version planed, but for the future, so it can be easier to overrides the labels that imply many changes depending of MC's gender, than adding manual redirection each time that the game will jump/call the said scenes. All is done in a single place (where the player choice the gender) which mean less risk to forget something and more simplicity if a label is misnamed.
But I'm out of the subject I presume.
 

Nottravis

Sci-fi Smutress
Donor
Game Developer
Jun 3, 2017
5,132
27,262
I understand how it can be useful for patches, and so why you mentioned it, but I fail to understand why PyTom added it. There's already a virtual flag for this, config.developer. If it's value is False, Ren'py will not complain about duplicated labels and probably use the last one loaded ; therefore, it will do what I suppose being the meaning of this new configuration variable.
This while the config.label_overrides offer a more precise control since the label used can be changed at any time during the game.

It can also do more than just patch. I don't think that it's used in one of the game available here, but you can have something like :
Python:
label start:

    [...]

    menu:
        "Easy game":
            $ config.label_overrides["dayUpdate"] = "easyDayUpdate"
        "Regular game":
            $ config.label_overrides["dayUpdate"] = "regularDayUpdate"
        "Hard game":
            pass
    [...]

    "Time to sleep."
    call dayUpdate
    [...]
which is easier than something like :
Python:
label start:

    [...]

    menu:
        "Easy game":
            $ gameLevel = 0
        "Regular game":
            $ gameLevel = 1
        "Hard game":
            $ gameLevel = 2
    [...]

    "Time to sleep."
    if gameLevel == 0:
        call easyDayUpdate
    elif gameLevel == 1:
        call regularDayUpdate
    else:
        call dayUpdate
    [...]
especially if dayUpdate is called from more than one place.

It can also works for the games with some scenes that change according to previous decision. Just redirect the label(s) when the decision is made, and you don't have to care about the decision when the time will come.
It's probably a good way to prevent the usual errors, like inverting the meaning of True and False because the decision was made few update ago and you don't remember correctly.
Same for games allowing to define the sex of the MC. Especially for a game like @Nottravis one. There's a female version planed, but for the future, so it can be easier to overrides the labels that imply many changes depending of MC's gender, than adding manual redirection each time that the game will jump/call the said scenes. All is done in a single place (where the player choice the gender) which mean less risk to forget something and more simplicity if a label is misnamed.
But I'm out of the subject I presume.
Well damn...I was going to do it a much more long winded way! Admittedly, it wasn't something I had to worry about for several months yet but that's an aces tip. Thanks! :)
 

Rich

Old Fart
Modder
Respected User
Donor
Game Developer
Jun 25, 2017
2,461
6,925
I understand how it can be useful for patches, and so why you mentioned it, but I fail to understand why PyTom added it. There's already a virtual flag for this, config.developer.
Possibly people had requested the benefits of duplicate labels without necessarily enabling the developer console and all that comes with that.
 

LewdWriter

Newbie
Oct 11, 2018
19
4
Hi, so is there a guide on how to properly setup a game to be patched with forbidden content? I’m currently doing it with the flag but the content is all there. I wasn’t aware that this would also be against Patreon’s terms.
 
U

User_920791

Guest
Guest
Hi, so is there a guide on how to properly setup a game to be patched with forbidden content? I’m currently doing it with the flag but the content is all there. I wasn’t aware that this would also be against Patreon’s terms.
As long your variables and labels don't indicate that you are creating mechanisms to put prohibited content into the game, my suggestion (put all the "extra" content into additional labels, into a separate file, and use a variable to direct the game to those labels) can be used without problems.

The solution indicated by @anne O'nymous is also very simple to use (and more safe for sure):
Python:
#patch.rpy
define config.label_overrides = {'OLD_LABEL':'NEW_LABEL','start':'start_anika_mod','C_S1_label2':'C_S1_label2_anika_mod'}

label NEW_LABEL:
    ...

label start_anika_mod:
    ...

label C_S1_label2_anika_mod:
    ...
 
  • Like
Reactions: walfeds
U

User_920791

Guest
Guest
@Anika Factory thanks. So would this mean that the files with the new labels would be part of the base game or would I include all those as part of the patch?
All prohibited content must be included only in the patch file and this file must be distributed in a way that the file's authorship can not be related to you ( , for example).
 

khumak

Engaged Member
Oct 2, 2017
3,437
3,477
The upcoming Ren'py 7.1.4 (in prerelease now) has a new option:



The documentation for this isn't up on the Ren'py site yet, but I would presume that this would allow you to override a label in a patch. (Probably, "last one loaded wins", using Ren'py's standard loading sequence.)
I love the allow duplicate labels idea and in fact I was asking specifically about whether such a feature was available recently to make modding easier since then I might be able to set my mod up as a separate file, similar to a patch rather than having to modify the main game's script file. So that sort of feature could easily be explained as just making your game mod friendly if they questioned it.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,787
[...] since then I might be able to set my mod up as a separate file, similar to a patch rather than having to modify the main game's script file.
After thinking a lot about config.allow_duplicate_labels, I no more discuss its interest. It permit amazing things, one of them being the possibility to distribute updates with auto-install feature (works in progress). But if you need it to have your mods in separated files, then you missed the whole part of the thread where we were talking about .
Among other use, it's how my Extended Variable Viewer add itself at the top of any games made with a version of Ren'py upper to 6.17.0 (included). It's also how many community made incest patches works. It's better to do it this way, because it don't overwrite the actual label, and so it permit to write mods that aren't just in separate files, but also compatible with most of the possible changes in the original code.

By example, to had the possibility to name the MC, you can do something like this :
script.rpy
Code:
mc = Character( "Alan" )

label start:
    "Welcome to my game. You'll play as [mc.name]."
    [...]
patch.rpy
Code:
init python:
    config.label_overrides["start"] = "myStart"
    config.label_overrides["startOUT"] = "start"

label myStart:
    mc.name = input( "Name of the MC" ).strip()
    jump startOUT
Doing the same with config.allow_duplicate_labels imply that you'll have to copy the whole code of the "start" label, and make a previous version of your mod incompatible in case there's change in this label. This while the use of config.label_overrides make you just inject your own code at the beginning of the label. Therefore, whatever the change in the said label, your mod will works correctly without reverting the game to a previous version. And it's the main interest of having the mod in separated files.
 

khumak

Engaged Member
Oct 2, 2017
3,437
3,477
After thinking a lot about config.allow_duplicate_labels, I no more discuss its interest. It permit amazing things, one of them being the possibility to distribute updates with auto-install feature (works in progress). But if you need it to have your mods in separated files, then you missed the whole part of the thread where we were talking about .
Among other use, it's how my Extended Variable Viewer add itself at the top of any games made with a version of Ren'py upper to 6.17.0 (included). It's also how many community made incest patches works. It's better to do it this way, because it don't overwrite the actual label, and so it permit to write mods that aren't just in separate files, but also compatible with most of the possible changes in the original code.

By example, to had the possibility to name the MC, you can do something like this :
script.rpy
Code:
mc = Character( "Alan" )

label start:
    "Welcome to my game. You'll play as [mc.name]."
    [...]
patch.rpy
Code:
init python:
    config.label_overrides["start"] = "myStart"
    config.label_overrides["startOUT"] = "start"

label myStart:
    mc.name = input( "Name of the MC" ).strip()
    jump startOUT
Doing the same with config.allow_duplicate_labels imply that you'll have to copy the whole code of the "start" label, and make a previous version of your mod incompatible in case there's change in this label. This while the use of config.label_overrides make you just inject your own code at the beginning of the label. Therefore, whatever the change in the said label, your mod will works correctly without reverting the game to a previous version. And it's the main interest of having the mod in separated files.
I couldn't figure out the syntax for config.allow_duplicate_labels but config.label_overrides worked great as a way to convert my mod to a separate file so I don't need to replace the script file anymore. Thanks for the config examples. I was hoping that the allow duplicate labels feature would allow me to do something like this:

Code:
init python:
    config.allow_duplicate_labels = True
Instead of this:

Code:
init python:
    config.label_overrides["vanilla_event_1"] = "mod_vanilla_event_1"
<long list of events 1-n>
    config.label_overrides["vanilla_event_n"] = "mod_vanilla_event_n"
But the 2nd method works fine. Just means having specific definitions renaming all of the events I'm changing instead of just replacing them with the original name intact.
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,787
I was hoping that the allow duplicate labels feature would allow me to do something like this:
Code:
init python:
    config.allow_duplicate_labels = True
It's more complicated than this. Since the files need to be parsed before the init blocks are played, it can't be defined at init time. It would be too late, the labels already have been parsed, and seen as duplicated, at this time.
Instead it must be defined at the early stage, like for user defined statements :
Code:
python early:
    config.allow_duplicate_labels = True
I assume that it's also better to put this in a file that will be treated early, so one starting with a number by example ; once again like for the user defined statements.


Just means having specific definitions renaming all of the events I'm changing instead of just replacing them with the original name intact.
If you follow a strict convention for the names, you can simplify it a little :
Code:
init python:
    myLabels = [ "vanilla_event_1", "vanilla_event_x", "vanilla_event_n" ]
    for lbl in myLabels:
        config.label_overrides[lbl] = "modded_{}".format( lbl )
You can even define the list directly in the for line, but it would create a really long and not necessarily easy to understood, line.
 

Porcus Dev

Engaged Member
Game Developer
Oct 12, 2017
2,582
4,686
After thinking a lot about config.allow_duplicate_labels, I no more discuss its interest. It permit amazing things, one of them being the possibility to distribute updates with auto-install feature (works in progress). But if you need it to have your mods in separated files, then you missed the whole part of the thread where we were talking about .
Among other use, it's how my Extended Variable Viewer add itself at the top of any games made with a version of Ren'py upper to 6.17.0 (included). It's also how many community made incest patches works. It's better to do it this way, because it don't overwrite the actual label, and so it permit to write mods that aren't just in separate files, but also compatible with most of the possible changes in the original code.

By example, to had the possibility to name the MC, you can do something like this :
script.rpy
Code:
mc = Character( "Alan" )

label start:
    "Welcome to my game. You'll play as [mc.name]."
    [...]
patch.rpy
Code:
init python:
    config.label_overrides["start"] = "myStart"
    config.label_overrides["startOUT"] = "start"

label myStart:
    mc.name = input( "Name of the MC" ).strip()
    jump startOUT
Doing the same with config.allow_duplicate_labels imply that you'll have to copy the whole code of the "start" label, and make a previous version of your mod incompatible in case there's change in this label. This while the use of config.label_overrides make you just inject your own code at the beginning of the label. Therefore, whatever the change in the said label, your mod will works correctly without reverting the game to a previous version. And it's the main interest of having the mod in separated files.
I'm trying to use this method but... I have a serious problem that I hope may have some solution.

The "config.label_overides" function works perfectly, but what about the translation? Is there any way to take advantage of the translation already done and that renpy generates new lines only where it finds differences? :unsure:

Thanks in advance :)
 

anne O'nymous

I'm not grumpy, I'm just coded that way.
Modder
Respected User
Donor
Jun 10, 2017
10,110
14,787
The "config.label_overides" function works perfectly, but what about the translation? Is there any way to take advantage of the translation already done and that renpy generates new lines only where it finds differences? :unsure:
Alright... All that I'll say is theoretical and just quickly validated once, so you need to stay careful and test deeply before using this for a release :

The translations are split in directories and files, only to ease the works ; one directory by language, one translation file by code file, and this way you find what you're looking for very easily.
But the translation is done by the use of basic statements :
Code:
translate LANGUAGE REFERENCE:
     SAYER "TRANSLATED TEXT"
And like for any other statements of the Ren'py's languages, they can be (almost) anywhere you want. Ren'py let us do bad things like creating a "game/scripts/I/want/a/deep/path/my strange file.rpy" that will contain things like :
Code:
label whatever:
    [...]
    label whatever.inner:
         default myVar = "its value"
         screen myScreen:
              [...]
and it will not complain that the default statement and the screen definition aren't at all at their place.

The exact same logic apply with translation. If you want to have a single file, named "apoifdfscxmklhdf.rpy", put directly in the "game" folder, and that will contain all the translations for all the supported languages, you can.
Therefore, there's nothing preventing you to have :
  • tl
    • whatever
      • script.rpy
      • update1.rpy
      • update2.rpy
Like there's nothing preventing you to have "tl/whatever/update1.rpy" in a different rpa file than "tl/whatever/update2.rpy".

BUT, like I said, I just tested it once since I never really had to works on translation. So, I don't guaranty this a 100%, I perhaps missed something.
 
  • Like
Reactions: Porcus Dev

Porcus Dev

Engaged Member
Game Developer
Oct 12, 2017
2,582
4,686
Alright... All that I'll say is theoretical and just quickly validated once, so you need to stay careful and test deeply before using this for a release :

The translations are split in directories and files, only to ease the works ; one directory by language, one translation file by code file, and this way you find what you're looking for very easily.
But the translation is done by the use of basic statements :
Code:
translate LANGUAGE REFERENCE:
     SAYER "TRANSLATED TEXT"
And like for any other statements of the Ren'py's languages, they can be (almost) anywhere you want. Ren'py let us do bad things like creating a "game/scripts/I/want/a/deep/path/my strange file.rpy" that will contain things like :
Code:
label whatever:
    [...]
    label whatever.inner:
         default myVar = "its value"
         screen myScreen:
              [...]
and it will not complain that the default statement and the screen definition aren't at all at their place.

The exact same logic apply with translation. If you want to have a single file, named "apoifdfscxmklhdf.rpy", put directly in the "game" folder, and that will contain all the translations for all the supported languages, you can.
Therefore, there's nothing preventing you to have :
  • tl
    • whatever
      • script.rpy
      • update1.rpy
      • update2.rpy
Like there's nothing preventing you to have "tl/whatever/update1.rpy" in a different rpa file than "tl/whatever/update2.rpy".

BUT, like I said, I just tested it once since I never really had to works on translation. So, I don't guaranty this a 100%, I perhaps missed something.
Thanks for your explanation anne O'nymous , but this isn't exactly my problem :p
(Now that you say it, I have to take into account how to add the translation of the "patch" later, next to the patch, but as you said, I already thought that it could be anywhere, or create it inside the folder "tl")

No... my problem is this:

Inside meg.rpy:
Code:
label meg_intro:
    scene black with fade
    pause 0.5
    "Mientras tanto, en un lejano pueblo..."
     .........
The translation generated by renpy is (meg.rpy inside "tl/english" folder):
Code:
# game/scripts/meg.rpy:4
translate english meg_intro_b472194a:

    # "Mientras tanto, en un lejano pueblo..."
    "Meanwhile, in a small town far away..."
Inside patch.rpy:
Code:
init python:
    config.label_overrides["meg_intro"] = "meg_intro_p"

label meg_intro_p:
    scene black with fade
    pause 0.5
    "Mientras tanto, en un lejano pueblo..."
     ..............................
Renpy generates a new translation, like this (patch.rpy inside "tl/english" folder):
Code:
# game/patch.rpy:7
translate english meg_intro_p_b472194a:

    # "Mientras tanto, en un lejano pueblo..."
    ""
How can I avoid that?
Note: If I don't generate the translation (tl/english/script.rpy) the Spanish text appears.

I know that the difference is that in the translation script there is different name of the label, "meg_intro" or "meg_intro_p"... is there any way for renpy to notice if the text is the same instead of the label name? (I seem to remember that in the menu options it does, I'm not sure).
Would it be as easy as completely removing the reference to the label name?
Or maybe generate the translation ("tl/english/patch.rpy"), make a copy/paste of the other translation ("tl/english/meg.rpy") and make a substitution of the label "meg_intro" for "meg_intro_p"?
I think this last option would work, but if there's any easier one I'd like to know :p


Thank you very much! ;)


Note: Could it be easier using the new function "config.allow_duplicate_labels"? :unsure:
(anyway, I would prefer not to have to change renpy version... are not going to start failing other things :eek::ROFLMAO::ROFLMAO::ROFLMAO:)