1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 21:27:24 +08:00

Merge branch 'master' into tournament-mappool-flow-logic

This commit is contained in:
Dan Balasescu 2020-03-23 10:33:58 +09:00 committed by GitHub
commit 296a594d0c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
55 changed files with 306 additions and 159 deletions

View File

@ -97,8 +97,10 @@ platform :ios do
changelog.gsub!('$BUILD_ID', options[:build])
pilot(
wait_processing_interval: 1800,
wait_processing_interval: 900,
changelog: changelog,
groups: ['osu! supporters', 'public'],
distribute_external: true,
ipa: './osu.iOS/bin/iPhone/Release/osu.iOS.ipa'
)
end

View File

@ -52,6 +52,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.317.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.319.0" />
</ItemGroup>
</Project>

View File

@ -4,29 +4,25 @@
using System;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Testing;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Osu.Objects;
using osu.Game.Rulesets.Osu.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using osu.Game.Tests.Visual;
using osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneHitCircleArea : ManualInputManagerTestScene
public class TestSceneHitCircleArea : OsuManualInputManagerTestScene
{
private HitCircle hitCircle;
private DrawableHitCircle drawableHitCircle;
private DrawableHitCircle.HitReceptor hitAreaReceptor => drawableHitCircle.HitArea;
[SetUp]
public new void SetUp()
{
base.SetUp();
Schedule(() =>
public void SetUp() => Schedule(() =>
{
hitCircle = new HitCircle
{
@ -45,7 +41,6 @@ namespace osu.Game.Rulesets.Osu.Tests
}
};
});
}
[Test]
public void TestCircleHitCentre()

View File

@ -23,7 +23,7 @@ using osuTK.Graphics;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneOsuDistanceSnapGrid : ManualInputManagerTestScene
public class TestSceneOsuDistanceSnapGrid : OsuManualInputManagerTestScene
{
private const double beat_length = 100;
private static readonly Vector2 grid_position = new Vector2(512, 384);

View File

@ -12,7 +12,7 @@ using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneResumeOverlay : ManualInputManagerTestScene
public class TestSceneResumeOverlay : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -41,7 +41,7 @@ namespace osu.Game.Rulesets.Osu.Tests
typeof(DrawableSliderTick),
typeof(DrawableSliderTail),
typeof(DrawableSliderHead),
typeof(DrawableRepeatPoint),
typeof(DrawableSliderRepeat),
typeof(DrawableOsuHitObject)
};
@ -146,7 +146,7 @@ namespace osu.Game.Rulesets.Osu.Tests
AddAssert("head samples updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle));
AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderTick>().All(assertTickSamples));
AddAssert("repeat samples updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<RepeatPoint>().All(assertSamples));
AddAssert("repeat samples updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderRepeat>().All(assertSamples));
AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0);
static bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick";
@ -181,7 +181,7 @@ namespace osu.Game.Rulesets.Osu.Tests
AddAssert("head samples not updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle));
AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderTick>().All(assertTickSamples));
AddAssert("repeat samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<RepeatPoint>().All(assertSamples));
AddAssert("repeat samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderRepeat>().All(assertSamples));
AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0);
static bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick";

View File

@ -32,7 +32,7 @@ namespace osu.Game.Rulesets.Osu.Tests
typeof(SliderBall),
typeof(DrawableSlider),
typeof(DrawableSliderTick),
typeof(DrawableRepeatPoint),
typeof(DrawableSliderRepeat),
typeof(DrawableOsuHitObject),
typeof(DrawableSliderHead),
typeof(DrawableSliderTail),
@ -327,7 +327,7 @@ namespace osu.Game.Rulesets.Osu.Tests
AddAssert("Tracking dropped", assertMidSliderJudgementFail);
}
private bool assertGreatJudge() => judgementResults.Last().Type == HitResult.Great;
private bool assertGreatJudge() => judgementResults.Any() && judgementResults.All(t => t.Type == HitResult.Great);
private bool assertHeadMissTailTracked() => judgementResults[^2].Type == HitResult.Great && judgementResults.First().Type == HitResult.Miss;

View File

@ -0,0 +1,16 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Judgements
{
public class OsuIgnoreJudgement : OsuJudgement
{
public override bool AffectsCombo => false;
protected override int NumericResultFor(HitResult result) => 0;
protected override double HealthIncreaseFor(HitResult result) => 0;
}
}

View File

@ -26,7 +26,7 @@ namespace osu.Game.Rulesets.Osu.Mods
return;
slider.NestedHitObjects.OfType<SliderTick>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
slider.NestedHitObjects.OfType<RepeatPoint>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
slider.NestedHitObjects.OfType<SliderRepeat>().ForEach(h => h.Position = new Vector2(h.Position.X, OsuPlayfield.BASE_SIZE.Y - h.Position.Y));
foreach (var point in slider.Path.ControlPoints)
point.Position.Value = new Vector2(point.Position.Value.X, -point.Position.Value.Y);

View File

@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Osu.Mods
case DrawableSliderHead _:
case DrawableSliderTail _:
case DrawableSliderTick _:
case DrawableRepeatPoint _:
case DrawableSliderRepeat _:
return;
default:

View File

@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.Osu.Mods
// Wiggle the repeat points with the slider instead of independently.
// Also fixes an issue with repeat points being positioned incorrectly.
if (osuObject is RepeatPoint)
if (osuObject is SliderRepeat)
return;
Random objRand = new Random((int)osuObject.StartTime);

View File

@ -88,8 +88,6 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
private void refresh()
{
ClearInternal();
OsuHitObject osuStart = Start.HitObject;
double startTime = osuStart.GetEndTime();
@ -116,6 +114,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
double? firstTransformStartTime = null;
double finalTransformEndTime = startTime;
int point = 0;
for (int d = (int)(spacing * 1.5); d < distance - spacing; d += spacing)
{
float fraction = (float)d / distance;
@ -126,13 +126,18 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
FollowPoint fp;
AddInternal(fp = new FollowPoint
if (InternalChildren.Count > point)
{
Position = pointStartPosition,
Rotation = rotation,
Alpha = 0,
Scale = new Vector2(1.5f * osuEnd.Scale),
});
fp = (FollowPoint)InternalChildren[point];
fp.ClearTransforms();
}
else
AddInternal(fp = new FollowPoint());
fp.Position = pointStartPosition;
fp.Rotation = rotation;
fp.Alpha = 0;
fp.Scale = new Vector2(1.5f * osuEnd.Scale);
if (firstTransformStartTime == null)
firstTransformStartTime = fadeInTime;
@ -146,8 +151,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables.Connections
finalTransformEndTime = fadeOutTime + osuEnd.TimeFadeIn;
}
point++;
}
int excessPoints = InternalChildren.Count - point;
for (int i = 0; i < excessPoints; i++)
RemoveInternal(InternalChildren[^1]);
// todo: use Expire() on FollowPoints and take lifetime from them when https://github.com/ppy/osu-framework/issues/3300 is fixed.
LifetimeStart = firstTransformStartTime ?? startTime;
LifetimeEnd = finalTransformEndTime;

View File

@ -6,13 +6,11 @@ using osuTK;
using osu.Framework.Graphics;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Osu.Objects.Drawables.Pieces;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics.Containers;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Osu.Skinning;
using osu.Game.Rulesets.Scoring;
using osuTK.Graphics;
using osu.Game.Skinning;
@ -26,12 +24,14 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public readonly SliderBall Ball;
public readonly SkinnableDrawable Body;
public override bool DisplayResult => false;
private PlaySliderBody sliderBody => Body.Drawable as PlaySliderBody;
private readonly Container<DrawableSliderHead> headContainer;
private readonly Container<DrawableSliderTail> tailContainer;
private readonly Container<DrawableSliderTick> tickContainer;
private readonly Container<DrawableRepeatPoint> repeatContainer;
private readonly Container<DrawableSliderRepeat> repeatContainer;
private readonly Slider slider;
@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
Body = new SkinnableDrawable(new OsuSkinComponent(OsuSkinComponents.SliderBody), _ => new DefaultSliderBody(), confineMode: ConfineMode.NoScaling),
tickContainer = new Container<DrawableSliderTick> { RelativeSizeAxes = Axes.Both },
repeatContainer = new Container<DrawableRepeatPoint> { RelativeSizeAxes = Axes.Both },
repeatContainer = new Container<DrawableSliderRepeat> { RelativeSizeAxes = Axes.Both },
Ball = new SliderBall(s, this)
{
GetInitialHitAction = () => HeadCircle.HitAction,
@ -100,7 +100,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
tickContainer.Add(tick);
break;
case DrawableRepeatPoint repeat:
case DrawableSliderRepeat repeat:
repeatContainer.Add(repeat);
break;
}
@ -129,8 +129,8 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
case SliderTick tick:
return new DrawableSliderTick(tick) { Position = tick.Position - slider.Position };
case RepeatPoint repeat:
return new DrawableRepeatPoint(repeat, this) { Position = repeat.Position - slider.Position };
case SliderRepeat repeat:
return new DrawableSliderRepeat(repeat, this) { Position = repeat.Position - slider.Position };
}
return base.CreateNestedHitObject(hitObject);
@ -193,22 +193,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
if (userTriggered || Time.Current < slider.EndTime)
return;
ApplyResult(r =>
{
var judgementsCount = NestedHitObjects.Count;
var judgementsHit = NestedHitObjects.Count(h => h.IsHit);
var hitFraction = (double)judgementsHit / judgementsCount;
if (hitFraction == 1 && HeadCircle.Result.Type == HitResult.Great)
r.Type = HitResult.Great;
else if (hitFraction >= 0.5 && HeadCircle.Result.Type >= HitResult.Good)
r.Type = HitResult.Good;
else if (hitFraction > 0)
r.Type = HitResult.Meh;
else
r.Type = HitResult.Miss;
});
ApplyResult(r => r.Type = r.Judgement.MaxResult);
}
protected override void UpdateStateTransforms(ArmedState state)

View File

@ -14,19 +14,19 @@ using osuTK;
namespace osu.Game.Rulesets.Osu.Objects.Drawables
{
public class DrawableRepeatPoint : DrawableOsuHitObject, ITrackSnaking
public class DrawableSliderRepeat : DrawableOsuHitObject, ITrackSnaking
{
private readonly RepeatPoint repeatPoint;
private readonly SliderRepeat sliderRepeat;
private readonly DrawableSlider drawableSlider;
private double animDuration;
private readonly Drawable scaleContainer;
public DrawableRepeatPoint(RepeatPoint repeatPoint, DrawableSlider drawableSlider)
: base(repeatPoint)
public DrawableSliderRepeat(SliderRepeat sliderRepeat, DrawableSlider drawableSlider)
: base(sliderRepeat)
{
this.repeatPoint = repeatPoint;
this.sliderRepeat = sliderRepeat;
this.drawableSlider = drawableSlider;
Size = new Vector2(OsuHitObject.OBJECT_RADIUS * 2);
@ -48,13 +48,13 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (repeatPoint.StartTime <= Time.Current)
if (sliderRepeat.StartTime <= Time.Current)
ApplyResult(r => r.Type = drawableSlider.Tracking.Value ? HitResult.Great : HitResult.Miss);
}
protected override void UpdateInitialTransforms()
{
animDuration = Math.Min(300, repeatPoint.SpanDuration);
animDuration = Math.Min(300, sliderRepeat.SpanDuration);
this.Animate(
d => d.FadeIn(animDuration),
@ -87,7 +87,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public void UpdateSnakingPosition(Vector2 start, Vector2 end)
{
bool isRepeatAtEnd = repeatPoint.RepeatIndex % 2 == 0;
bool isRepeatAtEnd = sliderRepeat.RepeatIndex % 2 == 0;
List<Vector2> curve = ((PlaySliderBody)drawableSlider.Body.Drawable).CurrentCurve;
Position = isRepeatAtEnd ? end : start;

View File

@ -46,7 +46,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (!userTriggered && timeOffset >= 0)
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : HitResult.Miss);
}
private void updatePosition() => Position = HitObject.Position - slider.Position;

View File

@ -64,7 +64,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (timeOffset >= 0)
ApplyResult(r => r.Type = Tracking ? HitResult.Great : HitResult.Miss);
ApplyResult(r => r.Type = Tracking ? r.Judgement.MaxResult : HitResult.Miss);
}
protected override void UpdateInitialTransforms()

View File

@ -177,7 +177,7 @@ namespace osu.Game.Rulesets.Osu.Objects
break;
case SliderEventType.Repeat:
AddNested(new RepeatPoint
AddNested(new SliderRepeat
{
RepeatIndex = e.SpanIndex,
SpanDuration = SpanDuration,
@ -223,7 +223,7 @@ namespace osu.Game.Rulesets.Osu.Objects
foreach (var tick in NestedHitObjects.OfType<SliderTick>())
tick.Samples = sampleList;
foreach (var repeat in NestedHitObjects.OfType<RepeatPoint>())
foreach (var repeat in NestedHitObjects.OfType<SliderRepeat>())
repeat.Samples = getNodeSamples(repeat.RepeatIndex + 1);
if (HeadCircle != null)
@ -233,7 +233,7 @@ namespace osu.Game.Rulesets.Osu.Objects
private IList<HitSampleInfo> getNodeSamples(int nodeIndex) =>
nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples;
public override Judgement CreateJudgement() => new OsuJudgement();
public override Judgement CreateJudgement() => new OsuIgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
}

View File

@ -10,7 +10,7 @@ using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Osu.Objects
{
public class RepeatPoint : OsuHitObject
public class SliderRepeat : OsuHitObject
{
public int RepeatIndex { get; set; }
public double SpanDuration { get; set; }
@ -28,8 +28,15 @@ namespace osu.Game.Rulesets.Osu.Objects
TimePreempt = Math.Min(SpanDuration * 2, TimePreempt);
}
public override Judgement CreateJudgement() => new OsuJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
public override Judgement CreateJudgement() => new SliderRepeatJudgement();
public class SliderRepeatJudgement : OsuJudgement
{
public override bool IsBonus => true;
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 30 : 0;
}
}
}

View File

@ -22,8 +22,8 @@ namespace osu.Game.Rulesets.Osu.Objects
pathVersion.BindValueChanged(_ => Position = slider.EndPosition);
}
public override Judgement CreateJudgement() => new IgnoreJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
public override Judgement CreateJudgement() => new SliderRepeat.SliderRepeatJudgement();
}
}

