1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-08 03:12:57 +08:00

Merge branch 'master' into fix-perfect-judgements

This commit is contained in:
Bartłomiej Dach 2020-03-08 14:06:18 +01:00
commit d5dda05d98
25 changed files with 234 additions and 85 deletions

View File

@ -52,6 +52,6 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.304.0" /> <PackageReference Include="ppy.osu.Game.Resources" Version="2020.304.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.302.0" /> <PackageReference Include="ppy.osu.Framework.Android" Version="2020.305.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,35 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Utils;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Tests.Visual;
namespace osu.Game.Rulesets.Osu.Tests.Mods
{
public class TestSceneOsuModDoubleTime : ModTestScene
{
public TestSceneOsuModDoubleTime()
: base(new OsuRuleset())
{
}
[TestCase(0.5)]
[TestCase(1.01)]
[TestCase(1.5)]
[TestCase(2)]
[TestCase(5)]
public void TestSpeedChangeCustomisation(double rate)
{
var mod = new OsuModDoubleTime { SpeedChange = { Value = rate } };
CreateModTest(new ModTestData
{
Mod = mod,
PassCondition = () => Player.ScoreProcessor.JudgedHits >= 2 &&
Precision.AlmostEquals(Player.GameplayClockContainer.GameplayClock.Rate, mod.SpeedChange.Value)
});
}
}
}

View File

@ -0,0 +1,108 @@
// 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 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 osuTK;
namespace osu.Game.Rulesets.Osu.Tests
{
public class TestSceneHitCircleArea : ManualInputManagerTestScene
{
private HitCircle hitCircle;
private DrawableHitCircle drawableHitCircle;
private DrawableHitCircle.HitReceptor hitAreaReceptor => drawableHitCircle.HitArea;
[SetUp]
public new void SetUp()
{
base.SetUp();
Schedule(() =>
{
hitCircle = new HitCircle
{
Position = new Vector2(100, 100),
StartTime = Time.Current + 500
};
hitCircle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
Child = new SkinProvidingContainer(new DefaultSkin())
{
RelativeSizeAxes = Axes.Both,
Child = drawableHitCircle = new DrawableHitCircle(hitCircle)
{
Size = new Vector2(100)
}
};
});
}
[Test]
public void TestCircleHitCentre()
{
AddStep("move mouse to centre", () => InputManager.MoveMouseTo(hitAreaReceptor.ScreenSpaceDrawQuad.Centre));
scheduleHit();
AddAssert("hit registered", () => hitAreaReceptor.HitAction == OsuAction.LeftButton);
}
[Test]
public void TestCircleHitLeftEdge()
{
AddStep("move mouse to left edge", () =>
{
var drawQuad = hitAreaReceptor.ScreenSpaceDrawQuad;
var mousePosition = new Vector2(drawQuad.TopLeft.X, drawQuad.Centre.Y);
InputManager.MoveMouseTo(mousePosition);
});
scheduleHit();
AddAssert("hit registered", () => hitAreaReceptor.HitAction == OsuAction.LeftButton);
}
[TestCase(0.95f, OsuAction.LeftButton)]
[TestCase(1.05f, null)]
public void TestHitsCloseToEdge(float relativeDistanceFromCentre, OsuAction? expectedAction)
{
AddStep("move mouse to top left circle edge", () =>
{
var drawQuad = hitAreaReceptor.ScreenSpaceDrawQuad;
// sqrt(2) / 2 = sin(45deg) = cos(45deg)
// draw width halved to get radius
float correction = relativeDistanceFromCentre * (float)Math.Sqrt(2) / 2 * (drawQuad.Width / 2);
var mousePosition = new Vector2(drawQuad.Centre.X - correction, drawQuad.Centre.Y - correction);
InputManager.MoveMouseTo(mousePosition);
});
scheduleHit();
AddAssert($"hit {(expectedAction == null ? "not " : string.Empty)}registered", () => hitAreaReceptor.HitAction == expectedAction);
}
[Test]
public void TestCircleMissBoundingBoxCorner()
{
AddStep("move mouse to top left corner of bounding box", () => InputManager.MoveMouseTo(hitAreaReceptor.ScreenSpaceDrawQuad.TopLeft));
scheduleHit();
AddAssert("hit not registered", () => hitAreaReceptor.HitAction == null);
}
private void scheduleHit() => AddStep("schedule action", () =>
{
var delay = hitCircle.StartTime - hitCircle.HitWindows.WindowFor(HitResult.Great) - Time.Current;
Scheduler.AddDelayed(() => hitAreaReceptor.OnPressed(OsuAction.LeftButton), delay);
});
}
}

