diff --git a/osu.Desktop/DiscordRichPresence.cs b/osu.Desktop/DiscordRichPresence.cs index 26d7402a5b..f1878d967d 100644 --- a/osu.Desktop/DiscordRichPresence.cs +++ b/osu.Desktop/DiscordRichPresence.cs @@ -26,7 +26,7 @@ namespace osu.Desktop [Resolved] private IBindable ruleset { get; set; } - private Bindable user; + private IBindable user; private readonly IBindable status = new Bindable(); private readonly IBindable activity = new Bindable(); diff --git a/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs b/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs index 9a4d1f9585..1ddb5ac630 100644 --- a/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs +++ b/osu.Game.Rulesets.Catch/UI/CatchReplayRecorder.cs @@ -2,10 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Replays; using osu.Game.Rulesets.Catch.Replays; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osuTK; namespace osu.Game.Rulesets.Catch.UI @@ -14,7 +14,7 @@ namespace osu.Game.Rulesets.Catch.UI { private readonly CatchPlayfield playfield; - public CatchReplayRecorder(Replay target, CatchPlayfield playfield) + public CatchReplayRecorder(Score target, CatchPlayfield playfield) : base(target) { this.playfield = playfield; diff --git a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs index 46733181e3..9389fa803b 100644 --- a/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs +++ b/osu.Game.Rulesets.Catch/UI/DrawableCatchRuleset.cs @@ -13,6 +13,7 @@ using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Scoring; namespace osu.Game.Rulesets.Catch.UI { @@ -31,7 +32,7 @@ namespace osu.Game.Rulesets.Catch.UI protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new CatchFramedReplayInputHandler(replay); - protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new CatchReplayRecorder(replay, (CatchPlayfield)Playfield); + protected override ReplayRecorder CreateReplayRecorder(Score score) => new CatchReplayRecorder(score, (CatchPlayfield)Playfield); protected override Playfield CreatePlayfield() => new CatchPlayfield(Beatmap.BeatmapInfo.BaseDifficulty, CreateDrawableRepresentation); diff --git a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs index 7f5b9a6ee0..941ac9816c 100644 --- a/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs +++ b/osu.Game.Rulesets.Mania/UI/DrawableManiaRuleset.cs @@ -23,6 +23,7 @@ using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Scoring; namespace osu.Game.Rulesets.Mania.UI { @@ -132,6 +133,6 @@ namespace osu.Game.Rulesets.Mania.UI protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new ManiaFramedReplayInputHandler(replay); - protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new ManiaReplayRecorder(replay); + protected override ReplayRecorder CreateReplayRecorder(Score score) => new ManiaReplayRecorder(score); } } diff --git a/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs b/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs index 18275000a2..b502d1f9e5 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaReplayRecorder.cs @@ -2,18 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Replays; using osu.Game.Rulesets.Mania.Replays; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osuTK; namespace osu.Game.Rulesets.Mania.UI { public class ManiaReplayRecorder : ReplayRecorder { - public ManiaReplayRecorder(Replay replay) - : base(replay) + public ManiaReplayRecorder(Score score) + : base(score) { } diff --git a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs index b235b59609..a44c97c3cf 100644 --- a/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs +++ b/osu.Game.Rulesets.Osu/Difficulty/OsuPerformanceCalculator.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Osu.Difficulty double multiplier = 1.12; // This is being adjusted to keep the final pp value scaled around what it used to be when changing things if (mods.Any(m => m is OsuModNoFail)) - multiplier *= 0.90; + multiplier *= Math.Max(0.90, 1.0 - 0.02 * countMiss); if (mods.Any(m => m is OsuModSpunOut)) multiplier *= 1.0 - Math.Pow((double)Attributes.SpinnerCount / totalHits, 0.85); diff --git a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs index 69179137a6..df3f7c64e4 100644 --- a/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs +++ b/osu.Game.Rulesets.Osu/UI/DrawableOsuRuleset.cs @@ -14,6 +14,7 @@ using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Play; using osuTK; @@ -44,7 +45,7 @@ namespace osu.Game.Rulesets.Osu.UI protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuFramedReplayInputHandler(replay); - protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new OsuReplayRecorder(replay); + protected override ReplayRecorder CreateReplayRecorder(Score score) => new OsuReplayRecorder(score); public override double GameplayStartTime { diff --git a/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs b/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs index b68ea136d5..1304dfe416 100644 --- a/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs +++ b/osu.Game.Rulesets.Osu/UI/OsuReplayRecorder.cs @@ -2,18 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Replays; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osuTK; namespace osu.Game.Rulesets.Osu.UI { public class OsuReplayRecorder : ReplayRecorder { - public OsuReplayRecorder(Replay replay) - : base(replay) + public OsuReplayRecorder(Score score) + : base(score) { } diff --git a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs index bbf8cb8de0..9cf931ee0a 100644 --- a/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs +++ b/osu.Game.Rulesets.Taiko/UI/DrawableTaikoRuleset.cs @@ -17,6 +17,7 @@ using osu.Game.Replays; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.UI.Scrolling; +using osu.Game.Scoring; using osu.Game.Skinning; using osuTK; @@ -82,6 +83,6 @@ namespace osu.Game.Rulesets.Taiko.UI protected override ReplayInputHandler CreateReplayInputHandler(Replay replay) => new TaikoFramedReplayInputHandler(replay); - protected override ReplayRecorder CreateReplayRecorder(Replay replay) => new TaikoReplayRecorder(replay); + protected override ReplayRecorder CreateReplayRecorder(Score score) => new TaikoReplayRecorder(score); } } diff --git a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs index 1859dabf03..e6391d1386 100644 --- a/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs +++ b/osu.Game.Rulesets.Taiko/UI/TaikoReplayRecorder.cs @@ -2,18 +2,18 @@ // See the LICENCE file in the repository root for full licence text. using System.Collections.Generic; -using osu.Game.Replays; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Taiko.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osuTK; namespace osu.Game.Rulesets.Taiko.UI { public class TaikoReplayRecorder : ReplayRecorder { - public TaikoReplayRecorder(Replay replay) - : base(replay) + public TaikoReplayRecorder(Score score) + : base(score) { } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs index b72960931f..b2ad7ca5b4 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs @@ -19,6 +19,7 @@ using osu.Game.Replays; using osu.Game.Rulesets; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Tests.Visual.UserInterface; using osuTK; @@ -53,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay { recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique) { - Recorder = recorder = new TestReplayRecorder(replay) + Recorder = recorder = new TestReplayRecorder(new Score { Replay = replay }) { ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos), }, @@ -271,7 +272,7 @@ namespace osu.Game.Tests.Visual.Gameplay internal class TestReplayRecorder : ReplayRecorder { - public TestReplayRecorder(Replay target) + public TestReplayRecorder(Score target) : base(target) { } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs index 6872b6a669..40c4214749 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs @@ -15,6 +15,7 @@ using osu.Game.Replays; using osu.Game.Rulesets; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Tests.Visual.UserInterface; using osuTK; @@ -44,7 +45,7 @@ namespace osu.Game.Tests.Visual.Gameplay { recordingManager = new TestRulesetInputManager(new TestSceneModSettings.TestRulesetInfo(), 0, SimultaneousBindingMode.Unique) { - Recorder = new TestReplayRecorder(replay) + Recorder = new TestReplayRecorder(new Score { Replay = replay }) { ScreenSpaceToGamefield = pos => recordingManager.ToLocalSpace(pos) }, @@ -206,7 +207,7 @@ namespace osu.Game.Tests.Visual.Gameplay internal class TestReplayRecorder : ReplayRecorder { - public TestReplayRecorder(Replay target) + public TestReplayRecorder(Score target) : base(target) { } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs index 72c6fd8d44..3e5b561a6f 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectator.cs @@ -17,6 +17,7 @@ using osu.Game.Replays.Legacy; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Replays; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Tests.Beatmaps.IO; using osu.Game.Users; @@ -272,7 +273,7 @@ namespace osu.Game.Tests.Visual.Gameplay frames.Add(new LegacyReplayFrame(i * 100, RNG.Next(0, 512), RNG.Next(0, 512), buttonState)); } - var bundle = new FrameDataBundle(frames); + var bundle = new FrameDataBundle(new ScoreInfo(), frames); ((ISpectatorClient)this).UserSentFrames(StreamingUser.Id, bundle); if (!sentState) diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs index 35473ee76c..e148fa381c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneSpectatorPlayback.cs @@ -27,6 +27,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; using osu.Game.Rulesets.UI; +using osu.Game.Scoring; using osu.Game.Screens.Play; using osu.Game.Tests.Visual.UserInterface; using osuTK; @@ -348,7 +349,7 @@ namespace osu.Game.Tests.Visual.Gameplay internal class TestReplayRecorder : ReplayRecorder { public TestReplayRecorder() - : base(new Replay()) + : base(new Score()) { } diff --git a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs index 49fab08ded..9cbdee3632 100644 --- a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs +++ b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Allocation; +using osu.Game.Online.API; using osu.Game.Screens.Menu; using osu.Game.Users; @@ -16,7 +17,7 @@ namespace osu.Game.Tests.Visual.Menus AddStep("toggle support", () => { - API.LocalUser.Value = new User + ((DummyAPIAccess)API).LocalUser.Value = new User { Username = API.LocalUser.Value.Username, Id = API.LocalUser.Value.Id + 1, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs index cdad37a9ad..9baaa42c83 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneLoungeRoomInfo.cs @@ -4,7 +4,6 @@ using System; using NUnit.Framework; using osu.Framework.Graphics; -using osu.Game.Online.Multiplayer; using osu.Game.Online.Multiplayer.RoomStatuses; using osu.Game.Screens.Multi.Lounge.Components; using osu.Game.Users; @@ -14,10 +13,8 @@ namespace osu.Game.Tests.Visual.Multiplayer public class TestSceneLoungeRoomInfo : MultiplayerTestScene { [SetUp] - public void Setup() => Schedule(() => + public new void Setup() => Schedule(() => { - Room = new Room(); - Child = new RoomInfo { Anchor = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs index 01cd26fbe5..6b1d90e06e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchBeatmapDetailArea.cs @@ -24,10 +24,8 @@ namespace osu.Game.Tests.Visual.Multiplayer private RulesetStore rulesetStore { get; set; } [SetUp] - public void Setup() => Schedule(() => + public new void Setup() => Schedule(() => { - Room = new Room(); - Child = new MatchBeatmapDetailArea { Anchor = Anchor.Centre, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs index e5943105b7..ec5292e51e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchHeader.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using NUnit.Framework; using osu.Game.Beatmaps; using osu.Game.Online.Multiplayer; using osu.Game.Rulesets.Osu; @@ -14,7 +15,12 @@ namespace osu.Game.Tests.Visual.Multiplayer { public TestSceneMatchHeader() { - Room = new Room(); + Child = new Header(); + } + + [SetUp] + public new void Setup() => Schedule(() => + { Room.Playlist.Add(new PlaylistItem { Beatmap = @@ -41,8 +47,6 @@ namespace osu.Game.Tests.Visual.Multiplayer Room.Name.Value = "A very awesome room"; Room.Host.Value = new User { Id = 2, Username = "peppy" }; - - Child = new Header(); - } + }); } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs index c24c6c4ba3..a72f71d79c 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchLeaderboard.cs @@ -3,10 +3,10 @@ using System.Collections.Generic; using Newtonsoft.Json; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Online.API; -using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Match.Components; using osu.Game.Users; using osuTK; @@ -19,8 +19,6 @@ namespace osu.Game.Tests.Visual.Multiplayer public TestSceneMatchLeaderboard() { - Room = new Room { RoomID = { Value = 3 } }; - Add(new MatchLeaderboard { Origin = Anchor.Centre, @@ -40,6 +38,12 @@ namespace osu.Game.Tests.Visual.Multiplayer api.Queue(req); } + [SetUp] + public new void Setup() => Schedule(() => + { + Room.RoomID.Value = 3; + }); + private class GetRoomScoresRequest : APIRequest> { protected override string Target => "rooms/3/leaderboard"; diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs index 07ff56b5c3..cbe8cc6137 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSettingsOverlay.cs @@ -23,10 +23,8 @@ namespace osu.Game.Tests.Visual.Multiplayer private TestRoomSettings settings; [SetUp] - public void Setup() => Schedule(() => + public new void Setup() => Schedule(() => { - Room = new Room(); - settings = new TestRoomSettings { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs index 55b8902d7b..4742fd0d84 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSongSelect.cs @@ -14,7 +14,6 @@ using osu.Framework.Platform; using osu.Framework.Screens; using osu.Framework.Utils; using osu.Game.Beatmaps; -using osu.Game.Online.Multiplayer; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu; @@ -94,12 +93,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("wait for present", () => songSelect.IsCurrentScreen()); } - [SetUp] - public void Setup() => Schedule(() => - { - Room = new Room(); - }); - [Test] public void TestItemAddedIfEmptyOnStart() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs index 2e22317539..65e9893851 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMatchSubScreen.cs @@ -45,12 +45,6 @@ namespace osu.Game.Tests.Visual.Multiplayer manager.Import(new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo.BeatmapSet).Wait(); } - [SetUp] - public void Setup() => Schedule(() => - { - Room = new Room(); - }); - [SetUpSteps] public void SetupSteps() { diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedParticipants.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedParticipants.cs deleted file mode 100644 index b6bfa7c93a..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedParticipants.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Framework.Graphics; -using osu.Game.Online.Multiplayer; -using osu.Game.Screens.Multi.Components; -using osuTK; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestSceneOverlinedParticipants : MultiplayerTestScene - { - protected override bool UseOnlineAPI => true; - - [SetUp] - public void Setup() => Schedule(() => - { - Room = new Room { RoomID = { Value = 7 } }; - }); - - [Test] - public void TestHorizontalLayout() - { - AddStep("create component", () => - { - Child = new ParticipantsDisplay(Direction.Horizontal) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Width = 500, - }; - }); - } - - [Test] - public void TestVerticalLayout() - { - AddStep("create component", () => - { - Child = new ParticipantsDisplay(Direction.Vertical) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(500) - }; - }); - } - } -} diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs deleted file mode 100644 index 14984988cb..0000000000 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneOverlinedPlaylist.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Graphics; -using osu.Game.Online.Multiplayer; -using osu.Game.Rulesets.Osu; -using osu.Game.Screens.Multi; -using osu.Game.Tests.Beatmaps; -using osuTK; - -namespace osu.Game.Tests.Visual.Multiplayer -{ - public class TestSceneOverlinedPlaylist : MultiplayerTestScene - { - protected override bool UseOnlineAPI => true; - - public TestSceneOverlinedPlaylist() - { - Room = new Room { RoomID = { Value = 7 } }; - - for (int i = 0; i < 10; i++) - { - Room.Playlist.Add(new PlaylistItem - { - ID = i, - Beatmap = { Value = new TestBeatmap(new OsuRuleset().RulesetInfo).BeatmapInfo }, - Ruleset = { Value = new OsuRuleset().RulesetInfo } - }); - } - - Add(new DrawableRoomPlaylist(false, false) - { - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(500), - }); - } - } -} diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs index f71c5fc5d2..7bbec7d30e 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneParticipantsList.cs @@ -3,24 +3,55 @@ using NUnit.Framework; using osu.Framework.Graphics; -using osu.Game.Online.Multiplayer; using osu.Game.Screens.Multi.Components; +using osu.Game.Users; namespace osu.Game.Tests.Visual.Multiplayer { public class TestSceneParticipantsList : MultiplayerTestScene { - protected override bool UseOnlineAPI => true; - [SetUp] - public void Setup() => Schedule(() => + public new void Setup() => Schedule(() => { - Room = new Room { RoomID = { Value = 7 } }; + Room.RoomID.Value = 7; + + for (int i = 0; i < 50; i++) + { + Room.RecentParticipants.Add(new User + { + Username = "peppy", + Id = 2 + }); + } }); - public TestSceneParticipantsList() + [Test] + public void TestHorizontalLayout() { - Add(new ParticipantsList { RelativeSizeAxes = Axes.Both }); + AddStep("create component", () => + { + Child = new ParticipantsDisplay(Direction.Horizontal) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.2f, + }; + }); + } + + [Test] + public void TestVerticalLayout() + { + AddStep("create component", () => + { + Child = new ParticipantsDisplay(Direction.Vertical) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Width = 0.2f, + Height = 0.2f, + }; + }); } } } diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs index 1925e0ef4f..c1dfb94464 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneRoomStatus.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.Multiplayer; @@ -22,18 +23,21 @@ namespace osu.Game.Tests.Visual.Multiplayer new DrawableRoom(new Room { Name = { Value = "Room 1" }, - Status = { Value = new RoomStatusOpen() } - }), + Status = { Value = new RoomStatusOpen() }, + EndDate = { Value = DateTimeOffset.Now.AddDays(1) } + }) { MatchingFilter = true }, new DrawableRoom(new Room { Name = { Value = "Room 2" }, - Status = { Value = new RoomStatusPlaying() } - }), + Status = { Value = new RoomStatusPlaying() }, + EndDate = { Value = DateTimeOffset.Now.AddDays(1) } + }) { MatchingFilter = true }, new DrawableRoom(new Room { Name = { Value = "Room 3" }, - Status = { Value = new RoomStatusEnded() } - }), + Status = { Value = new RoomStatusEnded() }, + EndDate = { Value = DateTimeOffset.Now } + }) { MatchingFilter = true }, } }; } diff --git a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs index 6c8ec917ba..dcfe0432a8 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneAccountCreationOverlay.cs @@ -14,7 +14,7 @@ namespace osu.Game.Tests.Visual.Online { private readonly Container userPanelArea; - private Bindable localUser; + private IBindable localUser; public TestSceneAccountCreationOverlay() { diff --git a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs index 0cc6e9f358..9bece39ca0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneFriendDisplay.cs @@ -20,7 +20,7 @@ namespace osu.Game.Tests.Visual.Online [Cached] private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - private TestFriendDisplay display; + private FriendDisplay display; [SetUp] public void Setup() => Schedule(() => @@ -28,7 +28,7 @@ namespace osu.Game.Tests.Visual.Online Child = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, - Child = display = new TestFriendDisplay() + Child = display = new FriendDisplay() }; }); @@ -41,7 +41,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestOnline() { - AddStep("Fetch online", () => display?.Fetch()); + // No need to do anything, fetch is performed automatically. } private List getUsers() => new List @@ -76,10 +76,5 @@ namespace osu.Game.Tests.Visual.Online LastVisit = DateTimeOffset.Now } }; - - private class TestFriendDisplay : FriendDisplay - { - public void Fetch() => PerformFetch(); - } } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs index 8e151a987a..0324da6cf5 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneNowPlayingCommand.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing; using osu.Game.Beatmaps; +using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Rulesets; using osu.Game.Users; @@ -18,6 +19,8 @@ namespace osu.Game.Tests.Visual.Online [Cached(typeof(IChannelPostTarget))] private PostTarget postTarget { get; set; } + private DummyAPIAccess api => (DummyAPIAccess)API; + public TestSceneNowPlayingCommand() { Add(postTarget = new PostTarget()); @@ -26,7 +29,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestGenericActivity() { - AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby(null)); + AddStep("Set activity", () => api.Activity.Value = new UserActivity.InLobby(null)); AddStep("Run command", () => Add(new NowPlayingCommand())); @@ -36,7 +39,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestEditActivity() { - AddStep("Set activity", () => API.Activity.Value = new UserActivity.Editing(new BeatmapInfo())); + AddStep("Set activity", () => api.Activity.Value = new UserActivity.Editing(new BeatmapInfo())); AddStep("Run command", () => Add(new NowPlayingCommand())); @@ -46,7 +49,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestPlayActivity() { - AddStep("Set activity", () => API.Activity.Value = new UserActivity.SoloGame(new BeatmapInfo(), new RulesetInfo())); + AddStep("Set activity", () => api.Activity.Value = new UserActivity.SoloGame(new BeatmapInfo(), new RulesetInfo())); AddStep("Run command", () => Add(new NowPlayingCommand())); @@ -57,7 +60,7 @@ namespace osu.Game.Tests.Visual.Online [TestCase(false)] public void TestLinkPresence(bool hasOnlineId) { - AddStep("Set activity", () => API.Activity.Value = new UserActivity.InLobby(null)); + AddStep("Set activity", () => api.Activity.Value = new UserActivity.InLobby(null)); AddStep("Set beatmap", () => Beatmap.Value = new DummyWorkingBeatmap(Audio, null) { diff --git a/osu.Game/Online/API/APIAccess.cs b/osu.Game/Online/API/APIAccess.cs index b916339a53..fe500b9548 100644 --- a/osu.Game/Online/API/APIAccess.cs +++ b/osu.Game/Online/API/APIAccess.cs @@ -39,9 +39,15 @@ namespace osu.Game.Online.API private string password; - public Bindable LocalUser { get; } = new Bindable(createGuestUser()); + public IBindable LocalUser => localUser; + public IBindableList Friends => friends; + public IBindable Activity => activity; - public Bindable Activity { get; } = new Bindable(); + private Bindable localUser { get; } = new Bindable(createGuestUser()); + + private BindableList friends { get; } = new BindableList(); + + private Bindable activity { get; } = new Bindable(); protected bool HasLogin => authentication.Token.Value != null || (!string.IsNullOrEmpty(ProvidedUsername) && !string.IsNullOrEmpty(password)); @@ -61,10 +67,10 @@ namespace osu.Game.Online.API authentication.TokenString = config.Get(OsuSetting.Token); authentication.Token.ValueChanged += onTokenChanged; - LocalUser.BindValueChanged(u => + localUser.BindValueChanged(u => { - u.OldValue?.Activity.UnbindFrom(Activity); - u.NewValue.Activity.BindTo(Activity); + u.OldValue?.Activity.UnbindFrom(activity); + u.NewValue.Activity.BindTo(activity); }, true); var thread = new Thread(run) @@ -134,23 +140,37 @@ namespace osu.Game.Online.API } var userReq = new GetUserRequest(); + userReq.Success += u => { - LocalUser.Value = u; + localUser.Value = u; // todo: save/pull from settings - LocalUser.Value.Status.Value = new UserStatusOnline(); + localUser.Value.Status.Value = new UserStatusOnline(); failureCount = 0; + }; + + if (!handleRequest(userReq)) + { + failConnectionProcess(); + continue; + } + + // getting user's friends is considered part of the connection process. + var friendsReq = new GetFriendsRequest(); + + friendsReq.Success += res => + { + friends.AddRange(res); //we're connected! state.Value = APIState.Online; }; - if (!handleRequest(userReq)) + if (!handleRequest(friendsReq)) { - if (State.Value == APIState.Connecting) - state.Value = APIState.Failing; + failConnectionProcess(); continue; } @@ -186,6 +206,13 @@ namespace osu.Game.Online.API Thread.Sleep(50); } + + void failConnectionProcess() + { + // if something went wrong during the connection process, we want to reset the state (but only if still connecting). + if (State.Value == APIState.Connecting) + state.Value = APIState.Failing; + } } public void Perform(APIRequest request) @@ -322,7 +349,7 @@ namespace osu.Game.Online.API return true; } - public bool IsLoggedIn => LocalUser.Value.Id > 1; + public bool IsLoggedIn => localUser.Value.Id > 1; public void Queue(APIRequest request) { @@ -352,8 +379,12 @@ namespace osu.Game.Online.API password = null; authentication.Clear(); - // Scheduled prior to state change such that the state changed event is invoked with the correct user present - Schedule(() => LocalUser.Value = createGuestUser()); + // Scheduled prior to state change such that the state changed event is invoked with the correct user and their friends present + Schedule(() => + { + localUser.Value = createGuestUser(); + friends.Clear(); + }); state.Value = APIState.Offline; } diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index e275676cea..265298270c 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -18,6 +18,8 @@ namespace osu.Game.Online.API Id = 1001, }); + public BindableList Friends { get; } = new BindableList(); + public Bindable Activity { get; } = new Bindable(); public string AccessToken => "token"; @@ -86,5 +88,9 @@ namespace osu.Game.Online.API } public void SetState(APIState newState) => state.Value = newState; + + IBindable IAPIProvider.LocalUser => LocalUser; + IBindableList IAPIProvider.Friends => Friends; + IBindable IAPIProvider.Activity => Activity; } } diff --git a/osu.Game/Online/API/IAPIProvider.cs b/osu.Game/Online/API/IAPIProvider.cs index cadc806f4f..3a444460f2 100644 --- a/osu.Game/Online/API/IAPIProvider.cs +++ b/osu.Game/Online/API/IAPIProvider.cs @@ -13,13 +13,19 @@ namespace osu.Game.Online.API /// The local user. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// - Bindable LocalUser { get; } + IBindable LocalUser { get; } + + /// + /// The user's friends. + /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. + /// + IBindableList Friends { get; } /// /// The current user's activity. /// This is not thread-safe and should be scheduled locally if consumed from a drawable component. /// - Bindable Activity { get; } + IBindable Activity { get; } /// /// Retrieve the OAuth access token. diff --git a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomSettings.cs b/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomSettings.cs index d2f64235c3..60e0d1292e 100644 --- a/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomSettings.cs +++ b/osu.Game/Online/RealtimeMultiplayer/MultiplayerRoomSettings.cs @@ -18,13 +18,20 @@ namespace osu.Game.Online.RealtimeMultiplayer public int RulesetID { get; set; } + public string BeatmapChecksum { get; set; } = string.Empty; + public string Name { get; set; } = "Unnamed room"; [NotNull] public IEnumerable Mods { get; set; } = Enumerable.Empty(); - public bool Equals(MultiplayerRoomSettings other) => BeatmapID == other.BeatmapID && Mods.SequenceEqual(other.Mods) && RulesetID == other.RulesetID && Name.Equals(other.Name, StringComparison.Ordinal); + public bool Equals(MultiplayerRoomSettings other) + => BeatmapID == other.BeatmapID + && BeatmapChecksum == other.BeatmapChecksum + && Mods.SequenceEqual(other.Mods) + && RulesetID == other.RulesetID + && Name.Equals(other.Name, StringComparison.Ordinal); - public override string ToString() => $"Name:{Name} Beatmap:{BeatmapID} Mods:{string.Join(',', Mods)} Ruleset:{RulesetID}"; + public override string ToString() => $"Name:{Name} Beatmap:{BeatmapID} ({BeatmapChecksum}) Mods:{string.Join(',', Mods)} Ruleset:{RulesetID}"; } } diff --git a/osu.Game/Online/Spectator/FrameDataBundle.cs b/osu.Game/Online/Spectator/FrameDataBundle.cs index 5281e61f9c..a8d0434324 100644 --- a/osu.Game/Online/Spectator/FrameDataBundle.cs +++ b/osu.Game/Online/Spectator/FrameDataBundle.cs @@ -1,20 +1,34 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + using System; using System.Collections.Generic; +using Newtonsoft.Json; using osu.Game.Replays.Legacy; +using osu.Game.Scoring; namespace osu.Game.Online.Spectator { [Serializable] public class FrameDataBundle { + public FrameHeader Header { get; set; } + public IEnumerable Frames { get; set; } - public FrameDataBundle(IEnumerable frames) + public FrameDataBundle(ScoreInfo score, IEnumerable frames) { Frames = frames; + Header = new FrameHeader(score); + } + + [JsonConstructor] + public FrameDataBundle(FrameHeader header, IEnumerable frames) + { + Header = header; + Frames = frames; } } } diff --git a/osu.Game/Online/Spectator/FrameHeader.cs b/osu.Game/Online/Spectator/FrameHeader.cs new file mode 100644 index 0000000000..b4988fecf9 --- /dev/null +++ b/osu.Game/Online/Spectator/FrameHeader.cs @@ -0,0 +1,59 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +#nullable enable + +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using osu.Game.Rulesets.Scoring; +using osu.Game.Scoring; + +namespace osu.Game.Online.Spectator +{ + [Serializable] + public class FrameHeader + { + /// + /// The current combo of the score. + /// + public int Combo { get; set; } + + /// + /// The maximum combo achieved up to the current point in time. + /// + public int MaxCombo { get; set; } + + /// + /// Cumulative hit statistics. + /// + public Dictionary Statistics { get; set; } + + /// + /// The time at which this frame was received by the server. + /// + public DateTimeOffset ReceivedTime { get; set; } + + /// + /// Construct header summary information from a point-in-time reference to a score which is actively being played. + /// + /// The score for reference. + public FrameHeader(ScoreInfo score) + { + Combo = score.Combo; + MaxCombo = score.MaxCombo; + + // copy for safety + Statistics = new Dictionary(score.Statistics); + } + + [JsonConstructor] + public FrameHeader(int combo, int maxCombo, Dictionary statistics, DateTimeOffset receivedTime) + { + Combo = combo; + MaxCombo = maxCombo; + Statistics = statistics; + ReceivedTime = receivedTime; + } + } +} diff --git a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs index 08b524087a..0167a5d025 100644 --- a/osu.Game/Online/Spectator/SpectatorStreamingClient.cs +++ b/osu.Game/Online/Spectator/SpectatorStreamingClient.cs @@ -21,6 +21,7 @@ using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Replays; using osu.Game.Rulesets.Replays.Types; +using osu.Game.Scoring; using osu.Game.Screens.Play; namespace osu.Game.Online.Spectator @@ -52,6 +53,9 @@ namespace osu.Game.Online.Spectator [CanBeNull] private IBeatmap currentBeatmap; + [CanBeNull] + private Score currentScore; + [Resolved] private IBindable currentRuleset { get; set; } @@ -203,7 +207,7 @@ namespace osu.Game.Online.Spectator return Task.CompletedTask; } - public void BeginPlaying(GameplayBeatmap beatmap) + public void BeginPlaying(GameplayBeatmap beatmap, Score score) { if (isPlaying) throw new InvalidOperationException($"Cannot invoke {nameof(BeginPlaying)} when already playing"); @@ -216,6 +220,8 @@ namespace osu.Game.Online.Spectator currentState.Mods = currentMods.Value.Select(m => new APIMod(m)); currentBeatmap = beatmap.PlayableBeatmap; + currentScore = score; + beginPlaying(); } @@ -308,7 +314,9 @@ namespace osu.Game.Online.Spectator pendingFrames.Clear(); - SendFrames(new FrameDataBundle(frames)); + Debug.Assert(currentScore != null); + + SendFrames(new FrameDataBundle(currentScore.ScoreInfo, frames)); lastSendTime = Time.Current; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1f5b991758..4ebf7fbe63 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -976,7 +976,7 @@ namespace osu.Game if (newScreen is IOsuScreen newOsuScreen) { OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode); - ((IBindable)API.Activity).BindTo(newOsuScreen.Activity); + API.Activity.BindTo(newOsuScreen.Activity); MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments; diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs index 742b1055b2..c983b337b5 100644 --- a/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs +++ b/osu.Game/Overlays/BeatmapSet/Buttons/FavouriteButton.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons private PostBeatmapFavouriteRequest request; private LoadingLayer loading; - private readonly Bindable localUser = new Bindable(); + private readonly IBindable localUser = new Bindable(); public string TooltipText { diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs index a58d662de7..9a2dcd014a 100644 --- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs +++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores public readonly Bindable Beatmap = new Bindable(); private readonly Bindable ruleset = new Bindable(); private readonly Bindable scope = new Bindable(BeatmapLeaderboardScope.Global); - private readonly Bindable user = new Bindable(); + private readonly IBindable user = new Bindable(); private readonly Box background; private readonly ScoreTable scoreTable; diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 2a78748be6..513fabf52a 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Overlays.Comments public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); - protected readonly Bindable User = new Bindable(); + protected readonly IBindable User = new Bindable(); [Resolved] private IAPIProvider api { get; set; } diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs index 41b25ee1a5..cc26a11da1 100644 --- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs +++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs @@ -5,18 +5,18 @@ using System.Collections.Generic; using System.Linq; using System.Threading; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; -using osu.Game.Online.API.Requests; using osu.Game.Users; using osuTK; namespace osu.Game.Overlays.Dashboard.Friends { - public class FriendDisplay : OverlayView> + public class FriendDisplay : CompositeDrawable { private List users = new List(); @@ -41,8 +41,16 @@ namespace osu.Game.Overlays.Dashboard.Friends private Container itemsPlaceholder; private LoadingLayer loading; - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private readonly IBindableList apiFriends = new BindableList(); + + public FriendDisplay() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + } + + [BackgroundDependencyLoader(true)] + private void load(OverlayColourProvider colourProvider, IAPIProvider api) { InternalChild = new FillFlowContainer { @@ -132,6 +140,9 @@ namespace osu.Game.Overlays.Dashboard.Friends background.Colour = colourProvider.Background4; controlBackground.Colour = colourProvider.Background5; + + apiFriends.BindTo(api.Friends); + apiFriends.BindCollectionChanged((_, __) => Schedule(() => Users = apiFriends.ToList()), true); } protected override void LoadComplete() @@ -143,13 +154,6 @@ namespace osu.Game.Overlays.Dashboard.Friends userListToolbar.SortCriteria.BindValueChanged(_ => recreatePanels()); } - protected override APIRequest> CreateRequest() => new GetFriendsRequest(); - - protected override void OnSuccess(List response) - { - Users = response; - } - private void recreatePanels() { if (!users.Any()) diff --git a/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs b/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs index 6e1b6e2c7d..6c2b2dc16a 100644 --- a/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/AddFriendButton.cs @@ -50,6 +50,8 @@ namespace osu.Game.Overlays.Profile.Header.Components } }; + // todo: when friending/unfriending is implemented, the APIAccess.Friends list should be updated accordingly. + User.BindValueChanged(user => updateFollowers(user.NewValue), true); } diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs index c1a601eaae..6940e43e5b 100644 --- a/osu.Game/Rulesets/UI/DrawableRuleset.cs +++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs @@ -268,12 +268,12 @@ namespace osu.Game.Rulesets.UI return false; } - public override void SetRecordTarget(Replay recordingReplay) + public sealed override void SetRecordTarget(Score score) { if (!(KeyBindingInputManager is IHasRecordingHandler recordingInputManager)) throw new InvalidOperationException($"A {nameof(KeyBindingInputManager)} which supports recording is not available"); - var recorder = CreateReplayRecorder(recordingReplay); + var recorder = CreateReplayRecorder(score); if (recorder == null) return; @@ -327,7 +327,7 @@ namespace osu.Game.Rulesets.UI protected virtual ReplayInputHandler CreateReplayInputHandler(Replay replay) => null; - protected virtual ReplayRecorder CreateReplayRecorder(Replay replay) => null; + protected virtual ReplayRecorder CreateReplayRecorder(Score score) => null; /// /// Creates a Playfield. @@ -516,8 +516,8 @@ namespace osu.Game.Rulesets.UI /// /// Sets a replay to be used to record gameplay. /// - /// The target to be recorded to. - public abstract void SetRecordTarget(Replay recordingReplay); + /// The target to be recorded to. + public abstract void SetRecordTarget(Score score); /// /// Invoked when the interactive user requests resuming from a paused state. diff --git a/osu.Game/Rulesets/UI/ReplayRecorder.cs b/osu.Game/Rulesets/UI/ReplayRecorder.cs index 1438ebd37a..a4d46e3888 100644 --- a/osu.Game/Rulesets/UI/ReplayRecorder.cs +++ b/osu.Game/Rulesets/UI/ReplayRecorder.cs @@ -10,8 +10,8 @@ using osu.Framework.Input; using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Game.Online.Spectator; -using osu.Game.Replays; using osu.Game.Rulesets.Replays; +using osu.Game.Scoring; using osu.Game.Screens.Play; using osuTK; @@ -20,7 +20,7 @@ namespace osu.Game.Rulesets.UI public abstract class ReplayRecorder : ReplayRecorder, IKeyBindingHandler where T : struct { - private readonly Replay target; + private readonly Score target; private readonly List pressedActions = new List(); @@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.UI [Resolved] private GameplayBeatmap gameplayBeatmap { get; set; } - protected ReplayRecorder(Replay target) + protected ReplayRecorder(Score target) { this.target = target; @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.UI inputManager = GetContainingInputManager(); - spectatorStreaming?.BeginPlaying(gameplayBeatmap); + spectatorStreaming?.BeginPlaying(gameplayBeatmap, target); } protected override void Dispose(bool isDisposing) @@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.UI private void recordFrame(bool important) { - var last = target.Frames.LastOrDefault(); + var last = target.Replay.Frames.LastOrDefault(); if (!important && last != null && Time.Current - last.Time < (1000d / RecordFrameRate)) return; @@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.UI if (frame != null) { - target.Frames.Add(frame); + target.Replay.Frames.Add(frame); spectatorStreaming?.HandleFrame(frame); } diff --git a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs index 8beb955824..bd4577fd57 100644 --- a/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs +++ b/osu.Game/Screens/Backgrounds/BackgroundScreenDefault.cs @@ -22,7 +22,7 @@ namespace osu.Game.Screens.Backgrounds private int currentDisplay; private const int background_count = 7; - private Bindable user; + private IBindable user; private Bindable skin; private Bindable mode; private Bindable introSequence; diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs index 8368047d5a..ceec12c967 100644 --- a/osu.Game/Screens/Menu/Disclaimer.cs +++ b/osu.Game/Screens/Menu/Disclaimer.cs @@ -147,7 +147,7 @@ namespace osu.Game.Screens.Menu if (nextScreen != null) LoadComponentAsync(nextScreen); - currentUser.BindTo(api.LocalUser); + ((IBindable)currentUser).BindTo(api.LocalUser); } public override void OnEntering(IScreen last) diff --git a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs index 92add458f9..c44beeffa5 100644 --- a/osu.Game/Screens/Menu/MenuLogoVisualisation.cs +++ b/osu.Game/Screens/Menu/MenuLogoVisualisation.cs @@ -12,7 +12,7 @@ namespace osu.Game.Screens.Menu { internal class MenuLogoVisualisation : LogoVisualisation { - private Bindable user; + private IBindable user; private Bindable skin; [BackgroundDependencyLoader] diff --git a/osu.Game/Screens/Menu/MenuSideFlashes.cs b/osu.Game/Screens/Menu/MenuSideFlashes.cs index 2ff8132d47..a1ae4555ed 100644 --- a/osu.Game/Screens/Menu/MenuSideFlashes.cs +++ b/osu.Game/Screens/Menu/MenuSideFlashes.cs @@ -35,7 +35,7 @@ namespace osu.Game.Screens.Menu private const double box_fade_in_time = 65; private const int box_width = 200; - private Bindable user; + private IBindable user; private Bindable skin; [Resolved] diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 7979b635aa..a54f9fc047 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -21,7 +22,6 @@ using osu.Game.Graphics.Containers; using osu.Game.IO.Archives; using osu.Game.Online.API; using osu.Game.Overlays; -using osu.Game.Replays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Scoring; @@ -157,14 +157,17 @@ namespace osu.Game.Screens.Play PrepareReplay(); } - private Replay recordingReplay; + [CanBeNull] + private Score recordingScore; /// /// Run any recording / playback setup for replays. /// protected virtual void PrepareReplay() { - DrawableRuleset.SetRecordTarget(recordingReplay = new Replay()); + DrawableRuleset.SetRecordTarget(recordingScore = new Score()); + + ScoreProcessor.NewJudgement += result => ScoreProcessor.PopulateScore(recordingScore.ScoreInfo); } [BackgroundDependencyLoader(true)] @@ -758,9 +761,9 @@ namespace osu.Game.Screens.Play var score = new Score { ScoreInfo = CreateScore() }; - if (recordingReplay?.Frames.Count > 0) + if (recordingScore?.Replay.Frames.Count > 0) { - score.Replay = recordingReplay; + score.Replay = recordingScore.Replay; using (var stream = new MemoryStream()) { diff --git a/osu.Game/Tests/Visual/MultiplayerTestScene.cs b/osu.Game/Tests/Visual/MultiplayerTestScene.cs index 4d073f16f4..6f24e00a92 100644 --- a/osu.Game/Tests/Visual/MultiplayerTestScene.cs +++ b/osu.Game/Tests/Visual/MultiplayerTestScene.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Game.Online.Multiplayer; @@ -12,11 +13,7 @@ namespace osu.Game.Tests.Visual [Cached] private readonly Bindable currentRoom = new Bindable(); - protected Room Room - { - get => currentRoom.Value; - set => currentRoom.Value = value; - } + protected Room Room => currentRoom.Value; private CachedModelDependencyContainer dependencies; @@ -26,5 +23,11 @@ namespace osu.Game.Tests.Visual dependencies.Model.BindTo(currentRoom); return dependencies; } + + [SetUp] + public void Setup() => Schedule(() => + { + currentRoom.Value = new Room(); + }); } }