Big update
Switched from using the official discord rpc library that requires downloading a dll/so to using discord-rpc-csharp
This commit is contained in:
parent
8332a5e40e
commit
26a905b4f8
4 changed files with 32 additions and 269 deletions
|
@ -1,241 +0,0 @@
|
|||
/*
|
||||
Copyright 2017 Discord, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
public class DiscordRpc
|
||||
{
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ReadyCallback(ref DiscordUser connectedUser);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void DisconnectedCallback(int errorCode, string message);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void ErrorCallback(int errorCode, string message);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void JoinCallback(string secret);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void SpectateCallback(string secret);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
|
||||
public delegate void RequestCallback(ref DiscordUser request);
|
||||
|
||||
public struct EventHandlers
|
||||
{
|
||||
public ReadyCallback readyCallback;
|
||||
public DisconnectedCallback disconnectedCallback;
|
||||
public ErrorCallback errorCallback;
|
||||
public JoinCallback joinCallback;
|
||||
public SpectateCallback spectateCallback;
|
||||
public RequestCallback requestCallback;
|
||||
}
|
||||
|
||||
[Serializable, StructLayout(LayoutKind.Sequential)]
|
||||
public struct RichPresenceStruct
|
||||
{
|
||||
public IntPtr state; /* max 128 bytes */
|
||||
public IntPtr details; /* max 128 bytes */
|
||||
public long startTimestamp;
|
||||
public long endTimestamp;
|
||||
public IntPtr largeImageKey; /* max 64 bytes */
|
||||
public IntPtr largeImageText; /* max 128 bytes */
|
||||
public IntPtr smallImageKey; /* max 32 bytes */
|
||||
public IntPtr smallImageText; /* max 128 bytes */
|
||||
public IntPtr partyId; /* max 128 bytes */
|
||||
public int partySize;
|
||||
public int partyMax;
|
||||
public IntPtr matchSecret; /* max 128 bytes */
|
||||
public IntPtr joinSecret; /* max 128 bytes */
|
||||
public IntPtr spectateSecret; /* max 128 bytes */
|
||||
public bool instance;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct DiscordUser
|
||||
{
|
||||
public string userId;
|
||||
public string username;
|
||||
public string discriminator;
|
||||
public string avatar;
|
||||
}
|
||||
|
||||
public enum Reply
|
||||
{
|
||||
No = 0,
|
||||
Yes = 1,
|
||||
Ignore = 2
|
||||
}
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_Initialize", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Initialize(string applicationId, ref EventHandlers handlers, bool autoRegister, string optionalSteamId);
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_Shutdown", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Shutdown();
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_RunCallbacks", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void RunCallbacks();
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_UpdatePresence", CallingConvention = CallingConvention.Cdecl)]
|
||||
private static extern void UpdatePresenceNative(ref RichPresenceStruct presence);
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_ClearPresence", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void ClearPresence();
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_Respond", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void Respond(string userId, Reply reply);
|
||||
|
||||
[DllImport("discord-rpc", EntryPoint = "Discord_UpdateHandlers", CallingConvention = CallingConvention.Cdecl)]
|
||||
public static extern void UpdateHandlers(ref EventHandlers handlers);
|
||||
|
||||
public static void UpdatePresence(RichPresence presence)
|
||||
{
|
||||
var presencestruct = presence.GetStruct();
|
||||
UpdatePresenceNative(ref presencestruct);
|
||||
presence.FreeMem();
|
||||
}
|
||||
|
||||
public class RichPresence
|
||||
{
|
||||
private RichPresenceStruct _presence;
|
||||
private readonly List<IntPtr> _buffers = new List<IntPtr>(10);
|
||||
|
||||
public string state; /* max 128 bytes */
|
||||
public string details; /* max 128 bytes */
|
||||
public long startTimestamp;
|
||||
public long endTimestamp;
|
||||
public string largeImageKey; /* max 64 bytes */
|
||||
public string largeImageText; /* max 128 bytes */
|
||||
public string smallImageKey; /* max 32 bytes */
|
||||
public string smallImageText; /* max 128 bytes */
|
||||
public string partyId; /* max 128 bytes */
|
||||
public int partySize;
|
||||
public int partyMax;
|
||||
public string matchSecret; /* max 128 bytes */
|
||||
public string joinSecret; /* max 128 bytes */
|
||||
public string spectateSecret; /* max 128 bytes */
|
||||
public bool instance;
|
||||
|
||||
/// <summary>
|
||||
/// Get the <see cref="RichPresenceStruct"/> reprensentation of this instance
|
||||
/// </summary>
|
||||
/// <returns><see cref="RichPresenceStruct"/> reprensentation of this instance</returns>
|
||||
internal RichPresenceStruct GetStruct()
|
||||
{
|
||||
if (_buffers.Count > 0)
|
||||
{
|
||||
FreeMem();
|
||||
}
|
||||
|
||||
_presence.state = StrToPtr(state, 128);
|
||||
_presence.details = StrToPtr(details, 128);
|
||||
_presence.startTimestamp = startTimestamp;
|
||||
_presence.endTimestamp = endTimestamp;
|
||||
_presence.largeImageKey = StrToPtr(largeImageKey, 64);
|
||||
_presence.largeImageText = StrToPtr(largeImageText, 128);
|
||||
_presence.smallImageKey = StrToPtr(smallImageKey, 32);
|
||||
_presence.smallImageText = StrToPtr(smallImageText, 128);
|
||||
_presence.partyId = StrToPtr(partyId, 128);
|
||||
_presence.partySize = partySize;
|
||||
_presence.partyMax = partyMax;
|
||||
_presence.matchSecret = StrToPtr(matchSecret, 128);
|
||||
_presence.joinSecret = StrToPtr(joinSecret, 128);
|
||||
_presence.spectateSecret = StrToPtr(spectateSecret, 128);
|
||||
_presence.instance = instance;
|
||||
|
||||
return _presence;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a pointer to a representation of the given string with a size of maxbytes
|
||||
/// </summary>
|
||||
/// <param name="input">String to convert</param>
|
||||
/// <param name="maxbytes">Max number of bytes to use</param>
|
||||
/// <returns>Pointer to the UTF-8 representation of <see cref="input"/></returns>
|
||||
private IntPtr StrToPtr(string input, int maxbytes)
|
||||
{
|
||||
if (string.IsNullOrEmpty(input)) return IntPtr.Zero;
|
||||
var convstr = StrClampBytes(input, maxbytes);
|
||||
var convbytecnt = Encoding.UTF8.GetByteCount(convstr);
|
||||
var buffer = Marshal.AllocHGlobal(convbytecnt);
|
||||
_buffers.Add(buffer);
|
||||
Marshal.Copy(Encoding.UTF8.GetBytes(convstr), 0, buffer, convbytecnt);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert string to UTF-8 and add null termination
|
||||
/// </summary>
|
||||
/// <param name="toconv">string to convert</param>
|
||||
/// <returns>UTF-8 representation of <see cref="toconv"/> with added null termination</returns>
|
||||
private static string StrToUtf8NullTerm(string toconv)
|
||||
{
|
||||
var str = toconv.Trim();
|
||||
var bytes = Encoding.Default.GetBytes(str);
|
||||
if (bytes.Length > 0 && bytes[bytes.Length - 1] != 0)
|
||||
{
|
||||
str += "\0\0";
|
||||
}
|
||||
return Encoding.UTF8.GetString(Encoding.UTF8.GetBytes(str));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamp the string to the given byte length preserving null termination
|
||||
/// </summary>
|
||||
/// <param name="toclamp">string to clamp</param>
|
||||
/// <param name="maxbytes">max bytes the resulting string should have (including null termination)</param>
|
||||
/// <returns>null terminated string with a byte length less or equal to <see cref="maxbytes"/></returns>
|
||||
private static string StrClampBytes(string toclamp, int maxbytes)
|
||||
{
|
||||
var str = StrToUtf8NullTerm(toclamp);
|
||||
var strbytes = Encoding.UTF8.GetBytes(str);
|
||||
|
||||
if (strbytes.Length <= maxbytes)
|
||||
{
|
||||
return str;
|
||||
}
|
||||
|
||||
var newstrbytes = new byte[] { };
|
||||
Array.Copy(strbytes, 0, newstrbytes, 0, maxbytes - 1);
|
||||
newstrbytes[newstrbytes.Length - 1] = 0;
|
||||
newstrbytes[newstrbytes.Length - 2] = 0;
|
||||
|
||||
return Encoding.UTF8.GetString(newstrbytes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Free the allocated memory for conversion to <see cref="RichPresenceStruct"/>
|
||||
/// </summary>
|
||||
internal void FreeMem()
|
||||
{
|
||||
for (var i = _buffers.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Marshal.FreeHGlobal(_buffers[i]);
|
||||
_buffers.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,9 +11,9 @@ namespace Ryujinx
|
|||
{
|
||||
class Program
|
||||
{
|
||||
private static DiscordRpc.RichPresence Presence;
|
||||
public static DiscordRPC.DiscordRpcClient DiscordClient;
|
||||
|
||||
private static DiscordRpc.EventHandlers Handlers;
|
||||
public static DiscordRPC.RichPresence DiscordPresence;
|
||||
|
||||
public static string ApplicationDirectory => AppDomain.CurrentDomain.BaseDirectory;
|
||||
|
||||
|
@ -21,18 +21,18 @@ namespace Ryujinx
|
|||
{
|
||||
Console.Title = "Ryujinx Console";
|
||||
|
||||
if (File.Exists("./discord-rpc.dll") || File.Exists("./discord-rpc.so"))
|
||||
{
|
||||
Handlers = new DiscordRpc.EventHandlers();
|
||||
Presence = new DiscordRpc.RichPresence();
|
||||
DiscordRpc.Initialize("568815339807309834", ref Handlers, true, null);
|
||||
Presence.details = "Ryujinx Console";
|
||||
Presence.state = "Reading the console logs...";
|
||||
Presence.startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||
Presence.largeImageKey = "ryujinx";
|
||||
Presence.largeImageText = "Ryujinx";
|
||||
DiscordRpc.UpdatePresence(Presence);
|
||||
}
|
||||
DiscordClient = new DiscordRPC.DiscordRpcClient("568815339807309834");
|
||||
DiscordPresence = new DiscordRPC.RichPresence();
|
||||
DiscordPresence.Assets = new DiscordRPC.Assets();
|
||||
DiscordPresence.Timestamps = new DiscordRPC.Timestamps(DateTime.UtcNow);
|
||||
|
||||
DiscordPresence.Details = "Ryujinx Console";
|
||||
DiscordPresence.State = "Reading the console logs...";
|
||||
DiscordPresence.Assets.LargeImageKey = "ryujinx";
|
||||
DiscordPresence.Assets.LargeImageText = "Ryujinx";
|
||||
|
||||
DiscordClient.Initialize();
|
||||
DiscordClient.SetPresence(DiscordPresence);
|
||||
|
||||
IGalRenderer renderer = new OglRenderer();
|
||||
|
||||
|
@ -117,11 +117,15 @@ namespace Ryujinx
|
|||
audioOut.Dispose();
|
||||
|
||||
Logger.Shutdown();
|
||||
|
||||
DiscordClient.Dispose();
|
||||
}
|
||||
|
||||
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
|
||||
{
|
||||
Logger.Shutdown();
|
||||
|
||||
DiscordClient.Dispose();
|
||||
}
|
||||
|
||||
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
|
@ -133,26 +137,25 @@ namespace Ryujinx
|
|||
if (e.IsTerminating)
|
||||
{
|
||||
Logger.Shutdown();
|
||||
|
||||
DiscordClient.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetGamePresence(Switch device)
|
||||
{
|
||||
if (File.Exists("./discord-rpc.dll") || File.Exists("./discord-rpc.so"))
|
||||
if (File.ReadAllLines("./RPsupported.dat").Contains(device.System.TitleID))
|
||||
{
|
||||
string[] RPsupported = File.ReadAllLines("./RPsupported");
|
||||
if (RPsupported.Contains(device.System.TitleID))
|
||||
{
|
||||
Presence.largeImageKey = device.System.TitleID;
|
||||
Presence.largeImageText = device.System.TitleName;
|
||||
}
|
||||
Presence.details = $"Playing {device.System.TitleName}";
|
||||
Presence.state = device.System.TitleID.ToUpper();
|
||||
Presence.smallImageKey = "ryujinx";
|
||||
Presence.smallImageText = "Ryujinx";
|
||||
Presence.startTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||
DiscordRpc.UpdatePresence(Presence);
|
||||
DiscordPresence.Assets.LargeImageKey = device.System.TitleID;
|
||||
DiscordPresence.Assets.LargeImageText = device.System.TitleName;
|
||||
}
|
||||
DiscordPresence.Details = $"Playing {device.System.TitleName}";
|
||||
DiscordPresence.State = device.System.TitleID.ToUpper();
|
||||
DiscordPresence.Assets.SmallImageKey = "ryujinx";
|
||||
DiscordPresence.Assets.SmallImageText = "Ryujinx";
|
||||
DiscordPresence.Timestamps = new DiscordRPC.Timestamps(DateTime.UtcNow);
|
||||
|
||||
DiscordClient.SetPresence(DiscordPresence);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscordRichPresence" Version="1.0.108" />
|
||||
<PackageReference Include="OpenTK.NetStandard" Version="1.0.4" />
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -23,7 +24,7 @@
|
|||
<None Update="Config.jsonc">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="RPsupported">
|
||||
<None Update="RPsupported.dat">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
|
Loading…
Add table
Reference in a new issue