View File

@ -170,7 +170,7 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
public Drawable ProxiedLayer => ApproachCircle; public Drawable ProxiedLayer => ApproachCircle;
public class HitReceptor : Drawable, IKeyBindingHandler<OsuAction> public class HitReceptor : CompositeDrawable, IKeyBindingHandler<OsuAction>
{ {
// IsHovered is used // IsHovered is used
public override bool HandlePositionalInput => true; public override bool HandlePositionalInput => true;
@ -185,6 +185,9 @@ namespace osu.Game.Rulesets.Osu.Objects.Drawables
Anchor = Anchor.Centre; Anchor = Anchor.Centre;
Origin = Anchor.Centre; Origin = Anchor.Centre;
CornerRadius = OsuHitObject.OBJECT_RADIUS;
CornerExponent = 2;
} }
public bool OnPressed(OsuAction action) public bool OnPressed(OsuAction action)

View File

@ -3,10 +3,8 @@
using System.ComponentModel; using System.ComponentModel;
using System.Linq; using System.Linq;
using osu.Game.Beatmaps;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Play; using osu.Game.Screens.Play;
using osu.Game.Storyboards;
namespace osu.Game.Tests.Visual.Gameplay namespace osu.Game.Tests.Visual.Gameplay
{ {
@ -15,8 +13,6 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
protected new TestPlayer Player => (TestPlayer)base.Player; protected new TestPlayer Player => (TestPlayer)base.Player;
private ClockBackedTestWorkingBeatmap.TrackVirtualManual track;
protected override Player CreatePlayer(Ruleset ruleset) protected override Player CreatePlayer(Ruleset ruleset)
{ {
SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray(); SelectedMods.Value = SelectedMods.Value.Concat(new[] { ruleset.GetAutoplayMod() }).ToArray();
@ -27,17 +23,12 @@ namespace osu.Game.Tests.Visual.Gameplay
{ {
AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0); AddUntilStep("score above zero", () => Player.ScoreProcessor.TotalScore.Value > 0);
AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2)); AddUntilStep("key counter counted keys", () => Player.HUDOverlay.KeyCounter.Children.Any(kc => kc.CountPresses > 2));
AddStep("rewind", () => track.Seek(-10000)); AddStep("seek to break time", () => Player.GameplayClockContainer.Seek(Player.BreakOverlay.Breaks.First().StartTime));
AddUntilStep("wait for seek to complete", () =>
Player.HUDOverlay.Progress.ReferenceClock.CurrentTime >= Player.BreakOverlay.Breaks.First().StartTime);
AddAssert("test keys not counting", () => !Player.HUDOverlay.KeyCounter.IsCounting);
AddStep("rewind", () => Player.GameplayClockContainer.Seek(-80000));
AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0)); AddUntilStep("key counter reset", () => Player.HUDOverlay.KeyCounter.Children.All(kc => kc.CountPresses == 0));
} }
protected override WorkingBeatmap CreateWorkingBeatmap(IBeatmap beatmap, Storyboard storyboard = null)
{
var working = base.CreateWorkingBeatmap(beatmap, storyboard);
track = (ClockBackedTestWorkingBeatmap.TrackVirtualManual)working.Track;
return working;
}
} }
} }

View File

@ -47,21 +47,22 @@ namespace osu.Game.Tests.Visual.Gameplay
Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key; Key testKey = ((KeyCounterKeyboard)kc.Children.First()).Key;
AddStep($"Press {testKey} key", () => void addPressKeyStep()
{ {
InputManager.PressKey(testKey); AddStep($"Press {testKey} key", () =>
InputManager.ReleaseKey(testKey); {
}); InputManager.PressKey(testKey);
InputManager.ReleaseKey(testKey);
});
}
addPressKeyStep();
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1); AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 1);
addPressKeyStep();
AddStep($"Press {testKey} key", () =>
{
InputManager.PressKey(testKey);
InputManager.ReleaseKey(testKey);
});
AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2); AddAssert($"Check {testKey} counter after keypress", () => testCounter.CountPresses == 2);
AddStep("Disable counting", () => testCounter.IsCounting = false);
addPressKeyStep();
AddAssert($"Check {testKey} count has not changed", () => testCounter.CountPresses == 2);
Add(kc); Add(kc);
} }

View File

