Merge branch 'master' into add-catcher-animation-states

This commit is contained in:
Dan Balasescu 2020-03-11 14:53:14 +09:00 committed by GitHub
commit 03c8140d3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 894 additions and 437 deletions

View File

@ -0,0 +1,54 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.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);
}
}

View File

@ -1,8 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
@ -28,11 +26,6 @@ namespace osu.Game.Rulesets.Catch.Tests
{ {
private RulesetInfo catchRuleset; private RulesetInfo catchRuleset;
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(CatcherArea),
};
public TestSceneCatcherArea() public TestSceneCatcherArea()
{ {
AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher); AddSliderStep<float>("CircleSize", 0, 8, 5, createCatcher);

View File

@ -2,19 +2,27 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using System;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Testing; using osu.Framework.Testing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Catch.Objects; using osu.Game.Rulesets.Catch.Objects;
using osu.Game.Rulesets.Catch.UI; using osu.Game.Rulesets.Catch.UI;
using osu.Game.Rulesets.Objects;
using osu.Game.Tests.Visual; using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Catch.Tests namespace osu.Game.Rulesets.Catch.Tests
{ {
[TestFixture] [TestFixture]
public class TestSceneHyperDash : PlayerTestScene public class TestSceneHyperDash : PlayerTestScene
{ {
public override IReadOnlyList<Type> RequiredTypes => new[]
{
typeof(CatcherArea),
};
public TestSceneHyperDash() public TestSceneHyperDash()
: base(new CatchRuleset()) : base(new CatchRuleset())
{ {
@ -26,9 +34,11 @@ namespace osu.Game.Rulesets.Catch.Tests
public void TestHyperDash() public void TestHyperDash()
{ {
AddAssert("First note is hyperdash", () => Beatmap.Value.Beatmap.HitObjects[0] is Fruit f && f.HyperDash); 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 right hyperdash", () => getCatcher().Scale.X > 0 && getCatcher().HyperDashing);
AddUntilStep("wait for left 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) // Should produce a hyper-dash (edge case test)
beatmap.HitObjects.Add(new Fruit { StartTime = 1816, X = 308 / 512f, NewCombo = true }); beatmap.HitObjects.Add(new Fruit { StartTime = 1816, X = 56 / 512f, NewCombo = true });
beatmap.HitObjects.Add(new JuiceStream { StartTime = 2008, X = 56 / 512f, }); beatmap.HitObjects.Add(new Fruit { StartTime = 2008, X = 308 / 512f, NewCombo = true });
double startTime = 3000; double startTime = 3000;
const float left_x = 0.02f; const float left_x = 0.02f;
const float right_x = 0.98f; const float right_x = 0.98f;
createObjects(() => new Fruit(), left_x); createObjects(() => new Fruit { X = left_x });
createObjects(() => new JuiceStream(), right_x); createObjects(() => new TestJuiceStream(right_x), 1);
createObjects(() => new JuiceStream(), left_x); createObjects(() => new TestJuiceStream(left_x), 1);
createObjects(() => new Fruit(), right_x); createObjects(() => new Fruit { X = right_x });
createObjects(() => new Fruit(), left_x); createObjects(() => new Fruit { X = left_x });
createObjects(() => new Fruit(), right_x); createObjects(() => new Fruit { X = right_x });
createObjects(() => new JuiceStream(), left_x); createObjects(() => new TestJuiceStream(left_x), 1);
return beatmap; return beatmap;
void createObjects(Func<CatchHitObject> createObject, float x) void createObjects(Func<CatchHitObject> createObject, int count = 3)
{ {
const float spacing = 140; const float spacing = 140;
for (int i = 0; i < 3; i++) for (int i = 0; i < count; i++)
{ {
var hitObject = createObject(); var hitObject = createObject();
hitObject.X = x;
hitObject.StartTime = startTime + i * spacing; hitObject.StartTime = startTime + i * spacing;
beatmap.HitObjects.Add(hitObject); beatmap.HitObjects.Add(hitObject);
} }
startTime += 700; 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)),
});
}
}
} }
} }

View File

@ -1,11 +1,17 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Catch.Judgements;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Mods namespace osu.Game.Rulesets.Catch.Mods
{ {
public class CatchModPerfect : ModPerfect public class CatchModPerfect : ModPerfect
{ {
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
=> !(result.Judgement is CatchBananaJudgement)
&& base.FailCondition(healthProcessor, result);
} }
} }

View File

@ -91,10 +91,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
ApplyResult(r => r.Type = CheckPosition.Invoke(HitObject) ? HitResult.Perfect : HitResult.Miss); 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) protected override void UpdateStateTransforms(ArmedState state)
{ {
var endTime = HitObject.GetEndTime(); var endTime = HitObject.GetEndTime();

View File

@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
float startRotation = RNG.NextSingle() * 20; float startRotation = RNG.NextSingle() * 20;
double duration = HitObject.TimePreempt + 2000; double duration = HitObject.TimePreempt + 2000;
this.RotateTo(startRotation).RotateTo(startRotation + 720, duration); ScaleContainer.RotateTo(startRotation).RotateTo(startRotation + 720, duration);
} }
} }
} }

View File

@ -13,7 +13,6 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
public DrawableFruit(Fruit h) public DrawableFruit(Fruit h)
: base(h) : base(h)
{ {
Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
} }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
@ -21,6 +20,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
{ {
ScaleContainer.Child = new SkinnableDrawable( ScaleContainer.Child = new SkinnableDrawable(
new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece()); new CatchSkinComponent(getComponent(HitObject.VisualRepresentation)), _ => new FruitPiece());
ScaleContainer.Rotation = (float)(RNG.NextDouble() - 0.5f) * 40;
} }
private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation) private CatchSkinComponents getComponent(FruitVisualRepresentation hitObjectVisualRepresentation)

View File

@ -6,6 +6,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables; using osu.Game.Rulesets.Objects.Drawables;
using osuTK;
namespace osu.Game.Rulesets.Catch.Objects.Drawables namespace osu.Game.Rulesets.Catch.Objects.Drawables
{ {
@ -14,11 +15,13 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
private readonly Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation; private readonly Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation;
private readonly Container dropletContainer; private readonly Container dropletContainer;
public override Vector2 OriginPosition => base.OriginPosition - new Vector2(0, CatchHitObject.OBJECT_RADIUS);
public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null) public DrawableJuiceStream(JuiceStream s, Func<CatchHitObject, DrawableHitObject<CatchHitObject>> createDrawableRepresentation = null)
: base(s) : base(s)
{ {
this.createDrawableRepresentation = createDrawableRepresentation; this.createDrawableRepresentation = createDrawableRepresentation;
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.X;
Origin = Anchor.BottomLeft; Origin = Anchor.BottomLeft;
X = 0; X = 0;
@ -27,6 +30,8 @@ namespace osu.Game.Rulesets.Catch.Objects.Drawables
protected override void AddNestedHitObject(DrawableHitObject hitObject) protected override void AddNestedHitObject(DrawableHitObject hitObject)
{ {
hitObject.Origin = Anchor.BottomCentre;
base.AddNestedHitObject(hitObject); base.AddNestedHitObject(hitObject);
dropletContainer.Add(hitObject); dropletContainer.Add(hitObject);
} }

View File

@ -24,8 +24,8 @@ namespace osu.Game.Rulesets.Catch.Objects
public int RepeatCount { get; set; } public int RepeatCount { get; set; }
public double Velocity; public double Velocity { get; private set; }
public double TickDistance; public double TickDistance { get; private set; }
/// <summary> /// <summary>
/// The length of one span of this <see cref="JuiceStream"/>. /// The length of one span of this <see cref="JuiceStream"/>.
@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Catch.Objects
{ {
base.CreateNestedHitObjects(); base.CreateNestedHitObjects();
var tickSamples = Samples.Select(s => new HitSampleInfo var dropletSamples = Samples.Select(s => new HitSampleInfo
{ {
Bank = s.Bank, Bank = s.Bank,
Name = @"slidertick", Name = @"slidertick",
@ -75,7 +75,6 @@ namespace osu.Game.Rulesets.Catch.Objects
{ {
AddNested(new TinyDroplet AddNested(new TinyDroplet
{ {
Samples = tickSamples,
StartTime = t + lastEvent.Value.Time, StartTime = t + lastEvent.Value.Time,
X = X + Path.PositionAt( X = X + Path.PositionAt(
lastEvent.Value.PathProgress + (t / sinceLastTick) * (e.PathProgress - lastEvent.Value.PathProgress)).X / CatchPlayfield.BASE_WIDTH, 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: case SliderEventType.Tick:
AddNested(new Droplet AddNested(new Droplet
{ {
Samples = tickSamples, Samples = dropletSamples,
StartTime = e.Time, StartTime = e.Time,
X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH, X = X + Path.PositionAt(e.PathProgress).X / CatchPlayfield.BASE_WIDTH,
}); });

View File

@ -250,21 +250,28 @@ namespace osu.Game.Rulesets.Catch.UI
if (!Trail) return; if (!Trail) return;
var additive = createAdditiveSprite(HyperDashing);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint);
additive.Expire(true);
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
}
private Drawable createAdditiveSprite(bool hyperDash)
{
var additive = createCatcherSprite(); var additive = createCatcherSprite();
additive.Anchor = Anchor; additive.Anchor = Anchor;
additive.Scale = Scale; additive.Scale = Scale;
additive.Colour = HyperDashing ? Color4.Red : Color4.White; additive.Colour = hyperDash ? Color4.Red : Color4.White;
additive.Blending = BlendingParameters.Additive; additive.Blending = BlendingParameters.Additive;
additive.RelativePositionAxes = RelativePositionAxes; additive.RelativePositionAxes = RelativePositionAxes;
additive.Position = Position; additive.Position = Position;
AdditiveTarget.Add(additive); AdditiveTarget.Add(additive);
additive.FadeTo(0.4f).FadeOut(800, Easing.OutQuint); return additive;
additive.Expire(true);
Scheduler.AddDelayed(beginTrail, HyperDashing ? 25 : 50);
} }
private Drawable createCatcherSprite() => new CatcherSprite(currentState); private Drawable createCatcherSprite() => new CatcherSprite(currentState);
@ -372,14 +379,14 @@ namespace osu.Game.Rulesets.Catch.UI
{ {
const float hyper_dash_transition_length = 180; const float hyper_dash_transition_length = 180;
bool previouslyHyperDashing = HyperDashing; bool wasHyperDashing = HyperDashing;
if (modifier <= 1 || X == targetPosition) if (modifier <= 1 || X == targetPosition)
{ {
hyperDashModifier = 1; hyperDashModifier = 1;
hyperDashDirection = 0; hyperDashDirection = 0;
if (previouslyHyperDashing) if (wasHyperDashing)
{ {
this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint); this.FadeColour(Color4.White, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint); this.FadeTo(1, hyper_dash_transition_length, Easing.OutQuint);
@ -392,11 +399,18 @@ namespace osu.Game.Rulesets.Catch.UI
hyperDashDirection = Math.Sign(targetPosition - X); hyperDashDirection = Math.Sign(targetPosition - X);
hyperDashTargetPosition = targetPosition; hyperDashTargetPosition = targetPosition;
if (!previouslyHyperDashing) if (!wasHyperDashing)
{ {
this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint); this.FadeColour(Color4.OrangeRed, hyper_dash_transition_length, Easing.OutQuint);
this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint); this.FadeTo(0.2f, hyper_dash_transition_length, Easing.OutQuint);
Trail = true; 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);
} }
} }
} }

View File

@ -0,0 +1,26 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.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);
}
}

View File

@ -0,0 +1,52 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.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);
}
}
}

View File

@ -0,0 +1,101 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.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;
}
}
}
}

