mirror of
https://github.com/ppy/osu.git
synced 2025-02-20 05:36:05 +08:00
Rework spectator components to use new user state
This commit is contained in:
parent
41007169f7
commit
f4210f7a30
@ -93,12 +93,8 @@ namespace osu.Game.Online.Spectator
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
// UserBeganPlaying() is called by the server regardless of whether the local user is watching the remote user, and is called a further time when the remote user is watched.
|
||||
// This may be a temporary thing (see: https://github.com/ppy/osu-server-spectator/blob/2273778e02cfdb4a9c6a934f2a46a8459cb5d29c/osu.Server.Spectator/Hubs/SpectatorHub.cs#L28-L29).
|
||||
// We don't want the user states to update unless the player is being watched, otherwise calling BindUserBeganPlaying() can lead to double invocations.
|
||||
if (watchingUsers.Contains(userId))
|
||||
playingUserStates[userId] = state;
|
||||
|
||||
OnUserBeganPlaying?.Invoke(userId, state);
|
||||
});
|
||||
|
||||
@ -109,8 +105,8 @@ namespace osu.Game.Online.Spectator
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
playingUserStates.Remove(userId);
|
||||
|
||||
if (watchingUsers.Contains(userId))
|
||||
playingUserStates[userId] = state;
|
||||
OnUserFinishedPlaying?.Invoke(userId, state);
|
||||
});
|
||||
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Dashboard
|
||||
{
|
||||
internal class CurrentlyPlayingDisplay : CompositeDrawable
|
||||
{
|
||||
private readonly IBindableDictionary<int, SpectatorState> playingUserStates = new BindableDictionary<int, SpectatorState>();
|
||||
private readonly IBindableDictionary<int, SpectatorState> userStates = new BindableDictionary<int, SpectatorState>();
|
||||
|
||||
private FillFlowContainer<PlayingUserPanel> userFlow;
|
||||
|
||||
@ -51,33 +51,32 @@ namespace osu.Game.Overlays.Dashboard
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
playingUserStates.BindTo(spectatorClient.PlayingUserStates);
|
||||
playingUserStates.BindCollectionChanged(onUsersChanged, true);
|
||||
userStates.BindTo(spectatorClient.PlayingUserStates);
|
||||
userStates.BindCollectionChanged(onUserStatesChanged, true);
|
||||
}
|
||||
|
||||
private void onUsersChanged(object sender, NotifyDictionaryChangedEventArgs<int, SpectatorState> e) => Schedule(() =>
|
||||
private void onUserStatesChanged(object sender, NotifyDictionaryChangedEventArgs<int, SpectatorState> e) => Schedule(() =>
|
||||
{
|
||||
switch (e.Action)
|
||||
{
|
||||
case NotifyDictionaryChangedAction.Add:
|
||||
case NotifyDictionaryChangedAction.Replace:
|
||||
Debug.Assert(e.NewItems != null);
|
||||
|
||||
foreach ((int userId, _) in e.NewItems)
|
||||
foreach ((int userId, SpectatorState state) in e.NewItems)
|
||||
{
|
||||
if (state.State != SpectatingUserState.Playing)
|
||||
{
|
||||
removePlayingUser(userId);
|
||||
continue;
|
||||
}
|
||||
|
||||
users.GetUserAsync(userId).ContinueWith(task =>
|
||||
{
|
||||
var user = task.GetResultSafely();
|
||||
|
||||
if (user == null) return;
|
||||
|
||||
Schedule(() =>
|
||||
{
|
||||
// user may no longer be playing.
|
||||
if (!playingUserStates.ContainsKey(user.Id))
|
||||
return;
|
||||
|
||||
userFlow.Add(createUserPanel(user));
|
||||
});
|
||||
if (user != null)
|
||||
Schedule(() => addPlayingUser(user));
|
||||
});
|
||||
}
|
||||
|
||||
@ -87,9 +86,20 @@ namespace osu.Game.Overlays.Dashboard
|
||||
Debug.Assert(e.OldItems != null);
|
||||
|
||||
foreach ((int userId, _) in e.OldItems)
|
||||
userFlow.FirstOrDefault(card => card.User.Id == userId)?.Expire();
|
||||
removePlayingUser(userId);
|
||||
break;
|
||||
}
|
||||
|
||||
void addPlayingUser(APIUser user)
|
||||
{
|
||||
// user may no longer be playing.
|
||||
if (!userStates.TryGetValue(user.Id, out var state2) || state2.State != SpectatingUserState.Playing)
|
||||
return;
|
||||
|
||||
userFlow.Add(createUserPanel(user));
|
||||
}
|
||||
|
||||
void removePlayingUser(int userId) => userFlow.FirstOrDefault(card => card.User.Id == userId)?.Expire();
|
||||
});
|
||||
|
||||
private PlayingUserPanel createUserPanel(APIUser user) =>
|
||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Screens.Spectate
|
||||
[Resolved]
|
||||
private UserLookupCache userLookupCache { get; set; }
|
||||
|
||||
private readonly IBindableDictionary<int, SpectatorState> playingUserStates = new BindableDictionary<int, SpectatorState>();
|
||||
private readonly IBindableDictionary<int, SpectatorState> userStates = new BindableDictionary<int, SpectatorState>();
|
||||
|
||||
private readonly Dictionary<int, APIUser> userMap = new Dictionary<int, APIUser>();
|
||||
private readonly Dictionary<int, SpectatorGameplayState> gameplayStates = new Dictionary<int, SpectatorGameplayState>();
|
||||
@ -77,8 +77,8 @@ namespace osu.Game.Screens.Spectate
|
||||
userMap[u.Id] = u;
|
||||
}
|
||||
|
||||
playingUserStates.BindTo(spectatorClient.PlayingUserStates);
|
||||
playingUserStates.BindCollectionChanged(onPlayingUserStatesChanged, true);
|
||||
userStates.BindTo(spectatorClient.PlayingUserStates);
|
||||
userStates.BindCollectionChanged(onUserStatesChanged, true);
|
||||
|
||||
realmSubscription = realm.RegisterForNotifications(
|
||||
realm => realm.All<BeatmapSetInfo>().Where(s => !s.DeletePending), beatmapsChanged);
|
||||
@ -99,7 +99,7 @@ namespace osu.Game.Screens.Spectate
|
||||
{
|
||||
foreach ((int userId, _) in userMap)
|
||||
{
|
||||
if (!playingUserStates.TryGetValue(userId, out var userState))
|
||||
if (!userStates.TryGetValue(userId, out var userState))
|
||||
continue;
|
||||
|
||||
if (beatmapSet.Beatmaps.Any(b => b.OnlineID == userState.BeatmapID))
|
||||
@ -107,40 +107,41 @@ namespace osu.Game.Screens.Spectate
|
||||
}
|
||||
}
|
||||
|
||||
private void onPlayingUserStatesChanged(object sender, NotifyDictionaryChangedEventArgs<int, SpectatorState> e)
|
||||
private void onUserStatesChanged(object sender, NotifyDictionaryChangedEventArgs<int, SpectatorState> e)
|
||||
{
|
||||
switch (e.Action)
|
||||
{
|
||||
case NotifyDictionaryChangedAction.Add:
|
||||
foreach ((int userId, var state) in e.NewItems.AsNonNull())
|
||||
onUserStateAdded(userId, state);
|
||||
onUserStateChanged(userId, state);
|
||||
break;
|
||||
|
||||
case NotifyDictionaryChangedAction.Remove:
|
||||
foreach ((int userId, var _) in e.OldItems.AsNonNull())
|
||||
foreach ((int userId, _) in e.OldItems.AsNonNull())
|
||||
onUserStateRemoved(userId);
|
||||
break;
|
||||
|
||||
case NotifyDictionaryChangedAction.Replace:
|
||||
foreach ((int userId, var _) in e.OldItems.AsNonNull())
|
||||
onUserStateRemoved(userId);
|
||||
|
||||
foreach ((int userId, var state) in e.NewItems.AsNonNull())
|
||||
onUserStateAdded(userId, state);
|
||||
onUserStateChanged(userId, state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onUserStateAdded(int userId, SpectatorState state)
|
||||
private void onUserStateChanged(int userId, SpectatorState newState)
|
||||
{
|
||||
if (state.RulesetID == null || state.BeatmapID == null)
|
||||
if (newState.RulesetID == null || newState.BeatmapID == null)
|
||||
return;
|
||||
|
||||
if (!userMap.ContainsKey(userId))
|
||||
return;
|
||||
|
||||
Schedule(() => OnUserStateChanged(userId, state));
|
||||
updateGameplayState(userId);
|
||||
// Do nothing for failed/completed states.
|
||||
if (newState.State == SpectatingUserState.Playing)
|
||||
{
|
||||
Schedule(() => OnUserStateChanged(userId, newState));
|
||||
updateGameplayState(userId);
|
||||
}
|
||||
}
|
||||
|
||||
private void onUserStateRemoved(int userId)
|
||||
@ -162,7 +163,7 @@ namespace osu.Game.Screens.Spectate
|
||||
Debug.Assert(userMap.ContainsKey(userId));
|
||||
|
||||
var user = userMap[userId];
|
||||
var spectatorState = playingUserStates[userId];
|
||||
var spectatorState = userStates[userId];
|
||||
|
||||
var resolvedRuleset = rulesets.AvailableRulesets.FirstOrDefault(r => r.OnlineID == spectatorState.RulesetID)?.CreateInstance();
|
||||
if (resolvedRuleset == null)
|
||||
|
Loading…
Reference in New Issue
Block a user