Register upgrade (#2)

* Update init to take an optional Steam ID. Add register for steam game. Remove url from cmd line params to launched game.

* Start on a build script
This commit is contained in:
Chris Marsh 2017-08-30 15:17:47 -07:00 committed by GitHub
parent 8bceae0a3a
commit 794bbccd51
16 changed files with 167 additions and 33 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
/build*/ /build*/
/.vscode/ /.vscode/
/thirdparty/ /thirdparty/
.vs/

60
build.py Normal file
View File

@ -0,0 +1,60 @@
import os
import subprocess
import sys
import shutil
from contextlib import contextmanager
SCRIPT_PATH = os.path.dirname(os.path.abspath(__file__))
@contextmanager
def cd(new_dir):
""" Temporarily change current directory """
if new_dir:
old_dir = os.getcwd()
os.chdir(new_dir)
yield
if new_dir:
os.chdir(old_dir)
def mkdir_p(path):
""" mkdir -p """
if not os.path.isdir(path):
os.makedirs(path)
def build(build_path, generator, options):
mkdir_p(build_path)
with cd(build_path):
initial_cmake = ['cmake', SCRIPT_PATH]
if generator:
initial_cmake.extend(['-G', generator])
for key in options:
val = 'ON' if options[key] else 'OFF'
initial_cmake.append('-D%s=%s' %(key, val))
subprocess.check_call(initial_cmake)
subprocess.check_call(['cmake', '--build', '.', '--config', 'Debug'])
subprocess.check_call(['cmake', '--build', '.', '--config', 'Release'])
def main():
os.chdir(SCRIPT_PATH)
if sys.platform.startswith('win'):
generator = 'Visual Studio 14 2015'
build(os.path.join(SCRIPT_PATH, 'builds', 'win32-static'), generator, {})
build(os.path.join(SCRIPT_PATH, 'builds', 'win32-dynamic'), generator, {'BUILD_DYNAMIC_LIB': True})
generator = 'Visual Studio 14 2015 Win64'
build(os.path.join(SCRIPT_PATH, 'builds', 'win64-static'), generator, {})
build(os.path.join(SCRIPT_PATH, 'builds', 'win64-dynamic'), generator, {'BUILD_DYNAMIC_LIB': True})
# todo: this in some better way
src_dll = os.path.join(SCRIPT_PATH, 'builds', 'win64-dynamic', 'src', 'Release', 'discord-rpc.dll')
dst_dll = os.path.join(SCRIPT_PATH, 'examples\\button-clicker\\Assets\\Resources\\discord-rpc.dll')
shutil.copy(src_dll, dst_dll)
dst_dll = os.path.join(SCRIPT_PATH, 'examples\\unrealstatus\\Plugins\\discordrpc\\Binaries\\ThirdParty\\discordrpcLibrary\\Win64\\discord-rpc.dll')
shutil.copy(src_dll, dst_dll)
if __name__ == '__main__':
sys.exit(main())

View File

@ -3,3 +3,4 @@
/obj/ /obj/
*.sln *.sln
*.csproj *.csproj
*.userprefs

View File

@ -5,6 +5,7 @@ using UnityEngine;
public class DiscordController : MonoBehaviour { public class DiscordController : MonoBehaviour {
public DiscordRpc.RichPresence presence; public DiscordRpc.RichPresence presence;
public string applicationId; public string applicationId;
public string optionalSteamId;
public int callbackCalls; public int callbackCalls;
public int clickCounter; public int clickCounter;
public UnityEngine.Events.UnityEvent onConnect; public UnityEngine.Events.UnityEvent onConnect;
@ -72,7 +73,7 @@ public class DiscordController : MonoBehaviour {
handlers.errorCallback += ErrorCallback; handlers.errorCallback += ErrorCallback;
handlers.joinCallback += JoinCallback; handlers.joinCallback += JoinCallback;
handlers.spectateCallback += SpectateCallback; handlers.spectateCallback += SpectateCallback;
DiscordRpc.Initialize(applicationId, ref handlers, true); DiscordRpc.Initialize(applicationId, ref handlers, true, optionalSteamId);
} }
void OnDisable() void OnDisable()

View File

@ -47,7 +47,7 @@ public class DiscordRpc
} }
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize")] [DllImport("discord-rpc", EntryPoint = "Discord_Initialize")]
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister); public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId);
[DllImport("discord-rpc", EntryPoint = "Discord_Shutdown")] [DllImport("discord-rpc", EntryPoint = "Discord_Shutdown")]
public static extern void Shutdown(); public static extern void Shutdown();

View File

@ -668,6 +668,7 @@ MonoBehaviour:
spectateSecret: spectateSecret:
instance: 0 instance: 0
applicationId: 345229890980937739 applicationId: 345229890980937739
optionalSteamId:
callbackCalls: 0 callbackCalls: 0
clickCounter: 0 clickCounter: 0
onConnect: onConnect:

View File

