Ren'Py Discord Presence

Script with full support for Discord Rich Presence in Ren'Py projects

Discord Rich Presence is the info shown in player's Discord profile about the game they're playing. This script contains the discord namespace with functions that let creators interact with Rich Presence's informations.

The script doesn't hinder players that do not use Discord in any way!

It can be downloaded on the GitHub page. The button below will take you right to it!

    I'll include a simplified version of the Readme file containing instructions and examples below, but its entirety is on the GitHub page, better formatted, too!

    # Discord Rich Presence Support for Ren'Py Projects
    This script contains a discord namespace containing functions that interact with Discord Rich Presence. 
    Discord Rich Presence in the player's Playing a game status on Discord. The code is very intuitive and simple to use, but can only be run on Ren'Py 8, 
    as the module this script depends on doesn't have a Py2 version. That's okay though - I recommend you to update to Ren'Py 8 in any case!
    
    An Application set up on the Discord Developer Portal is required for every game supporting Rich Presence. 
    After the App is created, you will receive the necessary Application ID to insert into settings.rpy, and it is also where all the images
     you plan on displaying in the presence need to be uploaded first. 
    What it is and how to work with it is covered under the Wiki tab on this GitHub page, local copy of which is included in the code files.
    
    Finally, this project is under the MIT License. This means you can use, modify and/or distribute this script, as long as I am credited. 
    "Lezalith" is enough, but a link to my website with Ren'Py content, LezCave.com, is greatly appreciated! and as long as the LICENSE.txt file stays included.
    
    # Table of Contents:
    - Download of one of two versions of a Discord Rich Presence.
    - Variables that you need to check out before using this script.
    - Functions and Screen Actions that allow you to interact with the Discord Presence.
    - First part of the Rich Presence elements described, examples included.
    - Second part of the Rich Presence elements described, examples included.
    - Notes about compatibility and limitations.
    - Examples of using this script inside both screen and label.
    
    # Download
    To get the script, download one of the releases on the right side of the GitHub page, under the Releases section. 
    Here are the files that you need to put into your game folder:
    
    - python-packages folder contains the pypresence modules that handle everything Discord-related.
    - RenPy_Discord_Presence folder contains this script's files:
        - rich_presence.rpy holds the entire script's code.
        - settings.rpy contains the two Related Variables described below.
        - discord_developer_portal.md is a local copy of the Wiki tab, as already mentioned.
        - LICENSE.TXT, a file containing the MIT License that I ask you keep when downloading the files.
    
    There are two versions for every release:
    
    ## Project Version
    Project Version contains the whole code of this repository. It is a project that can be launched from the Ren'Py Launcher and that shows how simple it is
    to update the presence status from both screens and labels, utilizing the set and update functions and their screen actions counterparts, 
    both described below. Simply launch the project and keep an eye on your Discord profile.
    
    All of the code related to the project is located in its script.rpy file, with insignificants modifications to screens.rpy and gui.rpy.
    
    ## Clean Version
    Clean Version does not contain project files and only contains the files listed above, meaning you can just copy everything over to your own project 
    and you're good to go!
    
    # Related Variables
    There are some important variables in the settings.rpy file that you need to visit. Here is what they do:
    
    application_id takes a string with an Application ID of your Application set up on Discord Developer Portal. 
    This has to be set in order for this script to work, having an invalid ID set will throw an error when launching the game.
    
    main_menu_state takes a dictionary. Keys are strings of properties corresponding to presence elements, and values are their values.
    This is the state shown in the presence anytime the game launches and/or enters the main menu. Below is what it looks like by default.
    
    There's also the start_state. Just like main_menu_state, this is a set of properties, ones that are set when the game starts.
    Script acknowledges this by reaching the start label, name of which you need to set in the start_label variable. 
    It can also be a list of label names instead, in case you have multiple labels this game can Start at.
    
    Unlike main_menu_state, start_state doesn't have to be set, and start_label can be set to None to ignore its functionality.
    
    Finally, there are log variables controlling what is printed out. Prints are recorded in the game's console and in the log.txt file.
    I recommend leaving these on, it's information your players can pass on to you in case they're having troubles with your game. 
    
    # Interacting With The Presence
    ## Functions
    Functions used to interact with the presence are defined inside the discord namespace. They're meant to be used inside labels and init python blocks.
    Here are the core two:
    
    discord.set takes property names corresponding to presence elements for arguments. All elements are listed below.
    If some properties are already set in the presence, they are discarded and only the passed properties are kept.
    An exception to this is the start property, which sticks to time since this session's launch unless specified.
    
    discord.update takes property names for arguments the same way discord.set does.
    Difference between the two is that discord.update keeps the current properties as they are and only changes the ones provided.
    
    ## Screen Actions
    discord.set and discord.update have Screen Actions counterparts, intuitive alternatives to Function(discord.set) and Function(discord.update).
    
    Same rules apply for both Actions:
    
    - They are sensitive as long as Presence was successfully initialized.
    - They are selected if properties given to the Action inside the screen match currently shown properties. 
       Exception to this is start - if it's not specified inside the screen but is present in currently shown properties, 
       it is considered to be "start_time in the comparison.
    
    # Basic Rich Presence Elements
    There are many things that can be shown inside Rich Presence. Below is a screenshot of a couple elements of Rich Presence highlighted, 
    with their property name equivalent below. 
    All the property names are listed below the screenshot with a short example using discord.update.
    
    In the preview project, dictionary with all the properties for this example is stored in the discord.first_example variable,
    and discord.main_menu_state is redirected to it.
    
    details takes a string, and is the upper line of text shown in the Presence.
    
    state takes a string, and is the lower line of text shown in the Presence.
    
    large_image takes a string that needs to correspond with an image uploaded onto the Discord Application.
    It is the larger image shown on the left side. If it doesn't find an image with that name, it displays a placeholder question mark image.
    
    small_image takes a string that needs to correspond with an image uploaded onto the Discord Application. 
    It is the smaller image, shown at the bottom right of the large_image. Unlike large_image, if it doesn't find an image with that name it shows nothing.
    
    If no large_image is set or found, small_image is used in its place and no smaller image at the bottom right is shown.
    
    start is a time from which Time Elapsed is calculated. It can take four different values:
    
    - "start_time" makes Time Elapsed refer to the start_time variable, where time since this game session's launch is recorded.
    - "new_time" inserts a new unix timestamp, reseting Time Elapsed to 0:0. It does not overwrite the recorded start_time by itself, 
       but you can change that one directly if you need to for some reason.
    - None which results in Time Elapsed being hidden.
    - Unix timestamp from which Time Elapsed is calculated.
    
    If start is not specified in the properties displayed, it is always present with the value of "start_time". 
    
    As you can see, there are two more property names included there that I haven't mentioned - large_text and small_text. 
    These are text tooltips that appear when the respective images are hovered by a cursor.
    
    # Advanced Rich Presence Elements
    The final screenshot covers all the remaining rich presence properties. state was already covered above, however it is required for the party_size property to work.
    In the preview project, dictionary with all the properties for this example is stored in the discord.second_example variable.
    
    end takes an unix timestamp and calculates Time Left until that timestamp. 
    Setting this pushes start completely aside and Time Elapsed with it and displays Time Left instead.
    
    party_size takes a list of two ints. This is used for multiplayer games, where the two numbers represent the current party size and max party size respectively. 
    We can still use it with visual novels if we're creative enough.
    
    For the party_size to be visible, state has to be also provided.
    
    buttons takes a list of up to two dicts, and allows for buttons to be added into the Presence. 
    The dict consists of two keys, label being the text written inside the button, and url being the link opened upon clicking it. 
    
    # Important Notes
    ## Discord Not Installed
    Discord presence only works for users who have the Discord desktop application installed. For players that do not have Discord installed, 
    this entire code will simply do nothing. 
    discord namespace is still defined with all the properties and methods, but none of the methods do anything.
    
    This means that players who have Discord (or have it but aren't logged in) can enjoy the benefits while those who do not aren't hindered in any way.
    
    ## Saving, Loading and Rollback
    All presence properties are compatible with both saving games and rollbacking dialogue:
    
    - Loading a saved game will restore the properties that were present when the game was saved. 
    start possibly preserves the value of start_time and refers to time since starting this game session.
    - Rollbacking past a change in the presence will return the presence to the original state, as would be expected.
    
    ## Limitations
    ### config.label_callback Variable Taken
    This script uses the config.label_callback variable to set start_state, meaning you can't use it yourself. 
    If you're fine with start_state functionality not present, you can delete its define statement in rich_presence.rpy.
    
    This will be fixed with Ren'Py 8.1 - a new variable called config.label_callbacks will be present, one that can take multiple functions 
    just like all the other callbacks. The line is already prepared in the file, and I'll release an updated version of this script myself once Ren'Py 8.1 comes out.
    
    ### Update Delays
    A Discord Desktop Application running on the same machine as the game that's updating the presence, has updates on the player's profile shown instantly. 
    This is not always the case for other Discord Desktop Apps - even ones where the account of the player themselves are logged in, curiously enough.
    
    How often this delay occurs seems to correlate with the frequency of the presence updates and especially affects the clear method, 
    but you shouldn't worry about it too much, as it seems to be about 12s on average when it does occur.
    
    ### Too Many Connections
    Connecting to the Discord Rich Presence multiple times in quick succession will result in the connection not being established. In practice, this happens when you...
    
    - ...launch and quit...
    - ...reload...
    - ...start and return to the main menu in...
    
    ...the game too many (approximately 4) times too fast (span of approximately 40s).
    
    This makes the game unresponsive for the approximate span since the oldest successful connection. 
    Restarting the game doesn't fix this, and the game won't launch again until the timer runs out. 
    
    My guess is that it's a precaution against malicious exploits on Discord's part and cannot be affected by Python code, but as is the case with Update Delays 
    it's not a big issue - while possible for creators (especially through reloads), players should fulfill these requirements incredibly rarely, if ever.
    
    # Support
    If you need help setting up this script or the App on Discord's Dev Portal, you can contact me on Discord itself. Either write me a DM, Lezalith (LezCave.com)#2853, 
    or preferably join my server! It's a server dedicated to my website, LezCave.com, where I post Ren'Py scripts and tutorials. Come say hello!
    
    A good alternative is pinging me on the official Ren'Py Discord server, where I'm one of the Moderators, so I'm very active there. 
    You can send me an email at Lezalith@gmail.com if you want to be extra formal, but I don't check my emails very often. 
    Consider also letting me know on Discord that you've sent me one, so I notice it and can reply to it.
    
    Finally, if you want to be extra supportive, you can donate a dollar or two to my Paypal.me/Lezalith. 
    I'll use the money to manage my website and dedicate more time to posting new articles!