From 680b5b719aa10366cd10abb0dbd2444a95e28c9a Mon Sep 17 00:00:00 2001 From: awesomeangotti Date: Sun, 5 Jul 2026 20:29:39 +0000 Subject: [PATCH] Discord Rich Presence: Allow selective writing to multiple (two) lines of RPC from play reports (#154) This PR implements a method inside the DiscordIntegrationModule class to allow a playreport parser (IDK if that is the actual name) to return information for both lines usable by playreports. It has complete backwards compatibility with all previous methods. Through the magic of JSON, multiline RPC is mine to command Reviewed-on: https://git.ryujinx.app/projects/Ryubing/pulls/154 --- .../Systems/DiscordIntegrationModule.cs | 42 ++++++++++++++++--- 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/Ryujinx/Systems/DiscordIntegrationModule.cs b/src/Ryujinx/Systems/DiscordIntegrationModule.cs index 195840133..38b2c174c 100644 --- a/src/Ryujinx/Systems/DiscordIntegrationModule.cs +++ b/src/Ryujinx/Systems/DiscordIntegrationModule.cs @@ -9,7 +9,9 @@ using Ryujinx.Common.Logging; using Ryujinx.HLE; using Ryujinx.HLE.Loaders.Processes; using Ryujinx.Horizon; +using System.Collections.Generic; using System.Text; +using System.Text.Json; namespace Ryujinx.Ava.Systems { @@ -135,20 +137,48 @@ namespace Ryujinx.Ava.Systems if (!formattedValue.Handled) return; + - _discordPresencePlaying.Details = TruncateToByteLength( - formattedValue.Reset - ? $"Playing {_currentApp.Title}" - : formattedValue.FormattedString - ); + + try // New format that attempts to deserialize json, and if it fails (using old method)... + { + Dictionary outDictionary = JsonSerializer.Deserialize>(formattedValue.FormattedString); + + _discordPresencePlaying.Details = TruncateToByteLength( + outDictionary["Details"].IsNullOrEmpty() + ? $"Playing {_currentApp.Title}" + : outDictionary["Details"] + ); + + _discordPresencePlaying.State = TruncateToByteLength( + outDictionary["State"].IsNullOrEmpty() + ? $"Total play time: {ValueFormatUtils.FormatTimeSpan(_currentApp.TimePlayed)}" + : outDictionary["State"] + ); - if (_discordClient.CurrentPresence.Details.Equals(_discordPresencePlaying.Details)) + } + catch // Utilize original code + { + _discordPresencePlaying.Details = TruncateToByteLength( + formattedValue.Reset + ? $"Playing {_currentApp.Title}" + : formattedValue.FormattedString + ); + } + + if (_discordClient.CurrentPresence.Details.Equals(_discordPresencePlaying.Details) && _discordClient.CurrentPresence.State.Equals(_discordPresencePlaying.State)) return; //don't trigger an update if the set presence Details are identical to current _discordClient.SetPresence(_discordPresencePlaying); Logger.Info?.Print(LogClass.UI, "Updated Discord RPC based on a supported play report."); } + public static string PrepareMultilineRpcString(string line1 = "", string line2 = "") + { + Dictionary rpcdict = new() { { "Details", line1 }, {"State", line2} }; + return JsonSerializer.Serialize(rpcdict); + } + private static string TruncateToByteLength(string input) { if (Encoding.UTF8.GetByteCount(input) <= ApplicationByteLimit)