Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rich Presence Extension #1832

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions docs/CubesterYT/RichPresence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Rich Presence
This extension allows you to use Rich Presence in your projects.

## Enabling Rich Presence

The Rich Presence SDK will be automatically downloaded and enabled when a project using the Rich Presence extension is put into the [TurboWarp Packager](https://packager.turbowarp.org/). You will need to select one of these environments:

## Basic Information

Remember that Rich Presence is only properly enabled when your project is packaged in a few specific environments. You can detect if this is the case using:

```scratch
<has rich presence support? :: #4D5057>
```

Then you can log in to the client using:

```scratch
set client id () and log in :: #4D5057
```

You can use this to fetch the current `client id`:

```scratch
(client id :: #4D5057)
```

## Presence Data

Presence Data is what is displayed when Rich Presence is active

Using this will allow you to set data to your Rich Presence:

```scratch
set [details v] to () :: #4D5057
```

It has these menu options:
- `details`: Specify the details of the activity (Ex. "Traveling to Dango Land!")
- `state`: Specify the state of the activity (Ex. "Searching for Dangos")
- `large image key`: Specify the key of the image you want to display as the main image shown on the activity (Ex. "DangoCat" would be the name/key of an image you uploaded to Developer Assets)
- `large image text`: Specify the text that would display when hovering over the large image (Ex. "Dango Cat!")
- `small image key`: Same as `large image key` except this is for the smaller image that displays as a circle on the bottom right of the large image (Ex. "OdenDog" would be the name/key of the image you uploaded to Developer Assets)
- `small image text`: Same as `large image text` except this is for the small image (Ex. "Oden Dog!")
- `party size`: **[Must be an integer]** Displays next to `state` and specifies the current size of the party. It doesn't have to have anything to do with "parties", so it can be used in other cases (Ex. "2", could be used to say 2 dangos found)
- `party max`: **[Must be an integer]** Displays next to `party size` and specifies the max party size. Just like `party size`, it doesn't have to be used for "parties" only (Ex. "8", could be used to say 8 dangos total, together with `party size` and `state`, could say "Searching for Dangos (2 of 8)")
- `JSON`: Allows you to specify the JSON of the Presence Data yourself, so you can use other features not listed on your own. **[Note that `instance` will ALWAYS be overridden to be `false`]**

Using this will allow you to toggle a timestamp on your Rich Presence:

```scratch
turn timestamp [on v] :: #4D5057
```

Finally, this will allow you to fetch the current Presence Data:

```scratch
(rich presence data :: #4D5057)
```

## Setting the Presence

To set the Rich Presence, you first need to check if the client is ready to go, use this to check if it's ready:

```scratch
<is rich presence ready? :: #4D5057>
```

Once it's ready, use this to set the presence:

```scratch
update rich presence :: #4D5057
```

Every time you want to update the presence, run the above block. Here's an example script:

```scratch
when green flag clicked
if <has rich presence support? :: #4D5057> then
set client id (1234567890123456789) and log in :: #4D5057
set [details v] to [Hello World!] :: #4D5057
turn timestamp [on v] :: #4D5057
forever
if <is rich presence ready? :: #4d5057> then
update rich presence :: #4D5057
wait (4) seconds
```

The Rich Presence SDK has a rate limit of 5 requests per 20 seconds, so you need to roughly follow that. As such, 4 seconds is what we recommend as the minimum.
221 changes: 221 additions & 0 deletions extensions/CubesterYT/RichPresence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
// Name: Rich Presence
// ID: cubesterRichPresence
// Description: Adds rich presence support to your project.
// By: CubesterYT <https://scratch.mit.edu/users/CubesterYT/>
// License: MPL-2.0

// Version V.1.0.0

(function (Scratch) {
"use strict";

/* globals RPC */

const canUseRPC = typeof RPC !== "undefined";
const client = canUseRPC && new RPC.Client({ transport: "ipc" });

let clientID = "";
let clientData = {};
let clientReady = false;

if (canUseRPC) {
client.on("ready", () => {
clientReady = true;
});
}

class RichPresence {
getInfo() {
return {
id: "cubesterRichPresence",
name: "Rich Presence",
color1: "#4D5057",
docsURI: "https://extensions.turbowarp.org/CubesterYT/RichPresence",

blocks: [
{
opcode: "hasPresence",
text: Scratch.translate("has rich presence support?"),
blockType: Scratch.BlockType.BOOLEAN,
},
{
opcode: "setClientID",
text: Scratch.translate("set client id [ID] and log in"),
blockType: Scratch.BlockType.COMMAND,
arguments: {
ID: {
type: Scratch.ArgumentType.STRING,
defaultValue: "",
},
},
},
{
opcode: "clientID",
text: Scratch.translate("client id"),
blockType: Scratch.BlockType.REPORTER,
},

"---",

{
opcode: "setData",
text: Scratch.translate("set [DATA] to [INPUT]"),
blockType: Scratch.BlockType.COMMAND,
arguments: {
DATA: {
type: Scratch.ArgumentType.STRING,
menu: "DATA",
},
INPUT: {
type: Scratch.ArgumentType.STRING,
},
},
},
{
opcode: "setTimestamp",
text: "turn timestamp [TOGGLE]",
blockType: Scratch.BlockType.COMMAND,
arguments: {
TOGGLE: {
type: Scratch.ArgumentType.STRING,
menu: "TOGGLE",
},
},
},
{
opcode: "presenceData",
text: Scratch.translate("rich presence data"),
blockType: Scratch.BlockType.REPORTER,
},

"---",

{
opcode: "presenceReady",
text: Scratch.translate("is rich presence ready?"),
blockType: Scratch.BlockType.BOOLEAN,
},
{
opcode: "updatePresence",
text: Scratch.translate("update rich presence"),
blockType: Scratch.BlockType.COMMAND,
},
],
menus: {
DATA: {
acceptReporters: false,
items: [
{ text: Scratch.translate("details"), value: "details" },
{ text: Scratch.translate("state"), value: "state" },
{
text: Scratch.translate("large image key"),
value: "large image key",
},
{
text: Scratch.translate("large image text"),
value: "large image text",
},
{
text: Scratch.translate("small image key"),
value: "small image key",
},
{
text: Scratch.translate("small image text"),
value: "small image text",
},
{ text: Scratch.translate("party size"), value: "party size" },
{ text: Scratch.translate("party max"), value: "party max" },
"JSON",
],
},
TOGGLE: {
acceptReporters: false,
items: [
{ text: Scratch.translate("on"), value: "on" },
{ text: Scratch.translate("off"), value: "off" },
],
},
},
};
}

hasPresence() {
return canUseRPC;
}
setClientID(args) {
if (!canUseRPC) return;
args.ID = Scratch.Cast.toNumber(args.ID);
clientID = args.ID;
client.login({ clientID }).catch(console.error);
}
clientID() {
if (!canUseRPC) return "Rich Presence unavailable";
return clientID;
}
setData(args) {
if (!canUseRPC) return;
args.INPUT = Scratch.Cast.toString(args.INPUT);
switch (args.DATA) {
case "details":
clientData.details = args.INPUT;
break;
case "state":
clientData.state = args.INPUT;
break;
case "large image key":
clientData.largeImageKey = args.INPUT;
break;
case "large image text":
clientData.largeImageText = args.INPUT;
break;
case "small image key":
clientData.smallImageKey = args.INPUT;
break;
case "small image text":
clientData.smallImageText = args.INPUT;
break;
case "party size":
clientData.partySize = Scratch.Cast.toNumber(args.INPUT);
break;
case "party max":
clientData.partyMax = Scratch.Cast.toNumber(args.INPUT);
break;
case "JSON":
try {
clientData = JSON.parse(args.INPUT);
} catch (error) {}
break;
default:
return; // This shouldn't happen, but it's good to have.
}
}
setTimestamp(args) {
if (!canUseRPC) return;
switch (args.TOGGLE) {
case "on":
clientData.startTimestamp = Date.now();
break;
case "off":
clientData.startTimestamp = null;
break;
default:
return; // This shouldn't happen, but it's good to have.
}
}
presenceData() {
if (!canUseRPC) return "Rich Presence unavailable";
return JSON.stringify(clientData);
}
presenceReady() {
if (!canUseRPC) return false;
return clientReady;
}
updatePresence() {
if (!canUseRPC) return;
clientData.instance = false;
client.setActivity(clientData);
}
}

Scratch.extensions.register(new RichPresence());
})(Scratch);
1 change: 1 addition & 0 deletions extensions/extensions.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"veggiecan/LongmanDictionary",
"CubesterYT/TurboHook",
"Alestore/nfcwarp",
"CubesterYT/RichPresence",
"steamworks",
"itchio",
"gamejolt",
Expand Down
Loading