1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 10:33:30 +08:00

Merge branch 'master' into selectionRotation

This commit is contained in:
Grrum 2020-12-13 08:01:44 -05:00 committed by GitHub
commit 635608ee3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 139 additions and 100 deletions

View File

@ -52,6 +52,6 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1203.0" />
<PackageReference Include="ppy.osu.Framework.Android" Version="2020.1212.0" />
</ItemGroup>
</Project>

View File

@ -16,6 +16,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
public abstract class DrawableTaikoRulesetTestScene : OsuTestScene
{
protected const int DEFAULT_PLAYFIELD_CONTAINER_HEIGHT = 768;
protected DrawableTaikoRuleset DrawableRuleset { get; private set; }
protected Container PlayfieldContainer { get; private set; }
@ -44,10 +46,10 @@ namespace osu.Game.Rulesets.Taiko.Tests
Add(PlayfieldContainer = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.X,
Height = 768,
Height = DEFAULT_PLAYFIELD_CONTAINER_HEIGHT,
Children = new[] { DrawableRuleset = new DrawableTaikoRuleset(new TaikoRuleset(), beatmap.GetPlayableBeatmap(new TaikoRuleset().RulesetInfo)) }
});
}

View File

@ -13,12 +13,15 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
public readonly HitResult Type;
public DrawableTestHit(Hit hit, HitResult type = HitResult.Great)
public DrawableTestHit(Hit hit, HitResult type = HitResult.Great, bool kiai = false)
: base(hit)
{
Type = type;
HitObject.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
var controlPoints = new ControlPointInfo();
controlPoints.Add(0, new EffectControlPoint { KiaiMode = kiai });
HitObject.ApplyDefaults(controlPoints, new BeatmapDifficulty());
}
protected override void UpdateInitialTransforms()

View File

@ -2,14 +2,16 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Utils;
using osu.Game.Audio;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
using osu.Game.Rulesets.Taiko.Judgements;
using osu.Game.Rulesets.Taiko.Objects;
@ -97,7 +99,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
break;
case 6:
PlayfieldContainer.Delay(delay).ResizeTo(new Vector2(1, TaikoPlayfield.DEFAULT_HEIGHT), 500);
PlayfieldContainer.Delay(delay).ResizeTo(new Vector2(1, DEFAULT_PLAYFIELD_CONTAINER_HEIGHT), 500);
break;
}
}
@ -106,13 +108,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Ok : HitResult.Great;
var cpi = new ControlPointInfo();
cpi.Add(0, new EffectControlPoint { KiaiMode = kiai });
Hit hit = new Hit();
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
var h = new DrawableTestHit(hit, kiai: kiai) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
DrawableRuleset.Playfield.Add(h);
@ -123,25 +120,27 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
HitResult hitResult = RNG.Next(2) == 0 ? HitResult.Ok : HitResult.Great;
var cpi = new ControlPointInfo();
cpi.Add(0, new EffectControlPoint { KiaiMode = kiai });
Hit hit = new Hit();
hit.ApplyDefaults(cpi, new BeatmapDifficulty());
var h = new DrawableTestHit(hit) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
Hit hit = new Hit
{
IsStrong = true,
Samples = createSamples(strong: true)
};
var h = new DrawableTestHit(hit, kiai: kiai) { X = RNG.NextSingle(hitResult == HitResult.Ok ? -0.1f : -0.05f, hitResult == HitResult.Ok ? 0.1f : 0.05f) };
DrawableRuleset.Playfield.Add(h);
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = hitResult });
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(new TestStrongNestedHit(h), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great });
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h.NestedHitObjects.Single(), new JudgementResult(new HitObject(), new TaikoStrongJudgement()) { Type = HitResult.Great });
}
private void addMissJudgement()
{
DrawableTestHit h;
DrawableRuleset.Playfield.Add(h = new DrawableTestHit(new Hit(), HitResult.Miss));
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(new HitObject(), new TaikoJudgement()) { Type = HitResult.Miss });
DrawableRuleset.Playfield.Add(h = new DrawableTestHit(new Hit { StartTime = DrawableRuleset.Playfield.Time.Current }, HitResult.Miss)
{
Alpha = 0
});
((TaikoPlayfield)DrawableRuleset.Playfield).OnNewResult(h, new JudgementResult(h.HitObject, new TaikoJudgement()) { Type = HitResult.Miss });
}
private void addBarLine(bool major, double delay = scroll_time)
@ -173,6 +172,7 @@ namespace osu.Game.Rulesets.Taiko.Tests
{
StartTime = DrawableRuleset.Playfield.Time.Current + scroll_time,
IsStrong = strong,
Samples = createSamples(strong: strong),
Duration = duration,
TickRate = 8,
};
@ -190,7 +190,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
Hit h = new Hit
{
StartTime = DrawableRuleset.Playfield.Time.Current + scroll_time,
IsStrong = strong
IsStrong = strong,
Samples = createSamples(HitType.Centre, strong)
};
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
@ -203,7 +204,8 @@ namespace osu.Game.Rulesets.Taiko.Tests
Hit h = new Hit
{
StartTime = DrawableRuleset.Playfield.Time.Current + scroll_time,
IsStrong = strong
IsStrong = strong,
Samples = createSamples(HitType.Rim, strong)
};
h.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty());
@ -211,14 +213,18 @@ namespace osu.Game.Rulesets.Taiko.Tests
DrawableRuleset.Playfield.Add(new DrawableHit(h));
}
private class TestStrongNestedHit : DrawableStrongNestedHit
// TODO: can be removed if a better way of handling colour/strong type and samples is developed
private IList<HitSampleInfo> createSamples(HitType? hitType = null, bool strong = false)
{
public TestStrongNestedHit(DrawableHitObject mainObject)
: base(new StrongHitObject { StartTime = mainObject.HitObject.StartTime }, mainObject)
{
}
var samples = new List<HitSampleInfo>();
public override bool OnPressed(TaikoAction action) => false;
if (hitType == HitType.Rim)
samples.Add(new HitSampleInfo(HitSampleInfo.HIT_CLAP));
if (strong)
samples.Add(new HitSampleInfo(HitSampleInfo.HIT_FINISH));
return samples;
}
}
}

