Compare commits
13 Commits
Author | SHA1 | Date | |
---|---|---|---|
7dc663a170 | |||
f872b4e49c | |||
ca5d70a5f9 | |||
ee9c504d1c | |||
127eadcb89 | |||
a7808a20ed | |||
3bdb88d918 | |||
aa79c70bf9 | |||
a089aab53e | |||
dafd85c39f | |||
b1d6a7c0fc | |||
e4b3ef63b7 | |||
86ca320cb9 |
19
LICENSE
Normal file
19
LICENSE
Normal file
@ -0,0 +1,19 @@
|
||||
Copyright 2017 Discord, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
@ -24,6 +24,8 @@ function.
|
||||
Download a release package, extract it, add `/include` to your compile includes, `/lib` to your
|
||||
linker paths, and link with `discord-rpc`.
|
||||
|
||||
Note that the release packages were compiled using Visual Studio 2015, so the [Visual C++ Redistributable for VS2015](https://www.microsoft.com/en-us/download/details.aspx?id=48145) will be a requirement for your game. If you wish to avoid this dependency, you should compile the libraries yourself using whatever dependencies are already in your game.
|
||||
|
||||
### From repo
|
||||
|
||||
There's a [CMake](https://cmake.org/download/) file that should be able to generate the lib for
|
||||
|
@ -56,7 +56,9 @@ Below is a full example of a `SET_ACTIVITY` command. Field restrictions like siz
|
||||
|
||||
## New RPC Events
|
||||
|
||||
The two new RPC events for Rich Presence power the ability to join and spectate your friends' games. First is the `GAME_JOIN` event:
|
||||
The three new RPC events for Rich Presence power the ability to join and spectate your friends' games.
|
||||
|
||||
First is the `ACTIVITY_JOIN` event:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -64,11 +66,11 @@ The two new RPC events for Rich Presence power the ability to join and spectate
|
||||
"data": {
|
||||
"secret": "025ed05c71f639de8bfaa0d679d7c94b2fdce12f"
|
||||
},
|
||||
"evnt": "GAME_JOIN"
|
||||
"evnt": "ACTIVITY_JOIN"
|
||||
}
|
||||
```
|
||||
|
||||
And second is the `GAME_SPECTATE` event:
|
||||
Second is the `ACTIVITY_SPECTATE` event:
|
||||
|
||||
```json
|
||||
{
|
||||
@ -76,7 +78,25 @@ And second is the `GAME_SPECTATE` event:
|
||||
"data": {
|
||||
"secret": "e7eb30d2ee025ed05c71ea495f770b76454ee4e0"
|
||||
},
|
||||
"evnt": "GAME_SPECTATE"
|
||||
"evnt": "ACTIVITY_SPECTATE"
|
||||
}
|
||||
```
|
||||
|
||||
And third is the `ACTIVITY_JOIN_REQUEST` event:
|
||||
|
||||
```json
|
||||
{
|
||||
"cmd": "DISPATCH",
|
||||
"data": {
|
||||
"user": {
|
||||
"id": "53908232506183680",
|
||||
"username": "Mason",
|
||||
"discriminator": "1337",
|
||||
"avatar": "a_bab14f271d565501444b2ca3be944b25"
|
||||
},
|
||||
"secret": "e459ca99273f59909dd16ed97865f3ad"
|
||||
},
|
||||
"evnt": "ACTIVITY_JOIN_REQUEST"
|
||||
}
|
||||
```
|
||||
|
||||
@ -85,7 +105,7 @@ In order to receive these events, you need to [subscribe](https://discordapp.com
|
||||
```json
|
||||
{
|
||||
"nonce": "be9a6de3-31d0-4767-a8e9-4818c5690015",
|
||||
"evt": "GAME_JOIN",
|
||||
"evt": "ACTIVITY_JOIN",
|
||||
"cmd": "SUBSCRIBE"
|
||||
}
|
||||
```
|
||||
@ -93,7 +113,15 @@ In order to receive these events, you need to [subscribe](https://discordapp.com
|
||||
```json
|
||||
{
|
||||
"nonce": "ae9qdde3-31d0-8989-a8e9-dnakwy174he",
|
||||
"evt": "GAME_SPECTATE",
|
||||
"evt": "ACTIVITY_SPECTATE",
|
||||
"cmd": "SUBSCRIBE"
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"nonce": "5dc0c062-98c6-47a0-8922-bbb52e9d6afa",
|
||||
"evt": "ACTIVITY_JOIN_REQUEST",
|
||||
"cmd": "SUBSCRIBE"
|
||||
}
|
||||
```
|
||||
|
@ -1,6 +1,16 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class DiscordController : MonoBehaviour {
|
||||
[System.Serializable]
|
||||
public class DiscordJoinEvent : UnityEngine.Events.UnityEvent<string> { }
|
||||
|
||||
[System.Serializable]
|
||||
public class DiscordSpectateEvent : UnityEngine.Events.UnityEvent<string> { }
|
||||
|
||||
[System.Serializable]
|
||||
public class DiscordJoinRequestEvent : UnityEngine.Events.UnityEvent<DiscordRpc.JoinRequest> { }
|
||||
|
||||
public class DiscordController : MonoBehaviour
|
||||
{
|
||||
public DiscordRpc.RichPresence presence;
|
||||
public string applicationId;
|
||||
public string optionalSteamId;
|
||||
@ -8,6 +18,9 @@ public class DiscordController : MonoBehaviour {
|
||||
public int clickCounter;
|
||||
public UnityEngine.Events.UnityEvent onConnect;
|
||||
public UnityEngine.Events.UnityEvent onDisconnect;
|
||||
public DiscordJoinEvent onJoin;
|
||||
public DiscordJoinEvent onSpectate;
|
||||
public DiscordJoinRequestEvent onJoinRequest;
|
||||
|
||||
DiscordRpc.EventHandlers handlers;
|
||||
|
||||
@ -45,21 +58,32 @@ public class DiscordController : MonoBehaviour {
|
||||
{
|
||||
++callbackCalls;
|
||||
Debug.Log(string.Format("Discord: join ({0})", secret));
|
||||
onJoin.Invoke(secret);
|
||||
}
|
||||
|
||||
public void SpectateCallback(string secret)
|
||||
{
|
||||
++callbackCalls;
|
||||
Debug.Log(string.Format("Discord: spectate ({0})", secret));
|
||||
onSpectate.Invoke(secret);
|
||||
}
|
||||
|
||||
void Start () {
|
||||
public void RequestCallback(DiscordRpc.JoinRequest request)
|
||||
{
|
||||
++callbackCalls;
|
||||
Debug.Log(string.Format("Discord: join request {0}: {1}", request.username, request.userId));
|
||||
onJoinRequest.Invoke(request);
|
||||
}
|
||||
|
||||
void Update () {
|
||||
|
||||
void Start()
|
||||
{
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
DiscordRpc.RunCallbacks();
|
||||
}
|
||||
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Debug.Log("Discord: init");
|
||||
@ -71,6 +95,7 @@ public class DiscordController : MonoBehaviour {
|
||||
handlers.errorCallback += ErrorCallback;
|
||||
handlers.joinCallback += JoinCallback;
|
||||
handlers.spectateCallback += SpectateCallback;
|
||||
handlers.requestCallback += RequestCallback;
|
||||
DiscordRpc.Initialize(applicationId, ref handlers, true, optionalSteamId);
|
||||
}
|
||||
|
||||
@ -82,6 +107,6 @@ public class DiscordController : MonoBehaviour {
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,9 @@ public class DiscordRpc
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void SpectateCallback(string secret);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void RequestCallback(JoinRequest request);
|
||||
|
||||
public struct EventHandlers
|
||||
{
|
||||
public ReadyCallback readyCallback;
|
||||
@ -24,6 +27,7 @@ public class DiscordRpc
|
||||
public ErrorCallback errorCallback;
|
||||
public JoinCallback joinCallback;
|
||||
public SpectateCallback spectateCallback;
|
||||
public RequestCallback requestCallback;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
@ -46,6 +50,21 @@ public class DiscordRpc
|
||||
public bool instance;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public struct JoinRequest
|
||||
{
|
||||
public string userId;
|
||||
public string username;
|
||||
public string avatar;
|
||||
}
|
||||
|
||||
public enum Reply
|
||||
{
|
||||
No = 0,
|
||||
Yes = 1,
|
||||
Ignore = 2
|
||||
}
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId);
|
||||
|
||||
@ -57,5 +76,8 @@ public class DiscordRpc
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_UpdatePresence", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void UpdatePresence(ref RichPresence presence);
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_Respond", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Respond(string userId, Reply reply);
|
||||
}
|
||||
|
||||
|
Binary file not shown.
@ -703,6 +703,21 @@ MonoBehaviour:
|
||||
m_CallState: 2
|
||||
m_TypeName: UnityEngine.Events.UnityEvent, UnityEngine, Version=0.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=null
|
||||
onJoin:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: DiscordJoinEvent, Assembly-CSharp, Version=0.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=null
|
||||
onSpectate:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: DiscordJoinEvent, Assembly-CSharp, Version=0.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=null
|
||||
onJoinRequest:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_TypeName: DiscordJoinRequestEvent, Assembly-CSharp, Version=0.0.0.0, Culture=neutral,
|
||||
PublicKeyToken=null
|
||||
--- !u!4 &1929635630
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
|
@ -1 +1 @@
|
||||
m_EditorVersion: 2017.1.0f3
|
||||
m_EditorVersion: 2017.1.1f1
|
||||
|
@ -83,7 +83,7 @@ static void handleDiscordJoinRequest(const DiscordJoinRequest* request)
|
||||
char yn[4];
|
||||
printf("\nDiscord: join request from %s - %s - %s\n",
|
||||
request->username,
|
||||
request->avatarUrl,
|
||||
request->avatar,
|
||||
request->userId);
|
||||
do {
|
||||
printf("Accept? (y/n)");
|
||||
|
@ -42,9 +42,9 @@ typedef struct DiscordRichPresence {
|
||||
} DiscordRichPresence;
|
||||
|
||||
typedef struct DiscordJoinRequest {
|
||||
char userId[24];
|
||||
char username[48];
|
||||
char avatarUrl[128];
|
||||
const char* userId;
|
||||
const char* username;
|
||||
const char* avatar;
|
||||
} DiscordJoinRequest;
|
||||
|
||||
typedef struct DiscordEventHandlers {
|
||||
|
@ -30,6 +30,7 @@ if(WIN32)
|
||||
set(BASE_RPC_SRC ${BASE_RPC_SRC} connection_win.cpp discord_register_win.cpp)
|
||||
add_library(discord-rpc ${RPC_LIBRARY_TYPE} ${BASE_RPC_SRC})
|
||||
target_compile_options(discord-rpc PRIVATE /EHsc
|
||||
/MT
|
||||
/Wall
|
||||
/wd4100 # unreferenced formal parameter
|
||||
/wd4514 # unreferenced inline
|
||||
@ -60,7 +61,10 @@ if(UNIX)
|
||||
target_link_libraries(discord-rpc PUBLIC pthread)
|
||||
target_compile_options(discord-rpc PRIVATE
|
||||
-g
|
||||
-Weverything
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wpedantic
|
||||
-Werror
|
||||
-Wno-unknown-pragmas # pragma push thing doesn't work on clang
|
||||
-Wno-old-style-cast # it's fine
|
||||
-Wno-c++98-compat # that was almost 2 decades ago
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
#include "backoff.h"
|
||||
#include "discord_register.h"
|
||||
#include "msg_queue.h"
|
||||
#include "rpc_connection.h"
|
||||
#include "serialization.h"
|
||||
#include "msg_queue.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
@ -32,6 +32,18 @@ struct QueuedMessage {
|
||||
}
|
||||
};
|
||||
|
||||
struct JoinRequest {
|
||||
// snowflake (64bit int), turned into a ascii decimal string, at most 20 chars +1 null
|
||||
// terminator = 21
|
||||
char userId[22];
|
||||
// 32 unicode glyphs is max name size => 4 bytes per glyph in the worst case, +1 for null
|
||||
// terminator = 129
|
||||
char username[130];
|
||||
// optional 'a_' + md5 hex digest (32 bytes) + null terminator = 35
|
||||
char avatar[36];
|
||||
// +1 on each because: it's even / I'm paranoid
|
||||
};
|
||||
|
||||
static RpcConnection* Connection{nullptr};
|
||||
static DiscordEventHandlers Handlers{};
|
||||
static std::atomic_bool WasJustConnected{false};
|
||||
@ -48,7 +60,7 @@ static char LastDisconnectErrorMessage[256];
|
||||
static std::mutex PresenceMutex;
|
||||
static QueuedMessage QueuedPresence{};
|
||||
static MsgQueue<QueuedMessage, MessageQueueSize> SendQueue;
|
||||
static MsgQueue<DiscordJoinRequest, JoinQueueSize> JoinAskQueue;
|
||||
static MsgQueue<JoinRequest, JoinQueueSize> JoinAskQueue;
|
||||
|
||||
// We want to auto connect, and retry on failure, but not as fast as possible. This does expoential
|
||||
// backoff from 0.5 seconds to 1 minute
|
||||
@ -71,7 +83,7 @@ static void UpdateReconnectTime()
|
||||
}
|
||||
|
||||
#ifdef DISCORD_DISABLE_IO_THREAD
|
||||
DISCORD_EXPORT void Discord_UpdateConnection(void)
|
||||
extern "C" DISCORD_EXPORT void Discord_UpdateConnection(void)
|
||||
#else
|
||||
static void Discord_UpdateConnection(void)
|
||||
#endif
|
||||
@ -136,16 +148,16 @@ static void Discord_UpdateConnection(void)
|
||||
auto user = GetObjMember(data, "user");
|
||||
auto userId = GetStrMember(user, "id");
|
||||
auto username = GetStrMember(user, "username");
|
||||
auto avatarUrl = GetStrMember(user, "avatar");
|
||||
auto avatar = GetStrMember(user, "avatar");
|
||||
auto joinReq = JoinAskQueue.GetNextAddMessage();
|
||||
if (userId && username && joinReq) {
|
||||
StringCopy(joinReq->userId, userId);
|
||||
StringCopy(joinReq->username, username);
|
||||
if (avatarUrl) {
|
||||
StringCopy(joinReq->avatarUrl, avatarUrl);
|
||||
if (avatar) {
|
||||
StringCopy(joinReq->avatar, avatar);
|
||||
}
|
||||
else {
|
||||
joinReq->avatarUrl[0] = 0;
|
||||
joinReq->avatar[0] = 0;
|
||||
}
|
||||
JoinAskQueue.CommitAdd();
|
||||
}
|
||||
@ -210,10 +222,10 @@ static bool RegisterForEvent(const char* evtName)
|
||||
return false;
|
||||
}
|
||||
|
||||
DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||
DiscordEventHandlers* handlers,
|
||||
int autoRegister,
|
||||
const char* optionalSteamId)
|
||||
extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||
DiscordEventHandlers* handlers,
|
||||
int autoRegister,
|
||||
const char* optionalSteamId)
|
||||
{
|
||||
if (autoRegister) {
|
||||
if (optionalSteamId && optionalSteamId[0]) {
|
||||
@ -267,7 +279,7 @@ DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
|
||||
#endif
|
||||
}
|
||||
|
||||
DISCORD_EXPORT void Discord_Shutdown()
|
||||
extern "C" DISCORD_EXPORT void Discord_Shutdown()
|
||||
{
|
||||
if (!Connection) {
|
||||
return;
|
||||
@ -285,7 +297,7 @@ DISCORD_EXPORT void Discord_Shutdown()
|
||||
RpcConnection::Destroy(Connection);
|
||||
}
|
||||
|
||||
DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence)
|
||||
extern "C" DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence)
|
||||
{
|
||||
PresenceMutex.lock();
|
||||
QueuedPresence.length = JsonWriteRichPresenceObj(
|
||||
@ -294,7 +306,7 @@ DISCORD_EXPORT void Discord_UpdatePresence(const DiscordRichPresence* presence)
|
||||
SignalIOActivity();
|
||||
}
|
||||
|
||||
DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply)
|
||||
extern "C" DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int reply)
|
||||
{
|
||||
// if we are not connected, let's not batch up stale messages for later
|
||||
if (!Connection || !Connection->IsOpen()) {
|
||||
@ -309,7 +321,7 @@ DISCORD_EXPORT void Discord_Respond(const char* userId, /* DISCORD_REPLY_ */ int
|
||||
}
|
||||
}
|
||||
|
||||
DISCORD_EXPORT void Discord_RunCallbacks()
|
||||
extern "C" DISCORD_EXPORT void Discord_RunCallbacks()
|
||||
{
|
||||
// Note on some weirdness: internally we might connect, get other signals, disconnect any number
|
||||
// of times inbetween calls here. Externally, we want the sequence to seem sane, so any other
|
||||
@ -353,7 +365,8 @@ DISCORD_EXPORT void Discord_RunCallbacks()
|
||||
while (JoinAskQueue.HavePendingSends()) {
|
||||
auto req = JoinAskQueue.GetNextSendMessage();
|
||||
if (Handlers.joinRequest) {
|
||||
Handlers.joinRequest(req);
|
||||
DiscordJoinRequest djr{req->userId, req->username, req->avatar};
|
||||
Handlers.joinRequest(&djr);
|
||||
}
|
||||
JoinAskQueue.CommitSend();
|
||||
}
|
||||
|
Reference in New Issue
Block a user