View File

@ -30,8 +30,15 @@ namespace osu.Game.Rulesets.Osu.Objects
TimePreempt = (StartTime - SpanStartTime) / 2 + offset;
}
public override Judgement CreateJudgement() => new OsuJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
public override Judgement CreateJudgement() => new SliderTickJudgement();
public class SliderTickJudgement : OsuJudgement
{
public override bool IsBonus => true;
protected override int NumericResultFor(HitResult result) => result == MaxResult ? 10 : 0;
}
}
}

View File

@ -37,7 +37,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Background
{
[TestFixture]
public class TestSceneUserDimBackgrounds : ManualInputManagerTestScene
public class TestSceneUserDimBackgrounds : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -12,7 +12,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Components
{
[TestFixture]
public class TestSceneIdleTracker : ManualInputManagerTestScene
public class TestSceneIdleTracker : OsuManualInputManagerTestScene
{
private IdleTrackingBox box1;
private IdleTrackingBox box2;

View File

@ -3,27 +3,83 @@
using System;
using System.Collections.Generic;
using osu.Framework.Allocation;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Testing;
using osu.Game.Screens.Edit;
using osu.Game.Screens.Edit.Compose.Components;
using osuTK;
using osuTK.Input;
namespace osu.Game.Tests.Visual.Editor
{
public class TestSceneBeatDivisorControl : OsuTestScene
public class TestSceneBeatDivisorControl : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(BindableBeatDivisor) };
private BeatDivisorControl beatDivisorControl;
private BindableBeatDivisor bindableBeatDivisor;
[BackgroundDependencyLoader]
private void load()
private SliderBar<int> tickSliderBar;
private EquilateralTriangle tickMarkerHead;
[SetUp]
public void SetUp() => Schedule(() =>
{
Child = new BeatDivisorControl(new BindableBeatDivisor())
Child = beatDivisorControl = new BeatDivisorControl(bindableBeatDivisor = new BindableBeatDivisor(16))
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Size = new Vector2(90, 90)
};
tickSliderBar = beatDivisorControl.ChildrenOfType<SliderBar<int>>().Single();
tickMarkerHead = tickSliderBar.ChildrenOfType<EquilateralTriangle>().Single();
});
[Test]
public void TestBindableBeatDivisor()
{
AddRepeatStep("move previous", () => bindableBeatDivisor.Previous(), 4);
AddAssert("divisor is 4", () => bindableBeatDivisor.Value == 4);
AddRepeatStep("move next", () => bindableBeatDivisor.Next(), 3);
AddAssert("divisor is 12", () => bindableBeatDivisor.Value == 12);
}
[Test]
public void TestMouseInput()
{
AddStep("hold marker", () =>
{
InputManager.MoveMouseTo(tickMarkerHead.ScreenSpaceDrawQuad.Centre);
InputManager.PressButton(MouseButton.Left);
});
AddStep("move to 8 and release", () =>
{
InputManager.MoveMouseTo(tickSliderBar.ScreenSpaceDrawQuad.Centre);
InputManager.ReleaseButton(MouseButton.Left);
});
AddAssert("divisor is 8", () => bindableBeatDivisor.Value == 8);
AddStep("hold marker", () => InputManager.PressButton(MouseButton.Left));
AddStep("move to 16", () => InputManager.MoveMouseTo(getPositionForDivisor(16)));
AddStep("move to ~10 and release", () =>
{
InputManager.MoveMouseTo(getPositionForDivisor(10));
InputManager.ReleaseButton(MouseButton.Left);
});
AddAssert("divisor clamped to 8", () => bindableBeatDivisor.Value == 8);
}
private Vector2 getPositionForDivisor(int divisor)
{
var relativePosition = (float)Math.Clamp(divisor, 0, 16) / 16;
var sliderDrawQuad = tickSliderBar.ScreenSpaceDrawQuad;
return new Vector2(
sliderDrawQuad.TopLeft.X + sliderDrawQuad.Width * relativePosition,
sliderDrawQuad.Centre.Y
);
}
}
}

View File

@ -17,7 +17,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.Editor
{
public class TestSceneZoomableScrollContainer : ManualInputManagerTestScene
public class TestSceneZoomableScrollContainer : OsuManualInputManagerTestScene
{
private ZoomableScrollContainer scrollContainer;
private Drawable innerBox;

View File

@ -18,7 +18,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
[Description("player pause/fail screens")]
public class TestSceneGameplayMenuOverlay : ManualInputManagerTestScene
public class TestSceneGameplayMenuOverlay : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[] { typeof(FailOverlay), typeof(PauseOverlay) };

View File

@ -15,7 +15,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestSceneHUDOverlay : ManualInputManagerTestScene
public class TestSceneHUDOverlay : OsuManualInputManagerTestScene
{
private HUDOverlay hudOverlay;

View File

@ -13,7 +13,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
[Description("'Hold to Quit' UI element")]
public class TestSceneHoldForMenuButton : ManualInputManagerTestScene
public class TestSceneHoldForMenuButton : OsuManualInputManagerTestScene
{
private bool exitAction;

View File

@ -13,7 +13,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
public class TestSceneKeyCounter : ManualInputManagerTestScene
public class TestSceneKeyCounter : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -29,7 +29,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
public class TestScenePlayerLoader : ManualInputManagerTestScene
public class TestScenePlayerLoader : OsuManualInputManagerTestScene
{
private TestPlayerLoader loader;
private TestPlayerLoaderContainer container;

View File

@ -14,7 +14,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Gameplay
{
[TestFixture]
public class TestSceneSkipOverlay : ManualInputManagerTestScene
public class TestSceneSkipOverlay : OsuManualInputManagerTestScene
{
private SkipOverlay skip;
private int requestCount;

View File

@ -20,7 +20,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Multiplayer
{
public class TestSceneDrawableRoomPlaylist : ManualInputManagerTestScene
public class TestSceneDrawableRoomPlaylist : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -27,7 +27,7 @@ namespace osu.Game.Tests.Visual.Navigation
/// <summary>
/// A scene which tests full game flow.
/// </summary>
public abstract class OsuGameTestScene : ManualInputManagerTestScene
public abstract class OsuGameTestScene : OsuManualInputManagerTestScene
{
private GameHost host;

View File

@ -22,7 +22,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.Online
{
public class TestSceneChatOverlay : ManualInputManagerTestScene
public class TestSceneChatOverlay : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -32,6 +32,16 @@ namespace osu.Game.Tests.Visual.Ranking
typeof(SmoothCircularProgress)
};
[Test]
public void TestLowDRank()
{
var score = createScore();
score.Accuracy = 0.2;
score.Rank = ScoreRank.D;
addCircleStep(score);
}
[Test]
public void TestDRank()
{

View File

@ -15,7 +15,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneCommentEditor : ManualInputManagerTestScene
public class TestSceneCommentEditor : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -17,7 +17,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
public class TestSceneCursors : ManualInputManagerTestScene
public class TestSceneCursors : OsuManualInputManagerTestScene
{
private readonly MenuCursorContainer menuCursorContainer;
private readonly CustomCursorBox[] cursorBoxes = new CustomCursorBox[6];

View File

@ -27,7 +27,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneDeleteLocalScore : ManualInputManagerTestScene
public class TestSceneDeleteLocalScore : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -12,7 +12,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
[TestFixture]
public class TestSceneOsuHoverContainer : ManualInputManagerTestScene
public class TestSceneOsuHoverContainer : OsuManualInputManagerTestScene
{
private OsuHoverTestContainer hoverContainer;
private Box colourContainer;

View File

@ -12,7 +12,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneStatefulMenuItem : ManualInputManagerTestScene
public class TestSceneStatefulMenuItem : OsuManualInputManagerTestScene
{
public override IReadOnlyList<Type> RequiredTypes => new[]
{

View File

@ -9,7 +9,7 @@ using osuTK.Input;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneSwitchButton : ManualInputManagerTestScene
public class TestSceneSwitchButton : OsuManualInputManagerTestScene
{
private SwitchButton switchButton;

View File

@ -3,6 +3,7 @@
using osu.Framework.Extensions.Color4Extensions;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osuTK.Graphics;
@ -47,23 +48,49 @@ namespace osu.Game.Graphics
{
case ScoreRank.XH:
case ScoreRank.X:
return Color4Extensions.FromHex(@"ce1c9d");
return Color4Extensions.FromHex(@"de31ae");
case ScoreRank.SH:
case ScoreRank.S:
return Color4Extensions.FromHex(@"00a8b5");
return Color4Extensions.FromHex(@"02b5c3");
case ScoreRank.A:
return Color4Extensions.FromHex(@"7cce14");
return Color4Extensions.FromHex(@"88da20");
case ScoreRank.B:
return Color4Extensions.FromHex(@"e3b130");
case ScoreRank.C:
return Color4Extensions.FromHex(@"f18252");
return Color4Extensions.FromHex(@"ff8e5d");
default:
return Color4Extensions.FromHex(@"e95353");
return Color4Extensions.FromHex(@"ff5a5a");
}
}
/// <summary>
/// Retrieves the colour for a <see cref="HitResult"/>.
/// </summary>
public Color4 ForHitResult(HitResult judgement)
{
switch (judgement)
{
case HitResult.Perfect:
case HitResult.Great:
return Blue;
case HitResult.Ok:
case HitResult.Good:
return Green;
case HitResult.Meh:
return Yellow;
case HitResult.Miss:
return Red;
default:
return Color4.White;
}
}

View File

@ -12,7 +12,6 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Skinning;
using osuTK.Graphics;
namespace osu.Game.Rulesets.Judgements
{
@ -68,7 +67,7 @@ namespace osu.Game.Rulesets.Judgements
{
Text = Result.Type.GetDescription().ToUpperInvariant(),
Font = OsuFont.Numeric.With(size: 20),
Colour = judgementColour(Result.Type),
Colour = colours.ForHitResult(Result.Type),
Scale = new Vector2(0.85f, 1),
}, confineMode: ConfineMode.NoScaling)
};
@ -110,28 +109,5 @@ namespace osu.Game.Rulesets.Judgements
Expire(true);
}
private Color4 judgementColour(HitResult judgement)
{
switch (judgement)
{
case HitResult.Perfect:
case HitResult.Great:
return colours.Blue;
case HitResult.Ok:
case HitResult.Good:
return colours.Green;
case HitResult.Meh:
return colours.Yellow;
case HitResult.Miss:
return colours.Red;
default:
return Color4.White;
}
}
}
}

View File

@ -279,6 +279,11 @@ namespace osu.Game.Screens.Edit.Compose.Components
handleMouseInput(e.ScreenSpaceMousePosition);
}
protected override void OnDragEnd(DragEndEvent e)
{
handleMouseInput(e.ScreenSpaceMousePosition);
}
private void handleMouseInput(Vector2 screenSpaceMousePosition)
{
// copied from SliderBar so we can do custom spacing logic.

View File

@ -387,6 +387,10 @@ namespace osu.Game.Screens.Play
private void onCompletion()
{
// screen may be in the exiting transition phase.
if (!this.IsCurrentScreen())
return;
// Only show the completion screen if the player hasn't failed
if (HealthProcessor.HasFailed || completionProgressDelegate != null)
return;
@ -581,7 +585,7 @@ namespace osu.Game.Screens.Play
if (completionProgressDelegate != null && !completionProgressDelegate.Cancelled && !completionProgressDelegate.Completed)
{
// proceed to result screen if beatmap already finished playing
scheduleGotoRanking();
completionProgressDelegate.RunTask();
return true;
}
@ -622,8 +626,16 @@ namespace osu.Game.Screens.Play
completionProgressDelegate = Schedule(delegate
{
var score = CreateScore();
if (DrawableRuleset.ReplayScore == null)
scoreManager.Import(score).ContinueWith(_ => Schedule(() => this.Push(CreateResults(score))));
{
scoreManager.Import(score).ContinueWith(_ => Schedule(() =>
{
// screen may be in the exiting transition phase.
if (this.IsCurrentScreen())
this.Push(CreateResults(score));
}));
}
else
this.Push(CreateResults(score));
});

View File

@ -119,42 +119,42 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
new SmoothCircularProgress
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#BE0089"),
Colour = OsuColour.ForRank(ScoreRank.X),
InnerRadius = RANK_CIRCLE_RADIUS,
Current = { Value = 1 }
},
new SmoothCircularProgress
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#0096A2"),
Colour = OsuColour.ForRank(ScoreRank.S),
InnerRadius = RANK_CIRCLE_RADIUS,
Current = { Value = 1 - virtual_ss_percentage }
},
new SmoothCircularProgress
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#72C904"),
Colour = OsuColour.ForRank(ScoreRank.A),
InnerRadius = RANK_CIRCLE_RADIUS,
Current = { Value = 0.95f }
},
new SmoothCircularProgress
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#D99D03"),
Colour = OsuColour.ForRank(ScoreRank.B),
InnerRadius = RANK_CIRCLE_RADIUS,
Current = { Value = 0.9f }
},
new SmoothCircularProgress
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#EA7948"),
Colour = OsuColour.ForRank(ScoreRank.C),
InnerRadius = RANK_CIRCLE_RADIUS,
Current = { Value = 0.8f }
},
new SmoothCircularProgress
{
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#FF5858"),
Colour = OsuColour.ForRank(ScoreRank.D),
InnerRadius = RANK_CIRCLE_RADIUS,
Current = { Value = 0.7f }
},
@ -196,6 +196,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Accuracy
new RankBadge(0.9f, ScoreRank.A),
new RankBadge(0.8f, ScoreRank.B),
new RankBadge(0.7f, ScoreRank.C),
new RankBadge(0.35f, ScoreRank.D),
}
},
rankText = new RankText(score.Rank)

View File

@ -5,7 +5,6 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Localisation;
@ -14,6 +13,7 @@ using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Rulesets.Scoring;
using osu.Game.Scoring;
using osu.Game.Screens.Play.HUD;
using osu.Game.Screens.Ranking.Expanded.Accuracy;
@ -56,13 +56,13 @@ namespace osu.Game.Screens.Ranking.Expanded
var topStatistics = new List<StatisticDisplay>
{
new AccuracyStatistic(score.Accuracy),
new ComboStatistic(score.MaxCombo, true),
new ComboStatistic(score.MaxCombo, !score.Statistics.TryGetValue(HitResult.Miss, out var missCount) || missCount == 0),
new CounterStatistic("pp", (int)(score.PP ?? 0)),
};
var bottomStatistics = new List<StatisticDisplay>();
foreach (var stat in score.SortedStatistics)
bottomStatistics.Add(new CounterStatistic(stat.Key.GetDescription(), stat.Value));
bottomStatistics.Add(new HitResultStatistic(stat.Key, stat.Value));
statisticDisplays.AddRange(topStatistics);
statisticDisplays.AddRange(bottomStatistics);
@ -204,6 +204,13 @@ namespace osu.Game.Screens.Ranking.Expanded
}
}
}
},
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Font = OsuFont.GetFont(size: 10, weight: FontWeight.SemiBold),
Text = $"Played on {score.Date.ToLocalTime():g}"
}
}
};

