DiscordIntegrationModule.cs 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using DiscordRPC;
  2. using Ryujinx.Common;
  3. using Ryujinx.UI.Common.Configuration;
  4. using System.Text;
  5. namespace Ryujinx.UI.Common
  6. {
  7. public static class DiscordIntegrationModule
  8. {
  9. private const string Description = "A simple, experimental Nintendo Switch emulator.";
  10. private const string ApplicationId = "1216775165866807456";
  11. private const int ApplicationByteLimit = 128;
  12. private const string Ellipsis = "…";
  13. private static DiscordRpcClient _discordClient;
  14. private static RichPresence _discordPresenceMain;
  15. public static void Initialize()
  16. {
  17. _discordPresenceMain = new RichPresence
  18. {
  19. Assets = new Assets
  20. {
  21. LargeImageKey = "ryujinx",
  22. LargeImageText = Description,
  23. },
  24. Details = "Main Menu",
  25. State = "Idling",
  26. Timestamps = Timestamps.Now,
  27. Buttons =
  28. [
  29. new Button
  30. {
  31. Label = "Website",
  32. Url = "https://ryujinx.org/",
  33. },
  34. ],
  35. };
  36. ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
  37. }
  38. private static void Update(object sender, ReactiveEventArgs<bool> evnt)
  39. {
  40. if (evnt.OldValue != evnt.NewValue)
  41. {
  42. // If the integration was active, disable it and unload everything
  43. if (evnt.OldValue)
  44. {
  45. _discordClient?.Dispose();
  46. _discordClient = null;
  47. }
  48. // If we need to activate it and the client isn't active, initialize it
  49. if (evnt.NewValue && _discordClient == null)
  50. {
  51. _discordClient = new DiscordRpcClient(ApplicationId);
  52. _discordClient.Initialize();
  53. _discordClient.SetPresence(_discordPresenceMain);
  54. }
  55. }
  56. }
  57. public static void SwitchToPlayingState(string titleId, string applicationName)
  58. {
  59. _discordClient?.SetPresence(new RichPresence
  60. {
  61. Assets = new Assets
  62. {
  63. LargeImageKey = "game",
  64. LargeImageText = TruncateToByteLength(applicationName, ApplicationByteLimit),
  65. SmallImageKey = "ryujinx",
  66. SmallImageText = Description,
  67. },
  68. Details = TruncateToByteLength($"Playing {applicationName}", ApplicationByteLimit),
  69. State = (titleId == "0000000000000000") ? "Homebrew" : titleId.ToUpper(),
  70. Timestamps = Timestamps.Now,
  71. Buttons =
  72. [
  73. new Button
  74. {
  75. Label = "Website",
  76. Url = "https://ryujinx.org/",
  77. },
  78. ],
  79. });
  80. }
  81. public static void SwitchToMainMenu()
  82. {
  83. _discordClient?.SetPresence(_discordPresenceMain);
  84. }
  85. private static string TruncateToByteLength(string input, int byteLimit)
  86. {
  87. if (Encoding.UTF8.GetByteCount(input) <= byteLimit)
  88. {
  89. return input;
  90. }
  91. // Find the length to trim the string to guarantee we have space for the trailing ellipsis.
  92. int trimLimit = byteLimit - Encoding.UTF8.GetByteCount(Ellipsis);
  93. // Make sure the string is long enough to perform the basic trim.
  94. // Amount of bytes != Length of the string
  95. if (input.Length > trimLimit)
  96. {
  97. // Basic trim to best case scenario of 1 byte characters.
  98. input = input[..trimLimit];
  99. }
  100. while (Encoding.UTF8.GetByteCount(input) > trimLimit)
  101. {
  102. // Remove one character from the end of the string at a time.
  103. input = input[..^1];
  104. }
  105. return input.TrimEnd() + Ellipsis;
  106. }
  107. public static void Exit()
  108. {
  109. _discordClient?.Dispose();
  110. }
  111. }
  112. }