View File

@ -95,6 +95,16 @@ namespace osu.Game.Screens.Play
localGameplayClock = new LocalGameplayClock(userOffsetClock);
GameplayClock.IsPaused.BindTo(IsPaused);
IsPaused.BindValueChanged(onPauseChanged);
}
private void onPauseChanged(ValueChangedEvent<bool> isPaused)
{
if (isPaused.NewValue)
this.TransformBindableTo(pauseFreqAdjust, 0, 200, Easing.Out).OnComplete(_ => adjustableClock.Stop());
else
this.TransformBindableTo(pauseFreqAdjust, 1, 200, Easing.In);
}
private double totalOffset => userOffsetClock.Offset + platformOffsetClock.Offset;
@ -154,13 +164,16 @@ namespace osu.Game.Screens.Play
public void Start()
{
// Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time
// This accounts for the audio clock source potentially taking time to enter a completely stopped state
Seek(GameplayClock.CurrentTime);
adjustableClock.Start();
IsPaused.Value = false;
if (!adjustableClock.IsRunning)
{
// Seeking the decoupled clock to its current time ensures that its source clock will be seeked to the same time
// This accounts for the audio clock source potentially taking time to enter a completely stopped state
Seek(GameplayClock.CurrentTime);
this.TransformBindableTo(pauseFreqAdjust, 1, 200, Easing.In);
adjustableClock.Start();
}
IsPaused.Value = false;
}
/// <summary>
@ -199,8 +212,6 @@ namespace osu.Game.Screens.Play
public void Stop()
{
this.TransformBindableTo(pauseFreqAdjust, 0, 200, Easing.Out).OnComplete(_ => adjustableClock.Stop());
IsPaused.Value = true;
}

View File

