1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-14 03:22:57 +08:00

Organise code, still hook up to RoomChanged to update room privacy mode, and use SkipIdenticalPresence + scheduling to avoid potential rate-limits

This commit is contained in:
Salman Ahmed 2024-03-20 06:40:18 +03:00
parent 1a08dbaa2b
commit b11ae1c571

View File

@ -2,16 +2,16 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Diagnostics;
using System.Text; using System.Text;
using DiscordRPC; using DiscordRPC;
using DiscordRPC.Message; using DiscordRPC.Message;
using Newtonsoft.Json; using Newtonsoft.Json;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Development; using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Framework.Threading;
using osu.Game; using osu.Game;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Extensions; using osu.Game.Extensions;
@ -53,8 +53,6 @@ namespace osu.Desktop
private readonly Bindable<DiscordRichPresenceMode> privacyMode = new Bindable<DiscordRichPresenceMode>(); private readonly Bindable<DiscordRichPresenceMode> privacyMode = new Bindable<DiscordRichPresenceMode>();
private int usersCurrentlyInLobby;
private readonly RichPresence presence = new RichPresence private readonly RichPresence presence = new RichPresence
{ {
Assets = new Assets { LargeImageKey = "osu_logo_lazer" }, Assets = new Assets { LargeImageKey = "osu_logo_lazer" },
@ -72,7 +70,9 @@ namespace osu.Desktop
client = new DiscordRpcClient(client_id) client = new DiscordRpcClient(client_id)
{ {
SkipIdenticalPresence = false // handles better on discord IPC loss, see updateStatus call in onReady. // SkipIdenticalPresence allows us to fire SetPresence at any point and leave it to the underlying implementation
// to check whether a difference has actually occurred before sending a command to Discord (with a minor caveat that's handled in onReady).
SkipIdenticalPresence = true
}; };
client.OnReady += onReady; client.OnReady += onReady;
@ -95,10 +95,11 @@ namespace osu.Desktop
activity.BindTo(u.NewValue.Activity); activity.BindTo(u.NewValue.Activity);
}, true); }, true);
ruleset.BindValueChanged(_ => updateStatus()); ruleset.BindValueChanged(_ => updatePresence());
status.BindValueChanged(_ => updateStatus()); status.BindValueChanged(_ => updatePresence());
activity.BindValueChanged(_ => updateStatus()); activity.BindValueChanged(_ => updatePresence());
privacyMode.BindValueChanged(_ => updateStatus()); privacyMode.BindValueChanged(_ => updatePresence());
multiplayerClient.RoomUpdated += onRoomUpdated;
client.Initialize(); client.Initialize();
} }
@ -106,24 +107,44 @@ namespace osu.Desktop
private void onReady(object _, ReadyMessage __) private void onReady(object _, ReadyMessage __)
{ {
Logger.Log("Discord RPC Client ready.", LoggingTarget.Network, LogLevel.Debug); Logger.Log("Discord RPC Client ready.", LoggingTarget.Network, LogLevel.Debug);
Schedule(updateStatus);
// when RPC is lost and reconnected, we have to clear presence state for updatePresence to work (see DiscordRpcClient.SkipIdenticalPresence).
if (client.CurrentPresence != null)
client.SetPresence(null);
updatePresence();
} }
private void updateStatus() private void onRoomUpdated() => updatePresence();
private ScheduledDelegate? presenceUpdateDelegate;
private void updatePresence()
{ {
Debug.Assert(ThreadSafety.IsUpdateThread); presenceUpdateDelegate?.Cancel();
presenceUpdateDelegate = Scheduler.AddDelayed(() =>
if (!client.IsInitialized)
return;
if (status.Value == UserStatus.Offline || privacyMode.Value == DiscordRichPresenceMode.Off)
{ {
client.ClearPresence(); if (!client.IsInitialized)
return; return;
}
bool hideIdentifiableInformation = privacyMode.Value == DiscordRichPresenceMode.Limited || status.Value == UserStatus.DoNotDisturb; if (status.Value == UserStatus.Offline || privacyMode.Value == DiscordRichPresenceMode.Off)
{
client.ClearPresence();
return;
}
bool hideIdentifiableInformation = privacyMode.Value == DiscordRichPresenceMode.Limited || status.Value == UserStatus.DoNotDisturb;
updatePresenceStatus(hideIdentifiableInformation);
updatePresenceParty(hideIdentifiableInformation);
updatePresenceAssets();
client.SetPresence(presence);
}, 200);
}
private void updatePresenceStatus(bool hideIdentifiableInformation)
{
if (activity.Value != null) if (activity.Value != null)
{ {
presence.State = truncate(activity.Value.GetStatus(hideIdentifiableInformation)); presence.State = truncate(activity.Value.GetStatus(hideIdentifiableInformation));
@ -150,14 +171,14 @@ namespace osu.Desktop
presence.State = "Idle"; presence.State = "Idle";
presence.Details = string.Empty; presence.Details = string.Empty;
} }
}
private void updatePresenceParty(bool hideIdentifiableInformation)
{
if (!hideIdentifiableInformation && multiplayerClient.Room != null) if (!hideIdentifiableInformation && multiplayerClient.Room != null)
{ {
MultiplayerRoom room = multiplayerClient.Room; MultiplayerRoom room = multiplayerClient.Room;
if (room.Users.Count == usersCurrentlyInLobby)
return;
presence.Party = new Party presence.Party = new Party
{ {
Privacy = string.IsNullOrEmpty(room.Settings.Password) ? Party.PrivacySetting.Public : Party.PrivacySetting.Private, Privacy = string.IsNullOrEmpty(room.Settings.Password) ? Party.PrivacySetting.Public : Party.PrivacySetting.Private,
@ -175,17 +196,16 @@ namespace osu.Desktop
}; };
presence.Secrets.JoinSecret = JsonConvert.SerializeObject(roomSecret); presence.Secrets.JoinSecret = JsonConvert.SerializeObject(roomSecret);
usersCurrentlyInLobby = room.Users.Count;
} }
else else
{ {
presence.Party = null; presence.Party = null;
presence.Secrets.JoinSecret = null; presence.Secrets.JoinSecret = null;
usersCurrentlyInLobby = 0;
} }
}
Logger.Log($"Updating Discord RPC presence with activity status: {presence.State}, details: {presence.Details}", LoggingTarget.Network, LogLevel.Debug); private void updatePresenceAssets()
{
// update user information // update user information
if (privacyMode.Value == DiscordRichPresenceMode.Limited) if (privacyMode.Value == DiscordRichPresenceMode.Limited)
presence.Assets.LargeImageText = string.Empty; presence.Assets.LargeImageText = string.Empty;
@ -200,17 +220,15 @@ namespace osu.Desktop
// update ruleset // update ruleset
presence.Assets.SmallImageKey = ruleset.Value.IsLegacyRuleset() ? $"mode_{ruleset.Value.OnlineID}" : "mode_custom"; presence.Assets.SmallImageKey = ruleset.Value.IsLegacyRuleset() ? $"mode_{ruleset.Value.OnlineID}" : "mode_custom";
presence.Assets.SmallImageText = ruleset.Value.Name; presence.Assets.SmallImageText = ruleset.Value.Name;
client.SetPresence(presence);
} }
private void onJoin(object sender, JoinMessage args) private void onJoin(object sender, JoinMessage args) => Scheduler.AddOnce(() =>
{ {
game.Window?.Raise(); game.Window?.Raise();
if (!api.IsLoggedIn) if (!api.IsLoggedIn)
{ {
Schedule(() => login?.Show()); login?.Show();
return; return;
} }
@ -231,7 +249,7 @@ namespace osu.Desktop
}); });
request.Failure += _ => Logger.Log($"Could not join multiplayer room, room could not be found (room ID: {roomId}).", LoggingTarget.Network, LogLevel.Important); request.Failure += _ => Logger.Log($"Could not join multiplayer room, room could not be found (room ID: {roomId}).", LoggingTarget.Network, LogLevel.Important);
api.Queue(request); api.Queue(request);
} });
private static readonly int ellipsis_length = Encoding.UTF8.GetByteCount(new[] { '…' }); private static readonly int ellipsis_length = Encoding.UTF8.GetByteCount(new[] { '…' });
@ -294,6 +312,9 @@ namespace osu.Desktop
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
if (multiplayerClient.IsNotNull())
multiplayerClient.RoomUpdated -= onRoomUpdated;
client.Dispose(); client.Dispose();
base.Dispose(isDisposing); base.Dispose(isDisposing);
} }