View File

@ -36,8 +36,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly SpriteIcon symbol; private readonly SpriteIcon symbol;
private readonly Color4 baseColour = OsuColour.FromHex(@"002c3c"); private readonly Color4 baseColour = Color4Extensions.FromHex(@"002c3c");
private readonly Color4 fillColour = OsuColour.FromHex(@"005b7c"); private readonly Color4 fillColour = Color4Extensions.FromHex(@"005b7c");
private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>(); private readonly IBindable<Vector2> positionBindable = new Bindable<Vector2>();

View File

@ -12,7 +12,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
new DifficultyRange(HitResult.Great, 80, 50, 20), new DifficultyRange(HitResult.Great, 80, 50, 20),
new DifficultyRange(HitResult.Good, 140, 100, 60), new DifficultyRange(HitResult.Good, 140, 100, 60),
new DifficultyRange(HitResult.Meh, 200, 150, 100), 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) public override bool IsHitResultAllowed(HitResult result)

View File

@ -0,0 +1,47 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.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)
}
}
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Judgements;
@ -39,7 +40,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
{ {
base.ApplyBeatmap(beatmap); base.ApplyBeatmap(beatmap);
hpMultiplier = 1 / (object_count_factor * beatmap.HitObjects.OfType<Hit>().Count() * BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.5, 0.75, 0.98)); hpMultiplier = 1 / (object_count_factor * Math.Max(1, beatmap.HitObjects.OfType<Hit>().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); hpMissMultiplier = BeatmapDifficulty.DifficultyRange(beatmap.BeatmapInfo.BaseDifficulty.DrainRate, 0.0018, 0.0075, 0.0120);
} }

View File

@ -99,7 +99,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
var storyboard = decoder.Decode(stream); var storyboard = decoder.Decode(stream);
StoryboardLayer background = storyboard.Layers.Single(l => l.Depth == 3); 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);
} }
} }
} }

View File

@ -1,5 +1,5 @@
[Variables] [Variables]
$var=1234 $var=34
[Events] [Events]
Sprite,Background,TopCentre,"img.jpg",$var56,240 Sprite,Background,TopCentre,"img.jpg",$var56,240

View File

@ -19,7 +19,7 @@ namespace osu.Game.Tests.Visual.Menus
API.LocalUser.Value = new User API.LocalUser.Value = new User
{ {
Username = API.LocalUser.Value.Username, Username = API.LocalUser.Value.Username,
Id = API.LocalUser.Value.Id, Id = API.LocalUser.Value.Id + 1,
IsSupporter = !API.LocalUser.Value.IsSupporter, IsSupporter = !API.LocalUser.Value.IsSupporter,
}; };
}); });

View File

@ -7,6 +7,7 @@ using System.Linq;
using NUnit.Framework; using NUnit.Framework;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -102,7 +103,7 @@ namespace osu.Game.Tests.Visual.Online
{ {
bool hasBackground = !string.IsNullOrEmpty(newLine.Message.Sender.Colour); 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 linkCompilers = newLine.ContentFlow.Where(d => d is DrawableLinkCompiler).ToList();
var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts); var linkSprites = linkCompilers.SelectMany(comp => ((DrawableLinkCompiler)comp).Parts);

View File

@ -465,6 +465,43 @@ namespace osu.Game.Tests.Visual.SongSelect
AddAssert("carousel still correct", () => songSelect.Carousel.SelectedBeatmap.OnlineBeatmapID == target.OnlineBeatmapID); 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<SearchTextBox>().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<SearchTextBox>().First().Text = "nononoo");
AddUntilStep("game lost selection", () => Beatmap.Value is DummyWorkingBeatmap);
AddAssert("carousel lost selection", () => songSelect.Carousel.SelectedBeatmap == null);
}
[Test] [Test]
public void TestAutoplayViaCtrlEnter() public void TestAutoplayViaCtrlEnter()
{ {

View File

@ -84,7 +84,7 @@ namespace osu.Game.Tournament.Components
// else if (info.CurrentMatch.Value.Team2.Value.Players.Any(u => u.Id == Message.Sender.Id)) // else if (info.CurrentMatch.Value.Team2.Value.Players.Any(u => u.Id == Message.Sender.Id))
// SenderText.Colour = TournamentGame.COLOUR_BLUE; // SenderText.Colour = TournamentGame.COLOUR_BLUE;
// else if (Message.Sender.Colour != null) // else if (Message.Sender.Colour != null)
// SenderText.Colour = ColourBox.Colour = OsuColour.FromHex(Message.Sender.Colour); // SenderText.Colour = ColourBox.Colour = Color4Extensions.FromHex(Message.Sender.Colour);
} }
} }
} }

View File

@ -76,7 +76,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
}, },
box = new Box box = new Box
{ {
Colour = OsuColour.FromHex("#FFE8AD"), Colour = Color4Extensions.FromHex("#FFE8AD"),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
}; };
@ -85,7 +85,7 @@ namespace osu.Game.Tournament.Screens.Gameplay.Components
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Type = EdgeEffectType.Glow, Type = EdgeEffectType.Glow,
Colour = OsuColour.FromHex("#FFE8AD").Opacity(0.1f), Colour = Color4Extensions.FromHex("#FFE8AD").Opacity(0.1f),
Hollow = true, Hollow = true,
Radius = 20, Radius = 20,
Roundness = 10, Roundness = 10,

View File

@ -4,6 +4,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
@ -85,8 +86,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
this.ladderEditor = ladderEditor; this.ladderEditor = ladderEditor;
colourWinner = losers colourWinner = losers
? OsuColour.FromHex("#8E7F48") ? Color4Extensions.FromHex("#8E7F48")
: OsuColour.FromHex("#1462AA"); : Color4Extensions.FromHex("#1462AA");
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
@ -180,8 +181,8 @@ namespace osu.Game.Tournament.Screens.Ladder.Components
{ {
bool winner = completed.Value && isWinner?.Invoke() == true; bool winner = completed.Value && isWinner?.Invoke() == true;
background.FadeColour(winner ? Color4.White : OsuColour.FromHex("#444"), winner ? 500 : 0, Easing.OutQuint); background.FadeColour(winner ? Color4.White : Color4Extensions.FromHex("#444"), winner ? 500 : 0, Easing.OutQuint);
backgroundRight.FadeColour(winner ? colourWinner : OsuColour.FromHex("#333"), winner ? 500 : 0, Easing.OutQuint); backgroundRight.FadeColour(winner ? colourWinner : Color4Extensions.FromHex("#333"), winner ? 500 : 0, Easing.OutQuint);
AcronymText.Colour = winner ? Color4.Black : Color4.White; AcronymText.Colour = winner ? Color4.Black : Color4.White;

View File

@ -32,8 +32,8 @@ namespace osu.Game.Tournament.Screens.Ladder
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours, Storage storage) private void load(OsuColour colours, Storage storage)
{ {
normalPathColour = OsuColour.FromHex("#66D1FF"); normalPathColour = Color4Extensions.FromHex("#66D1FF");
losersPathColour = OsuColour.FromHex("#FFC700"); losersPathColour = Color4Extensions.FromHex("#FFC700");
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;

View File

@ -1,9 +1,9 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Game.Graphics;
using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Cursor;
using osu.Game.Tournament.Models; using osu.Game.Tournament.Models;
using osuTK.Graphics; 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 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_RED = Color4Extensions.FromHex("#AA1414");
public static readonly Color4 COLOUR_BLUE = OsuColour.FromHex("#1462AA"); public static readonly Color4 COLOUR_BLUE = Color4Extensions.FromHex("#1462AA");
public static readonly Color4 ELEMENT_BACKGROUND_COLOUR = OsuColour.FromHex("#fff"); public static readonly Color4 ELEMENT_BACKGROUND_COLOUR = Color4Extensions.FromHex("#fff");
public static readonly Color4 ELEMENT_FOREGROUND_COLOUR = OsuColour.FromHex("#000"); 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() protected override void LoadComplete()
{ {

View File

@ -3,7 +3,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization;
using System.IO; using System.IO;
using osuTK; using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
@ -93,8 +92,8 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[1]); var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]); var origin = parseOrigin(split[2]);
var path = CleanFilename(split[3]); var path = CleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); var x = Parsing.ParseFloat(split[4], Parsing.MAX_COORDINATE_VALUE);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); var y = Parsing.ParseFloat(split[5], Parsing.MAX_COORDINATE_VALUE);
storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y)); storyboardSprite = new StoryboardSprite(path, origin, new Vector2(x, y));
storyboard.GetLayer(layer).Add(storyboardSprite); storyboard.GetLayer(layer).Add(storyboardSprite);
break; break;
@ -105,10 +104,10 @@ namespace osu.Game.Beatmaps.Formats
var layer = parseLayer(split[1]); var layer = parseLayer(split[1]);
var origin = parseOrigin(split[2]); var origin = parseOrigin(split[2]);
var path = CleanFilename(split[3]); var path = CleanFilename(split[3]);
var x = float.Parse(split[4], NumberFormatInfo.InvariantInfo); var x = Parsing.ParseFloat(split[4], Parsing.MAX_COORDINATE_VALUE);
var y = float.Parse(split[5], NumberFormatInfo.InvariantInfo); var y = Parsing.ParseFloat(split[5], Parsing.MAX_COORDINATE_VALUE);
var frameCount = int.Parse(split[6]); var frameCount = Parsing.ParseInt(split[6]);
var frameDelay = double.Parse(split[7], NumberFormatInfo.InvariantInfo); var frameDelay = Parsing.ParseDouble(split[7]);
var loopType = split.Length > 8 ? (AnimationLoopType)Enum.Parse(typeof(AnimationLoopType), split[8]) : AnimationLoopType.LoopForever; 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); storyboardSprite = new StoryboardAnimation(path, origin, new Vector2(x, y), frameCount, frameDelay, loopType);
storyboard.GetLayer(layer).Add(storyboardSprite); storyboard.GetLayer(layer).Add(storyboardSprite);
@ -117,10 +116,10 @@ namespace osu.Game.Beatmaps.Formats
case LegacyEventType.Sample: case LegacyEventType.Sample:
{ {
var time = double.Parse(split[1], CultureInfo.InvariantCulture); var time = Parsing.ParseDouble(split[1]);
var layer = parseLayer(split[2]); var layer = parseLayer(split[2]);
var path = CleanFilename(split[3]); 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)); storyboard.GetLayer(layer).Add(new StoryboardSampleInfo(path, time, (int)volume));
break; break;
} }
@ -138,17 +137,17 @@ namespace osu.Game.Beatmaps.Formats
case "T": case "T":
{ {
var triggerName = split[1]; var triggerName = split[1];
var startTime = split.Length > 2 ? double.Parse(split[2], CultureInfo.InvariantCulture) : double.MinValue; var startTime = split.Length > 2 ? Parsing.ParseDouble(split[2]) : double.MinValue;
var endTime = split.Length > 3 ? double.Parse(split[3], CultureInfo.InvariantCulture) : double.MaxValue; var endTime = split.Length > 3 ? Parsing.ParseDouble(split[3]) : double.MaxValue;
var groupNumber = split.Length > 4 ? int.Parse(split[4]) : 0; var groupNumber = split.Length > 4 ? Parsing.ParseInt(split[4]) : 0;
timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber); timelineGroup = storyboardSprite?.AddTrigger(triggerName, startTime, endTime, groupNumber);
break; break;
} }
case "L": case "L":
{ {
var startTime = double.Parse(split[1], CultureInfo.InvariantCulture); var startTime = Parsing.ParseDouble(split[1]);
var loopCount = int.Parse(split[2]); var loopCount = Parsing.ParseInt(split[2]);
timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount); timelineGroup = storyboardSprite?.AddLoop(startTime, loopCount);
break; break;
} }
@ -158,52 +157,52 @@ namespace osu.Game.Beatmaps.Formats
if (string.IsNullOrEmpty(split[3])) if (string.IsNullOrEmpty(split[3]))
split[3] = split[2]; split[3] = split[2];
var easing = (Easing)int.Parse(split[1]); var easing = (Easing)Parsing.ParseInt(split[1]);
var startTime = double.Parse(split[2], CultureInfo.InvariantCulture); var startTime = Parsing.ParseDouble(split[2]);
var endTime = double.Parse(split[3], CultureInfo.InvariantCulture); var endTime = Parsing.ParseDouble(split[3]);
switch (commandType) switch (commandType)
{ {
case "F": case "F":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.Alpha.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "S": case "S":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Scale.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.Scale.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "V": case "V":
{ {
var startX = float.Parse(split[4], CultureInfo.InvariantCulture); var startX = Parsing.ParseFloat(split[4]);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture); var startY = Parsing.ParseFloat(split[5]);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; var endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; var endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
timelineGroup?.VectorScale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY)); timelineGroup?.VectorScale.Add(easing, startTime, endTime, new Vector2(startX, startY), new Vector2(endX, endY));
break; break;
} }
case "R": case "R":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Rotation.Add(easing, startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue)); timelineGroup?.Rotation.Add(easing, startTime, endTime, MathUtils.RadiansToDegrees(startValue), MathUtils.RadiansToDegrees(endValue));
break; break;
} }
case "M": case "M":
{ {
var startX = float.Parse(split[4], CultureInfo.InvariantCulture); var startX = Parsing.ParseFloat(split[4]);
var startY = float.Parse(split[5], CultureInfo.InvariantCulture); var startY = Parsing.ParseFloat(split[5]);
var endX = split.Length > 6 ? float.Parse(split[6], CultureInfo.InvariantCulture) : startX; var endX = split.Length > 6 ? Parsing.ParseFloat(split[6]) : startX;
var endY = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startY; var endY = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startY;
timelineGroup?.X.Add(easing, startTime, endTime, startX, endX); timelineGroup?.X.Add(easing, startTime, endTime, startX, endX);
timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY); timelineGroup?.Y.Add(easing, startTime, endTime, startY, endY);
break; break;
@ -211,28 +210,28 @@ namespace osu.Game.Beatmaps.Formats
case "MX": case "MX":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.X.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "MY": case "MY":
{ {
var startValue = float.Parse(split[4], CultureInfo.InvariantCulture); var startValue = Parsing.ParseFloat(split[4]);
var endValue = split.Length > 5 ? float.Parse(split[5], CultureInfo.InvariantCulture) : startValue; var endValue = split.Length > 5 ? Parsing.ParseFloat(split[5]) : startValue;
timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue); timelineGroup?.Y.Add(easing, startTime, endTime, startValue, endValue);
break; break;
} }
case "C": case "C":
{ {
var startRed = float.Parse(split[4], CultureInfo.InvariantCulture); var startRed = Parsing.ParseFloat(split[4]);
var startGreen = float.Parse(split[5], CultureInfo.InvariantCulture); var startGreen = Parsing.ParseFloat(split[5]);
var startBlue = float.Parse(split[6], CultureInfo.InvariantCulture); var startBlue = Parsing.ParseFloat(split[6]);
var endRed = split.Length > 7 ? float.Parse(split[7], CultureInfo.InvariantCulture) : startRed; var endRed = split.Length > 7 ? Parsing.ParseFloat(split[7]) : startRed;
var endGreen = split.Length > 8 ? float.Parse(split[8], CultureInfo.InvariantCulture) : startGreen; var endGreen = split.Length > 8 ? Parsing.ParseFloat(split[8]) : startGreen;
var endBlue = split.Length > 9 ? float.Parse(split[9], CultureInfo.InvariantCulture) : startBlue; var endBlue = split.Length > 9 ? Parsing.ParseFloat(split[9]) : startBlue;
timelineGroup?.Colour.Add(easing, startTime, endTime, timelineGroup?.Colour.Add(easing, startTime, endTime,
new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1), new Color4(startRed / 255f, startGreen / 255f, startBlue / 255f, 1),
new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1)); new Color4(endRed / 255f, endGreen / 255f, endBlue / 255f, 1));

View File

