mirror of
https://github.com/ppy/osu
synced 2025-04-01 22:48:33 +00:00
Merge pull request #17767 from peppy/multiplayer-gameplay-leaderboard-test-improvements
Refactor multiplayer gameplay leaderboard tests to remove reliance on `Test` implementations
This commit is contained in:
commit
94e2a90af2
@ -0,0 +1,204 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using Moq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Testing;
|
||||||
|
using osu.Framework.Utils;
|
||||||
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Online.API;
|
||||||
|
using osu.Game.Online.API.Requests.Responses;
|
||||||
|
using osu.Game.Online.Multiplayer;
|
||||||
|
using osu.Game.Online.Spectator;
|
||||||
|
using osu.Game.Replays.Legacy;
|
||||||
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Play.HUD;
|
||||||
|
|
||||||
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
|
{
|
||||||
|
public abstract class MultiplayerGameplayLeaderboardTestScene : OsuTestScene
|
||||||
|
{
|
||||||
|
protected readonly BindableList<MultiplayerRoomUser> MultiplayerUsers = new BindableList<MultiplayerRoomUser>();
|
||||||
|
|
||||||
|
protected MultiplayerGameplayLeaderboard Leaderboard { get; private set; }
|
||||||
|
|
||||||
|
protected virtual MultiplayerRoomUser CreateUser(int userId) => new MultiplayerRoomUser(userId);
|
||||||
|
|
||||||
|
protected abstract MultiplayerGameplayLeaderboard CreateLeaderboard(OsuScoreProcessor scoreProcessor);
|
||||||
|
|
||||||
|
private readonly BindableList<int> multiplayerUserIds = new BindableList<int>();
|
||||||
|
|
||||||
|
private OsuConfigManager config;
|
||||||
|
|
||||||
|
private readonly Mock<SpectatorClient> spectatorClient = new Mock<SpectatorClient>();
|
||||||
|
private readonly Mock<MultiplayerClient> multiplayerClient = new Mock<MultiplayerClient>();
|
||||||
|
|
||||||
|
private readonly Dictionary<int, FrameHeader> lastHeaders = new Dictionary<int, FrameHeader>();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
|
||||||
|
Dependencies.CacheAs(spectatorClient.Object);
|
||||||
|
Dependencies.CacheAs(multiplayerClient.Object);
|
||||||
|
|
||||||
|
// To emulate `MultiplayerClient.CurrentMatchPlayingUserIds` we need a bindable list of *only IDs*.
|
||||||
|
// This tracks the list of users 1:1.
|
||||||
|
MultiplayerUsers.BindCollectionChanged((c, e) =>
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
Debug.Assert(e.NewItems != null);
|
||||||
|
|
||||||
|
foreach (var user in e.NewItems.OfType<MultiplayerRoomUser>())
|
||||||
|
multiplayerUserIds.Add(user.UserID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Remove:
|
||||||
|
Debug.Assert(e.OldItems != null);
|
||||||
|
|
||||||
|
foreach (var user in e.OldItems.OfType<MultiplayerRoomUser>())
|
||||||
|
multiplayerUserIds.Remove(user.UserID);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NotifyCollectionChangedAction.Reset:
|
||||||
|
multiplayerUserIds.Clear();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
multiplayerClient.SetupGet(c => c.CurrentMatchPlayingUserIds)
|
||||||
|
.Returns(() => multiplayerUserIds);
|
||||||
|
}
|
||||||
|
|
||||||
|
[SetUpSteps]
|
||||||
|
public virtual void SetUpSteps()
|
||||||
|
{
|
||||||
|
AddStep("reset counts", () => spectatorClient.Invocations.Clear());
|
||||||
|
|
||||||
|
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = new APIUser
|
||||||
|
{
|
||||||
|
Id = 1,
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("populate users", () =>
|
||||||
|
{
|
||||||
|
MultiplayerUsers.Clear();
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
MultiplayerUsers.Add(CreateUser(i));
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("create leaderboard", () =>
|
||||||
|
{
|
||||||
|
Leaderboard?.Expire();
|
||||||
|
|
||||||
|
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
||||||
|
var playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
|
||||||
|
OsuScoreProcessor scoreProcessor = new OsuScoreProcessor();
|
||||||
|
scoreProcessor.ApplyBeatmap(playableBeatmap);
|
||||||
|
|
||||||
|
Child = scoreProcessor;
|
||||||
|
|
||||||
|
LoadComponentAsync(Leaderboard = CreateLeaderboard(scoreProcessor), Add);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddUntilStep("wait for load", () => Leaderboard.IsLoaded);
|
||||||
|
|
||||||
|
AddStep("check watch requests were sent", () =>
|
||||||
|
{
|
||||||
|
foreach (var user in MultiplayerUsers)
|
||||||
|
spectatorClient.Verify(s => s.WatchUser(user.UserID), Times.Once);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestScoreUpdates()
|
||||||
|
{
|
||||||
|
AddRepeatStep("update state", UpdateUserStatesRandomly, 100);
|
||||||
|
AddToggleStep("switch compact mode", expanded => Leaderboard.Expanded.Value = expanded);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestUserQuit()
|
||||||
|
{
|
||||||
|
AddUntilStep("mark users quit", () =>
|
||||||
|
{
|
||||||
|
if (MultiplayerUsers.Count == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
MultiplayerUsers.RemoveAt(0);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("check stop watching requests were sent", () =>
|
||||||
|
{
|
||||||
|
foreach (var user in MultiplayerUsers)
|
||||||
|
spectatorClient.Verify(s => s.StopWatchingUser(user.UserID), Times.Once);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestChangeScoringMode()
|
||||||
|
{
|
||||||
|
AddRepeatStep("update state", UpdateUserStatesRandomly, 5);
|
||||||
|
AddStep("change to classic", () => config.SetValue(OsuSetting.ScoreDisplayMode, ScoringMode.Classic));
|
||||||
|
AddStep("change to standardised", () => config.SetValue(OsuSetting.ScoreDisplayMode, ScoringMode.Standardised));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void UpdateUserStatesRandomly()
|
||||||
|
{
|
||||||
|
foreach (var user in MultiplayerUsers)
|
||||||
|
{
|
||||||
|
if (RNG.NextBool())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int userId = user.UserID;
|
||||||
|
|
||||||
|
if (!lastHeaders.TryGetValue(userId, out var header))
|
||||||
|
{
|
||||||
|
lastHeaders[userId] = header = new FrameHeader(new ScoreInfo
|
||||||
|
{
|
||||||
|
Statistics = new Dictionary<HitResult, int>
|
||||||
|
{
|
||||||
|
[HitResult.Miss] = 0,
|
||||||
|
[HitResult.Meh] = 0,
|
||||||
|
[HitResult.Great] = 0
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (RNG.Next(0, 3))
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
header.Combo = 0;
|
||||||
|
header.Statistics[HitResult.Miss]++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
header.Combo++;
|
||||||
|
header.MaxCombo = Math.Max(header.MaxCombo, header.Combo);
|
||||||
|
header.Statistics[HitResult.Meh]++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
header.Combo++;
|
||||||
|
header.MaxCombo = Math.Max(header.MaxCombo, header.Combo);
|
||||||
|
header.Statistics[HitResult.Great]++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
spectatorClient.Raise(s => s.OnNewFrames -= null, userId, new FrameDataBundle(header, new[] { new LegacyReplayFrame(Time.Current, 0, 0, ReplayButtonState.None) }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,161 +1,22 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Allocation;
|
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Extensions.ObjectExtensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Utils;
|
|
||||||
using osu.Game.Configuration;
|
|
||||||
using osu.Game.Online.API;
|
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
using osu.Game.Online.Multiplayer;
|
|
||||||
using osu.Game.Online.Spectator;
|
|
||||||
using osu.Game.Replays.Legacy;
|
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osu.Game.Rulesets.Scoring;
|
|
||||||
using osu.Game.Scoring;
|
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
|
||||||
using osu.Game.Tests.Visual.Spectator;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
{
|
{
|
||||||
public class TestSceneMultiplayerGameplayLeaderboard : MultiplayerTestScene
|
public class TestSceneMultiplayerGameplayLeaderboard : MultiplayerGameplayLeaderboardTestScene
|
||||||
{
|
{
|
||||||
private static IEnumerable<int> users => Enumerable.Range(0, 16);
|
protected override MultiplayerGameplayLeaderboard CreateLeaderboard(OsuScoreProcessor scoreProcessor)
|
||||||
|
|
||||||
public new TestMultiplayerSpectatorClient SpectatorClient => (TestMultiplayerSpectatorClient)OnlinePlayDependencies?.SpectatorClient;
|
|
||||||
|
|
||||||
private MultiplayerGameplayLeaderboard leaderboard;
|
|
||||||
private OsuConfigManager config;
|
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
|
||||||
private void load()
|
|
||||||
{
|
{
|
||||||
Dependencies.Cache(config = new OsuConfigManager(LocalStorage));
|
return new MultiplayerGameplayLeaderboard(Ruleset.Value, scoreProcessor, MultiplayerUsers.ToArray())
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetUpSteps()
|
|
||||||
{
|
|
||||||
base.SetUpSteps();
|
|
||||||
|
|
||||||
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = UserLookupCache.GetUserAsync(1).GetResultSafely());
|
|
||||||
|
|
||||||
AddStep("create leaderboard", () =>
|
|
||||||
{
|
{
|
||||||
leaderboard?.Expire();
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
OsuScoreProcessor scoreProcessor;
|
};
|
||||||
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
|
||||||
|
|
||||||
var playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
|
|
||||||
var multiplayerUsers = new List<MultiplayerRoomUser>();
|
|
||||||
|
|
||||||
foreach (int user in users)
|
|
||||||
{
|
|
||||||
SpectatorClient.SendStartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
|
|
||||||
multiplayerUsers.Add(OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = user }, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
scoreProcessor = new OsuScoreProcessor(),
|
|
||||||
};
|
|
||||||
|
|
||||||
scoreProcessor.ApplyBeatmap(playableBeatmap);
|
|
||||||
|
|
||||||
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(Ruleset.Value, scoreProcessor, multiplayerUsers.ToArray())
|
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
}, Add);
|
|
||||||
});
|
|
||||||
|
|
||||||
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
|
|
||||||
AddUntilStep("wait for user population", () => MultiplayerClient.CurrentMatchPlayingUserIds.Count > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestScoreUpdates()
|
|
||||||
{
|
|
||||||
AddRepeatStep("update state", () => SpectatorClient.RandomlyUpdateState(), 100);
|
|
||||||
AddToggleStep("switch compact mode", expanded => leaderboard.Expanded.Value = expanded);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestUserQuit()
|
|
||||||
{
|
|
||||||
foreach (int user in users)
|
|
||||||
AddStep($"mark user {user} quit", () => MultiplayerClient.RemoveUser(UserLookupCache.GetUserAsync(user).GetResultSafely().AsNonNull()));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestChangeScoringMode()
|
|
||||||
{
|
|
||||||
AddRepeatStep("update state", () => SpectatorClient.RandomlyUpdateState(), 5);
|
|
||||||
AddStep("change to classic", () => config.SetValue(OsuSetting.ScoreDisplayMode, ScoringMode.Classic));
|
|
||||||
AddStep("change to standardised", () => config.SetValue(OsuSetting.ScoreDisplayMode, ScoringMode.Standardised));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies();
|
|
||||||
|
|
||||||
protected class TestDependencies : MultiplayerTestSceneDependencies
|
|
||||||
{
|
|
||||||
protected override TestSpectatorClient CreateSpectatorClient() => new TestMultiplayerSpectatorClient();
|
|
||||||
}
|
|
||||||
|
|
||||||
public class TestMultiplayerSpectatorClient : TestSpectatorClient
|
|
||||||
{
|
|
||||||
private readonly Dictionary<int, FrameHeader> lastHeaders = new Dictionary<int, FrameHeader>();
|
|
||||||
|
|
||||||
public void RandomlyUpdateState()
|
|
||||||
{
|
|
||||||
foreach ((int userId, _) in WatchedUserStates)
|
|
||||||
{
|
|
||||||
if (RNG.NextBool())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!lastHeaders.TryGetValue(userId, out var header))
|
|
||||||
{
|
|
||||||
lastHeaders[userId] = header = new FrameHeader(new ScoreInfo
|
|
||||||
{
|
|
||||||
Statistics = new Dictionary<HitResult, int>
|
|
||||||
{
|
|
||||||
[HitResult.Miss] = 0,
|
|
||||||
[HitResult.Meh] = 0,
|
|
||||||
[HitResult.Great] = 0
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (RNG.Next(0, 3))
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
header.Combo = 0;
|
|
||||||
header.Statistics[HitResult.Miss]++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
header.Combo++;
|
|
||||||
header.MaxCombo = Math.Max(header.MaxCombo, header.Combo);
|
|
||||||
header.Statistics[HitResult.Meh]++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
header.Combo++;
|
|
||||||
header.MaxCombo = Math.Max(header.MaxCombo, header.Combo);
|
|
||||||
header.Statistics[HitResult.Great]++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
((ISpectatorClient)this).UserSentFrames(userId, new FrameDataBundle(header, new[] { new LegacyReplayFrame(Time.Current, 0, 0, ReplayButtonState.None) }));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,121 +1,56 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
// 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.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
|
||||||
using osu.Framework.Extensions;
|
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
using osu.Game.Online.API;
|
|
||||||
using osu.Game.Online.API.Requests.Responses;
|
|
||||||
using osu.Game.Online.Multiplayer;
|
using osu.Game.Online.Multiplayer;
|
||||||
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
using osu.Game.Online.Multiplayer.MatchTypes.TeamVersus;
|
||||||
using osu.Game.Online.Rooms;
|
|
||||||
using osu.Game.Rulesets.Osu.Scoring;
|
using osu.Game.Rulesets.Osu.Scoring;
|
||||||
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
using osu.Game.Screens.OnlinePlay.Multiplayer;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
using osu.Game.Tests.Visual.OnlinePlay;
|
|
||||||
using osu.Game.Tests.Visual.Spectator;
|
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Multiplayer
|
namespace osu.Game.Tests.Visual.Multiplayer
|
||||||
{
|
{
|
||||||
public class TestSceneMultiplayerGameplayLeaderboardTeams : MultiplayerTestScene
|
public class TestSceneMultiplayerGameplayLeaderboardTeams : MultiplayerGameplayLeaderboardTestScene
|
||||||
{
|
{
|
||||||
private static IEnumerable<int> users => Enumerable.Range(0, 16);
|
protected override MultiplayerRoomUser CreateUser(int userId)
|
||||||
|
|
||||||
public new TestSceneMultiplayerGameplayLeaderboard.TestMultiplayerSpectatorClient SpectatorClient =>
|
|
||||||
(TestSceneMultiplayerGameplayLeaderboard.TestMultiplayerSpectatorClient)OnlinePlayDependencies?.SpectatorClient;
|
|
||||||
|
|
||||||
protected override OnlinePlayTestSceneDependencies CreateOnlinePlayDependencies() => new TestDependencies();
|
|
||||||
|
|
||||||
protected class TestDependencies : MultiplayerTestSceneDependencies
|
|
||||||
{
|
{
|
||||||
protected override TestSpectatorClient CreateSpectatorClient() => new TestSceneMultiplayerGameplayLeaderboard.TestMultiplayerSpectatorClient();
|
var user = base.CreateUser(userId);
|
||||||
|
user.MatchState = new TeamVersusUserState
|
||||||
|
{
|
||||||
|
TeamID = RNG.Next(0, 2)
|
||||||
|
};
|
||||||
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MultiplayerGameplayLeaderboard leaderboard;
|
protected override MultiplayerGameplayLeaderboard CreateLeaderboard(OsuScoreProcessor scoreProcessor) =>
|
||||||
private GameplayMatchScoreDisplay gameplayScoreDisplay;
|
new MultiplayerGameplayLeaderboard(Ruleset.Value, scoreProcessor, MultiplayerUsers.ToArray())
|
||||||
|
{
|
||||||
protected override Room CreateRoom()
|
Anchor = Anchor.Centre,
|
||||||
{
|
Origin = Anchor.Centre,
|
||||||
var room = base.CreateRoom();
|
};
|
||||||
room.Type.Value = MatchType.TeamVersus;
|
|
||||||
return room;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetUpSteps()
|
public override void SetUpSteps()
|
||||||
{
|
{
|
||||||
base.SetUpSteps();
|
base.SetUpSteps();
|
||||||
|
|
||||||
AddStep("set local user", () => ((DummyAPIAccess)API).LocalUser.Value = UserLookupCache.GetUserAsync(1).GetResultSafely());
|
AddStep("Add external display components", () =>
|
||||||
|
|
||||||
AddStep("create leaderboard", () =>
|
|
||||||
{
|
{
|
||||||
leaderboard?.Expire();
|
LoadComponentAsync(new MatchScoreDisplay
|
||||||
|
|
||||||
OsuScoreProcessor scoreProcessor;
|
|
||||||
Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
|
|
||||||
|
|
||||||
var playableBeatmap = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
|
|
||||||
var multiplayerUsers = new List<MultiplayerRoomUser>();
|
|
||||||
|
|
||||||
foreach (int user in users)
|
|
||||||
{
|
{
|
||||||
SpectatorClient.SendStartPlay(user, Beatmap.Value.BeatmapInfo.OnlineID);
|
Team1Score = { BindTarget = Leaderboard.TeamScores[0] },
|
||||||
var roomUser = OnlinePlayDependencies.MultiplayerClient.AddUser(new APIUser { Id = user }, true);
|
Team2Score = { BindTarget = Leaderboard.TeamScores[1] }
|
||||||
|
}, Add);
|
||||||
|
|
||||||
roomUser.MatchState = new TeamVersusUserState
|
LoadComponentAsync(new GameplayMatchScoreDisplay
|
||||||
{
|
|
||||||
TeamID = RNG.Next(0, 2)
|
|
||||||
};
|
|
||||||
|
|
||||||
multiplayerUsers.Add(roomUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
{
|
||||||
scoreProcessor = new OsuScoreProcessor(),
|
Anchor = Anchor.BottomCentre,
|
||||||
};
|
Origin = Anchor.BottomCentre,
|
||||||
|
Team1Score = { BindTarget = Leaderboard.TeamScores[0] },
|
||||||
scoreProcessor.ApplyBeatmap(playableBeatmap);
|
Team2Score = { BindTarget = Leaderboard.TeamScores[1] },
|
||||||
|
Expanded = { BindTarget = Leaderboard.Expanded },
|
||||||
LoadComponentAsync(leaderboard = new MultiplayerGameplayLeaderboard(Ruleset.Value, scoreProcessor, multiplayerUsers.ToArray())
|
}, Add);
|
||||||
{
|
|
||||||
Anchor = Anchor.Centre,
|
|
||||||
Origin = Anchor.Centre,
|
|
||||||
}, gameplayLeaderboard =>
|
|
||||||
{
|
|
||||||
LoadComponentAsync(new MatchScoreDisplay
|
|
||||||
{
|
|
||||||
Team1Score = { BindTarget = leaderboard.TeamScores[0] },
|
|
||||||
Team2Score = { BindTarget = leaderboard.TeamScores[1] }
|
|
||||||
}, Add);
|
|
||||||
|
|
||||||
LoadComponentAsync(gameplayScoreDisplay = new GameplayMatchScoreDisplay
|
|
||||||
{
|
|
||||||
Anchor = Anchor.BottomCentre,
|
|
||||||
Origin = Anchor.BottomCentre,
|
|
||||||
Team1Score = { BindTarget = leaderboard.TeamScores[0] },
|
|
||||||
Team2Score = { BindTarget = leaderboard.TeamScores[1] }
|
|
||||||
}, Add);
|
|
||||||
|
|
||||||
Add(gameplayLeaderboard);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
AddUntilStep("wait for load", () => leaderboard.IsLoaded);
|
|
||||||
AddUntilStep("wait for user population", () => MultiplayerClient.CurrentMatchPlayingUserIds.Count > 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TestScoreUpdates()
|
|
||||||
{
|
|
||||||
AddRepeatStep("update state", () => SpectatorClient.RandomlyUpdateState(), 100);
|
|
||||||
AddToggleStep("switch compact mode", expanded =>
|
|
||||||
{
|
|
||||||
leaderboard.Expanded.Value = expanded;
|
|
||||||
gameplayScoreDisplay.Expanded.Value = expanded;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a user leaves the room of their own accord.
|
/// Invoked when a user leaves the room of their own accord.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<MultiplayerRoomUser>? UserLeft;
|
public virtual event Action<MultiplayerRoomUser>? UserLeft;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Invoked when a user was kicked from the room forcefully.
|
/// Invoked when a user was kicked from the room forcefully.
|
||||||
@ -107,7 +107,7 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The users in the joined <see cref="Room"/> which are participating in the current gameplay loop.
|
/// The users in the joined <see cref="Room"/> which are participating in the current gameplay loop.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IBindableList<int> CurrentMatchPlayingUserIds => PlayingUserIds;
|
public virtual IBindableList<int> CurrentMatchPlayingUserIds => PlayingUserIds;
|
||||||
|
|
||||||
protected readonly BindableList<int> PlayingUserIds = new BindableList<int>();
|
protected readonly BindableList<int> PlayingUserIds = new BindableList<int>();
|
||||||
|
|
||||||
|
@ -54,17 +54,17 @@ namespace osu.Game.Online.Spectator
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called whenever new frames arrive from the server.
|
/// Called whenever new frames arrive from the server.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<int, FrameDataBundle>? OnNewFrames;
|
public virtual event Action<int, FrameDataBundle>? OnNewFrames;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called whenever a user starts a play session, or immediately if the user is being watched and currently in a play session.
|
/// Called whenever a user starts a play session, or immediately if the user is being watched and currently in a play session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<int, SpectatorState>? OnUserBeganPlaying;
|
public virtual event Action<int, SpectatorState>? OnUserBeganPlaying;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Called whenever a user finishes a play session.
|
/// Called whenever a user finishes a play session.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action<int, SpectatorState>? OnUserFinishedPlaying;
|
public virtual event Action<int, SpectatorState>? OnUserFinishedPlaying;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// All users currently being watched.
|
/// All users currently being watched.
|
||||||
@ -221,7 +221,7 @@ namespace osu.Game.Online.Spectator
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WatchUser(int userId)
|
public virtual void WatchUser(int userId)
|
||||||
{
|
{
|
||||||
Debug.Assert(ThreadSafety.IsUpdateThread);
|
Debug.Assert(ThreadSafety.IsUpdateThread);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user