diff --git a/osu.Android.props b/osu.Android.props
index 6a8e66ee6a..f623a92ade 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
new file mode 100644
index 0000000000..47e91e50d4
--- /dev/null
+++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
@@ -0,0 +1,54 @@
+// 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.Catch.Mods;
+using osu.Game.Rulesets.Catch.Objects;
+using osu.Game.Rulesets.Objects;
+using osu.Game.Rulesets.Objects.Types;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Catch.Tests.Mods
+{
+ public class TestSceneCatchModPerfect : ModPerfectTestScene
+ {
+ public TestSceneCatchModPerfect()
+ : base(new CatchRuleset(), new CatchModPerfect())
+ {
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestBananaShower(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new BananaShower { StartTime = 1000, EndTime = 3000 }, false), shouldMiss);
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestFruit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Fruit { StartTime = 1000 }), shouldMiss);
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestJuiceStream(bool shouldMiss)
+ {
+ var stream = new JuiceStream
+ {
+ StartTime = 1000,
+ Path = new SliderPath(PathType.Linear, new[]
+ {
+ Vector2.Zero,
+ new Vector2(100, 0),
+ })
+ };
+
+ CreateHitObjectTest(new HitObjectTestData(stream), shouldMiss);
+ }
+
+ // We only care about testing misses, hits are tested via JuiceStream
+ [TestCase(true)]
+ public void TestDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Droplet { StartTime = 1000 }), shouldMiss);
+
+ // We only care about testing misses, hits are tested via JuiceStream
+ [TestCase(true)]
+ public void TestTinyDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new TinyDroplet { StartTime = 1000 }), shouldMiss);
+ }
+}
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
index 20911b8d06..024c4cefb0 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneBananaShower.cs
@@ -18,7 +18,9 @@ namespace osu.Game.Rulesets.Catch.Tests
public override IReadOnlyList RequiredTypes => new[]
{
typeof(BananaShower),
+ typeof(Banana),
typeof(DrawableBananaShower),
+ typeof(DrawableBanana),
typeof(CatchRuleset),
typeof(DrawableCatchRuleset),
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
index caaad2f704..cf68c5424d 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneCatcherArea.cs
@@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using System;
-using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
@@ -28,11 +26,6 @@ namespace osu.Game.Rulesets.Catch.Tests
{
private RulesetInfo catchRuleset;
- public override IReadOnlyList RequiredTypes => new[]
- {
- typeof(CatcherArea),
- };
-
public TestSceneCatcherArea()
{
AddSliderStep("CircleSize", 0, 8, 5, createCatcher);
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
index 070847c0c1..304c7e3854 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneDrawableHitObjects.cs
@@ -4,7 +4,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
-using osu.Framework.Allocation;
+using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Beatmaps;
@@ -34,8 +34,8 @@ namespace osu.Game.Rulesets.Catch.Tests
private DrawableCatchRuleset drawableRuleset;
private double playfieldTime => drawableRuleset.Playfield.Time.Current;
- [BackgroundDependencyLoader]
- private void load()
+ [SetUp]
+ public void Setup() => Schedule(() =>
{
var controlPointInfo = new ControlPointInfo();
controlPointInfo.Add(0, new TimingControlPoint());
@@ -57,7 +57,7 @@ namespace osu.Game.Rulesets.Catch.Tests
ControlPointInfo = controlPointInfo
});
- Add(new Container
+ Child = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
@@ -66,16 +66,49 @@ namespace osu.Game.Rulesets.Catch.Tests
{
drawableRuleset = new DrawableCatchRuleset(new CatchRuleset(), beatmap.GetPlayableBeatmap(new CatchRuleset().RulesetInfo))
}
- });
+ };
+ });
+
+ [Test]
+ public void TestFruits()
+ {
+ AddStep("hit fruits", () => spawnFruits(true));
+ AddUntilStep("wait for completion", () => playfieldIsEmpty);
+ AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
AddStep("miss fruits", () => spawnFruits());
- AddStep("hit fruits", () => spawnFruits(true));
- AddStep("miss juicestream", () => spawnJuiceStream());
- AddStep("hit juicestream", () => spawnJuiceStream(true));
- AddStep("miss bananas", () => spawnBananas());
- AddStep("hit bananas", () => spawnBananas(true));
+ AddUntilStep("wait for completion", () => playfieldIsEmpty);
+ AddAssert("catcher state is failed", () => catcherState == CatcherAnimationState.Fail);
}
+ [Test]
+ public void TestJuicestream()
+ {
+ AddStep("hit juicestream", () => spawnJuiceStream(true));
+ AddUntilStep("wait for completion", () => playfieldIsEmpty);
+ AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
+
+ AddStep("miss juicestream", () => spawnJuiceStream());
+ AddUntilStep("wait for completion", () => playfieldIsEmpty);
+ AddAssert("catcher state is failed", () => catcherState == CatcherAnimationState.Fail);
+ }
+
+ [Test]
+ public void TestBananas()
+ {
+ AddStep("hit bananas", () => spawnBananas(true));
+ AddUntilStep("wait for completion", () => playfieldIsEmpty);
+ AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
+
+ AddStep("miss bananas", () => spawnBananas());
+ AddUntilStep("wait for completion", () => playfieldIsEmpty);
+ AddAssert("catcher state is idle", () => catcherState == CatcherAnimationState.Idle);
+ }
+
+ private bool playfieldIsEmpty => !((CatchPlayfield)drawableRuleset.Playfield).AllHitObjects.Any(h => h.IsAlive);
+
+ private CatcherAnimationState catcherState => ((CatchPlayfield)drawableRuleset.Playfield).CatcherArea.MovableCatcher.CurrentState;
+
private void spawnFruits(bool hit = false)
{
for (int i = 1; i <= 4; i++)
diff --git a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
index 7a7c3f4103..6f0d8f0a3a 100644
--- a/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
+++ b/osu.Game.Rulesets.Catch.Tests/TestSceneHyperDash.cs
@@ -2,19 +2,27 @@
// 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.Testing;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI;
+using osu.Game.Rulesets.Objects;
using osu.Game.Tests.Visual;
+using osuTK;
namespace osu.Game.Rulesets.Catch.Tests
{
[TestFixture]
public class TestSceneHyperDash : PlayerTestScene
{
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(CatcherArea),
+ };
+
public TestSceneHyperDash()
: base(new CatchRuleset())
{
@@ -26,9 +34,11 @@ namespace osu.Game.Rulesets.Catch.Tests
public void TestHyperDash()
{
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash);
- AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing);
+ AddUntilStep("wait for right movement", () => getCatcher().Scale.X > 0); // don't check hyperdashing as it happens too fast.
- for (int i = 0; i < 2; i++)
+ AddUntilStep("wait for left movement", () => getCatcher().Scale.X < 0);
+
+ for (int i = 0; i < 3; i++)
{
AddUntilStep("wait for right hyperdash", () => getCatcher().Scale.X > 0 && getCatcher().HyperDashing);
AddUntilStep("wait for left hyperdash", () => getCatcher().Scale.X < 0 && getCatcher().HyperDashing);
@@ -49,39 +59,51 @@ namespace osu.Game.Rulesets.Catch.Tests
};
// Should produce a hyper-dash (edge case test)
- beatmap.HitObjects.Add(new Fruit { StartTime = 1816, X = 308 / 512f, NewCombo = true });
- beatmap.HitObjects.Add(new JuiceStream { StartTime = 2008, X = 56 / 512f, });
+ beatmap.HitObjects.Add(new Fruit { StartTime = 1816, X = 56 / 512f, NewCombo = true });
+ beatmap.HitObjects.Add(new Fruit { StartTime = 2008, X = 308 / 512f, NewCombo = true });
double startTime = 3000;
const float left_x = 0.02f;
const float right_x = 0.98f;
- createObjects(() => new Fruit(), left_x);
- createObjects(() => new JuiceStream(), right_x);
- createObjects(() => new JuiceStream(), left_x);
- createObjects(() => new Fruit(), right_x);
- createObjects(() => new Fruit(), left_x);
- createObjects(() => new Fruit(), right_x);
- createObjects(() => new JuiceStream(), left_x);
+ createObjects(() => new Fruit { X = left_x });
+ createObjects(() => new TestJuiceStream(right_x), 1);
+ createObjects(() => new TestJuiceStream(left_x), 1);
+ createObjects(() => new Fruit { X = right_x });
+ createObjects(() => new Fruit { X = left_x });
+ createObjects(() => new Fruit { X = right_x });
+ createObjects(() => new TestJuiceStream(left_x), 1);
return beatmap;
- void createObjects(Func createObject, float x)
+ void createObjects(Func createObject, int count = 3)
{
const float spacing = 140;
- for (int i = 0; i < 3; i++)
+ for (int i = 0; i < count; i++)
{
var hitObject = createObject();
- hitObject.X = x;
hitObject.StartTime = startTime + i * spacing;
-
beatmap.HitObjects.Add(hitObject);
}
startTime += 700;
}
}
+
+ private class TestJuiceStream : JuiceStream
+ {
+ public TestJuiceStream(float x)
+ {
+ X = x;
+
+ Path = new SliderPath(new[]
+ {
+ new PathControlPoint(Vector2.Zero),
+ new PathControlPoint(new Vector2(30, 0)),
+ });
+ }
+ }
}
}
diff --git a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
index 1a5d0f983b..986dc9dbb9 100644
--- a/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
+++ b/osu.Game.Rulesets.Catch/Beatmaps/CatchBeatmapProcessor.cs
@@ -28,8 +28,6 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
ApplyPositionOffsets(Beatmap);
- initialiseHyperDash((List)Beatmap.HitObjects);
-
int index = 0;
foreach (var obj in Beatmap.HitObjects.OfType())
@@ -76,6 +74,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
break;
case JuiceStream juiceStream:
+ // Todo: BUG!! Stable used the last control point as the final position of the path, but it should use the computed path instead.
+ lastPosition = juiceStream.X + juiceStream.Path.ControlPoints[^1].Position.Value.X / CatchPlayfield.BASE_WIDTH;
+
+ // Todo: BUG!! Stable attempted to use the end time of the stream, but referenced it too early in execution and used the start time instead.
+ lastStartTime = juiceStream.StartTime;
+
foreach (var nested in juiceStream.NestedHitObjects)
{
var catchObject = (CatchHitObject)nested;
@@ -90,20 +94,12 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
break;
}
}
+
+ initialiseHyperDash(beatmap);
}
private static void applyHardRockOffset(CatchHitObject hitObject, ref float? lastPosition, ref double lastStartTime, FastRandom rng)
{
- if (hitObject is JuiceStream stream)
- {
- lastPosition = stream.EndX;
- lastStartTime = stream.EndTime;
- return;
- }
-
- if (!(hitObject is Fruit))
- return;
-
float offsetPosition = hitObject.X;
double startTime = hitObject.StartTime;
@@ -116,7 +112,9 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
}
float positionDiff = offsetPosition - lastPosition.Value;
- double timeDiff = startTime - lastStartTime;
+
+ // Todo: BUG!! Stable calculated time deltas as ints, which affects randomisation. This should be changed to a double.
+ int timeDiff = (int)(startTime - lastStartTime);
if (timeDiff > 1000)
{
@@ -132,7 +130,8 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
return;
}
- if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3d)
+ // ReSharper disable once PossibleLossOfFraction
+ if (Math.Abs(positionDiff * CatchPlayfield.BASE_WIDTH) < timeDiff / 3)
applyOffset(ref offsetPosition, positionDiff);
hitObject.XOffset = offsetPosition - hitObject.X;
@@ -191,14 +190,14 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
}
}
- private void initialiseHyperDash(List objects)
+ private static void initialiseHyperDash(IBeatmap beatmap)
{
List objectWithDroplets = new List();
- foreach (var currentObject in objects)
+ foreach (var currentObject in beatmap.HitObjects)
{
- if (currentObject is Fruit)
- objectWithDroplets.Add(currentObject);
+ if (currentObject is Fruit fruitObject)
+ objectWithDroplets.Add(fruitObject);
if (currentObject is JuiceStream)
{
@@ -212,7 +211,7 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
objectWithDroplets.Sort((h1, h2) => h1.StartTime.CompareTo(h2.StartTime));
- double halfCatcherWidth = CatcherArea.GetCatcherSize(Beatmap.BeatmapInfo.BaseDifficulty) / 2;
+ double halfCatcherWidth = CatcherArea.GetCatcherSize(beatmap.BeatmapInfo.BaseDifficulty) / 2;
int lastDirection = 0;
double lastExcess = halfCatcherWidth;
@@ -221,6 +220,10 @@ namespace osu.Game.Rulesets.Catch.Beatmaps
CatchHitObject currentObject = objectWithDroplets[i];
CatchHitObject nextObject = objectWithDroplets[i + 1];
+ // Reset variables in-case values have changed (e.g. after applying HR)
+ currentObject.HyperDashTarget = null;
+ currentObject.DistanceToHyperDash = 0;
+
int thisDirection = nextObject.X > currentObject.X ? 1 : -1;
double timeToNext = nextObject.StartTime - currentObject.StartTime - 1000f / 60f / 4; // 1/4th of a frame of grace time, taken from osu-stable
double distanceToNext = Math.Abs(nextObject.X - currentObject.X) - (lastDirection == thisDirection ? lastExcess : halfCatcherWidth);
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
index fb92399102..e3391c47f1 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
@@ -1,11 +1,17 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using osu.Game.Rulesets.Catch.Judgements;
+using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModPerfect : ModPerfect
{
+ protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
+ => !(result.Judgement is CatchBananaJudgement)
+ && base.FailCondition(healthProcessor, result);
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
index cf7231ebb2..01b76ceed9 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableBanana.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using osu.Framework.Graphics;
using osu.Framework.Utils;
using osuTK.Graphics;
@@ -22,6 +23,23 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
return colour ??= getBananaColour();
}
+ protected override void UpdateInitialTransforms()
+ {
+ base.UpdateInitialTransforms();
+
+ const float end_scale = 0.6f;
+ const float random_scale_range = 1.6f;
+
+ ScaleContainer.ScaleTo(HitObject.Scale * (end_scale + random_scale_range * RNG.NextSingle()))
+ .Then().ScaleTo(HitObject.Scale * end_scale, HitObject.TimePreempt);
+
+ ScaleContainer.RotateTo(getRandomAngle())
+ .Then()
+ .RotateTo(getRandomAngle(), HitObject.TimePreempt);
+
+ float getRandomAngle() => 180 * (RNG.NextSingle() * 2 - 1);
+ }
+
private Color4 getBananaColour()
{
switch (RNG.Next(0, 3))
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
index 5bfe0515a1..6844be5941 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableCatchHitObject.cs
@@ -91,10 +91,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss);
}
- protected sealed override double InitialLifetimeOffset => HitObject.TimePreempt;
-
- protected override void UpdateInitialTransforms() => this.FadeInFromZero(200);
-
protected override void UpdateStateTransforms(ArmedState state)
{
var endTime = HitObject.GetEndTime();
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
index 0a8e830af9..cad8892283 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableDroplet.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
float startRotation = RNG.NextSingle() * 20;
double duration = HitObject.TimePreempt + 2000;
- this.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
+ ScaleContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
}
}
}
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
index 197ad41247..fae5a10d04 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableFruit.cs
@@ -13,7 +13,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
public DrawableFruit(Fruit h)
: base(h)
{
- Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
}
[BackgroundDependencyLoader]
@@ -21,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
ScaleContainer.Child = new SkinnableDrawable(
new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece());
+
+ ScaleContainer.Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
}
private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation)
diff --git a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
index 932464cfd1..7bc016d94f 100644
--- a/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/Drawables/DrawableJuiceStream.cs
@@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
+using osuTK;
namespace osu.Game.Rulesets.Catch.Objects.Drawables
{
@@ -14,11 +15,13 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
private readonly Func> createDrawableRepresentation;
private readonly Container dropletContainer;
+ public override Vector2 OriginPosition => base.OriginPosition - new Vector2(0, CatchHitObject.OBJECT_RADIUS);
+
public DrawableJuiceStream(JuiceStream s, Func> createDrawableRepresentation = null)
: base(s)
{
this.createDrawableRepresentation = createDrawableRepresentation;
- RelativeSizeAxes = Axes.Both;
+ RelativeSizeAxes = Axes.X;
Origin = Anchor.BottomLeft;
X = 0;
@@ -27,6 +30,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
protected override void AddNestedHitObject(DrawableHitObject hitObject)
{
+ hitObject.Origin = Anchor.BottomCentre;
+
base.AddNestedHitObject(hitObject);
dropletContainer.Add(hitObject);
}
diff --git a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
index 642ff0246e..01011645bd 100644
--- a/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
+++ b/osu.Game.Rulesets.Catch/Objects/JuiceStream.cs
@@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Catch.Objects
public int RepeatCount { get; set; }
- public double Velocity;
- public double TickDistance;
+ public double Velocity { get; private set; }
+ public double TickDistance { get; private set; }
///
/// The length of one span of this .
@@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Objects
{
base.CreateNestedHitObjects();
- var tickSamples = Samples.Select(s => new HitSampleInfo
+ var dropletSamples = Samples.Select(s => new HitSampleInfo
{
Bank = s.Bank,
Name = @"slidertick",
@@ -75,7 +75,6 @@ namespace osu.Game.Rulesets.Catch.Objects
{
AddNested(new TinyDroplet
{
- Samples = tickSamples,
StartTime = t + lastEvent.Value.Time,
X = X + Path.PositionAt(
lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH,
@@ -93,7 +92,7 @@ namespace osu.Game.Rulesets.Catch.Objects
case SliderEventType.Tick:
AddNested(new Droplet
{
- Samples = tickSamples,
+ Samples = dropletSamples,
StartTime = e.Time,
X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH,
});
diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
index 43d98dc617..13f1ddf1d7 100644
--- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
+++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs
@@ -188,7 +188,7 @@ namespace osu.Game.Rulesets.Catch.UI
{
currentCatcher?.Hide();
- switch (currentState)
+ switch (CurrentState)
{
default:
currentCatcher = catcherIdle;
@@ -263,16 +263,14 @@ namespace osu.Game.Rulesets.Catch.UI
Position = Position
};
- AdditiveTarget?.Add(additive);
-
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
additive.Expire(true);
+
+ AdditiveTarget?.Add(additive);
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
}
- private Drawable createCatcherSprite() => new CatcherSprite(currentState);
-
///
/// Add a caught fruit to the catcher's stack.
///
@@ -341,7 +339,7 @@ namespace osu.Game.Rulesets.Catch.UI
if (validCatch)
updateState(fruit.Kiai ? CatcherAnimationState.Kiai : CatcherAnimationState.Idle);
- else
+ else if (!(fruit is Banana))
updateState(CatcherAnimationState.Fail);
return validCatch;
@@ -349,14 +347,14 @@ namespace osu.Game.Rulesets.Catch.UI
private void updateState(CatcherAnimationState state)
{
- if (currentState == state)
+ if (CurrentState == state)
return;
- currentState = state;
+ CurrentState = state;
updateCatcher();
}
- private CatcherAnimationState currentState;
+ public CatcherAnimationState CurrentState { get; private set; }
private double hyperDashModifier = 1;
private int hyperDashDirection;
@@ -376,14 +374,14 @@ namespace osu.Game.Rulesets.Catch.UI
{
const float hyper_dash_transition_length = 180;
- bool previouslyHyperDashing = HyperDashing;
+ bool wasHyperDashing = HyperDashing;
if (modifier <= 1 || X == targetPosition)
{
hyperDashModifier = 1;
hyperDashDirection = 0;
- if (previouslyHyperDashing)
+ if (wasHyperDashing)
{
this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint);
@@ -396,11 +394,18 @@ namespace osu.Game.Rulesets.Catch.UI
hyperDashDirection = Math.Sign(targetPosition - X);
hyperDashTargetPosition = targetPosition;
- if (!previouslyHyperDashing)
+ if (!wasHyperDashing)
{
this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
Trail = true;
+
+ var hyperDashEndGlow = createAdditiveSprite(true);
+
+ hyperDashEndGlow.MoveToOffset(new Vector2(0, -20), 1200, Easing.In);
+ hyperDashEndGlow.ScaleTo(hyperDashEndGlow.Scale * 0.9f).ScaleTo(hyperDashEndGlow.Scale * 1.2f, 1200, Easing.In);
+ hyperDashEndGlow.FadeOut(1200);
+ hyperDashEndGlow.Expire(true);
}
}
}
diff --git a/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs
new file mode 100644
index 0000000000..607d42a1bb
--- /dev/null
+++ b/osu.Game.Rulesets.Mania.Tests/Mods/TestSceneManiaModPerfect.cs
@@ -0,0 +1,26 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using NUnit.Framework;
+using osu.Game.Rulesets.Mania.Mods;
+using osu.Game.Rulesets.Mania.Objects;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Mania.Tests.Mods
+{
+ public class TestSceneManiaModPerfect : ModPerfectTestScene
+ {
+ public TestSceneManiaModPerfect()
+ : base(new ManiaRuleset(), new ManiaModPerfect())
+ {
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Note { StartTime = 1000 }), shouldMiss);
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestHoldNote(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new HoldNote { StartTime = 1000, EndTime = 3000 }), shouldMiss);
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs
new file mode 100644
index 0000000000..b03a894085
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/Mods/TestSceneOsuModPerfect.cs
@@ -0,0 +1,52 @@
+// 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.Objects.Types;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Tests.Visual;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Tests.Mods
+{
+ public class TestSceneOsuModPerfect : ModPerfectTestScene
+ {
+ public TestSceneOsuModPerfect()
+ : base(new OsuRuleset(), new OsuModPerfect())
+ {
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestHitCircle(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new HitCircle { StartTime = 1000 }), shouldMiss);
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestSlider(bool shouldMiss)
+ {
+ var slider = new Slider
+ {
+ StartTime = 1000,
+ Path = new SliderPath(PathType.Linear, new[] { Vector2.Zero, new Vector2(100, 0), })
+ };
+
+ CreateHitObjectTest(new HitObjectTestData(slider), shouldMiss);
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestSpinner(bool shouldMiss)
+ {
+ var spinner = new Spinner
+ {
+ StartTime = 1000,
+ EndTime = 3000,
+ Position = new Vector2(256, 192)
+ };
+
+ CreateHitObjectTest(new HitObjectTestData(spinner), shouldMiss);
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs
new file mode 100644
index 0000000000..5f3596976d
--- /dev/null
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneMissHitWindowJudgements.cs
@@ -0,0 +1,101 @@
+// 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.Beatmaps;
+using osu.Game.Replays;
+using osu.Game.Rulesets.Osu.Beatmaps;
+using osu.Game.Rulesets.Osu.Mods;
+using osu.Game.Rulesets.Osu.Objects;
+using osu.Game.Rulesets.Osu.Replays;
+using osu.Game.Rulesets.Osu.Scoring;
+using osu.Game.Rulesets.Scoring;
+using osu.Game.Scoring;
+using osu.Game.Tests.Visual;
+using osu.Game.Users;
+using osuTK;
+
+namespace osu.Game.Rulesets.Osu.Tests
+{
+ public class TestSceneMissHitWindowJudgements : ModTestScene
+ {
+ public TestSceneMissHitWindowJudgements()
+ : base(new OsuRuleset())
+ {
+ }
+
+ [Test]
+ public void TestMissViaEarlyHit()
+ {
+ var beatmap = new Beatmap
+ {
+ HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
+ };
+
+ var hitWindows = new OsuHitWindows();
+ hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
+
+ CreateModTest(new ModTestData
+ {
+ Autoplay = false,
+ Mod = new TestAutoMod(),
+ Beatmap = new Beatmap
+ {
+ HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
+ },
+ PassCondition = () => Player.Results.Count > 0 && Player.Results[0].TimeOffset < -hitWindows.WindowFor(HitResult.Meh) && Player.Results[0].Type == HitResult.Miss
+ });
+ }
+
+ [Test]
+ public void TestMissViaNotHitting()
+ {
+ var beatmap = new Beatmap
+ {
+ HitObjects = { new HitCircle { Position = new Vector2(256, 192) } }
+ };
+
+ var hitWindows = new OsuHitWindows();
+ hitWindows.SetDifficulty(beatmap.BeatmapInfo.BaseDifficulty.OverallDifficulty);
+
+ CreateModTest(new ModTestData
+ {
+ Autoplay = false,
+ Beatmap = beatmap,
+ PassCondition = () => Player.Results.Count > 0 && Player.Results[0].TimeOffset >= hitWindows.WindowFor(HitResult.Meh) && Player.Results[0].Type == HitResult.Miss
+ });
+ }
+
+ private class TestAutoMod : OsuModAutoplay
+ {
+ public override Score CreateReplayScore(IBeatmap beatmap) => new Score
+ {
+ ScoreInfo = new ScoreInfo { User = new User { Username = "Autoplay" } },
+ Replay = new MissingAutoGenerator(beatmap).Generate()
+ };
+ }
+
+ private class MissingAutoGenerator : OsuAutoGeneratorBase
+ {
+ public new OsuBeatmap Beatmap => (OsuBeatmap)base.Beatmap;
+
+ public MissingAutoGenerator(IBeatmap beatmap)
+ : base(beatmap)
+ {
+ }
+
+ public override Replay Generate()
+ {
+ AddFrameToReplay(new OsuReplayFrame(-100000, new Vector2(256, 500)));
+ AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 1500, new Vector2(256, 500)));
+ AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 1500, new Vector2(256, 500)));
+
+ AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 450, Beatmap.HitObjects[0].StackedPosition));
+ AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 350, Beatmap.HitObjects[0].StackedPosition, OsuAction.LeftButton));
+ AddFrameToReplay(new OsuReplayFrame(Beatmap.HitObjects[0].StartTime - 325, Beatmap.HitObjects[0].StackedPosition));
+
+ return Replay;
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
index de11ab6419..0ec7f2ebfe 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
@@ -36,8 +36,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly SpriteIcon symbol;
- private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c");
- private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c");
+ private readonly Color4 baseColour = Color4Extensions.FromHex(@"002c3c");
+ private readonly Color4 fillColour = Color4Extensions.FromHex(@"005b7c");
private readonly IBindable positionBindable = new Bindable();
diff --git a/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs b/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs
index a6491bb3f3..6f2998006f 100644
--- a/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs
+++ b/osu.Game.Rulesets.Osu/Scoring/OsuHitWindows.cs
@@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
new DifficultyRange(HitResult.Great, 80, 50, 20),
new DifficultyRange(HitResult.Good, 140, 100, 60),
new DifficultyRange(HitResult.Meh, 200, 150, 100),
- new DifficultyRange(HitResult.Miss, 200, 200, 200),
+ new DifficultyRange(HitResult.Miss, 400, 400, 400),
};
public override bool IsHitResultAllowed(HitResult result)
diff --git a/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs
new file mode 100644
index 0000000000..d3be2cdf0d
--- /dev/null
+++ b/osu.Game.Rulesets.Taiko.Tests/Mods/TestSceneTaikoModPerfect.cs
@@ -0,0 +1,47 @@
+// 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.Scoring;
+using osu.Game.Rulesets.Taiko.Mods;
+using osu.Game.Rulesets.Taiko.Objects;
+using osu.Game.Rulesets.Taiko.Scoring;
+using osu.Game.Tests.Visual;
+
+namespace osu.Game.Rulesets.Taiko.Tests.Mods
+{
+ public class TestSceneTaikoModPerfect : ModPerfectTestScene
+ {
+ public TestSceneTaikoModPerfect()
+ : base(new TestTaikoRuleset(), new TaikoModPerfect())
+ {
+ }
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestHit(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new CentreHit { StartTime = 1000 }), shouldMiss);
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestDrumRoll(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new DrumRoll { StartTime = 1000, EndTime = 3000 }), shouldMiss);
+
+ [TestCase(false)]
+ [TestCase(true)]
+ public void TestSwell(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new Swell { StartTime = 1000, EndTime = 3000 }), shouldMiss);
+
+ private class TestTaikoRuleset : TaikoRuleset
+ {
+ public override HealthProcessor CreateHealthProcessor(double drainStartTime) => new TestTaikoHealthProcessor();
+
+ private class TestTaikoHealthProcessor : TaikoHealthProcessor
+ {
+ protected override void Reset(bool storeResults)
+ {
+ base.Reset(storeResults);
+
+ Health.Value = 1; // Don't care about the health condition (only the mod condition)
+ }
+ }
+ }
+ }
+}
diff --git a/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs
index edb089dbac..dd3c2289ea 100644
--- a/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.cs
+++ b/osu.Game.Rulesets.Taiko/Scoring/TaikoHealthProcessor.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 System;
using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
@@ -39,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
{
base.ApplyBeatmap(beatmap);
- hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
+ hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType().Count()) * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98));
hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
}
diff --git a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
index 96ff6b81e3..76b76aa357 100644
--- a/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
+++ b/osu.Game.Tests/Beatmaps/Formats/LegacyStoryboardDecoderTest.cs
@@ -99,7 +99,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
var storyboard = decoder.Decode(stream);
StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3);
- Assert.AreEqual(123456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X);
+ Assert.AreEqual(3456, ((StoryboardSprite)background.Elements.Single()).InitialPosition.X);
}
}
}
diff --git a/osu.Game.Tests/Resources/variable-with-suffix.osb b/osu.Game.Tests/Resources/variable-with-suffix.osb
index 5c9b46ca98..fd284eb055 100644
--- a/osu.Game.Tests/Resources/variable-with-suffix.osb
+++ b/osu.Game.Tests/Resources/variable-with-suffix.osb
@@ -1,5 +1,5 @@
[Variables]
-$var=1234
+$var=34
[Events]
Sprite,Background,TopCentre,"img.jpg",$var56,240
diff --git a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs
index 681bf1b40b..49fab08ded 100644
--- a/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs
+++ b/osu.Game.Tests/Visual/Menus/TestSceneDisclaimer.cs
@@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Menus
API.LocalUser.Value = new User
{
Username = API.LocalUser.Value.Username,
- Id = API.LocalUser.Value.Id,
+ Id = API.LocalUser.Value.Id + 1,
IsSupporter = !API.LocalUser.Value.IsSupporter,
};
});
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
index 7a8570c09b..864fd31a0f 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChangelogOverlay.cs
@@ -17,8 +17,8 @@ namespace osu.Game.Tests.Visual.Online
public override IReadOnlyList RequiredTypes => new[]
{
- typeof(UpdateStreamBadgeArea),
- typeof(UpdateStreamBadge),
+ typeof(ChangelogUpdateStreamControl),
+ typeof(ChangelogUpdateStreamItem),
typeof(ChangelogHeader),
typeof(ChangelogContent),
typeof(ChangelogListing),
diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
index a1c77e2db0..c76d4fd5b8 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs
@@ -7,6 +7,7 @@ using System.Linq;
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
@@ -102,7 +103,7 @@ namespace osu.Game.Tests.Visual.Online
{
bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour);
- Color4 textColour = isAction && hasBackground ? OsuColour.FromHex(newLine.Message.Sender.Colour) : Color4.White;
+ Color4 textColour = isAction && hasBackground ? Color4Extensions.FromHex(newLine.Message.Sender.Colour) : Color4.White;
var linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);
diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
index 71ae47dc66..80e03d82e2 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapCarousel.cs
@@ -497,7 +497,7 @@ namespace osu.Game.Tests.Visual.SongSelect
}
bool changed = false;
- AddStep($"Load {beatmapSets.Count} Beatmaps", () =>
+ AddStep($"Load {(beatmapSets.Count > 0 ? beatmapSets.Count.ToString() : "some")} beatmaps", () =>
{
carousel.Filter(new FilterCriteria());
carousel.BeatmapSetsChanged = () => changed = true;
@@ -697,6 +697,8 @@ namespace osu.Game.Tests.Visual.SongSelect
public new List Items => base.Items;
public bool PendingFilterTask => PendingFilter != null;
+
+ protected override IEnumerable GetLoadableBeatmaps() => Enumerable.Empty();
}
}
}
diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
index 51d302123b..105d96cdfe 100644
--- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
+++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs
@@ -465,6 +465,43 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmap.OnlineBeatmapID == target.OnlineBeatmapID);
}
+ [Test]
+ public void TestExternalBeatmapChangeWhileFilteredThenRefilter()
+ {
+ createSongSelect();
+ addManyTestMaps();
+
+ changeRuleset(0);
+
+ AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
+
+ AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nonono");
+
+ AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap);
+
+ AddUntilStep("has no selection", () => songSelect.Carousel.SelectedBeatmap == null);
+
+ BeatmapInfo target = null;
+
+ AddStep("select beatmap externally", () =>
+ {
+ target = manager.GetAllUsableBeatmapSets().Where(b => b.Beatmaps.Any(bi => bi.RulesetID == 1))
+ .ElementAt(5).Beatmaps.First();
+
+ Beatmap.Value = manager.GetWorkingBeatmap(target);
+ });
+
+ AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap != null);
+
+ AddUntilStep("carousel has correct", () => songSelect.Carousel.SelectedBeatmap?.OnlineBeatmapID == target.OnlineBeatmapID);
+ AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.OnlineBeatmapID == target.OnlineBeatmapID);
+
+ AddStep("set filter text", () => songSelect.FilterControl.ChildrenOfType().First().Text = "nononoo");
+
+ AddUntilStep("game lost selection", () => Beatmap.Value is DummyWorkingBeatmap);
+ AddAssert("carousel lost selection", () => songSelect.Carousel.SelectedBeatmap == null);
+ }
+
[Test]
public void TestAutoplayViaCtrlEnter()
{
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs
new file mode 100644
index 0000000000..0d841dfef1
--- /dev/null
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFriendsOnlineStatusControl.cs
@@ -0,0 +1,63 @@
+// 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.Game.Overlays;
+using osu.Game.Overlays.Home.Friends;
+using osu.Game.Users;
+
+namespace osu.Game.Tests.Visual.UserInterface
+{
+ public class TestSceneFriendsOnlineStatusControl : OsuTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(FriendsOnlineStatusControl),
+ typeof(FriendsOnlineStatusItem),
+ typeof(OverlayStreamControl<>),
+ typeof(OverlayStreamItem<>),
+ typeof(FriendsBundle)
+ };
+
+ [Cached]
+ private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Blue);
+
+ private FriendsOnlineStatusControl control;
+
+ [SetUp]
+ public void SetUp() => Schedule(() => Child = control = new FriendsOnlineStatusControl
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ });
+
+ [Test]
+ public void Populate()
+ {
+ AddStep("Populate", () => control.Populate(new List
+ {
+ new User
+ {
+ IsOnline = true
+ },
+ new User
+ {
+ IsOnline = false
+ },
+ new User
+ {
+ IsOnline = false
+ }
+ }));
+
+ AddAssert("3 users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.All)?.Count == 3);
+ AddAssert("1 online user", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Online)?.Count == 1);
+ AddAssert("2 offline users", () => control.Items.FirstOrDefault(item => item.Status == FriendsOnlineStatus.Offline)?.Count == 2);
+ }
+ }
+}
diff --git a/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs
new file mode 100644
index 0000000000..9f885ed827
--- /dev/null
+++ b/osu.Game.Tournament.Tests/Components/TestSceneMatchHeader.cs
@@ -0,0 +1,42 @@
+// 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 osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics;
+using osu.Game.Tournament.Components;
+using osu.Game.Tournament.Screens.Gameplay.Components;
+using osuTK;
+
+namespace osu.Game.Tournament.Tests.Components
+{
+ public class TestSceneMatchHeader : TournamentTestScene
+ {
+ public override IReadOnlyList RequiredTypes => new[]
+ {
+ typeof(DrawableTournamentHeaderText),
+ typeof(DrawableTournamentHeaderLogo),
+ };
+
+ public TestSceneMatchHeader()
+ {
+ Child = new FillFlowContainer
+ {
+ RelativeSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical,
+ Spacing = new Vector2(50),
+ Children = new Drawable[]
+ {
+ new TournamentSpriteText { Text = "with logo", Font = OsuFont.Torus.With(size: 30) },
+ new MatchHeader(),
+ new TournamentSpriteText { Text = "without logo", Font = OsuFont.Torus.With(size: 30) },
+ new MatchHeader { ShowLogo = false },
+ new TournamentSpriteText { Text = "without scores", Font = OsuFont.Torus.With(size: 30) },
+ new MatchHeader { ShowScores = false },
+ }
+ };
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs
new file mode 100644
index 0000000000..3f5ab42fd7
--- /dev/null
+++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderLogo.cs
@@ -0,0 +1,37 @@
+// 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.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+
+namespace osu.Game.Tournament.Components
+{
+ public class DrawableTournamentHeaderLogo : CompositeDrawable
+ {
+ public DrawableTournamentHeaderLogo()
+ {
+ InternalChild = new LogoSprite();
+
+ Height = 82;
+ RelativeSizeAxes = Axes.X;
+ }
+
+ private class LogoSprite : Sprite
+ {
+ [BackgroundDependencyLoader]
+ private void load(TextureStore textures)
+ {
+ RelativeSizeAxes = Axes.Both;
+ FillMode = FillMode.Fit;
+
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Texture = textures.Get("header-logo");
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs
new file mode 100644
index 0000000000..bda696ba00
--- /dev/null
+++ b/osu.Game.Tournament/Components/DrawableTournamentHeaderText.cs
@@ -0,0 +1,37 @@
+// 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.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Graphics.Textures;
+
+namespace osu.Game.Tournament.Components
+{
+ public class DrawableTournamentHeaderText : CompositeDrawable
+ {
+ public DrawableTournamentHeaderText()
+ {
+ InternalChild = new TextSprite();
+
+ Height = 22;
+ RelativeSizeAxes = Axes.X;
+ }
+
+ private class TextSprite : Sprite
+ {
+ [BackgroundDependencyLoader]
+ private void load(TextureStore textures)
+ {
+ RelativeSizeAxes = Axes.Both;
+ FillMode = FillMode.Fit;
+
+ Anchor = Anchor.Centre;
+ Origin = Anchor.Centre;
+
+ Texture = textures.Get("header-text");
+ }
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Components/DrawableTournamentTitleText.cs b/osu.Game.Tournament/Components/DrawableTournamentTitleText.cs
deleted file mode 100644
index 4fbc6cd060..0000000000
--- a/osu.Game.Tournament/Components/DrawableTournamentTitleText.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Game.Graphics;
-
-namespace osu.Game.Tournament.Components
-{
- public class DrawableTournamentTitleText : TournamentSpriteText
- {
- public DrawableTournamentTitleText()
- {
- Text = "osu!taiko world cup 2020";
- Font = OsuFont.Torus.With(size: 26, weight: FontWeight.SemiBold);
- }
- }
-}
diff --git a/osu.Game.Tournament/Components/RoundDisplay.cs b/osu.Game.Tournament/Components/RoundDisplay.cs
index dd56c83c57..bebede6782 100644
--- a/osu.Game.Tournament/Components/RoundDisplay.cs
+++ b/osu.Game.Tournament/Components/RoundDisplay.cs
@@ -22,7 +22,7 @@ namespace osu.Game.Tournament.Components
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
- new DrawableTournamentTitleText(),
+ new DrawableTournamentHeaderText(),
new TournamentSpriteText
{
Text = match.Round.Value?.Name.Value ?? "Unknown Round",
diff --git a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
index 8eb1c98ba0..2a183d0d45 100644
--- a/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
+++ b/osu.Game.Tournament/Components/TournamentMatchChatDisplay.cs
@@ -84,7 +84,7 @@ namespace osu.Game.Tournament.Components
// else if (info.CurrentMatch.Value.Team2.Value.Players.Any(u => u.Id == Message.Sender.Id))
// SenderText.Colour = TournamentGame.COLOUR_BLUE;
// else if (Message.Sender.Colour != null)
- // SenderText.Colour = ColourBox.Colour = OsuColour.FromHex(Message.Sender.Colour);
+ // SenderText.Colour = ColourBox.Colour = Color4Extensions.FromHex(Message.Sender.Colour);
}
}
}
diff --git a/osu.Game.Tournament/Components/TourneyVideo.cs b/osu.Game.Tournament/Components/TourneyVideo.cs
index 43088d6b92..bc66fad8c1 100644
--- a/osu.Game.Tournament/Components/TourneyVideo.cs
+++ b/osu.Game.Tournament/Components/TourneyVideo.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Video;
-using osu.Framework.Platform;
using osu.Framework.Timing;
using osu.Game.Graphics;
@@ -28,13 +27,13 @@ namespace osu.Game.Tournament.Components
}
[BackgroundDependencyLoader]
- private void load(Storage storage)
+ private void load(TournamentStorage storage)
{
- var stream = storage.GetStream($@"videos/{filename}.m4v");
+ var stream = storage.GetStream($@"videos/{filename}");
if (stream != null)
{
- InternalChild = video = new VideoSprite(stream)
+ InternalChild = video = new VideoSprite(stream, false)
{
RelativeSizeAxes = Axes.Both,
FillMode = FillMode.Fit,
diff --git a/osu.Game.Tournament/IPC/FileBasedIPC.cs b/osu.Game.Tournament/IPC/FileBasedIPC.cs
index b19f2bedf0..eefa9fcfe6 100644
--- a/osu.Game.Tournament/IPC/FileBasedIPC.cs
+++ b/osu.Game.Tournament/IPC/FileBasedIPC.cs
@@ -163,12 +163,7 @@ namespace osu.Game.Tournament.IPC
{
try
{
- stableInstallPath = "G:\\My Drive\\Main\\osu!tourney";
-
- if (checkExists(stableInstallPath))
- return stableInstallPath;
-
- stableInstallPath = "G:\\My Drive\\Main\\osu!mappool";
+ stableInstallPath = Environment.GetEnvironmentVariable("OSU_STABLE_PATH");
if (checkExists(stableInstallPath))
return stableInstallPath;
diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs
index 69a68c946b..d790f4b754 100644
--- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchHeader.cs
@@ -2,14 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Framework.Input.Events;
using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osuTK;
-using osuTK.Input;
namespace osu.Game.Tournament.Screens.Gameplay.Components
{
@@ -17,13 +14,39 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
{
private TeamScoreDisplay teamDisplay1;
private TeamScoreDisplay teamDisplay2;
+ private DrawableTournamentHeaderLogo logo;
+
+ private bool showScores = true;
public bool ShowScores
{
+ get => showScores;
set
{
- teamDisplay1.ShowScore = value;
- teamDisplay2.ShowScore = value;
+ if (value == showScores)
+ return;
+
+ showScores = value;
+
+ if (IsLoaded)
+ updateDisplay();
+ }
+ }
+
+ private bool showLogo = true;
+
+ public bool ShowLogo
+ {
+ get => showLogo;
+ set
+ {
+ if (value == showLogo)
+ return;
+
+ showLogo = value;
+
+ if (IsLoaded)
+ updateDisplay();
}
}
@@ -38,19 +61,25 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
{
RelativeSizeAxes = Axes.Both,
Direction = FillDirection.Vertical,
+ Padding = new MarginPadding(20),
Spacing = new Vector2(5),
Children = new Drawable[]
{
- new DrawableTournamentTitleText
+ logo = new DrawableTournamentHeaderLogo
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
- Scale = new Vector2(1.2f)
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ Alpha = showLogo ? 1 : 0
},
- new RoundDisplay
+ new DrawableTournamentHeaderText
{
- Anchor = Anchor.Centre,
- Origin = Anchor.Centre,
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
+ },
+ new MatchRoundDisplay
+ {
+ Anchor = Anchor.TopCentre,
+ Origin = Anchor.TopCentre,
Scale = new Vector2(0.4f)
},
}
@@ -66,76 +95,16 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
Origin = Anchor.TopRight,
},
};
- }
- }
- public class TeamScoreDisplay : CompositeDrawable
- {
- private readonly TeamColour teamColour;
-
- private readonly Bindable currentMatch = new Bindable();
- private readonly Bindable currentTeam = new Bindable();
- private readonly Bindable currentTeamScore = new Bindable();
-
- private TeamDisplay teamDisplay;
-
- public bool ShowScore { set => teamDisplay.ShowScore = value; }
-
- public TeamScoreDisplay(TeamColour teamColour)
- {
- this.teamColour = teamColour;
-
- RelativeSizeAxes = Axes.Y;
- AutoSizeAxes = Axes.X;
+ updateDisplay();
}
- [BackgroundDependencyLoader]
- private void load(LadderInfo ladder)
+ private void updateDisplay()
{
- currentMatch.BindTo(ladder.CurrentMatch);
- currentMatch.BindValueChanged(matchChanged, true);
- }
+ teamDisplay1.ShowScore = showScores;
+ teamDisplay2.ShowScore = showScores;
- private void matchChanged(ValueChangedEvent match)
- {
- currentTeamScore.UnbindBindings();
- currentTeam.UnbindBindings();
-
- if (match.NewValue != null)
- {
- currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score);
- currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2);
- }
-
- // team may change to same team, which means score is not in a good state.
- // thus we handle this manually.
- teamChanged(currentTeam.Value);
- }
-
- protected override bool OnMouseDown(MouseDownEvent e)
- {
- switch (e.Button)
- {
- case MouseButton.Left:
- if (currentTeamScore.Value < currentMatch.Value.PointsToWin)
- currentTeamScore.Value++;
- return true;
-
- case MouseButton.Right:
- if (currentTeamScore.Value > 0)
- currentTeamScore.Value--;
- return true;
- }
-
- return base.OnMouseDown(e);
- }
-
- private void teamChanged(TournamentTeam team)
- {
- InternalChildren = new Drawable[]
- {
- teamDisplay = new TeamDisplay(team, teamColour, currentTeamScore, currentMatch.Value?.PointsToWin ?? 0),
- };
+ logo.Alpha = showLogo ? 1 : 0;
}
}
}
diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/RoundDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs
similarity index 92%
rename from osu.Game.Tournament/Screens/Gameplay/Components/RoundDisplay.cs
rename to osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs
index c8b0d3bdda..87793f7e1b 100644
--- a/osu.Game.Tournament/Screens/Gameplay/Components/RoundDisplay.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchRoundDisplay.cs
@@ -8,7 +8,7 @@ using osu.Game.Tournament.Models;
namespace osu.Game.Tournament.Screens.Gameplay.Components
{
- public class RoundDisplay : TournamentSpriteTextWithBackground
+ public class MatchRoundDisplay : TournamentSpriteTextWithBackground
{
private readonly Bindable currentMatch = new Bindable();
diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs
index ed14956793..2e7484542a 100644
--- a/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/Components/MatchScoreDisplay.cs
@@ -11,6 +11,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.IPC;
using osu.Game.Tournament.Models;
+using osuTK;
namespace osu.Game.Tournament.Screens.Gameplay.Components
{
@@ -131,13 +132,15 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
Margin = new MarginPadding { Top = bar_height, Horizontal = 10 };
Winning = false;
+
+ DisplayedCountSpriteText.Spacing = new Vector2(-6);
}
public bool Winning
{
set => DisplayedCountSpriteText.Font = value
- ? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50)
- : OsuFont.Torus.With(weight: FontWeight.Regular, size: 40);
+ ? OsuFont.Torus.With(weight: FontWeight.Bold, size: 50, fixedWidth: true)
+ : OsuFont.Torus.With(weight: FontWeight.Regular, size: 40, fixedWidth: true);
}
}
}
diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs
index c7071484ca..36c78c5ac1 100644
--- a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScore.cs
@@ -76,7 +76,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
},
box = new Box
{
- Colour = OsuColour.FromHex("#FFE8AD"),
+ Colour = Color4Extensions.FromHex("#FFE8AD"),
RelativeSizeAxes = Axes.Both,
},
};
@@ -85,7 +85,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
EdgeEffect = new EdgeEffectParameters
{
Type = EdgeEffectType.Glow,
- Colour = OsuColour.FromHex("#FFE8AD").Opacity(0.1f),
+ Colour = Color4Extensions.FromHex("#FFE8AD").Opacity(0.1f),
Hollow = true,
Radius = 20,
Roundness = 10,
diff --git a/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs
new file mode 100644
index 0000000000..462015f004
--- /dev/null
+++ b/osu.Game.Tournament/Screens/Gameplay/Components/TeamScoreDisplay.cs
@@ -0,0 +1,83 @@
+// 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.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Input.Events;
+using osu.Game.Tournament.Models;
+using osuTK.Input;
+
+namespace osu.Game.Tournament.Screens.Gameplay.Components
+{
+ public class TeamScoreDisplay : CompositeDrawable
+ {
+ private readonly TeamColour teamColour;
+
+ private readonly Bindable currentMatch = new Bindable();
+ private readonly Bindable currentTeam = new Bindable();
+ private readonly Bindable currentTeamScore = new Bindable();
+
+ private TeamDisplay teamDisplay;
+
+ public bool ShowScore { set => teamDisplay.ShowScore = value; }
+
+ public TeamScoreDisplay(TeamColour teamColour)
+ {
+ this.teamColour = teamColour;
+
+ RelativeSizeAxes = Axes.Y;
+ AutoSizeAxes = Axes.X;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load(LadderInfo ladder)
+ {
+ currentMatch.BindTo(ladder.CurrentMatch);
+ currentMatch.BindValueChanged(matchChanged, true);
+ }
+
+ private void matchChanged(ValueChangedEvent match)
+ {
+ currentTeamScore.UnbindBindings();
+ currentTeam.UnbindBindings();
+
+ if (match.NewValue != null)
+ {
+ currentTeamScore.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1Score : match.NewValue.Team2Score);
+ currentTeam.BindTo(teamColour == TeamColour.Red ? match.NewValue.Team1 : match.NewValue.Team2);
+ }
+
+ // team may change to same team, which means score is not in a good state.
+ // thus we handle this manually.
+ teamChanged(currentTeam.Value);
+ }
+
+ protected override bool OnMouseDown(MouseDownEvent e)
+ {
+ switch (e.Button)
+ {
+ case MouseButton.Left:
+ if (currentTeamScore.Value < currentMatch.Value.PointsToWin)
+ currentTeamScore.Value++;
+ return true;
+
+ case MouseButton.Right:
+ if (currentTeamScore.Value > 0)
+ currentTeamScore.Value--;
+ return true;
+ }
+
+ return base.OnMouseDown(e);
+ }
+
+ private void teamChanged(TournamentTeam team)
+ {
+ InternalChildren = new Drawable[]
+ {
+ teamDisplay = new TeamDisplay(team, teamColour, currentTeamScore, currentMatch.Value?.PointsToWin ?? 0),
+ };
+ }
+ }
+}
diff --git a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs
index 4d770855cd..8920990d1b 100644
--- a/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs
+++ b/osu.Game.Tournament/Screens/Gameplay/GameplayScreen.cs
@@ -47,7 +47,10 @@ namespace osu.Game.Tournament.Screens.Gameplay
Loop = true,
RelativeSizeAxes = Axes.Both,
},
- header = new MatchHeader(),
+ header = new MatchHeader
+ {
+ ShowLogo = false
+ },
new Container
{
RelativeSizeAxes = Axes.X,
diff --git a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs
index fe7e80873c..15cb7e44cb 100644
--- a/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs
+++ b/osu.Game.Tournament/Screens/Ladder/Components/DrawableMatchTeam.cs
@@ -4,6 +4,7 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@@ -85,8 +86,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
this.ladderEditor = ladderEditor;
colourWinner = losers
- ? OsuColour.FromHex("#8E7F48")
- : OsuColour.FromHex("#1462AA");
+ ? Color4Extensions.FromHex("#8E7F48")
+ : Color4Extensions.FromHex("#1462AA");
InternalChildren = new Drawable[]
{
@@ -180,8 +181,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{
bool winner = completed.Value && isWinner?.Invoke() == true;
- background.FadeColour(winner ? Color4.White : OsuColour.FromHex("#444"), winner ? 500 : 0, Easing.OutQuint);
- backgroundRight.FadeColour(winner ? colourWinner : OsuColour.FromHex("#333"), winner ? 500 : 0, Easing.OutQuint);
+ background.FadeColour(winner ? Color4.White : Color4Extensions.FromHex("#444"), winner ? 500 : 0, Easing.OutQuint);
+ backgroundRight.FadeColour(winner ? colourWinner : Color4Extensions.FromHex("#333"), winner ? 500 : 0, Easing.OutQuint);
AcronymText.Colour = winner ? Color4.Black : Color4.White;
diff --git a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
index c7e59cfa7b..534c402f6c 100644
--- a/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
+++ b/osu.Game.Tournament/Screens/Ladder/LadderScreen.cs
@@ -32,8 +32,8 @@ namespace osu.Game.Tournament.Screens.Ladder
[BackgroundDependencyLoader]
private void load(OsuColour colours, Storage storage)
{
- normalPathColour = OsuColour.FromHex("#66D1FF");
- losersPathColour = OsuColour.FromHex("#FFC700");
+ normalPathColour = Color4Extensions.FromHex("#66D1FF");
+ losersPathColour = Color4Extensions.FromHex("#FFC700");
RelativeSizeAxes = Axes.Both;
@@ -47,7 +47,7 @@ namespace osu.Game.Tournament.Screens.Ladder
RelativeSizeAxes = Axes.Both,
Loop = true,
},
- new DrawableTournamentTitleText
+ new DrawableTournamentHeaderText
{
Y = 100,
Anchor = Anchor.TopCentre,
diff --git a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
index 4f3f7cfdbf..2b0bfe0b74 100644
--- a/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
+++ b/osu.Game.Tournament/Screens/MapPool/MapPoolScreen.cs
@@ -50,7 +50,7 @@ namespace osu.Game.Tournament.Screens.MapPool
new MatchHeader(),
mapFlows = new FillFlowContainer>
{
- Y = 100,
+ Y = 140,
Spacing = new Vector2(10, 10),
Padding = new MarginPadding(25),
Direction = FillDirection.Vertical,
@@ -235,6 +235,7 @@ namespace osu.Game.Tournament.Screens.MapPool
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
+ Height = 42,
});
}
}
diff --git a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs
index 0fcec645e3..88289ad6bd 100644
--- a/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs
+++ b/osu.Game.Tournament/Screens/Schedule/ScheduleScreen.cs
@@ -62,7 +62,7 @@ namespace osu.Game.Tournament.Screens.Schedule
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
- new DrawableTournamentTitleText(),
+ new DrawableTournamentHeaderText(),
new Container
{
Margin = new MarginPadding { Top = 40 },
diff --git a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs
index 513d84b594..d48e396b89 100644
--- a/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs
+++ b/osu.Game.Tournament/Screens/TeamIntro/SeedingScreen.cs
@@ -15,7 +15,6 @@ using osu.Game.Tournament.Components;
using osu.Game.Tournament.Models;
using osu.Game.Tournament.Screens.Ladder.Components;
using osuTK;
-using osuTK.Graphics;
namespace osu.Game.Tournament.Screens.TeamIntro
{
@@ -140,9 +139,9 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Spacing = new Vector2(5),
Children = new Drawable[]
{
- new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = Color4.Black, },
- new TournamentSpriteText { Text = "by", Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
- new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
+ new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Title, Colour = TournamentGame.TEXT_COLOUR, },
+ new TournamentSpriteText { Text = "by", Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
+ new TournamentSpriteText { Text = beatmap.BeatmapInfo.Metadata.Artist, Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
}
},
new FillFlowContainer
@@ -154,8 +153,8 @@ namespace osu.Game.Tournament.Screens.TeamIntro
Spacing = new Vector2(40),
Children = new Drawable[]
{
- new TournamentSpriteText { Text = beatmap.Score.ToString("#,0"), Colour = Color4.Black, Width = 80 },
- new TournamentSpriteText { Text = "#" + beatmap.Seed.Value.ToString("#,0"), Colour = Color4.Black, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
+ new TournamentSpriteText { Text = beatmap.Score.ToString("#,0"), Colour = TournamentGame.TEXT_COLOUR, Width = 80 },
+ new TournamentSpriteText { Text = "#" + beatmap.Seed.Value.ToString("#,0"), Colour = TournamentGame.TEXT_COLOUR, Font = OsuFont.Torus.With(weight: FontWeight.Regular) },
}
},
};
@@ -204,7 +203,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = Color4.Black,
+ Colour = TournamentGame.TEXT_COLOUR,
},
new TournamentSpriteText
{
@@ -260,20 +259,18 @@ namespace osu.Game.Tournament.Screens.TeamIntro
AutoSizeAxes = Axes.Y;
RelativeSizeAxes = Axes.X;
- var colour = OsuColour.Gray(0.3f);
-
InternalChildren = new Drawable[]
{
new TournamentSpriteText
{
Text = left,
- Colour = colour,
- Font = OsuFont.Torus.With(size: 22),
+ Colour = TournamentGame.TEXT_COLOUR,
+ Font = OsuFont.Torus.With(size: 22, weight: FontWeight.SemiBold),
},
new TournamentSpriteText
{
Text = right,
- Colour = colour,
+ Colour = TournamentGame.TEXT_COLOUR,
Anchor = Anchor.TopRight,
Origin = Anchor.TopLeft,
Font = OsuFont.Torus.With(size: 22, weight: FontWeight.Regular),
@@ -305,7 +302,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
{
Text = team?.FullName.Value ?? "???",
Font = OsuFont.Torus.With(size: 32, weight: FontWeight.SemiBold),
- Colour = Color4.Black,
+ Colour = TournamentGame.TEXT_COLOUR,
},
}
};
diff --git a/osu.Game.Tournament/TournamentGame.cs b/osu.Game.Tournament/TournamentGame.cs
index 6d597d5e7d..78bb66d553 100644
--- a/osu.Game.Tournament/TournamentGame.cs
+++ b/osu.Game.Tournament/TournamentGame.cs
@@ -1,9 +1,9 @@
// 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.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
-using osu.Game.Graphics;
using osu.Game.Graphics.Cursor;
using osu.Game.Tournament.Models;
using osuTK.Graphics;
@@ -14,13 +14,13 @@ namespace osu.Game.Tournament
{
public static ColourInfo GetTeamColour(TeamColour teamColour) => teamColour == TeamColour.Red ? COLOUR_RED : COLOUR_BLUE;
- public static readonly Color4 COLOUR_RED = OsuColour.FromHex("#AA1414");
- public static readonly Color4 COLOUR_BLUE = OsuColour.FromHex("#1462AA");
+ public static readonly Color4 COLOUR_RED = Color4Extensions.FromHex("#AA1414");
+ public static readonly Color4 COLOUR_BLUE = Color4Extensions.FromHex("#1462AA");
- public static readonly Color4 ELEMENT_BACKGROUND_COLOUR = OsuColour.FromHex("#fff");
- public static readonly Color4 ELEMENT_FOREGROUND_COLOUR = OsuColour.FromHex("#000");
+ public static readonly Color4 ELEMENT_BACKGROUND_COLOUR = Color4Extensions.FromHex("#fff");
+ public static readonly Color4 ELEMENT_FOREGROUND_COLOUR = Color4Extensions.FromHex("#000");
- public static readonly Color4 TEXT_COLOUR = OsuColour.FromHex("#fff");
+ public static readonly Color4 TEXT_COLOUR = Color4Extensions.FromHex("#fff");
protected override void LoadComplete()
{
diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs
index 41165ca141..41822ae2c3 100644
--- a/osu.Game.Tournament/TournamentGameBase.cs
+++ b/osu.Game.Tournament/TournamentGameBase.cs
@@ -37,6 +37,8 @@ namespace osu.Game.Tournament
private Storage storage;
+ private TournamentStorage tournamentStorage;
+
private DependencyContainer dependencies;
private Bindable windowSize;
@@ -54,7 +56,9 @@ namespace osu.Game.Tournament
{
Resources.AddStore(new DllResourceStore(typeof(TournamentGameBase).Assembly));
- Textures.AddStore(new TextureLoaderStore(new ResourceStore(new StorageBackedResourceStore(storage))));
+ dependencies.CacheAs(tournamentStorage = new TournamentStorage(storage));
+
+ Textures.AddStore(new TextureLoaderStore(tournamentStorage));
this.storage = storage;
diff --git a/osu.Game.Tournament/TournamentStorage.cs b/osu.Game.Tournament/TournamentStorage.cs
new file mode 100644
index 0000000000..139ad3857b
--- /dev/null
+++ b/osu.Game.Tournament/TournamentStorage.cs
@@ -0,0 +1,19 @@
+// 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.IO.Stores;
+using osu.Framework.Platform;
+
+namespace osu.Game.Tournament
+{
+ internal class TournamentStorage : NamespacedResourceStore
+ {
+ public TournamentStorage(Storage storage)
+ : base(new StorageBackedResourceStore(storage), "tournament")
+ {
+ AddExtension("m4v");
+ AddExtension("avi");
+ AddExtension("mp4");
+ }
+ }
+}
diff --git a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
index 6569f76b2d..c81f933bca 100644
--- a/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
+++ b/osu.Game/Beatmaps/Formats/LegacyStoryboardDecoder.cs
@@ -3,7 +3,6 @@
using System;
using System.Collections.Generic;
-using System.Globalization;
using System.IO;
using osuTK;
using osuTK.Graphics;
@@ -93,8 +92,8 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]);
var path = CleanFilename(split[3]);
- var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo);
- var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo);
+ var x = Parsing.ParseFloat(split[4], Parsing.MAX_COORDINATE_VALUE);
+ var y = Parsing.ParseFloat(split[5], Parsing.MAX_COORDINATE_VALUE);
storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y));
storyboard.GetLayer(layer).Add(storyboardSprite);
break;
@@ -105,10 +104,10 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]);
var path = CleanFilename(split[3]);
- var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo);
- var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo);
- var frameCount = int.Parse(split[6]);
- var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo);
+ var x = Parsing.ParseFloat(split[4], Parsing.MAX_COORDINATE_VALUE);
+ var y = Parsing.ParseFloat(split[5], Parsing.MAX_COORDINATE_VALUE);
+ var frameCount = Parsing.ParseInt(split[6]);
+ var frameDelay = Parsing.ParseDouble(split[7]);
var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever;
storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType);
storyboard.GetLayer(layer).Add(storyboardSprite);
@@ -117,10 +116,10 @@ namespace osu.Game.Beatmaps.Formats
case LegacyEventType.Sample:
{
- var time = double.Parse(split[1], CultureInfo.InvariantCulture);
+ var time = Parsing.ParseDouble(split[1]);
var layer = parseLayer(split[2]);
var path = CleanFilename(split[3]);
- var volume = split.Length > 4 ? float.Parse(split[4], CultureInfo.InvariantCulture) : 100;
+ var volume = split.Length > 4 ? Parsing.ParseFloat(split[4]) : 100;
storyboard.GetLayer(layer).Add(new StoryboardSampleInfo(path, time, (int)volume));
break;
}
@@ -138,17 +137,17 @@ namespace osu.Game.Beatmaps.Formats
case "T":
{
var triggerName = split[1];
- var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue;
- var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue;
- var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0;
+ var startTime = split.Length > 2 ? Parsing.ParseDouble(split[2]) : double.MinValue;
+ var endTime = split.Length > 3 ? Parsing.ParseDouble(split[3]) : double.MaxValue;
+ var groupNumber = split.Length > 4 ? Parsing.ParseInt(split[4]) : 0;
timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber);
break;
}
case "L":
{
- var startTime = double.Parse(split[1], CultureInfo.InvariantCulture);
- var loopCount = int.Parse(split[2]);
+ var startTime = Parsing.ParseDouble(split[1]);
+ var loopCount = Parsing.ParseInt(split[2]);
timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount);
break;
}
@@ -158,52 +157,52 @@ namespace osu.Game.Beatmaps.Formats
if (string.IsNullOrEmpty(split[3]))
split[3] = split[2];
- var easing = (Easing)int.Parse(split[1]);
- var startTime = double.Parse(split[2], CultureInfo.InvariantCulture);
- var endTime = double.Parse(split[3], CultureInfo.InvariantCulture);
+ var easing = (Easing)Parsing.ParseInt(split[1]);
+ var startTime = Parsing.ParseDouble(split[2]);
+ var endTime = Parsing.ParseDouble(split[3]);
switch (commandType)
{
case "F":
{
- var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
- var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
+ var startValue = Parsing.ParseFloat(split[4]);
+ var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue);
break;
}
case "S":
{
- var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
- var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
+ var startValue = Parsing.ParseFloat(split[4]);
+ var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Scale.Add(easing, startTime, endTime, startValue, endValue);
break;
}
case "V":
{
- var startX = float.Parse(split[4], CultureInfo.InvariantCulture);
- var startY = float.Parse(split[5], CultureInfo.InvariantCulture);
- var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX;
- var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
+ var startX = Parsing.ParseFloat(split[4]);
+ var startY = Parsing.ParseFloat(split[5]);
+ var endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
+ var endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
timelineGroup?.VectorScale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY));
break;
}
case "R":
{
- var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
- var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
+ var startValue = Parsing.ParseFloat(split[4]);
+ var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Rotation.Add(easing, startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue));
break;
}
case "M":
{
- var startX = float.Parse(split[4], CultureInfo.InvariantCulture);
- var startY = float.Parse(split[5], CultureInfo.InvariantCulture);
- var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX;
- var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY;
+ var startX = Parsing.ParseFloat(split[4]);
+ var startY = Parsing.ParseFloat(split[5]);
+ var endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
+ var endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
timelineGroup?.X.Add(easing, startTime, endTime, startX, endX);
timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY);
break;
@@ -211,28 +210,28 @@ namespace osu.Game.Beatmaps.Formats
case "MX":
{
- var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
- var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
+ var startValue = Parsing.ParseFloat(split[4]);
+ var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue);
break;
}
case "MY":
{
- var startValue = float.Parse(split[4], CultureInfo.InvariantCulture);
- var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue;
+ var startValue = Parsing.ParseFloat(split[4]);
+ var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue);
break;
}
case "C":
{
- var startRed = float.Parse(split[4], CultureInfo.InvariantCulture);
- var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture);
- var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture);
- var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed;
- var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen;
- var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue;
+ var startRed = Parsing.ParseFloat(split[4]);
+ var startGreen = Parsing.ParseFloat(split[5]);
+ var startBlue = Parsing.ParseFloat(split[6]);
+ var endRed = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startRed;
+ var endGreen = split.Length > 8 ? Parsing.ParseFloat(split[8]) : startGreen;
+ var endBlue = split.Length > 9 ? Parsing.ParseFloat(split[9]) : startBlue;
timelineGroup?.Colour.Add(easing, startTime, endTime,
new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1),
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1));
diff --git a/osu.Game/Database/IModelDownloader.cs b/osu.Game/Database/IModelDownloader.cs
index 17f1ccab06..99aeb4eacf 100644
--- a/osu.Game/Database/IModelDownloader.cs
+++ b/osu.Game/Database/IModelDownloader.cs
@@ -15,11 +15,13 @@ namespace osu.Game.Database
{
///
/// Fired when a download begins.
+ /// This is NOT run on the update thread and should be scheduled.
///
event Action> DownloadBegan;
///
/// Fired when a download is interrupted, either due to user cancellation or failure.
+ /// This is NOT run on the update thread and should be scheduled.
///
event Action> DownloadFailed;
diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs
index 59dd823266..984f5e52d1 100644
--- a/osu.Game/Graphics/OsuColour.cs
+++ b/osu.Game/Graphics/OsuColour.cs
@@ -1,8 +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 System;
-using System.Globalization;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Beatmaps;
using osuTK.Graphics;
@@ -13,45 +12,6 @@ namespace osu.Game.Graphics
public static Color4 Gray(float amt) => new Color4(amt, amt, amt, 1f);
public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255);
- public static Color4 FromHex(string hex)
- {
- var hexSpan = hex[0] == '#' ? hex.AsSpan().Slice(1) : hex.AsSpan();
-
- switch (hexSpan.Length)
- {
- default:
- throw new ArgumentException(@"Invalid hex string length!");
-
- case 3:
- return new Color4(
- (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17),
- (byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17),
- (byte)(byte.Parse(hexSpan.Slice(2, 1), NumberStyles.HexNumber) * 17),
- 255);
-
- case 6:
- return new Color4(
- byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber),
- byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber),
- byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber),
- 255);
-
- case 4:
- return new Color4(
- (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17),
- (byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17),
- (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17),
- (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17));
-
- case 8:
- return new Color4(
- byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber),
- byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber),
- byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber),
- byte.Parse(hexSpan.Slice(6, 2), NumberStyles.HexNumber));
- }
- }
-
public Color4 ForDifficultyRating(DifficultyRating difficulty, bool useLighterColour = false)
{
switch (difficulty)
@@ -78,105 +38,105 @@ namespace osu.Game.Graphics
}
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
- public readonly Color4 PurpleLighter = FromHex(@"eeeeff");
- public readonly Color4 PurpleLight = FromHex(@"aa88ff");
- public readonly Color4 PurpleLightAlternative = FromHex(@"cba4da");
- public readonly Color4 Purple = FromHex(@"8866ee");
- public readonly Color4 PurpleDark = FromHex(@"6644cc");
- public readonly Color4 PurpleDarkAlternative = FromHex(@"312436");
- public readonly Color4 PurpleDarker = FromHex(@"441188");
+ public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff");
+ public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff");
+ public readonly Color4 PurpleLightAlternative = Color4Extensions.FromHex(@"cba4da");
+ public readonly Color4 Purple = Color4Extensions.FromHex(@"8866ee");
+ public readonly Color4 PurpleDark = Color4Extensions.FromHex(@"6644cc");
+ public readonly Color4 PurpleDarkAlternative = Color4Extensions.FromHex(@"312436");
+ public readonly Color4 PurpleDarker = Color4Extensions.FromHex(@"441188");
- public readonly Color4 PinkLighter = FromHex(@"ffddee");
- public readonly Color4 PinkLight = FromHex(@"ff99cc");
- public readonly Color4 Pink = FromHex(@"ff66aa");
- public readonly Color4 PinkDark = FromHex(@"cc5288");
- public readonly Color4 PinkDarker = FromHex(@"bb1177");
+ public readonly Color4 PinkLighter = Color4Extensions.FromHex(@"ffddee");
+ public readonly Color4 PinkLight = Color4Extensions.FromHex(@"ff99cc");
+ public readonly Color4 Pink = Color4Extensions.FromHex(@"ff66aa");
+ public readonly Color4 PinkDark = Color4Extensions.FromHex(@"cc5288");
+ public readonly Color4 PinkDarker = Color4Extensions.FromHex(@"bb1177");
- public readonly Color4 BlueLighter = FromHex(@"ddffff");
- public readonly Color4 BlueLight = FromHex(@"99eeff");
- public readonly Color4 Blue = FromHex(@"66ccff");
- public readonly Color4 BlueDark = FromHex(@"44aadd");
- public readonly Color4 BlueDarker = FromHex(@"2299bb");
+ public readonly Color4 BlueLighter = Color4Extensions.FromHex(@"ddffff");
+ public readonly Color4 BlueLight = Color4Extensions.FromHex(@"99eeff");
+ public readonly Color4 Blue = Color4Extensions.FromHex(@"66ccff");
+ public readonly Color4 BlueDark = Color4Extensions.FromHex(@"44aadd");
+ public readonly Color4 BlueDarker = Color4Extensions.FromHex(@"2299bb");
- public readonly Color4 YellowLighter = FromHex(@"ffffdd");
- public readonly Color4 YellowLight = FromHex(@"ffdd55");
- public readonly Color4 Yellow = FromHex(@"ffcc22");
- public readonly Color4 YellowDark = FromHex(@"eeaa00");
- public readonly Color4 YellowDarker = FromHex(@"cc6600");
+ public readonly Color4 YellowLighter = Color4Extensions.FromHex(@"ffffdd");
+ public readonly Color4 YellowLight = Color4Extensions.FromHex(@"ffdd55");
+ public readonly Color4 Yellow = Color4Extensions.FromHex(@"ffcc22");
+ public readonly Color4 YellowDark = Color4Extensions.FromHex(@"eeaa00");
+ public readonly Color4 YellowDarker = Color4Extensions.FromHex(@"cc6600");
- public readonly Color4 GreenLighter = FromHex(@"eeffcc");
- public readonly Color4 GreenLight = FromHex(@"b3d944");
- public readonly Color4 Green = FromHex(@"88b300");
- public readonly Color4 GreenDark = FromHex(@"668800");
- public readonly Color4 GreenDarker = FromHex(@"445500");
+ public readonly Color4 GreenLighter = Color4Extensions.FromHex(@"eeffcc");
+ public readonly Color4 GreenLight = Color4Extensions.FromHex(@"b3d944");
+ public readonly Color4 Green = Color4Extensions.FromHex(@"88b300");
+ public readonly Color4 GreenDark = Color4Extensions.FromHex(@"668800");
+ public readonly Color4 GreenDarker = Color4Extensions.FromHex(@"445500");
- public readonly Color4 Sky = FromHex(@"6bb5ff");
- public readonly Color4 GreySkyLighter = FromHex(@"c6e3f4");
- public readonly Color4 GreySkyLight = FromHex(@"8ab3cc");
- public readonly Color4 GreySky = FromHex(@"405461");
- public readonly Color4 GreySkyDark = FromHex(@"303d47");
- public readonly Color4 GreySkyDarker = FromHex(@"21272c");
+ public readonly Color4 Sky = Color4Extensions.FromHex(@"6bb5ff");
+ public readonly Color4 GreySkyLighter = Color4Extensions.FromHex(@"c6e3f4");
+ public readonly Color4 GreySkyLight = Color4Extensions.FromHex(@"8ab3cc");
+ public readonly Color4 GreySky = Color4Extensions.FromHex(@"405461");
+ public readonly Color4 GreySkyDark = Color4Extensions.FromHex(@"303d47");
+ public readonly Color4 GreySkyDarker = Color4Extensions.FromHex(@"21272c");
- public readonly Color4 Seafoam = FromHex(@"05ffa2");
- public readonly Color4 GreySeafoamLighter = FromHex(@"9ebab1");
- public readonly Color4 GreySeafoamLight = FromHex(@"4d7365");
- public readonly Color4 GreySeafoam = FromHex(@"33413c");
- public readonly Color4 GreySeafoamDark = FromHex(@"2c3532");
- public readonly Color4 GreySeafoamDarker = FromHex(@"1e2422");
+ public readonly Color4 Seafoam = Color4Extensions.FromHex(@"05ffa2");
+ public readonly Color4 GreySeafoamLighter = Color4Extensions.FromHex(@"9ebab1");
+ public readonly Color4 GreySeafoamLight = Color4Extensions.FromHex(@"4d7365");
+ public readonly Color4 GreySeafoam = Color4Extensions.FromHex(@"33413c");
+ public readonly Color4 GreySeafoamDark = Color4Extensions.FromHex(@"2c3532");
+ public readonly Color4 GreySeafoamDarker = Color4Extensions.FromHex(@"1e2422");
- public readonly Color4 Cyan = FromHex(@"05f4fd");
- public readonly Color4 GreyCyanLighter = FromHex(@"77b1b3");
- public readonly Color4 GreyCyanLight = FromHex(@"436d6f");
- public readonly Color4 GreyCyan = FromHex(@"293d3e");
- public readonly Color4 GreyCyanDark = FromHex(@"243536");
- public readonly Color4 GreyCyanDarker = FromHex(@"1e2929");
+ public readonly Color4 Cyan = Color4Extensions.FromHex(@"05f4fd");
+ public readonly Color4 GreyCyanLighter = Color4Extensions.FromHex(@"77b1b3");
+ public readonly Color4 GreyCyanLight = Color4Extensions.FromHex(@"436d6f");
+ public readonly Color4 GreyCyan = Color4Extensions.FromHex(@"293d3e");
+ public readonly Color4 GreyCyanDark = Color4Extensions.FromHex(@"243536");
+ public readonly Color4 GreyCyanDarker = Color4Extensions.FromHex(@"1e2929");
- public readonly Color4 Lime = FromHex(@"82ff05");
- public readonly Color4 GreyLimeLighter = FromHex(@"deff87");
- public readonly Color4 GreyLimeLight = FromHex(@"657259");
- public readonly Color4 GreyLime = FromHex(@"3f443a");
- public readonly Color4 GreyLimeDark = FromHex(@"32352e");
- public readonly Color4 GreyLimeDarker = FromHex(@"2e302b");
+ public readonly Color4 Lime = Color4Extensions.FromHex(@"82ff05");
+ public readonly Color4 GreyLimeLighter = Color4Extensions.FromHex(@"deff87");
+ public readonly Color4 GreyLimeLight = Color4Extensions.FromHex(@"657259");
+ public readonly Color4 GreyLime = Color4Extensions.FromHex(@"3f443a");
+ public readonly Color4 GreyLimeDark = Color4Extensions.FromHex(@"32352e");
+ public readonly Color4 GreyLimeDarker = Color4Extensions.FromHex(@"2e302b");
- public readonly Color4 Violet = FromHex(@"bf04ff");
- public readonly Color4 GreyVioletLighter = FromHex(@"ebb8fe");
- public readonly Color4 GreyVioletLight = FromHex(@"685370");
- public readonly Color4 GreyViolet = FromHex(@"46334d");
- public readonly Color4 GreyVioletDark = FromHex(@"2c2230");
- public readonly Color4 GreyVioletDarker = FromHex(@"201823");
+ public readonly Color4 Violet = Color4Extensions.FromHex(@"bf04ff");
+ public readonly Color4 GreyVioletLighter = Color4Extensions.FromHex(@"ebb8fe");
+ public readonly Color4 GreyVioletLight = Color4Extensions.FromHex(@"685370");
+ public readonly Color4 GreyViolet = Color4Extensions.FromHex(@"46334d");
+ public readonly Color4 GreyVioletDark = Color4Extensions.FromHex(@"2c2230");
+ public readonly Color4 GreyVioletDarker = Color4Extensions.FromHex(@"201823");
- public readonly Color4 Carmine = FromHex(@"ff0542");
- public readonly Color4 GreyCarmineLighter = FromHex(@"deaab4");
- public readonly Color4 GreyCarmineLight = FromHex(@"644f53");
- public readonly Color4 GreyCarmine = FromHex(@"342b2d");
- public readonly Color4 GreyCarmineDark = FromHex(@"302a2b");
- public readonly Color4 GreyCarmineDarker = FromHex(@"241d1e");
+ public readonly Color4 Carmine = Color4Extensions.FromHex(@"ff0542");
+ public readonly Color4 GreyCarmineLighter = Color4Extensions.FromHex(@"deaab4");
+ public readonly Color4 GreyCarmineLight = Color4Extensions.FromHex(@"644f53");
+ public readonly Color4 GreyCarmine = Color4Extensions.FromHex(@"342b2d");
+ public readonly Color4 GreyCarmineDark = Color4Extensions.FromHex(@"302a2b");
+ public readonly Color4 GreyCarmineDarker = Color4Extensions.FromHex(@"241d1e");
- public readonly Color4 Gray0 = FromHex(@"000");
- public readonly Color4 Gray1 = FromHex(@"111");
- public readonly Color4 Gray2 = FromHex(@"222");
- public readonly Color4 Gray3 = FromHex(@"333");
- public readonly Color4 Gray4 = FromHex(@"444");
- public readonly Color4 Gray5 = FromHex(@"555");
- public readonly Color4 Gray6 = FromHex(@"666");
- public readonly Color4 Gray7 = FromHex(@"777");
- public readonly Color4 Gray8 = FromHex(@"888");
- public readonly Color4 Gray9 = FromHex(@"999");
- public readonly Color4 GrayA = FromHex(@"aaa");
- public readonly Color4 GrayB = FromHex(@"bbb");
- public readonly Color4 GrayC = FromHex(@"ccc");
- public readonly Color4 GrayD = FromHex(@"ddd");
- public readonly Color4 GrayE = FromHex(@"eee");
- public readonly Color4 GrayF = FromHex(@"fff");
+ public readonly Color4 Gray0 = Color4Extensions.FromHex(@"000");
+ public readonly Color4 Gray1 = Color4Extensions.FromHex(@"111");
+ public readonly Color4 Gray2 = Color4Extensions.FromHex(@"222");
+ public readonly Color4 Gray3 = Color4Extensions.FromHex(@"333");
+ public readonly Color4 Gray4 = Color4Extensions.FromHex(@"444");
+ public readonly Color4 Gray5 = Color4Extensions.FromHex(@"555");
+ public readonly Color4 Gray6 = Color4Extensions.FromHex(@"666");
+ public readonly Color4 Gray7 = Color4Extensions.FromHex(@"777");
+ public readonly Color4 Gray8 = Color4Extensions.FromHex(@"888");
+ public readonly Color4 Gray9 = Color4Extensions.FromHex(@"999");
+ public readonly Color4 GrayA = Color4Extensions.FromHex(@"aaa");
+ public readonly Color4 GrayB = Color4Extensions.FromHex(@"bbb");
+ public readonly Color4 GrayC = Color4Extensions.FromHex(@"ccc");
+ public readonly Color4 GrayD = Color4Extensions.FromHex(@"ddd");
+ public readonly Color4 GrayE = Color4Extensions.FromHex(@"eee");
+ public readonly Color4 GrayF = Color4Extensions.FromHex(@"fff");
- public readonly Color4 RedLighter = FromHex(@"ffeded");
- public readonly Color4 RedLight = FromHex(@"ed7787");
- public readonly Color4 Red = FromHex(@"ed1121");
- public readonly Color4 RedDark = FromHex(@"ba0011");
- public readonly Color4 RedDarker = FromHex(@"870000");
+ public readonly Color4 RedLighter = Color4Extensions.FromHex(@"ffeded");
+ public readonly Color4 RedLight = Color4Extensions.FromHex(@"ed7787");
+ public readonly Color4 Red = Color4Extensions.FromHex(@"ed1121");
+ public readonly Color4 RedDark = Color4Extensions.FromHex(@"ba0011");
+ public readonly Color4 RedDarker = Color4Extensions.FromHex(@"870000");
- public readonly Color4 ChatBlue = FromHex(@"17292e");
+ public readonly Color4 ChatBlue = Color4Extensions.FromHex(@"17292e");
- public readonly Color4 ContextMenuGray = FromHex(@"223034");
+ public readonly Color4 ContextMenuGray = Color4Extensions.FromHex(@"223034");
}
}
diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
index 591ed3df83..a3ca851341 100644
--- a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
+++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs
@@ -4,6 +4,7 @@
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
@@ -38,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface
sampleClick = audio.Samples.Get(@"UI/generic-select");
BackgroundColour = Color4.Transparent;
- BackgroundColourHover = OsuColour.FromHex(@"172023");
+ BackgroundColourHover = Color4Extensions.FromHex(@"172023");
updateTextColour();
}
@@ -57,7 +58,7 @@ namespace osu.Game.Graphics.UserInterface
break;
case MenuItemType.Highlighted:
- text.Colour = OsuColour.FromHex(@"ffcc22");
+ text.Colour = Color4Extensions.FromHex(@"ffcc22");
break;
}
}
diff --git a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
index f44bd72aee..0e995ca73d 100644
--- a/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
+++ b/osu.Game/Graphics/UserInterfaceV2/LabelledDrawable.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -42,7 +43,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex("1c2125"),
+ Colour = Color4Extensions.FromHex("1c2125"),
},
new FillFlowContainer
{
diff --git a/osu.Game/Online/DownloadTrackingComposite.cs b/osu.Game/Online/DownloadTrackingComposite.cs
index 6e7ef99c6d..0769be2998 100644
--- a/osu.Game/Online/DownloadTrackingComposite.cs
+++ b/osu.Game/Online/DownloadTrackingComposite.cs
@@ -53,17 +53,17 @@ namespace osu.Game.Online
manager.ItemRemoved += itemRemoved;
}
- private void downloadBegan(ArchiveDownloadRequest request)
+ private void downloadBegan(ArchiveDownloadRequest request) => Schedule(() =>
{
if (request.Model.Equals(Model.Value))
attachDownload(request);
- }
+ });
- private void downloadFailed(ArchiveDownloadRequest request)
+ private void downloadFailed(ArchiveDownloadRequest request) => Schedule(() =>
{
if (request.Model.Equals(Model.Value))
attachDownload(null);
- }
+ });
private ArchiveDownloadRequest attachedRequest;
diff --git a/osu.Game/Online/Leaderboards/DrawableRank.cs b/osu.Game/Online/Leaderboards/DrawableRank.cs
index 20bda4601f..45b91bbf81 100644
--- a/osu.Game/Online/Leaderboards/DrawableRank.cs
+++ b/osu.Game/Online/Leaderboards/DrawableRank.cs
@@ -80,23 +80,23 @@ namespace osu.Game.Online.Leaderboards
{
case ScoreRank.XH:
case ScoreRank.X:
- return OsuColour.FromHex(@"ce1c9d");
+ return Color4Extensions.FromHex(@"ce1c9d");
case ScoreRank.SH:
case ScoreRank.S:
- return OsuColour.FromHex(@"00a8b5");
+ return Color4Extensions.FromHex(@"00a8b5");
case ScoreRank.A:
- return OsuColour.FromHex(@"7cce14");
+ return Color4Extensions.FromHex(@"7cce14");
case ScoreRank.B:
- return OsuColour.FromHex(@"e3b130");
+ return Color4Extensions.FromHex(@"e3b130");
case ScoreRank.C:
- return OsuColour.FromHex(@"f18252");
+ return Color4Extensions.FromHex(@"f18252");
default:
- return OsuColour.FromHex(@"e95353");
+ return Color4Extensions.FromHex(@"e95353");
}
}
@@ -109,23 +109,23 @@ namespace osu.Game.Online.Leaderboards
{
case ScoreRank.XH:
case ScoreRank.SH:
- return ColourInfo.GradientVertical(Color4.White, OsuColour.FromHex("afdff0"));
+ return ColourInfo.GradientVertical(Color4.White, Color4Extensions.FromHex("afdff0"));
case ScoreRank.X:
case ScoreRank.S:
- return ColourInfo.GradientVertical(OsuColour.FromHex(@"ffe7a8"), OsuColour.FromHex(@"ffb800"));
+ return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"ffe7a8"), Color4Extensions.FromHex(@"ffb800"));
case ScoreRank.A:
- return OsuColour.FromHex(@"275227");
+ return Color4Extensions.FromHex(@"275227");
case ScoreRank.B:
- return OsuColour.FromHex(@"553a2b");
+ return Color4Extensions.FromHex(@"553a2b");
case ScoreRank.C:
- return OsuColour.FromHex(@"473625");
+ return Color4Extensions.FromHex(@"473625");
default:
- return OsuColour.FromHex(@"512525");
+ return Color4Extensions.FromHex(@"512525");
}
}
}
diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
index ba92b993a2..1469f29874 100644
--- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs
+++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs
@@ -200,7 +200,7 @@ namespace osu.Game.Online.Leaderboards
scoreLabel = new GlowingSpriteText
{
TextColour = Color4.White,
- GlowColour = OsuColour.FromHex(@"83ccfa"),
+ GlowColour = Color4Extensions.FromHex(@"83ccfa"),
Text = score.TotalScore.ToString(@"N0"),
Font = OsuFont.Numeric.With(size: 23),
},
@@ -325,7 +325,7 @@ namespace osu.Game.Online.Leaderboards
Origin = Anchor.Centre,
Size = new Vector2(icon_size),
Rotation = 45,
- Colour = OsuColour.FromHex(@"3087ac"),
+ Colour = Color4Extensions.FromHex(@"3087ac"),
Icon = FontAwesome.Solid.Square,
Shadow = true,
},
@@ -334,7 +334,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(icon_size - 6),
- Colour = OsuColour.FromHex(@"a4edff"),
+ Colour = Color4Extensions.FromHex(@"a4edff"),
Icon = statistic.Icon,
},
},
@@ -344,7 +344,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
TextColour = Color4.White,
- GlowColour = OsuColour.FromHex(@"83ccfa"),
+ GlowColour = Color4Extensions.FromHex(@"83ccfa"),
Text = statistic.Value,
Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold),
},
diff --git a/osu.Game/Overlays/BeatmapSet/BasicStats.cs b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
index ba0a62ec2f..a2464bef09 100644
--- a/osu.Game/Overlays/BeatmapSet/BasicStats.cs
+++ b/osu.Game/Overlays/BeatmapSet/BasicStats.cs
@@ -3,6 +3,7 @@
using System;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@@ -124,7 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet
Icon = FontAwesome.Solid.Square,
Size = new Vector2(12),
Rotation = 45,
- Colour = OsuColour.FromHex(@"441288"),
+ Colour = Color4Extensions.FromHex(@"441288"),
},
new SpriteIcon
{
@@ -132,7 +133,7 @@ namespace osu.Game.Overlays.BeatmapSet
Origin = Anchor.Centre,
Icon = icon,
Size = new Vector2(12),
- Colour = OsuColour.FromHex(@"f7dd55"),
+ Colour = Color4Extensions.FromHex(@"f7dd55"),
Scale = new Vector2(0.8f),
},
value = new OsuSpriteText
diff --git a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs
index 6de1d3fca7..99b0b2ed3b 100644
--- a/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs
+++ b/osu.Game/Overlays/BeatmapSet/Buttons/HeaderButton.cs
@@ -2,8 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
-using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.BeatmapSet.Buttons
@@ -19,9 +19,9 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
[BackgroundDependencyLoader]
private void load()
{
- BackgroundColour = OsuColour.FromHex(@"094c5f");
- Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b");
- Triangles.ColourDark = OsuColour.FromHex(@"094c5f");
+ BackgroundColour = Color4Extensions.FromHex(@"094c5f");
+ Triangles.ColourLight = Color4Extensions.FromHex(@"0f7c9b");
+ Triangles.ColourDark = Color4Extensions.FromHex(@"094c5f");
Triangles.TriangleScale = 1.5f;
}
}
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
index f1250679c1..097ca27bf7 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoreTable.cs
@@ -52,22 +52,28 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
highAccuracyColour = colours.GreenLight;
}
- public IReadOnlyList Scores
+ private bool showPerformancePoints;
+
+ public void DisplayScores(IReadOnlyList scores, bool showPerformanceColumn)
{
- set
- {
- Content = null;
- backgroundFlow.Clear();
+ ClearScores();
- if (value?.Any() != true)
- return;
+ if (!scores.Any())
+ return;
- for (int i = 0; i < value.Count; i++)
- backgroundFlow.Add(new ScoreTableRowBackground(i, value[i], row_height));
+ showPerformancePoints = showPerformanceColumn;
- Columns = createHeaders(value[0]);
- Content = value.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
- }
+ for (int i = 0; i < scores.Count; i++)
+ backgroundFlow.Add(new ScoreTableRowBackground(i, scores[i], row_height));
+
+ Columns = createHeaders(scores.FirstOrDefault());
+ Content = scores.Select((s, i) => createContent(i, s)).ToArray().ToRectangular();
+ }
+
+ public void ClearScores()
+ {
+ Content = null;
+ backgroundFlow.Clear();
}
private TableColumn[] createHeaders(ScoreInfo score)
@@ -88,11 +94,10 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
columns.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
- columns.AddRange(new[]
- {
- new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)),
- new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)),
- });
+ if (showPerformancePoints)
+ columns.Add(new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)));
+
+ columns.Add(new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)));
return columns.ToArray();
}
@@ -150,24 +155,25 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
});
}
- content.AddRange(new Drawable[]
+ if (showPerformancePoints)
{
- new OsuSpriteText
+ content.Add(new OsuSpriteText
{
Text = $@"{score.PP:N0}",
Font = OsuFont.GetFont(size: text_size)
- },
- new FillFlowContainer
+ });
+ }
+
+ content.Add(new FillFlowContainer
+ {
+ Direction = FillDirection.Horizontal,
+ AutoSizeAxes = Axes.Both,
+ Spacing = new Vector2(1),
+ ChildrenEnumerable = score.Mods.Select(m => new ModIcon(m)
{
- Direction = FillDirection.Horizontal,
AutoSizeAxes = Axes.Both,
- Spacing = new Vector2(1),
- ChildrenEnumerable = score.Mods.Select(m => new ModIcon(m)
- {
- AutoSizeAxes = Axes.Both,
- Scale = new Vector2(0.3f)
- })
- },
+ Scale = new Vector2(0.3f)
+ })
});
return content.ToArray();
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
index 7607eac1f8..a58d662de7 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/ScoresContainer.cs
@@ -52,17 +52,17 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (value?.Scores.Any() != true)
{
- scoreTable.Scores = null;
+ scoreTable.ClearScores();
scoreTable.Hide();
return;
}
var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList();
+ var topScore = scoreInfos.First();
- scoreTable.Scores = scoreInfos;
+ scoreTable.DisplayScores(scoreInfos, topScore.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked);
scoreTable.Show();
- var topScore = scoreInfos.First();
var userScore = value.UserScore;
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);
diff --git a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs
index a15dc57d23..a92346e0fe 100644
--- a/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs
+++ b/osu.Game/Overlays/BeatmapSet/Scores/TopScoreStatisticsSection.cs
@@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation;
+using osu.Game.Beatmaps;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods;
@@ -96,6 +97,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
totalScoreColumn.Text = $@"{value.TotalScore:N0}";
accuracyColumn.Text = value.DisplayAccuracy;
maxComboColumn.Text = $@"{value.MaxCombo:N0}x";
+ ppColumn.Alpha = value.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked ? 1 : 0;
ppColumn.Text = $@"{value.PP:N0}";
statisticsColumns.ChildrenEnumerable = value.SortedStatistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value));
diff --git a/osu.Game/Overlays/Changelog/ChangelogHeader.cs b/osu.Game/Overlays/Changelog/ChangelogHeader.cs
index dcadbf4cf5..532efeb4bd 100644
--- a/osu.Game/Overlays/Changelog/ChangelogHeader.cs
+++ b/osu.Game/Overlays/Changelog/ChangelogHeader.cs
@@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Changelog
public Action ListingSelected;
- public UpdateStreamBadgeArea Streams;
+ public ChangelogUpdateStreamControl Streams;
private const string listing_string = "listing";
@@ -95,7 +95,7 @@ namespace osu.Game.Overlays.Changelog
Horizontal = 65,
Vertical = 20
},
- Child = Streams = new UpdateStreamBadgeArea()
+ Child = Streams = new ChangelogUpdateStreamControl()
}
}
};
diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs
new file mode 100644
index 0000000000..509a6dabae
--- /dev/null
+++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamControl.cs
@@ -0,0 +1,12 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Online.API.Requests.Responses;
+
+namespace osu.Game.Overlays.Changelog
+{
+ public class ChangelogUpdateStreamControl : OverlayStreamControl
+ {
+ protected override OverlayStreamItem CreateStreamItem(APIUpdateStream value) => new ChangelogUpdateStreamItem(value);
+ }
+}
diff --git a/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.cs
new file mode 100644
index 0000000000..f8e1ac0c84
--- /dev/null
+++ b/osu.Game/Overlays/Changelog/ChangelogUpdateStreamItem.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 Humanizer;
+using osu.Game.Graphics;
+using osu.Game.Online.API.Requests.Responses;
+using osuTK.Graphics;
+
+namespace osu.Game.Overlays.Changelog
+{
+ public class ChangelogUpdateStreamItem : OverlayStreamItem
+ {
+ public ChangelogUpdateStreamItem(APIUpdateStream stream)
+ : base(stream)
+ {
+ if (stream.IsFeatured)
+ Width *= 2;
+ }
+
+ protected override string MainText => Value.DisplayName;
+
+ protected override string AdditionalText => Value.LatestBuild.DisplayVersion;
+
+ protected override string InfoText => Value.LatestBuild.Users > 0 ? $"{"user".ToQuantity(Value.LatestBuild.Users, "N0")} online" : null;
+
+ protected override Color4 GetBarColour(OsuColour colours) => Value.Colour;
+ }
+}
diff --git a/osu.Game/Overlays/Chat/ChatLine.cs b/osu.Game/Overlays/Chat/ChatLine.cs
index 8abde8a24f..496986dc56 100644
--- a/osu.Game/Overlays/Chat/ChatLine.cs
+++ b/osu.Game/Overlays/Chat/ChatLine.cs
@@ -123,7 +123,7 @@ namespace osu.Game.Overlays.Chat
EdgeEffect = new EdgeEffectParameters
{
Radius = 1,
- Colour = OsuColour.FromHex(message.Sender.Colour),
+ Colour = Color4Extensions.FromHex(message.Sender.Colour),
Type = EdgeEffectType.Shadow,
},
Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 },
@@ -172,7 +172,7 @@ namespace osu.Game.Overlays.Chat
t.Font = OsuFont.GetFont(italics: true);
if (senderHasBackground)
- t.Colour = OsuColour.FromHex(message.Sender.Colour);
+ t.Colour = Color4Extensions.FromHex(message.Sender.Colour);
}
t.Font = t.Font.With(size: TextSize);
@@ -249,41 +249,41 @@ namespace osu.Game.Overlays.Chat
private static readonly Color4[] username_colours =
{
- OsuColour.FromHex("588c7e"),
- OsuColour.FromHex("b2a367"),
- OsuColour.FromHex("c98f65"),
- OsuColour.FromHex("bc5151"),
- OsuColour.FromHex("5c8bd6"),
- OsuColour.FromHex("7f6ab7"),
- OsuColour.FromHex("a368ad"),
- OsuColour.FromHex("aa6880"),
+ Color4Extensions.FromHex("588c7e"),
+ Color4Extensions.FromHex("b2a367"),
+ Color4Extensions.FromHex("c98f65"),
+ Color4Extensions.FromHex("bc5151"),
+ Color4Extensions.FromHex("5c8bd6"),
+ Color4Extensions.FromHex("7f6ab7"),
+ Color4Extensions.FromHex("a368ad"),
+ Color4Extensions.FromHex("aa6880"),
- OsuColour.FromHex("6fad9b"),
- OsuColour.FromHex("f2e394"),
- OsuColour.FromHex("f2ae72"),
- OsuColour.FromHex("f98f8a"),
- OsuColour.FromHex("7daef4"),
- OsuColour.FromHex("a691f2"),
- OsuColour.FromHex("c894d3"),
- OsuColour.FromHex("d895b0"),
+ Color4Extensions.FromHex("6fad9b"),
+ Color4Extensions.FromHex("f2e394"),
+ Color4Extensions.FromHex("f2ae72"),
+ Color4Extensions.FromHex("f98f8a"),
+ Color4Extensions.FromHex("7daef4"),
+ Color4Extensions.FromHex("a691f2"),
+ Color4Extensions.FromHex("c894d3"),
+ Color4Extensions.FromHex("d895b0"),
- OsuColour.FromHex("53c4a1"),
- OsuColour.FromHex("eace5c"),
- OsuColour.FromHex("ea8c47"),
- OsuColour.FromHex("fc4f4f"),
- OsuColour.FromHex("3d94ea"),
- OsuColour.FromHex("7760ea"),
- OsuColour.FromHex("af52c6"),
- OsuColour.FromHex("e25696"),
+ Color4Extensions.FromHex("53c4a1"),
+ Color4Extensions.FromHex("eace5c"),
+ Color4Extensions.FromHex("ea8c47"),
+ Color4Extensions.FromHex("fc4f4f"),
+ Color4Extensions.FromHex("3d94ea"),
+ Color4Extensions.FromHex("7760ea"),
+ Color4Extensions.FromHex("af52c6"),
+ Color4Extensions.FromHex("e25696"),
- OsuColour.FromHex("677c66"),
- OsuColour.FromHex("9b8732"),
- OsuColour.FromHex("8c5129"),
- OsuColour.FromHex("8c3030"),
- OsuColour.FromHex("1f5d91"),
- OsuColour.FromHex("4335a5"),
- OsuColour.FromHex("812a96"),
- OsuColour.FromHex("992861"),
+ Color4Extensions.FromHex("677c66"),
+ Color4Extensions.FromHex("9b8732"),
+ Color4Extensions.FromHex("8c5129"),
+ Color4Extensions.FromHex("8c3030"),
+ Color4Extensions.FromHex("1f5d91"),
+ Color4Extensions.FromHex("4335a5"),
+ Color4Extensions.FromHex("812a96"),
+ Color4Extensions.FromHex("992861"),
};
}
}
diff --git a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs
index 25a9a51638..b46ca6b040 100644
--- a/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs
+++ b/osu.Game/Overlays/Chat/Selection/ChannelSelectionOverlay.cs
@@ -41,10 +41,10 @@ namespace osu.Game.Overlays.Chat.Selection
{
RelativeSizeAxes = Axes.X;
- Waves.FirstWaveColour = OsuColour.FromHex("353535");
- Waves.SecondWaveColour = OsuColour.FromHex("434343");
- Waves.ThirdWaveColour = OsuColour.FromHex("515151");
- Waves.FourthWaveColour = OsuColour.FromHex("595959");
+ Waves.FirstWaveColour = Color4Extensions.FromHex("353535");
+ Waves.SecondWaveColour = Color4Extensions.FromHex("434343");
+ Waves.ThirdWaveColour = Color4Extensions.FromHex("515151");
+ Waves.FourthWaveColour = Color4Extensions.FromHex("595959");
Children = new Drawable[]
{
@@ -154,7 +154,7 @@ namespace osu.Game.Overlays.Chat.Selection
{
bg.Colour = colours.Gray3;
triangles.ColourDark = colours.Gray3;
- triangles.ColourLight = OsuColour.FromHex(@"353535");
+ triangles.ColourLight = Color4Extensions.FromHex(@"353535");
headerBg.Colour = colours.Gray2.Opacity(0.75f);
}
diff --git a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
index 1413b8fe78..5b428a3825 100644
--- a/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
+++ b/osu.Game/Overlays/Chat/Tabs/PrivateChannelTabItem.cs
@@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat.Tabs
{
var user = Value.Users.First();
- BackgroundActive = user.Colour != null ? OsuColour.FromHex(user.Colour) : colours.BlueDark;
+ BackgroundActive = user.Colour != null ? Color4Extensions.FromHex(user.Colour) : colours.BlueDark;
BackgroundInactive = BackgroundActive.Darken(0.5f);
}
}
diff --git a/osu.Game/Overlays/Dialog/PopupDialog.cs b/osu.Game/Overlays/Dialog/PopupDialog.cs
index 37db78faa1..02ef900dc5 100644
--- a/osu.Game/Overlays/Dialog/PopupDialog.cs
+++ b/osu.Game/Overlays/Dialog/PopupDialog.cs
@@ -10,7 +10,6 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
-using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osuTK;
@@ -114,13 +113,13 @@ namespace osu.Game.Overlays.Dialog
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"221a21"),
+ Colour = Color4Extensions.FromHex(@"221a21"),
},
new Triangles
{
RelativeSizeAxes = Axes.Both,
- ColourLight = OsuColour.FromHex(@"271e26"),
- ColourDark = OsuColour.FromHex(@"1e171e"),
+ ColourLight = Color4Extensions.FromHex(@"271e26"),
+ ColourDark = Color4Extensions.FromHex(@"1e171e"),
TriangleScale = 4,
},
},
diff --git a/osu.Game/Overlays/Dialog/PopupDialogButton.cs b/osu.Game/Overlays/Dialog/PopupDialogButton.cs
index 75bae25b73..76ee438d6d 100644
--- a/osu.Game/Overlays/Dialog/PopupDialogButton.cs
+++ b/osu.Game/Overlays/Dialog/PopupDialogButton.cs
@@ -1,7 +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.Game.Graphics;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Dialog
@@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Dialog
public PopupDialogButton()
{
Height = 50;
- BackgroundColour = OsuColour.FromHex(@"150e14");
+ BackgroundColour = Color4Extensions.FromHex(@"150e14");
TextSize = 18;
}
}
diff --git a/osu.Game/Overlays/Direct/FilterControl.cs b/osu.Game/Overlays/Direct/FilterControl.cs
index 70a3ab54fb..e5b2b5cc34 100644
--- a/osu.Game/Overlays/Direct/FilterControl.cs
+++ b/osu.Game/Overlays/Direct/FilterControl.cs
@@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Online.API.Requests;
@@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Direct
{
private DirectRulesetSelector rulesetSelector;
- protected override Color4 BackgroundColour => OsuColour.FromHex(@"384552");
+ protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"384552");
protected override DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked;
protected override BeatmapSearchCategory DefaultCategory => BeatmapSearchCategory.Leaderboard;
diff --git a/osu.Game/Overlays/Direct/Header.cs b/osu.Game/Overlays/Direct/Header.cs
index 80870dcb68..5b3e394a18 100644
--- a/osu.Game/Overlays/Direct/Header.cs
+++ b/osu.Game/Overlays/Direct/Header.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.ComponentModel;
+using osu.Framework.Extensions.Color4Extensions;
using osuTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
@@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Direct
{
public class Header : SearchableListHeader
{
- protected override Color4 BackgroundColour => OsuColour.FromHex(@"252f3a");
+ protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"252f3a");
protected override DirectTab DefaultTab => DirectTab.Search;
protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", Font = OsuFont.GetFont(size: 25) };
diff --git a/osu.Game/Overlays/DirectOverlay.cs b/osu.Game/Overlays/DirectOverlay.cs
index a6f8b65a0d..61986d1cf0 100644
--- a/osu.Game/Overlays/DirectOverlay.cs
+++ b/osu.Game/Overlays/DirectOverlay.cs
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Humanizer;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Threading;
@@ -34,9 +35,9 @@ namespace osu.Game.Overlays
private readonly OsuSpriteText resultCountsText;
private FillFlowContainer panels;
- protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74");
- protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71");
- protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"3f5265");
+ protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"485e74");
+ protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"465b71");
+ protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"3f5265");
protected override SearchableListHeader CreateHeader() => new Header();
protected override SearchableListFilterControl CreateFilterControl() => new FilterControl();
diff --git a/osu.Game/Overlays/Home/Friends/FriendsBundle.cs b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs
new file mode 100644
index 0000000000..75d00dfef8
--- /dev/null
+++ b/osu.Game/Overlays/Home/Friends/FriendsBundle.cs
@@ -0,0 +1,25 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+namespace osu.Game.Overlays.Home.Friends
+{
+ public class FriendsBundle
+ {
+ public FriendsOnlineStatus Status { get; }
+
+ public int Count { get; }
+
+ public FriendsBundle(FriendsOnlineStatus status, int count)
+ {
+ Status = status;
+ Count = count;
+ }
+ }
+
+ public enum FriendsOnlineStatus
+ {
+ All,
+ Online,
+ Offline
+ }
+}
diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs
new file mode 100644
index 0000000000..196f01ab4a
--- /dev/null
+++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusControl.cs
@@ -0,0 +1,26 @@
+// 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 osu.Game.Users;
+
+namespace osu.Game.Overlays.Home.Friends
+{
+ public class FriendsOnlineStatusControl : OverlayStreamControl
+ {
+ protected override OverlayStreamItem CreateStreamItem(FriendsBundle value) => new FriendsOnlineStatusItem(value);
+
+ public void Populate(List users)
+ {
+ var userCount = users.Count;
+ var onlineUsersCount = users.Count(user => user.IsOnline);
+
+ AddItem(new FriendsBundle(FriendsOnlineStatus.All, userCount));
+ AddItem(new FriendsBundle(FriendsOnlineStatus.Online, onlineUsersCount));
+ AddItem(new FriendsBundle(FriendsOnlineStatus.Offline, userCount - onlineUsersCount));
+
+ Current.Value = Items.FirstOrDefault();
+ }
+ }
+}
diff --git a/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs
new file mode 100644
index 0000000000..d9b780ce46
--- /dev/null
+++ b/osu.Game/Overlays/Home/Friends/FriendsOnlineStatusItem.cs
@@ -0,0 +1,39 @@
+// 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 osu.Game.Graphics;
+using osuTK.Graphics;
+
+namespace osu.Game.Overlays.Home.Friends
+{
+ public class FriendsOnlineStatusItem : OverlayStreamItem
+ {
+ public FriendsOnlineStatusItem(FriendsBundle value)
+ : base(value)
+ {
+ }
+
+ protected override string MainText => Value.Status.ToString();
+
+ protected override string AdditionalText => Value.Count.ToString();
+
+ protected override Color4 GetBarColour(OsuColour colours)
+ {
+ switch (Value.Status)
+ {
+ case FriendsOnlineStatus.All:
+ return Color4.White;
+
+ case FriendsOnlineStatus.Online:
+ return colours.GreenLight;
+
+ case FriendsOnlineStatus.Offline:
+ return Color4.Black;
+
+ default:
+ throw new ArgumentException($@"{Value.Status} status does not provide a colour in {nameof(GetBarColour)}.");
+ }
+ }
+ }
+}
diff --git a/osu.Game/Overlays/MedalOverlay.cs b/osu.Game/Overlays/MedalOverlay.cs
index aa28b0659d..4425c2f168 100644
--- a/osu.Game/Overlays/MedalOverlay.cs
+++ b/osu.Game/Overlays/MedalOverlay.cs
@@ -126,14 +126,14 @@ namespace osu.Game.Overlays
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"05262f"),
+ Colour = Color4Extensions.FromHex(@"05262f"),
},
new Triangles
{
RelativeSizeAxes = Axes.Both,
TriangleScale = 2,
- ColourDark = OsuColour.FromHex(@"04222b"),
- ColourLight = OsuColour.FromHex(@"052933"),
+ ColourDark = Color4Extensions.FromHex(@"04222b"),
+ ColourLight = Color4Extensions.FromHex(@"052933"),
},
innerSpin = new Sprite
{
diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
index 466c953151..e9b3598625 100644
--- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs
+++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs
@@ -63,10 +63,10 @@ namespace osu.Game.Overlays.Mods
public ModSelectOverlay()
{
- Waves.FirstWaveColour = OsuColour.FromHex(@"19b0e2");
- Waves.SecondWaveColour = OsuColour.FromHex(@"2280a2");
- Waves.ThirdWaveColour = OsuColour.FromHex(@"005774");
- Waves.FourthWaveColour = OsuColour.FromHex(@"003a4e");
+ Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2");
+ Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2");
+ Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774");
+ Waves.FourthWaveColour = Color4Extensions.FromHex(@"003a4e");
RelativeSizeAxes = Axes.Both;
diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs b/osu.Game/Overlays/OverlayStreamControl.cs
similarity index 62%
rename from osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs
rename to osu.Game/Overlays/OverlayStreamControl.cs
index ffb622dd37..8b6aca6d5d 100644
--- a/osu.Game/Overlays/Changelog/UpdateStreamBadgeArea.cs
+++ b/osu.Game/Overlays/OverlayStreamControl.cs
@@ -3,42 +3,32 @@
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
-using osu.Game.Online.API.Requests.Responses;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Graphics.UserInterface;
+using JetBrains.Annotations;
-namespace osu.Game.Overlays.Changelog
+namespace osu.Game.Overlays
{
- public class UpdateStreamBadgeArea : TabControl
+ public abstract class OverlayStreamControl : TabControl
{
- public UpdateStreamBadgeArea()
+ protected OverlayStreamControl()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
}
- public void Populate(List streams)
+ public void Populate(List streams) => streams.ForEach(AddItem);
+
+ protected override Dropdown CreateDropdown() => null;
+
+ protected override TabItem CreateTabItem(T value) => CreateStreamItem(value).With(item =>
{
- foreach (var updateStream in streams)
- AddItem(updateStream);
- }
+ item.SelectedItem.BindTo(Current);
+ });
- protected override bool OnHover(HoverEvent e)
- {
- foreach (var streamBadge in TabContainer.Children.OfType())
- streamBadge.UserHoveringArea = true;
-
- return base.OnHover(e);
- }
-
- protected override void OnHoverLost(HoverLostEvent e)
- {
- foreach (var streamBadge in TabContainer.Children.OfType())
- streamBadge.UserHoveringArea = false;
-
- base.OnHoverLost(e);
- }
+ [NotNull]
+ protected abstract OverlayStreamItem CreateStreamItem(T value);
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
{
@@ -47,9 +37,20 @@ namespace osu.Game.Overlays.Changelog
AllowMultiline = true,
};
- protected override Dropdown CreateDropdown() => null;
+ protected override bool OnHover(HoverEvent e)
+ {
+ foreach (var streamBadge in TabContainer.Children.OfType>())
+ streamBadge.UserHoveringArea = true;
- protected override TabItem CreateTabItem(APIUpdateStream value) =>
- new UpdateStreamBadge(value) { SelectedTab = { BindTarget = Current } };
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ foreach (var streamBadge in TabContainer.Children.OfType>())
+ streamBadge.UserHoveringArea = false;
+
+ base.OnHoverLost(e);
+ }
}
}
diff --git a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs b/osu.Game/Overlays/OverlayStreamItem.cs
similarity index 74%
rename from osu.Game/Overlays/Changelog/UpdateStreamBadge.cs
rename to osu.Game/Overlays/OverlayStreamItem.cs
index 6786bbc49f..630d3a0a22 100644
--- a/osu.Game/Overlays/Changelog/UpdateStreamBadge.cs
+++ b/osu.Game/Overlays/OverlayStreamItem.cs
@@ -1,46 +1,52 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using Humanizer;
-using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
-using osu.Game.Graphics;
-using osu.Game.Online.API.Requests.Responses;
using osu.Framework.Graphics.UserInterface;
-using osu.Game.Graphics.Sprites;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
-using osuTK;
+using osu.Framework.Graphics.Sprites;
+using osu.Framework.Allocation;
+using osu.Game.Graphics.Sprites;
+using osu.Game.Graphics;
+using osuTK.Graphics;
-namespace osu.Game.Overlays.Changelog
+namespace osu.Game.Overlays
{
- public class UpdateStreamBadge : TabItem
+ public abstract class OverlayStreamItem : TabItem
{
- private const float badge_width = 100;
- private const float transition_duration = 100;
+ public readonly Bindable SelectedItem = new Bindable();
- public readonly Bindable SelectedTab = new Bindable();
+ private bool userHoveringArea;
- private readonly APIUpdateStream stream;
+ public bool UserHoveringArea
+ {
+ set
+ {
+ if (value == userHoveringArea)
+ return;
+
+ userHoveringArea = value;
+ updateState();
+ }
+ }
private FillFlowContainer text;
private ExpandingBar expandingBar;
- public UpdateStreamBadge(APIUpdateStream stream)
- : base(stream)
+ protected OverlayStreamItem(T value)
+ : base(value)
{
- this.stream = stream;
+ Height = 60;
+ Width = 100;
+ Padding = new MarginPadding(5);
}
[BackgroundDependencyLoader]
- private void load(OverlayColourProvider colourProvider)
+ private void load(OverlayColourProvider colourProvider, OsuColour colours)
{
- Size = new Vector2(stream.IsFeatured ? badge_width * 2 : badge_width, 60);
- Padding = new MarginPadding(5);
-
AddRange(new Drawable[]
{
text = new FillFlowContainer
@@ -52,17 +58,17 @@ namespace osu.Game.Overlays.Changelog
{
new OsuSpriteText
{
- Text = stream.DisplayName,
+ Text = MainText,
Font = OsuFont.GetFont(size: 12, weight: FontWeight.Black),
},
new OsuSpriteText
{
- Text = stream.LatestBuild.DisplayVersion,
+ Text = AdditionalText,
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Regular),
},
new OsuSpriteText
{
- Text = stream.LatestBuild.Users > 0 ? $"{"user".ToQuantity(stream.LatestBuild.Users, "N0")} online" : null,
+ Text = InfoText,
Font = OsuFont.GetFont(size: 10),
Colour = colourProvider.Foreground1
},
@@ -71,7 +77,7 @@ namespace osu.Game.Overlays.Changelog
expandingBar = new ExpandingBar
{
Anchor = Anchor.TopCentre,
- Colour = stream.Colour,
+ Colour = GetBarColour(colours),
ExpandedSize = 4,
CollapsedSize = 2,
Expanded = true
@@ -79,9 +85,17 @@ namespace osu.Game.Overlays.Changelog
new HoverClickSounds()
});
- SelectedTab.BindValueChanged(_ => updateState(), true);
+ SelectedItem.BindValueChanged(_ => updateState(), true);
}
+ protected abstract string MainText { get; }
+
+ protected abstract string AdditionalText { get; }
+
+ protected virtual string InfoText => string.Empty;
+
+ protected abstract Color4 GetBarColour(OsuColour colours);
+
protected override void OnActivated() => updateState();
protected override void OnDeactivated() => updateState();
@@ -104,7 +118,7 @@ namespace osu.Game.Overlays.Changelog
bool textHighlighted = IsHovered;
bool barExpanded = IsHovered;
- if (SelectedTab.Value == null)
+ if (SelectedItem.Value == null)
{
// at listing, all badges are highlighted when user is not hovering any badge.
textHighlighted |= !userHoveringArea;
@@ -120,21 +134,7 @@ namespace osu.Game.Overlays.Changelog
}
expandingBar.Expanded = barExpanded;
- text.FadeTo(textHighlighted ? 1 : 0.5f, transition_duration, Easing.OutQuint);
- }
-
- private bool userHoveringArea;
-
- public bool UserHoveringArea
- {
- set
- {
- if (value == userHoveringArea)
- return;
-
- userHoveringArea = value;
- updateState();
- }
+ text.FadeTo(textHighlighted ? 1 : 0.5f, 100, Easing.OutQuint);
}
}
}
diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs
index 6ed4fc3187..2cc1f6533f 100644
--- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs
+++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs
@@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -170,7 +171,7 @@ namespace osu.Game.Overlays.Profile.Header
userCountryText.Text = user?.Country?.FullName ?? "Alien";
supporterTag.SupportLevel = user?.SupportLevel ?? 0;
titleText.Text = user?.Title ?? string.Empty;
- titleText.Colour = OsuColour.FromHex(user?.Colour ?? "fff");
+ titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff");
userStats.Clear();
diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs
index 3e78423a5a..f7c09e33c1 100644
--- a/osu.Game/Overlays/Profile/ProfileHeader.cs
+++ b/osu.Game/Overlays/Profile/ProfileHeader.cs
@@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
-using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Users;
@@ -48,7 +47,7 @@ namespace osu.Game.Overlays.Profile
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = ColourInfo.GradientVertical(OsuColour.FromHex("222").Opacity(0.8f), OsuColour.FromHex("222").Opacity(0.2f))
+ Colour = ColourInfo.GradientVertical(Color4Extensions.FromHex("222").Opacity(0.8f), Color4Extensions.FromHex("222").Opacity(0.2f))
},
}
};
diff --git a/osu.Game/Overlays/Social/FilterControl.cs b/osu.Game/Overlays/Social/FilterControl.cs
index 1c2cb95dfe..93fcc3c401 100644
--- a/osu.Game/Overlays/Social/FilterControl.cs
+++ b/osu.Game/Overlays/Social/FilterControl.cs
@@ -1,16 +1,16 @@
// 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.Extensions.Color4Extensions;
using osuTK.Graphics;
using osu.Framework.Graphics;
-using osu.Game.Graphics;
using osu.Game.Overlays.SearchableList;
namespace osu.Game.Overlays.Social
{
public class FilterControl : SearchableListFilterControl
{
- protected override Color4 BackgroundColour => OsuColour.FromHex(@"47253a");
+ protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"47253a");
protected override SocialSortCriteria DefaultTab => SocialSortCriteria.Rank;
protected override SortDirection DefaultCategory => SortDirection.Ascending;
diff --git a/osu.Game/Overlays/Social/Header.cs b/osu.Game/Overlays/Social/Header.cs
index 22bca9b421..22e0fdcd56 100644
--- a/osu.Game/Overlays/Social/Header.cs
+++ b/osu.Game/Overlays/Social/Header.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Framework.Allocation;
using System.ComponentModel;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Sprites;
namespace osu.Game.Overlays.Social
@@ -17,7 +18,7 @@ namespace osu.Game.Overlays.Social
{
private OsuSpriteText browser;
- protected override Color4 BackgroundColour => OsuColour.FromHex(@"38202e");
+ protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"38202e");
protected override SocialTab DefaultTab => SocialTab.AllPlayers;
protected override IconUsage Icon => FontAwesome.Solid.Users;
diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs
index 54c978738d..50c05e1b54 100644
--- a/osu.Game/Overlays/SocialOverlay.cs
+++ b/osu.Game/Overlays/SocialOverlay.cs
@@ -9,7 +9,6 @@ using osuTK;
using osuTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
@@ -18,6 +17,7 @@ using osu.Game.Overlays.Social;
using osu.Game.Users;
using System.Threading;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Threading;
namespace osu.Game.Overlays
@@ -27,9 +27,9 @@ namespace osu.Game.Overlays
private readonly LoadingSpinner loading;
private FillFlowContainer panels;
- protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b");
- protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"672b51");
- protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"5c2648");
+ protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"60284b");
+ protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"672b51");
+ protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"5c2648");
protected override SearchableListHeader CreateHeader() => new Header();
protected override SearchableListFilterControl CreateFilterControl() => new FilterControl();
diff --git a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
index 4bff8146b4..3478f18a40 100644
--- a/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
+++ b/osu.Game/Overlays/Volume/VolumeControlReceptor.cs
@@ -14,22 +14,8 @@ namespace osu.Game.Overlays.Volume
public Func ActionRequested;
public Func ScrollActionRequested;
- public bool OnPressed(GlobalAction action)
- {
- // if nothing else handles selection actions in the game, it's safe to let volume be adjusted.
- switch (action)
- {
- case GlobalAction.SelectPrevious:
- action = GlobalAction.IncreaseVolume;
- break;
-
- case GlobalAction.SelectNext:
- action = GlobalAction.DecreaseVolume;
- break;
- }
-
- return ActionRequested?.Invoke(action) ?? false;
- }
+ public bool OnPressed(GlobalAction action) =>
+ ActionRequested?.Invoke(action) ?? false;
public bool OnScroll(GlobalAction action, float amount, bool isPrecise) =>
ScrollActionRequested?.Invoke(action, amount, isPrecise) ?? false;
diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs
index 882d3ebd6a..7fe606d584 100644
--- a/osu.Game/Rulesets/Mods/ModPerfect.cs
+++ b/osu.Game/Rulesets/Mods/ModPerfect.cs
@@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => OsuIcon.ModPerfect;
public override string Description => "SS or quit.";
- protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result) => result.Type != result.Judgement.MaxResult;
+ protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
+ => !(result.Judgement is IgnoreJudgement)
+ && result.Type != result.Judgement.MaxResult;
}
}
diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs
index 752615245e..afd9e3d760 100644
--- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs
+++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuBar.cs
@@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -26,7 +27,7 @@ namespace osu.Game.Screens.Edit.Components.Menus
MaskingContainer.CornerRadius = 0;
ItemsContainer.Padding = new MarginPadding { Left = 100 };
- BackgroundColour = OsuColour.FromHex("111");
+ BackgroundColour = Color4Extensions.FromHex("111");
ScreenSelectionTabControl tabControl;
AddRangeInternal(new Drawable[]
diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs
index 02e5db306d..b99a053859 100644
--- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs
+++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs
@@ -2,11 +2,11 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
-using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osuTK;
@@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex("111")
+ Colour = Color4Extensions.FromHex("111")
},
new GridContainer
{
@@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex("222")
+ Colour = Color4Extensions.FromHex("222")
},
new FillFlowContainer
{
@@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex("333")
+ Colour = Color4Extensions.FromHex("333")
},
new Container
{
diff --git a/osu.Game/Screens/Menu/Disclaimer.cs b/osu.Game/Screens/Menu/Disclaimer.cs
index bcab73715b..ee8200321b 100644
--- a/osu.Game/Screens/Menu/Disclaimer.cs
+++ b/osu.Game/Screens/Menu/Disclaimer.cs
@@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Screens;
+using osu.Framework.Utils;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Online.API;
@@ -33,6 +34,7 @@ namespace osu.Game.Screens.Menu
private readonly OsuScreen nextScreen;
private readonly Bindable currentUser = new Bindable();
+ private FillFlowContainer fill;
public Disclaimer(OsuScreen nextScreen = null)
{
@@ -49,16 +51,16 @@ namespace osu.Game.Screens.Menu
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
- Icon = FontAwesome.Solid.ExclamationTriangle,
+ Icon = FontAwesome.Solid.Poo,
Size = new Vector2(icon_size),
Y = icon_y,
},
- new FillFlowContainer
+ fill = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
- Y = icon_y + icon_size,
+ Y = icon_y,
Anchor = Anchor.Centre,
Origin = Anchor.TopCentre,
Children = new Drawable[]
@@ -71,6 +73,8 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Spacing = new Vector2(0, 2),
+ LayoutDuration = 2000,
+ LayoutEasing = Easing.OutQuint
},
supportFlow = new LinkFlowContainer
{
@@ -86,23 +90,16 @@ namespace osu.Game.Screens.Menu
}
};
- textFlow.AddText("This is an ", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.Light));
- textFlow.AddText("early development build", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.SemiBold));
+ textFlow.AddText("This project is an ongoing ", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.Light));
+ textFlow.AddText("work in progress", t => t.Font = t.Font.With(Typeface.Exo, 30, FontWeight.SemiBold));
- textFlow.AddParagraph("Things may not work as expected", t => t.Font = t.Font.With(size: 20));
textFlow.NewParagraph();
static void format(SpriteText t) => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold);
- textFlow.AddParagraph("Detailed bug reports are welcomed via github issues.", format);
+ textFlow.AddParagraph(getRandomTip(), t => t.Font = t.Font.With(Typeface.Exo, 20, FontWeight.SemiBold));
textFlow.NewParagraph();
- textFlow.AddText("Visit ", format);
- textFlow.AddLink("discord.gg/ppy", "https://discord.gg/ppy", creationParameters: format);
- textFlow.AddText(" to help out or follow progress!", format);
-
- textFlow.NewParagraph();
- textFlow.NewParagraph();
textFlow.NewParagraph();
iconColour = colours.Yellow;
@@ -114,7 +111,7 @@ namespace osu.Game.Screens.Menu
if (e.NewValue.IsSupporter)
{
- supportFlow.AddText("Thank you for supporting osu!", format);
+ supportFlow.AddText("Eternal thanks to you for supporting osu!", format);
}
else
{
@@ -125,7 +122,7 @@ namespace osu.Game.Screens.Menu
heart = supportFlow.AddIcon(FontAwesome.Solid.Heart, t =>
{
- t.Padding = new MarginPadding { Left = 5 };
+ t.Padding = new MarginPadding { Left = 5, Top = 3 };
t.Font = t.Font.With(size: 12);
t.Origin = Anchor.Centre;
t.Colour = colours.Pink;
@@ -139,11 +136,6 @@ namespace osu.Game.Screens.Menu
}, true);
}
- private void animateHeart()
- {
- heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
- }
-
protected override void LoadComplete()
{
base.LoadComplete();
@@ -155,15 +147,28 @@ namespace osu.Game.Screens.Menu
{
base.OnEntering(last);
- icon.Delay(1000).FadeColour(iconColour, 200, Easing.OutQuint);
- icon.Delay(1000)
- .MoveToY(icon_y * 1.1f, 160, Easing.OutCirc)
- .RotateTo(-10, 160, Easing.OutCirc)
- .Then()
- .MoveToY(icon_y, 160, Easing.InCirc)
- .RotateTo(0, 160, Easing.InCirc);
+ icon.RotateTo(10);
+ icon.FadeOut();
+ icon.ScaleTo(0.5f);
+
+ icon.Delay(500).FadeIn(500).ScaleTo(1, 500, Easing.OutQuint);
+
+ using (BeginDelayedSequence(3000, true))
+ {
+ icon.FadeColour(iconColour, 200, Easing.OutQuint);
+ icon.MoveToY(icon_y * 1.3f, 500, Easing.OutCirc)
+ .RotateTo(-360, 520, Easing.OutQuint)
+ .Then()
+ .MoveToY(icon_y, 160, Easing.InQuart)
+ .FadeColour(Color4.White, 160);
+
+ fill.Delay(520 + 160).MoveToOffset(new Vector2(0, 15), 160, Easing.OutQuart);
+ }
supportFlow.FadeOut().Delay(2000).FadeIn(500);
+ double delay = 500;
+ foreach (var c in textFlow.Children)
+ c.FadeTo(0.001f).Delay(delay += 20).FadeIn(500);
animateHeart();
@@ -178,5 +183,35 @@ namespace osu.Game.Screens.Menu
this.Push(nextScreen);
});
}
+
+ private string getRandomTip()
+ {
+ string[] tips =
+ {
+ "You can press Ctrl-T anywhere in the game to toggle the toolbar!",
+ "You can press Ctrl-O anywhere in the game to access options!",
+ "All settings are dynamic and take effect in real-time. Try changing the skin while playing!",
+ "New features are coming online every update. Make sure to stay up-to-date!",
+ "If you find the UI too large or small, try adjusting UI scale in settings!",
+ "Try adjusting the \"Screen Scaling\" mode to change your gameplay or UI area, even in fullscreen!",
+ "For now, osu!direct is available to all users on lazer. You can access it anywhere using Ctrl-D!",
+ "Seeking in replays is available by dragging on the difficulty bar at the bottom of the screen!",
+ "Multithreading support means that even with low \"FPS\" your input and judgements will be accurate!",
+ "Try scrolling down in the mod select panel to find a bunch of new fun mods!",
+ "Most of the web content (profiles, rankings, etc.) are available natively in-game from the icons on the toolbar!",
+ "Get more details, hide or delete a beatmap by right-clicking on its panel at song select!",
+ "All delete operations are temporary until exiting. Restore accidentally deleted content from the maintenance settings!",
+ "Check out the \"timeshift\" multiplayer system, which has local permanent leaderboards and playlist support!",
+ "Toggle advanced frame / thread statistics with Ctrl-F11!",
+ "Take a look under the hood at performance counters and enable verbose performance logging with Ctrl-F2!",
+ };
+
+ return tips[RNG.Next(0, tips.Length)];
+ }
+
+ private void animateHeart()
+ {
+ heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
+ }
}
}
diff --git a/osu.Game/Screens/Menu/IntroSequence.cs b/osu.Game/Screens/Menu/IntroSequence.cs
index e2dd14b18c..6731fef6f7 100644
--- a/osu.Game/Screens/Menu/IntroSequence.cs
+++ b/osu.Game/Screens/Menu/IntroSequence.cs
@@ -94,7 +94,7 @@ namespace osu.Game.Screens.Menu
},
}
},
- bigRing = new Ring(OsuColour.FromHex(@"B6C5E9"), 0.85f),
+ bigRing = new Ring(Color4Extensions.FromHex(@"B6C5E9"), 0.85f),
mediumRing = new Ring(Color4.White.Opacity(130), 0.7f),
smallRing = new Ring(Color4.White, 0.6f),
welcomeText = new OsuSpriteText
@@ -121,7 +121,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Height = 0,
- Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160),
+ Colour = Color4Extensions.FromHex(@"C6D8FF").Opacity(160),
},
foregroundFill = new Box
{
@@ -139,28 +139,28 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.Centre,
Origin = Anchor.TopCentre,
Position = new Vector2(0, circle_offset),
- Colour = OsuColour.FromHex(@"AA92FF"),
+ Colour = Color4Extensions.FromHex(@"AA92FF"),
},
blueCircle = new Circle
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreRight,
Position = new Vector2(-circle_offset, 0),
- Colour = OsuColour.FromHex(@"8FE5FE"),
+ Colour = Color4Extensions.FromHex(@"8FE5FE"),
},
yellowCircle = new Circle
{
Anchor = Anchor.Centre,
Origin = Anchor.BottomCentre,
Position = new Vector2(0, -circle_offset),
- Colour = OsuColour.FromHex(@"FFD64C"),
+ Colour = Color4Extensions.FromHex(@"FFD64C"),
},
pinkCircle = new Circle
{
Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft,
Position = new Vector2(circle_offset, 0),
- Colour = OsuColour.FromHex(@"e967a1"),
+ Colour = Color4Extensions.FromHex(@"e967a1"),
},
};
diff --git a/osu.Game/Screens/Menu/IntroTriangles.cs b/osu.Game/Screens/Menu/IntroTriangles.cs
index 4e51ff939a..be5762e68d 100644
--- a/osu.Game/Screens/Menu/IntroTriangles.cs
+++ b/osu.Game/Screens/Menu/IntroTriangles.cs
@@ -259,11 +259,18 @@ namespace osu.Game.Screens.Menu
private class LazerLogo : CompositeDrawable
{
+ private readonly Stream videoStream;
+
public LazerLogo(Stream videoStream)
{
+ this.videoStream = videoStream;
Size = new Vector2(960);
+ }
- InternalChild = new VideoSprite(videoStream)
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ InternalChild = new VideoSprite(videoStream, false)
{
RelativeSizeAxes = Axes.Both,
Clock = new FramedOffsetClock(Clock) { Offset = -logo_1 }
diff --git a/osu.Game/Screens/Menu/OsuLogo.cs b/osu.Game/Screens/Menu/OsuLogo.cs
index be2f29cbe9..800520100e 100644
--- a/osu.Game/Screens/Menu/OsuLogo.cs
+++ b/osu.Game/Screens/Menu/OsuLogo.cs
@@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -14,7 +15,6 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events;
using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints;
-using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers;
using osuTK;
@@ -28,7 +28,7 @@ namespace osu.Game.Screens.Menu
///
public class OsuLogo : BeatSyncedContainer
{
- public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1");
+ public readonly Color4 OsuPink = Color4Extensions.FromHex(@"e967a1");
private const double transition_length = 300;
@@ -176,8 +176,8 @@ namespace osu.Game.Screens.Menu
triangles = new Triangles
{
TriangleScale = 4,
- ColourLight = OsuColour.FromHex(@"ff7db7"),
- ColourDark = OsuColour.FromHex(@"de5b95"),
+ ColourLight = Color4Extensions.FromHex(@"ff7db7"),
+ ColourDark = Color4Extensions.FromHex(@"de5b95"),
RelativeSizeAxes = Axes.Both,
},
}
diff --git a/osu.Game/Screens/Multi/Components/DrawableGameType.cs b/osu.Game/Screens/Multi/Components/DrawableGameType.cs
index f4941dd73a..28240f0796 100644
--- a/osu.Game/Screens/Multi/Components/DrawableGameType.cs
+++ b/osu.Game/Screens/Multi/Components/DrawableGameType.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@@ -27,7 +28,7 @@ namespace osu.Game.Screens.Multi.Components
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"545454"),
+ Colour = Color4Extensions.FromHex(@"545454"),
},
};
}
diff --git a/osu.Game/Screens/Multi/Components/ParticipantsList.cs b/osu.Game/Screens/Multi/Components/ParticipantsList.cs
index 5a2dc19b66..79d130adf5 100644
--- a/osu.Game/Screens/Multi/Components/ParticipantsList.cs
+++ b/osu.Game/Screens/Multi/Components/ParticipantsList.cs
@@ -2,12 +2,12 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Threading;
-using osu.Game.Graphics;
using osu.Game.Users;
using osu.Game.Users.Drawables;
using osuTK;
@@ -114,7 +114,7 @@ namespace osu.Game.Screens.Multi.Components
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"27252d"),
+ Colour = Color4Extensions.FromHex(@"27252d"),
},
avatar = new UpdateableAvatar { RelativeSizeAxes = Axes.Both },
};
diff --git a/osu.Game/Screens/Multi/Header.cs b/osu.Game/Screens/Multi/Header.cs
index 1cbf2a45e7..0a05472ba3 100644
--- a/osu.Game/Screens/Multi/Header.cs
+++ b/osu.Game/Screens/Multi/Header.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -30,7 +31,7 @@ namespace osu.Game.Screens.Multi
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"2f2043"),
+ Colour = Color4Extensions.FromHex(@"2f2043"),
},
new Container
{
diff --git a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs
index d45dac1ae6..de02d779e1 100644
--- a/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs
+++ b/osu.Game/Screens/Multi/Lounge/Components/DrawableRoom.cs
@@ -134,7 +134,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"212121"),
+ Colour = Color4Extensions.FromHex(@"212121"),
},
new StatusColouredContainer(transition_duration)
{
diff --git a/osu.Game/Screens/Multi/Match/Components/Footer.cs b/osu.Game/Screens/Multi/Match/Components/Footer.cs
index c0c866d815..94d7df6194 100644
--- a/osu.Game/Screens/Multi/Match/Components/Footer.cs
+++ b/osu.Game/Screens/Multi/Match/Components/Footer.cs
@@ -4,6 +4,7 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -44,7 +45,7 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
- background.Colour = OsuColour.FromHex(@"28242d");
+ background.Colour = Color4Extensions.FromHex(@"28242d");
}
}
}
diff --git a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs
index 115ac5037a..5d68de9ce6 100644
--- a/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs
+++ b/osu.Game/Screens/Multi/Match/Components/MatchSettingsOverlay.cs
@@ -91,7 +91,7 @@ namespace osu.Game.Screens.Multi.Match.Components
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"28242d"),
+ Colour = Color4Extensions.FromHex(@"28242d"),
},
new GridContainer
{
@@ -270,7 +270,7 @@ namespace osu.Game.Screens.Multi.Match.Components
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
+ Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
},
new FillFlowContainer
{
diff --git a/osu.Game/Screens/Multi/Match/Components/PurpleTriangleButton.cs b/osu.Game/Screens/Multi/Match/Components/PurpleTriangleButton.cs
index 8a0369ceba..1d93116d07 100644
--- a/osu.Game/Screens/Multi/Match/Components/PurpleTriangleButton.cs
+++ b/osu.Game/Screens/Multi/Match/Components/PurpleTriangleButton.cs
@@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
-using osu.Game.Graphics;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Multi.Match.Components
@@ -12,9 +12,9 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader]
private void load()
{
- BackgroundColour = OsuColour.FromHex(@"593790");
- Triangles.ColourLight = OsuColour.FromHex(@"7247b6");
- Triangles.ColourDark = OsuColour.FromHex(@"593790");
+ BackgroundColour = Color4Extensions.FromHex(@"593790");
+ Triangles.ColourLight = Color4Extensions.FromHex(@"7247b6");
+ Triangles.ColourDark = Color4Extensions.FromHex(@"593790");
}
}
}
diff --git a/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs b/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs
index 9de4a61cde..7ef39c2a74 100644
--- a/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs
+++ b/osu.Game/Screens/Multi/Match/Components/RoomAvailabilityPicker.cs
@@ -3,6 +3,7 @@
using osu.Framework.Allocation;
using osu.Framework.Extensions;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
@@ -52,7 +53,7 @@ namespace osu.Game.Screens.Multi.Match.Components
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"3d3943"),
+ Colour = Color4Extensions.FromHex(@"3d3943"),
},
selection = new Box
{
diff --git a/osu.Game/Screens/Multi/Multiplayer.cs b/osu.Game/Screens/Multi/Multiplayer.cs
index b0d773869a..863a28609b 100644
--- a/osu.Game/Screens/Multi/Multiplayer.cs
+++ b/osu.Game/Screens/Multi/Multiplayer.cs
@@ -13,7 +13,6 @@ using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables;
-using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Input;
@@ -75,7 +74,7 @@ namespace osu.Game.Screens.Multi
RelativeSizeAxes = Axes.Both;
Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING };
- var backgroundColour = OsuColour.FromHex(@"3e3a44");
+ var backgroundColour = Color4Extensions.FromHex(@"3e3a44");
InternalChild = waves = new MultiplayerWaveContainer
{
@@ -386,10 +385,10 @@ namespace osu.Game.Screens.Multi
public MultiplayerWaveContainer()
{
- FirstWaveColour = OsuColour.FromHex(@"654d8c");
- SecondWaveColour = OsuColour.FromHex(@"554075");
- ThirdWaveColour = OsuColour.FromHex(@"44325e");
- FourthWaveColour = OsuColour.FromHex(@"392850");
+ FirstWaveColour = Color4Extensions.FromHex(@"654d8c");
+ SecondWaveColour = Color4Extensions.FromHex(@"554075");
+ ThirdWaveColour = Color4Extensions.FromHex(@"44325e");
+ FourthWaveColour = Color4Extensions.FromHex(@"392850");
}
}
diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs
index 1db97af2f0..04c08cdbd2 100644
--- a/osu.Game/Screens/Select/BeatmapCarousel.cs
+++ b/osu.Game/Screens/Select/BeatmapCarousel.cs
@@ -153,9 +153,11 @@ namespace osu.Game.Screens.Select
beatmaps.BeatmapHidden += beatmapHidden;
beatmaps.BeatmapRestored += beatmapRestored;
- loadBeatmapSets(beatmaps.GetAllUsableBeatmapSetsEnumerable());
+ loadBeatmapSets(GetLoadableBeatmaps());
}
+ protected virtual IEnumerable GetLoadableBeatmaps() => beatmaps.GetAllUsableBeatmapSetsEnumerable();
+
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => Schedule(() =>
{
var existingSet = beatmapSets.FirstOrDefault(b => b.BeatmapSet.ID == beatmapSet.ID);
@@ -189,7 +191,7 @@ namespace osu.Game.Screens.Select
root.AddChild(newSet);
- applyActiveCriteria(false, false);
+ applyActiveCriteria(false);
//check if we can/need to maintain our current selection.
if (previouslySelectedID != null)
@@ -239,7 +241,7 @@ namespace osu.Game.Screens.Select
{
Debug.Assert(bypassFilters);
- applyActiveCriteria(false, true);
+ applyActiveCriteria(false);
}
return true;
@@ -396,7 +398,7 @@ namespace osu.Game.Screens.Select
{
if (PendingFilter?.Completed == false)
{
- applyActiveCriteria(false, false);
+ applyActiveCriteria(false);
Update();
}
}
@@ -406,10 +408,10 @@ namespace osu.Game.Screens.Select
if (newCriteria != null)
activeCriteria = newCriteria;
- applyActiveCriteria(debounce, true);
+ applyActiveCriteria(debounce);
}
- private void applyActiveCriteria(bool debounce, bool scroll)
+ private void applyActiveCriteria(bool debounce)
{
if (root.Children.Any() != true) return;
@@ -419,7 +421,7 @@ namespace osu.Game.Screens.Select
root.Filter(activeCriteria);
itemsCache.Invalidate();
- if (scroll) scrollPositionCache.Invalidate();
+ scrollPositionCache.Invalidate();
}
PendingFilter?.Cancel();
diff --git a/osu.Game/Screens/Select/BeatmapInfoWedge.cs b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
index cf49cf0228..f84aac3081 100644
--- a/osu.Game/Screens/Select/BeatmapInfoWedge.cs
+++ b/osu.Game/Screens/Select/BeatmapInfoWedge.cs
@@ -384,7 +384,7 @@ namespace osu.Game.Screens.Select
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
- Colour = OsuColour.FromHex(@"441288"),
+ Colour = Color4Extensions.FromHex(@"441288"),
Icon = FontAwesome.Solid.Square,
Rotation = 45,
},
@@ -394,7 +394,7 @@ namespace osu.Game.Screens.Select
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.8f),
- Colour = OsuColour.FromHex(@"f7dd55"),
+ Colour = Color4Extensions.FromHex(@"f7dd55"),
Icon = statistic.Icon,
},
}
diff --git a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
index 2ffb73f226..8c264ce974 100644
--- a/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
+++ b/osu.Game/Screens/Select/Carousel/CarouselBeatmap.cs
@@ -25,6 +25,13 @@ namespace osu.Game.Screens.Select.Carousel
{
base.Filter(criteria);
+ if (Beatmap.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
+ {
+ // bypass filtering for selected beatmap
+ Filtered.Value = false;
+ return;
+ }
+
bool match =
criteria.Ruleset == null ||
Beatmap.RulesetID == criteria.Ruleset.ID ||
diff --git a/osu.Game/Screens/Select/Carousel/CarouselItem.cs b/osu.Game/Screens/Select/Carousel/CarouselItem.cs
index 1108b72bd2..79c1a4cb6b 100644
--- a/osu.Game/Screens/Select/Carousel/CarouselItem.cs
+++ b/osu.Game/Screens/Select/Carousel/CarouselItem.cs
@@ -16,7 +16,7 @@ namespace osu.Game.Screens.Select.Carousel
///
/// This item is not in a hidden state.
///
- public bool Visible => State.Value == CarouselItemState.Selected || (State.Value != CarouselItemState.Collapsed && !Filtered.Value);
+ public bool Visible => State.Value != CarouselItemState.Collapsed && !Filtered.Value;
public virtual List Drawables
{
diff --git a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
index 50419a5fb9..841bbf415c 100644
--- a/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
+++ b/osu.Game/Screens/Select/Carousel/DrawableCarouselBeatmap.cs
@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
@@ -69,8 +70,8 @@ namespace osu.Game.Screens.Select.Carousel
{
TriangleScale = 2,
RelativeSizeAxes = Axes.Both,
- ColourLight = OsuColour.FromHex(@"3a7285"),
- ColourDark = OsuColour.FromHex(@"123744")
+ ColourLight = Color4Extensions.FromHex(@"3a7285"),
+ ColourDark = Color4Extensions.FromHex(@"123744")
},
new FillFlowContainer
{
diff --git a/osu.Game/Screens/Select/FilterCriteria.cs b/osu.Game/Screens/Select/FilterCriteria.cs
index 9fa57af01d..18be4fcac8 100644
--- a/osu.Game/Screens/Select/FilterCriteria.cs
+++ b/osu.Game/Screens/Select/FilterCriteria.cs
@@ -15,6 +15,8 @@ namespace osu.Game.Screens.Select
public GroupMode Group;
public SortMode Sort;
+ public BeatmapSetInfo SelectedBeatmapSet;
+
public OptionalRange StarDifficulty;
public OptionalRange ApproachRate;
public OptionalRange DrainRate;
diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs
index 67626d1e4f..528222a89c 100644
--- a/osu.Game/Screens/Select/SongSelect.cs
+++ b/osu.Game/Screens/Select/SongSelect.cs
@@ -392,7 +392,12 @@ namespace osu.Game.Screens.Select
}
// Even if a ruleset mismatch was not the cause (ie. a text filter is applied),
- // we still want to forcefully show the new beatmap, bypassing filters.
+ // we still want to temporarily show the new beatmap, bypassing filters.
+ // This will be undone the next time the user changes the filter.
+ var criteria = FilterControl.CreateCriteria();
+ criteria.SelectedBeatmapSet = e.NewValue.BeatmapInfo.BeatmapSet;
+ Carousel.Filter(criteria);
+
Carousel.SelectBeatmap(e.NewValue.BeatmapInfo);
}
}
diff --git a/osu.Game/Skinning/LegacySkinExtensions.cs b/osu.Game/Skinning/LegacySkinExtensions.cs
index fa4de21eec..52328d43b2 100644
--- a/osu.Game/Skinning/LegacySkinExtensions.cs
+++ b/osu.Game/Skinning/LegacySkinExtensions.cs
@@ -61,7 +61,7 @@ namespace osu.Game.Skinning
{
var iniRate = source.GetConfig(GlobalSkinConfiguration.AnimationFramerate);
- if (iniRate != null)
+ if (iniRate?.Value > 0)
return 1000f / iniRate.Value;
return 1000f / textures.Length;
diff --git a/osu.Game/Tests/Visual/ModPerfectTestScene.cs b/osu.Game/Tests/Visual/ModPerfectTestScene.cs
new file mode 100644
index 0000000000..798947eb40
--- /dev/null
+++ b/osu.Game/Tests/Visual/ModPerfectTestScene.cs
@@ -0,0 +1,67 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Game.Beatmaps;
+using osu.Game.Rulesets;
+using osu.Game.Rulesets.Mods;
+using osu.Game.Rulesets.Objects;
+
+namespace osu.Game.Tests.Visual
+{
+ public abstract class ModPerfectTestScene : ModTestScene
+ {
+ private readonly Ruleset ruleset;
+ private readonly ModPerfect mod;
+
+ protected ModPerfectTestScene(Ruleset ruleset, ModPerfect mod)
+ : base(ruleset)
+ {
+ this.ruleset = ruleset;
+ this.mod = mod;
+ }
+
+ protected void CreateHitObjectTest(HitObjectTestData testData, bool shouldMiss) => CreateModTest(new ModTestData
+ {
+ Mod = mod,
+ Beatmap = new Beatmap
+ {
+ BeatmapInfo = { Ruleset = ruleset.RulesetInfo },
+ HitObjects = { testData.HitObject }
+ },
+ Autoplay = !shouldMiss,
+ PassCondition = () => ((PerfectModTestPlayer)Player).CheckFailed(shouldMiss && testData.FailOnMiss)
+ });
+
+ protected override TestPlayer CreateModPlayer(Ruleset ruleset) => new PerfectModTestPlayer();
+
+ private class PerfectModTestPlayer : TestPlayer
+ {
+ public PerfectModTestPlayer()
+ : base(showResults: false)
+ {
+ }
+
+ protected override bool AllowFail => true;
+
+ public bool CheckFailed(bool failed)
+ {
+ if (!failed)
+ return ScoreProcessor.HasCompleted && !HealthProcessor.HasFailed;
+
+ return HealthProcessor.HasFailed;
+ }
+ }
+
+ protected class HitObjectTestData
+ {
+ public readonly HitObject HitObject;
+ public readonly bool FailOnMiss;
+
+ public HitObjectTestData(HitObject hitObject, bool failOnMiss = true)
+ {
+ HitObject = hitObject;
+ FailOnMiss = failOnMiss;
+ }
+ }
+ }
+}
diff --git a/osu.Game/Tests/Visual/ModTestScene.cs b/osu.Game/Tests/Visual/ModTestScene.cs
index 9abe543bf6..8b41fb5075 100644
--- a/osu.Game/Tests/Visual/ModTestScene.cs
+++ b/osu.Game/Tests/Visual/ModTestScene.cs
@@ -57,9 +57,11 @@ namespace osu.Game.Tests.Visual
SelectedMods.Value = mods;
- return new ModTestPlayer(AllowFail);
+ return CreateModPlayer(ruleset);
}
+ protected virtual TestPlayer CreateModPlayer(Ruleset ruleset) => new ModTestPlayer(AllowFail);
+
protected class ModTestPlayer : TestPlayer
{
protected override bool AllowFail { get; }
diff --git a/osu.Game/Tests/Visual/PlayerTestScene.cs b/osu.Game/Tests/Visual/PlayerTestScene.cs
index 0b09b5c08f..9e852719e0 100644
--- a/osu.Game/Tests/Visual/PlayerTestScene.cs
+++ b/osu.Game/Tests/Visual/PlayerTestScene.cs
@@ -66,6 +66,7 @@ namespace osu.Game.Tests.Visual
var beatmap = CreateBeatmap(ruleset.RulesetInfo);
Beatmap.Value = CreateWorkingBeatmap(beatmap);
+ Ruleset.Value = ruleset.RulesetInfo;
SelectedMods.Value = Array.Empty();
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index cc1ab654ab..ba6f0e2251 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -23,7 +23,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 04b688cfa3..54cd400d51 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -71,7 +71,7 @@
-
+
@@ -79,7 +79,7 @@
-
+