@ -15,11 +15,13 @@ namespace osu.Game.Database
{ {
/// <summary> /// <summary>
/// Fired when a <typeparamref name="TModel"/> download begins. /// Fired when a <typeparamref name="TModel"/> download begins.
/// This is NOT run on the update thread and should be scheduled.
/// </summary> /// </summary>
event Action<ArchiveDownloadRequest<TModel>> DownloadBegan; event Action<ArchiveDownloadRequest<TModel>> DownloadBegan;
/// <summary> /// <summary>
/// Fired when a <typeparamref name="TModel"/> download is interrupted, either due to user cancellation or failure. /// Fired when a <typeparamref name="TModel"/> download is interrupted, either due to user cancellation or failure.
/// This is NOT run on the update thread and should be scheduled.
/// </summary> /// </summary>
event Action<ArchiveDownloadRequest<TModel>> DownloadFailed; event Action<ArchiveDownloadRequest<TModel>> DownloadFailed;

View File

@ -1,8 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System; using osu.Framework.Extensions.Color4Extensions;
using System.Globalization;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osuTK.Graphics; 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(float amt) => new Color4(amt, amt, amt, 1f);
public static Color4 Gray(byte amt) => new Color4(amt, amt, amt, 255); 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) public Color4 ForDifficultyRating(DifficultyRating difficulty, bool useLighterColour = false)
{ {
switch (difficulty) switch (difficulty)
@ -78,105 +38,105 @@ namespace osu.Game.Graphics
} }
// See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less // See https://github.com/ppy/osu-web/blob/master/resources/assets/less/colors.less
public readonly Color4 PurpleLighter = FromHex(@"eeeeff"); public readonly Color4 PurpleLighter = Color4Extensions.FromHex(@"eeeeff");
public readonly Color4 PurpleLight = FromHex(@"aa88ff"); public readonly Color4 PurpleLight = Color4Extensions.FromHex(@"aa88ff");
public readonly Color4 PurpleLightAlternative = FromHex(@"cba4da"); public readonly Color4 PurpleLightAlternative = Color4Extensions.FromHex(@"cba4da");
public readonly Color4 Purple = FromHex(@"8866ee"); public readonly Color4 Purple = Color4Extensions.FromHex(@"8866ee");
public readonly Color4 PurpleDark = FromHex(@"6644cc"); public readonly Color4 PurpleDark = Color4Extensions.FromHex(@"6644cc");
public readonly Color4 PurpleDarkAlternative = FromHex(@"312436"); public readonly Color4 PurpleDarkAlternative = Color4Extensions.FromHex(@"312436");
public readonly Color4 PurpleDarker = FromHex(@"441188"); public readonly Color4 PurpleDarker = Color4Extensions.FromHex(@"441188");
public readonly Color4 PinkLighter = FromHex(@"ffddee"); public readonly Color4 PinkLighter = Color4Extensions.FromHex(@"ffddee");
public readonly Color4 PinkLight = FromHex(@"ff99cc"); public readonly Color4 PinkLight = Color4Extensions.FromHex(@"ff99cc");
public readonly Color4 Pink = FromHex(@"ff66aa"); public readonly Color4 Pink = Color4Extensions.FromHex(@"ff66aa");
public readonly Color4 PinkDark = FromHex(@"cc5288"); public readonly Color4 PinkDark = Color4Extensions.FromHex(@"cc5288");
public readonly Color4 PinkDarker = FromHex(@"bb1177"); public readonly Color4 PinkDarker = Color4Extensions.FromHex(@"bb1177");
public readonly Color4 BlueLighter = FromHex(@"ddffff"); public readonly Color4 BlueLighter = Color4Extensions.FromHex(@"ddffff");
public readonly Color4 BlueLight = FromHex(@"99eeff"); public readonly Color4 BlueLight = Color4Extensions.FromHex(@"99eeff");
public readonly Color4 Blue = FromHex(@"66ccff"); public readonly Color4 Blue = Color4Extensions.FromHex(@"66ccff");
public readonly Color4 BlueDark = FromHex(@"44aadd"); public readonly Color4 BlueDark = Color4Extensions.FromHex(@"44aadd");
public readonly Color4 BlueDarker = FromHex(@"2299bb"); public readonly Color4 BlueDarker = Color4Extensions.FromHex(@"2299bb");
public readonly Color4 YellowLighter = FromHex(@"ffffdd"); public readonly Color4 YellowLighter = Color4Extensions.FromHex(@"ffffdd");
public readonly Color4 YellowLight = FromHex(@"ffdd55"); public readonly Color4 YellowLight = Color4Extensions.FromHex(@"ffdd55");
public readonly Color4 Yellow = FromHex(@"ffcc22"); public readonly Color4 Yellow = Color4Extensions.FromHex(@"ffcc22");
public readonly Color4 YellowDark = FromHex(@"eeaa00"); public readonly Color4 YellowDark = Color4Extensions.FromHex(@"eeaa00");
public readonly Color4 YellowDarker = FromHex(@"cc6600"); public readonly Color4 YellowDarker = Color4Extensions.FromHex(@"cc6600");
public readonly Color4 GreenLighter = FromHex(@"eeffcc"); public readonly Color4 GreenLighter = Color4Extensions.FromHex(@"eeffcc");
public readonly Color4 GreenLight = FromHex(@"b3d944"); public readonly Color4 GreenLight = Color4Extensions.FromHex(@"b3d944");
public readonly Color4 Green = FromHex(@"88b300"); public readonly Color4 Green = Color4Extensions.FromHex(@"88b300");
public readonly Color4 GreenDark = FromHex(@"668800"); public readonly Color4 GreenDark = Color4Extensions.FromHex(@"668800");
public readonly Color4 GreenDarker = FromHex(@"445500"); public readonly Color4 GreenDarker = Color4Extensions.FromHex(@"445500");
public readonly Color4 Sky = FromHex(@"6bb5ff"); public readonly Color4 Sky = Color4Extensions.FromHex(@"6bb5ff");
public readonly Color4 GreySkyLighter = FromHex(@"c6e3f4"); public readonly Color4 GreySkyLighter = Color4Extensions.FromHex(@"c6e3f4");
public readonly Color4 GreySkyLight = FromHex(@"8ab3cc"); public readonly Color4 GreySkyLight = Color4Extensions.FromHex(@"8ab3cc");
public readonly Color4 GreySky = FromHex(@"405461"); public readonly Color4 GreySky = Color4Extensions.FromHex(@"405461");
public readonly Color4 GreySkyDark = FromHex(@"303d47"); public readonly Color4 GreySkyDark = Color4Extensions.FromHex(@"303d47");
public readonly Color4 GreySkyDarker = FromHex(@"21272c"); public readonly Color4 GreySkyDarker = Color4Extensions.FromHex(@"21272c");
public readonly Color4 Seafoam = FromHex(@"05ffa2"); public readonly Color4 Seafoam = Color4Extensions.FromHex(@"05ffa2");
public readonly Color4 GreySeafoamLighter = FromHex(@"9ebab1"); public readonly Color4 GreySeafoamLighter = Color4Extensions.FromHex(@"9ebab1");
public readonly Color4 GreySeafoamLight = FromHex(@"4d7365"); public readonly Color4 GreySeafoamLight = Color4Extensions.FromHex(@"4d7365");
public readonly Color4 GreySeafoam = FromHex(@"33413c"); public readonly Color4 GreySeafoam = Color4Extensions.FromHex(@"33413c");
public readonly Color4 GreySeafoamDark = FromHex(@"2c3532"); public readonly Color4 GreySeafoamDark = Color4Extensions.FromHex(@"2c3532");
public readonly Color4 GreySeafoamDarker = FromHex(@"1e2422"); public readonly Color4 GreySeafoamDarker = Color4Extensions.FromHex(@"1e2422");
public readonly Color4 Cyan = FromHex(@"05f4fd"); public readonly Color4 Cyan = Color4Extensions.FromHex(@"05f4fd");
public readonly Color4 GreyCyanLighter = FromHex(@"77b1b3"); public readonly Color4 GreyCyanLighter = Color4Extensions.FromHex(@"77b1b3");
public readonly Color4 GreyCyanLight = FromHex(@"436d6f"); public readonly Color4 GreyCyanLight = Color4Extensions.FromHex(@"436d6f");
public readonly Color4 GreyCyan = FromHex(@"293d3e"); public readonly Color4 GreyCyan = Color4Extensions.FromHex(@"293d3e");
public readonly Color4 GreyCyanDark = FromHex(@"243536"); public readonly Color4 GreyCyanDark = Color4Extensions.FromHex(@"243536");
public readonly Color4 GreyCyanDarker = FromHex(@"1e2929"); public readonly Color4 GreyCyanDarker = Color4Extensions.FromHex(@"1e2929");
public readonly Color4 Lime = FromHex(@"82ff05"); public readonly Color4 Lime = Color4Extensions.FromHex(@"82ff05");
public readonly Color4 GreyLimeLighter = FromHex(@"deff87"); public readonly Color4 GreyLimeLighter = Color4Extensions.FromHex(@"deff87");
public readonly Color4 GreyLimeLight = FromHex(@"657259"); public readonly Color4 GreyLimeLight = Color4Extensions.FromHex(@"657259");
public readonly Color4 GreyLime = FromHex(@"3f443a"); public readonly Color4 GreyLime = Color4Extensions.FromHex(@"3f443a");
public readonly Color4 GreyLimeDark = FromHex(@"32352e"); public readonly Color4 GreyLimeDark = Color4Extensions.FromHex(@"32352e");
public readonly Color4 GreyLimeDarker = FromHex(@"2e302b"); public readonly Color4 GreyLimeDarker = Color4Extensions.FromHex(@"2e302b");
public readonly Color4 Violet = FromHex(@"bf04ff"); public readonly Color4 Violet = Color4Extensions.FromHex(@"bf04ff");
public readonly Color4 GreyVioletLighter = FromHex(@"ebb8fe"); public readonly Color4 GreyVioletLighter = Color4Extensions.FromHex(@"ebb8fe");
public readonly Color4 GreyVioletLight = FromHex(@"685370"); public readonly Color4 GreyVioletLight = Color4Extensions.FromHex(@"685370");
public readonly Color4 GreyViolet = FromHex(@"46334d"); public readonly Color4 GreyViolet = Color4Extensions.FromHex(@"46334d");
public readonly Color4 GreyVioletDark = FromHex(@"2c2230"); public readonly Color4 GreyVioletDark = Color4Extensions.FromHex(@"2c2230");
public readonly Color4 GreyVioletDarker = FromHex(@"201823"); public readonly Color4 GreyVioletDarker = Color4Extensions.FromHex(@"201823");
public readonly Color4 Carmine = FromHex(@"ff0542"); public readonly Color4 Carmine = Color4Extensions.FromHex(@"ff0542");
public readonly Color4 GreyCarmineLighter = FromHex(@"deaab4"); public readonly Color4 GreyCarmineLighter = Color4Extensions.FromHex(@"deaab4");
public readonly Color4 GreyCarmineLight = FromHex(@"644f53"); public readonly Color4 GreyCarmineLight = Color4Extensions.FromHex(@"644f53");
public readonly Color4 GreyCarmine = FromHex(@"342b2d"); public readonly Color4 GreyCarmine = Color4Extensions.FromHex(@"342b2d");
public readonly Color4 GreyCarmineDark = FromHex(@"302a2b"); public readonly Color4 GreyCarmineDark = Color4Extensions.FromHex(@"302a2b");
public readonly Color4 GreyCarmineDarker = FromHex(@"241d1e"); public readonly Color4 GreyCarmineDarker = Color4Extensions.FromHex(@"241d1e");
public readonly Color4 Gray0 = FromHex(@"000"); public readonly Color4 Gray0 = Color4Extensions.FromHex(@"000");
public readonly Color4 Gray1 = FromHex(@"111"); public readonly Color4 Gray1 = Color4Extensions.FromHex(@"111");
public readonly Color4 Gray2 = FromHex(@"222"); public readonly Color4 Gray2 = Color4Extensions.FromHex(@"222");
public readonly Color4 Gray3 = FromHex(@"333"); public readonly Color4 Gray3 = Color4Extensions.FromHex(@"333");
public readonly Color4 Gray4 = FromHex(@"444"); public readonly Color4 Gray4 = Color4Extensions.FromHex(@"444");
public readonly Color4 Gray5 = FromHex(@"555"); public readonly Color4 Gray5 = Color4Extensions.FromHex(@"555");
public readonly Color4 Gray6 = FromHex(@"666"); public readonly Color4 Gray6 = Color4Extensions.FromHex(@"666");
public readonly Color4 Gray7 = FromHex(@"777"); public readonly Color4 Gray7 = Color4Extensions.FromHex(@"777");
public readonly Color4 Gray8 = FromHex(@"888"); public readonly Color4 Gray8 = Color4Extensions.FromHex(@"888");
public readonly Color4 Gray9 = FromHex(@"999"); public readonly Color4 Gray9 = Color4Extensions.FromHex(@"999");
public readonly Color4 GrayA = FromHex(@"aaa"); public readonly Color4 GrayA = Color4Extensions.FromHex(@"aaa");
public readonly Color4 GrayB = FromHex(@"bbb"); public readonly Color4 GrayB = Color4Extensions.FromHex(@"bbb");
public readonly Color4 GrayC = FromHex(@"ccc"); public readonly Color4 GrayC = Color4Extensions.FromHex(@"ccc");
public readonly Color4 GrayD = FromHex(@"ddd"); public readonly Color4 GrayD = Color4Extensions.FromHex(@"ddd");
public readonly Color4 GrayE = FromHex(@"eee"); public readonly Color4 GrayE = Color4Extensions.FromHex(@"eee");
public readonly Color4 GrayF = FromHex(@"fff"); public readonly Color4 GrayF = Color4Extensions.FromHex(@"fff");
public readonly Color4 RedLighter = FromHex(@"ffeded"); public readonly Color4 RedLighter = Color4Extensions.FromHex(@"ffeded");
public readonly Color4 RedLight = FromHex(@"ed7787"); public readonly Color4 RedLight = Color4Extensions.FromHex(@"ed7787");
public readonly Color4 Red = FromHex(@"ed1121"); public readonly Color4 Red = Color4Extensions.FromHex(@"ed1121");
public readonly Color4 RedDark = FromHex(@"ba0011"); public readonly Color4 RedDark = Color4Extensions.FromHex(@"ba0011");
public readonly Color4 RedDarker = FromHex(@"870000"); 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");
} }
} }

View File

@ -4,6 +4,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
@ -38,7 +39,7 @@ namespace osu.Game.Graphics.UserInterface
sampleClick = audio.Samples.Get(@"UI/generic-select"); sampleClick = audio.Samples.Get(@"UI/generic-select");
BackgroundColour = Color4.Transparent; BackgroundColour = Color4.Transparent;
BackgroundColourHover = OsuColour.FromHex(@"172023"); BackgroundColourHover = Color4Extensions.FromHex(@"172023");
updateTextColour(); updateTextColour();
} }
@ -57,7 +58,7 @@ namespace osu.Game.Graphics.UserInterface
break; break;
case MenuItemType.Highlighted: case MenuItemType.Highlighted:
text.Colour = OsuColour.FromHex(@"ffcc22"); text.Colour = Color4Extensions.FromHex(@"ffcc22");
break; break;
} }
} }

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -42,7 +43,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("1c2125"), Colour = Color4Extensions.FromHex("1c2125"),
}, },
new FillFlowContainer new FillFlowContainer
{ {

View File

@ -53,17 +53,17 @@ namespace osu.Game.Online
manager.ItemRemoved += itemRemoved; manager.ItemRemoved += itemRemoved;
} }
private void downloadBegan(ArchiveDownloadRequest<TModel> request) private void downloadBegan(ArchiveDownloadRequest<TModel> request) => Schedule(() =>
{ {
if (request.Model.Equals(Model.Value)) if (request.Model.Equals(Model.Value))
attachDownload(request); attachDownload(request);
} });
private void downloadFailed(ArchiveDownloadRequest<TModel> request) private void downloadFailed(ArchiveDownloadRequest<TModel> request) => Schedule(() =>
{ {
if (request.Model.Equals(Model.Value)) if (request.Model.Equals(Model.Value))
attachDownload(null); attachDownload(null);
} });
private ArchiveDownloadRequest<TModel> attachedRequest; private ArchiveDownloadRequest<TModel> attachedRequest;

View File

@ -80,23 +80,23 @@ namespace osu.Game.Online.Leaderboards
{ {
case ScoreRank.XH: case ScoreRank.XH:
case ScoreRank.X: case ScoreRank.X:
return OsuColour.FromHex(@"ce1c9d"); return Color4Extensions.FromHex(@"ce1c9d");
case ScoreRank.SH: case ScoreRank.SH:
case ScoreRank.S: case ScoreRank.S:
return OsuColour.FromHex(@"00a8b5"); return Color4Extensions.FromHex(@"00a8b5");
case ScoreRank.A: case ScoreRank.A:
return OsuColour.FromHex(@"7cce14"); return Color4Extensions.FromHex(@"7cce14");
case ScoreRank.B: case ScoreRank.B:
return OsuColour.FromHex(@"e3b130"); return Color4Extensions.FromHex(@"e3b130");
case ScoreRank.C: case ScoreRank.C:
return OsuColour.FromHex(@"f18252"); return Color4Extensions.FromHex(@"f18252");
default: default:
return OsuColour.FromHex(@"e95353"); return Color4Extensions.FromHex(@"e95353");
} }
} }
@ -109,23 +109,23 @@ namespace osu.Game.Online.Leaderboards
{ {
case ScoreRank.XH: case ScoreRank.XH:
case ScoreRank.SH: case ScoreRank.SH:
return ColourInfo.GradientVertical(Color4.White, OsuColour.FromHex("afdff0")); return ColourInfo.GradientVertical(Color4.White, Color4Extensions.FromHex("afdff0"));
case ScoreRank.X: case ScoreRank.X:
case ScoreRank.S: case ScoreRank.S:
return ColourInfo.GradientVertical(OsuColour.FromHex(@"ffe7a8"), OsuColour.FromHex(@"ffb800")); return ColourInfo.GradientVertical(Color4Extensions.FromHex(@"ffe7a8"), Color4Extensions.FromHex(@"ffb800"));
case ScoreRank.A: case ScoreRank.A:
return OsuColour.FromHex(@"275227"); return Color4Extensions.FromHex(@"275227");
case ScoreRank.B: case ScoreRank.B:
return OsuColour.FromHex(@"553a2b"); return Color4Extensions.FromHex(@"553a2b");
case ScoreRank.C: case ScoreRank.C:
return OsuColour.FromHex(@"473625"); return Color4Extensions.FromHex(@"473625");
default: default:
return OsuColour.FromHex(@"512525"); return Color4Extensions.FromHex(@"512525");
} }
} }
} }

View File

@ -200,7 +200,7 @@ namespace osu.Game.Online.Leaderboards
scoreLabel = new GlowingSpriteText scoreLabel = new GlowingSpriteText
{ {
TextColour = Color4.White, TextColour = Color4.White,
GlowColour = OsuColour.FromHex(@"83ccfa"), GlowColour = Color4Extensions.FromHex(@"83ccfa"),
Text = score.TotalScore.ToString(@"N0"), Text = score.TotalScore.ToString(@"N0"),
Font = OsuFont.Numeric.With(size: 23), Font = OsuFont.Numeric.With(size: 23),
}, },
@ -325,7 +325,7 @@ namespace osu.Game.Online.Leaderboards
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(icon_size), Size = new Vector2(icon_size),
Rotation = 45, Rotation = 45,
Colour = OsuColour.FromHex(@"3087ac"), Colour = Color4Extensions.FromHex(@"3087ac"),
Icon = FontAwesome.Solid.Square, Icon = FontAwesome.Solid.Square,
Shadow = true, Shadow = true,
}, },
@ -334,7 +334,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Size = new Vector2(icon_size - 6), Size = new Vector2(icon_size - 6),
Colour = OsuColour.FromHex(@"a4edff"), Colour = Color4Extensions.FromHex(@"a4edff"),
Icon = statistic.Icon, Icon = statistic.Icon,
}, },
}, },
@ -344,7 +344,7 @@ namespace osu.Game.Online.Leaderboards
Anchor = Anchor.CentreLeft, Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
TextColour = Color4.White, TextColour = Color4.White,
GlowColour = OsuColour.FromHex(@"83ccfa"), GlowColour = Color4Extensions.FromHex(@"83ccfa"),
Text = statistic.Value, Text = statistic.Value,
Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold), Font = OsuFont.GetFont(size: 17, weight: FontWeight.Bold),
}, },

View File

@ -3,6 +3,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
@ -124,7 +125,7 @@ namespace osu.Game.Overlays.BeatmapSet
Icon = FontAwesome.Solid.Square, Icon = FontAwesome.Solid.Square,
Size = new Vector2(12), Size = new Vector2(12),
Rotation = 45, Rotation = 45,
Colour = OsuColour.FromHex(@"441288"), Colour = Color4Extensions.FromHex(@"441288"),
}, },
new SpriteIcon new SpriteIcon
{ {
@ -132,7 +133,7 @@ namespace osu.Game.Overlays.BeatmapSet
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = icon, Icon = icon,
Size = new Vector2(12), Size = new Vector2(12),
Colour = OsuColour.FromHex(@"f7dd55"), Colour = Color4Extensions.FromHex(@"f7dd55"),
Scale = new Vector2(0.8f), Scale = new Vector2(0.8f),
}, },
value = new OsuSpriteText value = new OsuSpriteText

View File

@ -2,8 +2,8 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.BeatmapSet.Buttons namespace osu.Game.Overlays.BeatmapSet.Buttons
@ -19,9 +19,9 @@ namespace osu.Game.Overlays.BeatmapSet.Buttons
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
BackgroundColour = OsuColour.FromHex(@"094c5f"); BackgroundColour = Color4Extensions.FromHex(@"094c5f");
Triangles.ColourLight = OsuColour.FromHex(@"0f7c9b"); Triangles.ColourLight = Color4Extensions.FromHex(@"0f7c9b");
Triangles.ColourDark = OsuColour.FromHex(@"094c5f"); Triangles.ColourDark = Color4Extensions.FromHex(@"094c5f");
Triangles.TriangleScale = 1.5f; Triangles.TriangleScale = 1.5f;
} }
} }

View File

@ -52,22 +52,28 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
highAccuracyColour = colours.GreenLight; highAccuracyColour = colours.GreenLight;
} }
public IReadOnlyList<ScoreInfo> Scores private bool showPerformancePoints;
public void DisplayScores(IReadOnlyList<ScoreInfo> scores, bool showPerformanceColumn)
{ {
set ClearScores();
{
Content = null;
backgroundFlow.Clear();
if (value?.Any() != true) if (!scores.Any())
return; return;
for (int i = 0; i < value.Count; i++) showPerformancePoints = showPerformanceColumn;
backgroundFlow.Add(new ScoreTableRowBackground(i, value[i], row_height));
Columns = createHeaders(value[0]); for (int i = 0; i < scores.Count; i++)
Content = value.Select((s, i) => createContent(i, s)).ToArray().ToRectangular(); 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) 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.Add(new TableColumn(score.SortedStatistics.LastOrDefault().Key.GetDescription(), Anchor.CentreLeft, new Dimension(GridSizeMode.Distributed, minSize: 45, maxSize: 95)));
columns.AddRange(new[] if (showPerformancePoints)
{ columns.Add(new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)));
new TableColumn("pp", Anchor.CentreLeft, new Dimension(GridSizeMode.Absolute, 30)),
new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)), columns.Add(new TableColumn("mods", Anchor.CentreLeft, new Dimension(GridSizeMode.AutoSize)));
});
return columns.ToArray(); 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}", Text = $@"{score.PP:N0}",
Font = OsuFont.GetFont(size: text_size) 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, AutoSizeAxes = Axes.Both,
Spacing = new Vector2(1), Scale = new Vector2(0.3f)
ChildrenEnumerable = score.Mods.Select(m => new ModIcon(m) })
{
AutoSizeAxes = Axes.Both,
Scale = new Vector2(0.3f)
})
},
}); });
return content.ToArray(); return content.ToArray();

View File

@ -52,17 +52,17 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
if (value?.Scores.Any() != true) if (value?.Scores.Any() != true)
{ {
scoreTable.Scores = null; scoreTable.ClearScores();
scoreTable.Hide(); scoreTable.Hide();
return; return;
} }
var scoreInfos = value.Scores.Select(s => s.CreateScoreInfo(rulesets)).ToList(); 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(); scoreTable.Show();
var topScore = scoreInfos.First();
var userScore = value.UserScore; var userScore = value.UserScore;
var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets); var userScoreInfo = userScore?.Score.CreateScoreInfo(rulesets);

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
@ -96,6 +97,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
totalScoreColumn.Text = $@"{value.TotalScore:N0}"; totalScoreColumn.Text = $@"{value.TotalScore:N0}";
accuracyColumn.Text = value.DisplayAccuracy; accuracyColumn.Text = value.DisplayAccuracy;
maxComboColumn.Text = $@"{value.MaxCombo:N0}x"; maxComboColumn.Text = $@"{value.MaxCombo:N0}x";
ppColumn.Alpha = value.Beatmap?.Status == BeatmapSetOnlineStatus.Ranked ? 1 : 0;
ppColumn.Text = $@"{value.PP:N0}"; ppColumn.Text = $@"{value.PP:N0}";
statisticsColumns.ChildrenEnumerable = value.SortedStatistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value)); statisticsColumns.ChildrenEnumerable = value.SortedStatistics.Select(kvp => createStatisticsColumn(kvp.Key, kvp.Value));