@ -1,12 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System.IO; using osu.Framework.Allocation;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Video; using osu.Framework.Graphics.Video;
using osu.Framework.Platform;
using osu.Framework.Timing; using osu.Framework.Timing;
using osu.Game.Graphics; using osu.Game.Graphics;
@ -14,21 +15,24 @@ namespace osu.Game.Tournament.Components
{ {
public class TourneyVideo : CompositeDrawable public class TourneyVideo : CompositeDrawable
{ {
private readonly VideoSprite video; private readonly string filename;
private readonly bool drawFallbackGradient;
private VideoSprite video;
private readonly ManualClock manualClock; private ManualClock manualClock;
public TourneyVideo(Stream stream) public TourneyVideo(string filename, bool drawFallbackGradient = false)
{ {
if (stream == null) this.filename = filename;
{ this.drawFallbackGradient = drawFallbackGradient;
InternalChild = new Box }
{
Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.3f), OsuColour.Gray(0.6f)), [BackgroundDependencyLoader]
RelativeSizeAxes = Axes.Both, private void load(Storage storage)
}; {
} var stream = storage.GetStream($@"videos/{filename}.m4v");
else
if (stream != null)
{ {
InternalChild = video = new VideoSprite(stream) InternalChild = video = new VideoSprite(stream)
{ {
@ -37,6 +41,14 @@ namespace osu.Game.Tournament.Components
Clock = new FramedClock(manualClock = new ManualClock()) Clock = new FramedClock(manualClock = new ManualClock())
}; };
} }
else if (drawFallbackGradient)
{
InternalChild = new Box
{
Colour = ColourInfo.GradientVertical(OsuColour.Gray(0.3f), OsuColour.Gray(0.6f)),
RelativeSizeAxes = Axes.Both,
};
}
} }
public bool Loop public bool Loop

View File

@ -129,8 +129,6 @@ namespace osu.Game.Tournament.Screens.Editors
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
LayoutDuration = 200,
LayoutEasing = Easing.OutQuint,
ChildrenEnumerable = round.Beatmaps.Select(p => new RoundBeatmapRow(round, p)) ChildrenEnumerable = round.Beatmaps.Select(p => new RoundBeatmapRow(round, p))
}; };
} }

View File

@ -124,8 +124,6 @@ namespace osu.Game.Tournament.Screens.Editors
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
LayoutDuration = 200,
LayoutEasing = Easing.OutQuint,
ChildrenEnumerable = round.Beatmaps.Select(p => new SeedingBeatmapRow(round, p)) ChildrenEnumerable = round.Beatmaps.Select(p => new SeedingBeatmapRow(round, p))
}; };
} }

View File

@ -202,8 +202,6 @@ namespace osu.Game.Tournament.Screens.Editors
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
LayoutDuration = 200,
LayoutEasing = Easing.OutQuint,
ChildrenEnumerable = team.Players.Select(p => new PlayerRow(team, p)) ChildrenEnumerable = team.Players.Select(p => new PlayerRow(team, p))
}; };
} }

View File

@ -48,8 +48,6 @@ namespace osu.Game.Tournament.Screens.Editors
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
RelativeSizeAxes = Axes.X, RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y, AutoSizeAxes = Axes.Y,
LayoutDuration = 200,
LayoutEasing = Easing.OutQuint,
Spacing = new Vector2(20) Spacing = new Vector2(20)
}, },
}, },

View File

