mirror of
https://github.com/ppy/osu.git
synced 2024-11-11 11:37:28 +08:00
Merge branch 'master' into editor-test-play-dont-retain-test-time
This commit is contained in:
commit
c05c1625f2
@ -134,7 +134,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddAssert("player score matching expected bonus score", () =>
|
AddAssert("player score matching expected bonus score", () =>
|
||||||
{
|
{
|
||||||
// multipled by 2 to nullify the score multiplier. (autoplay mod selected)
|
// multipled by 2 to nullify the score multiplier. (autoplay mod selected)
|
||||||
double totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value * 2;
|
long totalScore = ((ScoreExposedPlayer)Player).ScoreProcessor.TotalScore.Value * 2;
|
||||||
return totalScore == (int)(drawableSpinner.Result.RateAdjustedRotation / 360) * new SpinnerTick().CreateJudgement().MaxNumericResult;
|
return totalScore == (int)(drawableSpinner.Result.RateAdjustedRotation / 360) * new SpinnerTick().CreateJudgement().MaxNumericResult;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -248,6 +248,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
slider.Path.ExpectedDistance.Value = null;
|
||||||
piece.ControlPoint.Type = type;
|
piece.ControlPoint.Type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,39 @@
|
|||||||
|
// 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 NUnit.Framework;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Game.Beatmaps;
|
||||||
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects;
|
||||||
|
using osu.Game.Rulesets.Taiko.Objects.Drawables;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Tests.Skinning
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class TestSceneDrawableSwell : TaikoSkinnableTestScene
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void TestHits()
|
||||||
|
{
|
||||||
|
AddStep("Centre hit", () => SetContents(_ => new DrawableSwell(createHitAtCurrentTime())
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Swell createHitAtCurrentTime()
|
||||||
|
{
|
||||||
|
var hit = new Swell
|
||||||
|
{
|
||||||
|
StartTime = Time.Current + 3000,
|
||||||
|
EndTime = Time.Current + 6000,
|
||||||
|
};
|
||||||
|
|
||||||
|
hit.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
|
||||||
|
|
||||||
|
return hit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
// 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 osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Colour;
|
||||||
|
using osu.Framework.Graphics.Sprites;
|
||||||
|
using osuTK;
|
||||||
|
using osuTK.Graphics;
|
||||||
|
|
||||||
|
namespace osu.Game.Rulesets.Taiko.Skinning.Argon
|
||||||
|
{
|
||||||
|
public class ArgonSwellCirclePiece : ArgonCirclePiece
|
||||||
|
{
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
AccentColour = ColourInfo.GradientVertical(
|
||||||
|
new Color4(240, 201, 0, 255),
|
||||||
|
new Color4(167, 139, 0, 255)
|
||||||
|
);
|
||||||
|
|
||||||
|
AddInternal(new SpriteIcon
|
||||||
|
{
|
||||||
|
Anchor = Anchor.Centre,
|
||||||
|
Origin = Anchor.Centre,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Icon = FontAwesome.Solid.Asterisk,
|
||||||
|
Size = new Vector2(ICON_SIZE),
|
||||||
|
Scale = new Vector2(0.8f, 1)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -60,6 +60,9 @@ namespace osu.Game.Rulesets.Taiko.Skinning.Argon
|
|||||||
case TaikoSkinComponents.TaikoExplosionMiss:
|
case TaikoSkinComponents.TaikoExplosionMiss:
|
||||||
case TaikoSkinComponents.TaikoExplosionOk:
|
case TaikoSkinComponents.TaikoExplosionOk:
|
||||||
return new ArgonHitExplosion(taikoComponent.Component);
|
return new ArgonHitExplosion(taikoComponent.Component);
|
||||||
|
|
||||||
|
case TaikoSkinComponents.Swell:
|
||||||
|
return new ArgonSwellCirclePiece();
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -65,7 +65,7 @@ namespace osu.Game.Tests.Database
|
|||||||
private class TestLegacyBeatmapImporter : LegacyBeatmapImporter
|
private class TestLegacyBeatmapImporter : LegacyBeatmapImporter
|
||||||
{
|
{
|
||||||
public TestLegacyBeatmapImporter()
|
public TestLegacyBeatmapImporter()
|
||||||
: base(null)
|
: base(null!)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ namespace osu.Game.Tests.Gameplay
|
|||||||
// Apply a miss judgement
|
// Apply a miss judgement
|
||||||
scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new TestJudgement()) { Type = HitResult.Miss });
|
scoreProcessor.ApplyResult(new JudgementResult(new HitObject(), new TestJudgement()) { Type = HitResult.Miss });
|
||||||
|
|
||||||
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0.0));
|
Assert.That(scoreProcessor.TotalScore.Value, Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
{
|
{
|
||||||
private TestGameplayLeaderboard leaderboard;
|
private TestGameplayLeaderboard leaderboard;
|
||||||
|
|
||||||
private readonly BindableDouble playerScore = new BindableDouble();
|
private readonly BindableLong playerScore = new BindableLong();
|
||||||
|
|
||||||
public TestSceneGameplayLeaderboard()
|
public TestSceneGameplayLeaderboard()
|
||||||
{
|
{
|
||||||
@ -76,8 +76,8 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
createLeaderboard();
|
createLeaderboard();
|
||||||
addLocalPlayer();
|
addLocalPlayer();
|
||||||
|
|
||||||
var player2Score = new BindableDouble(1234567);
|
var player2Score = new BindableLong(1234567);
|
||||||
var player3Score = new BindableDouble(1111111);
|
var player3Score = new BindableLong(1111111);
|
||||||
|
|
||||||
AddStep("add player 2", () => createLeaderboardScore(player2Score, new APIUser { Username = "Player 2" }));
|
AddStep("add player 2", () => createLeaderboardScore(player2Score, new APIUser { Username = "Player 2" }));
|
||||||
AddStep("add player 3", () => createLeaderboardScore(player3Score, new APIUser { Username = "Player 3" }));
|
AddStep("add player 3", () => createLeaderboardScore(player3Score, new APIUser { Username = "Player 3" }));
|
||||||
@ -161,9 +161,9 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createRandomScore(APIUser user) => createLeaderboardScore(new BindableDouble(RNG.Next(0, 5_000_000)), user);
|
private void createRandomScore(APIUser user) => createLeaderboardScore(new BindableLong(RNG.Next(0, 5_000_000)), user);
|
||||||
|
|
||||||
private void createLeaderboardScore(BindableDouble score, APIUser user, bool isTracked = false)
|
private void createLeaderboardScore(BindableLong score, APIUser user, bool isTracked = false)
|
||||||
{
|
{
|
||||||
var leaderboardScore = leaderboard.Add(user, isTracked);
|
var leaderboardScore = leaderboard.Add(user, isTracked);
|
||||||
leaderboardScore.TotalScore.BindTo(score);
|
leaderboardScore.TotalScore.BindTo(score);
|
||||||
|
@ -15,6 +15,7 @@ using osu.Game.Rulesets.Osu;
|
|||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
using osu.Game.Screens.Play.HUD;
|
using osu.Game.Screens.Play.HUD;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Gameplay
|
namespace osu.Game.Tests.Visual.Gameplay
|
||||||
{
|
{
|
||||||
@ -26,6 +27,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private readonly BindableList<ScoreInfo> scores = new BindableList<ScoreInfo>();
|
private readonly BindableList<ScoreInfo> scores = new BindableList<ScoreInfo>();
|
||||||
|
|
||||||
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
|
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
|
||||||
|
private readonly Bindable<PlayBeatmapDetailArea.TabType> beatmapTabType = new Bindable<PlayBeatmapDetailArea.TabType>();
|
||||||
|
|
||||||
private SoloGameplayLeaderboard leaderboard = null!;
|
private SoloGameplayLeaderboard leaderboard = null!;
|
||||||
|
|
||||||
@ -33,6 +35,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility);
|
config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility);
|
||||||
|
config.BindWith(OsuSetting.BeatmapDetailTab, beatmapTabType);
|
||||||
}
|
}
|
||||||
|
|
||||||
[SetUpSteps]
|
[SetUpSteps]
|
||||||
@ -70,6 +73,25 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value);
|
AddStep("toggle expanded", () => leaderboard.Expanded.Value = !leaderboard.Expanded.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[TestCase(PlayBeatmapDetailArea.TabType.Local, 51)]
|
||||||
|
[TestCase(PlayBeatmapDetailArea.TabType.Global, null)]
|
||||||
|
[TestCase(PlayBeatmapDetailArea.TabType.Country, null)]
|
||||||
|
[TestCase(PlayBeatmapDetailArea.TabType.Friends, null)]
|
||||||
|
public void TestTrackedScorePosition(PlayBeatmapDetailArea.TabType tabType, int? expectedOverflowIndex)
|
||||||
|
{
|
||||||
|
AddStep($"change TabType to {tabType}", () => beatmapTabType.Value = tabType);
|
||||||
|
AddUntilStep("tracked player is #50", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(50));
|
||||||
|
|
||||||
|
AddStep("add one more score", () => scores.Add(new ScoreInfo { User = new APIUser { Username = "New player 1" }, TotalScore = RNG.Next(600000, 1000000) }));
|
||||||
|
|
||||||
|
AddUntilStep("wait for sort", () => leaderboard.ChildrenOfType<GameplayLeaderboardScore>().First().ScorePosition != null);
|
||||||
|
|
||||||
|
if (expectedOverflowIndex == null)
|
||||||
|
AddUntilStep("tracked player has null position", () => leaderboard.TrackedScore?.ScorePosition, () => Is.Null);
|
||||||
|
else
|
||||||
|
AddUntilStep($"tracked player is #{expectedOverflowIndex}", () => leaderboard.TrackedScore?.ScorePosition, () => Is.EqualTo(expectedOverflowIndex));
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestVisibility()
|
public void TestVisibility()
|
||||||
{
|
{
|
||||||
@ -95,7 +117,7 @@ namespace osu.Game.Tests.Visual.Gameplay
|
|||||||
new ScoreInfo { User = new APIUser { Username = @"spaceman_atlas" }, TotalScore = RNG.Next(500000, 1000000) },
|
new ScoreInfo { User = new APIUser { Username = @"spaceman_atlas" }, TotalScore = RNG.Next(500000, 1000000) },
|
||||||
new ScoreInfo { User = new APIUser { Username = @"frenzibyte" }, TotalScore = RNG.Next(500000, 1000000) },
|
new ScoreInfo { User = new APIUser { Username = @"frenzibyte" }, TotalScore = RNG.Next(500000, 1000000) },
|
||||||
new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) },
|
new ScoreInfo { User = new APIUser { Username = @"Susko3" }, TotalScore = RNG.Next(500000, 1000000) },
|
||||||
}.Concat(Enumerable.Range(0, 50).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList();
|
}.Concat(Enumerable.Range(0, 44).Select(i => new ScoreInfo { User = new APIUser { Username = $"User {i + 1}" }, TotalScore = 1000000 - i * 10000 })).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Extensions;
|
using osu.Framework.Extensions;
|
||||||
@ -85,6 +86,19 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
AddAssert("did perform", () => actionPerformed);
|
AddAssert("did perform", () => actionPerformed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestPerformEnsuresScreenIsLoaded()
|
||||||
|
{
|
||||||
|
TestLoadBlockingScreen screen = null;
|
||||||
|
|
||||||
|
AddStep("push blocking screen", () => Game.ScreenStack.Push(screen = new TestLoadBlockingScreen()));
|
||||||
|
AddStep("perform", () => Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(TestLoadBlockingScreen) }));
|
||||||
|
AddAssert("action not performed", () => !actionPerformed);
|
||||||
|
|
||||||
|
AddStep("allow load", () => screen.LoadEvent.Set());
|
||||||
|
AddUntilStep("action performed", () => actionPerformed);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestOverlaysAlwaysClosed()
|
public void TestOverlaysAlwaysClosed()
|
||||||
{
|
{
|
||||||
@ -270,5 +284,16 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
return base.OnExiting(e);
|
return base.OnExiting(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class TestLoadBlockingScreen : OsuScreen
|
||||||
|
{
|
||||||
|
public readonly ManualResetEventSlim LoadEvent = new ManualResetEventSlim();
|
||||||
|
|
||||||
|
[BackgroundDependencyLoader]
|
||||||
|
private void load()
|
||||||
|
{
|
||||||
|
LoadEvent.Wait(10000);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,14 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Extensions;
|
using osu.Game.Extensions;
|
||||||
using osu.Game.Rulesets;
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Rulesets.Mania;
|
using osu.Game.Rulesets.Mania;
|
||||||
using osu.Game.Rulesets.Osu;
|
using osu.Game.Rulesets.Osu;
|
||||||
using osu.Game.Screens.Menu;
|
using osu.Game.Screens.Menu;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Navigation
|
namespace osu.Game.Tests.Visual.Navigation
|
||||||
{
|
{
|
||||||
@ -55,6 +57,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
presentAndConfirm(firstImport);
|
presentAndConfirm(firstImport);
|
||||||
|
|
||||||
var secondImport = importBeatmap(3);
|
var secondImport = importBeatmap(3);
|
||||||
|
confirmBeatmapInSongSelect(secondImport);
|
||||||
presentAndConfirm(secondImport);
|
presentAndConfirm(secondImport);
|
||||||
|
|
||||||
// Test presenting same beatmap more than once
|
// Test presenting same beatmap more than once
|
||||||
@ -74,6 +77,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
presentAndConfirm(firstImport);
|
presentAndConfirm(firstImport);
|
||||||
|
|
||||||
var secondImport = importBeatmap(3, new ManiaRuleset().RulesetInfo);
|
var secondImport = importBeatmap(3, new ManiaRuleset().RulesetInfo);
|
||||||
|
confirmBeatmapInSongSelect(secondImport);
|
||||||
presentAndConfirm(secondImport);
|
presentAndConfirm(secondImport);
|
||||||
|
|
||||||
presentSecondDifficultyAndConfirm(firstImport, 1);
|
presentSecondDifficultyAndConfirm(firstImport, 1);
|
||||||
@ -134,13 +138,22 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
return () => imported;
|
return () => imported;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void confirmBeatmapInSongSelect(Func<BeatmapSetInfo> getImport)
|
||||||
|
{
|
||||||
|
AddUntilStep("beatmap in song select", () =>
|
||||||
|
{
|
||||||
|
var songSelect = (Screens.Select.SongSelect)Game.ScreenStack.CurrentScreen;
|
||||||
|
return songSelect.ChildrenOfType<BeatmapCarousel>().Single().BeatmapSets.Any(b => b.MatchesOnlineID(getImport()));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void presentAndConfirm(Func<BeatmapSetInfo> getImport)
|
private void presentAndConfirm(Func<BeatmapSetInfo> getImport)
|
||||||
{
|
{
|
||||||
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
AddStep("present beatmap", () => Game.PresentBeatmap(getImport()));
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect songSelect && songSelect.IsLoaded);
|
||||||
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.MatchesOnlineID(getImport()));
|
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapSetInfo.OnlineID, () => Is.EqualTo(getImport().OnlineID));
|
||||||
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Beatmaps.First().Ruleset));
|
AddAssert("correct ruleset selected", () => Game.Ruleset.Value, () => Is.EqualTo(getImport().Beatmaps.First().Ruleset));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void presentSecondDifficultyAndConfirm(Func<BeatmapSetInfo> getImport, int importedID)
|
private void presentSecondDifficultyAndConfirm(Func<BeatmapSetInfo> getImport, int importedID)
|
||||||
@ -148,9 +161,9 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
Predicate<BeatmapInfo> pred = b => b.OnlineID == importedID * 2048;
|
Predicate<BeatmapInfo> pred = b => b.OnlineID == importedID * 2048;
|
||||||
AddStep("present difficulty", () => Game.PresentBeatmap(getImport(), pred));
|
AddStep("present difficulty", () => Game.PresentBeatmap(getImport(), pred));
|
||||||
|
|
||||||
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect);
|
AddUntilStep("wait for song select", () => Game.ScreenStack.CurrentScreen is Screens.Select.SongSelect songSelect && songSelect.IsLoaded);
|
||||||
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID == importedID * 2048);
|
AddUntilStep("correct beatmap displayed", () => Game.Beatmap.Value.BeatmapInfo.OnlineID, () => Is.EqualTo(importedID * 2048));
|
||||||
AddAssert("correct ruleset selected", () => Game.Ruleset.Value.Equals(getImport().Beatmaps.First().Ruleset));
|
AddAssert("correct ruleset selected", () => Game.Ruleset.Value, () => Is.EqualTo(getImport().Beatmaps.First().Ruleset));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -436,6 +436,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
|||||||
{
|
{
|
||||||
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
|
AddUntilStep("Wait for toolbar to load", () => Game.Toolbar.IsLoaded);
|
||||||
|
|
||||||
|
AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
|
||||||
|
|
||||||
TestPlaySongSelect songSelect = null;
|
TestPlaySongSelect songSelect = null;
|
||||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||||
|
|
||||||
|
@ -40,6 +40,43 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
AddWaitStep("wait for scroll", 5);
|
AddWaitStep("wait for scroll", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBindingTwoNonModifiers()
|
||||||
|
{
|
||||||
|
AddStep("press j", () => InputManager.PressKey(Key.J));
|
||||||
|
scrollToAndStartBinding("Increase volume");
|
||||||
|
AddStep("press k", () => InputManager.Key(Key.K));
|
||||||
|
AddStep("release j", () => InputManager.ReleaseKey(Key.J));
|
||||||
|
checkBinding("Increase volume", "K");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBindingSingleKey()
|
||||||
|
{
|
||||||
|
scrollToAndStartBinding("Increase volume");
|
||||||
|
AddStep("press k", () => InputManager.Key(Key.K));
|
||||||
|
checkBinding("Increase volume", "K");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBindingSingleModifier()
|
||||||
|
{
|
||||||
|
scrollToAndStartBinding("Increase volume");
|
||||||
|
AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft));
|
||||||
|
AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft));
|
||||||
|
checkBinding("Increase volume", "LShift");
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBindingSingleKeyWithModifier()
|
||||||
|
{
|
||||||
|
scrollToAndStartBinding("Increase volume");
|
||||||
|
AddStep("press shift", () => InputManager.PressKey(Key.ShiftLeft));
|
||||||
|
AddStep("press k", () => InputManager.Key(Key.K));
|
||||||
|
AddStep("release shift", () => InputManager.ReleaseKey(Key.ShiftLeft));
|
||||||
|
checkBinding("Increase volume", "LShift-K");
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestBindingMouseWheelToNonGameplay()
|
public void TestBindingMouseWheelToNonGameplay()
|
||||||
{
|
{
|
||||||
@ -169,7 +206,8 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
|
|
||||||
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha == 0);
|
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha == 0);
|
||||||
|
|
||||||
AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
|
AddAssert("binding cleared",
|
||||||
|
() => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -198,7 +236,8 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
|
|
||||||
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha == 0);
|
AddUntilStep("restore button hidden", () => settingsKeyBindingRow.ChildrenOfType<RestoreDefaultValueButton<bool>>().First().Alpha == 0);
|
||||||
|
|
||||||
AddAssert("binding cleared", () => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
|
AddAssert("binding cleared",
|
||||||
|
() => settingsKeyBindingRow.ChildrenOfType<KeyBindingRow.KeyButton>().ElementAt(0).KeyBinding.KeyCombination.Equals(settingsKeyBindingRow.Defaults.ElementAt(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -256,8 +295,8 @@ namespace osu.Game.Tests.Visual.Settings
|
|||||||
var firstRow = panel.ChildrenOfType<KeyBindingRow>().First(r => r.ChildrenOfType<OsuSpriteText>().Any(s => s.Text.ToString() == name));
|
var firstRow = panel.ChildrenOfType<KeyBindingRow>().First(r => r.ChildrenOfType<OsuSpriteText>().Any(s => s.Text.ToString() == name));
|
||||||
var firstButton = firstRow.ChildrenOfType<KeyBindingRow.KeyButton>().First();
|
var firstButton = firstRow.ChildrenOfType<KeyBindingRow.KeyButton>().First();
|
||||||
|
|
||||||
return firstButton.Text.Text == keyName;
|
return firstButton.Text.Text.ToString();
|
||||||
});
|
}, () => Is.EqualTo(keyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollToAndStartBinding(string name)
|
private void scrollToAndStartBinding(string name)
|
||||||
|
@ -1055,6 +1055,18 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
AddUntilStep("mod overlay hidden", () => songSelect!.ModSelect.State.Value == Visibility.Hidden);
|
AddUntilStep("mod overlay hidden", () => songSelect!.ModSelect.State.Value == Visibility.Hidden);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestBeatmapOptionsDisabled()
|
||||||
|
{
|
||||||
|
createSongSelect();
|
||||||
|
|
||||||
|
addRulesetImportStep(0);
|
||||||
|
|
||||||
|
AddAssert("options enabled", () => songSelect.ChildrenOfType<FooterButtonOptions>().Single().Enabled.Value);
|
||||||
|
AddStep("delete all beatmaps", () => manager.Delete());
|
||||||
|
AddAssert("options disabled", () => !songSelect.ChildrenOfType<FooterButtonOptions>().Single().Enabled.Value);
|
||||||
|
}
|
||||||
|
|
||||||
private void waitForInitialSelection()
|
private void waitForInitialSelection()
|
||||||
{
|
{
|
||||||
AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
|
AddUntilStep("wait for initial selection", () => !Beatmap.IsDefault);
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Testing;
|
||||||
using osu.Game.Screens.Select;
|
using osu.Game.Screens.Select;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
@ -43,6 +45,12 @@ namespace osu.Game.Tests.Visual.SongSelect
|
|||||||
InputManager.MoveMouseTo(Vector2.Zero);
|
InputManager.MoveMouseTo(Vector2.Zero);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestState()
|
||||||
|
{
|
||||||
|
AddRepeatStep("toggle options state", () => this.ChildrenOfType<FooterButton>().Last().Enabled.Toggle(), 20);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestFooterRandom()
|
public void TestFooterRandom()
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
#nullable disable
|
using System;
|
||||||
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using osu.Framework.IO.Stores;
|
using osu.Framework.IO.Stores;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
@ -22,22 +22,42 @@ namespace osu.Game.Database
|
|||||||
{
|
{
|
||||||
// make sure the directory exists
|
// make sure the directory exists
|
||||||
if (!storage.ExistsDirectory(string.Empty))
|
if (!storage.ExistsDirectory(string.Empty))
|
||||||
yield break;
|
return Array.Empty<string>();
|
||||||
|
|
||||||
foreach (string directory in storage.GetDirectories(string.Empty))
|
List<string> paths = new List<string>();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
var directoryStorage = storage.GetStorageForDirectory(directory);
|
foreach (string directory in storage.GetDirectories(string.Empty))
|
||||||
|
|
||||||
if (!directoryStorage.GetFiles(string.Empty).ExcludeSystemFileNames().Any())
|
|
||||||
{
|
{
|
||||||
// if a directory doesn't contain files, attempt looking for beatmaps inside of that directory.
|
var directoryStorage = storage.GetStorageForDirectory(directory);
|
||||||
// this is a special behaviour in stable for beatmaps only, see https://github.com/ppy/osu/issues/18615.
|
|
||||||
foreach (string subDirectory in GetStableImportPaths(directoryStorage))
|
try
|
||||||
yield return subDirectory;
|
{
|
||||||
|
if (!directoryStorage.GetFiles(string.Empty).ExcludeSystemFileNames().Any())
|
||||||
|
{
|
||||||
|
// if a directory doesn't contain files, attempt looking for beatmaps inside of that directory.
|
||||||
|
// this is a special behaviour in stable for beatmaps only, see https://github.com/ppy/osu/issues/18615.
|
||||||
|
foreach (string subDirectory in GetStableImportPaths(directoryStorage))
|
||||||
|
paths.Add(subDirectory);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
paths.Add(storage.GetFullPath(directory));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Catch any errors when enumerating files
|
||||||
|
Logger.Log($"Error when enumerating files in {directoryStorage.GetFullPath(string.Empty)}: {e}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
yield return storage.GetFullPath(directory);
|
|
||||||
}
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
// Catch any errors when enumerating directories
|
||||||
|
Logger.Log($"Error when enumerating directories in {storage.GetFullPath(string.Empty)}: {e}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return paths;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LegacyBeatmapImporter(IModelImporter<BeatmapSetInfo> importer)
|
public LegacyBeatmapImporter(IModelImporter<BeatmapSetInfo> importer)
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Extensions.Color4Extensions;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
@ -69,6 +70,8 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
protected Box Background;
|
protected Box Background;
|
||||||
protected SpriteText SpriteText;
|
protected SpriteText SpriteText;
|
||||||
|
|
||||||
|
private readonly Box flashLayer;
|
||||||
|
|
||||||
public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button)
|
public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button)
|
||||||
{
|
{
|
||||||
Height = 40;
|
Height = 40;
|
||||||
@ -99,6 +102,14 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
Depth = float.MinValue
|
Depth = float.MinValue
|
||||||
},
|
},
|
||||||
SpriteText = CreateText(),
|
SpriteText = CreateText(),
|
||||||
|
flashLayer = new Box
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Blending = BlendingParameters.Additive,
|
||||||
|
Depth = float.MinValue,
|
||||||
|
Colour = Color4.White.Opacity(0.5f),
|
||||||
|
Alpha = 0,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -125,7 +136,7 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
if (Enabled.Value)
|
if (Enabled.Value)
|
||||||
Background.FlashColour(Color4.White, 800, Easing.OutQuint);
|
flashLayer.FadeOutFromOne(800, Easing.OutQuint);
|
||||||
|
|
||||||
return base.OnClick(e);
|
return base.OnClick(e);
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ using osu.Game.Graphics.Sprites;
|
|||||||
|
|
||||||
namespace osu.Game.Graphics.UserInterface
|
namespace osu.Game.Graphics.UserInterface
|
||||||
{
|
{
|
||||||
public abstract class ScoreCounter : RollingCounter<double>
|
public abstract class ScoreCounter : RollingCounter<long>
|
||||||
{
|
{
|
||||||
protected override double RollingDuration => 1000;
|
protected override double RollingDuration => 1000;
|
||||||
protected override Easing RollingEasing => Easing.Out;
|
protected override Easing RollingEasing => Easing.Out;
|
||||||
@ -36,10 +36,10 @@ namespace osu.Game.Graphics.UserInterface
|
|||||||
UpdateDisplay();
|
UpdateDisplay();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override double GetProportionalDuration(double currentValue, double newValue) =>
|
protected override double GetProportionalDuration(long currentValue, long newValue) =>
|
||||||
currentValue > newValue ? currentValue - newValue : newValue - currentValue;
|
currentValue > newValue ? currentValue - newValue : newValue - currentValue;
|
||||||
|
|
||||||
protected override LocalisableString FormatCount(double count) => ((long)count).ToLocalisableString(formatString);
|
protected override LocalisableString FormatCount(long count) => count.ToLocalisableString(formatString);
|
||||||
|
|
||||||
protected override OsuSpriteText CreateSpriteText()
|
protected override OsuSpriteText CreateSpriteText()
|
||||||
=> base.CreateSpriteText().With(s => s.Font = s.Font.With(fixedWidth: true));
|
=> base.CreateSpriteText().With(s => s.Font = s.Font.With(fixedWidth: true));
|
||||||
|
@ -419,7 +419,7 @@ namespace osu.Game.Online.API
|
|||||||
failureCount++;
|
failureCount++;
|
||||||
log.Add($@"API failure count is now {failureCount}");
|
log.Add($@"API failure count is now {failureCount}");
|
||||||
|
|
||||||
if (failureCount >= 3 && State.Value == APIState.Online)
|
if (failureCount >= 3)
|
||||||
{
|
{
|
||||||
state.Value = APIState.Failing;
|
state.Value = APIState.Failing;
|
||||||
flushQueue();
|
flushQueue();
|
||||||
|
@ -16,6 +16,8 @@ namespace osu.Game.Online.API.Requests
|
|||||||
{
|
{
|
||||||
public class GetScoresRequest : APIRequest<APIScoresCollection>
|
public class GetScoresRequest : APIRequest<APIScoresCollection>
|
||||||
{
|
{
|
||||||
|
public const int MAX_SCORES_PER_REQUEST = 50;
|
||||||
|
|
||||||
private readonly IBeatmapInfo beatmapInfo;
|
private readonly IBeatmapInfo beatmapInfo;
|
||||||
private readonly BeatmapLeaderboardScope scope;
|
private readonly BeatmapLeaderboardScope scope;
|
||||||
private readonly IRulesetInfo ruleset;
|
private readonly IRulesetInfo ruleset;
|
||||||
|
@ -31,7 +31,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
public bool Passed { get; set; }
|
public bool Passed { get; set; }
|
||||||
|
|
||||||
[JsonProperty("total_score")]
|
[JsonProperty("total_score")]
|
||||||
public int TotalScore { get; set; }
|
public long TotalScore { get; set; }
|
||||||
|
|
||||||
[JsonProperty("accuracy")]
|
[JsonProperty("accuracy")]
|
||||||
public double Accuracy { get; set; }
|
public double Accuracy { get; set; }
|
||||||
@ -213,7 +213,7 @@ namespace osu.Game.Online.API.Requests.Responses
|
|||||||
public static SoloScoreInfo ForSubmission(ScoreInfo score) => new SoloScoreInfo
|
public static SoloScoreInfo ForSubmission(ScoreInfo score) => new SoloScoreInfo
|
||||||
{
|
{
|
||||||
Rank = score.Rank,
|
Rank = score.Rank,
|
||||||
TotalScore = (int)score.TotalScore,
|
TotalScore = score.TotalScore,
|
||||||
Accuracy = score.Accuracy,
|
Accuracy = score.Accuracy,
|
||||||
PP = score.PP,
|
PP = score.PP,
|
||||||
MaxCombo = score.MaxCombo,
|
MaxCombo = score.MaxCombo,
|
||||||
|
@ -7,6 +7,7 @@ using System.Diagnostics;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Development;
|
using osu.Framework.Development;
|
||||||
@ -727,13 +728,20 @@ namespace osu.Game.Online.Multiplayer
|
|||||||
if (Room == null)
|
if (Room == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Debug.Assert(APIRoom != null);
|
try
|
||||||
|
{
|
||||||
|
Debug.Assert(APIRoom != null);
|
||||||
|
|
||||||
Room.Playlist[Room.Playlist.IndexOf(Room.Playlist.Single(existing => existing.ID == item.ID))] = item;
|
Room.Playlist[Room.Playlist.IndexOf(Room.Playlist.Single(existing => existing.ID == item.ID))] = item;
|
||||||
|
|
||||||
int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID));
|
int existingIndex = APIRoom.Playlist.IndexOf(APIRoom.Playlist.Single(existing => existing.ID == item.ID));
|
||||||
APIRoom.Playlist.RemoveAt(existingIndex);
|
APIRoom.Playlist.RemoveAt(existingIndex);
|
||||||
APIRoom.Playlist.Insert(existingIndex, createPlaylistItem(item));
|
APIRoom.Playlist.Insert(existingIndex, createPlaylistItem(item));
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
throw new AggregateException($"Item: {JsonConvert.SerializeObject(createPlaylistItem(item))}\n\nRoom:{JsonConvert.SerializeObject(APIRoom)}", ex);
|
||||||
|
}
|
||||||
|
|
||||||
ItemChanged?.Invoke(item);
|
ItemChanged?.Invoke(item);
|
||||||
RoomUpdated?.Invoke();
|
RoomUpdated?.Invoke();
|
||||||
|
@ -145,7 +145,9 @@ namespace osu.Game.Online
|
|||||||
|
|
||||||
private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken)
|
private async Task onConnectionClosed(Exception? ex, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
isConnected.Value = false;
|
bool hasBeenCancelled = cancellationToken.IsCancellationRequested;
|
||||||
|
|
||||||
|
await disconnect(true);
|
||||||
|
|
||||||
if (ex != null)
|
if (ex != null)
|
||||||
await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false);
|
await handleErrorAndDelay(ex, cancellationToken).ConfigureAwait(false);
|
||||||
@ -153,7 +155,7 @@ namespace osu.Game.Online
|
|||||||
Logger.Log($"{ClientName} disconnected", LoggingTarget.Network);
|
Logger.Log($"{ClientName} disconnected", LoggingTarget.Network);
|
||||||
|
|
||||||
// make sure a disconnect wasn't triggered (and this is still the active connection).
|
// make sure a disconnect wasn't triggered (and this is still the active connection).
|
||||||
if (!cancellationToken.IsCancellationRequested)
|
if (!hasBeenCancelled)
|
||||||
await Task.Run(connect, default).ConfigureAwait(false);
|
await Task.Run(connect, default).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -174,7 +176,9 @@ namespace osu.Game.Online
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
isConnected.Value = false;
|
||||||
CurrentConnection = null;
|
CurrentConnection = null;
|
||||||
|
|
||||||
if (takeLock)
|
if (takeLock)
|
||||||
connectionLock.Release();
|
connectionLock.Release();
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ namespace osu.Game.Online.Rooms
|
|||||||
/// The total scores in the playlist item.
|
/// The total scores in the playlist item.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[JsonProperty("total")]
|
[JsonProperty("total")]
|
||||||
public int? TotalScores { get; set; }
|
public long? TotalScores { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The user's score, if any.
|
/// The user's score, if any.
|
||||||
|
@ -26,7 +26,7 @@ namespace osu.Game.Online.Spectator
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current total score.
|
/// The current total score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble TotalScore = new BindableDouble { MinValue = 0 };
|
public readonly BindableLong TotalScore = new BindableLong { MinValue = 0 };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current accuracy.
|
/// The current accuracy.
|
||||||
|
@ -41,11 +41,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
private IBindable<APIUser> apiUser;
|
private IBindable<APIUser> apiUser;
|
||||||
|
|
||||||
private Drawable currentContent;
|
|
||||||
private Container panelTarget;
|
private Container panelTarget;
|
||||||
private FillFlowContainer<BeatmapCard> foundContent;
|
private FillFlowContainer<BeatmapCard> foundContent;
|
||||||
private NotFoundDrawable notFoundContent;
|
|
||||||
private SupporterRequiredDrawable supporterRequiredContent;
|
|
||||||
private BeatmapListingFilterControl filterControl;
|
private BeatmapListingFilterControl filterControl;
|
||||||
|
|
||||||
public BeatmapListingOverlay()
|
public BeatmapListingOverlay()
|
||||||
@ -86,11 +83,6 @@ namespace osu.Game.Overlays
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Masking = true,
|
Masking = true,
|
||||||
Padding = new MarginPadding { Horizontal = 20 },
|
Padding = new MarginPadding { Horizontal = 20 },
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
notFoundContent = new NotFoundDrawable(),
|
|
||||||
supporterRequiredContent = new SupporterRequiredDrawable(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -107,7 +99,7 @@ namespace osu.Game.Overlays
|
|||||||
apiUser.BindValueChanged(_ => Schedule(() =>
|
apiUser.BindValueChanged(_ => Schedule(() =>
|
||||||
{
|
{
|
||||||
if (api.IsLoggedIn)
|
if (api.IsLoggedIn)
|
||||||
addContentToResultsArea(Drawable.Empty());
|
replaceResultsAreaContent(Drawable.Empty());
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,8 +147,8 @@ namespace osu.Game.Overlays
|
|||||||
|
|
||||||
if (searchResult.Type == BeatmapListingFilterControl.SearchResultType.SupporterOnlyFilters)
|
if (searchResult.Type == BeatmapListingFilterControl.SearchResultType.SupporterOnlyFilters)
|
||||||
{
|
{
|
||||||
supporterRequiredContent.UpdateText(searchResult.SupporterOnlyFiltersUsed);
|
var supporterOnly = new SupporterRequiredDrawable(searchResult.SupporterOnlyFiltersUsed);
|
||||||
addContentToResultsArea(supporterRequiredContent);
|
replaceResultsAreaContent(supporterOnly);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,13 +159,13 @@ namespace osu.Game.Overlays
|
|||||||
//No matches case
|
//No matches case
|
||||||
if (!newCards.Any())
|
if (!newCards.Any())
|
||||||
{
|
{
|
||||||
addContentToResultsArea(notFoundContent);
|
replaceResultsAreaContent(new NotFoundDrawable());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var content = createCardContainerFor(newCards);
|
var content = createCardContainerFor(newCards);
|
||||||
|
|
||||||
panelLoadTask = LoadComponentAsync(foundContent = content, addContentToResultsArea, (cancellationToken = new CancellationTokenSource()).Token);
|
panelLoadTask = LoadComponentAsync(foundContent = content, replaceResultsAreaContent, (cancellationToken = new CancellationTokenSource()).Token);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -221,36 +213,16 @@ namespace osu.Game.Overlays
|
|||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addContentToResultsArea(Drawable content)
|
private void replaceResultsAreaContent(Drawable content)
|
||||||
{
|
{
|
||||||
Loading.Hide();
|
Loading.Hide();
|
||||||
lastFetchDisplayedTime = Time.Current;
|
lastFetchDisplayedTime = Time.Current;
|
||||||
|
|
||||||
if (content == currentContent)
|
panelTarget.Child = content;
|
||||||
return;
|
|
||||||
|
|
||||||
var lastContent = currentContent;
|
|
||||||
|
|
||||||
if (lastContent != null)
|
|
||||||
{
|
|
||||||
lastContent.FadeOut();
|
|
||||||
if (!isPlaceholderContent(lastContent))
|
|
||||||
lastContent.Expire();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!content.IsAlive)
|
|
||||||
panelTarget.Add(content);
|
|
||||||
|
|
||||||
content.FadeInFromZero();
|
content.FadeInFromZero();
|
||||||
currentContent = content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Whether <paramref name="drawable"/> is a static placeholder reused multiple times by this overlay.
|
|
||||||
/// </summary>
|
|
||||||
private bool isPlaceholderContent(Drawable drawable)
|
|
||||||
=> drawable == notFoundContent || drawable == supporterRequiredContent;
|
|
||||||
|
|
||||||
private void onCardSizeChanged()
|
private void onCardSizeChanged()
|
||||||
{
|
{
|
||||||
if (foundContent?.IsAlive != true || !foundContent.Any())
|
if (foundContent?.IsAlive != true || !foundContent.Any())
|
||||||
@ -287,7 +259,7 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(LargeTextureStore textures)
|
||||||
{
|
{
|
||||||
AddInternal(new FillFlowContainer
|
AddInternal(new FillFlowContainer
|
||||||
{
|
{
|
||||||
@ -324,15 +296,19 @@ namespace osu.Game.Overlays
|
|||||||
{
|
{
|
||||||
private LinkFlowContainer supporterRequiredText;
|
private LinkFlowContainer supporterRequiredText;
|
||||||
|
|
||||||
public SupporterRequiredDrawable()
|
private readonly List<LocalisableString> filtersUsed;
|
||||||
|
|
||||||
|
public SupporterRequiredDrawable(List<LocalisableString> filtersUsed)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Height = 225;
|
Height = 225;
|
||||||
Alpha = 0;
|
Alpha = 0;
|
||||||
|
|
||||||
|
this.filtersUsed = filtersUsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(LargeTextureStore textures)
|
||||||
{
|
{
|
||||||
AddInternal(new FillFlowContainer
|
AddInternal(new FillFlowContainer
|
||||||
{
|
{
|
||||||
@ -360,14 +336,9 @@ namespace osu.Game.Overlays
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateText(List<LocalisableString> filters)
|
|
||||||
{
|
|
||||||
supporterRequiredText.Clear();
|
|
||||||
|
|
||||||
supporterRequiredText.AddText(
|
supporterRequiredText.AddText(
|
||||||
BeatmapsStrings.ListingSearchSupporterFilterQuoteDefault(string.Join(" and ", filters), "").ToString(),
|
BeatmapsStrings.ListingSearchSupporterFilterQuoteDefault(string.Join(" and ", filtersUsed), "").ToString(),
|
||||||
t =>
|
t =>
|
||||||
{
|
{
|
||||||
t.Font = OsuFont.GetFont(size: 16);
|
t.Font = OsuFont.GetFont(size: 16);
|
||||||
|
@ -119,22 +119,17 @@ namespace osu.Game.Overlays.Dashboard.Home.News
|
|||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(GameHost host)
|
private void load(GameHost host)
|
||||||
{
|
{
|
||||||
NewsPostBackground bg;
|
Child = new DelayedLoadUnloadWrapper(() => new NewsPostBackground(post.FirstImage)
|
||||||
|
|
||||||
Child = new DelayedLoadWrapper(bg = new NewsPostBackground(post.FirstImage)
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
FillMode = FillMode.Fill,
|
FillMode = FillMode.Fill,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Alpha = 0
|
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
};
|
};
|
||||||
|
|
||||||
bg.OnLoadComplete += d => d.FadeIn(250, Easing.In);
|
|
||||||
|
|
||||||
TooltipText = "view in browser";
|
TooltipText = "view in browser";
|
||||||
Action = () => host.OpenUrlExternally("https://osu.ppy.sh/home/news/" + post.Slug);
|
Action = () => host.OpenUrlExternally("https://osu.ppy.sh/home/news/" + post.Slug);
|
||||||
|
|
||||||
|
@ -49,7 +49,6 @@ namespace osu.Game.Overlays.News
|
|||||||
Action = () => host.OpenUrlExternally("https://osu.ppy.sh/home/news/" + post.Slug);
|
Action = () => host.OpenUrlExternally("https://osu.ppy.sh/home/news/" + post.Slug);
|
||||||
}
|
}
|
||||||
|
|
||||||
NewsPostBackground bg;
|
|
||||||
AddRange(new Drawable[]
|
AddRange(new Drawable[]
|
||||||
{
|
{
|
||||||
background = new Box
|
background = new Box
|
||||||
@ -71,14 +70,14 @@ namespace osu.Game.Overlays.News
|
|||||||
CornerRadius = 6,
|
CornerRadius = 6,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new DelayedLoadWrapper(bg = new NewsPostBackground(post.FirstImage)
|
new DelayedLoadUnloadWrapper(() => new NewsPostBackground(post.FirstImage)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
FillMode = FillMode.Fill,
|
FillMode = FillMode.Fill,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Alpha = 0
|
Alpha = 0
|
||||||
})
|
}, timeBeforeUnload: 5000)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both
|
RelativeSizeAxes = Axes.Both
|
||||||
},
|
},
|
||||||
@ -116,8 +115,6 @@ namespace osu.Game.Overlays.News
|
|||||||
IdleColour = colourProvider.Background4;
|
IdleColour = colourProvider.Background4;
|
||||||
HoverColour = colourProvider.Background3;
|
HoverColour = colourProvider.Background3;
|
||||||
|
|
||||||
bg.OnLoadComplete += d => d.FadeIn(250, Easing.In);
|
|
||||||
|
|
||||||
main.AddParagraph(post.Title, t => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold));
|
main.AddParagraph(post.Title, t => t.Font = OsuFont.GetFont(size: 20, weight: FontWeight.SemiBold));
|
||||||
main.AddParagraph(post.Preview, t => t.Font = OsuFont.GetFont(size: 12)); // Should use sans-serif font
|
main.AddParagraph(post.Preview, t => t.Font = OsuFont.GetFont(size: 12)); // Should use sans-serif font
|
||||||
main.AddParagraph("by ", t => t.Font = OsuFont.GetFont(size: 12));
|
main.AddParagraph("by ", t => t.Font = OsuFont.GetFont(size: 12));
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
|
|
||||||
@ -25,6 +26,12 @@ namespace osu.Game.Overlays.News
|
|||||||
Texture = store.Get(createUrl(sourceUrl));
|
Texture = store.Get(createUrl(sourceUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
this.FadeInFromZero(500, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
private string createUrl(string source)
|
private string createUrl(string source)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(source))
|
if (string.IsNullOrEmpty(source))
|
||||||
|
@ -100,7 +100,7 @@ namespace osu.Game.Overlays
|
|||||||
},
|
},
|
||||||
Children = new[]
|
Children = new[]
|
||||||
{
|
{
|
||||||
background = new Background(),
|
background = Empty(),
|
||||||
title = new OsuSpriteText
|
title = new OsuSpriteText
|
||||||
{
|
{
|
||||||
Origin = Anchor.BottomCentre,
|
Origin = Anchor.BottomCentre,
|
||||||
@ -413,7 +413,7 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(LargeTextureStore textures)
|
||||||
{
|
{
|
||||||
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ namespace osu.Game.Overlays
|
|||||||
Height = 80;
|
Height = 80;
|
||||||
RelativeSizeAxes = Axes.X;
|
RelativeSizeAxes = Axes.X;
|
||||||
Masking = true;
|
Masking = true;
|
||||||
InternalChild = new Background(textureName);
|
InternalChild = new DelayedLoadWrapper(() => new Background(textureName));
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Background : Sprite
|
private class Background : Sprite
|
||||||
@ -36,10 +36,16 @@ namespace osu.Game.Overlays
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(LargeTextureStore textures)
|
||||||
{
|
{
|
||||||
Texture = textures.Get(textureName);
|
Texture = textures.Get(textureName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
this.FadeInFromZero(500, Easing.OutQuint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Localisation;
|
using osu.Framework.Localisation;
|
||||||
using osu.Game.Localisation;
|
using osu.Game.Localisation;
|
||||||
@ -13,6 +15,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
{
|
{
|
||||||
protected override LocalisableString Header => BindingSettingsStrings.ShortcutAndGameplayBindings;
|
protected override LocalisableString Header => BindingSettingsStrings.ShortcutAndGameplayBindings;
|
||||||
|
|
||||||
|
public override IEnumerable<LocalisableString> FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "keybindings" });
|
||||||
|
|
||||||
public BindingSettings(KeyBindingPanel keyConfig)
|
public BindingSettings(KeyBindingPanel keyConfig)
|
||||||
{
|
{
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
|
@ -33,6 +33,11 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
{
|
{
|
||||||
public class KeyBindingRow : Container, IFilterable
|
public class KeyBindingRow : Container, IFilterable
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Invoked when the binding of this row is updated with a change being written.
|
||||||
|
/// </summary>
|
||||||
|
public Action<KeyBindingRow> BindingUpdated { get; set; }
|
||||||
|
|
||||||
private readonly object action;
|
private readonly object action;
|
||||||
private readonly IEnumerable<RealmKeyBinding> bindings;
|
private readonly IEnumerable<RealmKeyBinding> bindings;
|
||||||
|
|
||||||
@ -153,7 +158,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
Spacing = new Vector2(5),
|
Spacing = new Vector2(5),
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new CancelButton { Action = finalise },
|
new CancelButton { Action = () => finalise(false) },
|
||||||
new ClearButton { Action = clear },
|
new ClearButton { Action = clear },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -226,7 +231,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromMouseButton(e.Button));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,7 +245,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bindTarget.IsHovered)
|
if (bindTarget.IsHovered)
|
||||||
finalise();
|
finalise(false);
|
||||||
// prevent updating bind target before clear button's action
|
// prevent updating bind target before clear button's action
|
||||||
else if (!cancelAndClearButtons.Any(b => b.IsHovered))
|
else if (!cancelAndClearButtons.Any(b => b.IsHovered))
|
||||||
updateBindTarget();
|
updateBindTarget();
|
||||||
@ -252,7 +257,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
{
|
{
|
||||||
if (bindTarget.IsHovered)
|
if (bindTarget.IsHovered)
|
||||||
{
|
{
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState, e.ScrollDelta), KeyCombination.FromScrollDelta(e.ScrollDelta).First());
|
||||||
finalise();
|
finalise();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -263,10 +268,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
|
|
||||||
protected override bool OnKeyDown(KeyDownEvent e)
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
{
|
{
|
||||||
if (!HasFocus)
|
if (!HasFocus || e.Repeat)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromKey(e.Key));
|
||||||
if (!isModifier(e.Key)) finalise();
|
if (!isModifier(e.Key)) finalise();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -288,7 +293,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
if (!HasFocus)
|
if (!HasFocus)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromJoystickButton(e.Button));
|
||||||
finalise();
|
finalise();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -310,7 +315,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
if (!HasFocus)
|
if (!HasFocus)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromMidiKey(e.Key));
|
||||||
finalise();
|
finalise();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -332,7 +337,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
if (!HasFocus)
|
if (!HasFocus)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromTabletAuxiliaryButton(e.Button));
|
||||||
finalise();
|
finalise();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -354,7 +359,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
if (!HasFocus)
|
if (!HasFocus)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState));
|
bindTarget.UpdateKeyCombination(KeyCombination.FromInputState(e.CurrentState), KeyCombination.FromTabletPenButton(e.Button));
|
||||||
finalise();
|
finalise();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -377,10 +382,10 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bindTarget.UpdateKeyCombination(InputKey.None);
|
bindTarget.UpdateKeyCombination(InputKey.None);
|
||||||
finalise();
|
finalise(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finalise()
|
private void finalise(bool hasChanged = true)
|
||||||
{
|
{
|
||||||
if (bindTarget != null)
|
if (bindTarget != null)
|
||||||
{
|
{
|
||||||
@ -393,6 +398,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
{
|
{
|
||||||
// schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.)
|
// schedule to ensure we don't instantly get focus back on next OnMouseClick (see AcceptFocus impl.)
|
||||||
bindTarget = null;
|
bindTarget = null;
|
||||||
|
if (hasChanged)
|
||||||
|
BindingUpdated?.Invoke(this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +424,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
|
|
||||||
protected override void OnFocusLost(FocusLostEvent e)
|
protected override void OnFocusLost(FocusLostEvent e)
|
||||||
{
|
{
|
||||||
finalise();
|
finalise(false);
|
||||||
base.OnFocusLost(e);
|
base.OnFocusLost(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -563,6 +570,14 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update from a key combination, only allowing a single non-modifier key to be specified.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fullState">A <see cref="KeyCombination"/> generated from the full input state.</param>
|
||||||
|
/// <param name="triggerKey">The key which triggered this update, and should be used as the binding.</param>
|
||||||
|
public void UpdateKeyCombination(KeyCombination fullState, InputKey triggerKey) =>
|
||||||
|
UpdateKeyCombination(new KeyCombination(fullState.Keys.Where(KeyCombination.IsModifierKey).Append(triggerKey)));
|
||||||
|
|
||||||
public void UpdateKeyCombination(KeyCombination newCombination)
|
public void UpdateKeyCombination(KeyCombination newCombination)
|
||||||
{
|
{
|
||||||
if (KeyBinding.RulesetName != null && !RealmKeyBindingStore.CheckValidForGameplay(newCombination))
|
if (KeyBinding.RulesetName != null && !RealmKeyBindingStore.CheckValidForGameplay(newCombination))
|
||||||
|
@ -19,6 +19,12 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
{
|
{
|
||||||
public abstract class KeyBindingsSubsection : SettingsSubsection
|
public abstract class KeyBindingsSubsection : SettingsSubsection
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// After a successful binding, automatically select the next binding row to make quickly
|
||||||
|
/// binding a large set of keys easier on the user.
|
||||||
|
/// </summary>
|
||||||
|
protected virtual bool AutoAdvanceTarget => false;
|
||||||
|
|
||||||
protected IEnumerable<Framework.Input.Bindings.KeyBinding> Defaults;
|
protected IEnumerable<Framework.Input.Bindings.KeyBinding> Defaults;
|
||||||
|
|
||||||
public RulesetInfo Ruleset { get; protected set; }
|
public RulesetInfo Ruleset { get; protected set; }
|
||||||
@ -49,7 +55,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => b.ActionInt.Equals(intKey)).ToList())
|
Add(new KeyBindingRow(defaultGroup.Key, bindings.Where(b => b.ActionInt.Equals(intKey)).ToList())
|
||||||
{
|
{
|
||||||
AllowMainMouseButtons = Ruleset != null,
|
AllowMainMouseButtons = Ruleset != null,
|
||||||
Defaults = defaultGroup.Select(d => d.KeyCombination)
|
Defaults = defaultGroup.Select(d => d.KeyCombination),
|
||||||
|
BindingUpdated = onBindingUpdated
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +65,16 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
Action = () => Children.OfType<KeyBindingRow>().ForEach(k => k.RestoreDefaults())
|
Action = () => Children.OfType<KeyBindingRow>().ForEach(k => k.RestoreDefaults())
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void onBindingUpdated(KeyBindingRow sender)
|
||||||
|
{
|
||||||
|
if (AutoAdvanceTarget)
|
||||||
|
{
|
||||||
|
var next = Children.SkipWhile(c => c != sender).Skip(1).FirstOrDefault();
|
||||||
|
if (next != null)
|
||||||
|
GetContainingInputManager().ChangeFocus(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ResetButton : DangerousSettingsButton
|
public class ResetButton : DangerousSettingsButton
|
||||||
|
@ -8,6 +8,8 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
|||||||
{
|
{
|
||||||
public class VariantBindingsSubsection : KeyBindingsSubsection
|
public class VariantBindingsSubsection : KeyBindingsSubsection
|
||||||
{
|
{
|
||||||
|
protected override bool AutoAdvanceTarget => true;
|
||||||
|
|
||||||
protected override LocalisableString Header { get; }
|
protected override LocalisableString Header { get; }
|
||||||
|
|
||||||
public VariantBindingsSubsection(RulesetInfo ruleset, int variant)
|
public VariantBindingsSubsection(RulesetInfo ruleset, int variant)
|
||||||
|
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
#nullable disable
|
#nullable disable
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Sprites;
|
using osu.Framework.Graphics.Sprites;
|
||||||
@ -22,8 +20,6 @@ namespace osu.Game.Overlays.Settings.Sections
|
|||||||
|
|
||||||
public override LocalisableString Header => InputSettingsStrings.InputSectionHeader;
|
public override LocalisableString Header => InputSettingsStrings.InputSectionHeader;
|
||||||
|
|
||||||
public override IEnumerable<LocalisableString> FilterTerms => base.FilterTerms.Concat(new LocalisableString[] { "keybindings" });
|
|
||||||
|
|
||||||
public override Drawable CreateIcon() => new SpriteIcon
|
public override Drawable CreateIcon() => new SpriteIcon
|
||||||
{
|
{
|
||||||
Icon = FontAwesome.Solid.Keyboard
|
Icon = FontAwesome.Solid.Keyboard
|
||||||
|
@ -89,6 +89,10 @@ namespace osu.Game
|
|||||||
// check if we are already at a valid target screen.
|
// check if we are already at a valid target screen.
|
||||||
if (validScreens.Any(t => t.IsAssignableFrom(type)))
|
if (validScreens.Any(t => t.IsAssignableFrom(type)))
|
||||||
{
|
{
|
||||||
|
if (!((Drawable)current).IsLoaded)
|
||||||
|
// wait until screen is loaded before invoking action.
|
||||||
|
return true;
|
||||||
|
|
||||||
finalAction(current);
|
finalAction(current);
|
||||||
Cancel();
|
Cancel();
|
||||||
return true;
|
return true;
|
||||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Rulesets.Difficulty
|
|||||||
// calculate total score
|
// calculate total score
|
||||||
ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor();
|
ScoreProcessor scoreProcessor = ruleset.CreateScoreProcessor();
|
||||||
scoreProcessor.Mods.Value = perfectPlay.Mods;
|
scoreProcessor.Mods.Value = perfectPlay.Mods;
|
||||||
perfectPlay.TotalScore = (long)scoreProcessor.ComputeScore(ScoringMode.Standardised, perfectPlay);
|
perfectPlay.TotalScore = scoreProcessor.ComputeScore(ScoringMode.Standardised, perfectPlay);
|
||||||
|
|
||||||
// compute rank achieved
|
// compute rank achieved
|
||||||
// default to SS, then adjust the rank with mods
|
// default to SS, then adjust the rank with mods
|
||||||
|
@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current total score.
|
/// The current total score.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly BindableDouble TotalScore = new BindableDouble { MinValue = 0 };
|
public readonly BindableLong TotalScore = new BindableLong { MinValue = 0 };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current accuracy.
|
/// The current accuracy.
|
||||||
@ -267,7 +267,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
|
|
||||||
private void updateScore()
|
private void updateScore()
|
||||||
{
|
{
|
||||||
Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1;
|
Accuracy.Value = currentMaximumScoringValues.BaseScore > 0 ? (double)currentScoringValues.BaseScore / currentMaximumScoringValues.BaseScore : 1;
|
||||||
TotalScore.Value = ComputeScore(Mode.Value, currentScoringValues, maximumScoringValues);
|
TotalScore.Value = ComputeScore(Mode.Value, currentScoringValues, maximumScoringValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <param name="scoreInfo">The <see cref="ScoreInfo"/> to compute the total score of.</param>
|
/// <param name="scoreInfo">The <see cref="ScoreInfo"/> to compute the total score of.</param>
|
||||||
/// <returns>The total score in the given <see cref="ScoringMode"/>.</returns>
|
/// <returns>The total score in the given <see cref="ScoringMode"/>.</returns>
|
||||||
[Pure]
|
[Pure]
|
||||||
public double ComputeScore(ScoringMode mode, ScoreInfo scoreInfo)
|
public long ComputeScore(ScoringMode mode, ScoreInfo scoreInfo)
|
||||||
{
|
{
|
||||||
if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset))
|
if (!ruleset.RulesetInfo.Equals(scoreInfo.Ruleset))
|
||||||
throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\".");
|
throw new ArgumentException($"Unexpected score ruleset. Expected \"{ruleset.RulesetInfo.ShortName}\" but was \"{scoreInfo.Ruleset.ShortName}\".");
|
||||||
@ -316,9 +316,9 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <param name="maximum">The maximum scoring values.</param>
|
/// <param name="maximum">The maximum scoring values.</param>
|
||||||
/// <returns>The total score computed from the given scoring values.</returns>
|
/// <returns>The total score computed from the given scoring values.</returns>
|
||||||
[Pure]
|
[Pure]
|
||||||
public double ComputeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum)
|
public long ComputeScore(ScoringMode mode, ScoringValues current, ScoringValues maximum)
|
||||||
{
|
{
|
||||||
double accuracyRatio = maximum.BaseScore > 0 ? current.BaseScore / maximum.BaseScore : 1;
|
double accuracyRatio = maximum.BaseScore > 0 ? (double)current.BaseScore / maximum.BaseScore : 1;
|
||||||
double comboRatio = maximum.MaxCombo > 0 ? (double)current.MaxCombo / maximum.MaxCombo : 1;
|
double comboRatio = maximum.MaxCombo > 0 ? (double)current.MaxCombo / maximum.MaxCombo : 1;
|
||||||
return ComputeScore(mode, accuracyRatio, comboRatio, current.BonusScore, maximum.CountBasicHitObjects);
|
return ComputeScore(mode, accuracyRatio, comboRatio, current.BonusScore, maximum.CountBasicHitObjects);
|
||||||
}
|
}
|
||||||
@ -333,21 +333,23 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// <param name="totalBasicHitObjects">The total number of basic (non-tick and non-bonus) hitobjects in the beatmap.</param>
|
/// <param name="totalBasicHitObjects">The total number of basic (non-tick and non-bonus) hitobjects in the beatmap.</param>
|
||||||
/// <returns>The total score computed from the given scoring component ratios.</returns>
|
/// <returns>The total score computed from the given scoring component ratios.</returns>
|
||||||
[Pure]
|
[Pure]
|
||||||
public double ComputeScore(ScoringMode mode, double accuracyRatio, double comboRatio, double bonusScore, int totalBasicHitObjects)
|
public long ComputeScore(ScoringMode mode, double accuracyRatio, double comboRatio, long bonusScore, int totalBasicHitObjects)
|
||||||
{
|
{
|
||||||
|
double accuracyScore = accuracyPortion * accuracyRatio;
|
||||||
|
double comboScore = comboPortion * comboRatio;
|
||||||
|
double rawScore = (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier;
|
||||||
|
|
||||||
switch (mode)
|
switch (mode)
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
case ScoringMode.Standardised:
|
case ScoringMode.Standardised:
|
||||||
double accuracyScore = accuracyPortion * accuracyRatio;
|
return (long)Math.Round(rawScore);
|
||||||
double comboScore = comboPortion * comboRatio;
|
|
||||||
return (max_score * (accuracyScore + comboScore) + bonusScore) * scoreMultiplier;
|
|
||||||
|
|
||||||
case ScoringMode.Classic:
|
case ScoringMode.Classic:
|
||||||
// This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring.
|
// This gives a similar feeling to osu!stable scoring (ScoreV1) while keeping classic scoring as only a constant multiple of standardised scoring.
|
||||||
// The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes.
|
// The invariant is important to ensure that scores don't get re-ordered on leaderboards between the two scoring modes.
|
||||||
double scaledStandardised = ComputeScore(ScoringMode.Standardised, accuracyRatio, comboRatio, bonusScore, totalBasicHitObjects) / max_score;
|
double scaledRawScore = rawScore / max_score;
|
||||||
return Math.Pow(scaledStandardised * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier;
|
return (long)Math.Round(Math.Pow(scaledRawScore * Math.Max(1, totalBasicHitObjects), 2) * ClassicScoreMultiplier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,7 +419,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
score.MaximumStatistics[result] = maximumResultCounts.GetValueOrDefault(result);
|
score.MaximumStatistics[result] = maximumResultCounts.GetValueOrDefault(result);
|
||||||
|
|
||||||
// Populate total score after everything else.
|
// Populate total score after everything else.
|
||||||
score.TotalScore = (long)Math.Round(ComputeScore(ScoringMode.Standardised, score));
|
score.TotalScore = ComputeScore(ScoringMode.Standardised, score);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -99,7 +99,7 @@ namespace osu.Game.Scoring
|
|||||||
var scoreProcessor = ruleset.CreateScoreProcessor();
|
var scoreProcessor = ruleset.CreateScoreProcessor();
|
||||||
scoreProcessor.Mods.Value = score.Mods;
|
scoreProcessor.Mods.Value = score.Mods;
|
||||||
|
|
||||||
return (long)Math.Round(scoreProcessor.ComputeScore(mode, score));
|
return scoreProcessor.ComputeScore(mode, score);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -20,13 +20,13 @@ namespace osu.Game.Scoring
|
|||||||
/// The sum of all "basic" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBasic"/> and <see cref="Judgement.ToNumericResult"/>.
|
/// The sum of all "basic" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBasic"/> and <see cref="Judgement.ToNumericResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Key(0)]
|
[Key(0)]
|
||||||
public double BaseScore;
|
public long BaseScore;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The sum of all "bonus" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBonus"/> and <see cref="Judgement.ToNumericResult"/>.
|
/// The sum of all "bonus" <see cref="HitObject"/> scoring values. See: <see cref="HitResultExtensions.IsBonus"/> and <see cref="Judgement.ToNumericResult"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Key(1)]
|
[Key(1)]
|
||||||
public double BonusScore;
|
public long BonusScore;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The highest achieved combo.
|
/// The highest achieved combo.
|
||||||
|
@ -436,8 +436,11 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
|
|||||||
{
|
{
|
||||||
base.OnDragEnd(e);
|
base.OnDragEnd(e);
|
||||||
|
|
||||||
OnDragHandled?.Invoke(null);
|
dragOperation?.Cancel();
|
||||||
|
dragOperation = null;
|
||||||
|
|
||||||
changeHandler?.EndChange();
|
changeHandler?.EndChange();
|
||||||
|
OnDragHandled?.Invoke(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +270,7 @@ namespace osu.Game.Screens.Edit
|
|||||||
{
|
{
|
||||||
IsSeeking &= Transforms.Any();
|
IsSeeking &= Transforms.Any();
|
||||||
|
|
||||||
if (track.Value?.IsRunning != true)
|
if (!IsRunning)
|
||||||
{
|
{
|
||||||
// seeking in the editor can happen while the track isn't running.
|
// seeking in the editor can happen while the track isn't running.
|
||||||
// in this case we always want to expose ourselves as seeking (to avoid sample playback).
|
// in this case we always want to expose ourselves as seeking (to avoid sample playback).
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System.Linq;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Screens;
|
using osu.Framework.Screens;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
@ -27,7 +28,12 @@ namespace osu.Game.Screens.Edit.GameplayTest
|
|||||||
protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart)
|
protected override GameplayClockContainer CreateGameplayClockContainer(WorkingBeatmap beatmap, double gameplayStart)
|
||||||
{
|
{
|
||||||
var masterGameplayClockContainer = new MasterGameplayClockContainer(beatmap, gameplayStart);
|
var masterGameplayClockContainer = new MasterGameplayClockContainer(beatmap, gameplayStart);
|
||||||
masterGameplayClockContainer.Reset(editorState.Time);
|
|
||||||
|
// Only reset the time to the current point if the editor is later than the normal start time (and the first object).
|
||||||
|
// This allows more sane test playing from the start of the beatmap (ie. correctly adding lead-in time).
|
||||||
|
if (editorState.Time > gameplayStart && editorState.Time > DrawableRuleset.Objects.FirstOrDefault()?.StartTime)
|
||||||
|
masterGameplayClockContainer.Reset(editorState.Time);
|
||||||
|
|
||||||
return masterGameplayClockContainer;
|
return masterGameplayClockContainer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,8 +224,8 @@ namespace osu.Game.Screens.Menu
|
|||||||
{
|
{
|
||||||
rulesetsScale.ScaleTo(0.8f, 1000);
|
rulesetsScale.ScaleTo(0.8f, 1000);
|
||||||
rulesets.FadeIn().ScaleTo(1).TransformSpacingTo(new Vector2(200, 0));
|
rulesets.FadeIn().ScaleTo(1).TransformSpacingTo(new Vector2(200, 0));
|
||||||
welcomeText.FadeOut();
|
welcomeText.FadeOut().Expire();
|
||||||
triangles.FadeOut();
|
triangles.FadeOut().Expire();
|
||||||
}
|
}
|
||||||
|
|
||||||
using (BeginDelayedSequence(rulesets_2))
|
using (BeginDelayedSequence(rulesets_2))
|
||||||
@ -307,7 +307,7 @@ namespace osu.Game.Screens.Menu
|
|||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load(TextureStore textures)
|
private void load(LargeTextureStore textures)
|
||||||
{
|
{
|
||||||
InternalChildren = new Drawable[]
|
InternalChildren = new Drawable[]
|
||||||
{
|
{
|
||||||
|
@ -67,7 +67,7 @@ namespace osu.Game.Screens.OnlinePlay.Playlists
|
|||||||
{
|
{
|
||||||
await base.PrepareScoreForResultsAsync(score).ConfigureAwait(false);
|
await base.PrepareScoreForResultsAsync(score).ConfigureAwait(false);
|
||||||
|
|
||||||
Score.ScoreInfo.TotalScore = (int)Math.Round(ScoreProcessor.ComputeScore(ScoringMode.Standardised, Score.ScoreInfo));
|
Score.ScoreInfo.TotalScore = ScoreProcessor.ComputeScore(ScoringMode.Standardised, Score.ScoreInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Dispose(bool isDisposing)
|
protected override void Dispose(bool isDisposing)
|
||||||
|
@ -171,12 +171,14 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
for (int i = 0; i < Flow.Count; i++)
|
for (int i = 0; i < Flow.Count; i++)
|
||||||
{
|
{
|
||||||
Flow.SetLayoutPosition(orderedByScore[i], i);
|
Flow.SetLayoutPosition(orderedByScore[i], i);
|
||||||
orderedByScore[i].ScorePosition = i + 1;
|
orderedByScore[i].ScorePosition = CheckValidScorePosition(i + 1) ? i + 1 : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
sorting.Validate();
|
sorting.Validate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual bool CheckValidScorePosition(int i) => true;
|
||||||
|
|
||||||
private class InputDisabledScrollContainer : OsuScrollContainer
|
private class InputDisabledScrollContainer : OsuScrollContainer
|
||||||
{
|
{
|
||||||
public InputDisabledScrollContainer()
|
public InputDisabledScrollContainer()
|
||||||
|
@ -50,7 +50,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText;
|
private OsuSpriteText positionText, scoreText, accuracyText, comboText, usernameText;
|
||||||
|
|
||||||
public BindableDouble TotalScore { get; } = new BindableDouble();
|
public BindableLong TotalScore { get; } = new BindableLong();
|
||||||
public BindableDouble Accuracy { get; } = new BindableDouble(1);
|
public BindableDouble Accuracy { get; } = new BindableDouble(1);
|
||||||
public BindableInt Combo { get; } = new BindableInt();
|
public BindableInt Combo { get; } = new BindableInt();
|
||||||
public BindableBool HasQuit { get; } = new BindableBool();
|
public BindableBool HasQuit { get; } = new BindableBool();
|
||||||
@ -62,20 +62,22 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
|
|
||||||
private int? scorePosition;
|
private int? scorePosition;
|
||||||
|
|
||||||
|
private bool scorePositionIsSet;
|
||||||
|
|
||||||
public int? ScorePosition
|
public int? ScorePosition
|
||||||
{
|
{
|
||||||
get => scorePosition;
|
get => scorePosition;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (value == scorePosition)
|
// We always want to run once, as the incoming value may be null and require a visual update to "-".
|
||||||
|
if (value == scorePosition && scorePositionIsSet)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
scorePosition = value;
|
scorePosition = value;
|
||||||
|
|
||||||
if (scorePosition.HasValue)
|
positionText.Text = scorePosition.HasValue ? $"#{scorePosition.Value.FormatRank()}" : "-";
|
||||||
positionText.Text = $"#{scorePosition.Value.FormatRank()}";
|
scorePositionIsSet = true;
|
||||||
|
|
||||||
positionText.FadeTo(scorePosition.HasValue ? 1 : 0);
|
|
||||||
updateState();
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
{
|
{
|
||||||
public interface ILeaderboardScore
|
public interface ILeaderboardScore
|
||||||
{
|
{
|
||||||
BindableDouble TotalScore { get; }
|
BindableLong TotalScore { get; }
|
||||||
BindableDouble Accuracy { get; }
|
BindableDouble Accuracy { get; }
|
||||||
BindableInt Combo { get; }
|
BindableInt Combo { get; }
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -184,7 +183,7 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (TeamScores.TryGetValue(u.Team.Value, out var team))
|
if (TeamScores.TryGetValue(u.Team.Value, out var team))
|
||||||
team.Value += (int)Math.Round(u.ScoreProcessor.TotalScore.Value);
|
team.Value += u.ScoreProcessor.TotalScore.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,10 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Game.Configuration;
|
using osu.Game.Configuration;
|
||||||
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Rulesets.Scoring;
|
using osu.Game.Rulesets.Scoring;
|
||||||
using osu.Game.Scoring;
|
using osu.Game.Scoring;
|
||||||
|
using osu.Game.Screens.Select;
|
||||||
using osu.Game.Users;
|
using osu.Game.Users;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Play.HUD
|
namespace osu.Game.Screens.Play.HUD
|
||||||
@ -18,6 +20,9 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
private const int duration = 100;
|
private const int duration = 100;
|
||||||
|
|
||||||
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
|
private readonly Bindable<bool> configVisibility = new Bindable<bool>();
|
||||||
|
|
||||||
|
private readonly Bindable<PlayBeatmapDetailArea.TabType> scoreSource = new Bindable<PlayBeatmapDetailArea.TabType>();
|
||||||
|
|
||||||
private readonly IUser trackingUser;
|
private readonly IUser trackingUser;
|
||||||
|
|
||||||
public readonly IBindableList<ScoreInfo> Scores = new BindableList<ScoreInfo>();
|
public readonly IBindableList<ScoreInfo> Scores = new BindableList<ScoreInfo>();
|
||||||
@ -46,11 +51,13 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
private void load(OsuConfigManager config)
|
private void load(OsuConfigManager config)
|
||||||
{
|
{
|
||||||
config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility);
|
config.BindWith(OsuSetting.GameplayLeaderboard, configVisibility);
|
||||||
|
config.BindWith(OsuSetting.BeatmapDetailTab, scoreSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
|
||||||
Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true);
|
Scores.BindCollectionChanged((_, _) => Scheduler.AddOnce(showScores), true);
|
||||||
|
|
||||||
// Alpha will be updated via `updateVisibility` below.
|
// Alpha will be updated via `updateVisibility` below.
|
||||||
@ -93,6 +100,18 @@ namespace osu.Game.Screens.Play.HUD
|
|||||||
local.DisplayOrder.Value = long.MaxValue;
|
local.DisplayOrder.Value = long.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool CheckValidScorePosition(int i)
|
||||||
|
{
|
||||||
|
// change displayed position to '-' when there are 50 already submitted scores and tracked score is last
|
||||||
|
if (scoreSource.Value != PlayBeatmapDetailArea.TabType.Local)
|
||||||
|
{
|
||||||
|
if (i == Flow.Count && Flow.Count > GetScoresRequest.MAX_SCORES_PER_REQUEST)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base.CheckValidScorePosition(i);
|
||||||
|
}
|
||||||
|
|
||||||
private void updateVisibility() =>
|
private void updateVisibility() =>
|
||||||
this.FadeTo(AlwaysVisible.Value || configVisibility.Value ? 1 : 0, duration);
|
this.FadeTo(AlwaysVisible.Value || configVisibility.Value ? 1 : 0, duration);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ namespace osu.Game.Screens.Play
|
|||||||
api.Queue(req);
|
api.Queue(req);
|
||||||
|
|
||||||
// Generally a timeout would not happen here as APIAccess will timeout first.
|
// Generally a timeout would not happen here as APIAccess will timeout first.
|
||||||
if (!tcs.Task.Wait(60000))
|
if (!tcs.Task.Wait(30000))
|
||||||
req.TriggerFailure(new InvalidOperationException("Token retrieval timed out (request never run)"));
|
req.TriggerFailure(new InvalidOperationException("Token retrieval timed out (request never run)"));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -57,7 +57,18 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateModeLight() => modeLight.FadeColour(buttons.FirstOrDefault(b => b.IsHovered)?.SelectedColour ?? Color4.Transparent, TRANSITION_LENGTH, Easing.OutQuint);
|
private void updateModeLight()
|
||||||
|
{
|
||||||
|
var selectedButton = buttons.FirstOrDefault(b => b.Enabled.Value && b.IsHovered);
|
||||||
|
|
||||||
|
if (selectedButton != null)
|
||||||
|
{
|
||||||
|
modeLight.FadeIn(TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
modeLight.FadeColour(selectedButton.SelectedColour, TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
modeLight.FadeOut(TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
}
|
||||||
|
|
||||||
public Footer()
|
public Footer()
|
||||||
{
|
{
|
||||||
@ -78,6 +89,7 @@ namespace osu.Game.Screens.Select
|
|||||||
RelativeSizeAxes = Axes.X,
|
RelativeSizeAxes = Axes.X,
|
||||||
Height = 3,
|
Height = 3,
|
||||||
Position = new Vector2(0, -3),
|
Position = new Vector2(0, -3),
|
||||||
|
Colour = Color4.Black,
|
||||||
},
|
},
|
||||||
new FillFlowContainer
|
new FillFlowContainer
|
||||||
{
|
{
|
||||||
|
@ -120,10 +120,18 @@ namespace osu.Game.Screens.Select
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void LoadComplete()
|
||||||
|
{
|
||||||
|
base.LoadComplete();
|
||||||
|
Enabled.BindValueChanged(_ => updateDisplay(), true);
|
||||||
|
}
|
||||||
|
|
||||||
public Action Hovered;
|
public Action Hovered;
|
||||||
public Action HoverLost;
|
public Action HoverLost;
|
||||||
public GlobalAction? Hotkey;
|
public GlobalAction? Hotkey;
|
||||||
|
|
||||||
|
private bool mouseDown;
|
||||||
|
|
||||||
protected override void UpdateAfterChildren()
|
protected override void UpdateAfterChildren()
|
||||||
{
|
{
|
||||||
base.UpdateAfterChildren();
|
base.UpdateAfterChildren();
|
||||||
@ -140,32 +148,38 @@ namespace osu.Game.Screens.Select
|
|||||||
protected override bool OnHover(HoverEvent e)
|
protected override bool OnHover(HoverEvent e)
|
||||||
{
|
{
|
||||||
Hovered?.Invoke();
|
Hovered?.Invoke();
|
||||||
light.ScaleTo(new Vector2(1, 2), Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
updateDisplay();
|
||||||
light.FadeColour(SelectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnHoverLost(HoverLostEvent e)
|
protected override void OnHoverLost(HoverLostEvent e)
|
||||||
{
|
{
|
||||||
HoverLost?.Invoke();
|
HoverLost?.Invoke();
|
||||||
light.ScaleTo(new Vector2(1, 1), Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
updateDisplay();
|
||||||
light.FadeColour(DeselectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseDown(MouseDownEvent e)
|
protected override bool OnMouseDown(MouseDownEvent e)
|
||||||
{
|
{
|
||||||
box.FadeTo(0.3f, Footer.TRANSITION_LENGTH * 2, Easing.OutQuint);
|
if (!Enabled.Value)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
mouseDown = true;
|
||||||
|
updateDisplay();
|
||||||
return base.OnMouseDown(e);
|
return base.OnMouseDown(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnMouseUp(MouseUpEvent e)
|
protected override void OnMouseUp(MouseUpEvent e)
|
||||||
{
|
{
|
||||||
box.FadeOut(Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
mouseDown = false;
|
||||||
|
updateDisplay();
|
||||||
base.OnMouseUp(e);
|
base.OnMouseUp(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
|
if (!Enabled.Value)
|
||||||
|
return true;
|
||||||
|
|
||||||
box.ClearTransforms();
|
box.ClearTransforms();
|
||||||
box.Alpha = 1;
|
box.Alpha = 1;
|
||||||
box.FadeOut(Footer.TRANSITION_LENGTH * 3, Easing.OutQuint);
|
box.FadeOut(Footer.TRANSITION_LENGTH * 3, Easing.OutQuint);
|
||||||
@ -184,5 +198,20 @@ namespace osu.Game.Screens.Select
|
|||||||
}
|
}
|
||||||
|
|
||||||
public virtual void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) { }
|
public virtual void OnReleased(KeyBindingReleaseEvent<GlobalAction> e) { }
|
||||||
|
|
||||||
|
private void updateDisplay()
|
||||||
|
{
|
||||||
|
this.FadeTo(Enabled.Value ? 1 : 0.25f, Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
|
||||||
|
light.ScaleTo(Enabled.Value && IsHovered ? new Vector2(1, 2) : new Vector2(1), Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
light.FadeColour(Enabled.Value && IsHovered ? SelectedColour : DeselectedColour, Footer.TRANSITION_LENGTH, Easing.OutQuint);
|
||||||
|
|
||||||
|
box.FadeTo(Enabled.Value & mouseDown ? 0.3f : 0f, Footer.TRANSITION_LENGTH * 2, Easing.OutQuint);
|
||||||
|
|
||||||
|
if (Enabled.Value && IsHovered)
|
||||||
|
Hovered?.Invoke();
|
||||||
|
else
|
||||||
|
HoverLost?.Invoke();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,8 @@ namespace osu.Game.Screens.Select
|
|||||||
|
|
||||||
protected BeatmapDetailArea BeatmapDetails { get; private set; }
|
protected BeatmapDetailArea BeatmapDetails { get; private set; }
|
||||||
|
|
||||||
|
private FooterButtonOptions beatmapOptionsButton;
|
||||||
|
|
||||||
private readonly Bindable<RulesetInfo> decoupledRuleset = new Bindable<RulesetInfo>();
|
private readonly Bindable<RulesetInfo> decoupledRuleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
private double audioFeedbackLastPlaybackTime;
|
private double audioFeedbackLastPlaybackTime;
|
||||||
@ -314,7 +316,7 @@ namespace osu.Game.Screens.Select
|
|||||||
NextRandom = () => Carousel.SelectNextRandom(),
|
NextRandom = () => Carousel.SelectNextRandom(),
|
||||||
PreviousRandom = Carousel.SelectPreviousRandom
|
PreviousRandom = Carousel.SelectPreviousRandom
|
||||||
}, null),
|
}, null),
|
||||||
(new FooterButtonOptions(), BeatmapOptions)
|
(beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions)
|
||||||
};
|
};
|
||||||
|
|
||||||
protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay();
|
protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay();
|
||||||
@ -739,6 +741,16 @@ namespace osu.Game.Screens.Select
|
|||||||
beatmapInfoWedge.Beatmap = beatmap;
|
beatmapInfoWedge.Beatmap = beatmap;
|
||||||
|
|
||||||
BeatmapDetails.Beatmap = beatmap;
|
BeatmapDetails.Beatmap = beatmap;
|
||||||
|
|
||||||
|
bool beatmapSelected = beatmap is not DummyWorkingBeatmap;
|
||||||
|
|
||||||
|
if (beatmapSelected)
|
||||||
|
beatmapOptionsButton.Enabled.Value = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
beatmapOptionsButton.Enabled.Value = false;
|
||||||
|
BeatmapOptions.Hide();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly WeakReference<ITrack> lastTrack = new WeakReference<ITrack>(null);
|
private readonly WeakReference<ITrack> lastTrack = new WeakReference<ITrack>(null);
|
||||||
|
Loading…
Reference in New Issue
Block a user