This repository was archived by the owner on Sep 30, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
343 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -328,3 +328,4 @@ ASALocalRun/ | |
|
||
# MFractors (Xamarin productivity tool) working folder | ||
.mfractor/ | ||
BeatSaberDiscordPresence/libs/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BeatSaberDiscordPresence", "BeatSaberDiscordPresence\BeatSaberDiscordPresence.csproj", "{0A3B23AC-9395-49EF-BD55-57BAC10947AE}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{0A3B23AC-9395-49EF-BD55-57BAC10947AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{0A3B23AC-9395-49EF-BD55-57BAC10947AE}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{0A3B23AC-9395-49EF-BD55-57BAC10947AE}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{0A3B23AC-9395-49EF-BD55-57BAC10947AE}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
<?xml version="1.0" encoding="utf-8"?> | ||
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> | ||
<PropertyGroup> | ||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> | ||
<ProjectGuid>{0A3B23AC-9395-49EF-BD55-57BAC10947AE}</ProjectGuid> | ||
<OutputType>Library</OutputType> | ||
<AppDesignerFolder>Properties</AppDesignerFolder> | ||
<RootNamespace>BeatSaberDiscordPresence</RootNamespace> | ||
<AssemblyName>BeatSaberDiscordPresence</AssemblyName> | ||
<TargetFrameworkVersion>v3.5</TargetFrameworkVersion> | ||
<FileAlignment>512</FileAlignment> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> | ||
<PlatformTarget>AnyCPU</PlatformTarget> | ||
<DebugSymbols>true</DebugSymbols> | ||
<DebugType>full</DebugType> | ||
<Optimize>false</Optimize> | ||
<OutputPath>bin\Debug\</OutputPath> | ||
<DefineConstants>DEBUG;TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> | ||
<PlatformTarget>AnyCPU</PlatformTarget> | ||
<DebugType>pdbonly</DebugType> | ||
<Optimize>true</Optimize> | ||
<OutputPath>bin\Release\</OutputPath> | ||
<DefineConstants>TRACE</DefineConstants> | ||
<ErrorReport>prompt</ErrorReport> | ||
<WarningLevel>4</WarningLevel> | ||
</PropertyGroup> | ||
<ItemGroup> | ||
<Reference Include="Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | ||
<HintPath>D:\SteamLibrary\steamapps\common\Beat Saber\Beat Saber_Data\Managed\Assembly-CSharp.dll</HintPath> | ||
</Reference> | ||
<Reference Include="discord-rpc"> | ||
<HintPath>libs\discord-rpc.dll</HintPath> | ||
</Reference> | ||
<Reference Include="IllusionPlugin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"> | ||
<HintPath>D:\SteamLibrary\steamapps\common\Beat Saber\Beat Saber_Data\Managed\IllusionPlugin.dll</HintPath> | ||
</Reference> | ||
<Reference Include="System" /> | ||
<Reference Include="System.Core" /> | ||
<Reference Include="System.Data" /> | ||
<Reference Include="System.Xml" /> | ||
<Reference Include="UnityEngine, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | ||
<HintPath>D:\SteamLibrary\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.dll</HintPath> | ||
</Reference> | ||
<Reference Include="UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null"> | ||
<HintPath>D:\SteamLibrary\steamapps\common\Beat Saber\Beat Saber_Data\Managed\UnityEngine.CoreModule.dll</HintPath> | ||
</Reference> | ||
</ItemGroup> | ||
<ItemGroup> | ||
<Compile Include="DiscordRpc.cs" /> | ||
<Compile Include="Plugin.cs" /> | ||
<Compile Include="Properties\AssemblyInfo.cs" /> | ||
</ItemGroup> | ||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> | ||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it. | ||
Other similar extension points exist, see Microsoft.Common.targets. | ||
<Target Name="BeforeBuild"> | ||
</Target> | ||
<Target Name="AfterBuild"> | ||
</Target> | ||
--> | ||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,223 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Runtime.InteropServices; | ||
using System.Text; | ||
|
||
namespace BeatSaberDiscordPresence | ||
{ | ||
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 32 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 32 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, 32); | ||
_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); | ||
} | ||
} | ||
} | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
using System.Reflection; | ||
using System.Runtime.InteropServices; | ||
|
||
// General Information about an assembly is controlled through the following | ||
// set of attributes. Change these attribute values to modify the information | ||
// associated with an assembly. | ||
[assembly: AssemblyTitle("BeatSaberDiscordPresence")] | ||
[assembly: AssemblyDescription("")] | ||
[assembly: AssemblyConfiguration("")] | ||
[assembly: AssemblyCompany("")] | ||
[assembly: AssemblyProduct("BeatSaberDiscordPresence")] | ||
[assembly: AssemblyCopyright("Copyright © 2018")] | ||
[assembly: AssemblyTrademark("")] | ||
[assembly: AssemblyCulture("")] | ||
|
||
// Setting ComVisible to false makes the types in this assembly not visible | ||
// to COM components. If you need to access a type in this assembly from | ||
// COM, set the ComVisible attribute to true on that type. | ||
[assembly: ComVisible(false)] | ||
|
||
// The following GUID is for the ID of the typelib if this project is exposed to COM | ||
[assembly: Guid("0A3B23AC-9395-49EF-BD55-57BAC10947AE")] | ||
|
||
// Version information for an assembly consists of the following four values: | ||
// | ||
// Major Version | ||
// Minor Version | ||
// Build Number | ||
// Revision | ||
// | ||
// You can specify all the values or you can default the Build and Revision Numbers | ||
// by using the '*' as shown below: | ||
// [assembly: AssemblyVersion("1.0.*")] | ||
[assembly: AssemblyVersion("1.0.0.0")] | ||
[assembly: AssemblyFileVersion("1.0.0.0")] |