@ -6,6 +6,7 @@ using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Shapes;
using osu.Framework.Platform;
using osu.Framework.Threading; using osu.Framework.Threading;
using osu.Game.Graphics.UserInterface; using osu.Game.Graphics.UserInterface;
using osu.Game.Tournament.Components; using osu.Game.Tournament.Components;
@ -19,7 +20,7 @@ using osuTK.Graphics;
namespace osu.Game.Tournament.Screens.Gameplay namespace osu.Game.Tournament.Screens.Gameplay
{ {
public class GameplayScreen : BeatmapInfoScreen public class GameplayScreen : BeatmapInfoScreen, IProvideVideo
{ {
private readonly BindableBool warmup = new BindableBool(); private readonly BindableBool warmup = new BindableBool();
@ -39,12 +40,17 @@ namespace osu.Game.Tournament.Screens.Gameplay
private TournamentMatchChatDisplay chat { get; set; } private TournamentMatchChatDisplay chat { get; set; }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load(LadderInfo ladder, MatchIPCInfo ipc) private void load(LadderInfo ladder, MatchIPCInfo ipc, Storage storage)
{ {
this.ipc = ipc; this.ipc = ipc;
AddRangeInternal(new Drawable[] AddRangeInternal(new Drawable[]
{ {
new TourneyVideo("gameplay")
{
Loop = true,
RelativeSizeAxes = Axes.Both,
},
new MatchHeader(), new MatchHeader(),
new Container new Container
{ {

View File

@ -42,7 +42,7 @@ namespace osu.Game.Tournament.Screens.Ladder
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Children = new Drawable[] Children = new Drawable[]
{ {
new TourneyVideo(storage.GetStream(@"videos/ladder.m4v")) new TourneyVideo("ladder")
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Loop = true, Loop = true,

View File

@ -18,7 +18,7 @@ using osuTK.Graphics;
namespace osu.Game.Tournament.Screens.Schedule namespace osu.Game.Tournament.Screens.Schedule
{ {
public class ScheduleScreen : TournamentScreen, IProvideVideo public class ScheduleScreen : TournamentScreen
{ {
private readonly Bindable<TournamentMatch> currentMatch = new Bindable<TournamentMatch>(); private readonly Bindable<TournamentMatch> currentMatch = new Bindable<TournamentMatch>();
private Container mainContainer; private Container mainContainer;
@ -33,7 +33,7 @@ namespace osu.Game.Tournament.Screens.Schedule
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new TourneyVideo(storage.GetStream(@"videos/schedule.m4v")) new TourneyVideo("schedule")
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Loop = true, Loop = true,

View File

@ -34,7 +34,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new TourneyVideo(storage.GetStream(@"videos/seeding.m4v")) new TourneyVideo("seeding")
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Loop = true, Loop = true,

View File

@ -26,7 +26,7 @@ namespace osu.Game.Tournament.Screens.TeamIntro
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
new TourneyVideo(storage.GetStream(@"videos/teamintro.m4v")) new TourneyVideo("teamintro")
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Loop = true, Loop = true,

View File

@ -31,13 +31,13 @@ namespace osu.Game.Tournament.Screens.TeamWin
InternalChildren = new Drawable[] InternalChildren = new Drawable[]
{ {
blueWinVideo = new TourneyVideo(storage.GetStream(@"videos/teamwin-blue.m4v")) blueWinVideo = new TourneyVideo("teamwin-blue")
{ {
Alpha = 1, Alpha = 1,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Loop = true, Loop = true,
}, },
redWinVideo = new TourneyVideo(storage.GetStream(@"videos/teamwin-red.m4v")) redWinVideo = new TourneyVideo("teamwin-red")
{ {
Alpha = 0, Alpha = 0,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,

View File

@ -18,6 +18,9 @@ namespace osu.Game.Tournament.Screens
protected TournamentScreen() protected TournamentScreen()
{ {
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
FillMode = FillMode.Fit;
FillAspectRatio = 16 / 9f;
} }
public override void Hide() => this.FadeOut(FADE_DELAY); public override void Hide() => this.FadeOut(FADE_DELAY);

View File

@ -61,7 +61,7 @@ namespace osu.Game.Tournament
//Masking = true, //Masking = true,
Children = new Drawable[] Children = new Drawable[]
{ {
video = new TourneyVideo(storage.GetStream("videos/main.m4v")) video = new TourneyVideo("main", true)
{ {
Loop = true, Loop = true,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,

View File

@ -184,7 +184,7 @@ namespace osu.Game.Screens.Play
foreach (var mod in Mods.Value.OfType<IApplicableToHealthProcessor>()) foreach (var mod in Mods.Value.OfType<IApplicableToHealthProcessor>())
mod.ApplyToHealthProcessor(HealthProcessor); mod.ApplyToHealthProcessor(HealthProcessor);
BreakOverlay.IsBreakTime.ValueChanged += _ => updatePauseOnFocusLostState(); BreakOverlay.IsBreakTime.BindValueChanged(onBreakTimeChanged, true);
} }
private void addUnderlayComponents(Container target) private void addUnderlayComponents(Container target)
@ -229,7 +229,11 @@ namespace osu.Game.Screens.Play
IsPaused = { BindTarget = GameplayClockContainer.IsPaused } IsPaused = { BindTarget = GameplayClockContainer.IsPaused }
}, },
PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = GameplayClockContainer.UserPlaybackRate } } }, PlayerSettingsOverlay = { PlaybackSettings = { UserPlaybackRate = { BindTarget = GameplayClockContainer.UserPlaybackRate } } },
KeyCounter = { AlwaysVisible = { BindTarget = DrawableRuleset.HasReplayLoaded } }, KeyCounter =
{
AlwaysVisible = { BindTarget = DrawableRuleset.HasReplayLoaded },
IsCounting = false
},
RequestSeek = GameplayClockContainer.Seek, RequestSeek = GameplayClockContainer.Seek,
Anchor = Anchor.Centre, Anchor = Anchor.Centre,
Origin = Anchor.Centre Origin = Anchor.Centre
@ -286,6 +290,12 @@ namespace osu.Game.Screens.Play
HealthProcessor.IsBreakTime.BindTo(BreakOverlay.IsBreakTime); HealthProcessor.IsBreakTime.BindTo(BreakOverlay.IsBreakTime);
} }
private void onBreakTimeChanged(ValueChangedEvent<bool> isBreakTime)
{
updatePauseOnFocusLostState();
HUDOverlay.KeyCounter.IsCounting = !isBreakTime.NewValue;
}
private void updatePauseOnFocusLostState() => private void updatePauseOnFocusLostState() =>
HUDOverlay.HoldToQuit.PauseOnFocusLost = PauseOnFocusLost HUDOverlay.HoldToQuit.PauseOnFocusLost = PauseOnFocusLost
&& !DrawableRuleset.HasReplayLoaded.Value && !DrawableRuleset.HasReplayLoaded.Value

View File

@ -116,7 +116,7 @@ namespace osu.Game.Screens.Play
{ {
base.Update(); base.Update();
var progress = Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime)); var progress = fadeOutBeginTime <= displayTime ? 1 : Math.Max(0, 1 - (gameplayClock.CurrentTime - displayTime) / (fadeOutBeginTime - displayTime));
remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1)); remainingTimeBox.Width = (float)Interpolation.Lerp(remainingTimeBox.Width, progress, Math.Clamp(Time.Elapsed / 40, 0, 1));

View File

@ -231,15 +231,8 @@ namespace osu.Game.Tests.Visual
{ {
private readonly IFrameBasedClock referenceClock; private readonly IFrameBasedClock referenceClock;
private readonly ManualClock clock = new ManualClock();
private bool running; private bool running;
/// <summary>
/// Local offset added to the reference clock to resolve correct time.
/// </summary>
private double offset;
public TrackVirtualManual(IFrameBasedClock referenceClock) public TrackVirtualManual(IFrameBasedClock referenceClock)
{ {
this.referenceClock = referenceClock; this.referenceClock = referenceClock;
@ -248,10 +241,10 @@ namespace osu.Game.Tests.Visual
public override bool Seek(double seek) public override bool Seek(double seek)
{ {
offset = Math.Clamp(seek, 0, Length); accumulated = Math.Clamp(seek, 0, Length);
lastReferenceTime = null; lastReferenceTime = null;
return offset == seek; return accumulated == seek;
} }
public override void Start() public override void Start()
@ -270,9 +263,6 @@ namespace osu.Game.Tests.Visual
if (running) if (running)
{ {
running = false; running = false;
// on stopping, the current value should be transferred out of the clock, as we can no longer rely on
// the referenceClock (which will still be counting time).
offset = clock.CurrentTime;
lastReferenceTime = null; lastReferenceTime = null;
} }
} }
@ -281,7 +271,9 @@ namespace osu.Game.Tests.Visual
private double? lastReferenceTime; private double? lastReferenceTime;
public override double CurrentTime => clock.CurrentTime; private double accumulated;
public override double CurrentTime => Math.Min(accumulated, Length);
protected override void UpdateState() protected override void UpdateState()
{ {
@ -291,18 +283,12 @@ namespace osu.Game.Tests.Visual
{ {
double refTime = referenceClock.CurrentTime; double refTime = referenceClock.CurrentTime;
if (!lastReferenceTime.HasValue) if (lastReferenceTime.HasValue)
{ accumulated += (refTime - lastReferenceTime.Value) * Rate;
// if the clock just started running, the current value should be transferred to the offset
// (to zero the progression of time).
offset -= refTime;
}
lastReferenceTime = refTime; lastReferenceTime = refTime;
} }
clock.CurrentTime = Math.Min((lastReferenceTime ?? 0) + offset, Length);
if (CurrentTime >= Length) if (CurrentTime >= Length)
{ {
Stop(); Stop();

View File

@ -43,6 +43,8 @@ namespace osu.Game.Users.Drawables
set => base.EdgeEffect = value; set => base.EdgeEffect = value;
} }
protected override double LoadDelay => 200;
/// <summary> /// <summary>
/// Whether to show a default guest representation on null user (as opposed to nothing). /// Whether to show a default guest representation on null user (as opposed to nothing).
/// </summary> /// </summary>

View File

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

View File

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