12 Commits

Author SHA1 Message Date
8bb85f0545 Fix double function declaration 2019-01-14 00:09:17 -08:00
766596722c This one actually works!!!! 2019-01-04 14:13:30 -08:00
7fe88765fd maybe this fixes it 2019-01-04 14:11:37 -08:00
1d30b94987 Oops all variables 2019-01-04 14:11:37 -08:00
6796d2ffa9 Fix windows connection 2019-01-04 14:11:37 -08:00
d90a8efd47 Warnings as errors yelling 2019-01-04 14:11:37 -08:00
544f91a5a8 UE4 support 2019-01-04 14:11:37 -08:00
2f52c24f6d Get pipe from base connection instance 2019-01-04 14:11:09 -08:00
d5a342c7bb Choose pipe number on initialize 2019-01-04 14:10:56 -08:00
4e53fa0392 Fix code signing for macOS 10.10 (#260)
* Fix code signing for macOS 10.10
- Fixes #259

* Maybe this works
2018-12-19 08:40:51 -08:00
d478ed5608 Moved UE setup to be with unity setup (#254) 2018-12-14 16:04:31 -08:00
8db649ba5f Static EventHandler for IL2CPP support (#258)
* Added staticEventHandler which forward the invoke to the actual eventHandler set though Initialize

* Code Formatting - Replaced abs with 4 white spaces
2018-12-14 16:00:47 -08:00
13 changed files with 78 additions and 50 deletions

View File

@ -15,6 +15,33 @@ Zeroith, you should be set up to build things because you are a game developer,
First, head on over to the [Discord developers site](https://discordapp.com/developers/applications/me) and make yourself an app. Keep track of `Client ID` -- you'll need it here to pass to the init function. First, head on over to the [Discord developers site](https://discordapp.com/developers/applications/me) and make yourself an app. Keep track of `Client ID` -- you'll need it here to pass to the init function.
### Unreal Engine 4 Setup
To use the Rich Presense plugin with Unreal Engine Projects:
1. Download the latest [release](https://github.com/discordapp/discord-rpc/releases) for each operating system you are targeting and the zipped source code
2. In the source code zip, copy the UE plugin—`examples/unrealstatus/Plugins/discordrpc`—to your project's plugin directory
3. At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create an `Include` folder and copy `discord_rpc.h` and `discord_register.h` to it from the zip
4. Follow the steps below for each OS
5. Build your UE4 project
6. Launch the editor, and enable the Discord plugin.
#### Windows
- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Win64` folder
- Copy `lib/discord-rpc.lib` and `bin/discord-rpc.dll` from `[RELEASE_ZIP]/win64-dynamic` to the `Win64` folder
#### Mac
- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Mac` folder
- Copy `libdiscord-rpc.dylib` from `[RELEASE_ZIP]/osx-dynamic/lib` to the `Mac` folder
#### Linux
- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Linux` folder
- Inside, create another folder `x86_64-unknown-linux-gnu`
- Copy `libdiscord-rpc.so` from `[RELEASE_ZIP]/linux-dynamic/lib` to `Linux/x86_64-unknown-linux-gnu`
### Unity Setup ### Unity Setup
If you're a Unity developer looking to integrate Rich Presence into your game, follow this simple guide to get started towards success: If you're a Unity developer looking to integrate Rich Presence into your game, follow this simple guide to get started towards success:
@ -101,33 +128,6 @@ This is a sample [Unity](https://unity3d.com/) project that wraps a DLL version
This is a sample [Unreal](https://www.unrealengine.com) project that wraps the DLL version of the library with an Unreal plugin, exposes a blueprint class for interacting with it, and uses that to make a very simple UI. Run `python build.py unreal` in the root directory to build the correct library files and place them in their respective folders. This is a sample [Unreal](https://www.unrealengine.com) project that wraps the DLL version of the library with an Unreal plugin, exposes a blueprint class for interacting with it, and uses that to make a very simple UI. Run `python build.py unreal` in the root directory to build the correct library files and place them in their respective folders.
### Using the Unreal Engine plugin with your own project
To use the Rich Presense plugin with Unreal Engine Projects:
1. Download the latest [release](https://github.com/discordapp/discord-rpc/releases) for each operating system you are targeting and the zipped source code
2. In the source code zip, copy the UE plugin—`examples/unrealstatus/Plugins/discordrpc`—to your project's plugin directory
3. At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create an `Include` folder and copy `discord_rpc.h` and `discord_register.h` to it from the zip
4. Follow the steps below for each OS
5. Build your UE4 project
6. Launch the editor, and enable the Discord plugin.
#### Windows
- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Win64` folder
- Copy `lib/discord-rpc.lib` and `bin/discord-rpc.dll` from `[RELEASE_ZIP]/win64-dynamic` to the `Win64` folder
#### Mac
- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Mac` folder
- Copy `libdiscord-rpc.dylib` from `[RELEASE_ZIP]/osx-dynamic/lib` to the `Mac` folder
#### Linux
- At `[YOUR_UE_PROJECT]/Plugins/discordrpc/source/ThirdParty/DiscordRpcLibrary/`, create a `Linux` folder
- Inside, create another folder `x86_64-unknown-linux-gnu`
- Copy `libdiscord-rpc.so` from `[RELEASE_ZIP]/linux-dynamic/lib` to `Linux/x86_64-unknown-linux-gnu`
## Wrappers and Implementations ## Wrappers and Implementations
Below is a table of unofficial, community-developed wrappers for and implementations of Rich Presence in various languages. If you would like to have yours added, please make a pull request adding your repository to the table. The repository should include: Below is a table of unofficial, community-developed wrappers for and implementations of Rich Presence in various languages. If you would like to have yours added, please make a pull request adding your repository to the table. The repository should include:

View File

@ -7,29 +7,31 @@ using AOT;
public class DiscordRpc public class DiscordRpc
{ {
[MonoPInvokeCallback(typeof(OnReadyInfo))] [MonoPInvokeCallback(typeof(OnReadyInfo))]
public static void ReadyCallback(ref DiscordUser connectedUser) { } public static void ReadyCallback(ref DiscordUser connectedUser) { Callbacks.readyCallback(ref connectedUser); }
public delegate void OnReadyInfo(ref DiscordUser connectedUser); public delegate void OnReadyInfo(ref DiscordUser connectedUser);
[MonoPInvokeCallback(typeof(OnDisconnectedInfo))] [MonoPInvokeCallback(typeof(OnDisconnectedInfo))]
public static void DisconnectedCallback(int errorCode, string message) { } public static void DisconnectedCallback(int errorCode, string message) { Callbacks.disconnectedCallback(errorCode, message); }
public delegate void OnDisconnectedInfo(int errorCode, string message); public delegate void OnDisconnectedInfo(int errorCode, string message);
[MonoPInvokeCallback(typeof(OnErrorInfo))] [MonoPInvokeCallback(typeof(OnErrorInfo))]
public static void ErrorCallback(int errorCode, string message) { } public static void ErrorCallback(int errorCode, string message) { Callbacks.errorCallback(errorCode, message); }
public delegate void OnErrorInfo(int errorCode, string message); public delegate void OnErrorInfo(int errorCode, string message);
[MonoPInvokeCallback(typeof(OnJoinInfo))] [MonoPInvokeCallback(typeof(OnJoinInfo))]
public static void JoinCallback(string secret) { } public static void JoinCallback(string secret) { Callbacks.joinCallback(secret); }
public delegate void OnJoinInfo(string secret); public delegate void OnJoinInfo(string secret);
[MonoPInvokeCallback(typeof(OnSpectateInfo))] [MonoPInvokeCallback(typeof(OnSpectateInfo))]
public static void SpectateCallback(string secret) { } public static void SpectateCallback(string secret) { Callbacks.spectateCallback(secret); }
public delegate void OnSpectateInfo(string secret); public delegate void OnSpectateInfo(string secret);
[MonoPInvokeCallback(typeof(OnRequestInfo))] [MonoPInvokeCallback(typeof(OnRequestInfo))]
public static void RequestCallback(ref DiscordUser request) { } public static void RequestCallback(ref DiscordUser request) { Callbacks.requestCallback(ref request); }
public delegate void OnRequestInfo(ref DiscordUser request); public delegate void OnRequestInfo(ref DiscordUser request);
static EventHandlers Callbacks { get; set; }
public struct EventHandlers public struct EventHandlers
{ {
public OnReadyInfo readyCallback; public OnReadyInfo readyCallback;
@ -76,8 +78,23 @@ public class DiscordRpc
Ignore = 2 Ignore = 2
} }
public static void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId, int pipe = 0)
{
Callbacks = handlers;
EventHandlers staticEventHandlers = new EventHandlers();
staticEventHandlers.readyCallback += DiscordRpc.ReadyCallback;
staticEventHandlers.disconnectedCallback += DiscordRpc.DisconnectedCallback;
staticEventHandlers.errorCallback += DiscordRpc.ErrorCallback;
staticEventHandlers.joinCallback += DiscordRpc.JoinCallback;
staticEventHandlers.spectateCallback += DiscordRpc.SpectateCallback;
staticEventHandlers.requestCallback += DiscordRpc.RequestCallback;
InitializeInternal(applicationId, ref staticEventHandlers, autoRegister, optionalSteamId, pipe);
}
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)] [DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)]
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId); static extern void InitializeInternal(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId, int pipe);
[DllImport("discord-rpc", EntryPoint = "Discord_Shutdown", CallingConvention = CallingConvention.Cdecl)] [DllImport("discord-rpc", EntryPoint = "Discord_Shutdown", CallingConvention = CallingConvention.Cdecl)]
public static extern void Shutdown(); public static extern void Shutdown();

View File

@ -129,7 +129,7 @@ static void discordInit()
handlers.joinGame = handleDiscordJoin; handlers.joinGame = handleDiscordJoin;
handlers.spectateGame = handleDiscordSpectate; handlers.spectateGame = handleDiscordSpectate;
handlers.joinRequest = handleDiscordJoinRequest; handlers.joinRequest = handleDiscordJoinRequest;
Discord_Initialize(APPLICATION_ID, &handlers, 1, NULL); Discord_Initialize(APPLICATION_ID, &handlers, 1, NULL, 0);
} }
static void gameLoop() static void gameLoop()

View File

@ -82,7 +82,8 @@ static void JoinRequestHandler(const DiscordUser* request)
void UDiscordRpc::Initialize(const FString& applicationId, void UDiscordRpc::Initialize(const FString& applicationId,
bool autoRegister, bool autoRegister,
const FString& optionalSteamId) const FString& optionalSteamId,
int pipe)
{ {
self = this; self = this;
IsConnected = false; IsConnected = false;
@ -102,7 +103,7 @@ void UDiscordRpc::Initialize(const FString& applicationId,
auto appId = StringCast<ANSICHAR>(*applicationId); auto appId = StringCast<ANSICHAR>(*applicationId);
auto steamId = StringCast<ANSICHAR>(*optionalSteamId); auto steamId = StringCast<ANSICHAR>(*optionalSteamId);
Discord_Initialize( Discord_Initialize(
(const char*)appId.Get(), &handlers, autoRegister, (const char*)steamId.Get()); (const char*)appId.Get(), &handlers, autoRegister, (const char*)steamId.Get(), pipe);
} }
void UDiscordRpc::Shutdown() void UDiscordRpc::Shutdown()

View File

@ -99,7 +99,8 @@ public:
Category = "Discord") Category = "Discord")
void Initialize(const FString& applicationId, void Initialize(const FString& applicationId,
bool autoRegister, bool autoRegister,
const FString& optionalSteamId); const FString& optionalSteamId,
int optionalPipeNumber);
UFUNCTION(BlueprintCallable, UFUNCTION(BlueprintCallable,
meta = (DisplayName = "Shut down connection", Keywords = "Discord rpc"), meta = (DisplayName = "Shut down connection", Keywords = "Discord rpc"),

View File

@ -64,7 +64,8 @@ typedef struct DiscordEventHandlers {
DISCORD_EXPORT void Discord_Initialize(const char* applicationId, DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers, DiscordEventHandlers* handlers,
int autoRegister, int autoRegister,
const char* optionalSteamId); const char* optionalSteamId,
int optionalPipeNumber);
DISCORD_EXPORT void Discord_Shutdown(void); DISCORD_EXPORT void Discord_Shutdown(void);
/* checks for incoming messages, dispatches callbacks */ /* checks for incoming messages, dispatches callbacks */

View File

@ -72,6 +72,11 @@ if(UNIX)
add_library(discord-rpc ${BASE_RPC_SRC}) add_library(discord-rpc ${BASE_RPC_SRC})
target_link_libraries(discord-rpc PUBLIC pthread) target_link_libraries(discord-rpc PUBLIC pthread)
if (APPLE)
target_link_libraries(discord-rpc PRIVATE "-framework AppKit, -mmacosx-version-min=10.10")
endif (APPLE)
target_compile_options(discord-rpc PRIVATE target_compile_options(discord-rpc PRIVATE
-g -g
-Wall -Wall

View File

@ -12,7 +12,7 @@ struct BaseConnection {
static BaseConnection* Create(); static BaseConnection* Create();
static void Destroy(BaseConnection*&); static void Destroy(BaseConnection*&);
bool isOpen{false}; bool isOpen{false};
bool Open(); bool Open(int pipe);
bool Close(); bool Close();
bool Write(const void* data, size_t length); bool Write(const void* data, size_t length);
bool Read(void* data, size_t length); bool Read(void* data, size_t length);

View File

@ -49,7 +49,7 @@ static const char* GetTempPath()
c = nullptr; c = nullptr;
} }
bool BaseConnection::Open() bool BaseConnection::Open(int pipe)
{ {
const char* tempPath = GetTempPath(); const char* tempPath = GetTempPath();
auto self = reinterpret_cast<BaseConnectionUnix*>(this); auto self = reinterpret_cast<BaseConnectionUnix*>(this);
@ -62,8 +62,7 @@ bool BaseConnection::Open()
int optval = 1; int optval = 1;
setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)); setsockopt(self->sock, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval));
#endif #endif
for (int pipeNum = pipe; pipeNum < 10; ++pipeNum) {
for (int pipeNum = 0; pipeNum < 10; ++pipeNum) {
snprintf( snprintf(
PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum); PipeAddr.sun_path, sizeof(PipeAddr.sun_path), "%s/discord-ipc-%d", tempPath, pipeNum);
int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr)); int err = connect(self->sock, (const sockaddr*)&PipeAddr, sizeof(PipeAddr));

View File

@ -6,6 +6,7 @@
#define NOIME #define NOIME
#include <assert.h> #include <assert.h>
#include <windows.h> #include <windows.h>
#include <sstream>
int GetProcessId() int GetProcessId()
{ {
@ -30,11 +31,11 @@ static BaseConnectionWin Connection;
c = nullptr; c = nullptr;
} }
bool BaseConnection::Open() bool BaseConnection::Open(int pipe)
{ {
wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"}; wchar_t pipeName[]{L"\\\\?\\pipe\\discord-ipc-0"};
const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2; const size_t pipeDigit = sizeof(pipeName) / sizeof(wchar_t) - 2;
pipeName[pipeDigit] = L'0'; pipeName[pipeDigit] += pipe;
auto self = reinterpret_cast<BaseConnectionWin*>(this); auto self = reinterpret_cast<BaseConnectionWin*>(this);
for (;;) { for (;;) {
self->pipe = ::CreateFileW( self->pipe = ::CreateFileW(

View File

@ -273,7 +273,8 @@ static bool DeregisterForEvent(const char* evtName)
extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId, extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers, DiscordEventHandlers* handlers,
int autoRegister, int autoRegister,
const char* optionalSteamId) const char* optionalSteamId,
int pipe)
{ {
IoThread = new (std::nothrow) IoThreadHolder(); IoThread = new (std::nothrow) IoThreadHolder();
if (IoThread == nullptr) { if (IoThread == nullptr) {
@ -308,7 +309,7 @@ extern "C" DISCORD_EXPORT void Discord_Initialize(const char* applicationId,
return; return;
} }
Connection = RpcConnection::Create(applicationId); Connection = RpcConnection::Create(applicationId, pipe);
Connection->onConnect = [](JsonDocument& readyMessage) { Connection->onConnect = [](JsonDocument& readyMessage) {
Discord_UpdateHandlers(&QueuedHandlers); Discord_UpdateHandlers(&QueuedHandlers);
if (QueuedPresence.length > 0) { if (QueuedPresence.length > 0) {

View File

@ -6,10 +6,11 @@
static const int RpcVersion = 1; static const int RpcVersion = 1;
static RpcConnection Instance; static RpcConnection Instance;
/*static*/ RpcConnection* RpcConnection::Create(const char* applicationId) /*static*/ RpcConnection* RpcConnection::Create(const char* applicationId, int pipe)
{ {
Instance.connection = BaseConnection::Create(); Instance.connection = BaseConnection::Create();
StringCopy(Instance.appId, applicationId); StringCopy(Instance.appId, applicationId);
Instance.pipe = pipe;
return &Instance; return &Instance;
} }
@ -26,7 +27,7 @@ void RpcConnection::Open()
return; return;
} }
if (state == State::Disconnected && !connection->Open()) { if (state == State::Disconnected && !connection->Open(Instance.pipe)) {
return; return;
} }

View File

@ -43,11 +43,12 @@ struct RpcConnection {
void (*onConnect)(JsonDocument& message){nullptr}; void (*onConnect)(JsonDocument& message){nullptr};
void (*onDisconnect)(int errorCode, const char* message){nullptr}; void (*onDisconnect)(int errorCode, const char* message){nullptr};
char appId[64]{}; char appId[64]{};
int pipe;
int lastErrorCode{0}; int lastErrorCode{0};
char lastErrorMessage[256]{}; char lastErrorMessage[256]{};
RpcConnection::MessageFrame sendFrame; RpcConnection::MessageFrame sendFrame;
static RpcConnection* Create(const char* applicationId); static RpcConnection* Create(const char* applicationId, int pipe);
static void Destroy(RpcConnection*&); static void Destroy(RpcConnection*&);
inline bool IsOpen() const { return state == State::Connected; } inline bool IsOpen() const { return state == State::Connected; }