• Stars
    star
    105
  • Rank 316,772 (Top 7 %)
  • Language
    JavaScript
  • Created over 7 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An example using Discord's API and local RPC socket to add Voice and Text chat to an instance or match based multiplayer game.

Overview

Here you'll find an almost production grade sample of using Discord's API and local RPC socket to add Voice and Text chat to a match based multiplayer game.

There is also sample code that shows how to build a share feature that embeds an image (such as a screenshot from your game client) in a chat message, but this readme does not walk through it just yet :-)

These steps will be the same if you're using the GameBridge SDK, except you will connect to the RPC local to your game.

As far as effort goes, it should take about an afternoon to get a first cut going if you're roughly familiar with the underlying technologies. FWIW it took me about a day to build the first cut of this sample app.

This sample is basically two files that show the different parts of the workflow:

  • server/index.py for the server side
  • client/src/App.js for the client side

Good luck & have fun!

Additional Best Practices

This sample demonstrates a good workflow for using the Discord API & RPC but does not have the entirety of what represents production quality code. You should make sure to handle at minimum these scenarios if you're adapting this into your project:

  1. All HTTP requests from your game client to your game server could fail and should retry a few times.
  2. All HTTP requests to the Discord API backend from your game server or game client could fail and you should retry.
  3. All HTTP requests via the Discord RPC.Proxy (discordapp.io) could fail and you should retry a few times.

Sample Walkthrough

To implement match/instance based voice & text chat the basic workflow is as follows:

  • Connect to the local Discord RPC socket. Be sure to scan the available port range if you're working against a client. This is done in the connect() function in client/src/App.js. If you are using the SDK, the port will be provided in a callback.
  • Once connected:
    • Check if you have already authorized Discord for this user. To do this, you should return a valid Discord access_token when the user logs in to your game servers. The example /login endpoint in server/index.py shows what your login payload might return. Depending on the results...
    • if you don't have the user's access token: you need to get an RPC Token from Discord API to trade for a user's code. Retrive the RPC token as shown in the /discord_auth route in server/index.py. Then trade that rpc_token for a user's code by calling AUTHORIZE over the RPC socket as shown in App.js. Make sure to include the correct OAuth scopes that you intend to use. With the returned code, send it to your server and exchange it for the user's OAuth access and refresh tokens as shown in /discord_exchange_code. You should only do this flow the first time a user appears on your system.
    • if you ALREADY have the user's access token saved: you need to check if it has expired by comparing the current time with the Expiry you previously retrieved. If it has expired you need to refresh your access token as described here https://discordapp.com/developers/docs/topics/oauth2#implementing-oauth2. You can see an example of how this works in server/index.py by looking at the refresh_access_token helper function and where it is used.
  • Once you have the user's access_token in your game client, call AUTHENTICATE over the RPC socket as shown in client/src/App.js. If you get a success response then you're ready to go.
  • At this point your game will be connected to the local user's Discord account via the RPC system and ready to do work. If you are dev'ing against the Discord Client you'll see a clear indicator via a blue strip at the top of the window.
  • When a user joins a match, on your server, you should create a Discord Channel and put the user in it. Remember: be sure to do this lazily when a game user connects to a match and has Discord. Don't create a group along with your match. This will cause lots of empty Discord channels to be sitting around! Check out /join_match in server/index.py to see an example of lazy creating a channels and placing the user into it.
  • Send the new Discord channel id back to the client. This group will be the container for your match's voice & text chat functionality and used in many of the RPC calls.
  • On the client, now you can assume the channel is in the user's Direct Messages list and ready to go. Begin by making RPC calls to implement whatever features you want. In this sample we are joining the voice channel and connecting to text chat. You can see how this is done in the joinMatch() function in client/src/App.js.
  • One thing to note is when you subscribe to an event over the RPC you'll get messages sent to you as things happen in real time. Check out the handleDiscordRPCResponse() function in client/src/App.js to see an example of how to handle some of these events.

Sending Messages using the RPC Proxy

  • Sending messages from your game requires using the Discord RPC Proxy. Note that you can invoke almost any endpoint shown at http://discordapp.com/developers as if you were the user using this RPC.Proxy. For an example of how to send text messages as the user check out the onKeyUp() function in client/src/App.js.

Trying out this Sample

Creating a Discord Application

First up you'll need to create an application on Discord's platform. To do that head to https://discordapp.com/developers/applications/me and click the giant plus button.