@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using JetBrains.Annotations;
@ -71,8 +72,9 @@ namespace osu.Game.Screens.Play
}
private bool readyForPush =>
!playerConsumed
// don't push unless the player is completely loaded
player?.LoadState == LoadState.Ready
&& player?.LoadState == LoadState.Ready
// don't push if the user is hovering one of the panes, unless they are idle.
&& (IsHovered || idleTracker.IsIdle.Value)
// don't push if the user is dragging a slider or otherwise.
@ -84,6 +86,11 @@ namespace osu.Game.Screens.Play
private Player player;
/// <summary>
/// Whether the curent player instance has been consumed via <see cref="consumePlayer"/>.
/// </summary>
private bool playerConsumed;
private LogoTrackingContainer content;
private bool hideOverlays;
@ -179,7 +186,10 @@ namespace osu.Game.Screens.Play
contentIn();
MetadataInfo.Delay(750).FadeIn(500);
this.Delay(1800).Schedule(pushWhenLoaded);
// after an initial delay, start the debounced load check.
// this will continue to execute even after resuming back on restart.
Scheduler.Add(new ScheduledDelegate(pushWhenLoaded, 1800, 0));
showMuteWarningIfNeeded();
}
@ -188,17 +198,18 @@ namespace osu.Game.Screens.Play
{
base.OnResuming(last);
contentIn();
// prepare for a retry.
player = null;
playerConsumed = false;
cancelLoad();
this.Delay(400).Schedule(pushWhenLoaded);
contentIn();
}
public override void OnSuspending(IScreen next)
{
base.OnSuspending(next);
cancelLoad();
BackgroundBrightnessReduction = false;
// we're moving to player, so a period of silence is upcoming.
@ -274,6 +285,14 @@ namespace osu.Game.Screens.Play
}
}
private Player consumePlayer()
{
Debug.Assert(!playerConsumed);
playerConsumed = true;
return player;
}
private void prepareNewPlayer()
{
if (!this.IsCurrentScreen())
@ -315,64 +334,62 @@ namespace osu.Game.Screens.Play
{
if (!this.IsCurrentScreen()) return;
try
if (!readyForPush)
{
if (!readyForPush)
// as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce
// if we become unready for push during the delay.
cancelLoad();
return;
}
// if a push has already been scheduled, no further action is required.
// this value is reset via cancelLoad() to allow a second usage of the same PlayerLoader screen.
if (scheduledPushPlayer != null)
return;
scheduledPushPlayer = Scheduler.AddDelayed(() =>
{
// ensure that once we have reached this "point of no return", readyForPush will be false for all future checks (until a new player instance is prepared).
var consumedPlayer = consumePlayer();
contentOut();
TransformSequence<PlayerLoader> pushSequence = this.Delay(250);
// only show if the warning was created (i.e. the beatmap needs it)
// and this is not a restart of the map (the warning expires after first load).
if (epilepsyWarning?.IsAlive == true)
{
// as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce
// if we become unready for push during the delay.
cancelLoad();
return;
const double epilepsy_display_length = 3000;
pushSequence
.Schedule(() => epilepsyWarning.State.Value = Visibility.Visible)
.TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint)
.Delay(epilepsy_display_length)
.Schedule(() =>
{
epilepsyWarning.Hide();
epilepsyWarning.Expire();
})
.Delay(EpilepsyWarning.FADE_DURATION);
}
if (scheduledPushPlayer != null)
return;
scheduledPushPlayer = Scheduler.AddDelayed(() =>
pushSequence.Schedule(() =>
{
contentOut();
if (!this.IsCurrentScreen()) return;
TransformSequence<PlayerLoader> pushSequence = this.Delay(250);
LoadTask = null;
// only show if the warning was created (i.e. the beatmap needs it)
// and this is not a restart of the map (the warning expires after first load).
if (epilepsyWarning?.IsAlive == true)
{
const double epilepsy_display_length = 3000;
// By default, we want to load the player and never be returned to.
// Note that this may change if the player we load requested a re-run.
ValidForResume = false;
pushSequence
.Schedule(() => epilepsyWarning.State.Value = Visibility.Visible)
.TransformBindableTo(volumeAdjustment, 0.25, EpilepsyWarning.FADE_DURATION, Easing.OutQuint)
.Delay(epilepsy_display_length)
.Schedule(() =>
{
epilepsyWarning.Hide();
epilepsyWarning.Expire();
})
.Delay(EpilepsyWarning.FADE_DURATION);
}
pushSequence.Schedule(() =>
{
if (!this.IsCurrentScreen()) return;
LoadTask = null;
// By default, we want to load the player and never be returned to.
// Note that this may change if the player we load requested a re-run.
ValidForResume = false;
if (player.LoadedBeatmapSuccessfully)
this.Push(player);
else
this.Exit();
});
}, 500);
}
finally
{
Schedule(pushWhenLoaded);
}
if (consumedPlayer.LoadedBeatmapSuccessfully)
this.Push(consumedPlayer);
else
this.Exit();
});
}, 500);
}
private void cancelLoad()
@ -390,7 +407,7 @@ namespace osu.Game.Screens.Play
if (isDisposing)
{
// if the player never got pushed, we should explicitly dispose it.
DisposalTask = LoadTask?.ContinueWith(_ => player.Dispose());
DisposalTask = LoadTask?.ContinueWith(_ => player?.Dispose());
}
}

View File

@ -26,7 +26,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.1203.0" />
<PackageReference Include="ppy.osu.Framework" Version="2020.1212.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
<PackageReference Include="Sentry" Version="2.1.8" />
<PackageReference Include="SharpCompress" Version="0.26.0" />

View File

@ -70,7 +70,7 @@
<Reference Include="System.Net.Http" />
</ItemGroup>
<ItemGroup Label="Package References">
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1203.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2020.1212.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2020.1202.0" />
</ItemGroup>
<!-- See https://github.com/dotnet/runtime/issues/35988 (can be removed after Xamarin uses net5.0 / net6.0) -->
@ -88,7 +88,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.1203.0" />
<PackageReference Include="ppy.osu.Framework" Version="2020.1212.0" />
<PackageReference Include="SharpCompress" Version="0.26.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />