diff --git a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
index 3c6aaa39ca..a7078f1c09 100644
--- a/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
+++ b/Templates/Rulesets/ruleset-empty/osu.Game.Rulesets.EmptyFreeform.Tests/osu.Game.Rulesets.EmptyFreeform.Tests.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 0719dd30df..c133b0e3f8 100644
--- a/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
index d0db43cc81..92b48470e8 100644
--- a/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-empty/osu.Game.Rulesets.EmptyScrolling.Tests/osu.Game.Rulesets.EmptyScrolling.Tests.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
index 0719dd30df..c133b0e3f8 100644
--- a/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
+++ b/Templates/Rulesets/ruleset-scrolling-example/osu.Game.Rulesets.Pippidon.Tests/osu.Game.Rulesets.Pippidon.Tests.csproj
@@ -12,7 +12,7 @@
-
+
diff --git a/osu.Android.props b/osu.Android.props
index b2e3b32916..b296c114e9 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,10 +52,10 @@
-
+
-
+
diff --git a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
index 57b914bee6..a8599f2cb6 100644
--- a/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
+++ b/osu.Game.Benchmarks/osu.Game.Benchmarks.csproj
@@ -9,7 +9,7 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
index 13f2e25f05..d5496b7479 100644
--- a/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
+++ b/osu.Game.Rulesets.Catch.Tests/osu.Game.Rulesets.Catch.Tests.csproj
@@ -4,7 +4,7 @@
-
+
diff --git a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
index d51a6da4f9..2f12b1535e 100644
--- a/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
+++ b/osu.Game.Rulesets.Mania.Tests/osu.Game.Rulesets.Mania.Tests.csproj
@@ -4,7 +4,7 @@
-
+
diff --git a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
index fea2e408f6..e5b2e070d8 100644
--- a/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
+++ b/osu.Game.Rulesets.Osu.Tests/osu.Game.Rulesets.Osu.Tests.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs
new file mode 100644
index 0000000000..060c3c9443
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneDrumRollJudgements.cs
@@ -0,0 +1,36 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Taiko.Objects;
+
+namespace osu.Game.Rulesets.Taiko.Tests
+{
+ public class TestSceneDrumRollJudgements : TestSceneTaikoPlayer
+ {
+ [Test]
+ public void TestStrongDrumRollFullyJudgedOnKilled()
+ {
+ AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted.Value);
+ AddAssert("all judgements are misses", () => Player.Results.All(r => r.Type == r.Judgement.MinResult));
+ }
+
+ protected override bool Autoplay => false;
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset) => new Beatmap
+ {
+ BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo },
+ HitObjects =
+ {
+ new DrumRoll
+ {
+ StartTime = 1000,
+ Duration = 1000,
+ IsStrong = true
+ }
+ }
+ };
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
index ad3713e047..e48d80323a 100644
--- a/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
+++ b/osu.Game.Rulesets.Taiko.Tests/osu.Game.Rulesets.Taiko.Tests.csproj
@@ -4,7 +4,7 @@
-
+
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
index 521189d36c..b84db513f7 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRoll.cs
@@ -197,6 +197,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
}
+ public override void OnKilled()
+ {
+ base.OnKilled();
+
+ if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged)
+ ApplyResult(r => r.Type = r.Judgement.MinResult);
+ }
+
public override bool OnPressed(KeyBindingPressEvent e) => false;
}
}
diff --git a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
index dc2ed200a1..e24923e482 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableDrumRollTick.cs
@@ -5,6 +5,7 @@ using System;
using JetBrains.Annotations;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
+using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Taiko.Skinning.Default;
using osu.Game.Skinning;
@@ -52,6 +53,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = r.Judgement.MaxResult);
}
+ public override void OnKilled()
+ {
+ base.OnKilled();
+
+ if (Time.Current > HitObject.GetEndTime() && !Judged)
+ ApplyResult(r => r.Type = r.Judgement.MinResult);
+ }
+
protected override void UpdateHitStateTransforms(ArmedState state)
{
switch (state)
@@ -92,6 +101,14 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
ApplyResult(r => r.Type = ParentHitObject.IsHit ? r.Judgement.MaxResult : r.Judgement.MinResult);
}
+ public override void OnKilled()
+ {
+ base.OnKilled();
+
+ if (Time.Current > ParentHitObject.HitObject.GetEndTime() && !Judged)
+ ApplyResult(r => r.Type = r.Judgement.MinResult);
+ }
+
public override bool OnPressed(KeyBindingPressEvent e) => false;
}
}
diff --git a/osu.Game.Tests/Resources/TestResources.cs b/osu.Game.Tests/Resources/TestResources.cs
index d0ffb9c3db..1d99a5c20d 100644
--- a/osu.Game.Tests/Resources/TestResources.cs
+++ b/osu.Game.Tests/Resources/TestResources.cs
@@ -130,6 +130,7 @@ namespace osu.Game.Tests.Resources
StarRating = diff,
Length = length,
BPM = bpm,
+ Hash = Guid.NewGuid().ToString().ComputeMD5Hash(),
Ruleset = rulesetInfo,
Metadata = metadata,
BaseDifficulty = new BeatmapDifficulty
diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
new file mode 100644
index 0000000000..0f314242b4
--- /dev/null
+++ b/osu.Game.Tests/Visual/Navigation/TestSceneChangeAndUseGameplayBindings.cs
@@ -0,0 +1,88 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions;
+using osu.Framework.Input.Bindings;
+using osu.Framework.Testing;
+using osu.Game.Database;
+using osu.Game.Graphics.UserInterface;
+using osu.Game.Input.Bindings;
+using osu.Game.Overlays.Settings.Sections.Input;
+using osu.Game.Screens.Play;
+using osu.Game.Screens.Select;
+using osu.Game.Tests.Beatmaps.IO;
+using osuTK.Input;
+
+namespace osu.Game.Tests.Visual.Navigation
+{
+ public class TestSceneChangeAndUseGameplayBindings : OsuGameTestScene
+ {
+ [Test]
+ public void TestGameplayKeyBindings()
+ {
+ AddAssert("databased key is default", () => firstOsuRulesetKeyBindings.KeyCombination.Keys.SequenceEqual(new[] { InputKey.Z }));
+
+ AddStep("open settings", () => { Game.Settings.Show(); });
+
+ // Until step requires as settings has a delayed load.
+ AddUntilStep("wait for button", () => configureBindingsButton?.Enabled.Value == true);
+ AddStep("scroll to section", () => Game.Settings.SectionsContainer.ScrollTo(configureBindingsButton));
+ AddStep("press button", () => configureBindingsButton.TriggerClick());
+ AddUntilStep("wait for panel", () => keyBindingPanel?.IsLoaded == true);
+ AddUntilStep("wait for osu subsection", () => osuBindingSubsection?.IsLoaded == true);
+ AddStep("scroll to section", () => keyBindingPanel.SectionsContainer.ScrollTo(osuBindingSubsection));
+ AddWaitStep("wait for scroll to end", 3);
+ AddStep("start rebinding first osu! key", () =>
+ {
+ var button = osuBindingSubsection.ChildrenOfType().First();
+
+ InputManager.MoveMouseTo(button);
+ InputManager.Click(MouseButton.Left);
+ });
+
+ AddStep("Press 's'", () => InputManager.Key(Key.S));
+
+ AddUntilStep("wait for database updated", () => firstOsuRulesetKeyBindings.KeyCombination.Keys.SequenceEqual(new[] { InputKey.S }));
+
+ AddStep("close settings", () => Game.Settings.Hide());
+
+ AddStep("import beatmap", () => BeatmapImportHelper.LoadQuickOszIntoOsu(Game).WaitSafely());
+ PushAndConfirm(() => new PlaySongSelect());
+
+ AddStep("enter gameplay", () => InputManager.Key(Key.Enter));
+
+ AddUntilStep("wait for gameplay", () => player?.IsBreakTime.Value == false);
+
+ AddStep("press 'z'", () => InputManager.Key(Key.Z));
+ AddAssert("key counter didn't increase", () => keyCounter.CountPresses == 0);
+
+ AddStep("press 's'", () => InputManager.Key(Key.S));
+ AddAssert("key counter did increase", () => keyCounter.CountPresses == 1);
+ }
+
+ private KeyBindingsSubsection osuBindingSubsection => keyBindingPanel
+ .ChildrenOfType()
+ .FirstOrDefault(s => s.Ruleset.ShortName == "osu");
+
+ private OsuButton configureBindingsButton => Game.Settings
+ .ChildrenOfType().SingleOrDefault()?
+ .ChildrenOfType()?
+ .First(b => b.Text.ToString() == "Configure");
+
+ private KeyBindingPanel keyBindingPanel => Game.Settings
+ .ChildrenOfType().SingleOrDefault();
+
+ private RealmKeyBinding firstOsuRulesetKeyBindings => Game.Dependencies
+ .Get().Context
+ .All()
+ .AsEnumerable()
+ .First(k => k.RulesetName == "osu" && k.ActionInt == 0);
+
+ private Player player => Game.ScreenStack.CurrentScreen as Player;
+
+ private KeyCounter keyCounter => player.ChildrenOfType().First();
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
index be2db9a8a0..8a304110dd 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneScoresContainer.cs
@@ -1,11 +1,15 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
+using osu.Framework.Testing;
using osu.Framework.Utils;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
@@ -24,10 +28,11 @@ namespace osu.Game.Tests.Visual.Online
[Cached]
private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
- public TestSceneScoresContainer()
- {
- TestScoresContainer scoresContainer;
+ private TestScoresContainer scoresContainer;
+ [SetUpSteps]
+ public void SetUp() => Schedule(() =>
+ {
Child = new Container
{
Anchor = Anchor.TopCentre,
@@ -41,16 +46,110 @@ namespace osu.Game.Tests.Visual.Online
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
},
- scoresContainer = new TestScoresContainer(),
+ scoresContainer = new TestScoresContainer
+ {
+ Beatmap = { Value = CreateAPIBeatmap() }
+ }
}
};
+ });
- var allScores = new APIScoresCollection
+ [Test]
+ public void TestNoUserBest()
+ {
+ AddStep("Scores with no user best", () =>
+ {
+ var allScores = createScores();
+
+ allScores.UserScore = null;
+
+ scoresContainer.Scores = allScores;
+ });
+
+ AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any());
+ AddAssert("no user best displayed", () => scoresContainer.ChildrenOfType().Count() == 1);
+
+ AddStep("Load null scores", () => scoresContainer.Scores = null);
+
+ AddUntilStep("wait for scores not displayed", () => !scoresContainer.ChildrenOfType().Any());
+ AddAssert("no best score displayed", () => !scoresContainer.ChildrenOfType().Any());
+
+ AddStep("Load only one score", () =>
+ {
+ var allScores = createScores();
+
+ allScores.Scores.RemoveRange(1, allScores.Scores.Count - 1);
+
+ scoresContainer.Scores = allScores;
+ });
+
+ AddUntilStep("wait for scores not displayed", () => scoresContainer.ChildrenOfType().Count() == 1);
+ AddAssert("no best score displayed", () => scoresContainer.ChildrenOfType().Count() == 1);
+ }
+
+ [Test]
+ public void TestUserBest()
+ {
+ AddStep("Load scores with personal best", () =>
+ {
+ var allScores = createScores();
+ allScores.UserScore = createUserBest();
+ scoresContainer.Scores = allScores;
+ });
+
+ AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any());
+ AddAssert("best score displayed", () => scoresContainer.ChildrenOfType().Count() == 2);
+
+ AddStep("Load scores with personal best (null position)", () =>
+ {
+ var allScores = createScores();
+ var userBest = createUserBest();
+ userBest.Position = null;
+ allScores.UserScore = userBest;
+ scoresContainer.Scores = allScores;
+ });
+
+ AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any());
+ AddAssert("best score displayed", () => scoresContainer.ChildrenOfType().Count() == 2);
+
+ AddStep("Load scores with personal best (first place)", () =>
+ {
+ var allScores = createScores();
+ allScores.UserScore = new APIScoreWithPosition
+ {
+ Score = allScores.Scores.First(),
+ Position = 1,
+ };
+ scoresContainer.Scores = allScores;
+ });
+
+ AddUntilStep("wait for scores displayed", () => scoresContainer.ChildrenOfType().Any());
+ AddAssert("best score displayed", () => scoresContainer.ChildrenOfType().Count() == 1);
+
+ AddStep("Scores with no user best", () =>
+ {
+ var allScores = createScores();
+
+ allScores.UserScore = null;
+
+ scoresContainer.Scores = allScores;
+ });
+
+ AddUntilStep("best score not displayed", () => scoresContainer.ChildrenOfType().Count() == 1);
+ }
+
+ private int onlineID = 1;
+
+ private APIScoresCollection createScores()
+ {
+ var scores = new APIScoresCollection
{
Scores = new List
{
new APIScore
{
+ Date = DateTimeOffset.Now,
+ OnlineID = onlineID++,
User = new APIUser
{
Id = 6602580,
@@ -76,6 +175,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
+ Date = DateTimeOffset.Now,
+ OnlineID = onlineID++,
User = new APIUser
{
Id = 4608074,
@@ -100,6 +201,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
+ Date = DateTimeOffset.Now,
+ OnlineID = onlineID++,
User = new APIUser
{
Id = 1014222,
@@ -123,6 +226,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
+ Date = DateTimeOffset.Now,
+ OnlineID = onlineID++,
User = new APIUser
{
Id = 1541390,
@@ -145,6 +250,8 @@ namespace osu.Game.Tests.Visual.Online
},
new APIScore
{
+ Date = DateTimeOffset.Now,
+ OnlineID = onlineID++,
User = new APIUser
{
Id = 7151382,
@@ -164,85 +271,7 @@ namespace osu.Game.Tests.Visual.Online
}
};
- var myBestScore = new APIScoreWithPosition
- {
- Score = new APIScore
- {
- User = new APIUser
- {
- Id = 7151382,
- Username = @"Mayuri Hana",
- Country = new Country
- {
- FullName = @"Thailand",
- FlagName = @"TH",
- },
- },
- Rank = ScoreRank.D,
- PP = 160,
- MaxCombo = 1234,
- TotalScore = 123456,
- Accuracy = 0.6543,
- },
- Position = 1337,
- };
-
- var myBestScoreWithNullPosition = new APIScoreWithPosition
- {
- Score = new APIScore
- {
- User = new APIUser
- {
- Id = 7151382,
- Username = @"Mayuri Hana",
- Country = new Country
- {
- FullName = @"Thailand",
- FlagName = @"TH",
- },
- },
- Rank = ScoreRank.D,
- PP = 160,
- MaxCombo = 1234,
- TotalScore = 123456,
- Accuracy = 0.6543,
- },
- Position = null,
- };
-
- var oneScore = new APIScoresCollection
- {
- Scores = new List
- {
- new APIScore
- {
- User = new APIUser
- {
- Id = 6602580,
- Username = @"waaiiru",
- Country = new Country
- {
- FullName = @"Spain",
- FlagName = @"ES",
- },
- },
- Mods = new[]
- {
- new APIMod { Acronym = new OsuModDoubleTime().Acronym },
- new APIMod { Acronym = new OsuModHidden().Acronym },
- new APIMod { Acronym = new OsuModFlashlight().Acronym },
- new APIMod { Acronym = new OsuModHardRock().Acronym },
- },
- Rank = ScoreRank.XH,
- PP = 200,
- MaxCombo = 1234,
- TotalScore = 1234567890,
- Accuracy = 1,
- }
- }
- };
-
- foreach (var s in allScores.Scores)
+ foreach (var s in scores.Scores)
{
s.Statistics = new Dictionary
{
@@ -253,26 +282,34 @@ namespace osu.Game.Tests.Visual.Online
};
}
- AddStep("Load all scores", () =>
- {
- allScores.UserScore = null;
- scoresContainer.Scores = allScores;
- });
- AddStep("Load null scores", () => scoresContainer.Scores = null);
- AddStep("Load only one score", () => scoresContainer.Scores = oneScore);
- AddStep("Load scores with my best", () =>
- {
- allScores.UserScore = myBestScore;
- scoresContainer.Scores = allScores;
- });
-
- AddStep("Load scores with null my best position", () =>
- {
- allScores.UserScore = myBestScoreWithNullPosition;
- scoresContainer.Scores = allScores;
- });
+ return scores;
}
+ private APIScoreWithPosition createUserBest() => new APIScoreWithPosition
+ {
+ Score = new APIScore
+ {
+ Date = DateTimeOffset.Now,
+ OnlineID = onlineID++,
+ User = new APIUser
+ {
+ Id = 7151382,
+ Username = @"Mayuri Hana",
+ Country = new Country
+ {
+ FullName = @"Thailand",
+ FlagName = @"TH",
+ },
+ },
+ Rank = ScoreRank.D,
+ PP = 160,
+ MaxCombo = 1234,
+ TotalScore = 123456,
+ Accuracy = 0.6543,
+ },
+ Position = 1337,
+ };
+
private class TestScoresContainer : ScoresContainer
{
public new APIScoresCollection Scores
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs
index e9210496ca..11df115b1a 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsResultsScreen.cs
@@ -44,6 +44,10 @@ namespace osu.Game.Tests.Visual.Playlists
requestComplete = false;
totalCount = 0;
bindHandler();
+
+ // beatmap is required to be an actual beatmap so the scores can get their scores correctly calculated for standardised scoring.
+ // else the tests that rely on ordering will fall over.
+ Beatmap.Value = CreateWorkingBeatmap(Ruleset.Value);
});
[Test]
diff --git a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
index dfcf657218..bc9f759bdd 100644
--- a/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
+++ b/osu.Game.Tests/Visual/Playlists/TestScenePlaylistsRoomCreation.cs
@@ -19,6 +19,7 @@ using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Screens.OnlinePlay.Components;
+using osu.Game.Screens.OnlinePlay.Match.Components;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Play;
using osu.Game.Tests.Beatmaps;
@@ -73,6 +74,8 @@ namespace osu.Game.Tests.Visual.Playlists
AddUntilStep("Progress details are hidden", () => match.ChildrenOfType().FirstOrDefault()?.Parent.Alpha == 0);
+ AddUntilStep("Leaderboard shows two aggregate scores", () => match.ChildrenOfType().Count(s => s.ScoreText.Text != "0") == 2);
+
AddStep("start match", () => match.ChildrenOfType().First().TriggerClick());
AddUntilStep("player loader loaded", () => Stack.CurrentScreen is PlayerLoader);
}
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 3b115d43e5..c64ef918e3 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -6,7 +6,7 @@
-
+
diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
index 130fcfaca1..fb09a7be1e 100644
--- a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
+++ b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
@@ -7,7 +7,7 @@
-
+
WinExe
diff --git a/osu.Game/Beatmaps/BeatmapInfo.cs b/osu.Game/Beatmaps/BeatmapInfo.cs
index 224cf60c49..b0e10c2c38 100644
--- a/osu.Game/Beatmaps/BeatmapInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapInfo.cs
@@ -3,7 +3,6 @@
using System;
using System.Linq;
-using AutoMapper;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.Testing;
@@ -37,7 +36,6 @@ namespace osu.Game.Beatmaps
public BeatmapMetadata Metadata { get; set; }
- [IgnoreMap]
[Backlink(nameof(ScoreInfo.BeatmapInfo))]
public IQueryable Scores { get; } = null!;
@@ -155,7 +153,6 @@ namespace osu.Game.Beatmaps
#region Compatibility properties
[Ignored]
- [IgnoreMap]
public int RulesetID
{
get => Ruleset.OnlineID;
@@ -169,7 +166,6 @@ namespace osu.Game.Beatmaps
}
[Ignored]
- [IgnoreMap]
public BeatmapDifficulty BaseDifficulty
{
get => Difficulty;
diff --git a/osu.Game/Database/RealmContextFactory.cs b/osu.Game/Database/RealmContextFactory.cs
index 8548e63e94..10c2438df9 100644
--- a/osu.Game/Database/RealmContextFactory.cs
+++ b/osu.Game/Database/RealmContextFactory.cs
@@ -206,10 +206,17 @@ namespace osu.Game.Database
private RealmConfiguration getConfiguration()
{
+ // This is currently the only usage of temporary files at the osu! side.
+ // If we use the temporary folder in more situations in the future, this should be moved to a higher level (helper method or OsuGameBase).
+ string tempPathLocation = Path.Combine(Path.GetTempPath(), @"lazer");
+ if (!Directory.Exists(tempPathLocation))
+ Directory.CreateDirectory(tempPathLocation);
+
return new RealmConfiguration(storage.GetFullPath(Filename, true))
{
SchemaVersion = schema_version,
MigrationCallback = onMigration,
+ FallbackPipePath = tempPathLocation,
};
}
diff --git a/osu.Game/Database/RealmObjectExtensions.cs b/osu.Game/Database/RealmObjectExtensions.cs
index a162bd64d3..4ddf0077ca 100644
--- a/osu.Game/Database/RealmObjectExtensions.cs
+++ b/osu.Game/Database/RealmObjectExtensions.cs
@@ -4,7 +4,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Runtime.Serialization;
using AutoMapper;
+using AutoMapper.Internal;
using osu.Framework.Development;
using osu.Game.Beatmaps;
using osu.Game.Input.Bindings;
@@ -60,7 +62,14 @@ namespace osu.Game.Database
}
});
- c.AddGlobalIgnore(nameof(RealmObjectBase.ObjectSchema));
+ c.Internal().ForAllMaps((typeMap, expression) =>
+ {
+ expression.ForAllMembers(m =>
+ {
+ if (m.DestinationMember.Has() || m.DestinationMember.Has() || m.DestinationMember.Has())
+ m.Ignore();
+ });
+ });
}).CreateMapper();
private static readonly IMapper mapper = new MapperConfiguration(c =>
@@ -80,24 +89,35 @@ namespace osu.Game.Database
c.CreateMap();
c.CreateMap();
c.CreateMap();
- c.CreateMap().MaxDepth(2).AfterMap((s, d) =>
- {
- for (int i = 0; i < d.BeatmapSet?.Beatmaps.Count; i++)
- {
- if (d.BeatmapSet.Beatmaps[i].Equals(d))
- {
- d.BeatmapSet.Beatmaps[i] = d;
- break;
- }
- }
- });
- c.CreateMap().MaxDepth(2).AfterMap((s, d) =>
- {
- foreach (var beatmap in d.Beatmaps)
- beatmap.BeatmapSet = d;
- });
+ c.CreateMap()
+ .MaxDepth(2)
+ .AfterMap((s, d) =>
+ {
+ for (int i = 0; i < d.BeatmapSet?.Beatmaps.Count; i++)
+ {
+ if (d.BeatmapSet.Beatmaps[i].Equals(d))
+ {
+ d.BeatmapSet.Beatmaps[i] = d;
+ break;
+ }
+ }
+ });
+ c.CreateMap()
+ .MaxDepth(2)
+ .AfterMap((s, d) =>
+ {
+ foreach (var beatmap in d.Beatmaps)
+ beatmap.BeatmapSet = d;
+ });
- c.AddGlobalIgnore(nameof(RealmObjectBase.ObjectSchema));
+ c.Internal().ForAllMaps((typeMap, expression) =>
+ {
+ expression.ForAllMembers(m =>
+ {
+ if (m.DestinationMember.Has() || m.DestinationMember.Has() || m.DestinationMember.Has())
+ m.Ignore();
+ });
+ });
}).CreateMapper();
///
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index 247a509aa1..906e09b8c1 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -53,7 +53,9 @@ namespace osu.Game.Online.Leaderboards
private Drawable avatar;
private Drawable scoreRank;
private OsuSpriteText nameLabel;
- private GlowingSpriteText scoreLabel;
+
+ public GlowingSpriteText ScoreText { get; private set; }
+
private Container flagBadgeContainer;
private FillFlowContainer modsContainer;
@@ -198,7 +200,7 @@ namespace osu.Game.Online.Leaderboards
Spacing = new Vector2(5f, 0f),
Children = new Drawable[]
{
- scoreLabel = new GlowingSpriteText
+ ScoreText = new GlowingSpriteText
{
TextColour = Color4.White,
GlowColour = Color4Extensions.FromHex(@"83ccfa"),
@@ -240,7 +242,7 @@ namespace osu.Game.Online.Leaderboards
public override void Show()
{
- foreach (var d in new[] { avatar, nameLabel, scoreLabel, scoreRank, flagBadgeContainer, modsContainer }.Concat(statisticsLabels))
+ foreach (var d in new[] { avatar, nameLabel, ScoreText, scoreRank, flagBadgeContainer, modsContainer }.Concat(statisticsLabels))
d.FadeOut();
Alpha = 0;
@@ -262,7 +264,7 @@ namespace osu.Game.Online.Leaderboards
using (BeginDelayedSequence(250))
{
- scoreLabel.FadeIn(200);
+ ScoreText.FadeIn(200);
scoreRank.FadeIn(200);
using (BeginDelayedSequence(50))
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
index a40f29abf2..00dedc892b 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
@@ -65,6 +65,9 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
scoreTable.ClearScores();
scoreTable.Hide();
+ loading.Hide();
+ loading.FinishTransforms();
+
if (value?.Scores.Any() != true)
return;
@@ -258,9 +261,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
{
Scores = null;
notSupporterPlaceholder.Show();
-
- loading.Hide();
- loading.FinishTransforms();
return;
}
@@ -272,9 +272,6 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
getScoresRequest = new GetScoresRequest(Beatmap.Value, Beatmap.Value.Ruleset, scope.Value, modSelector.SelectedMods);
getScoresRequest.Success += scores =>
{
- loading.Hide();
- loading.FinishTransforms();
-
Scores = scores;
if (!scores.Scores.Any())
diff --git a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs
index 115a7bdc79..94c7c66538 100644
--- a/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs
+++ b/osu.Game/Overlays/Settings/Sections/Input/KeyBindingsSubsection.cs
@@ -18,7 +18,7 @@ namespace osu.Game.Overlays.Settings.Sections.Input
{
protected IEnumerable Defaults;
- protected RulesetInfo Ruleset;
+ public RulesetInfo Ruleset { get; protected set; }
private readonly int? variant;
diff --git a/osu.Game/Scoring/ScoreInfo.cs b/osu.Game/Scoring/ScoreInfo.cs
index fd0f14266a..e1328d8a06 100644
--- a/osu.Game/Scoring/ScoreInfo.cs
+++ b/osu.Game/Scoring/ScoreInfo.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using AutoMapper;
using JetBrains.Annotations;
using Newtonsoft.Json;
using osu.Framework.Localisation;
@@ -85,7 +84,7 @@ namespace osu.Game.Scoring
// Eventually we should either persist enough information to realm to not require the API lookups, or perform the API lookups locally.
private APIUser? user;
- [IgnoreMap]
+ [Ignored]
public APIUser User
{
get => user ??= new APIUser
@@ -187,10 +186,7 @@ namespace osu.Game.Scoring
if (mods != null)
return mods;
- if (apiMods != null)
- return APIMods.Select(m => m.ToMod(Ruleset.CreateInstance())).ToArray();
-
- return Array.Empty();
+ return APIMods.Select(m => m.ToMod(Ruleset.CreateInstance())).ToArray();
}
set
{
@@ -217,7 +213,7 @@ namespace osu.Game.Scoring
// then check mods set via Mods property.
if (mods != null)
- apiMods = mods.Select(m => new APIMod(m)).ToArray();
+ apiMods ??= mods.Select(m => new APIMod(m)).ToArray();
return apiMods ?? Array.Empty();
}
diff --git a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs
index 520f2c4585..5a0a7e71d4 100644
--- a/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs
+++ b/osu.Game/Tests/Visual/OnlinePlay/TestRoomRequestsHandler.cs
@@ -70,6 +70,29 @@ namespace osu.Game.Tests.Visual.OnlinePlay
return true;
}
+ case GetRoomLeaderboardRequest roomLeaderboardRequest:
+ roomLeaderboardRequest.TriggerSuccess(new APILeaderboard
+ {
+ Leaderboard = new List
+ {
+ new APIUserScoreAggregate
+ {
+ TotalScore = 1000000,
+ TotalAttempts = 5,
+ CompletedBeatmaps = 2,
+ User = new APIUser { Username = "best user" }
+ },
+ new APIUserScoreAggregate
+ {
+ TotalScore = 50,
+ TotalAttempts = 1,
+ CompletedBeatmaps = 1,
+ User = new APIUser { Username = "worst user" }
+ }
+ }
+ });
+ return true;
+
case PartRoomRequest partRoomRequest:
partRoomRequest.TriggerSuccess();
return true;
diff --git a/osu.Game/Tests/Visual/OsuTestScene.cs b/osu.Game/Tests/Visual/OsuTestScene.cs
index c631286d11..4af8ec3a99 100644
--- a/osu.Game/Tests/Visual/OsuTestScene.cs
+++ b/osu.Game/Tests/Visual/OsuTestScene.cs
@@ -294,10 +294,6 @@ namespace osu.Game.Tests.Visual
if (MusicController?.TrackLoaded == true)
MusicController.Stop();
- // TODO: what should we do here, if anything? should we use an in-memory realm in this instance?
- // if (contextFactory?.IsValueCreated == true)
- // contextFactory.Value.ResetDatabase();
-
RecycleLocalStorage(true);
}
diff --git a/osu.Game/Utils/SentryLogger.cs b/osu.Game/Utils/SentryLogger.cs
index 8f12760a6b..dbf04283b6 100644
--- a/osu.Game/Utils/SentryLogger.cs
+++ b/osu.Game/Utils/SentryLogger.cs
@@ -16,6 +16,7 @@ namespace osu.Game.Utils
{
private SentryClient sentry;
private Scope sentryScope;
+ private Exception lastException;
public SentryLogger(OsuGame game)
{
@@ -30,30 +31,27 @@ namespace osu.Game.Utils
sentry = new SentryClient(options);
sentryScope = new Scope(options);
- Exception lastException = null;
+ Logger.NewEntry += processLogEntry;
+ }
- Logger.NewEntry += entry =>
+ private void processLogEntry(LogEntry entry)
+ {
+ if (entry.Level < LogLevel.Verbose) return;
+
+ var exception = entry.Exception;
+
+ if (exception != null)
{
- if (entry.Level < LogLevel.Verbose) return;
+ if (!shouldSubmitException(exception)) return;
- var exception = entry.Exception;
+ // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports.
+ if (lastException != null && lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace, StringComparison.Ordinal)) return;
- if (exception != null)
- {
- if (!shouldSubmitException(exception))
- return;
-
- // since we let unhandled exceptions go ignored at times, we want to ensure they don't get submitted on subsequent reports.
- if (lastException != null &&
- lastException.Message == exception.Message && exception.StackTrace.StartsWith(lastException.StackTrace, StringComparison.Ordinal))
- return;
-
- lastException = exception;
- sentry.CaptureEvent(new SentryEvent(exception) { Message = entry.Message }, sentryScope);
- }
- else
- sentryScope.AddBreadcrumb(DateTimeOffset.Now, entry.Message, entry.Target.ToString(), "navigation");
- };
+ lastException = exception;
+ sentry.CaptureEvent(new SentryEvent(exception) { Message = entry.Message }, sentryScope);
+ }
+ else
+ sentryScope.AddBreadcrumb(DateTimeOffset.Now, entry.Message, entry.Target.ToString(), "navigation");
}
private bool shouldSubmitException(Exception exception)
@@ -92,15 +90,9 @@ namespace osu.Game.Utils
GC.SuppressFinalize(this);
}
- private bool isDisposed;
-
protected virtual void Dispose(bool isDisposing)
{
- if (isDisposed)
- return;
-
- isDisposed = true;
- sentry?.Dispose();
+ Logger.NewEntry -= processLogEntry;
sentry = null;
sentryScope = null;
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 2e5c9f4548..758575e74a 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -18,9 +18,9 @@
-
+
-
+
@@ -35,10 +35,10 @@
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 897be33c18..5925581e28 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -60,7 +60,7 @@
-
+
@@ -83,11 +83,11 @@
-
+
-
+