To configure your application to manage channels properly do this stuff:

  • Set a fun name like Legend of the Apple Tree: Summary of Clouds.
  • You can set an app icon later. This will show up as the group icon on a user's Discord client. Eventually it will auto-populate a server icon if you make one instead.
  • For development purposes add the REDIRECT URI http://localhost:3006
  • For development purposes add the RPC ORIGIN http://localhost:3000
  • Click Save and you'll be whisked to your app's detail page.
  • Click Create a Bot User and accept the confirmation.
  • Uncheck Public Bot in the new APP BOT USER section.
  • Later on you'll need the Client ID, Secret from the APP DETAILS section. You'll also need the Token from the APP BOT USER section. Don't need to grab them now... just pointing it out :-)
  • You'll want to come back here to add other people to your tester list to have them try your game during development.

Be sure to click Save Changes again at the bottom of the page!

Installing the Sample Client

First you need to clone client/example.config.json and rename it to client/config.json then fill out your application's client ID found at https://discordapp.com/developers/applications/me. Only the Client ID should be set here. The other details will be set on the example server.

Installing the client requires only that you have node and npm installed. Then, to install project dependencies, from this project's root folder:

cd client
npm install

Installing the Sample Server

This is a little more involved but not crazy town.

First you need to clone server/example.cfg and rename it to server/discord.cfg then fill out your application's configuration fields found at https://discordapp.com/developers/applications/me. The Client ID and Secret are in the APP DETAILS section up top. The Token is in the APP BOT USER section.

Next you'll need to setup and install Flask, the web framework used by this sample. Detailed instructions are available here http://flask.pocoo.org/docs/0.11/installation/.

Be sure to activate your virtual environment then install the python packages in addition to flask. If you're feeling lazy it's basically this on MacOS from the project's root folder:

sudo pip install virtualenv
cd server
virtualenv client
. client/bin/activate
pip install -r requirements.txt

If you're on Windows, you'll have to follow the instructions on Flask's site. I haven't tried it :-)

Running the Sample Client

Open a Terminal / Shell window to keep running. From the project's root folder:

cd client
npm start

Running the Sample Server

Open a Terminal / Shell window to keep running. From the project's root folder:

cd server
. client/bin/activate
FLASK_DEBUG=1 FLASK_APP=index.py flask run

Note that if you called your virtualenv something different, you will need to use that instead. E.g., . venv/client/activate

More Repositories

1

discord-api-docs

Official Discord API Documentation
Markdown
5,543
star
2

lilliput

Resize images and animated GIFs in Go
C++
1,923
star
3

manifold

Fast batch message passing between nodes for Erlang/Elixir.
Elixir
1,618
star
4

sorted_set_nif

Elixir SortedSet backed by a Rust-based NIF
Elixir
1,532
star
5

discord-open-source

List of open source communities living on Discord
JavaScript
1,319
star
6

focus-rings

A centralized system for displaying and stylizing focus indicators anywhere on a webpage.
TypeScript
1,120
star
7

fastglobal

Fast no copy globals for Elixir & Erlang.
Elixir
1,097
star
8

discord-rpc

C++
983
star
9

airhornbot

The only bot for Discord you'll ever need.
TypeScript
851
star
10

semaphore

Fast semaphore using ETS.
Elixir
718
star
11

react-dnd-accessible-backend

An add-on backend for `react-dnd` that provides support for keyboards and screenreaders by default.
TypeScript
576
star
12

ex_hash_ring

A fast consistent hash ring implementation in Elixir.
Elixir
475
star
13

discord-example-app

Basic Discord app with examples
JavaScript
434
star
14

OverlappingPanels

Overlapping Panels is a gestures-driven navigation UI library for Android
Kotlin
420
star
15

SimpleAST

Extensible Android library for both parsing text into Abstract Syntax Trees and rendering those trees as rich text.
Kotlin
360
star
16

discord-interactions-js

JS/Node helpers for Discord Interactions
TypeScript
345
star
17

instruments

Simple and Fast metrics for Elixir
Elixir
295
star
18

focus-layers

Tiny React hooks for isolating focus within subsections of the DOM.
TypeScript
292
star
19

discord-api-spec

OpenAPI specification for Discord APIs
237
star
20

discord-oauth2-example

Discord OAuth2 Example
Python
225
star
21

loqui

RPC Transport Layer - with minimal bullshit.
Rust
220
star
22