@ -86,7 +86,7 @@ static void discordInit()
handlers.errored = handleDiscordError; handlers.errored = handleDiscordError;
handlers.joinGame = handleDiscordJoin; handlers.joinGame = handleDiscordJoin;
handlers.spectateGame = handleDiscordSpectate; handlers.spectateGame = handleDiscordSpectate;
Discord_Initialize(APPLICATION_ID, &handlers, 1); Discord_Initialize(APPLICATION_ID, &handlers, 1, NULL);
} }
static void gameLoop() static void gameLoop()

View File

@ -53,7 +53,9 @@ static void SpectateGameHandler(const char* spectateSecret)
} }
} }
void UDiscordRpc::Initialize(const FString& applicationId, bool autoRegister) void UDiscordRpc::Initialize(const FString& applicationId,
bool autoRegister,
const FString& optionalSteamId)
{ {
self = this; self = this;
IsConnected = false; IsConnected = false;
@ -68,7 +70,8 @@ void UDiscordRpc::Initialize(const FString& applicationId, bool autoRegister)
handlers.spectateGame = SpectateGameHandler; handlers.spectateGame = SpectateGameHandler;
} }
auto appId = StringCast<ANSICHAR>(*applicationId); auto appId = StringCast<ANSICHAR>(*applicationId);
Discord_Initialize((const char*)appId.Get(), &handlers, autoRegister); auto steamId = StringCast<ANSICHAR>(*optionalSteamId);
Discord_Initialize((const char*)appId.Get(), &handlers, autoRegister, (const char*)steamId.Get());
} }
void UDiscordRpc::Shutdown() void UDiscordRpc::Shutdown()

View File

