diff --git a/osu.Android.props b/osu.Android.props
index 3b90b1675c..6609db3027 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -10,7 +10,7 @@
true
-
+
-
\ No newline at end of file
+
+
+
diff --git a/osu.Game.Rulesets.Mania.Tests/ManiaHealthProcessorTest.cs b/osu.Game.Rulesets.Mania.Tests/ManiaHealthProcessorTest.cs
new file mode 100644
index 0000000000..315849f7de
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/ManiaHealthProcessorTest.cs
@@ -0,0 +1,31 @@
+// 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.Rulesets.Mania.Beatmaps;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Mania.Scoring;
+
+namespace osu.Game.Rulesets.Mania.Tests
+{
+ [TestFixture]
+ public class ManiaHealthProcessorTest
+ {
+ [Test]
+ public void TestNoDrain()
+ {
+ var processor = new ManiaHealthProcessor(0);
+ processor.ApplyBeatmap(new ManiaBeatmap(new StageDefinition(4))
+ {
+ HitObjects =
+ {
+ new Note { StartTime = 0 },
+ new Note { StartTime = 1000 },
+ }
+ });
+
+ // No matter what, mania doesn't have passive HP drain.
+ Assert.That(processor.DrainRate, Is.Zero);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs b/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
index 183550eb7b..a33eac83c2 100644
--- a/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
+++ b/osu.Game.Rulesets.Mania/Scoring/ManiaHealthProcessor.cs
@@ -15,6 +15,15 @@ namespace osu.Game.Rulesets.Mania.Scoring
{
}
+ protected override double ComputeDrainRate()
+ {
+ // Base call is run only to compute HP recovery (namely, `HpMultiplierNormal`).
+ // This closely mirrors (broken) behaviour of stable and as such is preserved unchanged.
+ base.ComputeDrainRate();
+
+ return 0;
+ }
+
protected override IEnumerable EnumerateTopLevelHitObjects() => Beatmap.HitObjects;
protected override IEnumerable EnumerateNestedHitObjects(HitObject hitObject) => hitObject.NestedHitObjects;
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs
index c17a9ddf5f..fa85c8c9f8 100644
--- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs
@@ -12,9 +12,12 @@ using osu.Framework.Graphics.UserInterface;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Framework.Threading;
+using osu.Game.Online.API;
+using osu.Game.Beatmaps;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.SkinEditor;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Screens.Edit.Components;
using osu.Game.Screens.Play;
@@ -38,6 +41,9 @@ namespace osu.Game.Tests.Visual.Navigation
advanceToSongSelect();
openSkinEditor();
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
+
switchToGameplayScene();
BarHitErrorMeter hitErrorMeter = null;
@@ -98,6 +104,10 @@ namespace osu.Game.Tests.Visual.Navigation
{
advanceToSongSelect();
openSkinEditor();
+
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
+
switchToGameplayScene();
AddUntilStep("wait for components", () => skinEditor.ChildrenOfType().Any());
@@ -162,6 +172,9 @@ namespace osu.Game.Tests.Visual.Navigation
openSkinEditor();
AddStep("select DT", () => Game.SelectedMods.Value = new Mod[] { new OsuModDoubleTime() });
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
+
switchToGameplayScene();
AddAssert("DT still selected", () => ((Player)Game.ScreenStack.CurrentScreen).Mods.Value.Single() is OsuModDoubleTime);
@@ -174,6 +187,9 @@ namespace osu.Game.Tests.Visual.Navigation
openSkinEditor();
AddStep("select relax and spun out", () => Game.SelectedMods.Value = new Mod[] { new OsuModRelax(), new OsuModSpunOut() });
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
+
switchToGameplayScene();
AddAssert("no mod selected", () => !((Player)Game.ScreenStack.CurrentScreen).Mods.Value.Any());
@@ -186,6 +202,9 @@ namespace osu.Game.Tests.Visual.Navigation
openSkinEditor();
AddStep("select autoplay", () => Game.SelectedMods.Value = new Mod[] { new OsuModAutoplay() });
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
+
switchToGameplayScene();
AddAssert("no mod selected", () => !((Player)Game.ScreenStack.CurrentScreen).Mods.Value.Any());
@@ -198,6 +217,9 @@ namespace osu.Game.Tests.Visual.Navigation
openSkinEditor();
AddStep("select cinema", () => Game.SelectedMods.Value = new Mod[] { new OsuModCinema() });
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
+
switchToGameplayScene();
AddAssert("no mod selected", () => !((Player)Game.ScreenStack.CurrentScreen).Mods.Value.Any());
@@ -240,6 +262,43 @@ namespace osu.Game.Tests.Visual.Navigation
AddAssert("editor sidebars not empty", () => skinEditor.ChildrenOfType().SelectMany(sidebar => sidebar.Children).Count(), () => Is.GreaterThan(0));
}
+ [Test]
+ public void TestOpenSkinEditorGameplaySceneOnBeatmapWithNoObjects()
+ {
+ AddStep("set dummy beatmap", () => Game.Beatmap.SetDefault());
+ advanceToSongSelect();
+
+ AddStep("create empty beatmap", () => Game.BeatmapManager.CreateNew(new OsuRuleset().RulesetInfo, new GuestUser()));
+ AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
+
+ openSkinEditor();
+ switchToGameplayScene();
+ }
+
+ [Test]
+ public void TestOpenSkinEditorGameplaySceneWhenDummyBeatmapActive()
+ {
+ AddStep("set dummy beatmap", () => Game.Beatmap.SetDefault());
+
+ openSkinEditor();
+ }
+
+ [Test]
+ public void TestOpenSkinEditorGameplaySceneWhenDifferentRulesetActive()
+ {
+ BeatmapSetInfo beatmapSet = null!;
+
+ AddStep("import beatmap", () => beatmapSet = BeatmapImportHelper.LoadQuickOszIntoOsu(Game).GetResultSafely());
+ AddStep("select mania difficulty", () =>
+ {
+ var beatmap = beatmapSet.Beatmaps.First(b => b.Ruleset.OnlineID == 3);
+ Game.Beatmap.Value = Game.BeatmapManager.GetWorkingBeatmap(beatmap);
+ });
+
+ openSkinEditor();
+ switchToGameplayScene();
+ }
+
private void advanceToSongSelect()
{
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
@@ -266,9 +325,6 @@ namespace osu.Game.Tests.Visual.Navigation
private void switchToGameplayScene()
{
- AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
- AddUntilStep("wait for selected", () => !Game.Beatmap.IsDefault);
-
AddStep("Click gameplay scene button", () =>
{
InputManager.MoveMouseTo(skinEditor.ChildrenOfType().First(b => b.Text.ToString() == "Gameplay"));
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
index 7616b9b83c..c793535255 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-#nullable disable
-
using System;
using System.Linq;
using NUnit.Framework;
@@ -56,92 +54,76 @@ namespace osu.Game.Tests.Visual.Online
textContainer.Clear();
});
- [Test]
- public void TestLinksGeneral()
+ [TestCase("test!")]
+ [TestCase("dev.ppy.sh!")]
+ [TestCase("https://dev.ppy.sh!", LinkAction.External)]
+ [TestCase("http://dev.ppy.sh!", LinkAction.External)]
+ [TestCase("forgothttps://dev.ppy.sh!", LinkAction.External)]
+ [TestCase("forgothttp://dev.ppy.sh!", LinkAction.External)]
+ [TestCase("00:12:345 - Test?", LinkAction.OpenEditorTimestamp)]
+ [TestCase("00:12:345 (1,2) - Test?", LinkAction.OpenEditorTimestamp)]
+ [TestCase($"{OsuGameBase.OSU_PROTOCOL}edit/00:12:345 - Test?", LinkAction.OpenEditorTimestamp)]
+ [TestCase($"{OsuGameBase.OSU_PROTOCOL}edit/00:12:345 (1,2) - Test?", LinkAction.OpenEditorTimestamp)]
+ [TestCase($"{OsuGameBase.OSU_PROTOCOL}00:12:345 - not an editor timestamp", LinkAction.External)]
+ [TestCase("Wiki link for tasty [[Performance Points]]", LinkAction.OpenWiki)]
+ [TestCase("(osu forums)[https://dev.ppy.sh/forum] (old link format)", LinkAction.External)]
+ [TestCase("[https://dev.ppy.sh/home New site] (new link format)", LinkAction.External)]
+ [TestCase("[osu forums](https://dev.ppy.sh/forum) (new link format 2)", LinkAction.External)]
+ [TestCase("[https://dev.ppy.sh/home This is only a link to the new osu webpage but this is supposed to test word wrap.]", LinkAction.External)]
+ [TestCase("Let's (try)[https://dev.ppy.sh/home] [https://dev.ppy.sh/b/252238 multiple links] https://dev.ppy.sh/home", LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External)]
+ [TestCase("[https://dev.ppy.sh/home New link format with escaped [and \\[ paired] braces]", LinkAction.External)]
+ [TestCase("[Markdown link format with escaped [and \\[ paired] braces](https://dev.ppy.sh/home)", LinkAction.External)]
+ [TestCase("(Old link format with escaped (and \\( paired) parentheses)[https://dev.ppy.sh/home] and [[also a rogue wiki link]]", LinkAction.External, LinkAction.OpenWiki)]
+ [TestCase("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).")] // note that there's 0 links here (they get removed if a channel is not found)
+ [TestCase("Join my multiplayer game osump://12346.", LinkAction.JoinMultiplayerMatch)]
+ [TestCase("Join my multiplayer gameosump://12346.", LinkAction.JoinMultiplayerMatch)]
+ [TestCase("Join my [multiplayer game](osump://12346).", LinkAction.JoinMultiplayerMatch)]
+ [TestCase($"Join my [#english]({OsuGameBase.OSU_PROTOCOL}chan/#english).", LinkAction.OpenChannel)]
+ [TestCase($"Join my {OsuGameBase.OSU_PROTOCOL}chan/#english.", LinkAction.OpenChannel)]
+ [TestCase($"Join my{OsuGameBase.OSU_PROTOCOL}chan/#english.", LinkAction.OpenChannel)]
+ [TestCase("Join my #english or #japanese channels.", LinkAction.OpenChannel, LinkAction.OpenChannel)]
+ [TestCase("Join my #english or #nonexistent #hashtag channels.", LinkAction.OpenChannel)]
+ [TestCase("Hello world\uD83D\uDE12(<--This is an emoji). There are more:\uD83D\uDE10\uD83D\uDE00,\uD83D\uDE20")]
+ public void TestLinksGeneral(string text, params LinkAction[] actions)
{
- int messageIndex = 0;
+ addMessageWithChecks(text, expectedActions: actions);
+ }
- addMessageWithChecks("test!");
- addMessageWithChecks("dev.ppy.sh!");
- addMessageWithChecks("https://dev.ppy.sh!", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("http://dev.ppy.sh!", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("forgothttps://dev.ppy.sh!", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("forgothttp://dev.ppy.sh!", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("00:12:345 (1,2) - Test?", 1, expectedActions: LinkAction.OpenEditorTimestamp);
- addMessageWithChecks("Wiki link for tasty [[Performance Points]]", 1, expectedActions: LinkAction.OpenWiki);
- addMessageWithChecks("(osu forums)[https://dev.ppy.sh/forum] (old link format)", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("[https://dev.ppy.sh/home New site] (new link format)", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("[osu forums](https://dev.ppy.sh/forum) (new link format 2)", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("[https://dev.ppy.sh/home This is only a link to the new osu webpage but this is supposed to test word wrap.]", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("is now listening to [https://dev.ppy.sh/s/93523 IMAGE -MATERIAL- ]", 1, true, expectedActions: LinkAction.OpenBeatmapSet);
- addMessageWithChecks("is now playing [https://dev.ppy.sh/b/252238 IMAGE -MATERIAL- ]", 1, true, expectedActions: LinkAction.OpenBeatmap);
- addMessageWithChecks("Let's (try)[https://dev.ppy.sh/home] [https://dev.ppy.sh/b/252238 multiple links] https://dev.ppy.sh/home", 3,
- expectedActions: new[] { LinkAction.External, LinkAction.OpenBeatmap, LinkAction.External });
- addMessageWithChecks("[https://dev.ppy.sh/home New link format with escaped [and \\[ paired] braces]", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("[Markdown link format with escaped [and \\[ paired] braces](https://dev.ppy.sh/home)", 1, expectedActions: LinkAction.External);
- addMessageWithChecks("(Old link format with escaped (and \\( paired) parentheses)[https://dev.ppy.sh/home] and [[also a rogue wiki link]]", 2,
- expectedActions: new[] { LinkAction.External, LinkAction.OpenWiki });
- // note that there's 0 links here (they get removed if a channel is not found)
- addMessageWithChecks("#lobby or #osu would be blue (and work) in the ChatDisplay test (when a proper ChatOverlay is present).");
- addMessageWithChecks("I am important!", 0, false, true);
- addMessageWithChecks("feels important", 0, true, true);
- addMessageWithChecks("likes to post this [https://dev.ppy.sh/home link].", 1, true, true, expectedActions: LinkAction.External);
- addMessageWithChecks("Join my multiplayer game osump://12346.", 1, expectedActions: LinkAction.JoinMultiplayerMatch);
- addMessageWithChecks("Join my multiplayer gameosump://12346.", 1, expectedActions: LinkAction.JoinMultiplayerMatch);
- addMessageWithChecks("Join my [multiplayer game](osump://12346).", 1, expectedActions: LinkAction.JoinMultiplayerMatch);
- addMessageWithChecks($"Join my [#english]({OsuGameBase.OSU_PROTOCOL}chan/#english).", 1, expectedActions: LinkAction.OpenChannel);
- addMessageWithChecks($"Join my {OsuGameBase.OSU_PROTOCOL}chan/#english.", 1, expectedActions: LinkAction.OpenChannel);
- addMessageWithChecks($"Join my{OsuGameBase.OSU_PROTOCOL}chan/#english.", 1, expectedActions: LinkAction.OpenChannel);
- addMessageWithChecks("Join my #english or #japanese channels.", 2, expectedActions: new[] { LinkAction.OpenChannel, LinkAction.OpenChannel });
- addMessageWithChecks("Join my #english or #nonexistent #hashtag channels.", 1, expectedActions: LinkAction.OpenChannel);
- addMessageWithChecks("Hello world\uD83D\uDE12(<--This is an emoji). There are more:\uD83D\uDE10\uD83D\uDE00,\uD83D\uDE20");
+ [TestCase("is now listening to [https://dev.ppy.sh/s/93523 IMAGE -MATERIAL- ]", true, false, LinkAction.OpenBeatmapSet)]
+ [TestCase("is now playing [https://dev.ppy.sh/b/252238 IMAGE -MATERIAL- ]", true, false, LinkAction.OpenBeatmap)]
+ [TestCase("I am important!", false, true)]
+ [TestCase("feels important", true, true)]
+ [TestCase("likes to post this [https://dev.ppy.sh/home link].", true, true, LinkAction.External)]
+ public void TestActionAndImportantLinks(string text, bool isAction, bool isImportant, params LinkAction[] expectedActions)
+ {
+ addMessageWithChecks(text, isAction, isImportant, expectedActions);
+ }
- void addMessageWithChecks(string text, int linkAmount = 0, bool isAction = false, bool isImportant = false, params LinkAction[] expectedActions)
+ private void addMessageWithChecks(string text, bool isAction = false, bool isImportant = false, params LinkAction[] expectedActions)
+ {
+ ChatLine newLine = null!;
+
+ AddStep("add message", () =>
{
- ChatLine newLine = null;
- int index = messageIndex++;
+ newLine = new ChatLine(new DummyMessage(text, isAction, isImportant));
+ textContainer.Add(newLine);
+ });
- AddStep("add message", () =>
- {
- newLine = new ChatLine(new DummyMessage(text, isAction, isImportant, index));
- textContainer.Add(newLine);
- });
+ AddAssert("msg has the right action", () => newLine.Message.Links.Select(l => l.Action), () => Is.EqualTo(expectedActions));
+ AddAssert($"msg shows {expectedActions.Length} link(s)", isShowingLinks);
- AddAssert($"msg #{index} has {linkAmount} link(s)", () => newLine.Message.Links.Count == linkAmount);
- AddAssert($"msg #{index} has the right action", hasExpectedActions);
- //AddAssert($"msg #{index} is " + (isAction ? "italic" : "not italic"), () => newLine.ContentFlow.Any() && isAction == isItalic());
- AddAssert($"msg #{index} shows {linkAmount} link(s)", isShowingLinks);
+ bool isShowingLinks()
+ {
+ bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour);
- bool hasExpectedActions()
- {
- var expectedActionsList = expectedActions.ToList();
+ Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White;
- if (expectedActionsList.Count != newLine.Message.Links.Count)
- return false;
+ var linkCompilers = newLine.DrawableContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
+ var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);
- for (int i = 0; i < newLine.Message.Links.Count; i++)
- {
- var action = newLine.Message.Links[i].Action;
- if (action != expectedActions[i]) return false;
- }
-
- return true;
- }
-
- //bool isItalic() => newLine.ContentFlow.Where(d => d is OsuSpriteText).Cast().All(sprite => sprite.Font.Italics);
-
- bool isShowingLinks()
- {
- bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour);
-
- Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White;
-
- var linkCompilers = newLine.DrawableContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
- var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);
-
- return linkSprites.All(d => d.Colour == linkColour)
- && newLine.DrawableContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour);
- }
+ return linkSprites.All(d => d.Colour == linkColour)
+ && newLine.DrawableContentFlow.Except(linkSprites.Concat(linkCompilers)).All(d => d.Colour == textColour)
+ && linkCompilers.Count == expectedActions.Length;
}
}
@@ -155,7 +137,7 @@ namespace osu.Game.Tests.Visual.Online
addEchoWithWait("[https://dev.ppy.sh/forum let's try multiple words too!]");
addEchoWithWait("(long loading times! clickable while loading?)[https://dev.ppy.sh/home]", null, 5000);
- void addEchoWithWait(string text, string completeText = null, double delay = 250)
+ void addEchoWithWait(string text, string? completeText = null, double delay = 250)
{
int index = messageIndex++;
@@ -184,21 +166,12 @@ namespace osu.Game.Tests.Visual.Online
{
private static long messageCounter;
- internal static readonly APIUser TEST_SENDER_BACKGROUND = new APIUser
- {
- Username = @"i-am-important",
- Id = 42,
- Colour = "#250cc9",
- };
-
internal static readonly APIUser TEST_SENDER = new APIUser
{
Username = @"Somebody",
Id = 1,
};
- public new DateTimeOffset Timestamp = DateTimeOffset.Now;
-
public DummyMessage(string text, bool isAction = false, bool isImportant = false, int number = 0)
: base(messageCounter++)
{
diff --git a/osu.Game/Graphics/Containers/LinkFlowContainer.cs b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
index 40e883f8ac..aa72996fff 100644
--- a/osu.Game/Graphics/Containers/LinkFlowContainer.cs
+++ b/osu.Game/Graphics/Containers/LinkFlowContainer.cs
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
+using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.Online;
using osu.Game.Users;
@@ -47,9 +48,16 @@ namespace osu.Game.Graphics.Containers
foreach (var link in links)
{
+ string displayText = text.Substring(link.Index, link.Length);
+
+ if (previousLinkEnd > link.Index)
+ {
+ Logger.Log($@"Link ""{link.Url}"" with text ""{displayText}"" overlaps previous link, ignoring.");
+ continue;
+ }
+
AddText(text[previousLinkEnd..link.Index]);
- string displayText = text.Substring(link.Index, link.Length);
object linkArgument = link.Argument;
string tooltip = displayText == link.Url ? null : link.Url;
diff --git a/osu.Game/Localisation/EditorSetupStrings.cs b/osu.Game/Localisation/EditorSetupStrings.cs
index 401411365b..eff6f9e6b8 100644
--- a/osu.Game/Localisation/EditorSetupStrings.cs
+++ b/osu.Game/Localisation/EditorSetupStrings.cs
@@ -179,21 +179,11 @@ namespace osu.Game.Localisation
///
public static LocalisableString ClickToSelectTrack => new TranslatableString(getKey(@"click_to_select_track"), @"Click to select a track");
- ///
- /// "Click to replace the track"
- ///
- public static LocalisableString ClickToReplaceTrack => new TranslatableString(getKey(@"click_to_replace_track"), @"Click to replace the track");
-
///
/// "Click to select a background image"
///
public static LocalisableString ClickToSelectBackground => new TranslatableString(getKey(@"click_to_select_background"), @"Click to select a background image");
- ///
- /// "Click to replace the background image"
- ///
- public static LocalisableString ClickToReplaceBackground => new TranslatableString(getKey(@"click_to_replace_background"), @"Click to replace the background image");
-
///
/// "Ruleset ({0})"
///
diff --git a/osu.Game/Online/Chat/MessageFormatter.cs b/osu.Game/Online/Chat/MessageFormatter.cs
index 9a194dba47..f055633d64 100644
--- a/osu.Game/Online/Chat/MessageFormatter.cs
+++ b/osu.Game/Online/Chat/MessageFormatter.cs
@@ -85,8 +85,8 @@ namespace osu.Game.Online.Chat
if (escapeChars != null)
displayText = escapeChars.Aggregate(displayText, (current, c) => current.Replace($"\\{c}", c.ToString()));
- // Check for encapsulated links
- if (result.Links.Find(l => (l.Index <= index && l.Index + l.Length >= index + m.Length) || (index <= l.Index && index + m.Length >= l.Index + l.Length)) == null)
+ // Check for overlapping links
+ if (!result.Links.Exists(l => l.Overlaps(index, m.Length)))
{
result.Text = result.Text.Remove(index, m.Length).Insert(index, displayText);
@@ -364,7 +364,9 @@ namespace osu.Game.Online.Chat
Argument = argument;
}
- public bool Overlaps(Link otherLink) => Index < otherLink.Index + otherLink.Length && otherLink.Index < Index + Length;
+ public bool Overlaps(Link otherLink) => Overlaps(otherLink.Index, otherLink.Length);
+
+ public bool Overlaps(int otherIndex, int otherLength) => Index < otherIndex + otherLength && otherIndex < Index + Length;
public int CompareTo(Link? otherLink) => Index > otherLink?.Index ? 1 : -1;
}
diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs
index f8784504b8..a645683c5f 100644
--- a/osu.Game/Overlays/BeatmapListingOverlay.cs
+++ b/osu.Game/Overlays/BeatmapListingOverlay.cs
@@ -183,9 +183,7 @@ namespace osu.Game.Overlays
// new results may contain beatmaps from a previous page,
// this is dodgy but matches web behaviour for now.
// see: https://github.com/ppy/osu-web/issues/9270
- // todo: replace custom equality compraer with ExceptBy in net6.0
- // newCards = newCards.ExceptBy(foundContent.Select(c => c.BeatmapSet.OnlineID), c => c.BeatmapSet.OnlineID);
- newCards = newCards.Except(foundContent, BeatmapCardEqualityComparer.Default);
+ newCards = newCards.ExceptBy(foundContent.Select(c => c.BeatmapSet.OnlineID), c => c.BeatmapSet.OnlineID);
panelLoadTask = LoadComponentsAsync(newCards, loaded =>
{
@@ -378,21 +376,5 @@ namespace osu.Game.Overlays
if (shouldShowMore)
filterControl.FetchNextPage();
}
-
- private class BeatmapCardEqualityComparer : IEqualityComparer
- {
- public static BeatmapCardEqualityComparer Default { get; } = new BeatmapCardEqualityComparer();
-
- public bool Equals(BeatmapCard x, BeatmapCard y)
- {
- if (ReferenceEquals(x, y)) return true;
- if (ReferenceEquals(x, null)) return false;
- if (ReferenceEquals(y, null)) return false;
-
- return x.BeatmapSet.Equals(y.BeatmapSet);
- }
-
- public int GetHashCode(BeatmapCard obj) => obj.BeatmapSet.GetHashCode();
- }
}
}
diff --git a/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs b/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs
index 84fd342493..4fc9fbb6d5 100644
--- a/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs
+++ b/osu.Game/Overlays/Chat/ChatOverlayTopBar.cs
@@ -46,7 +46,7 @@ namespace osu.Game.Overlays.Chat
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Icon = HexaconsIcons.Social,
+ Icon = HexaconsIcons.Messaging,
Size = new Vector2(24),
},
// Placeholder text
diff --git a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs
index 18d1c4c62b..be7ddd115b 100644
--- a/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs
+++ b/osu.Game/Overlays/SkinEditor/SkinEditorOverlay.cs
@@ -17,7 +17,6 @@ using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Graphics.Containers;
using osu.Game.Input.Bindings;
-using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods;
using osu.Game.Scoring;
using osu.Game.Screens;
@@ -26,6 +25,7 @@ using osu.Game.Screens.Edit.Components;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using osu.Game.Screens.Select;
+using osu.Game.Users;
using osu.Game.Utils;
using osuTK;
@@ -55,9 +55,6 @@ namespace osu.Game.Overlays.SkinEditor
[Resolved]
private MusicController music { get; set; } = null!;
- [Resolved]
- private IBindable ruleset { get; set; } = null!;
-
[Resolved]
private Bindable> mods { get; set; } = null!;
@@ -139,6 +136,12 @@ namespace osu.Game.Overlays.SkinEditor
{
performer?.PerformFromScreen(screen =>
{
+ if (beatmap.Value is DummyWorkingBeatmap)
+ {
+ // presume we don't have anything good to play and just bail.
+ return;
+ }
+
// If we're playing the intro, switch away to another beatmap.
if (beatmap.Value.BeatmapSetInfo.Protected)
{
@@ -150,7 +153,7 @@ namespace osu.Game.Overlays.SkinEditor
if (screen is Player)
return;
- var replayGeneratingMod = ruleset.Value.CreateInstance().GetAutoplayMod();
+ var replayGeneratingMod = beatmap.Value.BeatmapInfo.Ruleset.CreateInstance().GetAutoplayMod();
IReadOnlyList usableMods = mods.Value;
@@ -285,6 +288,8 @@ namespace osu.Game.Overlays.SkinEditor
private partial class EndlessPlayer : ReplayPlayer
{
+ protected override UserActivity? InitialActivity => null;
+
public EndlessPlayer(Func, Score> createScore)
: base(createScore, new PlayerConfiguration
{
@@ -294,10 +299,21 @@ namespace osu.Game.Overlays.SkinEditor
{
}
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ if (!LoadedBeatmapSuccessfully)
+ Scheduler.AddDelayed(this.Exit, 3000);
+ }
+
protected override void Update()
{
base.Update();
+ if (!LoadedBeatmapSuccessfully)
+ return;
+
if (GameplayState.HasPassed)
GameplayClockContainer.Seek(0);
}
diff --git a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs
index 8c84ad90ba..f6d20319cb 100644
--- a/osu.Game/Screens/Edit/Setup/ResourcesSection.cs
+++ b/osu.Game/Screens/Edit/Setup/ResourcesSection.cs
@@ -146,13 +146,8 @@ namespace osu.Game.Screens.Edit.Setup
private void updatePlaceholderText()
{
- audioTrackChooser.Text = audioTrackChooser.Current.Value == null
- ? EditorSetupStrings.ClickToSelectTrack
- : EditorSetupStrings.ClickToReplaceTrack;
-
- backgroundChooser.Text = backgroundChooser.Current.Value == null
- ? EditorSetupStrings.ClickToSelectBackground
- : EditorSetupStrings.ClickToReplaceBackground;
+ audioTrackChooser.Text = audioTrackChooser.Current.Value?.Name ?? EditorSetupStrings.ClickToSelectTrack;
+ backgroundChooser.Text = backgroundChooser.Current.Value?.Name ?? EditorSetupStrings.ClickToSelectBackground;
}
}
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 4d1fdaa89a..cc100605b4 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 7e5c5be4ea..a6b3527466 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -23,6 +23,6 @@
iossimulator-x64
-
+