diff --git a/DiscordRPC.Example/Program.cs b/DiscordRPC.Example/Program.cs
index 84b13589..6dd49a02 100644
--- a/DiscordRPC.Example/Program.cs
+++ b/DiscordRPC.Example/Program.cs
@@ -1,4 +1,5 @@
-using DiscordRPC.Message;
+using DiscordRPC.Events;
+using DiscordRPC.Message;
using System;
using System.Text;
using System.Threading;
@@ -142,6 +143,8 @@ static void FullClientExample()
//Register to the events we care about. We are registering to everyone just to show off the events
+ client.OnAuthorize += OnAuthorize;
+
client.OnReady += OnReady; //Called when the client is ready to send presences
client.OnClose += OnClose; //Called when connection to discord is lost
client.OnError += OnError; //Called when discord has a error
@@ -159,7 +162,7 @@ static void FullClientExample()
client.OnJoinRequested += OnJoinRequested; //Called when someone else has requested to join this client.
//Before we send a initial presence, we will generate a random "game ID" for this example.
- // For a real game, this "game ID" can be a unique ID that your Match Maker / Master Server generates.
+ // For a real game, this "game ID" can be a unique ID that your Match Maker / Master Server generates.
// This is used for the Join / Specate feature. This can be ignored if you do not plan to implement that feature.
presence.Secrets = new Secrets()
{
@@ -192,7 +195,7 @@ static void FullClientExample()
client.SetSubscription(EventType.Join | EventType.Spectate | EventType.JoinRequest); //This will alert us if discord wants to join a game
//Set some new presence to tell Discord we are in a game.
- // If the connection is not yet available, this will be queued until a Ready event is called,
+ // If the connection is not yet available, this will be queued until a Ready event is called,
// then it will be sent. All messages are queued until Discord is ready to receive them.
client.SetPresence(presence);
@@ -209,14 +212,14 @@ static void MainLoop()
{
/*
* Enter a infinite loop, polling the Discord Client for events.
- * In game termonology, this will be equivalent to our main game loop.
+ * In game termonology, this will be equivalent to our main game loop.
* If you were making a GUI application without a infinite loop, you could implement
* this with timers.
*/
isRunning = true;
while (client != null && isRunning)
{
- //We will invoke the client events.
+ //We will invoke the client events.
// In a game situation, you would do this in the Update.
// Not required if AutoEvents is enabled.
//if (client != null && !client.AutoEvents)
@@ -270,9 +273,17 @@ static async void ReadyTaskExample()
#region Events
#region State Events
+ private static void OnAuthorize(object sender, AuthorizeMessage args)
+ {
+ //This is called after the user has authorized the application.
+
+ Console.WriteLine("On Authorize. Auth code: {0}", args.Code);
+
+ }
+
private static void OnReady(object sender, ReadyMessage args)
{
- //This is called when we are all ready to start receiving and sending discord events.
+ //This is called when we are all ready to start receiving and sending discord events.
// It will give us some basic information about discord to use in the future.
//DEBUG: Update the presence timestamp
@@ -304,7 +315,7 @@ private static void OnConnectionEstablished(object sender, ConnectionEstablished
}
private static void OnConnectionFailed(object sender, ConnectionFailedMessage args)
{
- //This is called when the client fails to establish a connection to discord.
+ //This is called when the client fails to establish a connection to discord.
// It can be assumed that Discord is unavailable on the supplied pipe.
Console.WriteLine("Pipe Connection Failed. Could not connect to pipe #{0}", args.FailedPipe);
isRunning = false;
@@ -337,11 +348,11 @@ private static void OnJoin(object sender, JoinMessage args)
/*
* This is called when the Discord Client wants to join a online game to play.
* It can be triggered from a invite that your user has clicked on within discord or from an accepted invite.
- *
+ *
* The secret should be some sort of encrypted data that will give your game the nessary information to connect.
* For example, it could be the Game ID and the Game Password which will allow you to look up from the Master Server.
* Please avoid using IP addresses within these fields, its not secure and defeats the Discord security measures.
- *
+ *
* This feature requires the RegisterURI to be true on the client.
*/
Console.WriteLine("Joining Game '{0}'", args.Secret);
@@ -351,11 +362,11 @@ private static void OnSpectate(object sender, SpectateMessage args)
{ /*
* This is called when the Discord Client wants to join a online game to watch and spectate.
* It can be triggered from a invite that your user has clicked on within discord.
- *
+ *
* The secret should be some sort of encrypted data that will give your game the nessary information to connect.
* For example, it could be the Game ID and the Game Password which will allow you to look up from the Master Server.
* Please avoid using IP addresses within these fields, its not secure and defeats the Discord security measures.
- *
+ *
* This feature requires the RegisterURI to be true on the client.
*/
Console.WriteLine("Spectating Game '{0}'", args.Secret);
@@ -368,10 +379,10 @@ private static void OnJoinRequested(object sender, JoinRequestMessage args)
* You should trigger a UI prompt to your user sayings 'X wants to join your game' with a YES or NO button. You can also get
* other information about the user such as their avatar (which this library will provide a useful link) and their nickname to
* make it more personalised. You can combine this with more API if you wish. Check the Discord API documentation.
- *
+ *
* Once a user clicks on a response, call the Respond function, passing the message, to respond to the request.
* A example is provided below.
- *
+ *
* This feature requires the RegisterURI to be true on the client.
*/
diff --git a/DiscordRPC/DiscordRpcClient.cs b/DiscordRPC/DiscordRpcClient.cs
index 80ac2a5d..ceeb9bde 100644
--- a/DiscordRPC/DiscordRpcClient.cs
+++ b/DiscordRPC/DiscordRpcClient.cs
@@ -41,7 +41,7 @@ public sealed class DiscordRpcClient : IDisposable
public int ProcessID { get; private set; }
///
- /// The maximum size of the message queue received from Discord.
+ /// The maximum size of the message queue received from Discord.
///
public int MaxQueueSize { get; private set; }
@@ -65,7 +65,7 @@ public ILogger Logger
private ILogger _logger;
///
- /// Indicates if the client will automatically invoke the events without having to be called.
+ /// Indicates if the client will automatically invoke the events without having to be called.
///
public bool AutoEvents { get; private set; }
@@ -126,6 +126,12 @@ public bool ShutdownOnly
#region Events
+ ///
+ /// Called when the discord client has received an Authorize response.
+ /// If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
+ ///
+ public event OnAuthorizeEvent OnAuthorize;
+
///
/// Called when the discord client is ready to send and receive messages.
/// If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
@@ -288,6 +294,11 @@ private void ProcessMessage(IMessage message)
if (message == null) return;
switch (message.Type)
{
+ case MessageType.Authorize:
+ if (OnAuthorize != null)
+ OnAuthorize.Invoke(this, message as AuthorizeMessage);
+ break;
+
//We got a update, so we will update our current presence
case MessageType.PresenceUpdate:
lock (_sync)
@@ -333,14 +344,14 @@ private void ProcessMessage(IMessage message)
//Resend our presence and subscription
SynchronizeState();
}
-
- if (OnReady != null)
+
+ if (OnReady != null)
OnReady.Invoke(this, message as ReadyMessage);
-
+
break;
case MessageType.Close:
- if (OnClose != null)
+ if (OnClose != null)
OnClose.Invoke(this, message as CloseMessage);
break;
@@ -366,9 +377,9 @@ private void ProcessMessage(IMessage message)
{
var sub = message as SubscribeMessage;
Subscription |= sub.Event;
- }
-
- if (OnSubscribe != null)
+ }
+
+ if (OnSubscribe != null)
OnSubscribe.Invoke(this, message as SubscribeMessage);
break;
@@ -413,6 +424,25 @@ private void ProcessMessage(IMessage message)
}
#endregion
+ ///
+ /// Used to authenticate a new client with your app. By default this pops up a modal in-app that asks the user to authorize access to your app.
+ ///
+ /// The OAuth2 application id.
+ /// The scopes to authorize.
+ public void Authorize(string clientID, params string[] scopes)
+ {
+ if (IsDisposed)
+ throw new ObjectDisposedException("Discord IPC Client");
+
+ if (connection == null)
+ throw new ObjectDisposedException("Connection", "Cannot initialize as the connection has been deinitialized");
+
+ if (!IsInitialized)
+ throw new UninitializedException();
+
+ connection.EnqueueCommand(new AuthorizeCommand { clientID = clientID, scopes = scopes });
+ }
+
///
/// Respond to a Join Request. All requests will timeout after 30 seconds.
/// Because of the 30 second timeout, it is recommended to call faster than every 15 seconds to give your users adequate time to respond to the request.
@@ -474,7 +504,7 @@ public void SetPresence(RichPresence presence)
}
//Update our local store
- lock (_sync)
+ lock (_sync)
{
CurrentPresence = presence?.Clone();
}
@@ -567,7 +597,7 @@ public RichPresence UpdateDetails(string details)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
presence.Details = details;
SetPresence(presence);
return presence;
@@ -590,7 +620,7 @@ public RichPresence UpdateState(string state)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
presence.State = state;
SetPresence(presence);
return presence;
@@ -613,7 +643,7 @@ public RichPresence UpdateParty(Party party)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
presence.Party = party;
SetPresence(presence);
return presence;
@@ -641,7 +671,7 @@ public RichPresence UpdatePartySize(int size)
if (presence.Party == null)
throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
- //Update the value
+ //Update the value
presence.Party.Size = size;
SetPresence(presence);
return presence;
@@ -671,7 +701,7 @@ public RichPresence UpdatePartySize(int size, int max)
if (presence.Party == null)
throw new BadPresenceException("Cannot set the size of the party if the party does not exist");
- //Update the value
+ //Update the value
presence.Party.Size = size;
presence.Party.Max = max;
SetPresence(presence);
@@ -696,7 +726,7 @@ public RichPresence UpdateLargeAsset(string key = null, string tooltip = null)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
if (presence.Assets == null) presence.Assets = new Assets();
presence.Assets.LargeImageKey = key ?? presence.Assets.LargeImageKey;
presence.Assets.LargeImageText = tooltip ?? presence.Assets.LargeImageText;
@@ -722,7 +752,7 @@ public RichPresence UpdateSmallAsset(string key = null, string tooltip = null)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
if (presence.Assets == null) presence.Assets = new Assets();
presence.Assets.SmallImageKey = key ?? presence.Assets.SmallImageKey;
presence.Assets.SmallImageText = tooltip ?? presence.Assets.SmallImageText;
@@ -748,7 +778,7 @@ public RichPresence UpdateSecrets(Secrets secrets)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
presence.Secrets = secrets;
SetPresence(presence);
return presence;
@@ -778,7 +808,7 @@ public RichPresence UpdateStartTime(DateTime time)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
if (presence.Timestamps == null) presence.Timestamps = new Timestamps();
presence.Timestamps.Start = time;
SetPresence(presence);
@@ -809,7 +839,7 @@ public RichPresence UpdateEndTime(DateTime time)
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
if (presence.Timestamps == null) presence.Timestamps = new Timestamps();
presence.Timestamps.End = time;
SetPresence(presence);
@@ -833,7 +863,7 @@ public RichPresence UpdateClearTime()
else { presence = CurrentPresence.Clone(); }
}
- //Update the value
+ //Update the value
presence.Timestamps = null;
SetPresence(presence);
return presence;
@@ -881,7 +911,7 @@ public bool RegisterUriScheme(string steamAppID = null, string executable = null
public void Subscribe(EventType type) { SetSubscription(Subscription | type); }
///
- ///
+ ///
///
///
[System.Obsolete("Replaced with Unsubscribe", true)]
@@ -925,7 +955,7 @@ public void SetSubscription(EventType type)
/// Represents if the unsubscribe payload should be sent instead.
private void SubscribeToTypes(EventType type, bool isUnsubscribe)
{
- //Because of SetSubscription, this can actually be none as there is no differences.
+ //Because of SetSubscription, this can actually be none as there is no differences.
//If that is the case, we should just stop here
if (type == EventType.None) return;
diff --git a/DiscordRPC/Events.cs b/DiscordRPC/Events.cs
index b28c7fec..bb484f23 100644
--- a/DiscordRPC/Events.cs
+++ b/DiscordRPC/Events.cs
@@ -6,6 +6,13 @@
namespace DiscordRPC.Events
{
+ ///
+ /// Called when the Discord Client has received an Authorize Response.
+ ///
+ /// The Discord client handler that sent this event
+ /// The arguments supplied with the event
+ public delegate void OnAuthorizeEvent(object sender, AuthorizeMessage args);
+
///
/// Called when the Discord Client is ready to send and receive messages.
///
diff --git a/DiscordRPC/Message/AuthorizeMessage.cs b/DiscordRPC/Message/AuthorizeMessage.cs
new file mode 100644
index 00000000..2907e565
--- /dev/null
+++ b/DiscordRPC/Message/AuthorizeMessage.cs
@@ -0,0 +1,35 @@
+using DiscordRPC.RPC.Commands;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace DiscordRPC.Message
+{
+ ///
+ /// Representation of the message received by discord when an authorization response has been received.
+ ///
+ public class AuthorizeMessage : IMessage
+ {
+ ///
+ /// The type of message received from discord
+ ///
+ public override MessageType Type { get { return MessageType.Authorize; } }
+
+ internal AuthorizeMessage(AuthorizeResponse auth)
+ {
+ if (auth == null)
+ {
+ Code = "";
+ }
+ else
+ {
+ Code = auth.Code;
+ }
+ }
+
+ ///
+ /// The OAuth2 authorization code
+ ///
+ public string Code { get; internal set; }
+ }
+}
diff --git a/DiscordRPC/Message/MessageType.cs b/DiscordRPC/Message/MessageType.cs
index 223291ee..41fe9be9 100644
--- a/DiscordRPC/Message/MessageType.cs
+++ b/DiscordRPC/Message/MessageType.cs
@@ -21,6 +21,11 @@ public enum MessageType
///
Error,
+ ///
+ /// The Discord Client received an authorize response.
+ ///
+ Authorize,
+
///
/// The Discord Client has updated the presence.
///
@@ -35,14 +40,14 @@ public enum MessageType
/// The Discord Client has unsubscribed from an event.
///
Unsubscribe,
-
+
///
/// The Discord Client wishes for this process to join a game.
///
Join,
///
- /// The Discord Client wishes for this process to spectate a game.
+ /// The Discord Client wishes for this process to spectate a game.
///
Spectate,
diff --git a/DiscordRPC/RPC/Commands/AuthorizeCommand.cs b/DiscordRPC/RPC/Commands/AuthorizeCommand.cs
new file mode 100644
index 00000000..de8dd069
--- /dev/null
+++ b/DiscordRPC/RPC/Commands/AuthorizeCommand.cs
@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using DiscordRPC.RPC.Payload;
+using Newtonsoft.Json;
+
+namespace DiscordRPC.RPC.Commands
+{
+ internal class AuthorizeCommand : ICommand
+ {
+ ///
+ /// OAuth2 application id
+ ///
+ [JsonProperty("client_id")]
+ public string clientID { get; set; }
+
+ ///
+ /// scopes to authorize
+ ///
+ [JsonProperty("scopes")]
+ public string[] scopes = { "identify" };
+
+ ///
+ /// scopes to authorize
+ ///
+ [JsonProperty("prompt")]
+ public string prompt = "none";
+
+ public IPayload PreparePayload(long nonce)
+ {
+ return new ArgumentPayload(this, nonce)
+ {
+ Command = Command.Authorize,
+ };
+ }
+ }
+
+ [JsonObject(MemberSerialization = MemberSerialization.OptIn)]
+ [Serializable]
+ internal class AuthorizeResponse
+ {
+ ///
+ /// The OAuth2 authorization code
+ ///
+ [JsonProperty("code")]
+ public string Code { get; set; }
+ }
+}
diff --git a/DiscordRPC/RPC/Payload/Command.cs b/DiscordRPC/RPC/Payload/Command.cs
index 1863fb14..24662347 100644
--- a/DiscordRPC/RPC/Payload/Command.cs
+++ b/DiscordRPC/RPC/Payload/Command.cs
@@ -50,7 +50,7 @@ internal enum Command
///
/// used to authorize a new client with your app
///
- [Obsolete("This value is appart of the RPC API and is not supported by this library.", true)]
+ [EnumValue("AUTHORIZE")]
Authorize,
///
diff --git a/DiscordRPC/RPC/RpcConnection.cs b/DiscordRPC/RPC/RpcConnection.cs
index fd8ea6a4..dba2d35c 100644
--- a/DiscordRPC/RPC/RpcConnection.cs
+++ b/DiscordRPC/RPC/RpcConnection.cs
@@ -52,10 +52,10 @@ public ILogger Logger
}
private ILogger _logger;
- ///
- /// Called when a message is received from the RPC and is about to be enqueued. This is cross-thread and will execute on the RPC thread.
- ///
- public event OnRpcMessageEvent OnRpcMessage;
+ ///
+ /// Called when a message is received from the RPC and is about to be enqueued. This is cross-thread and will execute on the RPC thread.
+ ///
+ public event OnRpcMessageEvent OnRpcMessage;
#region States
@@ -82,14 +82,14 @@ public RpcState State
private volatile bool aborting = false;
private volatile bool shutdown = false;
-
+
///
/// Indicates if the RPC connection is still running in the background
///
public bool IsRunning { get { return thread != null; } }
///
- /// Forces the to call instead, safely saying goodbye to Discord.
+ /// Forces the to call instead, safely saying goodbye to Discord.
/// This option helps prevents ghosting in applications where the Process ID is a host and the game is executed within the host (ie: the Unity3D editor). This will tell Discord that we have no presence and we are closing the connection manually, instead of waiting for the process to terminate.
///
public bool ShutdownOnly { get; set; }
@@ -109,12 +109,12 @@ public RpcState State
private int targetPipe; //The pipe to taget. Leave as -1 for any available pipe.
private readonly object l_rtqueue = new object(); //Lock for the send queue
- private readonly uint _maxRtQueueSize;
+ private readonly uint _maxRtQueueSize;
private Queue _rtqueue; //The send queue
private readonly object l_rxqueue = new object(); //Lock for the receive queue
- private readonly uint _maxRxQueueSize; //The max size of the RX queue
- private Queue _rxqueue; //The receive queue
+ private readonly uint _maxRxQueueSize; //The max size of the RX queue
+ private Queue _rxqueue; //The receive queue
private AutoResetEvent queueUpdatedEvent = new AutoResetEvent(false);
private BackoffDelay delay; //The backoff delay before reconnecting.
@@ -127,8 +127,8 @@ public RpcState State
/// The ID of the currently running process
/// The target pipe to connect too
/// The pipe client we shall use.
- /// The maximum size of the out queue
- /// The maximum size of the in queue
+ /// The maximum size of the out queue
+ /// The maximum size of the in queue
public RpcConnection(string applicationID, int processID, int targetPipe, INamedPipeClient client, uint maxRxQueueSize = 128, uint maxRtQueueSize = 512)
{
this.applicationID = applicationID;
@@ -141,16 +141,16 @@ public RpcConnection(string applicationID, int processID, int targetPipe, INamed
Logger = new ConsoleLogger();
delay = new BackoffDelay(500, 60 * 1000);
- _maxRtQueueSize = maxRtQueueSize;
+ _maxRtQueueSize = maxRtQueueSize;
_rtqueue = new Queue((int)_maxRtQueueSize + 1);
- _maxRxQueueSize = maxRxQueueSize;
- _rxqueue = new Queue((int)_maxRxQueueSize + 1);
-
+ _maxRxQueueSize = maxRxQueueSize;
+ _rxqueue = new Queue((int)_maxRxQueueSize + 1);
+
nonce = 0;
}
-
-
+
+
private long GetNextNonce()
{
nonce += 1;
@@ -163,25 +163,25 @@ private long GetNextNonce()
///
/// The command to enqueue
internal void EnqueueCommand(ICommand command)
- {
- Logger.Trace("Enqueue Command: {0}", command.GetType().FullName);
+ {
+ Logger.Trace("Enqueue Command: {0}", command.GetType().FullName);
- //We cannot add anything else if we are aborting or shutting down.
- if (aborting || shutdown) return;
+ //We cannot add anything else if we are aborting or shutting down.
+ if (aborting || shutdown) return;
//Enqueue the set presence argument
lock (l_rtqueue)
- {
- //If we are too big drop the last element
- if (_rtqueue.Count == _maxRtQueueSize)
- {
- Logger.Error("Too many enqueued commands, dropping oldest one. Maybe you are pushing new presences to fast?");
- _rtqueue.Dequeue();
- }
-
- //Enqueue the message
- _rtqueue.Enqueue(command);
- }
+ {
+ //If we are too big drop the last element
+ if (_rtqueue.Count == _maxRtQueueSize)
+ {
+ Logger.Error("Too many enqueued commands, dropping oldest one. Maybe you are pushing new presences to fast?");
+ _rtqueue.Dequeue();
+ }
+
+ //Enqueue the message
+ _rtqueue.Enqueue(command);
+ }
}
///
@@ -190,40 +190,40 @@ internal void EnqueueCommand(ICommand command)
/// The message to add
private void EnqueueMessage(IMessage message)
{
- //Invoke the message
- try
- {
- if (OnRpcMessage != null)
- OnRpcMessage.Invoke(this, message);
- }
- catch (Exception e)
- {
- Logger.Error("Unhandled Exception while processing event: {0}", e.GetType().FullName);
- Logger.Error(e.Message);
- Logger.Error(e.StackTrace);
- }
-
- //Small queue sizes should just ignore messages
- if (_maxRxQueueSize <= 0)
- {
- Logger.Trace("Enqueued Message, but queue size is 0.");
- return;
- }
-
- //Large queue sizes should keep the queue in check
- Logger.Trace("Enqueue Message: {0}", message.Type);
- lock (l_rxqueue)
- {
- //If we are too big drop the last element
- if (_rxqueue.Count == _maxRxQueueSize)
- {
- Logger.Warning("Too many enqueued messages, dropping oldest one.");
- _rxqueue.Dequeue();
- }
-
- //Enqueue the message
- _rxqueue.Enqueue(message);
- }
+ //Invoke the message
+ try
+ {
+ if (OnRpcMessage != null)
+ OnRpcMessage.Invoke(this, message);
+ }
+ catch (Exception e)
+ {
+ Logger.Error("Unhandled Exception while processing event: {0}", e.GetType().FullName);
+ Logger.Error(e.Message);
+ Logger.Error(e.StackTrace);
+ }
+
+ //Small queue sizes should just ignore messages
+ if (_maxRxQueueSize <= 0)
+ {
+ Logger.Trace("Enqueued Message, but queue size is 0.");
+ return;
+ }
+
+ //Large queue sizes should keep the queue in check
+ Logger.Trace("Enqueue Message: {0}", message.Type);
+ lock (l_rxqueue)
+ {
+ //If we are too big drop the last element
+ if (_rxqueue.Count == _maxRxQueueSize)
+ {
+ Logger.Warning("Too many enqueued messages, dropping oldest one.");
+ _rxqueue.Dequeue();
+ }
+
+ //Enqueue the message
+ _rxqueue.Enqueue(message);
+ }
}
///
@@ -231,9 +231,9 @@ private void EnqueueMessage(IMessage message)
///
///
internal IMessage DequeueMessage()
- {
- //Logger.Trace("Deque Message");
- lock (l_rxqueue)
+ {
+ //Logger.Trace("Deque Message");
+ lock (l_rxqueue)
{
//We have nothing, so just return null.
if (_rxqueue.Count == 0) return null;
@@ -244,13 +244,13 @@ internal IMessage DequeueMessage()
}
///
- /// Dequeues all messages from the event stack.
+ /// Dequeues all messages from the event stack.
///
///
internal IMessage[] DequeueMessages()
- {
- //Logger.Trace("Deque Multiple Messages");
- lock (l_rxqueue)
+ {
+ //Logger.Trace("Deque Multiple Messages");
+ lock (l_rxqueue)
{
//Copy the messages into an array
IMessage[] messages = _rxqueue.ToArray();
@@ -263,31 +263,31 @@ internal IMessage[] DequeueMessages()
}
}
#endregion
-
+
///
/// Main thread loop
///
private void MainLoop()
{
- //initialize the pipe
- Logger.Info("RPC Connection Started");
- if (Logger.Level <= LogLevel.Trace)
- {
- Logger.Trace("============================");
- Logger.Trace("Assembly: " + System.Reflection.Assembly.GetAssembly(typeof(RichPresence)).FullName);
- Logger.Trace("Pipe: " + namedPipe.GetType().FullName);
- Logger.Trace("Platform: " + Environment.OSVersion.ToString());
- Logger.Trace("applicationID: " + applicationID);
- Logger.Trace("targetPipe: " + targetPipe);
- Logger.Trace("POLL_RATE: " + POLL_RATE);
- Logger.Trace("_maxRtQueueSize: " + _maxRtQueueSize);
- Logger.Trace("_maxRxQueueSize: " + _maxRxQueueSize);
- Logger.Trace("============================");
- }
-
- //Forever trying to connect unless the abort signal is sent
- //Keep Alive Loop
- while (!aborting && !shutdown)
+ //initialize the pipe
+ Logger.Info("RPC Connection Started");
+ if (Logger.Level <= LogLevel.Trace)
+ {
+ Logger.Trace("============================");
+ Logger.Trace("Assembly: " + System.Reflection.Assembly.GetAssembly(typeof(RichPresence)).FullName);
+ Logger.Trace("Pipe: " + namedPipe.GetType().FullName);
+ Logger.Trace("Platform: " + Environment.OSVersion.ToString());
+ Logger.Trace("applicationID: " + applicationID);
+ Logger.Trace("targetPipe: " + targetPipe);
+ Logger.Trace("POLL_RATE: " + POLL_RATE);
+ Logger.Trace("_maxRtQueueSize: " + _maxRtQueueSize);
+ Logger.Trace("_maxRxQueueSize: " + _maxRxQueueSize);
+ Logger.Trace("============================");
+ }
+
+ //Forever trying to connect unless the abort signal is sent
+ //Keep Alive Loop
+ while (!aborting && !shutdown)
{
try
{
@@ -341,19 +341,19 @@ private void MainLoop()
break;
//We have pinged, so we will flip it and respond back with pong
- case Opcode.Ping:
+ case Opcode.Ping:
Logger.Trace("PING");
frame.Opcode = Opcode.Pong;
namedPipe.WriteFrame(frame);
break;
//We have ponged? I have no idea if Discord actually sends ping/pongs.
- case Opcode.Pong:
+ case Opcode.Pong:
Logger.Trace("PONG");
break;
//A frame has been sent, we should deal with that
- case Opcode.Frame:
+ case Opcode.Frame:
if (shutdown)
{
//We are shutting down, so skip it
@@ -378,13 +378,13 @@ private void MainLoop()
try { if (response != null) ProcessFrame(response); } catch(Exception e)
- {
+ {
Logger.Error("Failed to process event! {0}", e.Message);
Logger.Error("Data: {0}", frame.Message);
}
break;
-
+
default:
case Opcode.Handshake:
@@ -398,7 +398,7 @@ private void MainLoop()
}
if (!aborting && namedPipe.IsConnected)
- {
+ {
//Process the entire command queue we have left
ProcessCommandQueue();
@@ -475,7 +475,7 @@ private void ProcessFrame(EventPayload response)
{
//We have an error
Logger.Error("Error received from the RPC");
-
+
//Create the event objetc and push it to the queue
ErrorMessage err = response.GetObject();
Logger.Error("Server responded with an error message: ({0}) {1}", err.Code.ToString(), err.Message);
@@ -517,6 +517,11 @@ private void ProcessFrame(EventPayload response)
ProcessDispatch(response);
break;
+ case Command.Authorize:
+ AuthorizeResponse auth = response.GetObject();
+ EnqueueMessage(new AuthorizeMessage(auth));
+ break;
+
//We were sent a Activity Update, better enqueue it
case Command.SetActivity:
if (response.Data == null)
@@ -537,8 +542,8 @@ private void ProcessFrame(EventPayload response)
JsonSerializer serializer = new JsonSerializer();
serializer.Converters.Add(new Converters.EnumSnakeCaseConverter());
- //Go through the data, looking for the evt property, casting it to a server event
- var evt = response.GetObject().Event.Value;
+ //Go through the data, looking for the evt property, casting it to a server event
+ var evt = response.GetObject().Event.Value;
//Enqueue the appropriate message.
if (response.Command == Command.Subscribe)
@@ -547,8 +552,8 @@ private void ProcessFrame(EventPayload response)
EnqueueMessage(new UnsubscribeMessage(evt));
break;
-
-
+
+
case Command.SendActivityJoinInvite:
Logger.Trace("Got invite response ack.");
break;
@@ -556,7 +561,7 @@ private void ProcessFrame(EventPayload response)
case Command.CloseActivityJoinRequest:
Logger.Trace("Got invite response reject ack.");
break;
-
+
//we have no idea what we were sent
default:
Logger.Error("Unkown frame was received! {0}", response.Command);
@@ -565,7 +570,7 @@ private void ProcessFrame(EventPayload response)
return;
}
- Logger.Trace("Received a frame while we are disconnected. Ignoring. Cmd: {0}, Event: {1}", response.Command, response.Event);
+ Logger.Trace("Received a frame while we are disconnected. Ignoring. Cmd: {0}, Event: {1}", response.Command, response.Event);
}
private void ProcessDispatch(EventPayload response)
@@ -597,11 +602,11 @@ private void ProcessDispatch(EventPayload response)
break;
}
}
-
+
#endregion
#region Writting
-
+
private void ProcessCommandQueue()
{
//Logger.Info("Checking command queue");
@@ -617,7 +622,7 @@ private void ProcessCommandQueue()
//Prepare some variabels we will clone into with locks
bool needsWriting = true;
ICommand item = null;
-
+
//Continue looping until we dont need anymore messages
while (needsWriting && namedPipe.IsConnected)
{
@@ -626,7 +631,7 @@ private void ProcessCommandQueue()
//Pull the value and update our writing needs
// If we have nothing to write, exit the loop
needsWriting = _rtqueue.Count > 0;
- if (!needsWriting) break;
+ if (!needsWriting) break;
//Peek at the item
item = _rtqueue.Peek();
@@ -635,7 +640,7 @@ private void ProcessCommandQueue()
//BReak out of the loop as soon as we send this item
if (shutdown || (!aborting && LOCK_STEP))
needsWriting = false;
-
+
//Prepare the payload
IPayload payload = item.PreparePayload(GetNextNonce());
Logger.Trace("Attempting to send payload: {0}", payload.Command);
@@ -692,7 +697,7 @@ private void ProcessCommandQueue()
#region Connection
///
- /// Establishes the handshake with the server.
+ /// Establishes the handshake with the server.
///
///
private void EstablishHandshake()
@@ -701,7 +706,7 @@ private void EstablishHandshake()
//We are establishing a lock and not releasing it until we sent the handshake message.
// We need to set the key, and it would not be nice if someone did things between us setting the key.
-
+
//Check its state
if (State != RpcState.Disconnected)
{
@@ -710,7 +715,7 @@ private void EstablishHandshake()
}
//Send it off to the server
- Logger.Trace("Sending Handshake...");
+ Logger.Trace("Sending Handshake...");
if (!namedPipe.WriteFrame(new PipeFrame(Opcode.Handshake, new Handshake() { Version = VERSION, ClientID = applicationID })))
{
Logger.Error("Failed to write a handshake.");
@@ -727,14 +732,14 @@ private void EstablishHandshake()
private void SendHandwave()
{
Logger.Info("Attempting to wave goodbye...");
-
+
//Check its state
if (State == RpcState.Disconnected)
{
Logger.Error("State must NOT be disconnected in order to send a handwave!");
return;
}
-
+
//Send the handwave
if (!namedPipe.WriteFrame(new PipeFrame(Opcode.Close, new Handshake() { Version = VERSION, ClientID = applicationID })))
{
@@ -742,7 +747,7 @@ private void SendHandwave()
return;
}
}
-
+
///
/// Attempts to connect to the pipe. Returns true on success
@@ -780,7 +785,7 @@ public bool AttemptConnection()
return true;
}
-
+
///
/// Sets the current state of the pipe, locking the l_states object for thread saftey.
///
@@ -795,7 +800,7 @@ private void SetConnectionState(RpcState state)
}
///
- /// Closes the connection and disposes of resources. This will not force termination, but instead allow Discord disconnect us after we say goodbye.
+ /// Closes the connection and disposes of resources. This will not force termination, but instead allow Discord disconnect us after we say goodbye.
/// This option helps prevents ghosting in applications where the Process ID is a host and the game is executed within the host (ie: the Unity3D editor). This will tell Discord that we have no presence and we are closing the connection manually, instead of waiting for the process to terminate.
///
public void Shutdown()
@@ -868,7 +873,7 @@ internal enum RpcState
/// Disconnected from the discord client
///
Disconnected,
-
+
///
/// Connecting to the discord client. The handshake has been sent and we are awaiting the ready event
///
diff --git a/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.XML b/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.XML
index dec5ba7a..fa1f45e2 100644
--- a/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.XML
+++ b/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.XML
@@ -60,7 +60,7 @@
The maximum size of the message queue received from Discord.
-
+
The dispose state of the client object.
@@ -75,6 +75,11 @@
Indicates if the client will automatically invoke the events without having to be called.
+
+
+ Skips sending presences that are identical to the current one.
+
+
The pipe the discord client is on, ranging from 0 to 9. Use -1 to scan through all pipes.
@@ -112,52 +117,58 @@
This option helps prevents ghosting in applications where the Process ID is a host and the game is executed within the host (ie: the Unity3D editor). This will tell Discord that we have no presence and we are closing the connection manually, instead of waiting for the process to terminate.
+
+
+ Called when the discord client has received an Authorize response.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
+
+
Called when the discord client is ready to send and receive messages.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Called when connection to the Discord Client is lost. The connection will remain close and unready to accept messages until the Ready event is called again.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Called when a error has occured during the transmission of a message. For example, if a bad Rich Presence payload is sent, this event will be called explaining what went wrong.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Called when the Discord Client has updated the presence.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Called when the Discord Client has subscribed to an event.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Called when the Discord Client has unsubscribed from an event.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Called when the Discord Client wishes for this process to join a game.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Called when the Discord Client wishes for this process to spectate a game.
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
@@ -169,12 +180,13 @@
The connection to the discord client was succesfull. This is called before .
- This event is not invoked untill is executed.
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
Failed to establish any connection with discord. Discord is potentially not running?
+ If is true then this event will execute on a different thread. If it is not true however, then this event is not invoked untill and will be on the calling thread.
@@ -201,6 +213,7 @@
Dequeues all the messages from Discord, processes them and then invoke appropriate event handlers. This will process the message and update the internal state before invoking the events. Returns the messages that were invoked in the order they were invoked.
+ This method cannot be used if is enabled.
Returns the messages that were invoked and in the order they were invoked.
@@ -210,6 +223,13 @@
+
+
+ Used to authenticate a new client with your app. By default this pops up a modal in-app that asks the user to authorize access to your app.
+
+ The OAuth2 application id.
+ The scopes to authorize.
+
Respond to a Join Request. All requests will timeout after 30 seconds.
@@ -224,23 +244,38 @@
The Rich Presence to set on the current Discord user.
+
+
+ Updates only the of the and updates/removes the buttons. Returns the newly edited Rich Presence.
+
+ The buttons of the Rich Presence
+ Updated Rich Presence
+
+
+
+ Updates only the of the and updates the button with the given index. Returns the newly edited Rich Presence.
+
+ The buttons of the Rich Presence
+ The number of the button
+ Updated Rich Presence
+
- Updates only the of the and sends the updated presence to Discord. Returns the newly edited Rich Presence.
+ Updates only the of the and sends the updated presence to Discord. Returns the newly edited Rich Presence.
The details of the Rich Presence
Updated Rich Presence
- Updates only the of the and sends the updated presence to Discord. Returns the newly edited Rich Presence.
+ Updates only the of the and sends the updated presence to Discord. Returns the newly edited Rich Presence.
The state of the Rich Presence
Updated Rich Presence
- Updates only the of the and sends the updated presence to Discord. Returns the newly edited Rich Presence.
+ Updates only the of the and sends the updated presence to Discord. Returns the newly edited Rich Presence.
The party of the Rich Presence
Updated Rich Presence
@@ -386,6 +421,13 @@
Terminates the connection to Discord and disposes of the object.
+
+
+ Called when the Discord Client has received an Authorize Response.
+
+ The Discord client handler that sent this event
+ The arguments supplied with the event
+
Called when the Discord Client is ready to send and receive messages.
@@ -505,6 +547,11 @@
A InvalidConfigurationException is thrown when trying to perform a action that conflicts with the current configuration.
+
+
+ The exception that is thrown when a error occurs while communicating with a pipe or when a connection attempt fails.
+
+
A StringOutOfRangeException is thrown when the length of a string exceeds the allowed limit.
@@ -557,11 +604,6 @@
Creates a new uninitialized exception with default message.
-
-
- The exception that is thrown when a error occurs while communicating with a pipe or when a connection attempt fails.
-
-
The maximum time the backoff can reach
@@ -623,7 +665,7 @@
- Converts the string into CamelCase (Pascal Case).
+ Converts the string into UpperCamelCase (Pascal Case).
The string to convert
@@ -727,12 +769,20 @@
-
+
+
+ Attempts a new connection
+
+ The pipe number to connect too.
+ Should the connection to a sandbox be attempted?
+
+
+
Starts a read. Can be executed in another thread.
-
+
Ends a read. Can be executed in another thread.
@@ -762,6 +812,39 @@
Disposes of the stream
+
+
+ Returns a platform specific path that Discord is hosting the IPC on.
+
+ The pipe number.
+ The sandbox environment the pipe is in
+
+
+
+
+ returns a platform specific path that Discord is hosting the IPC on.
+
+ The pipe number
+
+
+
+
+ Gets the name of the possible sandbox environment the pipe might be located within. If the platform doesn't support sandboxed Discord, then it will return null.
+
+
+
+
+
+ Gets the temporary path for the current environment. Only applicable for UNIX based systems.
+
+
+
+
+
+ Returns true if the current OS platform is Unix based (Unix or MacOSX).
+
+
+
The operation code that the was sent under. This defines the type of frame and the data to expect.
@@ -873,6 +956,11 @@
+
+
+ Returns minimum value between a int and a unsigned int
+
+
Attempts to read a UInt32
@@ -887,116 +975,129 @@
-
+
- Logs the outputs to a file
+ Compares if the frame equals the other frame.
+
+
+
+
+
+
+ Logs the outputs to the console using
-
+
The level of logging to apply to this logger.
-
+
Should the output be coloured?
-
+
- Creates a new instance of the file logger
+ A alias too
- The path of the log file.
-
+
- Creates a new instance of the file logger
+ Creates a new instance of a Console Logger.
- The path of the log file.
- The level to assign to the logger.
-
+
+
+ Creates a new instance of a Console Logger
+
+ The log level
+
+
+
+ Creates a new instance of a Console Logger with a set log level
+
+ The log level
+ Should the logs be in colour?
+
+
Informative log messages
-
+
Informative log messages
-
+
Warning log messages
-
+
Error log messsages
-
+
- Logs the outputs to the console using
+ Logs the outputs to a file
-
+
The level of logging to apply to this logger.
-
+
Should the output be coloured?
-
-
- A alias too
-
-
-
+
- Creates a new instance of a Console Logger.
+ Creates a new instance of the file logger
+ The path of the log file.
-
+
- Creates a new instance of a Console Logger with a set log level
+ Creates a new instance of the file logger
-
-
+ The path of the log file.
+ The level to assign to the logger.
-
+
Informative log messages
-
+
Informative log messages
-
+
Warning log messages
-
+
Error log messsages
@@ -1109,19 +1210,39 @@
-
+
- Failed to establish any connection with discord. Discord is potentially not running?
+ Representation of the message received by discord when an authorization response has been received.
-
+
The type of message received from discord
-
+
- The pipe we failed to connect too.
+ The OAuth2 authorization code
+
+
+
+
+ Called when the IPC has closed.
+
+
+
+
+ The type of message
+
+
+
+
+ The reason for the close
+
+
+
+
+ The closure code
@@ -1139,49 +1260,88 @@
The pipe we ended up connecting too
-
+
- Representation of the message received by discord when the presence has been updated.
+ Failed to establish any connection with discord. Discord is potentially not running?
-
+
The type of message received from discord
-
+
- The rich presence Discord has set
+ The pipe we failed to connect too.
-
+
- The name of the application Discord has set it for
+ Created when a error occurs within the ipc and it is sent to the client.
-
+
- The ID of the application discord has set it for
+ The type of message received from discord
-
+
- Called when the IPC has closed.
+ The Discord error code.
-
+
- The type of message
+ The message associated with the error code.
-
+
- The reason for the close
+ The error message received by discord. See https://discordapp.com/developers/docs/topics/rpc#rpc-server-payloads-rpc-errors for documentation
-
+
+ Pipe was Successful
+
+
+ The pipe had an exception
+
+
+ The pipe received corrupted data
+
+
+ The functionality was not yet implemented
+
+
+ Unkown Discord error
+
+
+ Invalid Payload received
+
+
+ Invalid command was sent
+
+
+ Invalid event was sent
+
+
- The closure code
+ Messages received from discord.
+
+
+
+
+ The type of message received from discord
+
+
+
+
+ The time the message was created
+
+
+
+
+ Creates a new instance of the message
@@ -1214,200 +1374,161 @@
The discord user that is requesting access.
-
+
- Called when the Discord Client wishes for this process to spectate a game. D -> C.
+ Type of message.
-
+
- The type of message received from discord
+ The Discord Client is ready to send and receive messages.
-
+
- Called as validation of a subscribe
+ The connection to the Discord Client is lost. The connection will remain close and unready to accept messages until the Ready event is called again.
-
+
- The type of message received from discord
+ A error has occured during the transmission of a message. For example, if a bad Rich Presence payload is sent, this event will be called explaining what went wrong.
-
+
- The event that was subscribed too.
+ The Discord Client received an authorize response.
-
+
- Called as validation of a subscribe
+ The Discord Client has updated the presence.
-
+
- The type of message received from discord
+ The Discord Client has subscribed to an event.
-
+
- The event that was subscribed too.
+ The Discord Client has unsubscribed from an event.
-
+
- Called when the ipc is ready to send arguments.
+ The Discord Client wishes for this process to join a game.
-
+
- The type of message received from discord
+ The Discord Client wishes for this process to spectate a game.
-
+
- The configuration of the connection
+ Another discord user requests permission to join this game.
-
+
- User the connection belongs too
+ The connection to the discord client was succesfull. This is called before .
-
+
- The version of the RPC
+ Failed to establish any connection with discord. Discord is potentially not running?
-
+
- Messages received from discord.
+ Representation of the message received by discord when the presence has been updated.
-
+
The type of message received from discord
-
-
- The time the message was created
-
-
-
+
- Creates a new instance of the message
+ The rich presence Discord has set
-
+
- Type of message.
+ The name of the application Discord has set it for
-
+
- The Discord Client is ready to send and receive messages.
+ The ID of the application discord has set it for
-
+
- The connection to the Discord Client is lost. The connection will remain close and unready to accept messages until the Ready event is called again.
+ Called when the ipc is ready to send arguments.
-
+
- A error has occured during the transmission of a message. For example, if a bad Rich Presence payload is sent, this event will be called explaining what went wrong.
+ The type of message received from discord
-
+
- The Discord Client has updated the presence.
+ The configuration of the connection
-
+
- The Discord Client has subscribed to an event.
+ User the connection belongs too
-
+
- The Discord Client has unsubscribed from an event.
+ The version of the RPC
-
+
- The Discord Client wishes for this process to join a game.
+ Called when the Discord Client wishes for this process to spectate a game. D -> C.
-
+
- The Discord Client wishes for this process to spectate a game.
+ The type of message received from discord
-
+
- Another discord user requests permission to join this game.
+ Called as validation of a subscribe
-
+
- The connection to the discord client was succesfull. This is called before .
+ The type of message received from discord
-
+
- Failed to establish any connection with discord. Discord is potentially not running?
+ The event that was subscribed too.
-
+
- Created when a error occurs within the ipc and it is sent to the client.
+ Called as validation of a subscribe
-
+
The type of message received from discord
-
-
- The Discord error code.
-
-
-
-
- The message associated with the error code.
-
-
-
+
- The error message received by discord. See https://discordapp.com/developers/docs/topics/rpc#rpc-server-payloads-rpc-errors for documentation
+ The event that was subscribed too.
-
- Pipe was Successful
-
-
- The pipe had an exception
-
-
- The pipe received corrupted data
-
-
- The functionality was not yet implemented
-
-
- Unkown Discord error
-
-
- Invalid Payload received
-
-
- Invalid command was sent
-
-
- Invalid event was sent
-
Registers the URI scheme. If Steam ID is passed, the application will be launched through steam instead of directly.
@@ -1461,138 +1582,84 @@
-
+
- The Rich Presence structure that will be sent and received by Discord. Use this class to build your presence and update it appropriately.
+ The base rich presence structure
-
+
- The user's current status. For example, "Playing Solo" or "With Friends".
+ The user's current status. For example, "Playing Solo" or "With Friends".
Max 128 bytes
-
+
+ Inernal inner state string
+
+
What the user is currently doing. For example, "Competitive - Total Mayhem".
Max 128 bytes
-
+
+ Inernal inner detail string
+
+
The time elapsed / remaining time data.
-
+
The names of the images to use and the tooltips to give those images.
-
+
The party the player is currently in. The must be set for this to be included in the RichPresence update.
-
+
The secrets used for Join / Spectate. Secrets are obfuscated data of your choosing. They could be match ids, player ids, lobby ids, etc. Make this object null if you do not wish too / unable too implement the Join / Request feature.
To keep security on the up and up, Discord requires that you properly hash/encode/encrypt/put-a-padlock-on-and-swallow-the-key-but-wait-then-how-would-you-open-it your secrets.
Visit the Rich Presence How-To for more information.
-
+
Marks the as a game session with a specific beginning and end. It was going to be used as a form of notification, but was replaced with the join feature. It may potentially have use in the future, but it currently has no use.
"TLDR it marks the matchSecret field as an instance, that is to say a context in game that’s not like a lobby state/not in game state. It was gonna he used for notify me, but we scrapped that for ask to join. We may put it to another use in the future. For now, don’t worry about it" - Mason (Discord API Server 14 / 03 / 2018)
-
-
-
-
-
- Clones the presence into a new instance. Used for thread safe writing and reading. This function will ignore properties if they are in a invalid state.
+
-
-
-
-
- Merges the passed presence with this one, taking into account the image key to image id annoyance.
-
-
-
-
-
- Updates this presence with any values from the previous one
-
-
-
+
Does the Rich Presence have valid timestamps?
-
+
Does the Rich Presence have valid assets?
-
+
Does the Rich Presence have a valid party?
-
+
Does the Rich Presence have valid secrets?
-
-
- Sets the state of the Rich Presence. See also .
-
- The user's current status.
- The modified Rich Presence.
-
-
-
- Sets the details of the Rich Presence. See also .
-
- What the user is currently doing.
- The modified Rich Presence.
-
-
-
- Sets the timestamp of the Rich Presence. See also .
-
- The time elapsed / remaining time data.
- The modified Rich Presence.
-
-
-
- Sets the assets of the Rich Presence. See also .
-
- The names of the images to use and the tooltips to give those images.
- The modified Rich Presence.
-
-
-
- Sets the Rich Presence's party. See also .
-
- The party the player is currently in.
- The modified Rich Presence.
-
-
-
- Sets the Rich Presence's secrets. See also .
-
- The secrets used for Join / Spectate.
- The modified Rich Presence.
-
-
+
Attempts to call on the string and return the result, if its within a valid length.
@@ -1602,12 +1669,25 @@
The encoding to count the bytes with
True if the string fits within the number of bytes
-
+
Operator that converts a presence into a boolean for null checks.
+
+
+ Checks if the other rich presence differs from the current one
+
+
+
+
+
+
+ Converts this BaseRichPresence to RichPresence
+
+
+
The secrets used for Join / Spectate. Secrets are obfuscated data of your choosing. They could be match ids, player ids, lobby ids, etc.
@@ -1673,7 +1753,13 @@
Name of the uploaded image for the large profile artwork.
- Max 32 Bytes.
+ Max 256 Bytes.
+
+ Allows URL to directly link to images.
+
+
+
+ Gets if the large square image is from an external link
@@ -1685,7 +1771,13 @@
Name of the uploaded image for the small profile artwork.
- Max 32 Bytes.
+ Max 256 Bytes.
+
+ Allows URL to directly link to images.
+
+
+
+ Gets if the small profile artwork is from an external link
@@ -1716,18 +1808,18 @@
- Creates a new timestamp for now.
+ A new timestamp that starts from the current time.
- Creates a new timestamp starting at UtcNow and ending in the supplied timespan
+ Creates a new timestamp starting at the current time and ending in the supplied timespan
How long the Timestamp will last for in seconds.
Returns a new timestamp with given duration.
- Creates a new timestamp starting at UtcNow and ending in the supplied timespan
+ Creates a new timestamp starting at current time and ending in the supplied timespan
How long the Timestamp will last for.
Returns a new timestamp with given duration.
@@ -1747,9 +1839,15 @@
Creates a empty timestamp object
-
+
+
+ Creates a timestamp with the set start time
+
+
+
+
- Creates a timestamp with the set start or end time.
+ Creates a timestamp with a set duration
The start time
The end time
@@ -1784,6 +1882,21 @@
Structure representing the part the player is in.
+
+
+ Privacy of the party
+
+
+
+
+ The party is private, invites only.
+
+
+
+
+ THe party is public, anyone can join.
+
+
A unique ID for the player's current party / lobby / group. If this is not supplied, they player will not be in a party and the rest of the information will not be sent.
@@ -1800,6 +1913,106 @@
The maxium size of the party / lobby / group. This is required to be larger than . If it is smaller than the current party size, it will automatically be set too when the presence is sent.
+
+
+ The privacy of the party
+
+
+
+
+ A Rich Presence button.
+
+
+
+
+ Text shown on the button
+ Max 32 bytes.
+
+
+
+
+ The URL opened when clicking the button.
+ Max 512 bytes.
+
+
+
+
+ The Rich Presence structure that will be sent and received by Discord. Use this class to build your presence and update it appropriately.
+
+
+
+
+ The buttons to display in the presence.
+ Max of 2
+
+
+
+
+ Does the Rich Presence have any buttons?
+
+
+
+
+
+ Sets the state of the Rich Presence. See also .
+
+ The user's current status.
+ The modified Rich Presence.
+
+
+
+ Sets the details of the Rich Presence. See also .
+
+ What the user is currently doing.
+ The modified Rich Presence.
+
+
+
+ Sets the timestamp of the Rich Presence. See also .
+
+ The time elapsed / remaining time data.
+ The modified Rich Presence.
+
+
+
+ Sets the assets of the Rich Presence. See also .
+
+ The names of the images to use and the tooltips to give those images.
+ The modified Rich Presence.
+
+
+
+ Sets the Rich Presence's party. See also .
+
+ The party the player is currently in.
+ The modified Rich Presence.
+
+
+
+ Sets the Rich Presence's secrets. See also .
+
+ The secrets used for Join / Spectate.
+ The modified Rich Presence.
+
+
+
+ Clones the presence into a new instance. Used for thread safe writing and reading. This function will ignore properties if they are in a invalid state.
+
+
+
+
+
+ Merges the passed presence with this one, taking into account the image key to image id annoyance.
+
+
+ self
+
+
+
+ Operator that converts a presence into a boolean for null checks.
+
+
+
A rich presence that has been parsed from the pipe as a response.
@@ -1815,24 +2028,34 @@
Name of the bot
-
+
- The process ID
+ OAuth2 application id
-
+
- The rich presence to be set. Can be null.
+ scopes to authorize
-
+
- The user ID that we are accepting / rejecting
+ scopes to authorize
-
+
- If true, the user will be allowed to connect.
+ The OAuth2 authorization code
+
+
+
+
+ The process ID
+
+
+
+
+ The rich presence to be set. Can be null.
@@ -1845,6 +2068,16 @@
The rich presence to be set. Can be null.
+
+
+ The user ID that we are accepting / rejecting
+
+
+
+
+ If true, the user will be allowed to connect.
+
+
The close code the discord gave us
@@ -1955,6 +2188,21 @@
used to capture a keyboard shortcut entered by the user RPC Events
+
+
+ Base Payload that is received by both client and server
+
+
+
+
+ The type of payload
+
+
+
+
+ A incremental value to help identify payloads
+
+
The payload that is sent by the client to discord for events such as setting the rich presence.
@@ -1981,21 +2229,6 @@
-
-
- Base Payload that is received by both client and server
-
-
-
-
- The type of payload
-
-
-
-
- A incremental value to help identify payloads
-
-
Used for Discord IPC Events
@@ -2121,7 +2354,7 @@
This option helps prevents ghosting in applications where the Process ID is a host and the game is executed within the host (ie: the Unity3D editor). This will tell Discord that we have no presence and we are closing the connection manually, instead of waiting for the process to terminate.
-
+
Creates a new instance of the RPC.
@@ -2130,6 +2363,7 @@
The target pipe to connect too
The pipe client we shall use.
The maximum size of the out queue
+ The maximum size of the in queue
@@ -2223,67 +2457,6 @@
We are connect to the client and can send and receive messages.
-
-
- Handles HTTP Rich Presence Requests
-
-
-
-
- Sets the Rich Presence over the HTTP protocol. Does not support Join / Spectate and by default is blocking.
-
- The presence to send to discord
- The ID of the application
- The port the discord client is currently on. Specify this for testing. Will start scanning from supplied port.
- Returns the rich presence result from the server. This can be null if presence was set to be null, or if there was no valid response from the client.
-
-
-
- Attempts to set the Rich Presence over the HTTP protocol. Does not support Join / Specate and by default is blocking.
-
- The presence to send to discord
- The response object from the client
- The ID of the application
- The port the discord client is currently on. Specify this for testing. Will start scanning from supplied port.
- True if the response was valid from the server, otherwise false.
-
-
-
- Attempts to parse the response of a Web Request to a rich presence
-
- The json data received by the client
- The parsed rich presence
- True if the parse was succesfull
-
-
-
- Prepares a struct containing data requried to make a succesful web client request to set the rich presence.
-
- The rich presence to set.
- The ID of the application the presence belongs too.
- The port the client is located on. The default port for the discord client is 6463, but it may move iteratively upto 6473 if the ports are unavailable.
- Returns a web request containing nessary data to make a POST request
-
-
-
- Details of a HTTP Post request that will set the rich presence.
-
-
-
-
- The URL to send the POST request too
-
-
-
-
- The JSON formatted body to send with the POST request
-
-
-
-
- The headers to send with the body
-
-
Object representing a Discord user. This is used for join requests.
@@ -2315,7 +2488,7 @@
Graphics Interchange Format (.gif)
- If you pronounce it .jif, you need to re-evaluate your life choices.
+ Animated avatars that Discord Nitro users are able to use. If the user doesn't have an animated avatar, then it will just be a single frame gif.
@@ -2361,15 +2534,88 @@
The discriminator of the user.
+ If the user has migrated to unique a , the discriminator will always be 0.
+
+
+
+ The display name of the user
+
+ This will be empty if the user has not set a global display name.
- The avatar hash of the user. Too get a URI for the avatar, use the . This can be null if the user has no avatar. The will account for this and return the discord default.
+ The avatar hash of the user. Too get a URL for the avatar, use the . This can be null if the user has no avatar. The will account for this and return the discord default.
+
+
+
+
+ The flags on a users account, often represented as a badge.
+
+
+
+
+ A flag on the user account
+
+
+
+ No flag
+
+
+ Staff of Discord.
+
+
+ Partners of Discord.
+
+
+ Original HypeSquad which organise events.
+
+
+ Bug Hunters that found and reported bugs in Discord.
+
+
+ The HypeSquad House of Bravery.
+
+
+ The HypeSquad House of Brilliance.
+
+
+ The HypeSquad House of Balance (the best one).
+
+
+ Early Supporter of Discord and had Nitro before the store was released.
+
+
+ Apart of a team.
+ Unclear if it is reserved for members that share a team with the current application.
+
+
+
+
+ The premium type of the user.
+
+
+
+
+ Type of premium
+
+ No subscription to any forms of Nitro.
+
+
+ Nitro Classic subscription. Has chat perks and animated avatars.
+
+
+ Nitro subscription. Has chat perks, animated avatars, server boosting, and access to free Nitro Games.
+
- The endpoint for the CDN. Normally cdn.discordapp.com
+ The endpoint for the CDN. Normally cdn.discordapp.com.
+
+
+
+
+ Creates a new User instance.
@@ -2378,13 +2624,21 @@
The configuration received by the OnReady event.
+
+
+ Gets a URL that can be used to download the user's avatar. If the user has not yet set their avatar, it will return the default one that discord is using. The default avatar only supports the format.
+
+ The file returned will be 128px x 128px
+ The format of the target avatar
+ URL to the discord CDN for the particular avatar
+
Gets a URL that can be used to download the user's avatar. If the user has not yet set their avatar, it will return the default one that discord is using. The default avatar only supports the format.
The format of the target avatar
- The optional size of the avatar you wish for. Defaults to x128.
-
+ The optional size of the avatar you wish for.
+ URL to the discord CDN for the particular avatar
@@ -2395,9 +2649,10 @@
- Formats the user into username#discriminator
+ Formats the user into a displayable format. If the user has a , then this will be used.
+ If the user still has a discriminator, then this will return the form of `Username#Discriminator`.
-
+ String of the user that can be used for display.
diff --git a/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.dll b/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.dll
index bbd00585..db365114 100644
Binary files a/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.dll and b/Unity Example/Assets/Discord RPC/Plugins/DiscordRPC.dll differ
diff --git a/Unity Example/Assets/Discord RPC/Plugins/Newtonsoft.Json.dll b/Unity Example/Assets/Discord RPC/Plugins/Newtonsoft.Json.dll
index cf7b462b..7af125a2 100644
Binary files a/Unity Example/Assets/Discord RPC/Plugins/Newtonsoft.Json.dll and b/Unity Example/Assets/Discord RPC/Plugins/Newtonsoft.Json.dll differ
diff --git a/Unity Example/Assets/Discord RPC/Scripts/Control/DiscordEvents.cs b/Unity Example/Assets/Discord RPC/Scripts/Control/DiscordEvents.cs
index 3200d434..e3f819fc 100644
--- a/Unity Example/Assets/Discord RPC/Scripts/Control/DiscordEvents.cs
+++ b/Unity Example/Assets/Discord RPC/Scripts/Control/DiscordEvents.cs
@@ -9,6 +9,9 @@ namespace DiscordRPC.Unity
[Serializable]
public class DiscordEvents
{
+ [Serializable]
+ public class AuthorizeMessageEvent : UnityEvent { }
+
[Serializable]
public class ReadyMessageEvent : UnityEvent { }
@@ -42,6 +45,7 @@ public class ConnectionEstablishedMessageEvent : UnityEvent { }
+ public AuthorizeMessageEvent OnAuthorize = new AuthorizeMessageEvent();
public ReadyMessageEvent OnReady = new ReadyMessageEvent();
public CloseMessageEvent OnClose = new CloseMessageEvent();
public ErrorMessageEvent OnError = new ErrorMessageEvent();
@@ -56,6 +60,7 @@ public class ConnectionFailedMessageEvent : UnityEvent
public void RegisterEvents(DiscordRpcClient client)
{
+ client.OnAuthorize += (s, args) => OnAuthorize.Invoke(args);
client.OnReady += (s, args) => OnReady.Invoke(args);
client.OnClose += (s, args) => OnClose.Invoke(args);
client.OnError += (s, args) => OnError.Invoke(args);