diff --git a/osu.Android.props b/osu.Android.props
index 3a9fdfebab..1c180a6b39 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,7 +52,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch/CatchRuleset.cs b/osu.Game.Rulesets.Catch/CatchRuleset.cs
index 76863acc78..eafa1b9b9d 100644
--- a/osu.Game.Rulesets.Catch/CatchRuleset.cs
+++ b/osu.Game.Rulesets.Catch/CatchRuleset.cs
@@ -130,7 +130,8 @@ namespace osu.Game.Rulesets.Catch
return new Mod[]
{
new MultiMod(new ModWindUp(), new ModWindDown()),
- new CatchModFloatingFruits()
+ new CatchModFloatingFruits(),
+ new CatchModMuted(),
};
default:
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs
new file mode 100644
index 0000000000..6d2565440a
--- /dev/null
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModMuted.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Catch.Mods
+{
+ public class CatchModMuted : ModMuted
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/ManiaRuleset.cs b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
index fe736766d9..f4b6e10af4 100644
--- a/osu.Game.Rulesets.Mania/ManiaRuleset.cs
+++ b/osu.Game.Rulesets.Mania/ManiaRuleset.cs
@@ -253,7 +253,8 @@ namespace osu.Game.Rulesets.Mania
case ModType.Fun:
return new Mod[]
{
- new MultiMod(new ModWindUp(), new ModWindDown())
+ new MultiMod(new ModWindUp(), new ModWindDown()),
+ new ManiaModMuted(),
};
default:
diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs
new file mode 100644
index 0000000000..33ebcf303a
--- /dev/null
+++ b/osu.Game.Rulesets.Mania/Mods/ManiaModMuted.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mods;
+
+namespace osu.Game.Rulesets.Mania.Mods
+{
+ public class ManiaModMuted : ModMuted
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs
new file mode 100644
index 0000000000..5e3ee37b61
--- /dev/null
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModMuted.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu.Objects;
+
+namespace osu.Game.Rulesets.Osu.Mods
+{
+ public class OsuModMuted : ModMuted
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
index e21d1da009..210d5e0403 100644
--- a/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
+++ b/osu.Game.Rulesets.Osu/Mods/OsuModTarget.cs
@@ -4,8 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using osu.Framework.Allocation;
-using osu.Framework.Audio.Track;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
@@ -16,7 +14,6 @@ using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Beatmaps.Timing;
using osu.Game.Configuration;
using osu.Game.Graphics;
-using osu.Game.Graphics.Containers;
using osu.Game.Overlays.Settings;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects;
@@ -29,7 +26,6 @@ using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Osu.Utils;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.UI;
-using osu.Game.Skinning;
using osuTK;
using osuTK.Graphics;
@@ -67,11 +63,6 @@ namespace osu.Game.Rulesets.Osu.Mods
///
private const float distance_cap = 380f;
- // The distances from the hit objects to the borders of the playfield they start to "turn around" and curve towards the middle.
- // The closer the hit objects draw to the border, the sharper the turn
- private const byte border_distance_x = 192;
- private const byte border_distance_y = 144;
-
///
/// The extent of rotation towards playfield centre when a circle is near the edge
///
@@ -341,46 +332,7 @@ namespace osu.Game.Rulesets.Osu.Mods
public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
{
- drawableRuleset.Overlays.Add(new TargetBeatContainer(drawableRuleset.Beatmap.HitObjects.First().StartTime));
- }
-
- public class TargetBeatContainer : BeatSyncedContainer
- {
- private readonly double firstHitTime;
-
- private PausableSkinnableSound sample;
-
- public TargetBeatContainer(double firstHitTime)
- {
- this.firstHitTime = firstHitTime;
- AllowMistimedEventFiring = false;
- Divisor = 1;
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- InternalChildren = new Drawable[]
- {
- sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana"))
- };
- }
-
- protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
- {
- base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
-
- if (!IsBeatSyncedWithTrack) return;
-
- int timeSignature = (int)timingPoint.TimeSignature;
-
- // play metronome from one measure before the first object.
- if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
- return;
-
- sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f;
- sample.Play();
- }
+ drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime));
}
#endregion
diff --git a/osu.Game.Rulesets.Osu/OsuRuleset.cs b/osu.Game.Rulesets.Osu/OsuRuleset.cs
index 27794d6010..b13cdff1ec 100644
--- a/osu.Game.Rulesets.Osu/OsuRuleset.cs
+++ b/osu.Game.Rulesets.Osu/OsuRuleset.cs
@@ -189,6 +189,7 @@ namespace osu.Game.Rulesets.Osu
new OsuModTraceable(),
new OsuModBarrelRoll(),
new OsuModApproachDifferent(),
+ new OsuModMuted(),
};
case ModType.System:
diff --git a/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs
new file mode 100644
index 0000000000..0f1e0b2885
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko/Mods/TaikoModMuted.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Taiko.Objects;
+
+namespace osu.Game.Rulesets.Taiko.Mods
+{
+ public class TaikoModMuted : ModMuted
+ {
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
index ab5fcf6336..adc924ba38 100644
--- a/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
+++ b/osu.Game.Rulesets.Taiko/TaikoRuleset.cs
@@ -149,7 +149,8 @@ namespace osu.Game.Rulesets.Taiko
case ModType.Fun:
return new Mod[]
{
- new MultiMod(new ModWindUp(), new ModWindDown())
+ new MultiMod(new ModWindUp(), new ModWindDown()),
+ new TaikoModMuted(),
};
default:
diff --git a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs
index d2369056e1..fcc9f44f0c 100644
--- a/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs
+++ b/osu.Game.Tournament.Tests/NonVisual/CustomTourneyDirectoryTest.cs
@@ -1,21 +1,18 @@
// 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 System.IO;
-using System.Threading;
-using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Platform;
-using osu.Game.Tournament.Configuration;
using osu.Game.Tests;
+using osu.Game.Tournament.Configuration;
namespace osu.Game.Tournament.Tests.NonVisual
{
[TestFixture]
- public class CustomTourneyDirectoryTest
+ public class CustomTourneyDirectoryTest : TournamentHostTest
{
[Test]
public void TestDefaultDirectory()
@@ -24,7 +21,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
{
try
{
- var osu = loadOsu(host);
+ var osu = LoadTournament(host);
var storage = osu.Dependencies.Get();
Assert.That(storage.GetFullPath("."), Is.EqualTo(Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default")));
@@ -54,7 +51,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
try
{
- var osu = loadOsu(host);
+ var osu = LoadTournament(host);
storage = osu.Dependencies.Get();
@@ -111,7 +108,7 @@ namespace osu.Game.Tournament.Tests.NonVisual
try
{
- var osu = loadOsu(host);
+ var osu = LoadTournament(host);
var storage = osu.Dependencies.Get();
@@ -151,25 +148,6 @@ namespace osu.Game.Tournament.Tests.NonVisual
}
}
- private TournamentGameBase loadOsu(GameHost host)
- {
- var osu = new TournamentGameBase();
- Task.Run(() => host.Run(osu))
- .ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted);
- waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
- return osu;
- }
-
- private static void waitForOrAssert(Func result, string failureMessage, int timeout = 90000)
- {
- Task task = Task.Run(() =>
- {
- while (!result()) Thread.Sleep(200);
- });
-
- Assert.IsTrue(task.Wait(timeout), failureMessage);
- }
-
private string basePath(string testInstance) => Path.Combine(RuntimeInfo.StartupDirectory, "headless", testInstance);
}
}
diff --git a/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs b/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs
new file mode 100644
index 0000000000..692cb3870c
--- /dev/null
+++ b/osu.Game.Tournament.Tests/NonVisual/DataLoadTest.cs
@@ -0,0 +1,45 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.IO;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Platform;
+using osu.Game.Rulesets;
+using osu.Game.Tests;
+
+namespace osu.Game.Tournament.Tests.NonVisual
+{
+ public class DataLoadTest : TournamentHostTest
+ {
+ [Test]
+ public void TestUnavailableRuleset()
+ {
+ using (HeadlessGameHost host = new CleanRunHeadlessGameHost(nameof(TestUnavailableRuleset)))
+ {
+ try
+ {
+ var osu = new TestTournament();
+
+ LoadTournament(host, osu);
+ var storage = osu.Dependencies.Get();
+
+ Assert.That(storage.GetFullPath("."), Is.EqualTo(Path.Combine(host.Storage.GetFullPath("."), "tournaments", "default")));
+ }
+ finally
+ {
+ host.Exit();
+ }
+ }
+ }
+
+ public class TestTournament : TournamentGameBase
+ {
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Ruleset.Value = new RulesetInfo(); // not available
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs
index e4eb5a36fb..eaa009c180 100644
--- a/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs
+++ b/osu.Game.Tournament.Tests/NonVisual/IPCLocationTest.cs
@@ -1,10 +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 System.IO;
-using System.Threading;
-using System.Threading.Tasks;
using NUnit.Framework;
using osu.Framework;
using osu.Framework.Allocation;
@@ -15,7 +12,7 @@ using osu.Game.Tournament.IPC;
namespace osu.Game.Tournament.Tests.NonVisual
{
[TestFixture]
- public class IPCLocationTest
+ public class IPCLocationTest : TournamentHostTest
{
[Test]
public void CheckIPCLocation()
@@ -34,11 +31,11 @@ namespace osu.Game.Tournament.Tests.NonVisual
try
{
- var osu = loadOsu(host);
+ var osu = LoadTournament(host);
TournamentStorage storage = (TournamentStorage)osu.Dependencies.Get();
FileBasedIPC ipc = null;
- waitForOrAssert(() => (ipc = osu.Dependencies.Get() as FileBasedIPC) != null, @"ipc could not be populated in a reasonable amount of time");
+ WaitForOrAssert(() => (ipc = osu.Dependencies.Get() as FileBasedIPC) != null, @"ipc could not be populated in a reasonable amount of time");
Assert.True(ipc.SetIPCLocation(testStableInstallDirectory));
Assert.True(storage.AllTournaments.Exists("stable.json"));
@@ -51,24 +48,5 @@ namespace osu.Game.Tournament.Tests.NonVisual
}
}
}
-
- private TournamentGameBase loadOsu(GameHost host)
- {
- var osu = new TournamentGameBase();
- Task.Run(() => host.Run(osu))
- .ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted);
- waitForOrAssert(() => osu.IsLoaded, @"osu! failed to start in a reasonable amount of time");
- return osu;
- }
-
- private static void waitForOrAssert(Func result, string failureMessage, int timeout = 90000)
- {
- Task task = Task.Run(() =>
- {
- while (!result()) Thread.Sleep(200);
- });
-
- Assert.IsTrue(task.Wait(timeout), failureMessage);
- }
}
}
diff --git a/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs b/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs
new file mode 100644
index 0000000000..b14684200f
--- /dev/null
+++ b/osu.Game.Tournament.Tests/NonVisual/TournamentHostTest.cs
@@ -0,0 +1,33 @@
+// 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 System.Threading;
+using System.Threading.Tasks;
+using NUnit.Framework;
+using osu.Framework.Platform;
+
+namespace osu.Game.Tournament.Tests.NonVisual
+{
+ public abstract class TournamentHostTest
+ {
+ public static TournamentGameBase LoadTournament(GameHost host, TournamentGameBase tournament = null)
+ {
+ tournament ??= new TournamentGameBase();
+ Task.Run(() => host.Run(tournament))
+ .ContinueWith(t => Assert.Fail($"Host threw exception {t.Exception}"), TaskContinuationOptions.OnlyOnFaulted);
+ WaitForOrAssert(() => tournament.IsLoaded, @"osu! failed to start in a reasonable amount of time");
+ return tournament;
+ }
+
+ public static void WaitForOrAssert(Func result, string failureMessage, int timeout = 90000)
+ {
+ Task task = Task.Run(() =>
+ {
+ while (!result()) Thread.Sleep(200);
+ });
+
+ Assert.IsTrue(task.Wait(timeout), failureMessage);
+ }
+ }
+}
diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs
index 92eb7ac713..531da00faf 100644
--- a/osu.Game.Tournament/TournamentGameBase.cs
+++ b/osu.Game.Tournament/TournamentGameBase.cs
@@ -66,7 +66,9 @@ namespace osu.Game.Tournament
}
ladder ??= new LadderInfo();
- ladder.Ruleset.Value ??= RulesetStore.AvailableRulesets.First();
+
+ ladder.Ruleset.Value = RulesetStore.GetRuleset(ladder.Ruleset.Value?.ShortName)
+ ?? RulesetStore.AvailableRulesets.First();
bool addedInfo = false;
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 8e32b2e6a7..3cfa2cc755 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -1058,7 +1058,7 @@ namespace osu.Game
OverlayActivationMode.BindTo(newOsuScreen.OverlayActivationMode);
API.Activity.BindTo(newOsuScreen.Activity);
- MusicController.AllowRateAdjustments = newOsuScreen.AllowRateAdjustments;
+ MusicController.AllowTrackAdjustments = newOsuScreen.AllowTrackAdjustments;
if (newOsuScreen.HideOverlaysOnEnter)
CloseAllOverlays();
diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs
index a7fac24351..f2d575550a 100644
--- a/osu.Game/OsuGameBase.cs
+++ b/osu.Game/OsuGameBase.cs
@@ -479,7 +479,7 @@ namespace osu.Game
if (r.NewValue?.Available != true)
{
// reject the change if the ruleset is not available.
- Ruleset.Value = r.OldValue;
+ Ruleset.Value = r.OldValue?.Available == true ? r.OldValue : RulesetStore.AvailableRulesets.First();
return;
}
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
index ddd1dfa6cd..fee0e62315 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
@@ -18,6 +18,8 @@ using osu.Game.Scoring;
using osu.Game.Users.Drawables;
using osuTK;
using osuTK.Graphics;
+using osu.Framework.Localisation;
+using osu.Framework.Extensions.LocalisationExtensions;
namespace osu.Game.Overlays.BeatmapSet.Scores
{
@@ -211,11 +213,11 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
return content.ToArray();
}
- protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty);
+ protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default);
private class HeaderText : OsuSpriteText
{
- public HeaderText(string text)
+ public HeaderText(LocalisableString text)
{
Text = text.ToUpper();
Font = OsuFont.GetFont(size: 10, weight: FontWeight.Bold);
diff --git a/osu.Game/Overlays/MusicController.cs b/osu.Game/Overlays/MusicController.cs
index a15f80ca21..8fd50c3df2 100644
--- a/osu.Game/Overlays/MusicController.cs
+++ b/osu.Game/Overlays/MusicController.cs
@@ -400,35 +400,38 @@ namespace osu.Game.Overlays
NextTrack();
}
- private bool allowRateAdjustments;
+ private bool allowTrackAdjustments;
///
- /// Whether mod rate adjustments are allowed to be applied.
+ /// Whether mod track adjustments are allowed to be applied.
///
- public bool AllowRateAdjustments
+ public bool AllowTrackAdjustments
{
- get => allowRateAdjustments;
+ get => allowTrackAdjustments;
set
{
- if (allowRateAdjustments == value)
+ if (allowTrackAdjustments == value)
return;
- allowRateAdjustments = value;
+ allowTrackAdjustments = value;
ResetTrackAdjustments();
}
}
///
- /// Resets the speed adjustments currently applied on and applies the mod adjustments if is true.
+ /// Resets the adjustments currently applied on and applies the mod adjustments if is true.
///
///
- /// Does not reset speed adjustments applied directly to the beatmap track.
+ /// Does not reset any adjustments applied directly to the beatmap track.
///
public void ResetTrackAdjustments()
{
- CurrentTrack.ResetSpeedAdjustments();
+ CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Balance);
+ CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Frequency);
+ CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Tempo);
+ CurrentTrack.RemoveAllAdjustments(AdjustableProperty.Volume);
- if (allowRateAdjustments)
+ if (allowTrackAdjustments)
{
foreach (var mod in mods.Value.OfType())
mod.ApplyToTrack(CurrentTrack);
diff --git a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs
index 585b5c22aa..f568aae59c 100644
--- a/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs
+++ b/osu.Game/Overlays/Rankings/Tables/RankingsTable.cs
@@ -13,6 +13,7 @@ using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Game.Users;
using osu.Game.Users.Drawables;
using osuTK;
+using osu.Framework.Localisation;
namespace osu.Game.Overlays.Rankings.Tables
{
@@ -74,7 +75,7 @@ namespace osu.Game.Overlays.Rankings.Tables
protected override Drawable CreateHeader(int index, TableColumn column)
{
- var title = column?.Header ?? string.Empty;
+ var title = column?.Header ?? default;
return new HeaderText(title, title == HighlightedColumn);
}
@@ -109,7 +110,7 @@ namespace osu.Game.Overlays.Rankings.Tables
{
private readonly bool isHighlighted;
- public HeaderText(string text, bool isHighlighted)
+ public HeaderText(LocalisableString text, bool isHighlighted)
{
this.isHighlighted = isHighlighted;
diff --git a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs
index a6969f483f..56814244c0 100644
--- a/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs
+++ b/osu.Game/Overlays/Rankings/Tables/UserBasedTable.cs
@@ -9,6 +9,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Users;
using osu.Game.Scoring;
+using osu.Framework.Localisation;
namespace osu.Game.Overlays.Rankings.Tables
{
@@ -31,8 +32,8 @@ namespace osu.Game.Overlays.Rankings.Tables
protected override Drawable CreateHeader(int index, TableColumn column)
{
- var title = column?.Header ?? string.Empty;
- return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title));
+ var title = column?.Header ?? default;
+ return new UserTableHeaderText(title, HighlightedColumn == title, GradeColumns.Contains(title.ToString()));
}
protected sealed override Country GetCountry(UserStatistics item) => item.User.Country;
@@ -66,7 +67,7 @@ namespace osu.Game.Overlays.Rankings.Tables
private class UserTableHeaderText : HeaderText
{
- public UserTableHeaderText(string text, bool isHighlighted, bool isGrade)
+ public UserTableHeaderText(LocalisableString text, bool isHighlighted, bool isGrade)
: base(text, isHighlighted)
{
Margin = new MarginPadding
diff --git a/osu.Game/Rulesets/Mods/Metronome.cs b/osu.Game/Rulesets/Mods/Metronome.cs
new file mode 100644
index 0000000000..ee0a42b4bc
--- /dev/null
+++ b/osu.Game/Rulesets/Mods/Metronome.cs
@@ -0,0 +1,53 @@
+// 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.Track;
+using osu.Framework.Graphics;
+using osu.Game.Audio;
+using osu.Game.Beatmaps.ControlPoints;
+using osu.Game.Graphics.Containers;
+using osu.Game.Skinning;
+
+namespace osu.Game.Rulesets.Mods
+{
+ public class Metronome : BeatSyncedContainer
+ {
+ private readonly double firstHitTime;
+
+ private PausableSkinnableSound sample;
+
+ /// Start time of the first hit object, used for providing a count down.
+ public Metronome(double firstHitTime)
+ {
+ this.firstHitTime = firstHitTime;
+ AllowMistimedEventFiring = false;
+ Divisor = 1;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ InternalChildren = new Drawable[]
+ {
+ sample = new PausableSkinnableSound(new SampleInfo("Gameplay/catch-banana"))
+ };
+ }
+
+ protected override void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
+ {
+ base.OnNewBeat(beatIndex, timingPoint, effectPoint, amplitudes);
+
+ if (!IsBeatSyncedWithTrack) return;
+
+ int timeSignature = (int)timingPoint.TimeSignature;
+
+ // play metronome from one measure before the first object.
+ if (BeatSyncClock.CurrentTime < firstHitTime - timingPoint.BeatLength * timeSignature)
+ return;
+
+ sample.Frequency.Value = beatIndex % timeSignature == 0 ? 1 : 0.5f;
+ sample.Play();
+ }
+ }
+}
diff --git a/osu.Game/Rulesets/Mods/ModMuted.cs b/osu.Game/Rulesets/Mods/ModMuted.cs
new file mode 100644
index 0000000000..9e69bc1386
--- /dev/null
+++ b/osu.Game/Rulesets/Mods/ModMuted.cs
@@ -0,0 +1,48 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Audio;
+using osu.Framework.Audio.Track;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Configuration;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.UI;
+
+namespace osu.Game.Rulesets.Mods
+{
+ public abstract class ModMuted : Mod
+ {
+ public override string Name => "Muted";
+ public override string Acronym => "MU";
+ public override IconUsage? Icon => FontAwesome.Solid.VolumeMute;
+ public override string Description => "Can you still feel the rhythm without music?";
+ public override ModType Type => ModType.Fun;
+ public override double ScoreMultiplier => 1;
+ }
+
+ public abstract class ModMuted : ModMuted, IApplicableToDrawableRuleset, IApplicableToTrack
+ where TObject : HitObject
+ {
+ private readonly BindableNumber volumeAdjust = new BindableDouble();
+
+ [SettingSource("Enable metronome", "Add a metronome to help you keep track of the rhythm.")]
+ public BindableBool EnableMetronome { get; } = new BindableBool
+ {
+ Default = true,
+ Value = true
+ };
+
+ public void ApplyToTrack(ITrack track)
+ {
+ track.AddAdjustment(AdjustableProperty.Volume, volumeAdjust);
+ }
+
+ public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset)
+ {
+ if (EnableMetronome.Value)
+ drawableRuleset.Overlays.Add(new Metronome(drawableRuleset.Beatmap.HitObjects.First().StartTime));
+ }
+ }
+}
diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs
index b6dc97a7f6..61a3b0f5cc 100644
--- a/osu.Game/Screens/Edit/Editor.cs
+++ b/osu.Game/Screens/Edit/Editor.cs
@@ -55,7 +55,7 @@ namespace osu.Game.Screens.Edit
public override bool DisallowExternalBeatmapRulesetChanges => true;
- public override bool AllowRateAdjustments => false;
+ public override bool AllowTrackAdjustments => false;
protected bool HasUnsavedChanges => lastSavedHash != changeHandler.CurrentStateHash;
diff --git a/osu.Game/Screens/Edit/EditorTable.cs b/osu.Game/Screens/Edit/EditorTable.cs
index 9578b96897..756339405c 100644
--- a/osu.Game/Screens/Edit/EditorTable.cs
+++ b/osu.Game/Screens/Edit/EditorTable.cs
@@ -2,10 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Extensions.LocalisationExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Input.Events;
+using osu.Framework.Localisation;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
@@ -42,11 +44,11 @@ namespace osu.Game.Screens.Edit
});
}
- protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? string.Empty);
+ protected override Drawable CreateHeader(int index, TableColumn column) => new HeaderText(column?.Header ?? default);
private class HeaderText : OsuSpriteText
{
- public HeaderText(string text)
+ public HeaderText(LocalisableString text)
{
Text = text.ToUpper();
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold);
diff --git a/osu.Game/Screens/IOsuScreen.cs b/osu.Game/Screens/IOsuScreen.cs
index 0434135547..17384c161c 100644
--- a/osu.Game/Screens/IOsuScreen.cs
+++ b/osu.Game/Screens/IOsuScreen.cs
@@ -59,9 +59,9 @@ namespace osu.Game.Screens
Bindable Ruleset { get; }
///
- /// Whether mod rate adjustments are allowed to be applied.
+ /// Whether mod track adjustments are allowed to be applied.
///
- bool AllowRateAdjustments { get; }
+ bool AllowTrackAdjustments { get; }
///
/// Invoked when the back button has been pressed to close any overlays before exiting this .
diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs
index e53b46f391..1d0182a945 100644
--- a/osu.Game/Screens/Menu/MainMenu.cs
+++ b/osu.Game/Screens/Menu/MainMenu.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Screens.Menu
public override bool AllowExternalScreenChange => true;
- public override bool AllowRateAdjustments => false;
+ public override bool AllowTrackAdjustments => false;
private Screen songSelect;
diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs
index 2a2759e0dd..56ed7a9564 100644
--- a/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs
+++ b/osu.Game/Screens/OnlinePlay/Multiplayer/Spectate/MultiSpectatorScreen.cs
@@ -24,7 +24,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer.Spectate
public override bool DisallowExternalBeatmapRulesetChanges => true;
// We are managing our own adjustments. For now, this happens inside the Player instances themselves.
- public override bool AllowRateAdjustments => false;
+ public override bool AllowTrackAdjustments => false;
///
/// Whether all spectating players have finished loading.
diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs
index c3b2612e79..e3fe14a585 100644
--- a/osu.Game/Screens/OsuScreen.cs
+++ b/osu.Game/Screens/OsuScreen.cs
@@ -81,7 +81,7 @@ namespace osu.Game.Screens
public virtual float BackgroundParallaxAmount => 1;
- public virtual bool AllowRateAdjustments => true;
+ public virtual bool AllowTrackAdjustments => true;
public Bindable Beatmap { get; private set; }
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index 0e4d38660b..d76d44767a 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -56,7 +56,7 @@ namespace osu.Game.Screens.Play
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.UserTriggered;
// We are managing our own adjustments (see OnEntering/OnExiting).
- public override bool AllowRateAdjustments => false;
+ public override bool AllowTrackAdjustments => false;
private readonly IBindable gameActive = new Bindable(true);
diff --git a/osu.Game/Screens/StartupScreen.cs b/osu.Game/Screens/StartupScreen.cs
index e5e134fd39..15f75d7cff 100644
--- a/osu.Game/Screens/StartupScreen.cs
+++ b/osu.Game/Screens/StartupScreen.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Screens
public override bool CursorVisible => false;
- public override bool AllowRateAdjustments => false;
+ public override bool AllowTrackAdjustments => false;
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 4baaf89c67..2efcfeb278 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -36,7 +36,7 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 66cae06713..2630614c03 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -93,7 +93,7 @@
-
+