erlpack

High Performance Erlang Term Format Packer
Cython
211
star
23

cloudflare-sample-app

Example discord bot using Cloudflare Workers
JavaScript
197
star
24

access

Access, a centralized portal for employees to transparently discover, request, and manage their access for all internal systems needed to do their jobs
Python
190
star
25

use-memo-value

Reuse the previous version of a value unless it has changed
TypeScript
170
star
26

zen_monitor

Efficient Process.monitor replacement
Elixir
167
star
27

deque

Fast bounded deque using two rotating lists.
Elixir
141
star
28

avatar-remix-bot

TypeScript
127
star
29

linked-roles-sample

JavaScript
119
star
30

punt

Punt is a tiny and lightweight daemon which helps ship logs to Elasticsearch.
Go
113
star
31

embedded-app-sdk

πŸš€ The Discord Embedded App SDK lets you build rich, multiplayer experiences as Activities inside Discord.
TypeScript
109
star
32

endanger

Build Dangerfiles with ease.
TypeScript
96
star
33

discord-interactions-python

Useful tools for building interactions in Python
Python
93
star
34

react-base-hooks

Basic utility React hooks
TypeScript
77
star
35

dynamic-pool

a lock-free, thread-safe, dynamically-sized object pool.
Rust
76
star
36

itsdangerous-rs

A rust port of itsdangerous!
Rust
72
star
37

gen_registry

Simple and efficient local Process Registry
Elixir
71
star
38

confetti-cannon

Launch Confetti
TypeScript
45
star
39

discord-react-forms

Forms... in React
JavaScript
43
star
40

discord-interactions-php

PHP utilities for building Discord Interaction webhooks
PHP
40
star
41

babel-plugin-define-patterns

Create constants that replace various expressions at build-time
JavaScript
39
star
42

eslint-traverse

Create a sub-traversal of an AST node in your ESLint plugin
JavaScript
30
star
43

rapidxml

Mirror of rapidxml from http://rapidxml.sourceforge.net/
C++
29
star
44

memory_size

Elixir
29
star
45

gamesdk-and-dispatch

Public issue tracker for the Discord Game SDK and Dispatch
22
star
46

dispenser

Elixir library to buffer and send events to subscribers.
Elixir
17
star
47

eslint-plugin-discord

Custom ESLint rules for Discord
JavaScript
16
star
48

chromium-build

Python
15
star
49

hash_ring

hash_ring
C
14
star
50

limited_queue

Simple Elixir queue, with a constant-time `size/1` and a maximum capacity
Elixir
13
star
51

perceptual

A smarter volume slider scale
TypeScript
13
star
52

discord_vigilante

12
star
53

heroku-sample-app

Example discord bot using Heroku
JavaScript
11
star
54

postcss-theme-shorthand

Converts `light-` and `dark-` prefixed CSS properties into corresponding light/dark theme globals
JavaScript
11
star
55

babel-plugin-strip-object-freeze

Replace all instances of Object.freeze(value) with value
JavaScript
10
star
56

libyuv

our fork of libyuv for webrtc
C++
10
star
57

lilliput-rs

Lilliput, in Rust!
Rust
9
star
58

lilliput-bench

Benchmarker for lilliput
Python
8
star
59

sqlite3

Mirror of sqlite amalgamation from https://www.sqlite.org/
C
7
star
60

openh264

C++
6
star
61

slate-react-package-fork

TypeScript
6
star
62

rlottiebinding-ios

rlottie ios submodule
Starlark
5
star
63

jemalloc_info

A small library for exporting jemalloc allocation data in Elixir
Elixir
5
star
64

libnice

Fork of https://nice.freedesktop.org/wiki/
C
5
star
65

libvpx

C
4
star
66

libsrtp

Fork of libsrtp
C
4
star
67

RLottieAndroid

C++
4
star
68

opentelemetry-rust-datadog

Rust
4
star
69

slate-package-fork

JavaScript
4
star
70

lilliput-dep-source

Convenient source repo for Lilliput's dependencies
3
star
71

slate-hotkeys-package-fork

3
star
72

rules_ios

Bazel rules for building iOS applications and frameworks
Starlark
2
star
73

cocoapods-bazel

A Cocoapods plugin for automatically generating Bazel BUILD files
Ruby
2
star
74

eslint-plugin-react-discord

Fork of eslint-plugin-react
JavaScript
1
star