diff --git a/osu.Android.props b/osu.Android.props
index 2c3c8bcaad..93a9a073a4 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -61,6 +61,6 @@
-
+
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 7c282f449b..c527a81f51 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 4dcfc1b81f..af10d5e06e 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 197309c7c4..c331c811d2 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
@@ -4,7 +4,7 @@
-
+
diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs
index 002b3f8cda..f94b0138fd 100644
--- a/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/OsuLegacySkin.cs
@@ -101,7 +101,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
return !hasFont(font)
? null
- : new LegacySpriteText(this, font)
+ : new LegacySpriteText(source, font)
{
// Spacing value was reverse-engineered from the ratio of the rendered sprite size in the visual inspector vs the actual texture size
Scale = new Vector2(0.96f),
@@ -112,13 +112,13 @@ namespace osu.Game.Rulesets.Osu.Skinning
return null;
}
- public Texture GetTexture(string componentName) => null;
+ public Texture GetTexture(string componentName) => source.GetTexture(componentName);
- public SampleChannel GetSample(ISampleInfo sample) => null;
+ public SampleChannel GetSample(ISampleInfo sample) => source.GetSample(sample);
public TValue GetValue(Func query) where TConfiguration : SkinConfiguration
- => configuration.Value is TConfiguration conf ? query.Invoke(conf) : default;
+ => configuration.Value is TConfiguration conf ? query.Invoke(conf) : source.GetValue(query);
- private bool hasFont(string fontName) => GetTexture($"{fontName}-0") != null;
+ private bool hasFont(string fontName) => source.GetTexture($"{fontName}-0") != null;
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
new file mode 100644
index 0000000000..f27e329e8e
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneSwellJudgements.cs
@@ -0,0 +1,74 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Collections.Generic;
+using System.Linq;
+using NUnit.Framework;
+using osu.Framework.Allocation;
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Rulesets.Taiko.Judgements;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Screens.Play;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Taiko.Tests
+{
+ public class TestSceneSwellJudgements : PlayerTestScene
+ {
+ protected new TestPlayer Player => (TestPlayer)base.Player;
+
+ public TestSceneSwellJudgements()
+ : base(new TaikoRuleset())
+ {
+ }
+
+ [Test]
+ public void TestZeroTickTimeOffsets()
+ {
+ AddUntilStep("gameplay finished", () => Player.ScoreProcessor.HasCompleted);
+ AddAssert("all tick offsets are 0", () => Player.Results.Where(r => r.Judgement is TaikoSwellTickJudgement).All(r => r.TimeOffset == 0));
+ }
+
+ protected override bool Autoplay => true;
+
+ protected override IBeatmap CreateBeatmap(RulesetInfo ruleset)
+ {
+ var beatmap = new Beatmap
+ {
+ BeatmapInfo = { Ruleset = new TaikoRuleset().RulesetInfo },
+ HitObjects =
+ {
+ new Swell
+ {
+ StartTime = 1000,
+ Duration = 1000,
+ }
+ }
+ };
+
+ return beatmap;
+ }
+
+ protected override Player CreatePlayer(Ruleset ruleset) => new TestPlayer();
+
+ protected class TestPlayer : Player
+ {
+ public readonly List Results = new List();
+
+ public new ScoreProcessor ScoreProcessor => base.ScoreProcessor;
+
+ public TestPlayer()
+ : base(false, false)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ ScoreProcessor.NewJudgement += r => Results.Add(r);
+ }
+ }
+ }
+}
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 a5db1625d9..d2a0a8fa6f 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/DrawableSwellTick.cs b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs
index 8b27d78101..ce875ebba8 100644
--- a/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs
+++ b/osu.Game.Rulesets.Taiko/Objects/Drawables/DrawableSwellTick.cs
@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Framework.Graphics;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Taiko.Objects.Drawables
@@ -14,7 +15,13 @@ namespace osu.Game.Rulesets.Taiko.Objects.Drawables
{
}
- public void TriggerResult(HitResult type) => ApplyResult(r => r.Type = type);
+ protected override void UpdateInitialTransforms() => this.FadeOut();
+
+ public void TriggerResult(HitResult type)
+ {
+ HitObject.StartTime = Time.Current;
+ ApplyResult(r => r.Type = type);
+ }
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
new file mode 100644
index 0000000000..f20440249b
--- /dev/null
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneBarHitErrorMeter.cs
@@ -0,0 +1,119 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Rulesets.Catch.Objects;
+using System;
+using System.Collections.Generic;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Scoring;
+using osu.Framework.MathUtils;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Screens.Play.HUD.HitErrorMeters;
+
+namespace osu.Game.Tests.Visual.Gameplay
+{
+ public class TestSceneBarHitErrorMeter : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(HitErrorMeter),
+ };
+
+ private HitErrorMeter meter;
+ private HitErrorMeter meter2;
+ private HitWindows hitWindows;
+
+ public TestSceneBarHitErrorMeter()
+ {
+ recreateDisplay(new OsuHitWindows(), 5);
+
+ AddRepeatStep("New random judgement", () => newJudgement(), 40);
+
+ AddRepeatStep("New max negative", () => newJudgement(-hitWindows.HalfWindowFor(HitResult.Meh)), 20);
+ AddRepeatStep("New max positive", () => newJudgement(hitWindows.HalfWindowFor(HitResult.Meh)), 20);
+ AddStep("New fixed judgement (50ms)", () => newJudgement(50));
+ }
+
+ [Test]
+ public void TestOsu()
+ {
+ AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1));
+ AddStep("OD 10", () => recreateDisplay(new OsuHitWindows(), 10));
+ }
+
+ [Test]
+ public void TestTaiko()
+ {
+ AddStep("OD 1", () => recreateDisplay(new TaikoHitWindows(), 1));
+ AddStep("OD 10", () => recreateDisplay(new TaikoHitWindows(), 10));
+ }
+
+ [Test]
+ public void TestMania()
+ {
+ AddStep("OD 1", () => recreateDisplay(new ManiaHitWindows(), 1));
+ AddStep("OD 10", () => recreateDisplay(new ManiaHitWindows(), 10));
+ }
+
+ [Test]
+ public void TestCatch()
+ {
+ AddStep("OD 1", () => recreateDisplay(new CatchHitWindows(), 1));
+ AddStep("OD 10", () => recreateDisplay(new CatchHitWindows(), 10));
+ }
+
+ private void recreateDisplay(HitWindows hitWindows, float overallDifficulty)
+ {
+ this.hitWindows = hitWindows;
+
+ hitWindows?.SetDifficulty(overallDifficulty);
+
+ Clear();
+
+ Add(new FillFlowContainer
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Direction = FillDirection.Vertical,
+ AutoSizeAxes = Axes.Both,
+ Children = new[]
+ {
+ new SpriteText { Text = $@"Great: {hitWindows?.Great}" },
+ new SpriteText { Text = $@"Good: {hitWindows?.Good}" },
+ new SpriteText { Text = $@"Meh: {hitWindows?.Meh}" },
+ }
+ });
+
+ Add(meter = new BarHitErrorMeter(hitWindows, true)
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ });
+
+ Add(meter2 = new BarHitErrorMeter(hitWindows, false)
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ });
+ }
+
+ private void newJudgement(double offset = 0)
+ {
+ var judgement = new JudgementResult(new Judgement())
+ {
+ TimeOffset = offset == 0 ? RNG.Next(-150, 150) : offset,
+ Type = HitResult.Perfect,
+ };
+
+ meter.OnNewJudgement(judgement);
+ meter2.OnNewJudgement(judgement);
+ }
+ }
+}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
index 8f19df65a9..ee9e088dcc 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneBeatmapSetOverlay.cs
@@ -176,6 +176,8 @@ namespace osu.Game.Tests.Visual.Online
HasVideo = true,
HasStoryboard = true,
Covers = new BeatmapSetOnlineCovers(),
+ Language = new BeatmapSetOnlineLanguage { Id = 3, Name = "English" },
+ Genre = new BeatmapSetOnlineGenre { Id = 4, Name = "Rock" },
},
Metrics = new BeatmapSetMetrics { Ratings = Enumerable.Range(0, 11).ToArray() },
Beatmaps = new List
diff --git a/osu.Game.Tests/osu.Game.Tests.csproj b/osu.Game.Tests/osu.Game.Tests.csproj
index 4a9d88f3a6..84f67c9319 100644
--- a/osu.Game.Tests/osu.Game.Tests.csproj
+++ b/osu.Game.Tests/osu.Game.Tests.csproj
@@ -5,7 +5,7 @@
-
+
diff --git a/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj b/osu.Game.Tournament.Tests/osu.Game.Tournament.Tests.csproj
index 2a8bd393da..bba3c92245 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/BeatmapSetOnlineInfo.cs b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
index df3a45d1cc..06dee4d3f5 100644
--- a/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
+++ b/osu.Game/Beatmaps/BeatmapSetOnlineInfo.cs
@@ -75,6 +75,28 @@ namespace osu.Game.Beatmaps
/// The availability of this beatmap set.
///
public BeatmapSetOnlineAvailability Availability { get; set; }
+
+ ///
+ /// The song genre of this beatmap set.
+ ///
+ public BeatmapSetOnlineGenre Genre { get; set; }
+
+ ///
+ /// The song language of this beatmap set.
+ ///
+ public BeatmapSetOnlineLanguage Language { get; set; }
+ }
+
+ public class BeatmapSetOnlineGenre
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
+ }
+
+ public class BeatmapSetOnlineLanguage
+ {
+ public int Id { get; set; }
+ public string Name { get; set; }
}
public class BeatmapSetOnlineCovers
diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs
index fb472f3f89..0cecbb225f 100644
--- a/osu.Game/Configuration/OsuConfigManager.cs
+++ b/osu.Game/Configuration/OsuConfigManager.cs
@@ -83,6 +83,7 @@ namespace osu.Game.Configuration
Set(OsuSetting.ShowInterface, true);
Set(OsuSetting.ShowHealthDisplayWhenCantFail, true);
Set(OsuSetting.KeyOverlay, false);
+ Set(OsuSetting.ScoreMeter, ScoreMeterType.HitErrorBoth);
Set(OsuSetting.FloatingComments, false);
@@ -136,6 +137,7 @@ namespace osu.Game.Configuration
BlurLevel,
ShowStoryboard,
KeyOverlay,
+ ScoreMeter,
FloatingComments,
ShowInterface,
ShowHealthDisplayWhenCantFail,
diff --git a/osu.Game/Configuration/ScoreMeterType.cs b/osu.Game/Configuration/ScoreMeterType.cs
index 21a63fb3ed..b85ef9309d 100644
--- a/osu.Game/Configuration/ScoreMeterType.cs
+++ b/osu.Game/Configuration/ScoreMeterType.cs
@@ -1,12 +1,22 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System.ComponentModel;
+
namespace osu.Game.Configuration
{
public enum ScoreMeterType
{
+ [Description("None")]
None,
- Colour,
- Error
+
+ [Description("Hit Error (left)")]
+ HitErrorLeft,
+
+ [Description("Hit Error (right)")]
+ HitErrorRight,
+
+ [Description("Hit Error (both)")]
+ HitErrorBoth,
}
}
diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
index e5bfde8f8f..1ca14256e5 100644
--- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
+++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs
@@ -69,6 +69,12 @@ namespace osu.Game.Online.API.Requests.Responses
[JsonProperty(@"availability")]
private BeatmapSetOnlineAvailability availability { get; set; }
+ [JsonProperty(@"genre")]
+ private BeatmapSetOnlineGenre genre { get; set; }
+
+ [JsonProperty(@"language")]
+ private BeatmapSetOnlineLanguage language { get; set; }
+
[JsonProperty(@"beatmaps")]
private IEnumerable beatmaps { get; set; }
@@ -95,6 +101,8 @@ namespace osu.Game.Online.API.Requests.Responses
LastUpdated = lastUpdated,
Availability = availability,
HasFavourited = hasFavourited,
+ Genre = genre,
+ Language = language
},
Beatmaps = beatmaps?.Select(b => b.ToBeatmap(rulesets)).ToList(),
};
diff --git a/osu.Game/Overlays/BeatmapSet/Info.cs b/osu.Game/Overlays/BeatmapSet/Info.cs
index 44827f0a0c..16d6236051 100644
--- a/osu.Game/Overlays/BeatmapSet/Info.cs
+++ b/osu.Game/Overlays/BeatmapSet/Info.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Overlays.BeatmapSet
public Info()
{
- MetadataSection source, tags;
+ MetadataSection source, tags, genre, language;
RelativeSizeAxes = Axes.X;
Height = 220;
Masking = true;
@@ -83,11 +83,12 @@ namespace osu.Game.Overlays.BeatmapSet
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- LayoutDuration = transition_duration,
+ Direction = FillDirection.Full,
Children = new[]
{
source = new MetadataSection("Source"),
+ genre = new MetadataSection("Genre") { Width = 0.5f },
+ language = new MetadataSection("Language") { Width = 0.5f },
tags = new MetadataSection("Tags"),
},
},
@@ -119,6 +120,8 @@ namespace osu.Game.Overlays.BeatmapSet
{
source.Text = b.NewValue?.Metadata.Source ?? string.Empty;
tags.Text = b.NewValue?.Metadata.Tags ?? string.Empty;
+ genre.Text = b.NewValue?.OnlineInfo?.Genre?.Name ?? string.Empty;
+ language.Text = b.NewValue?.OnlineInfo?.Language?.Name ?? string.Empty;
};
}
@@ -139,7 +142,7 @@ namespace osu.Game.Overlays.BeatmapSet
{
if (string.IsNullOrEmpty(value))
{
- this.FadeOut(transition_duration);
+ Hide();
return;
}
@@ -149,12 +152,6 @@ namespace osu.Game.Overlays.BeatmapSet
}
}
- public Color4 TextColour
- {
- get => textFlow.Colour;
- set => textFlow.Colour = value;
- }
-
public MetadataSection(string title)
{
RelativeSizeAxes = Axes.X;
diff --git a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs
index 4d77e5f93d..cb0639d85d 100644
--- a/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs
+++ b/osu.Game/Overlays/Chat/Selection/ChannelListItem.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Chat.Selection
private Color4 topicColour;
private Color4 hoverColour;
- public IEnumerable FilterTerms => new[] { channel.Name };
+ public IEnumerable FilterTerms => new[] { channel.Name, channel.Topic };
public bool MatchingFilter
{
diff --git a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs
index 24ed0cc022..c6d96c5917 100644
--- a/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs
+++ b/osu.Game/Overlays/Profile/Header/Components/RankGraph.cs
@@ -296,7 +296,11 @@ namespace osu.Game.Overlays.Profile.Header.Components
this.MoveTo(pos, 200, Easing.OutQuint);
}
- protected override void PopIn() => this.FadeIn(200, Easing.OutQuint);
+ protected override void PopIn()
+ {
+ instantMove |= !IsPresent;
+ this.FadeIn(200, Easing.OutQuint);
+ }
protected override void PopOut() => this.FadeOut(200, Easing.OutQuint);
}
diff --git a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs
index 9142492610..520a8852b3 100644
--- a/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/Gameplay/GeneralSettings.cs
@@ -44,6 +44,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
LabelText = "Always show key overlay",
Bindable = config.GetBindable(OsuSetting.KeyOverlay)
},
+ new SettingsEnumDropdown
+ {
+ LabelText = "Score meter type",
+ Bindable = config.GetBindable(OsuSetting.ScoreMeter)
+ },
new SettingsEnumDropdown
{
LabelText = "Score display mode",
diff --git a/osu.Game/Rulesets/Objects/HitWindows.cs b/osu.Game/Rulesets/Objects/HitWindows.cs
index fe099aaee7..e88af67c7c 100644
--- a/osu.Game/Rulesets/Objects/HitWindows.cs
+++ b/osu.Game/Rulesets/Objects/HitWindows.cs
@@ -65,6 +65,19 @@ namespace osu.Game.Rulesets.Objects
return HitResult.None;
}
+ ///
+ /// Retrieves a mapping of s to their half window timing for all allowed s.
+ ///
+ ///
+ public IEnumerable<(HitResult result, double length)> GetAllAvailableHalfWindows()
+ {
+ for (var result = HitResult.Meh; result <= HitResult.Perfect; ++result)
+ {
+ if (IsHitResultAllowed(result))
+ yield return (result, HalfWindowFor(result));
+ }
+ }
+
///
/// Check whether it is possible to achieve the provided .
///
diff --git a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
index e47df6b473..3b7e457990 100644
--- a/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
+++ b/osu.Game/Rulesets/Scoring/ScoreProcessor.cs
@@ -90,7 +90,7 @@ namespace osu.Game.Rulesets.Scoring
///
/// Whether all s have been processed.
///
- protected virtual bool HasCompleted => false;
+ public virtual bool HasCompleted => false;
///
/// Whether this ScoreProcessor has already triggered the failed state.
@@ -205,7 +205,7 @@ namespace osu.Game.Rulesets.Scoring
private const double combo_portion = 0.7;
private const double max_score = 1000000;
- protected sealed override bool HasCompleted => JudgedHits == MaxHits;
+ public sealed override bool HasCompleted => JudgedHits == MaxHits;
protected int MaxHits { get; private set; }
protected int JudgedHits { get; private set; }
diff --git a/osu.Game/Rulesets/UI/DrawableRuleset.cs b/osu.Game/Rulesets/UI/DrawableRuleset.cs
index 021bd515b5..0ee9196fb8 100644
--- a/osu.Game/Rulesets/UI/DrawableRuleset.cs
+++ b/osu.Game/Rulesets/UI/DrawableRuleset.cs
@@ -215,10 +215,6 @@ namespace osu.Game.Rulesets.UI
continueResume();
}
- public ResumeOverlay ResumeOverlay { get; private set; }
-
- protected virtual ResumeOverlay CreateResumeOverlay() => null;
-
///
/// Creates and adds the visual representation of a to this .
///
@@ -389,6 +385,13 @@ namespace osu.Game.Rulesets.UI
///
public abstract GameplayCursorContainer Cursor { get; }
+ ///
+ /// An optional overlay used when resuming gameplay from a paused state.
+ ///
+ public ResumeOverlay ResumeOverlay { get; protected set; }
+
+ protected virtual ResumeOverlay CreateResumeOverlay() => null;
+
///
/// Sets a replay to be used, overriding local input.
///
diff --git a/osu.Game/Screens/Edit/BindableBeatDivisor.cs b/osu.Game/Screens/Edit/BindableBeatDivisor.cs
index ea3b68e3bd..2aeb1ef04b 100644
--- a/osu.Game/Screens/Edit/BindableBeatDivisor.cs
+++ b/osu.Game/Screens/Edit/BindableBeatDivisor.cs
@@ -4,6 +4,9 @@
using System;
using System.Linq;
using osu.Framework.Bindables;
+using osu.Framework.Graphics.Colour;
+using osu.Game.Graphics;
+using osuTK.Graphics;
namespace osu.Game.Screens.Edit
{
@@ -35,5 +38,41 @@ namespace osu.Game.Screens.Edit
protected override int DefaultMinValue => VALID_DIVISORS.First();
protected override int DefaultMaxValue => VALID_DIVISORS.Last();
protected override int DefaultPrecision => 1;
+
+ ///
+ /// Retrieves the appropriate colour for a beat divisor.
+ ///
+ /// The beat divisor.
+ /// The set of colours.
+ /// The applicable colour from for .
+ public static ColourInfo GetColourFor(int beatDivisor, OsuColour colours)
+ {
+ switch (beatDivisor)
+ {
+ case 2:
+ return colours.BlueLight;
+
+ case 4:
+ return colours.Blue;
+
+ case 8:
+ return colours.BlueDarker;
+
+ case 16:
+ return colours.PurpleDark;
+
+ case 3:
+ return colours.YellowLight;
+
+ case 6:
+ return colours.Yellow;
+
+ case 12:
+ return colours.YellowDarker;
+
+ default:
+ return Color4.White;
+ }
+ }
}
}
diff --git a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
index 0d16d8474b..4d89e43ee5 100644
--- a/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/BeatDivisorControl.cs
@@ -188,6 +188,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
private Marker marker;
+ [Resolved]
+ private OsuColour colours { get; set; }
+
private readonly BindableBeatDivisor beatDivisor;
private readonly int[] availableDivisors;
@@ -204,11 +207,12 @@ namespace osu.Game.Screens.Edit.Compose.Components
{
foreach (var t in availableDivisors)
{
- AddInternal(new Tick(t)
+ AddInternal(new Tick
{
Anchor = Anchor.TopLeft,
Origin = Anchor.TopCentre,
RelativePositionAxes = Axes.X,
+ Colour = BindableBeatDivisor.GetColourFor(t, colours),
X = getMappedPosition(t)
});
}
@@ -284,11 +288,8 @@ namespace osu.Game.Screens.Edit.Compose.Components
private class Tick : CompositeDrawable
{
- private readonly int divisor;
-
- public Tick(int divisor)
+ public Tick()
{
- this.divisor = divisor;
Size = new Vector2(2.5f, 10);
InternalChild = new Box { RelativeSizeAxes = Axes.Both };
@@ -296,42 +297,6 @@ namespace osu.Game.Screens.Edit.Compose.Components
CornerRadius = 0.5f;
Masking = true;
}
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- Colour = getColourForDivisor(divisor, colours);
- }
-
- private ColourInfo getColourForDivisor(int divisor, OsuColour colours)
- {
- switch (divisor)
- {
- case 2:
- return colours.BlueLight;
-
- case 4:
- return colours.Blue;
-
- case 8:
- return colours.BlueDarker;
-
- case 16:
- return colours.PurpleDark;
-
- case 3:
- return colours.YellowLight;
-
- case 6:
- return colours.Yellow;
-
- case 12:
- return colours.YellowDarker;
-
- default:
- return Color4.White;
- }
- }
}
private class Marker : CompositeDrawable
diff --git a/osu.Game/Screens/Menu/IntroCircles.cs b/osu.Game/Screens/Menu/IntroCircles.cs
index 4fa1a81123..c069f82134 100644
--- a/osu.Game/Screens/Menu/IntroCircles.cs
+++ b/osu.Game/Screens/Menu/IntroCircles.cs
@@ -77,7 +77,7 @@ namespace osu.Game.Screens.Menu
Scheduler.AddDelayed(delegate
{
- // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Manu.
+ // Only start the current track if it is the menu music. A beatmap's track is started when entering the Main Menu.
if (menuMusic.Value)
{
track.Restart();
diff --git a/osu.Game/Screens/Menu/LogoVisualisation.cs b/osu.Game/Screens/Menu/LogoVisualisation.cs
index 9d0a5cd05b..6984959e9c 100644
--- a/osu.Game/Screens/Menu/LogoVisualisation.cs
+++ b/osu.Game/Screens/Menu/LogoVisualisation.cs
@@ -47,7 +47,7 @@ namespace osu.Game.Screens.Menu
private const float visualiser_rounds = 5;
///
- /// How much should each bar go down each milisecond (based on a full bar).
+ /// How much should each bar go down each millisecond (based on a full bar).
///
private const float decay_per_milisecond = 0.0024f;
@@ -161,7 +161,7 @@ namespace osu.Game.Screens.Menu
private IShader shader;
private Texture texture;
- //Asuming the logo is a circle, we don't need a second dimension.
+ //Assuming the logo is a circle, we don't need a second dimension.
private float size;
private Color4 colour;
diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs
index 0c5bf12bdb..534400e720 100644
--- a/osu.Game/Screens/Menu/OsuLogo.cs
+++ b/osu.Game/Screens/Menu/OsuLogo.cs
@@ -229,7 +229,7 @@ namespace osu.Game.Screens.Menu
}
///
- /// Schedule a new extenral animation. Handled queueing and finishing previous animations in a sane way.
+ /// Schedule a new external animation. Handled queueing and finishing previous animations in a sane way.
///
/// The animation to be performed
/// If true, the new animation is delayed until all previous transforms finish. If false, existing transformed are cleared.
diff --git a/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs
new file mode 100644
index 0000000000..cdfa0e993b
--- /dev/null
+++ b/osu.Game/Screens/Play/HUD/HitErrorDisplay.cs
@@ -0,0 +1,100 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Extensions.IEnumerableExtensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Configuration;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Screens.Play.HUD.HitErrorMeters;
+
+namespace osu.Game.Screens.Play.HUD
+{
+ public class HitErrorDisplay : Container
+ {
+ private const int fade_duration = 200;
+ private const int margin = 10;
+
+ private readonly Bindable type = new Bindable();
+
+ private readonly HitWindows hitWindows;
+
+ private readonly ScoreProcessor processor;
+
+ public HitErrorDisplay(ScoreProcessor processor, HitWindows hitWindows)
+ {
+ this.processor = processor;
+ this.hitWindows = hitWindows;
+
+ RelativeSizeAxes = Axes.Both;
+
+ processor.NewJudgement += onNewJudgement;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuConfigManager config)
+ {
+ config.BindWith(OsuSetting.ScoreMeter, type);
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ type.BindValueChanged(typeChanged, true);
+ }
+
+ private void onNewJudgement(JudgementResult result)
+ {
+ foreach (var c in Children)
+ c.OnNewJudgement(result);
+ }
+
+ private void typeChanged(ValueChangedEvent type)
+ {
+ Children.ForEach(c => c.FadeOut(fade_duration, Easing.OutQuint));
+
+ if (hitWindows == null)
+ return;
+
+ switch (type.NewValue)
+ {
+ case ScoreMeterType.HitErrorBoth:
+ createBar(false);
+ createBar(true);
+ break;
+
+ case ScoreMeterType.HitErrorLeft:
+ createBar(false);
+ break;
+
+ case ScoreMeterType.HitErrorRight:
+ createBar(true);
+ break;
+ }
+ }
+
+ private void createBar(bool rightAligned)
+ {
+ var display = new BarHitErrorMeter(hitWindows, rightAligned)
+ {
+ Margin = new MarginPadding(margin),
+ Anchor = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft,
+ Origin = rightAligned ? Anchor.CentreRight : Anchor.CentreLeft,
+ Alpha = 0,
+ };
+
+ Add(display);
+ display.FadeInFromZero(fade_duration, Easing.OutQuint);
+ }
+
+ protected override void Dispose(bool isDisposing)
+ {
+ base.Dispose(isDisposing);
+ processor.NewJudgement -= onNewJudgement;
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs
new file mode 100644
index 0000000000..594dd64e52
--- /dev/null
+++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs
@@ -0,0 +1,284 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using System.Linq;
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Colour;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Graphics;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Scoring;
+using osuTK;
+using osuTK.Graphics;
+
+namespace osu.Game.Screens.Play.HUD.HitErrorMeters
+{
+ public class BarHitErrorMeter : HitErrorMeter
+ {
+ private readonly Anchor alignment;
+
+ private const int arrow_move_duration = 400;
+
+ private const int judgement_line_width = 6;
+
+ private const int bar_height = 200;
+
+ private const int bar_width = 2;
+
+ private const int spacing = 2;
+
+ private const float chevron_size = 8;
+
+ private SpriteIcon arrow;
+
+ private Container colourBarsEarly;
+ private Container colourBarsLate;
+
+ private Container judgementsContainer;
+
+ private double maxHitWindow;
+
+ public BarHitErrorMeter(HitWindows hitWindows, bool rightAligned = false)
+ : base(hitWindows)
+ {
+ alignment = rightAligned ? Anchor.x0 : Anchor.x2;
+
+ AutoSizeAxes = Axes.Both;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(OsuColour colours)
+ {
+ InternalChild = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.X,
+ Height = bar_height,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(spacing, 0),
+ Margin = new MarginPadding(2),
+ Children = new Drawable[]
+ {
+ judgementsContainer = new Container
+ {
+ Anchor = Anchor.y1 | alignment,
+ Origin = Anchor.y1 | alignment,
+ Width = judgement_line_width,
+ RelativeSizeAxes = Axes.Y,
+ },
+ colourBars = new Container
+ {
+ Width = bar_width,
+ RelativeSizeAxes = Axes.Y,
+ Anchor = Anchor.y1 | alignment,
+ Origin = Anchor.y1 | alignment,
+ Children = new Drawable[]
+ {
+ colourBarsEarly = new Container
+ {
+ Anchor = Anchor.y1 | alignment,
+ Origin = alignment,
+ RelativeSizeAxes = Axes.Both,
+ Height = 0.5f,
+ Scale = new Vector2(1, -1),
+ },
+ colourBarsLate = new Container
+ {
+ Anchor = Anchor.y1 | alignment,
+ Origin = alignment,
+ RelativeSizeAxes = Axes.Both,
+ Height = 0.5f,
+ },
+ new SpriteIcon
+ {
+ Y = -10,
+ Size = new Vector2(10),
+ Icon = FontAwesome.Solid.ShippingFast,
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ },
+ new SpriteIcon
+ {
+ Y = 10,
+ Size = new Vector2(10),
+ Icon = FontAwesome.Solid.Bicycle,
+ Anchor = Anchor.BottomCentre,
+ Origin = Anchor.BottomCentre,
+ }
+ }
+ },
+ new Container
+ {
+ Anchor = Anchor.y1 | alignment,
+ Origin = Anchor.y1 | alignment,
+ Width = chevron_size,
+ RelativeSizeAxes = Axes.Y,
+ Child = arrow = new SpriteIcon
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.Centre,
+ RelativePositionAxes = Axes.Y,
+ Y = 0.5f,
+ Icon = alignment == Anchor.x2 ? FontAwesome.Solid.ChevronRight : FontAwesome.Solid.ChevronLeft,
+ Size = new Vector2(chevron_size),
+ }
+ },
+ }
+ };
+
+ createColourBars(colours);
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ colourBars.Height = 0;
+ colourBars.ResizeHeightTo(1, 800, Easing.OutQuint);
+
+ arrow.Alpha = 0;
+ arrow.Delay(200).FadeInFromZero(600);
+ }
+
+ private void createColourBars(OsuColour colours)
+ {
+ var windows = HitWindows.GetAllAvailableHalfWindows().ToArray();
+
+ maxHitWindow = windows.First().length;
+
+ for (var i = 0; i < windows.Length; i++)
+ {
+ var (result, length) = windows[i];
+
+ colourBarsEarly.Add(createColourBar(result, (float)(length / maxHitWindow), i == 0));
+ colourBarsLate.Add(createColourBar(result, (float)(length / maxHitWindow), i == 0));
+ }
+
+ // a little nub to mark the centre point.
+ var centre = createColourBar(windows.Last().result, 0.01f);
+ centre.Anchor = centre.Origin = Anchor.y1 | (alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2);
+ centre.Width = 2.5f;
+ colourBars.Add(centre);
+
+ Color4 getColour(HitResult result)
+ {
+ switch (result)
+ {
+ case HitResult.Meh:
+ return colours.Yellow;
+
+ case HitResult.Ok:
+ return colours.Green;
+
+ case HitResult.Good:
+ return colours.GreenLight;
+
+ case HitResult.Great:
+ return colours.Blue;
+
+ default:
+ return colours.BlueLight;
+ }
+ }
+
+ Drawable createColourBar(HitResult result, float height, bool first = false)
+ {
+ var colour = getColour(result);
+
+ if (first)
+ {
+ // the first bar needs gradient rendering.
+ const float gradient_start = 0.8f;
+
+ return new Container
+ {
+ RelativeSizeAxes = Axes.Both,
+ Children = new Drawable[]
+ {
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = getColour(result),
+ Height = height * gradient_start
+ },
+ new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ RelativePositionAxes = Axes.Both,
+ Colour = ColourInfo.GradientVertical(colour, colour.Opacity(0)),
+ Y = gradient_start,
+ Height = height * (1 - gradient_start)
+ },
+ }
+ };
+ }
+
+ return new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = colour,
+ Height = height
+ };
+ }
+ }
+
+ private double floatingAverage;
+ private Container colourBars;
+
+ public override void OnNewJudgement(JudgementResult judgement)
+ {
+ if (!judgement.IsHit)
+ return;
+
+ judgementsContainer.Add(new JudgementLine
+ {
+ Y = getRelativeJudgementPosition(judgement.TimeOffset),
+ Anchor = alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2,
+ Origin = Anchor.y1 | (alignment == Anchor.x2 ? Anchor.x0 : Anchor.x2),
+ });
+
+ arrow.MoveToY(
+ getRelativeJudgementPosition(floatingAverage = floatingAverage * 0.9 + judgement.TimeOffset * 0.1)
+ , arrow_move_duration, Easing.Out);
+ }
+
+ private float getRelativeJudgementPosition(double value) => (float)((value / maxHitWindow) + 1) / 2;
+
+ private class JudgementLine : CompositeDrawable
+ {
+ private const int judgement_fade_duration = 10000;
+
+ public JudgementLine()
+ {
+ RelativeSizeAxes = Axes.X;
+ RelativePositionAxes = Axes.Y;
+ Height = 3;
+
+ InternalChild = new CircularContainer
+ {
+ Masking = true,
+ RelativeSizeAxes = Axes.Both,
+ Child = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = Color4.White,
+ }
+ };
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+
+ Width = 0;
+
+ this.ResizeWidthTo(1, 200, Easing.OutElasticHalf);
+ this.FadeTo(0.8f, 150).Then().FadeOut(judgement_fade_duration, Easing.OutQuint).Expire();
+ }
+ }
+ }
+}
diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs
new file mode 100644
index 0000000000..da1d9fff0d
--- /dev/null
+++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs
@@ -0,0 +1,21 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Graphics.Containers;
+using osu.Game.Rulesets.Judgements;
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Screens.Play.HUD.HitErrorMeters
+{
+ public abstract class HitErrorMeter : CompositeDrawable
+ {
+ protected readonly HitWindows HitWindows;
+
+ protected HitErrorMeter(HitWindows hitWindows)
+ {
+ HitWindows = hitWindows;
+ }
+
+ public abstract void OnNewJudgement(JudgementResult judgement);
+ }
+}
diff --git a/osu.Game/Screens/Play/HUDOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs
index 43b9491750..8e642ea552 100644
--- a/osu.Game/Screens/Play/HUDOverlay.cs
+++ b/osu.Game/Screens/Play/HUDOverlay.cs
@@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
+using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@@ -33,6 +34,7 @@ namespace osu.Game.Screens.Play
public readonly HealthDisplay HealthDisplay;
public readonly SongProgress Progress;
public readonly ModDisplay ModDisplay;
+ public readonly HitErrorDisplay HitErrorDisplay;
public readonly HoldForMenuButton HoldToQuit;
public readonly PlayerSettingsOverlay PlayerSettingsOverlay;
@@ -84,6 +86,7 @@ namespace osu.Game.Screens.Play
HealthDisplay = CreateHealthDisplay(),
Progress = CreateProgress(),
ModDisplay = CreateModsContainer(),
+ HitErrorDisplay = CreateHitErrorDisplayOverlay(),
}
},
PlayerSettingsOverlay = CreatePlayerSettingsOverlay(),
@@ -256,6 +259,8 @@ namespace osu.Game.Screens.Play
Margin = new MarginPadding { Top = 20, Right = 10 },
};
+ protected virtual HitErrorDisplay CreateHitErrorDisplayOverlay() => new HitErrorDisplay(scoreProcessor, drawableRuleset.Objects.FirstOrDefault()?.HitWindows);
+
protected virtual PlayerSettingsOverlay CreatePlayerSettingsOverlay() => new PlayerSettingsOverlay();
protected virtual void BindProcessor(ScoreProcessor processor)
diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs
index b487f3e61b..3f1603eabe 100644
--- a/osu.Game/Screens/Play/Player.cs
+++ b/osu.Game/Screens/Play/Player.cs
@@ -178,6 +178,7 @@ namespace osu.Game.Screens.Play
},
// display the cursor above some HUD elements.
DrawableRuleset.Cursor?.CreateProxy() ?? new Container(),
+ DrawableRuleset.ResumeOverlay?.CreateProxy() ?? new Container(),
HUDOverlay = new HUDOverlay(ScoreProcessor, DrawableRuleset, Mods.Value)
{
HoldToQuit =
diff --git a/osu.Game/Skinning/DefaultSkin.cs b/osu.Game/Skinning/DefaultSkin.cs
index f917514877..9eda5d597a 100644
--- a/osu.Game/Skinning/DefaultSkin.cs
+++ b/osu.Game/Skinning/DefaultSkin.cs
@@ -13,7 +13,7 @@ namespace osu.Game.Skinning
public DefaultSkin()
: base(SkinInfo.Default)
{
- Configuration = new SkinConfiguration();
+ Configuration = new DefaultSkinConfiguration();
}
public override Drawable GetDrawableComponent(ISkinComponent component) => null;
diff --git a/osu.Game/Skinning/DefaultSkinConfiguration.cs b/osu.Game/Skinning/DefaultSkinConfiguration.cs
new file mode 100644
index 0000000000..722b35f102
--- /dev/null
+++ b/osu.Game/Skinning/DefaultSkinConfiguration.cs
@@ -0,0 +1,28 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osuTK.Graphics;
+
+namespace osu.Game.Skinning
+{
+ ///
+ /// A skin configuration pre-populated with sane defaults.
+ ///
+ public class DefaultSkinConfiguration : SkinConfiguration
+ {
+ public DefaultSkinConfiguration()
+ {
+ HitCircleFont = "default";
+
+ ComboColours.AddRange(new[]
+ {
+ new Color4(17, 136, 170, 255),
+ new Color4(102, 136, 0, 255),
+ new Color4(204, 102, 0, 255),
+ new Color4(121, 9, 13, 255)
+ });
+
+ CursorExpand = true;
+ }
+ }
+}
diff --git a/osu.Game/Skinning/LegacySkin.cs b/osu.Game/Skinning/LegacySkin.cs
index e51bf8245c..27d47befca 100644
--- a/osu.Game/Skinning/LegacySkin.cs
+++ b/osu.Game/Skinning/LegacySkin.cs
@@ -35,7 +35,7 @@ namespace osu.Game.Skinning
using (StreamReader reader = new StreamReader(stream))
Configuration = new LegacySkinDecoder().Decode(reader);
else
- Configuration = new SkinConfiguration();
+ Configuration = new DefaultSkinConfiguration();
Samples = audioManager.GetSampleStore(storage);
Textures = new TextureStore(new TextureLoaderStore(storage));
diff --git a/osu.Game/Skinning/LegacySkinDecoder.cs b/osu.Game/Skinning/LegacySkinDecoder.cs
index ecb112955c..0160755eed 100644
--- a/osu.Game/Skinning/LegacySkinDecoder.cs
+++ b/osu.Game/Skinning/LegacySkinDecoder.cs
@@ -5,14 +5,14 @@ using osu.Game.Beatmaps.Formats;
namespace osu.Game.Skinning
{
- public class LegacySkinDecoder : LegacyDecoder
+ public class LegacySkinDecoder : LegacyDecoder
{
public LegacySkinDecoder()
: base(1)
{
}
- protected override void ParseLine(SkinConfiguration skin, Section section, string line)
+ protected override void ParseLine(DefaultSkinConfiguration skin, Section section, string line)
{
line = StripComments(line);
diff --git a/osu.Game/Skinning/SkinConfiguration.cs b/osu.Game/Skinning/SkinConfiguration.cs
index 93b599f9f6..d585c58ef1 100644
--- a/osu.Game/Skinning/SkinConfiguration.cs
+++ b/osu.Game/Skinning/SkinConfiguration.cs
@@ -7,21 +7,18 @@ using osuTK.Graphics;
namespace osu.Game.Skinning
{
+ ///
+ /// An empty skin configuration.
+ ///
public class SkinConfiguration : IHasComboColours, IHasCustomColours
{
public readonly SkinInfo SkinInfo = new SkinInfo();
- public List ComboColours { get; set; } = new List
- {
- new Color4(17, 136, 170, 255),
- new Color4(102, 136, 0, 255),
- new Color4(204, 102, 0, 255),
- new Color4(121, 9, 13, 255)
- };
+ public List ComboColours { get; set; } = new List();
public Dictionary CustomColours { get; set; } = new Dictionary();
- public string HitCircleFont { get; set; } = "default";
+ public string HitCircleFont { get; set; }
public int HitCircleOverlap { get; set; }
@@ -29,6 +26,6 @@ namespace osu.Game.Skinning
public float? SliderPathRadius { get; set; }
- public bool? CursorExpand { get; set; } = true;
+ public bool? CursorExpand { get; set; }
}
}
diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs
index 1ab20ecd48..ccd996098c 100644
--- a/osu.Game/Tests/Visual/PlayerTestScene.cs
+++ b/osu.Game/Tests/Visual/PlayerTestScene.cs
@@ -3,6 +3,7 @@
using System.Linq;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Testing;
using osu.Game.Configuration;
using osu.Game.Rulesets;
@@ -40,6 +41,8 @@ namespace osu.Game.Tests.Visual
protected virtual bool AllowFail => false;
+ protected virtual bool Autoplay => false;
+
private void loadPlayer()
{
var beatmap = CreateBeatmap(ruleset.RulesetInfo);
@@ -49,6 +52,13 @@ namespace osu.Game.Tests.Visual
if (!AllowFail)
Mods.Value = new[] { ruleset.GetAllMods().First(m => m is ModNoFail) };
+ if (Autoplay)
+ {
+ var mod = ruleset.GetAutoplayMod();
+ if (mod != null)
+ Mods.Value = Mods.Value.Concat(mod.Yield()).ToArray();
+ }
+
Player = CreatePlayer(ruleset);
LoadScreen(Player);
}
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 8e6ce2d1ba..330018d5cb 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 47cc6ec97a..9f8d82ad1e 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -118,8 +118,8 @@
-
-
+
+