diff --git a/README.md b/README.md
index 016bd7d922..8f922f74a7 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
# osu!
-[](https://ci.appveyor.com/project/peppy/osu)
+[](https://github.com/ppy/osu/actions/workflows/ci.yml)
[](https://github.com/ppy/osu/releases/latest)
[](https://www.codefactor.io/repository/github/ppy/osu)
[](https://discord.gg/ppy)
diff --git a/osu.Android.props b/osu.Android.props
index f8cd4e41d4..f757847c10 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -51,8 +51,8 @@
-
-
+
+
diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs
index 744ded37c9..92941665e0 100644
--- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacySliderBody.cs
@@ -3,9 +3,9 @@
using System;
using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Utils;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Skinning.Default;
+using osu.Game.Utils;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Skinning.Legacy
@@ -40,7 +40,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy
Color4 outerColour = AccentColour.Darken(0.1f);
Color4 innerColour = lighten(AccentColour, 0.5f);
- return Interpolation.ValueAt(position / realGradientPortion, outerColour, innerColour, 0, 1);
+ return LegacyUtils.InterpolateNonLinear(position / realGradientPortion, outerColour, innerColour, 0, 1);
}
///
diff --git a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
index 0983b806e2..07ec86b0e7 100644
--- a/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
+++ b/osu.Game.Tests/NonVisual/Multiplayer/StatefulMultiplayerClientTest.cs
@@ -24,6 +24,8 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
AddRepeatStep("add some users", () => Client.AddUser(new User { Id = id++ }), 5);
checkPlayingUserCount(0);
+ AddAssert("playlist item is available", () => Client.CurrentMatchPlayingItem.Value != null);
+
changeState(3, MultiplayerUserState.WaitingForLoad);
checkPlayingUserCount(3);
@@ -41,6 +43,8 @@ namespace osu.Game.Tests.NonVisual.Multiplayer
AddStep("leave room", () => Client.LeaveRoom());
checkPlayingUserCount(0);
+
+ AddAssert("playlist item is null", () => Client.CurrentMatchPlayingItem.Value == null);
}
[Test]
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
index 072e32370d..e9fae32335 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiSpectatorScreen.cs
@@ -12,6 +12,7 @@ using osu.Game.Rulesets.UI;
using osu.Game.Screens.OnlinePlay.Multiplayer.Spectate;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps.IO;
+using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -47,8 +48,9 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
AddStep("start players silently", () =>
{
- Client.CurrentMatchPlayingUserIds.Add(PLAYER_1_ID);
- Client.CurrentMatchPlayingUserIds.Add(PLAYER_2_ID);
+ OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_1_ID }, true);
+ OnlinePlayDependencies.Client.AddUser(new User { Id = PLAYER_2_ID }, true);
+
playingUserIds.Add(PLAYER_1_ID);
playingUserIds.Add(PLAYER_2_ID);
});
@@ -264,7 +266,8 @@ namespace osu.Game.Tests.Visual.Multiplayer
{
foreach (int id in userIds)
{
- Client.CurrentMatchPlayingUserIds.Add(id);
+ OnlinePlayDependencies.Client.AddUser(new User { Id = id }, true);
+
SpectatorClient.StartPlay(id, beatmapId ?? importedBeatmapId);
playingUserIds.Add(id);
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
index 0e368b59dd..8121492a0b 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayerGameplayLeaderboard.cs
@@ -20,6 +20,7 @@ using osu.Game.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Tests.Visual.OnlinePlay;
using osu.Game.Tests.Visual.Spectator;
+using osu.Game.Users;
namespace osu.Game.Tests.Visual.Multiplayer
{
@@ -53,10 +54,10 @@ namespace osu.Game.Tests.Visual.Multiplayer
var playable = Beatmap.Value.GetPlayableBeatmap(Ruleset.Value);
foreach (var user in users)
+ {
SpectatorClient.StartPlay(user, Beatmap.Value.BeatmapInfo.OnlineBeatmapID ?? 0);
-
- // Todo: This is REALLY bad.
- Client.CurrentMatchPlayingUserIds.AddRange(users);
+ OnlinePlayDependencies.Client.AddUser(new User { Id = user }, true);
+ }
Children = new Drawable[]
{
diff --git a/osu.Game/Graphics/UserInterface/OsuDropdown.cs b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
index b97f12df02..61dd5fb2d9 100644
--- a/osu.Game/Graphics/UserInterface/OsuDropdown.cs
+++ b/osu.Game/Graphics/UserInterface/OsuDropdown.cs
@@ -288,7 +288,7 @@ namespace osu.Game.Graphics.UserInterface
},
};
- AddInternal(new HoverSounds());
+ AddInternal(new HoverClickSounds());
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Graphics/UserInterface/OsuMenu.cs b/osu.Game/Graphics/UserInterface/OsuMenu.cs
index e7bf4f66ee..a16adcbd57 100644
--- a/osu.Game/Graphics/UserInterface/OsuMenu.cs
+++ b/osu.Game/Graphics/UserInterface/OsuMenu.cs
@@ -1,6 +1,9 @@
// 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.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Sample;
using osuTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@@ -13,6 +16,12 @@ namespace osu.Game.Graphics.UserInterface
{
public class OsuMenu : Menu
{
+ private Sample sampleOpen;
+ private Sample sampleClose;
+
+ // todo: this shouldn't be required after https://github.com/ppy/osu-framework/issues/4519 is fixed.
+ private bool wasOpened;
+
public OsuMenu(Direction direction, bool topLevelMenu = false)
: base(direction, topLevelMenu)
{
@@ -22,8 +31,30 @@ namespace osu.Game.Graphics.UserInterface
ItemsContainer.Padding = new MarginPadding(5);
}
- protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
- protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
+ [BackgroundDependencyLoader]
+ private void load(AudioManager audio)
+ {
+ sampleOpen = audio.Samples.Get(@"UI/dropdown-open");
+ sampleClose = audio.Samples.Get(@"UI/dropdown-close");
+ }
+
+ protected override void AnimateOpen()
+ {
+ if (!TopLevelMenu && !wasOpened)
+ sampleOpen?.Play();
+
+ this.FadeIn(300, Easing.OutQuint);
+ wasOpened = true;
+ }
+
+ protected override void AnimateClose()
+ {
+ if (!TopLevelMenu && wasOpened)
+ sampleClose?.Play();
+
+ this.FadeOut(300, Easing.OutQuint);
+ wasOpened = false;
+ }
protected override void UpdateSize(Vector2 newSize)
{
diff --git a/osu.Game/Online/Multiplayer/MultiplayerClient.cs b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
index bffb2d341a..dafc737ba2 100644
--- a/osu.Game/Online/Multiplayer/MultiplayerClient.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerClient.cs
@@ -62,7 +62,9 @@ namespace osu.Game.Online.Multiplayer
///
/// The users in the joined which are participating in the current gameplay loop.
///
- public readonly BindableList CurrentMatchPlayingUserIds = new BindableList();
+ public IBindableList CurrentMatchPlayingUserIds => PlayingUserIds;
+
+ protected readonly BindableList PlayingUserIds = new BindableList();
public readonly Bindable CurrentMatchPlayingItem = new Bindable();
@@ -179,7 +181,8 @@ namespace osu.Game.Online.Multiplayer
{
APIRoom = null;
Room = null;
- CurrentMatchPlayingUserIds.Clear();
+ CurrentMatchPlayingItem.Value = null;
+ PlayingUserIds.Clear();
RoomUpdated?.Invoke();
});
@@ -376,7 +379,7 @@ namespace osu.Game.Online.Multiplayer
return;
Room.Users.Remove(user);
- CurrentMatchPlayingUserIds.Remove(user.UserID);
+ PlayingUserIds.Remove(user.UserID);
RoomUpdated?.Invoke();
}, false);
@@ -659,16 +662,16 @@ namespace osu.Game.Online.Multiplayer
/// The new state of the user.
private void updateUserPlayingState(int userId, MultiplayerUserState state)
{
- bool wasPlaying = CurrentMatchPlayingUserIds.Contains(userId);
+ bool wasPlaying = PlayingUserIds.Contains(userId);
bool isPlaying = state >= MultiplayerUserState.WaitingForLoad && state <= MultiplayerUserState.FinishedPlay;
if (isPlaying == wasPlaying)
return;
if (isPlaying)
- CurrentMatchPlayingUserIds.Add(userId);
+ PlayingUserIds.Add(userId);
else
- CurrentMatchPlayingUserIds.Remove(userId);
+ PlayingUserIds.Remove(userId);
}
private Task scheduleAsync(Action action, CancellationToken cancellationToken = default)
diff --git a/osu.Game/Overlays/News/Sidebar/MonthSection.cs b/osu.Game/Overlays/News/Sidebar/MonthSection.cs
index cd6ab224a9..948f312f15 100644
--- a/osu.Game/Overlays/News/Sidebar/MonthSection.cs
+++ b/osu.Game/Overlays/News/Sidebar/MonthSection.cs
@@ -79,8 +79,6 @@ namespace osu.Game.Overlays.News.Sidebar
private readonly SpriteIcon icon;
- protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds();
-
public DropdownHeader(int month, int year)
{
var date = new DateTime(year, month, 1);
diff --git a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs
index c455cb0c50..7da964d84b 100644
--- a/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs
+++ b/osu.Game/Screens/OnlinePlay/Lounge/Components/DrawableRoom.cs
@@ -5,6 +5,8 @@ using System;
using System.Collections.Generic;
using osu.Framework;
using osu.Framework.Allocation;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Sample;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
@@ -44,6 +46,8 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
public event Action StateChanged;
+ protected override HoverSounds CreateHoverSounds(HoverSampleSet sampleSet) => new HoverSounds();
+
private readonly Box selectionBox;
[Resolved(canBeNull: true)]
@@ -62,6 +66,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
private SelectionState state;
+ private Sample sampleSelect;
+ private Sample sampleJoin;
+
public SelectionState State
{
get => state;
@@ -125,7 +132,7 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
}
[BackgroundDependencyLoader]
- private void load(OsuColour colours)
+ private void load(OsuColour colours, AudioManager audio)
{
float stripWidth = side_strip_width * (Room.Category.Value == RoomCategory.Spotlight ? 2 : 1);
@@ -221,6 +228,9 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
},
},
};
+
+ sampleSelect = audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select");
+ sampleJoin = audio.Samples.Get($@"UI/{HoverSampleSet.Submit.GetDescription()}-select");
}
protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent)
@@ -273,22 +283,25 @@ namespace osu.Game.Screens.OnlinePlay.Lounge.Components
{
}
- protected override bool ShouldBeConsideredForInput(Drawable child) => state == SelectionState.Selected;
+ protected override bool ShouldBeConsideredForInput(Drawable child) => state == SelectionState.Selected || child is HoverSounds;
protected override bool OnClick(ClickEvent e)
{
if (Room != selectedRoom.Value)
{
+ sampleSelect?.Play();
selectedRoom.Value = Room;
return true;
}
if (Room.HasPassword.Value)
{
+ sampleJoin?.Play();
this.ShowPopover();
return true;
}
+ sampleJoin?.Play();
lounge?.Join(Room, null);
return base.OnClick(e);
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs
index 043cce4630..b54a4a7726 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerPlayer.cs
@@ -96,7 +96,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer
{
base.LoadComplete();
- ((IBindable)leaderboard.Expanded).BindTo(IsBreakTime);
+ ((IBindable)leaderboard.Expanded).BindTo(HUDOverlay.ShowHud);
}
protected override void StartGameplay()
diff --git a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
index a10c16fcd5..7ee77759b0 100644
--- a/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
+++ b/osu.Game/Screens/Play/HUD/MultiplayerGameplayLeaderboard.cs
@@ -31,7 +31,7 @@ namespace osu.Game.Screens.Play.HUD
private UserLookupCache userLookupCache { get; set; }
private readonly ScoreProcessor scoreProcessor;
- private readonly BindableList playingUsers;
+ private readonly IBindableList playingUsers;
private Bindable scoringMode;
///
diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs
index 67280e4acd..b1cd1f86c0 100644
--- a/osu.Game/Skinning/LegacyHealthDisplay.cs
+++ b/osu.Game/Skinning/LegacyHealthDisplay.cs
@@ -11,6 +11,7 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Utils;
using osu.Game.Rulesets.Judgements;
using osu.Game.Screens.Play.HUD;
+using osu.Game.Utils;
using osuTK;
using osuTK.Graphics;
@@ -83,10 +84,10 @@ namespace osu.Game.Skinning
private static Color4 getFillColour(double hp)
{
if (hp < 0.2)
- return Interpolation.ValueAt(0.2 - hp, Color4.Black, Color4.Red, 0, 0.2);
+ return LegacyUtils.InterpolateNonLinear(0.2 - hp, Color4.Black, Color4.Red, 0, 0.2);
if (hp < epic_cutoff)
- return Interpolation.ValueAt(0.5 - hp, Color4.White, Color4.Black, 0, 0.5);
+ return LegacyUtils.InterpolateNonLinear(0.5 - hp, Color4.White, Color4.Black, 0, 0.5);
return Color4.White;
}
diff --git a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
index 43aadf5acb..cffaea5c94 100644
--- a/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
+++ b/osu.Game/Tests/Visual/Multiplayer/TestMultiplayerClient.cs
@@ -50,7 +50,16 @@ namespace osu.Game.Tests.Visual.Multiplayer
public void Disconnect() => isConnected.Value = false;
- public void AddUser(User user) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(user.Id) { User = user });
+ public MultiplayerRoomUser AddUser(User user, bool markAsPlaying = false)
+ {
+ var roomUser = new MultiplayerRoomUser(user.Id) { User = user };
+ ((IMultiplayerClient)this).UserJoined(roomUser);
+
+ if (markAsPlaying)
+ PlayingUserIds.Add(user.Id);
+
+ return roomUser;
+ }
public void AddNullUser(int userId) => ((IMultiplayerClient)this).UserJoined(new MultiplayerRoomUser(userId));
diff --git a/osu.Game/Utils/LegacyUtils.cs b/osu.Game/Utils/LegacyUtils.cs
new file mode 100644
index 0000000000..64306adf50
--- /dev/null
+++ b/osu.Game/Utils/LegacyUtils.cs
@@ -0,0 +1,65 @@
+// 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.Transforms;
+using osuTK.Graphics;
+
+namespace osu.Game.Utils
+{
+ public static class LegacyUtils
+ {
+ public static Color4 InterpolateNonLinear(double time, Color4 startColour, Color4 endColour, double startTime, double endTime, Easing easing = Easing.None)
+ => InterpolateNonLinear(time, startColour, endColour, startTime, endTime, new DefaultEasingFunction(easing));
+
+ public static Colour4 InterpolateNonLinear(double time, Colour4 startColour, Colour4 endColour, double startTime, double endTime, Easing easing = Easing.None)
+ => InterpolateNonLinear(time, startColour, endColour, startTime, endTime, new DefaultEasingFunction(easing));
+
+ ///
+ /// Interpolates between two sRGB s directly in sRGB space.
+ ///
+ public static Color4 InterpolateNonLinear(double time, Color4 startColour, Color4 endColour, double startTime, double endTime, TEasing easing) where TEasing : IEasingFunction
+ {
+ if (startColour == endColour)
+ return startColour;
+
+ double current = time - startTime;
+ double duration = endTime - startTime;
+
+ if (duration == 0 || current == 0)
+ return startColour;
+
+ float t = Math.Max(0, Math.Min(1, (float)easing.ApplyEasing(current / duration)));
+
+ return new Color4(
+ startColour.R + t * (endColour.R - startColour.R),
+ startColour.G + t * (endColour.G - startColour.G),
+ startColour.B + t * (endColour.B - startColour.B),
+ startColour.A + t * (endColour.A - startColour.A));
+ }
+
+ ///
+ /// Interpolates between two sRGB s directly in sRGB space.
+ ///
+ public static Colour4 InterpolateNonLinear(double time, Colour4 startColour, Colour4 endColour, double startTime, double endTime, TEasing easing) where TEasing : IEasingFunction
+ {
+ if (startColour == endColour)
+ return startColour;
+
+ double current = time - startTime;
+ double duration = endTime - startTime;
+
+ if (duration == 0 || current == 0)
+ return startColour;
+
+ float t = Math.Max(0, Math.Min(1, (float)easing.ApplyEasing(current / duration)));
+
+ return new Colour4(
+ startColour.R + t * (endColour.R - startColour.R),
+ startColour.G + t * (endColour.G - startColour.G),
+ startColour.B + t * (endColour.B - startColour.B),
+ startColour.A + t * (endColour.A - startColour.A));
+ }
+ }
+}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index ec59b28ceb..3a840296ac 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,8 +36,8 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
diff --git a/osu.iOS.props b/osu.iOS.props
index bcc4b5f254..217ec6089a 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,8 +70,8 @@
-
-
+
+
@@ -93,7 +93,7 @@
-
+