View File

@ -0,0 +1,27 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Game.Graphics;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Screens.Ranking.Expanded.Statistics
{
public class HitResultStatistic : CounterStatistic
{
private readonly HitResult result;
public HitResultStatistic(HitResult result, int count)
: base(result.GetDescription(), count)
{
this.result = result;
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
HeaderText.Colour = colours.ForHitResult(result);
}
}
}

View File

@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
@ -16,8 +17,9 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics
/// </summary>
public abstract class StatisticDisplay : CompositeDrawable
{
private readonly string header;
protected SpriteText HeaderText { get; private set; }
private readonly string header;
private Drawable content;
/// <summary>
@ -53,7 +55,7 @@ namespace osu.Game.Screens.Ranking.Expanded.Statistics
RelativeSizeAxes = Axes.Both,
Colour = Color4Extensions.FromHex("#222")
},
new OsuSpriteText
HeaderText = new OsuSpriteText
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
@ -135,7 +136,7 @@ namespace osu.Game.Screens.Ranking
protected override void Update()
{
base.Update();
content.Height = DrawHeight;
content.Height = Math.Max(768, DrawHeight);
}
}
}

View File

@ -14,7 +14,7 @@ using osuTK.Graphics;
namespace osu.Game.Tests.Visual
{
public abstract class ManualInputManagerTestScene : OsuTestScene
public abstract class OsuManualInputManagerTestScene : OsuTestScene
{
protected override Container<Drawable> Content => content;
private readonly Container content;
@ -24,7 +24,7 @@ namespace osu.Game.Tests.Visual
private readonly TriangleButton buttonTest;
private readonly TriangleButton buttonLocal;
protected ManualInputManagerTestScene()
protected OsuManualInputManagerTestScene()
{
base.Content.AddRange(new Drawable[]
{

View File

@ -11,7 +11,7 @@ namespace osu.Game.Tests.Visual
/// <summary>
/// A test case which can be used to test a screen (that relies on OnEntering being called to execute startup instructions).
/// </summary>
public abstract class ScreenTestScene : ManualInputManagerTestScene
public abstract class ScreenTestScene : OsuManualInputManagerTestScene
{
protected readonly OsuScreenStack Stack;

View File

@ -8,7 +8,7 @@ using osu.Game.Rulesets.Edit;
namespace osu.Game.Tests.Visual
{
public abstract class SelectionBlueprintTestScene : ManualInputManagerTestScene
public abstract class SelectionBlueprintTestScene : OsuManualInputManagerTestScene
{
protected override Container<Drawable> Content => content ?? base.Content;
private readonly Container content;

View File

@ -68,7 +68,7 @@ namespace osu.Game.Users.Drawables
if (!OpenOnClick.Value)
return;
if (user != null)
if (user?.Id > 1)
game?.ShowUser(user.Id);
}

View File

@ -23,7 +23,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
<PackageReference Include="ppy.osu.Framework" Version="2020.317.0" />
<PackageReference Include="ppy.osu.Framework" Version="2020.319.0" />
<PackageReference Include="Sentry" Version="2.1.0" />
<PackageReference Include="SharpCompress" Version="0.24.0" />
<PackageReference Include="NUnit" Version="3.12.0" />

View File

@ -71,7 +71,7 @@
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.315.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.317.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.319.0" />
</ItemGroup>
<!-- Xamarin.iOS does not automatically handle transitive dependencies from NuGet packages. -->
<ItemGroup Label="Transitive Dependencies">
@ -79,7 +79,7 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="ppy.osu.Framework" Version="2020.317.0" />
<PackageReference Include="ppy.osu.Framework" Version="2020.319.0" />
<PackageReference Include="SharpCompress" Version="0.24.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />