mirror of
https://github.com/SK-la/Ez2Lazer.git
synced 2026-03-13 11:20:28 +00:00
Merge remote-tracking branch 'upstream/master' into locmain
# Conflicts: # osu.Game/Screens/Ranking/Statistics/StatisticsPanel.cs # osu.Game/osu.Game.csproj
This commit is contained in:
88
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModEasy.cs
Normal file
88
osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModEasy.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||||
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
|
using osu.Game.Tests.Beatmaps;
|
||||||
|
using osu.Game.Tests.Visual;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Osu.Tests.Mods
|
||||||
|
{
|
||||||
|
public partial class TestSceneOsuModEasy : OsuModTestScene
|
||||||
|
{
|
||||||
|
protected override bool AllowFail => true;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestMultipleApplication()
|
||||||
|
{
|
||||||
|
bool reapplied = false;
|
||||||
|
CreateModTest(new ModTestData
|
||||||
|
{
|
||||||
|
Mods = [new OsuModEasy { Retries = { Value = 1 } }],
|
||||||
|
Autoplay = false,
|
||||||
|
CreateBeatmap = () =>
|
||||||
|
{
|
||||||
|
// do stuff to speed up fails
|
||||||
|
var b = new TestBeatmap(new OsuRuleset().RulesetInfo)
|
||||||
|
{
|
||||||
|
Difficulty = { DrainRate = 10 }
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var ho in b.HitObjects)
|
||||||
|
ho.StartTime /= 4;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
},
|
||||||
|
PassCondition = () =>
|
||||||
|
{
|
||||||
|
if (((ModEasyTestPlayer)Player).FailuresSuppressed > 0 && !reapplied)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
foreach (var mod in Player.GameplayState.Mods.OfType<IApplicableToDifficulty>())
|
||||||
|
mod.ApplyToDifficulty(new BeatmapDifficulty());
|
||||||
|
|
||||||
|
foreach (var mod in Player.GameplayState.Mods.OfType<IApplicableToPlayer>())
|
||||||
|
mod.ApplyToPlayer(Player);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// don't care if this fails. in fact a failure here is probably better than the alternative.
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
reapplied = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Player.GameplayState.HasFailed && ((ModEasyTestPlayer)Player).FailuresSuppressed <= 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override TestPlayer CreateModPlayer(Ruleset ruleset) => new ModEasyTestPlayer(CurrentTestData, AllowFail);
|
||||||
|
|
||||||
|
private partial class ModEasyTestPlayer : ModTestPlayer
|
||||||
|
{
|
||||||
|
public int FailuresSuppressed { get; private set; }
|
||||||
|
|
||||||
|
public ModEasyTestPlayer(ModTestData data, bool allowFail)
|
||||||
|
: base(data, allowFail)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool CheckModsAllowFailure()
|
||||||
|
{
|
||||||
|
bool failureAllowed = GameplayState.Mods.OfType<IApplicableFailOverride>().All(m => m.PerformFail());
|
||||||
|
|
||||||
|
if (!failureAllowed)
|
||||||
|
FailuresSuppressed++;
|
||||||
|
|
||||||
|
return failureAllowed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Extensions.ObjectExtensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Utils;
|
using osu.Framework.Utils;
|
||||||
@@ -37,13 +38,16 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IEditorChangeHandler? changeHandler { get; set; }
|
private IEditorChangeHandler? changeHandler { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private EditorBeatmap editorBeatmap { get; set; } = null!;
|
||||||
|
|
||||||
[Resolved(CanBeNull = true)]
|
[Resolved(CanBeNull = true)]
|
||||||
private IDistanceSnapProvider? snapProvider { get; set; }
|
private IDistanceSnapProvider? snapProvider { get; set; }
|
||||||
|
|
||||||
private BindableList<HitObject> selectedItems { get; } = new BindableList<HitObject>();
|
private BindableList<HitObject> selectedItems { get; } = new BindableList<HitObject>();
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(EditorBeatmap editorBeatmap)
|
private void load()
|
||||||
{
|
{
|
||||||
selectedItems.BindTo(editorBeatmap.SelectedHitObjects);
|
selectedItems.BindTo(editorBeatmap.SelectedHitObjects);
|
||||||
}
|
}
|
||||||
@@ -53,15 +57,22 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
selectedItems.CollectionChanged += (_, __) => updateState();
|
selectedItems.CollectionChanged += (_, __) => updateState();
|
||||||
|
editorBeatmap.HitObjectUpdated += hitObjectUpdated;
|
||||||
updateState();
|
updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void hitObjectUpdated(HitObject hitObject)
|
||||||
|
{
|
||||||
|
if (selectedMovableObjects.Contains(hitObject))
|
||||||
|
updateState();
|
||||||
|
}
|
||||||
|
|
||||||
private void updateState()
|
private void updateState()
|
||||||
{
|
{
|
||||||
var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects);
|
var quad = GeometryUtils.GetSurroundingQuad(selectedMovableObjects);
|
||||||
|
|
||||||
CanScaleX.Value = quad.Width > 0;
|
CanScaleX.Value = Precision.DefinitelyBigger(quad.Width, 0);
|
||||||
CanScaleY.Value = quad.Height > 0;
|
CanScaleY.Value = Precision.DefinitelyBigger(quad.Height, 0);
|
||||||
CanScaleDiagonally.Value = CanScaleX.Value && CanScaleY.Value;
|
CanScaleDiagonally.Value = CanScaleX.Value && CanScaleY.Value;
|
||||||
CanScaleFromPlayfieldOrigin.Value = selectedMovableObjects.Any();
|
CanScaleFromPlayfieldOrigin.Value = selectedMovableObjects.Any();
|
||||||
IsScalingSlider.Value = selectedMovableObjects.Count() == 1 && selectedMovableObjects.First() is Slider;
|
IsScalingSlider.Value = selectedMovableObjects.Count() == 1 && selectedMovableObjects.First() is Slider;
|
||||||
@@ -339,5 +350,13 @@ namespace osu.Game.Rulesets.Osu.Edit
|
|||||||
PathControlPointTypes = (hitObject as IHasPath)?.Path.ControlPoints.Select(p => p.Type).ToArray();
|
PathControlPointTypes = (hitObject as IHasPath)?.Path.ControlPoints.Select(p => p.Type).ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool isDisposing)
|
||||||
|
{
|
||||||
|
base.Dispose(isDisposing);
|
||||||
|
|
||||||
|
if (editorBeatmap.IsNotNull())
|
||||||
|
editorBeatmap.HitObjectUpdated -= hitObjectUpdated;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,6 +132,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName);
|
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName);
|
||||||
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
|
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
|
||||||
AddStep("add effect point", () => EditorBeatmap.ControlPointInfo.Add(500, new EffectControlPoint { KiaiMode = true }));
|
AddStep("add effect point", () => EditorBeatmap.ControlPointInfo.Add(500, new EffectControlPoint { KiaiMode = true }));
|
||||||
|
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
|
||||||
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[]
|
AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[]
|
||||||
{
|
{
|
||||||
new HitCircle
|
new HitCircle
|
||||||
@@ -185,6 +186,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
var effectPoint = EditorBeatmap.ControlPointInfo.EffectPoints.Single();
|
var effectPoint = EditorBeatmap.ControlPointInfo.EffectPoints.Single();
|
||||||
return effectPoint.Time == 500 && effectPoint.KiaiMode && effectPoint.ScrollSpeedBindable.IsDefault;
|
return effectPoint.Time == 500 && effectPoint.KiaiMode && effectPoint.ScrollSpeedBindable.IsDefault;
|
||||||
});
|
});
|
||||||
|
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
|
||||||
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
|
AddAssert("created difficulty has no objects", () => EditorBeatmap.HitObjects.Count == 0);
|
||||||
|
|
||||||
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
|
AddAssert("status is modified", () => EditorBeatmap.BeatmapInfo.Status == BeatmapOnlineStatus.LocallyModified);
|
||||||
@@ -223,6 +225,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = previousDifficultyName = Guid.NewGuid().ToString());
|
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = previousDifficultyName = Guid.NewGuid().ToString());
|
||||||
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
|
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
|
||||||
|
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
|
||||||
AddStep("add effect points", () =>
|
AddStep("add effect points", () =>
|
||||||
{
|
{
|
||||||
EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 });
|
EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 });
|
||||||
@@ -253,6 +256,8 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
|
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
|
||||||
|
|
||||||
AddAssert("created difficulty has effect points", () =>
|
AddAssert("created difficulty has effect points", () =>
|
||||||
{
|
{
|
||||||
return EditorBeatmap.ControlPointInfo.EffectPoints.SequenceEqual(new[]
|
return EditorBeatmap.ControlPointInfo.EffectPoints.SequenceEqual(new[]
|
||||||
@@ -284,6 +289,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
|
|
||||||
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName);
|
AddStep("set unique difficulty name", () => EditorBeatmap.BeatmapInfo.DifficultyName = firstDifficultyName);
|
||||||
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
|
AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 }));
|
||||||
|
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
|
||||||
AddStep("add effect points", () =>
|
AddStep("add effect points", () =>
|
||||||
{
|
{
|
||||||
EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 });
|
EditorBeatmap.ControlPointInfo.Add(250, new EffectControlPoint { KiaiMode = false, ScrollSpeed = 0.05 });
|
||||||
@@ -311,6 +317,8 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
|
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
|
||||||
|
|
||||||
AddAssert("created difficulty has effect points", () =>
|
AddAssert("created difficulty has effect points", () =>
|
||||||
{
|
{
|
||||||
// since this difficulty is on another ruleset, scroll speed specifications are completely reset,
|
// since this difficulty is on another ruleset, scroll speed specifications are completely reset,
|
||||||
@@ -344,6 +352,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
StartTime = 1000
|
StartTime = 1000
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
AddStep("add bookmarks", () => EditorBeatmap.Bookmarks.AddRange([500, 1000]));
|
||||||
AddStep("set approach rate", () => EditorBeatmap.Difficulty.ApproachRate = 4);
|
AddStep("set approach rate", () => EditorBeatmap.Difficulty.ApproachRate = 4);
|
||||||
AddStep("set combo colours", () =>
|
AddStep("set combo colours", () =>
|
||||||
{
|
{
|
||||||
@@ -394,6 +403,7 @@ namespace osu.Game.Tests.Visual.Editing
|
|||||||
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
|
return timingPoint.Time == 0 && timingPoint.BeatLength == 1000;
|
||||||
});
|
});
|
||||||
AddAssert("created difficulty has objects", () => EditorBeatmap.HitObjects.Count == 2);
|
AddAssert("created difficulty has objects", () => EditorBeatmap.HitObjects.Count == 2);
|
||||||
|
AddAssert("created difficulty has bookmarks", () => EditorBeatmap.Bookmarks.Count == 2);
|
||||||
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
|
AddAssert("approach rate correctly copied", () => EditorBeatmap.Difficulty.ApproachRate == 4);
|
||||||
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
|
AddAssert("combo colours correctly copied", () => EditorBeatmap.BeatmapSkin.AsNonNull().ComboColours.Count == 2);
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ using osu.Game.Beatmaps;
|
|||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Online.Chat;
|
using osu.Game.Online.Chat;
|
||||||
|
using osu.Game.Rulesets.Catch;
|
||||||
using osu.Game.Rulesets.Mania.Mods;
|
using osu.Game.Rulesets.Mania.Mods;
|
||||||
using osu.Game.Rulesets.Mods;
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Rulesets.Osu.Mods;
|
using osu.Game.Rulesets.Osu.Mods;
|
||||||
@@ -266,6 +267,8 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
|||||||
AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible);
|
AddUntilStep("wait for placeholder visible", () => getPlaceholder()?.State.Value == Visibility.Visible);
|
||||||
|
|
||||||
AddAssert("still has selection", () => Beatmap.IsDefault, () => Is.False);
|
AddAssert("still has selection", () => Beatmap.IsDefault, () => Is.False);
|
||||||
|
|
||||||
|
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMinimum, 0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -365,13 +368,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
|||||||
SortBy(SortMode.Difficulty);
|
SortBy(SortMode.Difficulty);
|
||||||
checkMatchedBeatmaps(6);
|
checkMatchedBeatmaps(6);
|
||||||
|
|
||||||
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Any(d => d.Enabled.Value));
|
scopeBeatmap(false);
|
||||||
AddStep("click spread indicator", () =>
|
|
||||||
{
|
|
||||||
InputManager.MoveMouseTo(this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Single(d => d.Enabled.Value));
|
|
||||||
InputManager.Click(MouseButton.Left);
|
|
||||||
});
|
|
||||||
WaitForFiltering();
|
|
||||||
checkMatchedBeatmaps(3);
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
AddStep("press Escape", () => InputManager.Key(Key.Escape));
|
AddStep("press Escape", () => InputManager.Key(Key.Escape));
|
||||||
@@ -389,9 +386,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
|||||||
SortBy(SortMode.Artist);
|
SortBy(SortMode.Artist);
|
||||||
checkMatchedBeatmaps(6);
|
checkMatchedBeatmaps(6);
|
||||||
|
|
||||||
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Any(d => d.Enabled.Value));
|
scopeBeatmap(true);
|
||||||
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
|
|
||||||
WaitForFiltering();
|
|
||||||
checkMatchedBeatmaps(3);
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
AddStep("press Escape", () => InputManager.Key(Key.Escape));
|
AddStep("press Escape", () => InputManager.Key(Key.Escape));
|
||||||
@@ -413,9 +408,7 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
|||||||
WaitForFiltering();
|
WaitForFiltering();
|
||||||
checkMatchedBeatmaps(3);
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Any(d => d.Enabled.Value));
|
scopeBeatmap(true);
|
||||||
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
|
|
||||||
WaitForFiltering();
|
|
||||||
checkMatchedBeatmaps(3);
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
AddStep("press Escape", () => InputManager.Key(Key.Escape));
|
AddStep("press Escape", () => InputManager.Key(Key.Escape));
|
||||||
@@ -424,6 +417,179 @@ namespace osu.Game.Tests.Visual.SongSelectV2
|
|||||||
AddAssert("text filter not emptied", () => filterTextBox.Current.Value, () => Is.Not.Empty);
|
AddAssert("text filter not emptied", () => filterTextBox.Current.Value, () => Is.Not.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(false)]
|
||||||
|
[TestCase(true)]
|
||||||
|
public void TestUnscopeRevertsToOriginalSelection(bool grouped)
|
||||||
|
{
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
|
||||||
|
LoadSongSelect();
|
||||||
|
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
|
||||||
|
checkMatchedBeatmaps(6);
|
||||||
|
|
||||||
|
AddStep("select normal difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Normal")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal")));
|
||||||
|
|
||||||
|
scopeBeatmap(grouped);
|
||||||
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
|
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
|
||||||
|
|
||||||
|
AddStep("exit scoped view", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<FilterControl.ScopedBeatmapSetDisplay>().First());
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
WaitForFiltering();
|
||||||
|
|
||||||
|
checkMatchedBeatmaps(6);
|
||||||
|
AddAssert("normal difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal")));
|
||||||
|
|
||||||
|
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(false)]
|
||||||
|
[TestCase(true)]
|
||||||
|
public void TestUnscopeWhenSelectedBeatmapHiddenByFilters(bool grouped)
|
||||||
|
{
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
|
||||||
|
LoadSongSelect();
|
||||||
|
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
|
||||||
|
checkMatchedBeatmaps(6);
|
||||||
|
|
||||||
|
AddStep("set star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, findBeatmap("Hard").StarRating + 0.1));
|
||||||
|
WaitForFiltering();
|
||||||
|
|
||||||
|
AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
|
||||||
|
|
||||||
|
scopeBeatmap(grouped);
|
||||||
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
|
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
|
||||||
|
|
||||||
|
AddStep("exit scoped view", () =>
|
||||||
|
{
|
||||||
|
InputManager.MoveMouseTo(this.ChildrenOfType<FilterControl.ScopedBeatmapSetDisplay>().First());
|
||||||
|
InputManager.Click(MouseButton.Left);
|
||||||
|
});
|
||||||
|
WaitForFiltering();
|
||||||
|
|
||||||
|
AddAssert("hard difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
|
||||||
|
|
||||||
|
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(false)]
|
||||||
|
[TestCase(true)]
|
||||||
|
public void TestUnscopeByChangingRuleset(bool grouped)
|
||||||
|
{
|
||||||
|
bool showConverts = Config.Get<bool>(OsuSetting.ShowConvertedBeatmaps);
|
||||||
|
|
||||||
|
AddStep("hide converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
|
||||||
|
|
||||||
|
ImportBeatmapForRuleset(0, 2);
|
||||||
|
|
||||||
|
LoadSongSelect();
|
||||||
|
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
|
||||||
|
checkMatchedBeatmaps(2);
|
||||||
|
|
||||||
|
scopeBeatmap(grouped);
|
||||||
|
checkMatchedBeatmaps(2);
|
||||||
|
|
||||||
|
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
|
||||||
|
|
||||||
|
AddStep("change ruleset", () => Ruleset.Value = new CatchRuleset().RulesetInfo);
|
||||||
|
WaitForFiltering();
|
||||||
|
|
||||||
|
AddAssert("hard catch difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
|
||||||
|
|
||||||
|
AddStep("revert convert setting", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, showConverts));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(false)]
|
||||||
|
[TestCase(true)]
|
||||||
|
public void TestUnscopeByShowingConverts(bool grouped)
|
||||||
|
{
|
||||||
|
bool showConverts = Config.Get<bool>(OsuSetting.ShowConvertedBeatmaps);
|
||||||
|
|
||||||
|
AddStep("hide converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, false));
|
||||||
|
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
|
||||||
|
LoadSongSelect();
|
||||||
|
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
|
||||||
|
checkMatchedBeatmaps(6);
|
||||||
|
|
||||||
|
AddStep("set star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, Beatmap.Value.BeatmapSetInfo.Beatmaps.ElementAt(1).StarRating + 0.1));
|
||||||
|
WaitForFiltering();
|
||||||
|
|
||||||
|
AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
|
||||||
|
|
||||||
|
scopeBeatmap(grouped);
|
||||||
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
|
AddStep("select insane difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Insane")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Insane")));
|
||||||
|
|
||||||
|
AddStep("show converts", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, true));
|
||||||
|
WaitForFiltering();
|
||||||
|
|
||||||
|
AddAssert("hard difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
|
||||||
|
|
||||||
|
AddStep("revert convert setting", () => Config.SetValue(OsuSetting.ShowConvertedBeatmaps, showConverts));
|
||||||
|
AddStep("reset star difficulty filter", () => Config.SetValue(OsuSetting.DisplayStarsMaximum, 10.1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[TestCase(false)]
|
||||||
|
[TestCase(true)]
|
||||||
|
public void TestUnscopeByChangingFilterText(bool grouped)
|
||||||
|
{
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
ImportBeatmapForRuleset(0);
|
||||||
|
|
||||||
|
LoadSongSelect();
|
||||||
|
SortBy(grouped ? SortMode.Title : SortMode.Difficulty);
|
||||||
|
checkMatchedBeatmaps(6);
|
||||||
|
|
||||||
|
AddStep("select hard difficulty", () => Beatmap.Value = Beatmaps.GetWorkingBeatmap(findBeatmap("Hard")));
|
||||||
|
AddUntilStep("selection changed", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Hard")));
|
||||||
|
|
||||||
|
scopeBeatmap(grouped);
|
||||||
|
checkMatchedBeatmaps(3);
|
||||||
|
|
||||||
|
AddStep("set filter text", () => filterTextBox.Current.Value = findBeatmap("Normal").DifficultyName);
|
||||||
|
WaitForFiltering();
|
||||||
|
|
||||||
|
AddAssert("normal difficulty is selected", () => Beatmap.Value.BeatmapInfo, () => Is.EqualTo(findBeatmap("Normal")));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scopeBeatmap(bool grouped)
|
||||||
|
{
|
||||||
|
if (grouped)
|
||||||
|
{
|
||||||
|
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Any(d => d.Enabled.Value));
|
||||||
|
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapSet.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddUntilStep("wait for spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Any(d => d.Enabled.Value));
|
||||||
|
AddStep("click spread indicator", () => this.ChildrenOfType<PanelBeatmapStandalone.SpreadDisplay>().Single(d => d.Enabled.Value).TriggerClick());
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForFiltering();
|
||||||
|
}
|
||||||
|
|
||||||
|
private BeatmapInfo findBeatmap(string difficultySubstring) => Beatmap.Value.BeatmapSetInfo.Beatmaps.First(b => b.DifficultyName.Contains(difficultySubstring));
|
||||||
|
|
||||||
private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType<NoResultsPlaceholder>().FirstOrDefault();
|
private NoResultsPlaceholder? getPlaceholder() => SongSelect.ChildrenOfType<NoResultsPlaceholder>().FirstOrDefault();
|
||||||
|
|
||||||
private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected));
|
private void checkMatchedBeatmaps(int expected) => AddUntilStep($"{expected} matching shown", () => Carousel.MatchedBeatmapsCount, () => Is.EqualTo(expected));
|
||||||
|
|||||||
@@ -154,7 +154,11 @@ namespace osu.Game.Beatmaps
|
|||||||
{
|
{
|
||||||
DifficultyName = NamingUtils.GetNextBestName(targetBeatmapSet.Beatmaps.Select(b => b.DifficultyName), "New Difficulty")
|
DifficultyName = NamingUtils.GetNextBestName(targetBeatmapSet.Beatmaps.Select(b => b.DifficultyName), "New Difficulty")
|
||||||
};
|
};
|
||||||
var newBeatmap = new Beatmap { BeatmapInfo = newBeatmapInfo };
|
var newBeatmap = new Beatmap
|
||||||
|
{
|
||||||
|
BeatmapInfo = newBeatmapInfo,
|
||||||
|
Bookmarks = referenceWorkingBeatmap.Beatmap.Bookmarks.ToArray()
|
||||||
|
};
|
||||||
|
|
||||||
foreach (var timingPoint in referenceWorkingBeatmap.Beatmap.ControlPointInfo.TimingPoints)
|
foreach (var timingPoint in referenceWorkingBeatmap.Beatmap.ControlPointInfo.TimingPoints)
|
||||||
newBeatmap.ControlPointInfo.Add(timingPoint.Time, timingPoint.DeepClone());
|
newBeatmap.ControlPointInfo.Add(timingPoint.Time, timingPoint.DeepClone());
|
||||||
|
|||||||
@@ -3,17 +3,18 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Screens.Play;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Mods
|
namespace osu.Game.Rulesets.Mods
|
||||||
{
|
{
|
||||||
public abstract class ModEasyWithExtraLives : ModEasy, IApplicableFailOverride, IApplicableToHealthProcessor
|
public abstract class ModEasyWithExtraLives : ModEasy, IApplicableFailOverride, IApplicableToPlayer, IApplicableToHealthProcessor
|
||||||
{
|
{
|
||||||
[SettingSource("Extra Lives", "Number of extra lives")]
|
[SettingSource("Extra Lives", "Number of extra lives")]
|
||||||
public Bindable<int> Retries { get; } = new BindableInt(2)
|
public Bindable<int> Retries { get; } = new BindableInt(2)
|
||||||
@@ -33,18 +34,26 @@ namespace osu.Game.Rulesets.Mods
|
|||||||
|
|
||||||
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModAccuracyChallenge)).ToArray();
|
public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(ModAccuracyChallenge)).ToArray();
|
||||||
|
|
||||||
private int retries;
|
private int? retries;
|
||||||
|
|
||||||
private readonly BindableNumber<double> health = new BindableDouble();
|
private readonly BindableNumber<double> health = new BindableDouble();
|
||||||
|
|
||||||
public override void ApplyToDifficulty(BeatmapDifficulty difficulty)
|
public void ApplyToPlayer(Player player)
|
||||||
{
|
{
|
||||||
base.ApplyToDifficulty(difficulty);
|
// this throw works for two reasons:
|
||||||
|
// - every time `Player` loads, it deep-clones mods into itself, and the deep clone copies *only* `[SettingsSource]` properties
|
||||||
|
// - `Player` is the only consumer of `IApplicableToPlayer` and it calls `ApplyToPlayer()` exactly once per mod instance
|
||||||
|
// if either of the above assumptions no longer holds true for any reason, this will need to be reconsidered
|
||||||
|
if (retries != null)
|
||||||
|
throw new InvalidOperationException(@"Cannot apply this mod instance to a player twice.");
|
||||||
|
|
||||||
retries = Retries.Value;
|
retries = Retries.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool PerformFail()
|
public bool PerformFail()
|
||||||
{
|
{
|
||||||
|
Debug.Assert(retries != null);
|
||||||
|
|
||||||
if (retries == 0) return true;
|
if (retries == 0) return true;
|
||||||
|
|
||||||
health.Value = health.MaxValue;
|
health.Value = health.MaxValue;
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
|
|
||||||
private readonly BindableWithCurrent<EditorBeatmapSkin.SampleSet?> current = new BindableWithCurrent<EditorBeatmapSkin.SampleSet?>();
|
private readonly BindableWithCurrent<EditorBeatmapSkin.SampleSet?> current = new BindableWithCurrent<EditorBeatmapSkin.SampleSet?>();
|
||||||
private readonly Dictionary<(string name, string bank), SampleButton> buttons = new Dictionary<(string, string), SampleButton>();
|
private readonly Dictionary<(string name, string bank), SampleButton> buttons = new Dictionary<(string, string), SampleButton>();
|
||||||
|
private readonly Bindable<DirectoryInfo?> lastSelectedFileDirectory = new Bindable<DirectoryInfo?>();
|
||||||
|
|
||||||
private FormControlBackground background = null!;
|
private FormControlBackground background = null!;
|
||||||
private FormFieldCaption caption = null!;
|
private FormFieldCaption caption = null!;
|
||||||
@@ -125,6 +126,7 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
Margin = new MarginPadding(5),
|
Margin = new MarginPadding(5),
|
||||||
SampleAddRequested = SampleAddRequested,
|
SampleAddRequested = SampleAddRequested,
|
||||||
SampleRemoveRequested = SampleRemoveRequested,
|
SampleRemoveRequested = SampleRemoveRequested,
|
||||||
|
LastSelectedFileDirectory = { BindTarget = lastSelectedFileDirectory },
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@@ -197,6 +199,7 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
public Action<string>? SampleRemoveRequested { get; init; }
|
public Action<string>? SampleRemoveRequested { get; init; }
|
||||||
|
|
||||||
private Bindable<FileInfo?> selectedFile { get; } = new Bindable<FileInfo?>();
|
private Bindable<FileInfo?> selectedFile { get; } = new Bindable<FileInfo?>();
|
||||||
|
public Bindable<DirectoryInfo?> LastSelectedFileDirectory { get; } = new Bindable<DirectoryInfo?>();
|
||||||
|
|
||||||
private TrianglesV2? triangles { get; set; }
|
private TrianglesV2? triangles { get; set; }
|
||||||
|
|
||||||
@@ -313,6 +316,7 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
|
|
||||||
this.HidePopover();
|
this.HidePopover();
|
||||||
ActualFilename.Value = SampleAddRequested?.Invoke(selectedFile.Value, ExpectedFilename.Value) ?? selectedFile.Value.ToString();
|
ActualFilename.Value = SampleAddRequested?.Invoke(selectedFile.Value, ExpectedFilename.Value) ?? selectedFile.Value.ToString();
|
||||||
|
LastSelectedFileDirectory.Value = selectedFile.Value.Directory;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteSample()
|
private void deleteSample()
|
||||||
@@ -324,7 +328,9 @@ namespace osu.Game.Screens.Edit.Components
|
|||||||
ActualFilename.Value = null;
|
ActualFilename.Value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Popover? GetPopover() => ActualFilename.Value == null ? new FormFileSelector.FileChooserPopover(SupportedExtensions.AUDIO_EXTENSIONS, selectedFile, null) : null;
|
public Popover? GetPopover() => ActualFilename.Value == null
|
||||||
|
? new FormFileSelector.FileChooserPopover(SupportedExtensions.AUDIO_EXTENSIONS, selectedFile, LastSelectedFileDirectory.Value?.FullName)
|
||||||
|
: null;
|
||||||
|
|
||||||
public MenuItem[]? ContextMenuItems =>
|
public MenuItem[]? ContextMenuItems =>
|
||||||
ActualFilename.Value != null
|
ActualFilename.Value != null
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.Placeholders;
|
using osu.Game.Online.Placeholders;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
|
using osu.Game.Rulesets.Mods;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Ranking.Statistics.User;
|
using osu.Game.Screens.Ranking.Statistics.User;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
@@ -287,6 +288,8 @@ namespace osu.Game.Screens.Ranking.Statistics
|
|||||||
preventTaggingReason = "Play the beatmap in its original ruleset to contribute to beatmap tags!";
|
preventTaggingReason = "Play the beatmap in its original ruleset to contribute to beatmap tags!";
|
||||||
else if (localUserScore.Rank < ScoreRank.C)
|
else if (localUserScore.Rank < ScoreRank.C)
|
||||||
preventTaggingReason = "Set a better score to contribute to beatmap tags!";
|
preventTaggingReason = "Set a better score to contribute to beatmap tags!";
|
||||||
|
else if (localUserScore.Mods.Any(m => (m.Type == ModType.Conversion) && !(m is ModClassic)))
|
||||||
|
preventTaggingReason = "Play this beatmap without conversion mods to contribute to beatmap tags!";
|
||||||
|
|
||||||
if (preventTaggingReason == null)
|
if (preventTaggingReason == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,13 +22,8 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
{
|
{
|
||||||
public partial class ScopedBeatmapSetDisplay : OsuClickableContainer, IKeyBindingHandler<GlobalAction>
|
public partial class ScopedBeatmapSetDisplay : OsuClickableContainer, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
public Bindable<BeatmapSetInfo?> ScopedBeatmapSet
|
public IBindable<BeatmapSetInfo?> ScopedBeatmapSet { get; } = new Bindable<BeatmapSetInfo?>();
|
||||||
{
|
|
||||||
get => scopedBeatmapSet.Current;
|
|
||||||
set => scopedBeatmapSet.Current = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly BindableWithCurrent<BeatmapSetInfo?> scopedBeatmapSet = new BindableWithCurrent<BeatmapSetInfo?>();
|
|
||||||
private Box flashLayer = null!;
|
private Box flashLayer = null!;
|
||||||
private Container content = null!;
|
private Container content = null!;
|
||||||
private OsuTextFlowContainer text = null!;
|
private OsuTextFlowContainer text = null!;
|
||||||
@@ -44,7 +39,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(OverlayColourProvider colourProvider)
|
private void load(ISongSelect? songSelect, OverlayColourProvider colourProvider)
|
||||||
{
|
{
|
||||||
Content.AutoSizeEasing = Easing.OutQuint;
|
Content.AutoSizeEasing = Easing.OutQuint;
|
||||||
Content.AutoSizeDuration = transition_duration;
|
Content.AutoSizeDuration = transition_duration;
|
||||||
@@ -97,25 +92,25 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
Alpha = 0,
|
Alpha = 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
Action = () => scopedBeatmapSet.Value = null;
|
Action = () => songSelect?.UnscopeBeatmapSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
scopedBeatmapSet.BindValueChanged(_ => updateState(), true);
|
ScopedBeatmapSet.BindValueChanged(_ => updateState(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateState()
|
private void updateState()
|
||||||
{
|
{
|
||||||
if (scopedBeatmapSet.Value != null)
|
if (ScopedBeatmapSet.Value != null)
|
||||||
{
|
{
|
||||||
content.BypassAutoSizeAxes = Axes.None;
|
content.BypassAutoSizeAxes = Axes.None;
|
||||||
text.Clear();
|
text.Clear();
|
||||||
text.AddText(SongSelectStrings.TemporarilyShowingAllBeatmapsIn);
|
text.AddText(SongSelectStrings.TemporarilyShowingAllBeatmapsIn);
|
||||||
text.AddText(@" ");
|
text.AddText(@" ");
|
||||||
text.AddText(scopedBeatmapSet.Value.Metadata.GetDisplayTitleRomanisable(), t => t.Font = OsuFont.Style.Body.With(weight: FontWeight.Bold));
|
text.AddText(ScopedBeatmapSet.Value.Metadata.GetDisplayTitleRomanisable(), t => t.Font = OsuFont.Style.Body.With(weight: FontWeight.Bold));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -126,7 +121,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
|
|
||||||
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
{
|
{
|
||||||
if (scopedBeatmapSet.Value != null && e.Action == GlobalAction.Back && !e.Repeat)
|
if (ScopedBeatmapSet.Value != null && e.Action == GlobalAction.Back && !e.Repeat)
|
||||||
{
|
{
|
||||||
TriggerClick();
|
TriggerClick();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
|
|
||||||
private const float corner_radius = 10;
|
private const float corner_radius = 10;
|
||||||
|
|
||||||
public Bindable<BeatmapSetInfo?> ScopedBeatmapSet { get; } = new Bindable<BeatmapSetInfo?>();
|
public IBindable<BeatmapSetInfo?> ScopedBeatmapSet { get; } = new Bindable<BeatmapSetInfo?>();
|
||||||
|
|
||||||
private SongSelectSearchTextBox searchTextBox = null!;
|
private SongSelectSearchTextBox searchTextBox = null!;
|
||||||
private ShearedToggleButton showConvertedBeatmapsButton = null!;
|
private ShearedToggleButton showConvertedBeatmapsButton = null!;
|
||||||
@@ -57,6 +57,9 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private Ez2ConfigManager ezConfig { get; set; } = null!;
|
private Ez2ConfigManager ezConfig { get; set; } = null!;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ISongSelect? songSelect { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
|
private IBindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||||
|
|
||||||
@@ -124,7 +127,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
HoldFocus = true,
|
HoldFocus = true,
|
||||||
ScopedBeatmapSet = ScopedBeatmapSet,
|
ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
new GridContainer
|
new GridContainer
|
||||||
@@ -246,7 +249,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
},
|
},
|
||||||
new ScopedBeatmapSetDisplay
|
new ScopedBeatmapSetDisplay
|
||||||
{
|
{
|
||||||
ScopedBeatmapSet = ScopedBeatmapSet,
|
ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet },
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -413,7 +416,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
{
|
{
|
||||||
if (clearScopedSet && ScopedBeatmapSet.Value != null)
|
if (clearScopedSet && ScopedBeatmapSet.Value != null)
|
||||||
{
|
{
|
||||||
ScopedBeatmapSet.Value = null;
|
songSelect?.UnscopeBeatmapSet();
|
||||||
// because `ScopedBeatmapSet` has a value change callback bound to it that calls `updateCriteria()` again,
|
// because `ScopedBeatmapSet` has a value change callback bound to it that calls `updateCriteria()` again,
|
||||||
// we can just do nothing other than clear it to avoid extra work and duplicated `CriteriaChanged` invocations
|
// we can just do nothing other than clear it to avoid extra work and duplicated `CriteriaChanged` invocations
|
||||||
return;
|
return;
|
||||||
@@ -446,34 +449,22 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
|
|
||||||
internal partial class SongSelectSearchTextBox : ShearedFilterTextBox
|
internal partial class SongSelectSearchTextBox : ShearedFilterTextBox
|
||||||
{
|
{
|
||||||
public Bindable<BeatmapSetInfo?> ScopedBeatmapSet
|
public IBindable<BeatmapSetInfo?> ScopedBeatmapSet { get; } = new Bindable<BeatmapSetInfo?>();
|
||||||
{
|
|
||||||
get => scopedBeatmapSet.Current;
|
|
||||||
set => scopedBeatmapSet.Current = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly BindableWithCurrent<BeatmapSetInfo?> scopedBeatmapSet = new BindableWithCurrent<BeatmapSetInfo?>();
|
|
||||||
|
|
||||||
protected override InnerSearchTextBox CreateInnerTextBox() => new InnerTextBox
|
protected override InnerSearchTextBox CreateInnerTextBox() => new InnerTextBox
|
||||||
{
|
{
|
||||||
ScopedBeatmapSet = ScopedBeatmapSet,
|
ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet },
|
||||||
};
|
};
|
||||||
|
|
||||||
private partial class InnerTextBox : InnerFilterTextBox
|
private partial class InnerTextBox : InnerFilterTextBox
|
||||||
{
|
{
|
||||||
public Bindable<BeatmapSetInfo?> ScopedBeatmapSet
|
public IBindable<BeatmapSetInfo?> ScopedBeatmapSet { get; } = new Bindable<BeatmapSetInfo?>();
|
||||||
{
|
|
||||||
get => scopedBeatmapSet.Current;
|
|
||||||
set => scopedBeatmapSet.Current = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly BindableWithCurrent<BeatmapSetInfo?> scopedBeatmapSet = new BindableWithCurrent<BeatmapSetInfo?>();
|
|
||||||
|
|
||||||
public override bool HandleLeftRightArrows => false;
|
public override bool HandleLeftRightArrows => false;
|
||||||
|
|
||||||
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||||
{
|
{
|
||||||
if (e.Action == GlobalAction.Back && scopedBeatmapSet.Value != null)
|
if (e.Action == GlobalAction.Back && ScopedBeatmapSet.Value != null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return base.OnPressed(e);
|
return base.OnPressed(e);
|
||||||
|
|||||||
@@ -48,8 +48,21 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
IEnumerable<OsuMenuItem> GetForwardActions(BeatmapInfo beatmap);
|
IEnumerable<OsuMenuItem> GetForwardActions(BeatmapInfo beatmap);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set this to a non-<see langword="null"/> value in order to temporarily bypass filter and show all difficulties of the given beatmap set.
|
/// Temporarily bypasses filters and shows all difficulties of the given beatmapset.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Bindable<BeatmapSetInfo?> ScopedBeatmapSet { get; }
|
/// <param name="beatmapSet">The beatmapset.</param>
|
||||||
|
void ScopeToBeatmapSet(BeatmapSetInfo beatmapSet);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the beatmapset scope and reverts the previously selected filters.
|
||||||
|
/// </summary>
|
||||||
|
void UnscopeBeatmapSet();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the currently scoped beatmapset. Used by external consumers for displaying its state.
|
||||||
|
/// Cannot be used to change the value, any changes must be done through <see cref="ScopeToBeatmapSet"/>
|
||||||
|
/// or <see cref="UnscopeBeatmapSet"/>.
|
||||||
|
/// </summary>
|
||||||
|
IBindable<BeatmapSetInfo?> ScopedBeatmapSet { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,11 +34,14 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
|
|
||||||
protected override Colour4 DimColour => Colour4.White;
|
protected override Colour4 DimColour => Colour4.White;
|
||||||
|
|
||||||
private readonly Bindable<BeatmapSetInfo?> scopedBeatmapSet = new Bindable<BeatmapSetInfo?>();
|
private readonly IBindable<BeatmapSetInfo?> scopedBeatmapSet = new Bindable<BeatmapSetInfo?>();
|
||||||
private readonly Bindable<bool> showConvertedBeatmaps = new Bindable<bool>();
|
private readonly Bindable<bool> showConvertedBeatmaps = new Bindable<bool>();
|
||||||
|
|
||||||
private const double transition_duration = 200;
|
private const double transition_duration = 200;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ISongSelect? songSelect { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private Bindable<RulesetInfo> ruleset { get; set; } = null!;
|
private Bindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISongSelect? songSelect, OsuConfigManager configManager)
|
private void load(OsuConfigManager configManager)
|
||||||
{
|
{
|
||||||
Add(new FillFlowContainer
|
Add(new FillFlowContainer
|
||||||
{
|
{
|
||||||
@@ -201,7 +204,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Action = () => scopedBeatmapSet.Value = BeatmapSet.Value;
|
Action = () => songSelect?.ScopeToBeatmapSet(BeatmapSet.Value);
|
||||||
updateEnabled();
|
updateEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,11 +29,14 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
|
|
||||||
protected override Colour4 DimColour => Colour4.White;
|
protected override Colour4 DimColour => Colour4.White;
|
||||||
|
|
||||||
private readonly Bindable<BeatmapSetInfo?> scopedBeatmapSet = new Bindable<BeatmapSetInfo?>();
|
private readonly IBindable<BeatmapSetInfo?> scopedBeatmapSet = new Bindable<BeatmapSetInfo?>();
|
||||||
private readonly Bindable<bool> showConvertedBeatmaps = new Bindable<bool>();
|
private readonly Bindable<bool> showConvertedBeatmaps = new Bindable<bool>();
|
||||||
|
|
||||||
private const double transition_duration = 200;
|
private const double transition_duration = 200;
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private ISongSelect? songSelect { get; set; }
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private Bindable<RulesetInfo> ruleset { get; set; } = null!;
|
private Bindable<RulesetInfo> ruleset { get; set; } = null!;
|
||||||
|
|
||||||
@@ -56,12 +59,12 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
Action = () =>
|
Action = () =>
|
||||||
{
|
{
|
||||||
if (Beatmap.Value != null)
|
if (Beatmap.Value != null)
|
||||||
scopedBeatmapSet.Value = Beatmap.Value.BeatmapSet!;
|
songSelect?.ScopeToBeatmapSet(Beatmap.Value.BeatmapSet!);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(ISongSelect? songSelect, OsuConfigManager configManager)
|
private void load(OsuConfigManager configManager)
|
||||||
{
|
{
|
||||||
Add(new FillFlowContainer
|
Add(new FillFlowContainer
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -288,6 +288,7 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
|
ScopedBeatmapSet = { BindTarget = ScopedBeatmapSet },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1266,7 +1267,29 @@ namespace osu.Game.Screens.SelectV2
|
|||||||
beatmaps.Restore(b);
|
beatmaps.Restore(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bindable<BeatmapSetInfo?> ScopedBeatmapSet => filterControl.ScopedBeatmapSet;
|
private GroupedBeatmap? beforeScopedSelection;
|
||||||
|
|
||||||
|
private readonly Bindable<BeatmapSetInfo?> scopedBeatmapSet = new Bindable<BeatmapSetInfo?>();
|
||||||
|
public IBindable<BeatmapSetInfo?> ScopedBeatmapSet => scopedBeatmapSet;
|
||||||
|
|
||||||
|
public void ScopeToBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||||
|
{
|
||||||
|
beforeScopedSelection = carousel.CurrentGroupedBeatmap;
|
||||||
|
|
||||||
|
scopedBeatmapSet.Value = beatmapSet;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnscopeBeatmapSet()
|
||||||
|
{
|
||||||
|
if (scopedBeatmapSet.Value == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (beforeScopedSelection != null)
|
||||||
|
queueBeatmapSelection(beforeScopedSelection);
|
||||||
|
|
||||||
|
scopedBeatmapSet.Value = null;
|
||||||
|
beforeScopedSelection = null;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user