diff --git a/global.json b/global.json
index 9aa5b6192b..233a040d18 100644
--- a/global.json
+++ b/global.json
@@ -5,6 +5,6 @@
"version": "3.1.100"
},
"msbuild-sdks": {
- "Microsoft.Build.Traversal": "2.0.50"
+ "Microsoft.Build.Traversal": "2.0.52"
}
}
\ No newline at end of file
diff --git a/osu.Android.props b/osu.Android.props
index 71d4e5aacf..e5b0245dd0 100644
--- a/osu.Android.props
+++ b/osu.Android.props
@@ -52,6 +52,6 @@
-
+
diff --git a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
index 3e06e78dba..c1b7214d72 100644
--- a/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
+++ b/osu.Game.Rulesets.Catch.Tests/Mods/TestSceneCatchModPerfect.cs
@@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Catch.Tests.Mods
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)]
+ [TestCase(false)]
public void TestTinyDroplet(bool shouldMiss) => CreateHitObjectTest(new HitObjectTestData(new TinyDroplet { StartTime = 1000 }), shouldMiss);
}
}
diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
index e3391c47f1..fb92399102 100644
--- a/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
+++ b/osu.Game.Rulesets.Catch/Mods/CatchModPerfect.cs
@@ -1,17 +1,11 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Rulesets.Catch.Judgements;
-using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mods;
-using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Catch.Mods
{
public class CatchModPerfect : ModPerfect
{
- protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
- => !(result.Judgement is CatchBananaJudgement)
- && base.FailCondition(healthProcessor, result);
}
}
diff --git a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
index f122588a2b..99d899db80 100644
--- a/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Catch/Replays/CatchFramedReplayInputHandler.cs
@@ -35,18 +35,15 @@ namespace osu.Game.Rulesets.Catch.Replays
}
}
- public override List GetPendingInputs()
+ public override void CollectPendingInputs(List inputs)
{
- if (!Position.HasValue) return new List();
+ if (!Position.HasValue) return;
- return new List
+ inputs.Add(new CatchReplayState
{
- new CatchReplayState
- {
- PressedActions = CurrentFrame?.Actions ?? new List(),
- CatcherX = Position.Value
- },
- };
+ PressedActions = CurrentFrame?.Actions ?? new List(),
+ CatcherX = Position.Value
+ });
}
public class CatchReplayState : ReplayState
diff --git a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs
index 0d13b85901..95072cf4f8 100644
--- a/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs
+++ b/osu.Game.Rulesets.Mania.Tests/TestSceneHoldNoteInput.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using System.Linq;
using NUnit.Framework;
using osu.Framework.Screens;
using osu.Game.Beatmaps;
@@ -10,6 +11,8 @@ using osu.Game.Replays;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Replays;
+using osu.Game.Rulesets.Mania.Scoring;
+using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Replays;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
@@ -236,6 +239,53 @@ namespace osu.Game.Rulesets.Mania.Tests
assertTailJudgement(HitResult.Meh);
}
+ [Test]
+ public void TestMissReleaseAndHitSecondRelease()
+ {
+ var windows = new ManiaHitWindows();
+ windows.SetDifficulty(10);
+
+ var beatmap = new Beatmap
+ {
+ HitObjects =
+ {
+ new HoldNote
+ {
+ StartTime = 1000,
+ Duration = 500,
+ Column = 0,
+ },
+ new HoldNote
+ {
+ StartTime = 1000 + 500 + windows.WindowFor(HitResult.Miss) + 10,
+ Duration = 500,
+ Column = 0,
+ },
+ },
+ BeatmapInfo =
+ {
+ BaseDifficulty = new BeatmapDifficulty
+ {
+ SliderTickRate = 4,
+ OverallDifficulty = 10,
+ },
+ Ruleset = new ManiaRuleset().RulesetInfo
+ },
+ };
+
+ performTest(new List
+ {
+ new ManiaReplayFrame(beatmap.HitObjects[1].StartTime, ManiaAction.Key1),
+ new ManiaReplayFrame(beatmap.HitObjects[1].GetEndTime()),
+ }, beatmap);
+
+ AddAssert("first hold note missed", () => judgementResults.Where(j => beatmap.HitObjects[0].NestedHitObjects.Contains(j.HitObject))
+ .All(j => j.Type == HitResult.Miss));
+
+ AddAssert("second hold note missed", () => judgementResults.Where(j => beatmap.HitObjects[1].NestedHitObjects.Contains(j.HitObject))
+ .All(j => j.Type == HitResult.Perfect));
+ }
+
private void assertHeadJudgement(HitResult result)
=> AddAssert($"head judged as {result}", () => judgementResults[0].Type == result);
@@ -250,11 +300,11 @@ namespace osu.Game.Rulesets.Mania.Tests
private ScoreAccessibleReplayPlayer currentPlayer;
- private void performTest(List frames)
+ private void performTest(List frames, Beatmap beatmap = null)
{
- AddStep("load player", () =>
+ if (beatmap == null)
{
- Beatmap.Value = CreateWorkingBeatmap(new Beatmap
+ beatmap = new Beatmap
{
HitObjects =
{
@@ -270,9 +320,14 @@ namespace osu.Game.Rulesets.Mania.Tests
BaseDifficulty = new BeatmapDifficulty { SliderTickRate = 4 },
Ruleset = new ManiaRuleset().RulesetInfo
},
- });
+ };
- Beatmap.Value.Beatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = 0.1f });
+ beatmap.ControlPointInfo.Add(0, new DifficultyControlPoint { SpeedMultiplier = 0.1f });
+ }
+
+ AddStep("load player", () =>
+ {
+ Beatmap.Value = CreateWorkingBeatmap(beatmap);
var p = new ScoreAccessibleReplayPlayer(new Score { Replay = new Replay { Frames = frames } });
diff --git a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
index 2262bd2b7d..0c5289efe1 100644
--- a/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
+++ b/osu.Game.Rulesets.Mania/Objects/Drawables/DrawableHoldNote.cs
@@ -167,6 +167,12 @@ namespace osu.Game.Rulesets.Mania.Objects.Drawables
if (action != Action.Value)
return false;
+ // The tail has a lenience applied to it which is factored into the miss window (i.e. the miss judgement will be delayed).
+ // But the hold cannot ever be started within the late-lenience window, so we should skip trying to begin the hold during that time.
+ // Note: Unlike below, we use the tail's start time to determine the time offset.
+ if (Time.Current > Tail.HitObject.StartTime && !Tail.HitObject.HitWindows.CanBeHit(Time.Current - Tail.HitObject.StartTime))
+ return false;
+
beginHoldAt(Time.Current - Head.HitObject.StartTime);
Head.UpdateResult();
diff --git a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
index 899718b77e..aa0c148caf 100644
--- a/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Mania/Replays/ManiaFramedReplayInputHandler.cs
@@ -18,6 +18,9 @@ namespace osu.Game.Rulesets.Mania.Replays
protected override bool IsImportant(ManiaReplayFrame frame) => frame.Actions.Any();
- public override List GetPendingInputs() => new List { new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() } };
+ public override void CollectPendingInputs(List inputs)
+ {
+ inputs.Add(new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() });
+ }
}
}
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs
index c3b4d2625e..854626d362 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneOutOfOrderHits.cs
@@ -223,7 +223,7 @@ namespace osu.Game.Rulesets.Osu.Tests
const double time_slider = 1500;
const double time_circle = 1510;
Vector2 positionCircle = Vector2.Zero;
- Vector2 positionSlider = new Vector2(80);
+ Vector2 positionSlider = new Vector2(30);
var hitObjects = new List
{
diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
index 8cb7f3f4b6..67afc45e32 100644
--- a/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
+++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSpinner.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Osu.Tests
private void testSingle(float circleSize, bool auto = false)
{
- var spinner = new Spinner { StartTime = Time.Current + 1000, EndTime = Time.Current + 4000 };
+ var spinner = new Spinner { StartTime = Time.Current + 2000, EndTime = Time.Current + 5000 };
spinner.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty { CircleSize = circleSize });
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
index 72502c02cd..07f40f763b 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSlider.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using osuTK;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
@@ -11,6 +12,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Skinning;
+using osu.Game.Rulesets.Osu.UI;
using osu.Game.Rulesets.Scoring;
using osuTK.Graphics;
using osu.Game.Skinning;
@@ -81,6 +83,42 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
foreach (var drawableHitObject in NestedHitObjects)
drawableHitObject.AccentColour.Value = colour.NewValue;
}, true);
+
+ Tracking.BindValueChanged(updateSlidingSample);
+ }
+
+ private SkinnableSound slidingSample;
+
+ protected override void LoadSamples()
+ {
+ base.LoadSamples();
+
+ slidingSample?.Expire();
+ slidingSample = null;
+
+ var firstSample = HitObject.Samples.FirstOrDefault();
+
+ if (firstSample != null)
+ {
+ var clone = HitObject.SampleControlPoint.ApplyTo(firstSample);
+ clone.Name = "sliderslide";
+
+ AddInternal(slidingSample = new SkinnableSound(clone)
+ {
+ Looping = true
+ });
+ }
+ }
+
+ private void updateSlidingSample(ValueChangedEvent tracking)
+ {
+ // note that samples will not start playing if exiting a seek operation in the middle of a slider.
+ // may be something we want to address at a later point, but not so easy to make happen right now
+ // (SkinnableSound would need to expose whether the sample is already playing and this logic would need to run in Update).
+ if (tracking.NewValue && ShouldPlaySamples)
+ slidingSample?.Play();
+ else
+ slidingSample?.Stop();
}
protected override void AddNestedHitObject(DrawableHitObject hitObject)
@@ -156,6 +194,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Tracking.Value = Ball.Tracking;
+ if (Tracking.Value && slidingSample != null)
+ // keep the sliding sample playing at the current tracking position
+ slidingSample.Balance.Value = CalculateSamplePlaybackBalance(Ball.X / OsuPlayfield.BASE_SIZE.X);
+
double completionProgress = Math.Clamp((Time.Current - slider.StartTime) / slider.Duration, 0, 1);
Ball.UpdateProgress(completionProgress);
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs
index 720ffcd51c..d79ecb7b4e 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSliderRepeat.cs
@@ -23,6 +23,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private readonly Drawable scaleContainer;
+ public override bool DisplayResult => false;
+
public DrawableSliderRepeat(SliderRepeat sliderRepeat, DrawableSlider drawableSlider)
: base(sliderRepeat)
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
index be6766509c..9c4608cbb1 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/DrawableSpinner.cs
@@ -93,7 +93,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Background = new SpinnerBackground
{
- Alpha = 0.6f,
+ Disc =
+ {
+ Alpha = 0f,
+ },
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
},
@@ -125,10 +128,10 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
private void load(OsuColour colours)
{
normalColour = baseColour;
+ completeColour = colours.YellowLight;
Background.AccentColour = normalColour;
-
- completeColour = colours.YellowLight.Opacity(0.75f);
+ Ticks.AccentColour = normalColour;
Disc.AccentColour = fillColour;
circle.Colour = colours.BlueDark;
@@ -147,16 +150,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (Progress >= 1 && !Disc.Complete)
{
Disc.Complete = true;
-
- const float duration = 200;
-
- Disc.FadeAccent(completeColour, duration);
-
- Background.FadeAccent(completeColour, duration);
- Background.FadeOut(duration);
-
- circle.FadeColour(completeColour, duration);
- glow.FadeColour(completeColour, duration);
+ transformFillColour(completeColour, 200);
}
if (userTriggered || Time.Current < Spinner.EndTime)
@@ -204,32 +198,59 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
base.UpdateInitialTransforms();
- circleContainer.ScaleTo(Spinner.Scale * 0.3f);
- circleContainer.ScaleTo(Spinner.Scale, HitObject.TimePreempt / 1.4f, Easing.OutQuint);
+ circleContainer.ScaleTo(0);
+ mainContainer.ScaleTo(0);
- mainContainer
- .ScaleTo(0)
- .ScaleTo(Spinner.Scale * circle.DrawHeight / DrawHeight * 1.4f, HitObject.TimePreempt - 150, Easing.OutQuint)
- .Then()
- .ScaleTo(1, 500, Easing.OutQuint);
+ using (BeginDelayedSequence(HitObject.TimePreempt / 2, true))
+ {
+ float phaseOneScale = Spinner.Scale * 0.7f;
+
+ circleContainer.ScaleTo(phaseOneScale, HitObject.TimePreempt / 4, Easing.OutQuint);
+
+ mainContainer
+ .ScaleTo(phaseOneScale * circle.DrawHeight / DrawHeight * 1.6f, HitObject.TimePreempt / 4, Easing.OutQuint)
+ .RotateTo((float)(25 * Spinner.Duration / 2000), HitObject.TimePreempt + Spinner.Duration);
+
+ using (BeginDelayedSequence(HitObject.TimePreempt / 2, true))
+ {
+ circleContainer.ScaleTo(Spinner.Scale, 400, Easing.OutQuint);
+ mainContainer.ScaleTo(1, 400, Easing.OutQuint);
+ }
+ }
}
protected override void UpdateStateTransforms(ArmedState state)
{
base.UpdateStateTransforms(state);
- var sequence = this.Delay(Spinner.Duration).FadeOut(160);
-
- switch (state)
+ using (BeginDelayedSequence(Spinner.Duration, true))
{
- case ArmedState.Hit:
- sequence.ScaleTo(Scale * 1.2f, 320, Easing.Out);
- break;
+ this.FadeOut(160);
- case ArmedState.Miss:
- sequence.ScaleTo(Scale * 0.8f, 320, Easing.In);
- break;
+ switch (state)
+ {
+ case ArmedState.Hit:
+ transformFillColour(completeColour, 0);
+ this.ScaleTo(Scale * 1.2f, 320, Easing.Out);
+ mainContainer.RotateTo(mainContainer.Rotation + 180, 320);
+ break;
+
+ case ArmedState.Miss:
+ this.ScaleTo(Scale * 0.8f, 320, Easing.In);
+ break;
+ }
}
}
+
+ private void transformFillColour(Colour4 colour, double duration)
+ {
+ Disc.FadeAccent(colour, duration);
+
+ Background.FadeAccent(colour.Darken(1), duration);
+ Ticks.FadeAccent(colour, duration);
+
+ circle.FadeColour(colour, duration);
+ glow.FadeColour(colour, duration);
+ }
}
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
index 395c76a233..07dc6021c9 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SliderBall.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
private readonly Slider slider;
private readonly Drawable followCircle;
private readonly DrawableSlider drawableSlider;
- private readonly CircularContainer ball;
+ private readonly Drawable ball;
public SliderBall(Slider slider, DrawableSlider drawableSlider = null)
{
@@ -54,19 +54,11 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Alpha = 0,
Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderFollowCircle), _ => new DefaultFollowCircle()),
},
- ball = new CircularContainer
+ ball = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall())
{
- Masking = true,
- RelativeSizeAxes = Axes.Both,
- Origin = Anchor.Centre,
Anchor = Anchor.Centre,
- Alpha = 1,
- Child = new Container
- {
- RelativeSizeAxes = Axes.Both,
- Child = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBall), _ => new DefaultSliderBall()),
- }
- }
+ Origin = Anchor.Centre,
+ },
};
}
@@ -187,12 +179,12 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
return;
Position = newPos;
- Rotation = -90 + (float)(-Math.Atan2(diff.X, diff.Y) * 180 / Math.PI);
+ ball.Rotation = -90 + (float)(-Math.Atan2(diff.X, diff.Y) * 180 / Math.PI);
lastPosition = newPos;
}
- private class FollowCircleContainer : Container
+ private class FollowCircleContainer : CircularContainer
{
public override bool HandlePositionalInput => true;
}
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs
index 77228e28af..944354abca 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerBackground.cs
@@ -1,18 +1,18 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osuTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
+using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
public class SpinnerBackground : CircularContainer, IHasAccentColour
{
- protected Box Disc;
+ public readonly Box Disc;
public Color4 AccentColour
{
diff --git a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs
index 676cefb236..ba7e8eae6f 100644
--- a/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs
+++ b/osu.Game.Rulesets.Osu/Objects/Drawables/Pieces/SpinnerTicks.cs
@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
+using System.Linq;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
@@ -9,10 +10,11 @@ using osu.Framework.Graphics.Effects;
using osuTK;
using osuTK.Graphics;
using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
{
- public class SpinnerTicks : Container
+ public class SpinnerTicks : Container, IHasAccentColour
{
public SpinnerTicks()
{
@@ -20,28 +22,22 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
Anchor = Anchor.Centre;
RelativeSizeAxes = Axes.Both;
- const float count = 18;
+ const float count = 8;
for (float i = 0; i < count; i++)
{
Add(new Container
{
- Colour = Color4.Black,
Alpha = 0.4f,
- EdgeEffect = new EdgeEffectParameters
- {
- Type = EdgeEffectType.Glow,
- Radius = 10,
- Colour = Color4.Gray.Opacity(0.2f),
- },
+ Blending = BlendingParameters.Additive,
RelativePositionAxes = Axes.Both,
Masking = true,
CornerRadius = 5,
Size = new Vector2(60, 10),
Origin = Anchor.Centre,
Position = new Vector2(
- 0.5f + MathF.Sin(i / count * 2 * MathF.PI) / 2 * 0.86f,
- 0.5f + MathF.Cos(i / count * 2 * MathF.PI) / 2 * 0.86f
+ 0.5f + MathF.Sin(i / count * 2 * MathF.PI) / 2 * 0.83f,
+ 0.5f + MathF.Cos(i / count * 2 * MathF.PI) / 2 * 0.83f
),
Rotation = -i / count * 360 + 90,
Children = new[]
@@ -54,5 +50,25 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Pieces
});
}
}
+
+ public Color4 AccentColour
+ {
+ get => Colour;
+ set
+ {
+ Colour = value;
+
+ foreach (var c in Children.OfType())
+ {
+ c.EdgeEffect =
+ new EdgeEffectParameters
+ {
+ Type = EdgeEffectType.Glow,
+ Radius = 20,
+ Colour = value.Opacity(0.8f),
+ };
+ }
+ }
+ }
}
}
diff --git a/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs b/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs
index b42e9ac187..cf48dc053f 100644
--- a/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Osu/Replays/OsuFramedReplayInputHandler.cs
@@ -36,19 +36,10 @@ namespace osu.Game.Rulesets.Osu.Replays
}
}
- public override List GetPendingInputs()
+ public override void CollectPendingInputs(List inputs)
{
- return new List
- {
- new MousePositionAbsoluteInput
- {
- Position = GamefieldToScreenSpace(Position ?? Vector2.Zero)
- },
- new ReplayState
- {
- PressedActions = CurrentFrame?.Actions ?? new List()
- }
- };
+ inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(Position ?? Vector2.Zero) });
+ inputs.Add(new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() });
}
}
}
diff --git a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs b/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs
index b4ed75d97c..0f586034d5 100644
--- a/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs
+++ b/osu.Game.Rulesets.Osu/Skinning/LegacySliderBall.cs
@@ -15,6 +15,9 @@ namespace osu.Game.Rulesets.Osu.Skinning
{
private readonly Drawable animationContent;
+ private Sprite layerNd;
+ private Sprite layerSpec;
+
public LegacySliderBall(Drawable animationContent)
{
this.animationContent = animationContent;
@@ -29,18 +32,37 @@ namespace osu.Game.Rulesets.Osu.Skinning
InternalChildren = new[]
{
- new Sprite
+ layerNd = new Sprite
{
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
Texture = skin.GetTexture("sliderb-nd"),
Colour = new Color4(5, 5, 5, 255),
},
- animationContent,
- new Sprite
+ animationContent.With(d =>
{
+ d.Anchor = Anchor.Centre;
+ d.Origin = Anchor.Centre;
+ }),
+ layerSpec = new Sprite
+ {
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
Texture = skin.GetTexture("sliderb-spec"),
Blending = BlendingParameters.Additive,
},
};
}
+
+ protected override void UpdateAfterChildren()
+ {
+ base.UpdateAfterChildren();
+
+ //undo rotation on layers which should not be rotated.
+ float appliedRotation = Parent.Rotation;
+
+ layerNd.Rotation = -appliedRotation;
+ layerSpec.Rotation = -appliedRotation;
+ }
}
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs
index d200c44a02..cb6a0decde 100644
--- a/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/Skinning/TestSceneDrawableTaikoMascot.cs
@@ -111,7 +111,7 @@ namespace osu.Game.Rulesets.Taiko.Tests.Skinning
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Miss }, TaikoMascotAnimationState.Fail);
- assertStateAfterResult(new JudgementResult(new DrumRoll(), new TaikoDrumRollJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Fail);
+ assertStateAfterResult(new JudgementResult(new DrumRoll(), new TaikoDrumRollJudgement()) { Type = HitResult.Great }, TaikoMascotAnimationState.Idle);
assertStateAfterResult(new JudgementResult(new Hit(), new TaikoJudgement()) { Type = HitResult.Good }, TaikoMascotAnimationState.Idle);
}
diff --git a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
index aaa634648a..0be005e1c4 100644
--- a/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
+++ b/osu.Game.Rulesets.Taiko.Tests/TestSceneTaikoSuddenDeath.cs
@@ -36,7 +36,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
};
[Test]
- public void TestSpinnerDoesNotFail()
+ public void TestSpinnerDoesFail()
{
bool judged = false;
AddStep("Setup judgements", () =>
@@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
Player.ScoreProcessor.NewJudgement += b => judged = true;
});
AddUntilStep("swell judged", () => judged);
- AddAssert("not failed", () => !Player.HasFailed);
+ AddAssert("failed", () => Player.HasFailed);
}
}
}
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs
index 604daa929f..0d91002f4b 100644
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs
+++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoDrumRollJudgement.cs
@@ -7,8 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoDrumRollJudgement : TaikoJudgement
{
- public override bool AffectsCombo => false;
-
protected override double HealthIncreaseFor(HitResult result)
{
// Drum rolls can be ignored with no health penalty
diff --git a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs
index 29be5e0eac..4d61efd3ee 100644
--- a/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs
+++ b/osu.Game.Rulesets.Taiko/Judgements/TaikoSwellJudgement.cs
@@ -7,8 +7,6 @@ namespace osu.Game.Rulesets.Taiko.Judgements
{
public class TaikoSwellJudgement : TaikoJudgement
{
- public override bool AffectsCombo => false;
-
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
diff --git a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs
index 97337acc45..138e8f9785 100644
--- a/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs
+++ b/osu.Game.Rulesets.Taiko/Replays/TaikoFramedReplayInputHandler.cs
@@ -18,6 +18,9 @@ namespace osu.Game.Rulesets.Taiko.Replays
protected override bool IsImportant(TaikoReplayFrame frame) => frame.Actions.Any();
- public override List GetPendingInputs() => new List { new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() } };
+ public override void CollectPendingInputs(List inputs)
+ {
+ inputs.Add(new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() });
+ }
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
index c7455583e4..bc1c10e59d 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecorder.cs
@@ -173,19 +173,10 @@ namespace osu.Game.Tests.Visual.Gameplay
{
}
- public override List GetPendingInputs()
+ public override void CollectPendingInputs(List inputs)
{
- return new List
- {
- new MousePositionAbsoluteInput
- {
- Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero)
- },
- new ReplayState
- {
- PressedActions = CurrentFrame?.Actions ?? new List()
- }
- };
+ inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero) });
+ inputs.Add(new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() });
}
}
diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs
index 7822f07957..c0f99db85d 100644
--- a/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs
+++ b/osu.Game.Tests/Visual/Gameplay/TestSceneReplayRecording.cs
@@ -113,19 +113,10 @@ namespace osu.Game.Tests.Visual.Gameplay
{
}
- public override List GetPendingInputs()
+ public override void CollectPendingInputs(List inputs)
{
- return new List
- {
- new MousePositionAbsoluteInput
- {
- Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero)
- },
- new ReplayState
- {
- PressedActions = CurrentFrame?.Actions ?? new List()
- }
- };
+ inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(CurrentFrame?.Position ?? Vector2.Zero) });
+ inputs.Add(new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() });
}
}
diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftResultsScreen.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftResultsScreen.cs
index 9fc7c336cb..0023866124 100644
--- a/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftResultsScreen.cs
+++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneTimeshiftResultsScreen.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using System.Threading.Tasks;
using NUnit.Framework;
using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets.Osu;
using osu.Game.Rulesets.Scoring;
@@ -65,11 +64,11 @@ namespace osu.Game.Tests.Visual.Multiplayer
private void bindHandler(double delay = 0)
{
- var roomScores = new List();
+ var roomScores = new List();
for (int i = 0; i < 10; i++)
{
- roomScores.Add(new RoomScore
+ roomScores.Add(new MultiplayerScore
{
ID = i,
Accuracy = 0.9 - 0.01 * i,
diff --git a/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs
index 997db827f3..d60222fa0b 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneRankingsSpotlightSelector.cs
@@ -30,12 +30,6 @@ namespace osu.Game.Tests.Visual.Online
Add(selector = new SpotlightSelector());
}
- [Test]
- public void TestVisibility()
- {
- AddStep("Toggle Visibility", selector.ToggleVisibility);
- }
-
[Test]
public void TestLocalSpotlights()
{
diff --git a/osu.Game.Tests/Visual/Online/TestSceneSocialOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneSocialOverlay.cs
deleted file mode 100644
index 77e77d90c1..0000000000
--- a/osu.Game.Tests/Visual/Online/TestSceneSocialOverlay.cs
+++ /dev/null
@@ -1,84 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using NUnit.Framework;
-using osu.Game.Overlays;
-using osu.Game.Users;
-
-namespace osu.Game.Tests.Visual.Online
-{
- [TestFixture]
- public class TestSceneSocialOverlay : OsuTestScene
- {
- protected override bool UseOnlineAPI => true;
-
- public TestSceneSocialOverlay()
- {
- SocialOverlay s = new SocialOverlay
- {
- Users = new[]
- {
- new User
- {
- Username = @"flyte",
- Id = 3103765,
- Country = new Country { FlagName = @"JP" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c1.jpg",
- },
- new User
- {
- Username = @"Cookiezi",
- Id = 124493,
- Country = new Country { FlagName = @"KR" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c2.jpg",
- },
- new User
- {
- Username = @"Angelsim",
- Id = 1777162,
- Country = new Country { FlagName = @"KR" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
- },
- new User
- {
- Username = @"Rafis",
- Id = 2558286,
- Country = new Country { FlagName = @"PL" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c4.jpg",
- },
- new User
- {
- Username = @"hvick225",
- Id = 50265,
- Country = new Country { FlagName = @"TW" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c5.jpg",
- },
- new User
- {
- Username = @"peppy",
- Id = 2,
- Country = new Country { FlagName = @"AU" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
- },
- new User
- {
- Username = @"filsdelama",
- Id = 2831793,
- Country = new Country { FlagName = @"FR" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c7.jpg"
- },
- new User
- {
- Username = @"_index",
- Id = 652457,
- Country = new Country { FlagName = @"RU" },
- CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c8.jpg"
- },
- },
- };
- Add(s);
-
- AddStep(@"toggle", s.ToggleVisibility);
- }
- }
-}
diff --git a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
index f763e50067..c2e9945c99 100644
--- a/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
+++ b/osu.Game.Tests/Visual/Online/TestSceneUserPanel.cs
@@ -42,6 +42,19 @@ namespace osu.Game.Tests.Visual.Online
Spacing = new Vector2(10f),
Children = new Drawable[]
{
+ new UserBrickPanel(new User
+ {
+ Username = @"flyte",
+ Id = 3103765,
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c6.jpg"
+ }),
+ new UserBrickPanel(new User
+ {
+ Username = @"peppy",
+ Id = 2,
+ Colour = "99EB47",
+ CoverUrl = @"https://osu.ppy.sh/images/headers/profile-covers/c3.jpg",
+ }),
flyte = new UserGridPanel(new User
{
Username = @"flyte",
diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs
index 60af5b37ef..2a76b8e265 100644
--- a/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs
+++ b/osu.Game.Tests/Visual/UserInterface/TestSceneOverlayHeader.cs
@@ -36,11 +36,11 @@ namespace osu.Game.Tests.Visual.UserInterface
}
});
- addHeader("Orange OverlayHeader (no background)", new TestNoBackgroundHeader(), OverlayColourScheme.Orange);
- addHeader("Blue OverlayHeader", new TestNoControlHeader(), OverlayColourScheme.Blue);
+ addHeader("Orange OverlayHeader (no background, 100 padding)", new TestNoBackgroundHeader(), OverlayColourScheme.Orange);
+ addHeader("Blue OverlayHeader (default 50 padding)", new TestNoControlHeader(), OverlayColourScheme.Blue);
addHeader("Green TabControlOverlayHeader (string) with ruleset selector", new TestStringTabControlHeader(), OverlayColourScheme.Green);
- addHeader("Pink TabControlOverlayHeader (enum)", new TestEnumTabControlHeader(), OverlayColourScheme.Pink);
- addHeader("Red BreadcrumbControlOverlayHeader (no background)", new TestBreadcrumbControlHeader(), OverlayColourScheme.Red);
+ addHeader("Pink TabControlOverlayHeader (enum, 30 padding)", new TestEnumTabControlHeader(), OverlayColourScheme.Pink);
+ addHeader("Red BreadcrumbControlOverlayHeader (no background, 10 padding)", new TestBreadcrumbControlHeader(), OverlayColourScheme.Red);
}
private void addHeader(string name, OverlayHeader header, OverlayColourScheme colourScheme)
@@ -86,6 +86,11 @@ namespace osu.Game.Tests.Visual.UserInterface
private class TestNoBackgroundHeader : OverlayHeader
{
protected override OverlayTitle CreateTitle() => new TestTitle();
+
+ public TestNoBackgroundHeader()
+ {
+ ContentSidePadding = 100;
+ }
}
private class TestNoControlHeader : OverlayHeader
@@ -112,6 +117,11 @@ namespace osu.Game.Tests.Visual.UserInterface
private class TestEnumTabControlHeader : TabControlOverlayHeader
{
+ public TestEnumTabControlHeader()
+ {
+ ContentSidePadding = 30;
+ }
+
protected override Drawable CreateBackground() => new OverlayHeaderBackground(@"Headers/rankings");
protected override OverlayTitle CreateTitle() => new TestTitle();
@@ -130,6 +140,8 @@ namespace osu.Game.Tests.Visual.UserInterface
public TestBreadcrumbControlHeader()
{
+ ContentSidePadding = 10;
+
TabControl.AddItem("tab1");
TabControl.AddItem("tab2");
TabControl.Current.Value = "tab2";
diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
index af6ca24165..e7788b75f3 100644
--- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
+++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs
@@ -64,49 +64,49 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The time to find the difficulty control point at.
/// The difficulty control point.
- public DifficultyControlPoint DifficultyPointAt(double time) => binarySearchWithFallback(DifficultyPoints, time);
+ public DifficultyControlPoint DifficultyPointAt(double time) => binarySearchWithFallback(DifficultyPoints, time, DifficultyControlPoint.DEFAULT);
///
/// Finds the effect control point that is active at .
///
/// The time to find the effect control point at.
/// The effect control point.
- public EffectControlPoint EffectPointAt(double time) => binarySearchWithFallback(EffectPoints, time);
+ public EffectControlPoint EffectPointAt(double time) => binarySearchWithFallback(EffectPoints, time, EffectControlPoint.DEFAULT);
///
/// Finds the sound control point that is active at .
///
/// The time to find the sound control point at.
/// The sound control point.
- public SampleControlPoint SamplePointAt(double time) => binarySearchWithFallback(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : null);
+ public SampleControlPoint SamplePointAt(double time) => binarySearchWithFallback(SamplePoints, time, SamplePoints.Count > 0 ? SamplePoints[0] : SampleControlPoint.DEFAULT);
///
/// Finds the timing control point that is active at .
///
/// The time to find the timing control point at.
/// The timing control point.
- public TimingControlPoint TimingPointAt(double time) => binarySearchWithFallback(TimingPoints, time, TimingPoints.Count > 0 ? TimingPoints[0] : null);
+ public TimingControlPoint TimingPointAt(double time) => binarySearchWithFallback(TimingPoints, time, TimingPoints.Count > 0 ? TimingPoints[0] : TimingControlPoint.DEFAULT);
///
/// Finds the maximum BPM represented by any timing control point.
///
[JsonIgnore]
public double BPMMaximum =>
- 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
+ 60000 / (TimingPoints.OrderBy(c => c.BeatLength).FirstOrDefault() ?? TimingControlPoint.DEFAULT).BeatLength;
///
/// Finds the minimum BPM represented by any timing control point.
///
[JsonIgnore]
public double BPMMinimum =>
- 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
+ 60000 / (TimingPoints.OrderByDescending(c => c.BeatLength).FirstOrDefault() ?? TimingControlPoint.DEFAULT).BeatLength;
///
/// Finds the mode BPM (most common BPM) represented by the control points.
///
[JsonIgnore]
public double BPMMode =>
- 60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? new TimingControlPoint()).BeatLength;
+ 60000 / (TimingPoints.GroupBy(c => c.BeatLength).OrderByDescending(grp => grp.Count()).FirstOrDefault()?.FirstOrDefault() ?? TimingControlPoint.DEFAULT).BeatLength;
///
/// Remove all s and return to a pristine state.
@@ -170,12 +170,12 @@ namespace osu.Game.Beatmaps.ControlPoints
///
/// The list to search.
/// The time to find the control point at.
- /// The control point to use when is before any control points. If null, a new control point will be constructed.
+ /// The control point to use when is before any control points.
/// The active control point at , or a fallback if none found.
- private T binarySearchWithFallback(IReadOnlyList list, double time, T prePoint = null)
- where T : ControlPoint, new()
+ private T binarySearchWithFallback(IReadOnlyList list, double time, T fallback)
+ where T : ControlPoint
{
- return binarySearch(list, time) ?? prePoint ?? new T();
+ return binarySearch(list, time) ?? fallback;
}
///
diff --git a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
index 2448b2b25c..1d38790f87 100644
--- a/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/DifficultyControlPoint.cs
@@ -7,6 +7,11 @@ namespace osu.Game.Beatmaps.ControlPoints
{
public class DifficultyControlPoint : ControlPoint
{
+ public static readonly DifficultyControlPoint DEFAULT = new DifficultyControlPoint
+ {
+ SpeedMultiplierBindable = { Disabled = true },
+ };
+
///
/// The speed multiplier at this control point.
///
diff --git a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
index 9b69147468..9e8e3978be 100644
--- a/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/EffectControlPoint.cs
@@ -7,6 +7,12 @@ namespace osu.Game.Beatmaps.ControlPoints
{
public class EffectControlPoint : ControlPoint
{
+ public static readonly EffectControlPoint DEFAULT = new EffectControlPoint
+ {
+ KiaiModeBindable = { Disabled = true },
+ OmitFirstBarLineBindable = { Disabled = true }
+ };
+
///
/// Whether the first bar line of this control point is ignored.
///
diff --git a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
index 61851a00d7..c052c04ea0 100644
--- a/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/SampleControlPoint.cs
@@ -10,6 +10,12 @@ namespace osu.Game.Beatmaps.ControlPoints
{
public const string DEFAULT_BANK = "normal";
+ public static readonly SampleControlPoint DEFAULT = new SampleControlPoint
+ {
+ SampleBankBindable = { Disabled = true },
+ SampleVolumeBindable = { Disabled = true }
+ };
+
///
/// The default sample bank at this control point.
///
diff --git a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
index 1927dd6575..9345299c3a 100644
--- a/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
+++ b/osu.Game/Beatmaps/ControlPoints/TimingControlPoint.cs
@@ -13,6 +13,21 @@ namespace osu.Game.Beatmaps.ControlPoints
///
public readonly Bindable TimeSignatureBindable = new Bindable(TimeSignatures.SimpleQuadruple) { Default = TimeSignatures.SimpleQuadruple };
+ ///
+ /// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
+ ///
+ private const double default_beat_length = 60000.0 / 60.0;
+
+ public static readonly TimingControlPoint DEFAULT = new TimingControlPoint
+ {
+ BeatLengthBindable =
+ {
+ Value = default_beat_length,
+ Disabled = true
+ },
+ TimeSignatureBindable = { Disabled = true }
+ };
+
///
/// The time signature at this control point.
///
diff --git a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
index dd5c41285a..df063f57d5 100644
--- a/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
+++ b/osu.Game/Graphics/Containers/BeatSyncedContainer.cs
@@ -43,14 +43,6 @@ namespace osu.Game.Graphics.Containers
///
public double MinimumBeatLength { get; set; }
- ///
- /// Default length of a beat in milliseconds. Used whenever there is no beatmap or track playing.
- ///
- private const double default_beat_length = 60000.0 / 60.0;
-
- private TimingControlPoint defaultTiming;
- private EffectControlPoint defaultEffect;
-
protected bool IsBeatSyncedWithTrack { get; private set; }
protected override void Update()
@@ -81,8 +73,8 @@ namespace osu.Game.Graphics.Containers
if (timingPoint == null || !IsBeatSyncedWithTrack)
{
currentTrackTime = Clock.CurrentTime;
- timingPoint = defaultTiming;
- effectPoint = defaultEffect;
+ timingPoint = TimingControlPoint.DEFAULT;
+ effectPoint = EffectControlPoint.DEFAULT;
}
double beatLength = timingPoint.BeatLength / Divisor;
@@ -116,17 +108,6 @@ namespace osu.Game.Graphics.Containers
private void load(IBindable beatmap)
{
Beatmap.BindTo(beatmap);
-
- defaultTiming = new TimingControlPoint
- {
- BeatLength = default_beat_length,
- };
-
- defaultEffect = new EffectControlPoint
- {
- KiaiMode = false,
- OmitFirstBarLine = false
- };
}
protected virtual void OnNewBeat(int beatIndex, TimingControlPoint timingPoint, EffectControlPoint effectPoint, ChannelAmplitudes amplitudes)
diff --git a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
index 8977f014b6..f77a3109c9 100644
--- a/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
+++ b/osu.Game/Graphics/UserInterface/FocusedTextBox.cs
@@ -67,6 +67,8 @@ namespace osu.Game.Graphics.UserInterface
public bool OnPressed(GlobalAction action)
{
+ if (!HasFocus) return false;
+
if (action == GlobalAction.Back)
{
if (Text.Length > 0)
diff --git a/osu.Game/Online/API/Requests/Responses/APICreatedRoom.cs b/osu.Game/Online/Multiplayer/APICreatedRoom.cs
similarity index 78%
rename from osu.Game/Online/API/Requests/Responses/APICreatedRoom.cs
rename to osu.Game/Online/Multiplayer/APICreatedRoom.cs
index a554101bc7..2a3bb39647 100644
--- a/osu.Game/Online/API/Requests/Responses/APICreatedRoom.cs
+++ b/osu.Game/Online/Multiplayer/APICreatedRoom.cs
@@ -2,9 +2,8 @@
// See the LICENCE file in the repository root for full licence text.
using Newtonsoft.Json;
-using osu.Game.Online.Multiplayer;
-namespace osu.Game.Online.API.Requests.Responses
+namespace osu.Game.Online.Multiplayer
{
public class APICreatedRoom : Room
{
diff --git a/osu.Game/Online/API/APIPlaylistBeatmap.cs b/osu.Game/Online/Multiplayer/APIPlaylistBeatmap.cs
similarity index 94%
rename from osu.Game/Online/API/APIPlaylistBeatmap.cs
rename to osu.Game/Online/Multiplayer/APIPlaylistBeatmap.cs
index 4f7786e880..98972ef36d 100644
--- a/osu.Game/Online/API/APIPlaylistBeatmap.cs
+++ b/osu.Game/Online/Multiplayer/APIPlaylistBeatmap.cs
@@ -6,7 +6,7 @@ using osu.Game.Beatmaps;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Rulesets;
-namespace osu.Game.Online.API
+namespace osu.Game.Online.Multiplayer
{
public class APIPlaylistBeatmap : APIBeatmap
{
diff --git a/osu.Game/Online/API/Requests/Responses/APIScoreToken.cs b/osu.Game/Online/Multiplayer/APIScoreToken.cs
similarity index 85%
rename from osu.Game/Online/API/Requests/Responses/APIScoreToken.cs
rename to osu.Game/Online/Multiplayer/APIScoreToken.cs
index 1d2465bedf..1f0063d94e 100644
--- a/osu.Game/Online/API/Requests/Responses/APIScoreToken.cs
+++ b/osu.Game/Online/Multiplayer/APIScoreToken.cs
@@ -3,7 +3,7 @@
using Newtonsoft.Json;
-namespace osu.Game.Online.API.Requests.Responses
+namespace osu.Game.Online.Multiplayer
{
public class APIScoreToken
{
diff --git a/osu.Game/Online/API/Requests/CreateRoomRequest.cs b/osu.Game/Online/Multiplayer/CreateRoomRequest.cs
similarity index 86%
rename from osu.Game/Online/API/Requests/CreateRoomRequest.cs
rename to osu.Game/Online/Multiplayer/CreateRoomRequest.cs
index c848c55cc6..dcb4ed51ea 100644
--- a/osu.Game/Online/API/Requests/CreateRoomRequest.cs
+++ b/osu.Game/Online/Multiplayer/CreateRoomRequest.cs
@@ -4,10 +4,9 @@
using System.Net.Http;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
-using osu.Game.Online.API.Requests.Responses;
-using osu.Game.Online.Multiplayer;
+using osu.Game.Online.API;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class CreateRoomRequest : APIRequest
{
diff --git a/osu.Game/Online/API/Requests/CreateRoomScoreRequest.cs b/osu.Game/Online/Multiplayer/CreateRoomScoreRequest.cs
similarity index 90%
rename from osu.Game/Online/API/Requests/CreateRoomScoreRequest.cs
rename to osu.Game/Online/Multiplayer/CreateRoomScoreRequest.cs
index e6246b4f1f..f973f96b37 100644
--- a/osu.Game/Online/API/Requests/CreateRoomScoreRequest.cs
+++ b/osu.Game/Online/Multiplayer/CreateRoomScoreRequest.cs
@@ -3,9 +3,9 @@
using System.Net.Http;
using osu.Framework.IO.Network;
-using osu.Game.Online.API.Requests.Responses;
+using osu.Game.Online.API;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class CreateRoomScoreRequest : APIRequest
{
diff --git a/osu.Game/Online/API/Requests/GetRoomPlaylistScoresRequest.cs b/osu.Game/Online/Multiplayer/GetRoomPlaylistScoresRequest.cs
similarity index 85%
rename from osu.Game/Online/API/Requests/GetRoomPlaylistScoresRequest.cs
rename to osu.Game/Online/Multiplayer/GetRoomPlaylistScoresRequest.cs
index 38f852870b..3d3bd20ff3 100644
--- a/osu.Game/Online/API/Requests/GetRoomPlaylistScoresRequest.cs
+++ b/osu.Game/Online/Multiplayer/GetRoomPlaylistScoresRequest.cs
@@ -3,8 +3,9 @@
using System.Collections.Generic;
using Newtonsoft.Json;
+using osu.Game.Online.API;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class GetRoomPlaylistScoresRequest : APIRequest
{
@@ -23,6 +24,6 @@ namespace osu.Game.Online.API.Requests
public class RoomPlaylistScores
{
[JsonProperty("scores")]
- public List Scores { get; set; }
+ public List Scores { get; set; }
}
}
diff --git a/osu.Game/Online/API/Requests/GetRoomRequest.cs b/osu.Game/Online/Multiplayer/GetRoomRequest.cs
similarity index 84%
rename from osu.Game/Online/API/Requests/GetRoomRequest.cs
rename to osu.Game/Online/Multiplayer/GetRoomRequest.cs
index 531e1857de..2907b49f1d 100644
--- a/osu.Game/Online/API/Requests/GetRoomRequest.cs
+++ b/osu.Game/Online/Multiplayer/GetRoomRequest.cs
@@ -1,9 +1,9 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
-using osu.Game.Online.Multiplayer;
+using osu.Game.Online.API;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class GetRoomRequest : APIRequest
{
diff --git a/osu.Game/Online/API/Requests/GetRoomScoresRequest.cs b/osu.Game/Online/Multiplayer/GetRoomScoresRequest.cs
similarity index 89%
rename from osu.Game/Online/API/Requests/GetRoomScoresRequest.cs
rename to osu.Game/Online/Multiplayer/GetRoomScoresRequest.cs
index eb53369d18..bc913030dd 100644
--- a/osu.Game/Online/API/Requests/GetRoomScoresRequest.cs
+++ b/osu.Game/Online/Multiplayer/GetRoomScoresRequest.cs
@@ -2,9 +2,10 @@
// See the LICENCE file in the repository root for full licence text.
using System.Collections.Generic;
+using osu.Game.Online.API;
using osu.Game.Online.API.Requests.Responses;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class GetRoomScoresRequest : APIRequest>
{
diff --git a/osu.Game/Online/API/Requests/GetRoomsRequest.cs b/osu.Game/Online/Multiplayer/GetRoomsRequest.cs
similarity index 94%
rename from osu.Game/Online/API/Requests/GetRoomsRequest.cs
rename to osu.Game/Online/Multiplayer/GetRoomsRequest.cs
index c47ed20909..64e0386f77 100644
--- a/osu.Game/Online/API/Requests/GetRoomsRequest.cs
+++ b/osu.Game/Online/Multiplayer/GetRoomsRequest.cs
@@ -4,10 +4,10 @@
using System.Collections.Generic;
using Humanizer;
using osu.Framework.IO.Network;
-using osu.Game.Online.Multiplayer;
+using osu.Game.Online.API;
using osu.Game.Screens.Multi.Lounge.Components;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class GetRoomsRequest : APIRequest>
{
diff --git a/osu.Game/Online/API/Requests/JoinRoomRequest.cs b/osu.Game/Online/Multiplayer/JoinRoomRequest.cs
similarity index 90%
rename from osu.Game/Online/API/Requests/JoinRoomRequest.cs
rename to osu.Game/Online/Multiplayer/JoinRoomRequest.cs
index b0808afa45..74375af856 100644
--- a/osu.Game/Online/API/Requests/JoinRoomRequest.cs
+++ b/osu.Game/Online/Multiplayer/JoinRoomRequest.cs
@@ -3,9 +3,9 @@
using System.Net.Http;
using osu.Framework.IO.Network;
-using osu.Game.Online.Multiplayer;
+using osu.Game.Online.API;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class JoinRoomRequest : APIRequest
{
diff --git a/osu.Game/Online/API/RoomScore.cs b/osu.Game/Online/Multiplayer/MultiplayerScore.cs
similarity index 95%
rename from osu.Game/Online/API/RoomScore.cs
rename to osu.Game/Online/Multiplayer/MultiplayerScore.cs
index 3c7f8c9833..3bbf19b11f 100644
--- a/osu.Game/Online/API/RoomScore.cs
+++ b/osu.Game/Online/Multiplayer/MultiplayerScore.cs
@@ -6,15 +6,15 @@ using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
-using osu.Game.Online.Multiplayer;
+using osu.Game.Online.API;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Users;
-namespace osu.Game.Online.API
+namespace osu.Game.Online.Multiplayer
{
- public class RoomScore
+ public class MultiplayerScore
{
[JsonProperty("id")]
public int ID { get; set; }
diff --git a/osu.Game/Online/API/Requests/PartRoomRequest.cs b/osu.Game/Online/Multiplayer/PartRoomRequest.cs
similarity index 90%
rename from osu.Game/Online/API/Requests/PartRoomRequest.cs
rename to osu.Game/Online/Multiplayer/PartRoomRequest.cs
index c988cd5c9e..54bb005d96 100644
--- a/osu.Game/Online/API/Requests/PartRoomRequest.cs
+++ b/osu.Game/Online/Multiplayer/PartRoomRequest.cs
@@ -3,9 +3,9 @@
using System.Net.Http;
using osu.Framework.IO.Network;
-using osu.Game.Online.Multiplayer;
+using osu.Game.Online.API;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
public class PartRoomRequest : APIRequest
{
diff --git a/osu.Game/Online/API/Requests/SubmitRoomScoreRequest.cs b/osu.Game/Online/Multiplayer/SubmitRoomScoreRequest.cs
similarity index 90%
rename from osu.Game/Online/API/Requests/SubmitRoomScoreRequest.cs
rename to osu.Game/Online/Multiplayer/SubmitRoomScoreRequest.cs
index 8eb2952159..d31aef2ea5 100644
--- a/osu.Game/Online/API/Requests/SubmitRoomScoreRequest.cs
+++ b/osu.Game/Online/Multiplayer/SubmitRoomScoreRequest.cs
@@ -4,11 +4,12 @@
using System.Net.Http;
using Newtonsoft.Json;
using osu.Framework.IO.Network;
+using osu.Game.Online.API;
using osu.Game.Scoring;
-namespace osu.Game.Online.API.Requests
+namespace osu.Game.Online.Multiplayer
{
- public class SubmitRoomScoreRequest : APIRequest
+ public class SubmitRoomScoreRequest : APIRequest
{
private readonly int scoreId;
private readonly int roomId;
diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs
index 618049e72c..f4bb10340e 100644
--- a/osu.Game/OsuGame.cs
+++ b/osu.Game/OsuGame.cs
@@ -63,7 +63,8 @@ namespace osu.Game
private ChannelManager channelManager;
- private NotificationOverlay notifications;
+ [NotNull]
+ private readonly NotificationOverlay notifications = new NotificationOverlay();
private NowPlayingOverlay nowPlaying;
@@ -82,7 +83,7 @@ namespace osu.Game
public virtual Storage GetStorageForStableInstall() => null;
- public float ToolbarOffset => Toolbar.Position.Y + Toolbar.DrawHeight;
+ public float ToolbarOffset => (Toolbar?.Position.Y ?? 0) + (Toolbar?.DrawHeight ?? 0);
private IdleTracker idleTracker;
@@ -250,7 +251,7 @@ namespace osu.Game
case LinkAction.OpenEditorTimestamp:
case LinkAction.JoinMultiplayerMatch:
case LinkAction.Spectate:
- waitForReady(() => notifications, _ => notifications?.Post(new SimpleNotification
+ waitForReady(() => notifications, _ => notifications.Post(new SimpleNotification
{
Text = @"This link type is not yet supported!",
Icon = FontAwesome.Solid.LifeRing,
@@ -536,14 +537,14 @@ namespace osu.Game
MenuCursorContainer.CanShowCursor = menuScreen?.CursorVisible ?? false;
// todo: all archive managers should be able to be looped here.
- SkinManager.PostNotification = n => notifications?.Post(n);
+ SkinManager.PostNotification = n => notifications.Post(n);
SkinManager.GetStableStorage = GetStorageForStableInstall;
- BeatmapManager.PostNotification = n => notifications?.Post(n);
+ BeatmapManager.PostNotification = n => notifications.Post(n);
BeatmapManager.GetStableStorage = GetStorageForStableInstall;
BeatmapManager.PresentImport = items => PresentBeatmap(items.First());
- ScoreManager.PostNotification = n => notifications?.Post(n);
+ ScoreManager.PostNotification = n => notifications.Post(n);
ScoreManager.GetStableStorage = GetStorageForStableInstall;
ScoreManager.PresentImport = items => PresentScore(items.First());
@@ -615,12 +616,12 @@ namespace osu.Game
loadComponentSingleFile(MusicController = new MusicController(), Add, true);
- loadComponentSingleFile(notifications = new NotificationOverlay
+ loadComponentSingleFile(notifications.With(d =>
{
- GetToolbarHeight = () => ToolbarOffset,
- Anchor = Anchor.TopRight,
- Origin = Anchor.TopRight,
- }, rightFloatingOverlayContent.Add, true);
+ d.GetToolbarHeight = () => ToolbarOffset;
+ d.Anchor = Anchor.TopRight;
+ d.Origin = Anchor.TopRight;
+ }), rightFloatingOverlayContent.Add, true);
loadComponentSingleFile(screenshotManager, Add);
diff --git a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs
index 79fda99c73..41b25ee1a5 100644
--- a/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs
+++ b/osu.Game/Overlays/Dashboard/Friends/FriendDisplay.cs
@@ -225,6 +225,9 @@ namespace osu.Game.Overlays.Dashboard.Friends
case OverlayPanelDisplayStyle.List:
return new UserListPanel(user);
+
+ case OverlayPanelDisplayStyle.Brick:
+ return new UserBrickPanel(user);
}
}
diff --git a/osu.Game/Overlays/OverlayHeader.cs b/osu.Game/Overlays/OverlayHeader.cs
index dbc934bde9..cc7f798c4a 100644
--- a/osu.Game/Overlays/OverlayHeader.cs
+++ b/osu.Game/Overlays/OverlayHeader.cs
@@ -12,9 +12,26 @@ namespace osu.Game.Overlays
{
public abstract class OverlayHeader : Container
{
- public const int CONTENT_X_MARGIN = 50;
+ private float contentSidePadding;
+
+ ///
+ /// Horizontal padding of the header content.
+ ///
+ protected float ContentSidePadding
+ {
+ get => contentSidePadding;
+ set
+ {
+ contentSidePadding = value;
+ content.Padding = new MarginPadding
+ {
+ Horizontal = value
+ };
+ }
+ }
private readonly Box titleBackground;
+ private readonly Container content;
protected readonly FillFlowContainer HeaderInfo;
@@ -50,14 +67,10 @@ namespace osu.Game.Overlays
RelativeSizeAxes = Axes.Both,
Colour = Color4.Gray,
},
- new Container
+ content = new Container
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding
- {
- Horizontal = CONTENT_X_MARGIN,
- },
Children = new[]
{
CreateTitle().With(title =>
@@ -79,6 +92,8 @@ namespace osu.Game.Overlays
CreateContent()
}
});
+
+ ContentSidePadding = 50;
}
[BackgroundDependencyLoader]
diff --git a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
index 7269007b41..87b9d89d4d 100644
--- a/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
+++ b/osu.Game/Overlays/OverlayPanelDisplayStyleControl.cs
@@ -34,6 +34,10 @@ namespace osu.Game.Overlays
{
Icon = FontAwesome.Solid.Bars
});
+ AddTabItem(new PanelDisplayTabItem(OverlayPanelDisplayStyle.Brick)
+ {
+ Icon = FontAwesome.Solid.Th
+ });
}
protected override TabFillFlowContainer CreateTabFlow() => new TabFillFlowContainer
@@ -96,6 +100,7 @@ namespace osu.Game.Overlays
public enum OverlayPanelDisplayStyle
{
Card,
- List
+ List,
+ Brick
}
}
diff --git a/osu.Game/Overlays/Profile/ProfileHeader.cs b/osu.Game/Overlays/Profile/ProfileHeader.cs
index 0161d91daa..2e5f1071f2 100644
--- a/osu.Game/Overlays/Profile/ProfileHeader.cs
+++ b/osu.Game/Overlays/Profile/ProfileHeader.cs
@@ -23,6 +23,8 @@ namespace osu.Game.Overlays.Profile
public ProfileHeader()
{
+ ContentSidePadding = UserProfileOverlay.CONTENT_X_MARGIN;
+
User.ValueChanged += e => updateDisplay(e.NewValue);
TabControl.AddItem("info");
diff --git a/osu.Game/Overlays/Rankings/SpotlightSelector.cs b/osu.Game/Overlays/Rankings/SpotlightSelector.cs
index f112c1ec43..422373d099 100644
--- a/osu.Game/Overlays/Rankings/SpotlightSelector.cs
+++ b/osu.Game/Overlays/Rankings/SpotlightSelector.cs
@@ -18,10 +18,8 @@ using osu.Game.Online.API.Requests;
namespace osu.Game.Overlays.Rankings
{
- public class SpotlightSelector : VisibilityContainer, IHasCurrentValue
+ public class SpotlightSelector : CompositeDrawable, IHasCurrentValue
{
- private const int duration = 300;
-
private readonly BindableWithCurrent current = new BindableWithCurrent();
public readonly Bindable Sort = new Bindable();
@@ -37,10 +35,7 @@ namespace osu.Game.Overlays.Rankings
set => dropdown.Items = value;
}
- protected override bool StartHidden => true;
-
private readonly Box background;
- private readonly Container content;
private readonly SpotlightsDropdown dropdown;
private readonly InfoColumn startDateColumn;
private readonly InfoColumn endDateColumn;
@@ -51,73 +46,68 @@ namespace osu.Game.Overlays.Rankings
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
- Add(content = new Container
+ InternalChildren = new Drawable[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Children = new Drawable[]
+ background = new Box
{
- background = new Box
- {
- RelativeSizeAxes = Axes.Both,
- },
- new Container
+ RelativeSizeAxes = Axes.Both,
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN },
+ Child = new FillFlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
- Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN },
- Child = new FillFlowContainer
+ Direction = FillDirection.Vertical,
+ Children = new Drawable[]
{
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Direction = FillDirection.Vertical,
- Children = new Drawable[]
+ new Container
{
- new Container
- {
- Margin = new MarginPadding { Vertical = 20 },
- RelativeSizeAxes = Axes.X,
- Height = 40,
- Depth = -float.MaxValue,
- Child = dropdown = new SpotlightsDropdown
- {
- RelativeSizeAxes = Axes.X,
- Current = Current
- }
- },
- new Container
+ Margin = new MarginPadding { Vertical = 20 },
+ RelativeSizeAxes = Axes.X,
+ Height = 40,
+ Depth = -float.MaxValue,
+ Child = dropdown = new SpotlightsDropdown
{
RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Children = new Drawable[]
+ Current = Current
+ }
+ },
+ new Container
+ {
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Children = new Drawable[]
+ {
+ new FillFlowContainer
{
- new FillFlowContainer
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(10, 0),
+ Margin = new MarginPadding { Bottom = 5 },
+ Children = new Drawable[]
{
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Spacing = new Vector2(10, 0),
- Margin = new MarginPadding { Bottom = 5 },
- Children = new Drawable[]
- {
- startDateColumn = new InfoColumn(@"Start Date"),
- endDateColumn = new InfoColumn(@"End Date"),
- mapCountColumn = new InfoColumn(@"Map Count"),
- participantsColumn = new InfoColumn(@"Participants")
- }
- },
- new RankingsSortTabControl
- {
- Anchor = Anchor.CentreRight,
- Origin = Anchor.CentreRight,
- Current = Sort
+ startDateColumn = new InfoColumn(@"Start Date"),
+ endDateColumn = new InfoColumn(@"End Date"),
+ mapCountColumn = new InfoColumn(@"Map Count"),
+ participantsColumn = new InfoColumn(@"Participants")
}
+ },
+ new RankingsSortTabControl
+ {
+ Anchor = Anchor.CentreRight,
+ Origin = Anchor.CentreRight,
+ Current = Sort
}
}
}
}
}
}
- });
+ };
}
[BackgroundDependencyLoader]
@@ -134,10 +124,6 @@ namespace osu.Game.Overlays.Rankings
participantsColumn.Value = response.Spotlight.Participants?.ToString("N0");
}
- protected override void PopIn() => content.FadeIn(duration, Easing.OutQuint);
-
- protected override void PopOut() => content.FadeOut(duration, Easing.OutQuint);
-
private string dateToString(DateTimeOffset date) => date.ToString("yyyy-MM-dd");
private class InfoColumn : FillFlowContainer
diff --git a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
index 0f9b07bf89..61339df76f 100644
--- a/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
+++ b/osu.Game/Overlays/Rankings/SpotlightsLayout.cs
@@ -81,8 +81,6 @@ namespace osu.Game.Overlays.Rankings
{
base.LoadComplete();
- selector.Show();
-
selectedSpotlight.BindValueChanged(_ => onSpotlightChanged());
sort.BindValueChanged(_ => onSpotlightChanged());
Ruleset.BindValueChanged(onRulesetChanged);
diff --git a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
index 52b712a40e..34e5da4ef4 100644
--- a/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
+++ b/osu.Game/Overlays/Settings/Sections/General/LoginSettings.cs
@@ -33,7 +33,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
[Resolved]
private OsuColour colours { get; set; }
- private UserPanel panel;
+ private UserGridPanel panel;
private UserDropdown dropdown;
///
diff --git a/osu.Game/Overlays/Social/FilterControl.cs b/osu.Game/Overlays/Social/FilterControl.cs
deleted file mode 100644
index 93fcc3c401..0000000000
--- a/osu.Game/Overlays/Social/FilterControl.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Framework.Extensions.Color4Extensions;
-using osuTK.Graphics;
-using osu.Framework.Graphics;
-using osu.Game.Overlays.SearchableList;
-
-namespace osu.Game.Overlays.Social
-{
- public class FilterControl : SearchableListFilterControl
- {
- protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"47253a");
- protected override SocialSortCriteria DefaultTab => SocialSortCriteria.Rank;
- protected override SortDirection DefaultCategory => SortDirection.Ascending;
-
- public FilterControl()
- {
- Tabs.Margin = new MarginPadding { Top = 10 };
- }
- }
-
- public enum SocialSortCriteria
- {
- Rank,
- Name,
- Location,
- //[Description("Time Zone")]
- //TimeZone,
- //[Description("World Map")]
- //WorldMap,
- }
-}
diff --git a/osu.Game/Overlays/Social/Header.cs b/osu.Game/Overlays/Social/Header.cs
deleted file mode 100644
index 22e0fdcd56..0000000000
--- a/osu.Game/Overlays/Social/Header.cs
+++ /dev/null
@@ -1,67 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using osu.Game.Overlays.SearchableList;
-using osuTK.Graphics;
-using osu.Framework.Graphics;
-using osu.Game.Graphics.Sprites;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics;
-using osu.Framework.Allocation;
-using System.ComponentModel;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Graphics.Sprites;
-
-namespace osu.Game.Overlays.Social
-{
- public class Header : SearchableListHeader
- {
- private OsuSpriteText browser;
-
- protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"38202e");
-
- protected override SocialTab DefaultTab => SocialTab.AllPlayers;
- protected override IconUsage Icon => FontAwesome.Solid.Users;
-
- protected override Drawable CreateHeaderText()
- {
- return new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Horizontal,
- Children = new[]
- {
- new OsuSpriteText
- {
- Text = "social ",
- Font = OsuFont.GetFont(size: 25),
- },
- browser = new OsuSpriteText
- {
- Text = "browser",
- Font = OsuFont.GetFont(size: 25, weight: FontWeight.Light),
- },
- },
- };
- }
-
- [BackgroundDependencyLoader]
- private void load(OsuColour colours)
- {
- browser.Colour = colours.Pink;
- }
- }
-
- public enum SocialTab
- {
- [Description("All Players")]
- AllPlayers,
-
- [Description("Friends")]
- Friends,
- //[Description("Team Members")]
- //TeamMembers,
- //[Description("Chat Channels")]
- //ChatChannels,
- }
-}
diff --git a/osu.Game/Overlays/SocialOverlay.cs b/osu.Game/Overlays/SocialOverlay.cs
deleted file mode 100644
index 1b05142192..0000000000
--- a/osu.Game/Overlays/SocialOverlay.cs
+++ /dev/null
@@ -1,242 +0,0 @@
-// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
-// See the LICENCE file in the repository root for full licence text.
-
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using osu.Framework.Bindables;
-using osuTK;
-using osuTK.Graphics;
-using osu.Framework.Graphics;
-using osu.Framework.Graphics.Containers;
-using osu.Game.Graphics.UserInterface;
-using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
-using osu.Game.Overlays.SearchableList;
-using osu.Game.Overlays.Social;
-using osu.Game.Users;
-using System.Threading;
-using osu.Framework.Allocation;
-using osu.Framework.Extensions.Color4Extensions;
-using osu.Framework.Threading;
-
-namespace osu.Game.Overlays
-{
- public class SocialOverlay : SearchableListOverlay
- {
- private readonly LoadingSpinner loading;
- private FillFlowContainer panels;
-
- protected override Color4 BackgroundColour => Color4Extensions.FromHex(@"60284b");
- protected override Color4 TrianglesColourLight => Color4Extensions.FromHex(@"672b51");
- protected override Color4 TrianglesColourDark => Color4Extensions.FromHex(@"5c2648");
-
- protected override SearchableListHeader CreateHeader() => new Header();
- protected override SearchableListFilterControl CreateFilterControl() => new FilterControl();
-
- private User[] users = Array.Empty();
-
- public User[] Users
- {
- get => users;
- set
- {
- if (users == value)
- return;
-
- users = value ?? Array.Empty();
-
- if (LoadState >= LoadState.Ready)
- recreatePanels();
- }
- }
-
- public SocialOverlay()
- : base(OverlayColourScheme.Pink)
- {
- Add(loading = new LoadingSpinner());
-
- Filter.Search.Current.ValueChanged += text =>
- {
- if (!string.IsNullOrEmpty(text.NewValue))
- {
- // force searching in players until searching for friends is supported
- Header.Tabs.Current.Value = SocialTab.AllPlayers;
-
- if (Filter.Tabs.Current.Value != SocialSortCriteria.Rank)
- Filter.Tabs.Current.Value = SocialSortCriteria.Rank;
- }
- };
-
- Header.Tabs.Current.ValueChanged += _ => queueUpdate();
- Filter.Tabs.Current.ValueChanged += _ => onFilterUpdate();
-
- Filter.DisplayStyleControl.DisplayStyle.ValueChanged += _ => recreatePanels();
- Filter.Dropdown.Current.ValueChanged += _ => recreatePanels();
-
- currentQuery.BindTo(Filter.Search.Current);
- currentQuery.ValueChanged += query =>
- {
- queryChangedDebounce?.Cancel();
-
- if (string.IsNullOrEmpty(query.NewValue))
- queueUpdate();
- else
- queryChangedDebounce = Scheduler.AddDelayed(updateSearch, 500);
- };
- }
-
- [BackgroundDependencyLoader]
- private void load()
- {
- recreatePanels();
- }
-
- private APIRequest getUsersRequest;
-
- private readonly Bindable currentQuery = new Bindable();
-
- private ScheduledDelegate queryChangedDebounce;
-
- private void queueUpdate() => Scheduler.AddOnce(updateSearch);
-
- private CancellationTokenSource loadCancellation;
-
- private void updateSearch()
- {
- queryChangedDebounce?.Cancel();
-
- if (!IsLoaded)
- return;
-
- Users = null;
- clearPanels();
- getUsersRequest?.Cancel();
-
- if (API?.IsLoggedIn != true)
- return;
-
- switch (Header.Tabs.Current.Value)
- {
- case SocialTab.Friends:
- var friendRequest = new GetFriendsRequest(); // TODO filter arguments?
- friendRequest.Success += users => Users = users.ToArray();
- API.Queue(getUsersRequest = friendRequest);
- break;
-
- default:
- var userRequest = new GetUsersRequest(); // TODO filter arguments!
- userRequest.Success += res => Users = res.Users.Select(r => r.User).ToArray();
- API.Queue(getUsersRequest = userRequest);
- break;
- }
- }
-
- private void recreatePanels()
- {
- clearPanels();
-
- if (Users == null)
- {
- loading.Hide();
- return;
- }
-
- IEnumerable sortedUsers = Users;
-
- switch (Filter.Tabs.Current.Value)
- {
- case SocialSortCriteria.Location:
- sortedUsers = sortedUsers.OrderBy(u => u.Country.FullName);
- break;
-
- case SocialSortCriteria.Name:
- sortedUsers = sortedUsers.OrderBy(u => u.Username);
- break;
- }
-
- if (Filter.Dropdown.Current.Value == SortDirection.Descending)
- sortedUsers = sortedUsers.Reverse();
-
- var newPanels = new FillFlowContainer
- {
- RelativeSizeAxes = Axes.X,
- AutoSizeAxes = Axes.Y,
- Spacing = new Vector2(10f),
- Margin = new MarginPadding { Top = 10 },
- ChildrenEnumerable = sortedUsers.Select(u =>
- {
- UserPanel panel;
-
- switch (Filter.DisplayStyleControl.DisplayStyle.Value)
- {
- case PanelDisplayStyle.Grid:
- panel = new UserGridPanel(u)
- {
- Anchor = Anchor.TopCentre,
- Origin = Anchor.TopCentre,
- Width = 290,
- };
- break;
-
- default:
- panel = new UserListPanel(u);
- break;
- }
-
- panel.Status.BindTo(u.Status);
- panel.Activity.BindTo(u.Activity);
- return panel;
- })
- };
-
- LoadComponentAsync(newPanels, f =>
- {
- if (panels != null)
- ScrollFlow.Remove(panels);
-
- loading.Hide();
- ScrollFlow.Add(panels = newPanels);
- }, (loadCancellation = new CancellationTokenSource()).Token);
- }
-
- private void onFilterUpdate()
- {
- if (Filter.Tabs.Current.Value == SocialSortCriteria.Rank)
- {
- queueUpdate();
- return;
- }
-
- recreatePanels();
- }
-
- private void clearPanels()
- {
- loading.Show();
-
- loadCancellation?.Cancel();
-
- if (panels != null)
- {
- panels.Expire();
- panels = null;
- }
- }
-
- public override void APIStateChanged(IAPIProvider api, APIState state)
- {
- switch (state)
- {
- case APIState.Online:
- queueUpdate();
- break;
-
- default:
- Users = null;
- clearPanels();
- break;
- }
- }
- }
-}
diff --git a/osu.Game/Overlays/TabControlOverlayHeader.cs b/osu.Game/Overlays/TabControlOverlayHeader.cs
index e8e000f441..61605d9e9e 100644
--- a/osu.Game/Overlays/TabControlOverlayHeader.cs
+++ b/osu.Game/Overlays/TabControlOverlayHeader.cs
@@ -22,6 +22,7 @@ namespace osu.Game.Overlays
protected OsuTabControl TabControl;
private readonly Box controlBackground;
+ private readonly Container tabControlContainer;
private readonly BindableWithCurrent current = new BindableWithCurrent();
public Bindable Current
@@ -30,6 +31,16 @@ namespace osu.Game.Overlays
set => current.Current = value;
}
+ protected new float ContentSidePadding
+ {
+ get => base.ContentSidePadding;
+ set
+ {
+ base.ContentSidePadding = value;
+ tabControlContainer.Padding = new MarginPadding { Horizontal = value };
+ }
+ }
+
protected TabControlOverlayHeader()
{
HeaderInfo.Add(new Container
@@ -42,11 +53,16 @@ namespace osu.Game.Overlays
{
RelativeSizeAxes = Axes.Both,
},
- TabControl = CreateTabControl().With(control =>
+ tabControlContainer = new Container
{
- control.Margin = new MarginPadding { Left = CONTENT_X_MARGIN };
- control.Current = Current;
- })
+ RelativeSizeAxes = Axes.X,
+ AutoSizeAxes = Axes.Y,
+ Padding = new MarginPadding { Horizontal = ContentSidePadding },
+ Child = TabControl = CreateTabControl().With(control =>
+ {
+ control.Current = Current;
+ })
+ }
}
});
}
diff --git a/osu.Game/Rulesets/Mods/ModPerfect.cs b/osu.Game/Rulesets/Mods/ModPerfect.cs
index 7fe606d584..65f1a972ed 100644
--- a/osu.Game/Rulesets/Mods/ModPerfect.cs
+++ b/osu.Game/Rulesets/Mods/ModPerfect.cs
@@ -17,6 +17,7 @@ namespace osu.Game.Rulesets.Mods
protected override bool FailCondition(HealthProcessor healthProcessor, JudgementResult result)
=> !(result.Judgement is IgnoreJudgement)
+ && result.Judgement.AffectsCombo
&& result.Type != result.Judgement.MaxResult;
}
}
diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
index b633cb0860..f275153ce3 100644
--- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
+++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs
@@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
if (Result == null)
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
- loadSamples();
+ LoadSamples();
}
protected override void LoadComplete()
@@ -145,14 +145,14 @@ namespace osu.Game.Rulesets.Objects.Drawables
}
samplesBindable = HitObject.SamplesBindable.GetBoundCopy();
- samplesBindable.CollectionChanged += (_, __) => loadSamples();
+ samplesBindable.CollectionChanged += (_, __) => LoadSamples();
apply(HitObject);
updateState(ArmedState.Idle, true);
}
- private void loadSamples()
+ protected virtual void LoadSamples()
{
if (Samples != null)
{
@@ -353,17 +353,32 @@ namespace osu.Game.Rulesets.Objects.Drawables
[Resolved(canBeNull: true)]
private GameplayClock gameplayClock { get; set; }
+ ///
+ /// Calculate the position to be used for sample playback at a specified X position (0..1).
+ ///
+ /// The lookup X position. Generally should be .
+ ///
+ protected double CalculateSamplePlaybackBalance(double position)
+ {
+ const float balance_adjust_amount = 0.4f;
+
+ return balance_adjust_amount * (userPositionalHitSounds.Value ? position - 0.5f : 0);
+ }
+
+ ///
+ /// Whether samples should currently be playing. Will be false during seek operations.
+ ///
+ protected bool ShouldPlaySamples => gameplayClock?.IsSeeking != true;
+
///
/// Plays all the hit sounds for this .
/// This is invoked automatically when this is hit.
///
public virtual void PlaySamples()
{
- const float balance_adjust_amount = 0.4f;
-
- if (Samples != null && gameplayClock?.IsSeeking != true)
+ if (Samples != null && ShouldPlaySamples)
{
- Samples.Balance.Value = balance_adjust_amount * (userPositionalHitSounds.Value ? SamplePlaybackPosition - 0.5f : 0);
+ Samples.Balance.Value = CalculateSamplePlaybackBalance(SamplePlaybackPosition);
Samples.Play();
}
}
diff --git a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs
index 55d82c4083..cf5c88b8fd 100644
--- a/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs
+++ b/osu.Game/Rulesets/Replays/FramedReplayInputHandler.cs
@@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using JetBrains.Annotations;
-using osu.Framework.Input.StateChanges;
using osu.Game.Input.Handlers;
using osu.Game.Replays;
@@ -69,8 +68,6 @@ namespace osu.Game.Rulesets.Replays
return true;
}
- public override List GetPendingInputs() => new List();
-
private const double sixty_frame_time = 1000.0 / 60;
protected virtual double AllowedImportantTimeSpan => sixty_frame_time * 1.2;
diff --git a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs b/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs
index 571bbde716..1afbf5c32a 100644
--- a/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs
+++ b/osu.Game/Screens/Multi/Match/Components/MatchLeaderboard.cs
@@ -6,7 +6,6 @@ using System.Collections.Generic;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Online.API.Requests.Responses;
using osu.Game.Online.Leaderboards;
using osu.Game.Online.Multiplayer;
diff --git a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
index cf0197d26b..c2381fe219 100644
--- a/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
+++ b/osu.Game/Screens/Multi/Play/TimeshiftPlayer.cs
@@ -10,7 +10,6 @@ using osu.Framework.Bindables;
using osu.Framework.Logging;
using osu.Framework.Screens;
using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Scoring;
diff --git a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs
index 5cafc974f1..f367d44347 100644
--- a/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs
+++ b/osu.Game/Screens/Multi/Ranking/TimeshiftResultsScreen.cs
@@ -9,7 +9,6 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Online.Multiplayer;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking;
diff --git a/osu.Game/Screens/Multi/RoomManager.cs b/osu.Game/Screens/Multi/RoomManager.cs
index 491be2e946..2a96fa536d 100644
--- a/osu.Game/Screens/Multi/RoomManager.cs
+++ b/osu.Game/Screens/Multi/RoomManager.cs
@@ -14,7 +14,6 @@ using osu.Framework.Logging;
using osu.Game.Beatmaps;
using osu.Game.Online;
using osu.Game.Online.API;
-using osu.Game.Online.API.Requests;
using osu.Game.Online.Multiplayer;
using osu.Game.Rulesets;
using osu.Game.Screens.Multi.Lounge.Components;
diff --git a/osu.Game/Screens/Ranking/ScorePanel.cs b/osu.Game/Screens/Ranking/ScorePanel.cs
index 9633f5c533..5da432d5b2 100644
--- a/osu.Game/Screens/Ranking/ScorePanel.cs
+++ b/osu.Game/Screens/Ranking/ScorePanel.cs
@@ -13,6 +13,7 @@ using osu.Framework.Input.Events;
using osu.Game.Scoring;
using osu.Game.Screens.Ranking.Contracted;
using osu.Game.Screens.Ranking.Expanded;
+using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
@@ -142,7 +143,16 @@ namespace osu.Game.Screens.Ranking
CornerRadius = 20,
CornerExponent = 2.5f,
Masking = true,
- Child = middleLayerBackground = new Box { RelativeSizeAxes = Axes.Both }
+ Children = new[]
+ {
+ middleLayerBackground = new Box { RelativeSizeAxes = Axes.Both },
+ new UserCoverBackground
+ {
+ RelativeSizeAxes = Axes.Both,
+ User = Score.User,
+ Colour = ColourInfo.GradientVertical(Color4.White.Opacity(0.5f), Color4Extensions.FromHex("#444").Opacity(0))
+ },
+ }
},
middleLayerContentContainer = new Container { RelativeSizeAxes = Axes.Both }
}
@@ -155,18 +165,10 @@ namespace osu.Game.Screens.Ranking
{
base.LoadComplete();
- if (state == PanelState.Expanded)
- {
- topLayerBackground.FadeColour(expanded_top_layer_colour);
- middleLayerBackground.FadeColour(expanded_middle_layer_colour);
- }
- else
- {
- topLayerBackground.FadeColour(contracted_top_layer_colour);
- middleLayerBackground.FadeColour(contracted_middle_layer_colour);
- }
-
updateState();
+
+ topLayerBackground.FinishTransforms(false, nameof(Colour));
+ middleLayerBackground.FinishTransforms(false, nameof(Colour));
}
private PanelState state = PanelState.Contracted;
diff --git a/osu.Game/Skinning/SkinnableSound.cs b/osu.Game/Skinning/SkinnableSound.cs
index 24d6648273..49f9f01cff 100644
--- a/osu.Game/Skinning/SkinnableSound.cs
+++ b/osu.Game/Skinning/SkinnableSound.cs
@@ -98,6 +98,8 @@ namespace osu.Game.Skinning
protected override void SkinChanged(ISkinSource skin, bool allowFallback)
{
+ bool wasPlaying = samplesContainer.Any(s => s.Playing);
+
var channels = hitSamples.Select(s =>
{
var ch = skin.GetSample(s);
@@ -121,6 +123,9 @@ namespace osu.Game.Skinning
}).Where(c => c != null);
samplesContainer.ChildrenEnumerable = channels.Select(c => new DrawableSample(c));
+
+ if (wasPlaying)
+ Play();
}
}
}
diff --git a/osu.Game/Users/ExtendedUserPanel.cs b/osu.Game/Users/ExtendedUserPanel.cs
new file mode 100644
index 0000000000..2604815751
--- /dev/null
+++ b/osu.Game/Users/ExtendedUserPanel.cs
@@ -0,0 +1,148 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osuTK;
+using osu.Framework.Allocation;
+using osu.Framework.Bindables;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Game.Graphics;
+using osu.Game.Graphics.Sprites;
+using osu.Framework.Graphics.Sprites;
+using osu.Game.Users.Drawables;
+using osu.Framework.Input.Events;
+
+namespace osu.Game.Users
+{
+ public abstract class ExtendedUserPanel : UserPanel
+ {
+ public readonly Bindable Status = new Bindable();
+
+ public readonly IBindable Activity = new Bindable();
+
+ protected TextFlowContainer LastVisitMessage { get; private set; }
+
+ private SpriteIcon statusIcon;
+ private OsuSpriteText statusMessage;
+
+ protected ExtendedUserPanel(User user)
+ : base(user)
+ {
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ BorderColour = ColourProvider?.Light1 ?? Colours.GreyVioletLighter;
+
+ Status.ValueChanged += status => displayStatus(status.NewValue, Activity.Value);
+ Activity.ValueChanged += activity => displayStatus(Status.Value, activity.NewValue);
+ }
+
+ protected override void LoadComplete()
+ {
+ base.LoadComplete();
+ Status.TriggerChange();
+
+ // Colour should be applied immediately on first load.
+ statusIcon.FinishTransforms();
+ }
+
+ protected UpdateableAvatar CreateAvatar() => new UpdateableAvatar
+ {
+ User = User,
+ OpenOnClick = { Value = false }
+ };
+
+ protected UpdateableFlag CreateFlag() => new UpdateableFlag(User.Country)
+ {
+ Size = new Vector2(39, 26)
+ };
+
+ protected SpriteIcon CreateStatusIcon() => statusIcon = new SpriteIcon
+ {
+ Icon = FontAwesome.Regular.Circle,
+ Size = new Vector2(25)
+ };
+
+ protected FillFlowContainer CreateStatusMessage(bool rightAlignedChildren)
+ {
+ var statusContainer = new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Vertical
+ };
+
+ var alignment = rightAlignedChildren ? Anchor.CentreRight : Anchor.CentreLeft;
+
+ statusContainer.Add(LastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)).With(text =>
+ {
+ text.Anchor = alignment;
+ text.Origin = alignment;
+ text.AutoSizeAxes = Axes.Both;
+ text.Alpha = 0;
+
+ if (User.LastVisit.HasValue)
+ {
+ text.AddText(@"Last seen ");
+ text.AddText(new DrawableDate(User.LastVisit.Value, italic: false)
+ {
+ Shadow = false
+ });
+ }
+ }));
+
+ statusContainer.Add(statusMessage = new OsuSpriteText
+ {
+ Anchor = alignment,
+ Origin = alignment,
+ Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold)
+ });
+
+ return statusContainer;
+ }
+
+ private void displayStatus(UserStatus status, UserActivity activity = null)
+ {
+ if (status != null)
+ {
+ LastVisitMessage.FadeTo(status is UserStatusOffline && User.LastVisit.HasValue ? 1 : 0);
+
+ // Set status message based on activity (if we have one) and status is not offline
+ if (activity != null && !(status is UserStatusOffline))
+ {
+ statusMessage.Text = activity.Status;
+ statusIcon.FadeColour(activity.GetAppropriateColour(Colours), 500, Easing.OutQuint);
+ return;
+ }
+
+ // Otherwise use only status
+ statusMessage.Text = status.Message;
+ statusIcon.FadeColour(status.GetAppropriateColour(Colours), 500, Easing.OutQuint);
+
+ return;
+ }
+
+ // Fallback to web status if local one is null
+ if (User.IsOnline)
+ {
+ Status.Value = new UserStatusOnline();
+ return;
+ }
+
+ Status.Value = new UserStatusOffline();
+ }
+
+ protected override bool OnHover(HoverEvent e)
+ {
+ BorderThickness = 2;
+ return base.OnHover(e);
+ }
+
+ protected override void OnHoverLost(HoverLostEvent e)
+ {
+ BorderThickness = 0;
+ base.OnHoverLost(e);
+ }
+ }
+}
diff --git a/osu.Game/Users/UserBrickPanel.cs b/osu.Game/Users/UserBrickPanel.cs
new file mode 100644
index 0000000000..9ca7768187
--- /dev/null
+++ b/osu.Game/Users/UserBrickPanel.cs
@@ -0,0 +1,65 @@
+// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
+// See the LICENCE file in the repository root for full licence text.
+
+using osu.Framework.Allocation;
+using osu.Framework.Extensions.Color4Extensions;
+using osu.Framework.Graphics;
+using osu.Framework.Graphics.Containers;
+using osu.Framework.Graphics.Shapes;
+using osu.Game.Graphics;
+using osuTK;
+
+namespace osu.Game.Users
+{
+ public class UserBrickPanel : UserPanel
+ {
+ public UserBrickPanel(User user)
+ : base(user)
+ {
+ AutoSizeAxes = Axes.Both;
+ CornerRadius = 6;
+ }
+
+ [BackgroundDependencyLoader]
+ private void load()
+ {
+ Background.FadeTo(0.2f);
+ }
+
+ protected override Drawable CreateLayout() => new FillFlowContainer
+ {
+ AutoSizeAxes = Axes.Both,
+ Direction = FillDirection.Horizontal,
+ Spacing = new Vector2(5, 0),
+ Margin = new MarginPadding
+ {
+ Horizontal = 10,
+ Vertical = 3,
+ },
+ Anchor = Anchor.Centre,
+ Origin = Anchor.Centre,
+ Children = new Drawable[]
+ {
+ new CircularContainer
+ {
+ Anchor = Anchor.CentreLeft,
+ Origin = Anchor.CentreLeft,
+ Masking = true,
+ Width = 4,
+ Height = 13,
+ Child = new Box
+ {
+ RelativeSizeAxes = Axes.Both,
+ Colour = string.IsNullOrEmpty(User.Colour) ? Color4Extensions.FromHex("0087ca") : Color4Extensions.FromHex(User.Colour)
+ }
+ },
+ CreateUsername().With(u =>
+ {
+ u.Anchor = Anchor.CentreLeft;
+ u.Origin = Anchor.CentreLeft;
+ u.Font = OsuFont.GetFont(size: 13, weight: FontWeight.Bold);
+ })
+ }
+ };
+ }
+}
diff --git a/osu.Game/Users/UserGridPanel.cs b/osu.Game/Users/UserGridPanel.cs
index e62a834d6d..44dcbc305d 100644
--- a/osu.Game/Users/UserGridPanel.cs
+++ b/osu.Game/Users/UserGridPanel.cs
@@ -9,7 +9,7 @@ using osuTK;
namespace osu.Game.Users
{
- public class UserGridPanel : UserPanel
+ public class UserGridPanel : ExtendedUserPanel
{
private const int margin = 10;
diff --git a/osu.Game/Users/UserListPanel.cs b/osu.Game/Users/UserListPanel.cs
index 1c3ae20577..9c95eff739 100644
--- a/osu.Game/Users/UserListPanel.cs
+++ b/osu.Game/Users/UserListPanel.cs
@@ -12,7 +12,7 @@ using osu.Game.Overlays.Profile.Header.Components;
namespace osu.Game.Users
{
- public class UserListPanel : UserPanel
+ public class UserListPanel : ExtendedUserPanel
{
public UserListPanel(User user)
: base(user)
diff --git a/osu.Game/Users/UserPanel.cs b/osu.Game/Users/UserPanel.cs
index 6f59f9e443..94c0c31cfc 100644
--- a/osu.Game/Users/UserPanel.cs
+++ b/osu.Game/Users/UserPanel.cs
@@ -2,9 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
-using osuTK;
using osu.Framework.Allocation;
-using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -14,11 +12,8 @@ using osu.Game.Overlays;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics.UserInterface;
using osu.Framework.Graphics.Cursor;
-using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.Containers;
-using osu.Game.Users.Drawables;
using JetBrains.Annotations;
-using osu.Framework.Input.Events;
namespace osu.Game.Users
{
@@ -26,21 +21,12 @@ namespace osu.Game.Users
{
public readonly User User;
- public readonly Bindable Status = new Bindable();
-
- public readonly IBindable Activity = new Bindable();
-
public new Action Action;
protected Action ViewProfile { get; private set; }
protected DelayedLoadUnloadWrapper Background { get; private set; }
- protected TextFlowContainer LastVisitMessage { get; private set; }
-
- private SpriteIcon statusIcon;
- private OsuSpriteText statusMessage;
-
protected UserPanel(User user)
{
if (user == null)
@@ -53,23 +39,22 @@ namespace osu.Game.Users
private UserProfileOverlay profileOverlay { get; set; }
[Resolved(canBeNull: true)]
- private OverlayColourProvider colourProvider { get; set; }
+ protected OverlayColourProvider ColourProvider { get; private set; }
[Resolved]
- private OsuColour colours { get; set; }
+ protected OsuColour Colours { get; private set; }
[BackgroundDependencyLoader]
private void load()
{
Masking = true;
- BorderColour = colourProvider?.Light1 ?? colours.GreyVioletLighter;
AddRange(new[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
- Colour = colourProvider?.Background5 ?? colours.Gray1
+ Colour = ColourProvider?.Background5 ?? Colours.Gray1
},
Background = new DelayedLoadUnloadWrapper(() => new UserCoverBackground
{
@@ -86,9 +71,6 @@ namespace osu.Game.Users
CreateLayout()
});
- Status.ValueChanged += status => displayStatus(status.NewValue, Activity.Value);
- Activity.ValueChanged += activity => displayStatus(Status.Value, activity.NewValue);
-
base.Action = ViewProfile = () =>
{
Action?.Invoke();
@@ -96,41 +78,9 @@ namespace osu.Game.Users
};
}
- protected override void LoadComplete()
- {
- base.LoadComplete();
- Status.TriggerChange();
-
- // Colour should be applied immediately on first load.
- statusIcon.FinishTransforms();
- }
-
- protected override bool OnHover(HoverEvent e)
- {
- BorderThickness = 2;
- return base.OnHover(e);
- }
-
- protected override void OnHoverLost(HoverLostEvent e)
- {
- BorderThickness = 0;
- base.OnHoverLost(e);
- }
-
[NotNull]
protected abstract Drawable CreateLayout();
- protected UpdateableAvatar CreateAvatar() => new UpdateableAvatar
- {
- User = User,
- OpenOnClick = { Value = false }
- };
-
- protected UpdateableFlag CreateFlag() => new UpdateableFlag(User.Country)
- {
- Size = new Vector2(39, 26)
- };
-
protected OsuSpriteText CreateUsername() => new OsuSpriteText
{
Font = OsuFont.GetFont(size: 16, weight: FontWeight.Bold),
@@ -138,80 +88,6 @@ namespace osu.Game.Users
Text = User.Username,
};
- protected SpriteIcon CreateStatusIcon() => statusIcon = new SpriteIcon
- {
- Icon = FontAwesome.Regular.Circle,
- Size = new Vector2(25)
- };
-
- protected FillFlowContainer CreateStatusMessage(bool rightAlignedChildren)
- {
- var statusContainer = new FillFlowContainer
- {
- AutoSizeAxes = Axes.Both,
- Direction = FillDirection.Vertical
- };
-
- var alignment = rightAlignedChildren ? Anchor.CentreRight : Anchor.CentreLeft;
-
- statusContainer.Add(LastVisitMessage = new TextFlowContainer(t => t.Font = OsuFont.GetFont(size: 12, weight: FontWeight.SemiBold)).With(text =>
- {
- text.Anchor = alignment;
- text.Origin = alignment;
- text.AutoSizeAxes = Axes.Both;
- text.Alpha = 0;
-
- if (User.LastVisit.HasValue)
- {
- text.AddText(@"Last seen ");
- text.AddText(new DrawableDate(User.LastVisit.Value, italic: false)
- {
- Shadow = false
- });
- }
- }));
-
- statusContainer.Add(statusMessage = new OsuSpriteText
- {
- Anchor = alignment,
- Origin = alignment,
- Font = OsuFont.GetFont(size: 14, weight: FontWeight.SemiBold)
- });
-
- return statusContainer;
- }
-
- private void displayStatus(UserStatus status, UserActivity activity = null)
- {
- if (status != null)
- {
- LastVisitMessage.FadeTo(status is UserStatusOffline && User.LastVisit.HasValue ? 1 : 0);
-
- // Set status message based on activity (if we have one) and status is not offline
- if (activity != null && !(status is UserStatusOffline))
- {
- statusMessage.Text = activity.Status;
- statusIcon.FadeColour(activity.GetAppropriateColour(colours), 500, Easing.OutQuint);
- return;
- }
-
- // Otherwise use only status
- statusMessage.Text = status.Message;
- statusIcon.FadeColour(status.GetAppropriateColour(colours), 500, Easing.OutQuint);
-
- return;
- }
-
- // Fallback to web status if local one is null
- if (User.IsOnline)
- {
- Status.Value = new UserStatusOnline();
- return;
- }
-
- Status.Value = new UserStatusOffline();
- }
-
public MenuItem[] ContextMenuItems => new MenuItem[]
{
new OsuMenuItem("View Profile", MenuItemType.Highlighted, ViewProfile),
diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj
index 2f3d08c528..5af28ae11a 100644
--- a/osu.Game/osu.Game.csproj
+++ b/osu.Game/osu.Game.csproj
@@ -24,7 +24,7 @@
-
+
diff --git a/osu.iOS.props b/osu.iOS.props
index 2bb3914c25..4a94ec33d8 100644
--- a/osu.iOS.props
+++ b/osu.iOS.props
@@ -70,7 +70,7 @@
-
+
@@ -80,7 +80,7 @@
-
+