@ -6,22 +6,19 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "DiscordRpcBlueprint.generated.h" #include "DiscordRpcBlueprint.generated.h"
// unreal's header tool hates clang-format
// clang-format off
DECLARE_LOG_CATEGORY_EXTERN(Discord, Log, All); DECLARE_LOG_CATEGORY_EXTERN(Discord, Log, All);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDiscordConnected); DECLARE_DYNAMIC_MULTICAST_DELEGATE(FDiscordConnected);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordDisconnected, DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordDisconnected, int, errorCode, const FString&, errorMessage);
int, DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordErrored, int, errorCode, const FString&, errorMessage);
errorCode,
const FString&,
errorMessage);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FDiscordErrored,
int,
errorCode,
const FString&,
errorMessage);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordJoin, const FString&, joinSecret); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordJoin, const FString&, joinSecret);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordSpectate, const FString&, spectateSecret); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FDiscordSpectate, const FString&, spectateSecret);
// clang-format on
/** /**
* Rich presence data * Rich presence data
*/ */
@ -73,7 +70,7 @@ public:
UFUNCTION(BlueprintCallable, UFUNCTION(BlueprintCallable,
meta = (DisplayName = "Initialize connection", Keywords = "Discord rpc"), meta = (DisplayName = "Initialize connection", Keywords = "Discord rpc"),
Category = "Discord") Category = "Discord")
void Initialize(const FString& applicationId, bool autoRegister); void Initialize(const FString& applicationId, bool autoRegister, const FString& optionalSteamId);
UFUNCTION(BlueprintCallable, UFUNCTION(BlueprintCallable,
meta = (DisplayName = "Shut down connection", Keywords = "Discord rpc"), meta = (DisplayName = "Shut down connection", Keywords = "Discord rpc"),

View File

@ -51,7 +51,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);
DISCORD_EXPORT void Discord_Shutdown(); DISCORD_EXPORT void Discord_Shutdown();
/* checks for incoming messages, dispatches callbacks */ /* checks for incoming messages, dispatches callbacks */

View File

@ -10,6 +10,7 @@ endif (NOT ${ENABLE_IO_THREAD})
set(BASE_RPC_SRC set(BASE_RPC_SRC
${PROJECT_SOURCE_DIR}/include/discord-rpc.h ${PROJECT_SOURCE_DIR}/include/discord-rpc.h
discord-rpc.cpp discord-rpc.cpp
discord-register.h
discord-register.cpp discord-register.cpp
rpc_connection.h rpc_connection.h
rpc_connection.cpp rpc_connection.cpp

View File

@ -12,27 +12,31 @@
#pragma comment(lib, "Psapi.lib") #pragma comment(lib, "Psapi.lib")
#endif #endif
void Discord_Register(const char* applicationId)
{
#ifdef _WIN32 #ifdef _WIN32
void Discord_RegisterW(const wchar_t* applicationId, const wchar_t* command)
{
// https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/aa767914(v=vs.85).aspx
// we want to register games so we can run them as discord-<appid>:// // we want to register games so we can run them as discord-<appid>://
// Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions. // Update the HKEY_CURRENT_USER, because it doesn't seem to require special permissions.
wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
wchar_t exeFilePath[MAX_PATH]; wchar_t exeFilePath[MAX_PATH];
GetModuleFileNameExW(GetCurrentProcess(), nullptr, exeFilePath, MAX_PATH); int exeLen = GetModuleFileNameExW(GetCurrentProcess(), nullptr, exeFilePath, MAX_PATH);
wchar_t openCommand[1024];
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
if (command && command[0]) {
StringCbPrintfW(openCommand, sizeof(openCommand), L"%s", command);
}
else {
lstrcpyW(openCommand, exeFilePath);
}
wchar_t protocolName[64]; wchar_t protocolName[64];
StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", appId); StringCbPrintfW(protocolName, sizeof(protocolName), L"discord-%s", applicationId);
wchar_t protocolDescription[128]; wchar_t protocolDescription[128];
StringCbPrintfW( StringCbPrintfW(
protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", appId); protocolDescription, sizeof(protocolDescription), L"URL:Run game %s protocol", applicationId);
wchar_t urlProtocol = 0; wchar_t urlProtocol = 0;
wchar_t openCommand[MAX_PATH + 8];
StringCbPrintfW(openCommand, sizeof(openCommand), L"\"%s\" \"%%1\"", exeFilePath);
wchar_t keyName[256]; wchar_t keyName[256];
StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName); StringCbPrintfW(keyName, sizeof(keyName), L"Software\\Classes\\%s", protocolName);
@ -58,9 +62,8 @@ void Discord_Register(const char* applicationId)
fprintf(stderr, "Error writing description\n"); fprintf(stderr, "Error writing description\n");
} }
len = lstrlenW(exeFilePath) + 1; result = RegSetKeyValueW(
result = key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, (exeLen + 1) * sizeof(wchar_t));
RegSetKeyValueW(key, L"DefaultIcon", nullptr, REG_SZ, exeFilePath, len * sizeof(wchar_t));
if (FAILED(result)) { if (FAILED(result)) {
fprintf(stderr, "Error writing icon\n"); fprintf(stderr, "Error writing icon\n");
} }
@ -72,5 +75,63 @@ void Discord_Register(const char* applicationId)
fprintf(stderr, "Error writing command\n"); fprintf(stderr, "Error writing command\n");
} }
RegCloseKey(key); RegCloseKey(key);
}
#endif
void Discord_Register(const char* applicationId, const char* command)
{
#ifdef _WIN32
wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
wchar_t openCommand[1024];
const wchar_t* wcommand = nullptr;
if (command && command[0]) {
const auto commandBufferLen = sizeof(openCommand) / sizeof(*openCommand);
MultiByteToWideChar(CP_UTF8, 0, command, -1, openCommand, commandBufferLen);
wcommand = openCommand;
}
Discord_RegisterW(appId, wcommand);
#endif
}
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId)
{
#ifdef _WIN32
wchar_t appId[32];
MultiByteToWideChar(CP_UTF8, 0, applicationId, -1, appId, 32);
wchar_t wSteamId[32];
MultiByteToWideChar(CP_UTF8, 0, steamId, -1, wSteamId, 32);
HKEY key;
auto status = RegOpenKeyExW(HKEY_CURRENT_USER, L"Software\\Valve\\Steam", 0, KEY_READ, &key);
if (status != ERROR_SUCCESS) {
fprintf(stderr, "Error opening Steam key\n");
return;
}
wchar_t steamPath[MAX_PATH];
DWORD pathBytes = sizeof(steamPath);
status = RegQueryValueExW(key, L"SteamExe", nullptr, nullptr, (BYTE*)steamPath, &pathBytes);
RegCloseKey(key);
if (status != ERROR_SUCCESS || pathBytes < 1) {
fprintf(stderr, "Error reading SteamExe key\n");
return;
}
DWORD pathChars = pathBytes / sizeof(wchar_t);
for (DWORD i = 0; i < pathChars; ++i) {
if (steamPath[i] == L'/') {
steamPath[i] = L'\\';
}
}
wchar_t command[1024];
StringCbPrintfW(command, sizeof(command), L"\"%s\" steam://run/%s", steamPath, wSteamId);
Discord_RegisterW(appId, command);
#endif #endif
} }

View File

@ -1,3 +1,4 @@
#pragma once #pragma once
void Discord_Register(const char* applicationId); void Discord_Register(const char* applicationId, const char* command);
void Discord_RegisterSteamGame(const char* applicationId, const char* steamId);

View File

@ -208,10 +208,16 @@ bool RegisterForEvent(const char* evtName)
extern "C" void Discord_Initialize(const char* applicationId, extern "C" void Discord_Initialize(const char* applicationId,
DiscordEventHandlers* handlers, DiscordEventHandlers* handlers,
int autoRegister) int autoRegister,
const char* optionalSteamId)
{ {
if (autoRegister) { if (autoRegister) {
Discord_Register(applicationId); if (optionalSteamId && optionalSteamId[0]) {
Discord_RegisterSteamGame(applicationId, optionalSteamId);
}
else {
Discord_Register(applicationId, nullptr);
}
} }
Pid = GetProcessId(); Pid = GetProcessId();