View File

@ -123,7 +123,7 @@ namespace osu.Game.Overlays.Chat
EdgeEffect = new EdgeEffectParameters EdgeEffect = new EdgeEffectParameters
{ {
Radius = 1, Radius = 1,
Colour = OsuColour.FromHex(message.Sender.Colour), Colour = Color4Extensions.FromHex(message.Sender.Colour),
Type = EdgeEffectType.Shadow, Type = EdgeEffectType.Shadow,
}, },
Padding = new MarginPadding { Left = 3, Right = 3, Bottom = 1, Top = -3 }, 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); t.Font = OsuFont.GetFont(italics: true);
if (senderHasBackground) if (senderHasBackground)
t.Colour = OsuColour.FromHex(message.Sender.Colour); t.Colour = Color4Extensions.FromHex(message.Sender.Colour);
} }
t.Font = t.Font.With(size: TextSize); t.Font = t.Font.With(size: TextSize);
@ -249,41 +249,41 @@ namespace osu.Game.Overlays.Chat
private static readonly Color4[] username_colours = private static readonly Color4[] username_colours =
{ {
OsuColour.FromHex("588c7e"), Color4Extensions.FromHex("588c7e"),
OsuColour.FromHex("b2a367"), Color4Extensions.FromHex("b2a367"),
OsuColour.FromHex("c98f65"), Color4Extensions.FromHex("c98f65"),
OsuColour.FromHex("bc5151"), Color4Extensions.FromHex("bc5151"),
OsuColour.FromHex("5c8bd6"), Color4Extensions.FromHex("5c8bd6"),
OsuColour.FromHex("7f6ab7"), Color4Extensions.FromHex("7f6ab7"),
OsuColour.FromHex("a368ad"), Color4Extensions.FromHex("a368ad"),
OsuColour.FromHex("aa6880"), Color4Extensions.FromHex("aa6880"),
OsuColour.FromHex("6fad9b"), Color4Extensions.FromHex("6fad9b"),
OsuColour.FromHex("f2e394"), Color4Extensions.FromHex("f2e394"),
OsuColour.FromHex("f2ae72"), Color4Extensions.FromHex("f2ae72"),
OsuColour.FromHex("f98f8a"), Color4Extensions.FromHex("f98f8a"),
OsuColour.FromHex("7daef4"), Color4Extensions.FromHex("7daef4"),
OsuColour.FromHex("a691f2"), Color4Extensions.FromHex("a691f2"),
OsuColour.FromHex("c894d3"), Color4Extensions.FromHex("c894d3"),
OsuColour.FromHex("d895b0"), Color4Extensions.FromHex("d895b0"),
OsuColour.FromHex("53c4a1"), Color4Extensions.FromHex("53c4a1"),
OsuColour.FromHex("eace5c"), Color4Extensions.FromHex("eace5c"),
OsuColour.FromHex("ea8c47"), Color4Extensions.FromHex("ea8c47"),
OsuColour.FromHex("fc4f4f"), Color4Extensions.FromHex("fc4f4f"),
OsuColour.FromHex("3d94ea"), Color4Extensions.FromHex("3d94ea"),
OsuColour.FromHex("7760ea"), Color4Extensions.FromHex("7760ea"),
OsuColour.FromHex("af52c6"), Color4Extensions.FromHex("af52c6"),
OsuColour.FromHex("e25696"), Color4Extensions.FromHex("e25696"),
OsuColour.FromHex("677c66"), Color4Extensions.FromHex("677c66"),
OsuColour.FromHex("9b8732"), Color4Extensions.FromHex("9b8732"),
OsuColour.FromHex("8c5129"), Color4Extensions.FromHex("8c5129"),
OsuColour.FromHex("8c3030"), Color4Extensions.FromHex("8c3030"),
OsuColour.FromHex("1f5d91"), Color4Extensions.FromHex("1f5d91"),
OsuColour.FromHex("4335a5"), Color4Extensions.FromHex("4335a5"),
OsuColour.FromHex("812a96"), Color4Extensions.FromHex("812a96"),
OsuColour.FromHex("992861"), Color4Extensions.FromHex("992861"),
}; };
} }
} }

View File

@ -41,10 +41,10 @@ namespace osu.Game.Overlays.Chat.Selection
{ {
RelativeSizeAxes = Axes.X; RelativeSizeAxes = Axes.X;
Waves.FirstWaveColour = OsuColour.FromHex("353535"); Waves.FirstWaveColour = Color4Extensions.FromHex("353535");
Waves.SecondWaveColour = OsuColour.FromHex("434343"); Waves.SecondWaveColour = Color4Extensions.FromHex("434343");
Waves.ThirdWaveColour = OsuColour.FromHex("515151"); Waves.ThirdWaveColour = Color4Extensions.FromHex("515151");
Waves.FourthWaveColour = OsuColour.FromHex("595959"); Waves.FourthWaveColour = Color4Extensions.FromHex("595959");
Children = new Drawable[] Children = new Drawable[]
{ {
@ -154,7 +154,7 @@ namespace osu.Game.Overlays.Chat.Selection
{ {
bg.Colour = colours.Gray3; bg.Colour = colours.Gray3;
triangles.ColourDark = colours.Gray3; triangles.ColourDark = colours.Gray3;
triangles.ColourLight = OsuColour.FromHex(@"353535"); triangles.ColourLight = Color4Extensions.FromHex(@"353535");
headerBg.Colour = colours.Gray2.Opacity(0.75f); headerBg.Colour = colours.Gray2.Opacity(0.75f);
} }

View File

@ -89,7 +89,7 @@ namespace osu.Game.Overlays.Chat.Tabs
{ {
var user = Value.Users.First(); 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); BackgroundInactive = BackgroundActive.Darken(0.5f);
} }
} }

View File

@ -10,7 +10,6 @@ using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osuTK; using osuTK;
@ -114,13 +113,13 @@ namespace osu.Game.Overlays.Dialog
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"221a21"), Colour = Color4Extensions.FromHex(@"221a21"),
}, },
new Triangles new Triangles
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
ColourLight = OsuColour.FromHex(@"271e26"), ColourLight = Color4Extensions.FromHex(@"271e26"),
ColourDark = OsuColour.FromHex(@"1e171e"), ColourDark = Color4Extensions.FromHex(@"1e171e"),
TriangleScale = 4, TriangleScale = 4,
}, },
}, },

View File

@ -1,7 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays.Dialog namespace osu.Game.Overlays.Dialog
@ -11,7 +11,7 @@ namespace osu.Game.Overlays.Dialog
public PopupDialogButton() public PopupDialogButton()
{ {
Height = 50; Height = 50;
BackgroundColour = OsuColour.FromHex(@"150e14"); BackgroundColour = Color4Extensions.FromHex(@"150e14");
TextSize = 18; TextSize = 18;
} }
} }

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
@ -16,7 +17,7 @@ namespace osu.Game.Overlays.Direct
{ {
private DirectRulesetSelector rulesetSelector; 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 DirectSortCriteria DefaultTab => DirectSortCriteria.Ranked;
protected override BeatmapSearchCategory DefaultCategory => BeatmapSearchCategory.Leaderboard; protected override BeatmapSearchCategory DefaultCategory => BeatmapSearchCategory.Leaderboard;

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Extensions.Color4Extensions;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
@ -13,7 +14,7 @@ namespace osu.Game.Overlays.Direct
{ {
public class Header : SearchableListHeader<DirectTab> public class Header : SearchableListHeader<DirectTab>
{ {
protected override Color4 BackgroundColour => OsuColour.FromHex(@"252f3a"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"252f3a");
protected override DirectTab DefaultTab => DirectTab.Search; protected override DirectTab DefaultTab => DirectTab.Search;
protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", Font = OsuFont.GetFont(size: 25) }; protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", Font = OsuFont.GetFont(size: 25) };

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using Humanizer; using Humanizer;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Threading; using osu.Framework.Threading;
@ -34,9 +35,9 @@ namespace osu.Game.Overlays
private readonly OsuSpriteText resultCountsText; private readonly OsuSpriteText resultCountsText;
private FillFlowContainer<DirectPanel> panels; private FillFlowContainer<DirectPanel> panels;
protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"485e74");
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71"); protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"465b71");
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"3f5265"); protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"3f5265");
protected override SearchableListHeader<DirectTab> CreateHeader() => new Header(); protected override SearchableListHeader<DirectTab> CreateHeader() => new Header();
protected override SearchableListFilterControl<DirectSortCriteria, BeatmapSearchCategory> CreateFilterControl() => new FilterControl(); protected override SearchableListFilterControl<DirectSortCriteria, BeatmapSearchCategory> CreateFilterControl() => new FilterControl();

View File

@ -126,14 +126,14 @@ namespace osu.Game.Overlays
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"05262f"), Colour = Color4Extensions.FromHex(@"05262f"),
}, },
new Triangles new Triangles
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
TriangleScale = 2, TriangleScale = 2,
ColourDark = OsuColour.FromHex(@"04222b"), ColourDark = Color4Extensions.FromHex(@"04222b"),
ColourLight = OsuColour.FromHex(@"052933"), ColourLight = Color4Extensions.FromHex(@"052933"),
}, },
innerSpin = new Sprite innerSpin = new Sprite
{ {

View File

@ -63,10 +63,10 @@ namespace osu.Game.Overlays.Mods
public ModSelectOverlay() public ModSelectOverlay()
{ {
Waves.FirstWaveColour = OsuColour.FromHex(@"19b0e2"); Waves.FirstWaveColour = Color4Extensions.FromHex(@"19b0e2");
Waves.SecondWaveColour = OsuColour.FromHex(@"2280a2"); Waves.SecondWaveColour = Color4Extensions.FromHex(@"2280a2");
Waves.ThirdWaveColour = OsuColour.FromHex(@"005774"); Waves.ThirdWaveColour = Color4Extensions.FromHex(@"005774");
Waves.FourthWaveColour = OsuColour.FromHex(@"003a4e"); Waves.FourthWaveColour = Color4Extensions.FromHex(@"003a4e");
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -170,7 +171,7 @@ namespace osu.Game.Overlays.Profile.Header
userCountryText.Text = user?.Country?.FullName ?? "Alien"; userCountryText.Text = user?.Country?.FullName ?? "Alien";
supporterTag.SupportLevel = user?.SupportLevel ?? 0; supporterTag.SupportLevel = user?.SupportLevel ?? 0;
titleText.Text = user?.Title ?? string.Empty; titleText.Text = user?.Title ?? string.Empty;
titleText.Colour = OsuColour.FromHex(user?.Colour ?? "fff"); titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff");
userStats.Clear(); userStats.Clear();

View File

@ -7,7 +7,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Profile.Header; using osu.Game.Overlays.Profile.Header;
using osu.Game.Users; using osu.Game.Users;
@ -48,7 +47,7 @@ namespace osu.Game.Overlays.Profile
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, 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))
}, },
} }
}; };

View File

@ -1,16 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Extensions.Color4Extensions;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Overlays.SearchableList; using osu.Game.Overlays.SearchableList;
namespace osu.Game.Overlays.Social namespace osu.Game.Overlays.Social
{ {
public class FilterControl : SearchableListFilterControl<SocialSortCriteria, SortDirection> public class FilterControl : SearchableListFilterControl<SocialSortCriteria, SortDirection>
{ {
protected override Color4 BackgroundColour => OsuColour.FromHex(@"47253a"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"47253a");
protected override SocialSortCriteria DefaultTab => SocialSortCriteria.Rank; protected override SocialSortCriteria DefaultTab => SocialSortCriteria.Rank;
protected override SortDirection DefaultCategory => SortDirection.Ascending; protected override SortDirection DefaultCategory => SortDirection.Ascending;

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using System.ComponentModel; using System.ComponentModel;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
namespace osu.Game.Overlays.Social namespace osu.Game.Overlays.Social
@ -17,7 +18,7 @@ namespace osu.Game.Overlays.Social
{ {
private OsuSpriteText browser; 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 SocialTab DefaultTab => SocialTab.AllPlayers;
protected override IconUsage Icon => FontAwesome.Solid.Users; protected override IconUsage Icon => FontAwesome.Solid.Users;

View File

@ -9,7 +9,6 @@ using osuTK;
using osuTK.Graphics; using osuTK.Graphics;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API; using osu.Game.Online.API;
using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests;
@ -18,6 +17,7 @@ using osu.Game.Overlays.Social;
using osu.Game.Users; using osu.Game.Users;
using System.Threading; using System.Threading;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Threading; using osu.Framework.Threading;
namespace osu.Game.Overlays namespace osu.Game.Overlays
@ -27,9 +27,9 @@ namespace osu.Game.Overlays
private readonly LoadingSpinner loading; private readonly LoadingSpinner loading;
private FillFlowContainer<SocialPanel> panels; private FillFlowContainer<SocialPanel> panels;
protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b"); protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"60284b");
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"672b51"); protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"672b51");
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"5c2648"); protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"5c2648");
protected override SearchableListHeader<SocialTab> CreateHeader() => new Header(); protected override SearchableListHeader<SocialTab> CreateHeader() => new Header();
protected override SearchableListFilterControl<SocialSortCriteria, SortDirection> CreateFilterControl() => new FilterControl(); protected override SearchableListFilterControl<SocialSortCriteria, SortDirection> CreateFilterControl() => new FilterControl();

View File

@ -15,6 +15,8 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage? Icon => OsuIcon.ModPerfect; public override IconUsage? Icon => OsuIcon.ModPerfect;
public override string Description => "SS or quit."; 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;
} }
} }

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -26,7 +27,7 @@ namespace osu.Game.Screens.Edit.Components.Menus
MaskingContainer.CornerRadius = 0; MaskingContainer.CornerRadius = 0;
ItemsContainer.Padding = new MarginPadding { Left = 100 }; ItemsContainer.Padding = new MarginPadding { Left = 100 };
BackgroundColour = OsuColour.FromHex("111"); BackgroundColour = Color4Extensions.FromHex("111");
ScreenSelectionTabControl tabControl; ScreenSelectionTabControl tabControl;
AddRangeInternal(new Drawable[] AddRangeInternal(new Drawable[]

View File

@ -2,11 +2,11 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osuTK; using osuTK;
@ -31,7 +31,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("111") Colour = Color4Extensions.FromHex("111")
}, },
new GridContainer new GridContainer
{ {
@ -49,7 +49,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("222") Colour = Color4Extensions.FromHex("222")
}, },
new FillFlowContainer new FillFlowContainer
{ {
@ -76,7 +76,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex("333") Colour = Color4Extensions.FromHex("333")
}, },
new Container<TimelineButton> new Container<TimelineButton>
{ {

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Framework.Utils;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Online.API; using osu.Game.Online.API;
@ -33,6 +34,7 @@ namespace osu.Game.Screens.Menu
private readonly OsuScreen nextScreen; private readonly OsuScreen nextScreen;
private readonly Bindable<User> currentUser = new Bindable<User>(); private readonly Bindable<User> currentUser = new Bindable<User>();
private FillFlowContainer fill;
public Disclaimer(OsuScreen nextScreen = null) public Disclaimer(OsuScreen nextScreen = null)
{ {
@ -49,16 +51,16 @@ namespace osu.Game.Screens.Menu
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
Icon = FontAwesome.Solid.ExclamationTriangle, Icon = FontAwesome.Solid.Poo,
Size = new Vector2(icon_size), Size = new Vector2(icon_size),
Y = icon_y, Y = icon_y,
}, },
new FillFlowContainer fill = new FillFlowContainer
{ {
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Y = icon_y + icon_size, Y = icon_y,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Children = new Drawable[] Children = new Drawable[]
@ -71,6 +73,8 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.TopCentre, Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Spacing = new Vector2(0, 2), Spacing = new Vector2(0, 2),
LayoutDuration = 2000,
LayoutEasing = Easing.OutQuint
}, },
supportFlow = new LinkFlowContainer 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("This project is an ongoing ", 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("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(); textFlow.NewParagraph();
static void format(SpriteText t) => t.Font = OsuFont.GetFont(size: 15, weight: FontWeight.SemiBold); 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.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(); textFlow.NewParagraph();
iconColour = colours.Yellow; iconColour = colours.Yellow;
@ -114,7 +111,7 @@ namespace osu.Game.Screens.Menu
if (e.NewValue.IsSupporter) if (e.NewValue.IsSupporter)
{ {
supportFlow.AddText("Thank you for supporting osu!", format); supportFlow.AddText("Eternal thanks to you for supporting osu!", format);
} }
else else
{ {
@ -125,7 +122,7 @@ namespace osu.Game.Screens.Menu
heart = supportFlow.AddIcon(FontAwesome.Solid.Heart, t => 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.Font = t.Font.With(size: 12);
t.Origin = Anchor.Centre; t.Origin = Anchor.Centre;
t.Colour = colours.Pink; t.Colour = colours.Pink;
@ -139,11 +136,6 @@ namespace osu.Game.Screens.Menu
}, true); }, true);
} }
private void animateHeart()
{
heart.FlashColour(Color4.White, 750, Easing.OutQuint).Loop();
}
protected override void LoadComplete() protected override void LoadComplete()
{ {
base.LoadComplete(); base.LoadComplete();
@ -155,15 +147,28 @@ namespace osu.Game.Screens.Menu
{ {
base.OnEntering(last); base.OnEntering(last);
icon.Delay(1000).FadeColour(iconColour, 200, Easing.OutQuint); icon.RotateTo(10);
icon.Delay(1000) icon.FadeOut();
.MoveToY(icon_y * 1.1f, 160, Easing.OutCirc) icon.ScaleTo(0.5f);
.RotateTo(-10, 160, Easing.OutCirc)
.Then() icon.Delay(500).FadeIn(500).ScaleTo(1, 500, Easing.OutQuint);
.MoveToY(icon_y, 160, Easing.InCirc)
.RotateTo(0, 160, Easing.InCirc); 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); 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(); animateHeart();
@ -178,5 +183,35 @@ namespace osu.Game.Screens.Menu
this.Push(nextScreen); 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();
}
} }
} }

View File

@ -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), mediumRing = new Ring(Color4.White.Opacity(130), 0.7f),
smallRing = new Ring(Color4.White, 0.6f), smallRing = new Ring(Color4.White, 0.6f),
welcomeText = new OsuSpriteText welcomeText = new OsuSpriteText
@ -121,7 +121,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Height = 0, Height = 0,
Colour = OsuColour.FromHex(@"C6D8FF").Opacity(160), Colour = Color4Extensions.FromHex(@"C6D8FF").Opacity(160),
}, },
foregroundFill = new Box foregroundFill = new Box
{ {
@ -139,28 +139,28 @@ namespace osu.Game.Screens.Menu
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.TopCentre, Origin = Anchor.TopCentre,
Position = new Vector2(0, circle_offset), Position = new Vector2(0, circle_offset),
Colour = OsuColour.FromHex(@"AA92FF"), Colour = Color4Extensions.FromHex(@"AA92FF"),
}, },
blueCircle = new Circle blueCircle = new Circle
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.CentreRight, Origin = Anchor.CentreRight,
Position = new Vector2(-circle_offset, 0), Position = new Vector2(-circle_offset, 0),
Colour = OsuColour.FromHex(@"8FE5FE"), Colour = Color4Extensions.FromHex(@"8FE5FE"),
}, },
yellowCircle = new Circle yellowCircle = new Circle
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.BottomCentre, Origin = Anchor.BottomCentre,
Position = new Vector2(0, -circle_offset), Position = new Vector2(0, -circle_offset),
Colour = OsuColour.FromHex(@"FFD64C"), Colour = Color4Extensions.FromHex(@"FFD64C"),
}, },
pinkCircle = new Circle pinkCircle = new Circle
{ {
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.CentreLeft, Origin = Anchor.CentreLeft,
Position = new Vector2(circle_offset, 0), Position = new Vector2(circle_offset, 0),
Colour = OsuColour.FromHex(@"e967a1"), Colour = Color4Extensions.FromHex(@"e967a1"),
}, },
}; };

View File

@ -6,6 +6,7 @@ using osu.Framework.Allocation;
using osu.Framework.Audio; using osu.Framework.Audio;
using osu.Framework.Audio.Sample; using osu.Framework.Audio.Sample;
using osu.Framework.Audio.Track; using osu.Framework.Audio.Track;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -14,7 +15,6 @@ using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events; using osu.Framework.Input.Events;
using osu.Framework.Utils; using osu.Framework.Utils;
using osu.Game.Beatmaps.ControlPoints; using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds; using osu.Game.Graphics.Backgrounds;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osuTK; using osuTK;
@ -28,7 +28,7 @@ namespace osu.Game.Screens.Menu
/// </summary> /// </summary>
public class OsuLogo : BeatSyncedContainer public class OsuLogo : BeatSyncedContainer
{ {
public readonly Color4 OsuPink = OsuColour.FromHex(@"e967a1"); public readonly Color4 OsuPink = Color4Extensions.FromHex(@"e967a1");
private const double transition_length = 300; private const double transition_length = 300;
@ -176,8 +176,8 @@ namespace osu.Game.Screens.Menu
triangles = new Triangles triangles = new Triangles
{ {
TriangleScale = 4, TriangleScale = 4,
ColourLight = OsuColour.FromHex(@"ff7db7"), ColourLight = Color4Extensions.FromHex(@"ff7db7"),
ColourDark = OsuColour.FromHex(@"de5b95"), ColourDark = Color4Extensions.FromHex(@"de5b95"),
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
}, },
} }

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
@ -27,7 +28,7 @@ namespace osu.Game.Screens.Multi.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"545454"), Colour = Color4Extensions.FromHex(@"545454"),
}, },
}; };
} }

View File

@ -2,12 +2,12 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor; using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics;
using osu.Game.Users; using osu.Game.Users;
using osu.Game.Users.Drawables; using osu.Game.Users.Drawables;
using osuTK; using osuTK;
@ -114,7 +114,7 @@ namespace osu.Game.Screens.Multi.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"27252d"), Colour = Color4Extensions.FromHex(@"27252d"),
}, },
avatar = new UpdateableAvatar { RelativeSizeAxes = Axes.Both }, avatar = new UpdateableAvatar { RelativeSizeAxes = Axes.Both },
}; };

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -30,7 +31,7 @@ namespace osu.Game.Screens.Multi
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"2f2043"), Colour = Color4Extensions.FromHex(@"2f2043"),
}, },
new Container new Container
{ {

View File

@ -134,7 +134,7 @@ namespace osu.Game.Screens.Multi.Lounge.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"212121"), Colour = Color4Extensions.FromHex(@"212121"),
}, },
new StatusColouredContainer(transition_duration) new StatusColouredContainer(transition_duration)
{ {

View File

@ -4,6 +4,7 @@
using System; using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
@ -44,7 +45,7 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(OsuColour colours) private void load(OsuColour colours)
{ {
background.Colour = OsuColour.FromHex(@"28242d"); background.Colour = Color4Extensions.FromHex(@"28242d");
} }
} }
} }

View File

@ -91,7 +91,7 @@ namespace osu.Game.Screens.Multi.Match.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"28242d"), Colour = Color4Extensions.FromHex(@"28242d"),
}, },
new GridContainer new GridContainer
{ {
@ -270,7 +270,7 @@ namespace osu.Game.Screens.Multi.Match.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"28242d").Darken(0.5f).Opacity(1f), Colour = Color4Extensions.FromHex(@"28242d").Darken(0.5f).Opacity(1f),
}, },
new FillFlowContainer new FillFlowContainer
{ {

View File

@ -2,7 +2,7 @@
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Game.Graphics; using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Multi.Match.Components namespace osu.Game.Screens.Multi.Match.Components
@ -12,9 +12,9 @@ namespace osu.Game.Screens.Multi.Match.Components
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
{ {
BackgroundColour = OsuColour.FromHex(@"593790"); BackgroundColour = Color4Extensions.FromHex(@"593790");
Triangles.ColourLight = OsuColour.FromHex(@"7247b6"); Triangles.ColourLight = Color4Extensions.FromHex(@"7247b6");
Triangles.ColourDark = OsuColour.FromHex(@"593790"); Triangles.ColourDark = Color4Extensions.FromHex(@"593790");
} }
} }
} }

View File

@ -3,6 +3,7 @@
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions; using osu.Framework.Extensions;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface; using osu.Framework.Graphics.UserInterface;
@ -52,7 +53,7 @@ namespace osu.Game.Screens.Multi.Match.Components
new Box new Box
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"3d3943"), Colour = Color4Extensions.FromHex(@"3d3943"),
}, },
selection = new Box selection = new Box
{ {

View File

@ -13,7 +13,6 @@ using osu.Framework.Logging;
using osu.Framework.Screens; using osu.Framework.Screens;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Drawables; using osu.Game.Beatmaps.Drawables;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers; using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Input; using osu.Game.Input;
@ -75,7 +74,7 @@ namespace osu.Game.Screens.Multi
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING }; Padding = new MarginPadding { Horizontal = -HORIZONTAL_OVERFLOW_PADDING };
var backgroundColour = OsuColour.FromHex(@"3e3a44"); var backgroundColour = Color4Extensions.FromHex(@"3e3a44");
InternalChild = waves = new MultiplayerWaveContainer InternalChild = waves = new MultiplayerWaveContainer
{ {
@ -386,10 +385,10 @@ namespace osu.Game.Screens.Multi
public MultiplayerWaveContainer() public MultiplayerWaveContainer()
{ {
FirstWaveColour = OsuColour.FromHex(@"654d8c"); FirstWaveColour = Color4Extensions.FromHex(@"654d8c");
SecondWaveColour = OsuColour.FromHex(@"554075"); SecondWaveColour = Color4Extensions.FromHex(@"554075");
ThirdWaveColour = OsuColour.FromHex(@"44325e"); ThirdWaveColour = Color4Extensions.FromHex(@"44325e");
FourthWaveColour = OsuColour.FromHex(@"392850"); FourthWaveColour = Color4Extensions.FromHex(@"392850");
} }
} }

View File

@ -189,7 +189,7 @@ namespace osu.Game.Screens.Select
root.AddChild(newSet); root.AddChild(newSet);
applyActiveCriteria(false, false); applyActiveCriteria(false);
//check if we can/need to maintain our current selection. //check if we can/need to maintain our current selection.
if (previouslySelectedID != null) if (previouslySelectedID != null)
@ -239,7 +239,7 @@ namespace osu.Game.Screens.Select
{ {
Debug.Assert(bypassFilters); Debug.Assert(bypassFilters);
applyActiveCriteria(false, true); applyActiveCriteria(false);
} }
return true; return true;
@ -396,7 +396,7 @@ namespace osu.Game.Screens.Select
{ {
if (PendingFilter?.Completed == false) if (PendingFilter?.Completed == false)
{ {
applyActiveCriteria(false, false); applyActiveCriteria(false);
Update(); Update();
} }
} }
@ -406,10 +406,10 @@ namespace osu.Game.Screens.Select
if (newCriteria != null) if (newCriteria != null)
activeCriteria = newCriteria; 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; if (root.Children.Any() != true) return;
@ -419,7 +419,7 @@ namespace osu.Game.Screens.Select
root.Filter(activeCriteria); root.Filter(activeCriteria);
itemsCache.Invalidate(); itemsCache.Invalidate();
if (scroll) scrollPositionCache.Invalidate(); scrollPositionCache.Invalidate();
} }
PendingFilter?.Cancel(); PendingFilter?.Cancel();

View File

@ -384,7 +384,7 @@ namespace osu.Game.Screens.Select
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Colour = OsuColour.FromHex(@"441288"), Colour = Color4Extensions.FromHex(@"441288"),
Icon = FontAwesome.Solid.Square, Icon = FontAwesome.Solid.Square,
Rotation = 45, Rotation = 45,
}, },
@ -394,7 +394,7 @@ namespace osu.Game.Screens.Select
Origin = Anchor.Centre, Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Scale = new Vector2(0.8f), Scale = new Vector2(0.8f),
Colour = OsuColour.FromHex(@"f7dd55"), Colour = Color4Extensions.FromHex(@"f7dd55"),
Icon = statistic.Icon, Icon = statistic.Icon,
}, },
} }

View File

@ -25,6 +25,13 @@ namespace osu.Game.Screens.Select.Carousel
{ {
base.Filter(criteria); base.Filter(criteria);
if (Beatmap.BeatmapSet?.Equals(criteria.SelectedBeatmapSet) == true)
{
// bypass filtering for selected beatmap
Filtered.Value = false;
return;
}
bool match = bool match =
criteria.Ruleset == null || criteria.Ruleset == null ||
Beatmap.RulesetID == criteria.Ruleset.ID || Beatmap.RulesetID == criteria.Ruleset.ID ||

View File

@ -16,7 +16,7 @@ namespace osu.Game.Screens.Select.Carousel
/// <summary> /// <summary>
/// This item is not in a hidden state. /// This item is not in a hidden state.
/// </summary> /// </summary>
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<DrawableCarouselItem> Drawables public virtual List<DrawableCarouselItem> Drawables
{ {

View File

@ -4,6 +4,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
@ -69,8 +70,8 @@ namespace osu.Game.Screens.Select.Carousel
{ {
TriangleScale = 2, TriangleScale = 2,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
ColourLight = OsuColour.FromHex(@"3a7285"), ColourLight = Color4Extensions.FromHex(@"3a7285"),
ColourDark = OsuColour.FromHex(@"123744") ColourDark = Color4Extensions.FromHex(@"123744")
}, },
new FillFlowContainer new FillFlowContainer
{ {

View File

@ -15,6 +15,8 @@ namespace osu.Game.Screens.Select
public GroupMode Group; public GroupMode Group;
public SortMode Sort; public SortMode Sort;
public BeatmapSetInfo SelectedBeatmapSet;
public OptionalRange<double> StarDifficulty; public OptionalRange<double> StarDifficulty;
public OptionalRange<float> ApproachRate; public OptionalRange<float> ApproachRate;
public OptionalRange<float> DrainRate; public OptionalRange<float> DrainRate;

View File

@ -392,7 +392,12 @@ namespace osu.Game.Screens.Select
} }
// Even if a ruleset mismatch was not the cause (ie. a text filter is applied), // 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); Carousel.SelectBeatmap(e.NewValue.BeatmapInfo);
} }
} }

View File

@ -0,0 +1,67 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.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;
}
}
}
}

View File

@ -57,9 +57,11 @@ namespace osu.Game.Tests.Visual
SelectedMods.Value = mods; SelectedMods.Value = mods;
return new ModTestPlayer(AllowFail); return CreateModPlayer(ruleset);
} }
protected virtual TestPlayer CreateModPlayer(Ruleset ruleset) => new ModTestPlayer(AllowFail);
protected class ModTestPlayer : TestPlayer protected class ModTestPlayer : TestPlayer
{ {
protected override bool AllowFail { get; } protected override bool AllowFail { get; }

View File

@ -66,6 +66,7 @@ namespace osu.Game.Tests.Visual
var beatmap = CreateBeatmap(ruleset.RulesetInfo); var beatmap = CreateBeatmap(ruleset.RulesetInfo);
Beatmap.Value = CreateWorkingBeatmap(beatmap); Beatmap.Value = CreateWorkingBeatmap(beatmap);
Ruleset.Value = ruleset.RulesetInfo;
SelectedMods.Value = Array.Empty<Mod>(); SelectedMods.Value = Array.Empty<Mod>();