mirror of
https://github.com/ppy/osu.git
synced 2025-02-13 16:02:58 +08:00
Merge remote-tracking branch 'ppy/master' into fix-skin-performance
This commit is contained in:
commit
0d817e8e98
@ -1 +1 @@
|
|||||||
Subproject commit e8ae207769ec26fb7ddd67a2433514fcda354ecd
|
Subproject commit 71900dc350bcebbb60d912d4023a1d2a6bbbc3c1
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
// Copyright (c) 2007-2018 ppy Pty Ltd <contact@ppy.sh>.
|
||||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
@ -26,7 +27,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5));
|
SpinsRequired = (int)(Duration / 1000 * BeatmapDifficulty.DifficultyRange(difficulty.OverallDifficulty, 3, 5, 7.5));
|
||||||
|
|
||||||
// spinning doesn't match 1:1 with stable, so let's fudge them easier for the time being.
|
// spinning doesn't match 1:1 with stable, so let's fudge them easier for the time being.
|
||||||
SpinsRequired = (int)(SpinsRequired * 0.6);
|
SpinsRequired = (int)Math.Max(1, SpinsRequired * 0.6);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDecodeBeatmapGeneral()
|
public void TestDecodeBeatmapGeneral()
|
||||||
{
|
{
|
||||||
var decoder = new LegacyBeatmapDecoder();
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||||
using (var stream = new StreamReader(resStream))
|
using (var stream = new StreamReader(resStream))
|
||||||
{
|
{
|
||||||
@ -110,7 +110,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDecodeBeatmapEvents()
|
public void TestDecodeBeatmapEvents()
|
||||||
{
|
{
|
||||||
var decoder = new LegacyBeatmapDecoder();
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||||
using (var stream = new StreamReader(resStream))
|
using (var stream = new StreamReader(resStream))
|
||||||
{
|
{
|
||||||
@ -128,7 +128,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDecodeBeatmapTimingPoints()
|
public void TestDecodeBeatmapTimingPoints()
|
||||||
{
|
{
|
||||||
var decoder = new LegacyBeatmapDecoder();
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||||
using (var stream = new StreamReader(resStream))
|
using (var stream = new StreamReader(resStream))
|
||||||
{
|
{
|
||||||
@ -187,7 +187,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
[Test]
|
[Test]
|
||||||
public void TestDecodeBeatmapHitObjects()
|
public void TestDecodeBeatmapHitObjects()
|
||||||
{
|
{
|
||||||
var decoder = new LegacyBeatmapDecoder();
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
using (var resStream = Resource.OpenResource("Soleily - Renatus (Gamu) [Insane].osu"))
|
||||||
using (var stream = new StreamReader(resStream))
|
using (var stream = new StreamReader(resStream))
|
||||||
{
|
{
|
||||||
|
@ -159,7 +159,7 @@ namespace osu.Game.Tests.Beatmaps.Formats
|
|||||||
using (var sr = new StreamReader(stream))
|
using (var sr = new StreamReader(stream))
|
||||||
{
|
{
|
||||||
|
|
||||||
var legacyDecoded = new LegacyBeatmapDecoder().DecodeBeatmap(sr);
|
var legacyDecoded = new LegacyBeatmapDecoder { ApplyOffsets = false }.DecodeBeatmap(sr);
|
||||||
using (var ms = new MemoryStream())
|
using (var ms = new MemoryStream())
|
||||||
using (var sw = new StreamWriter(ms))
|
using (var sw = new StreamWriter(ms))
|
||||||
using (var sr2 = new StreamReader(ms))
|
using (var sr2 = new StreamReader(ms))
|
||||||
|
@ -58,7 +58,7 @@ namespace osu.Game.Tests.Beatmaps.IO
|
|||||||
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
Assert.AreEqual("03. Renatus - Soleily 192kbps.mp3", meta.AudioFile);
|
||||||
Assert.AreEqual("Deif", meta.AuthorString);
|
Assert.AreEqual("Deif", meta.AuthorString);
|
||||||
Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile);
|
Assert.AreEqual("machinetop_background.jpg", meta.BackgroundFile);
|
||||||
Assert.AreEqual(164471, meta.PreviewTime);
|
Assert.AreEqual(164471 + LegacyBeatmapDecoder.UniversalOffset, meta.PreviewTime);
|
||||||
Assert.AreEqual(string.Empty, meta.Source);
|
Assert.AreEqual(string.Empty, meta.Source);
|
||||||
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags);
|
Assert.AreEqual("MBC7 Unisphere 地球ヤバイEP Chikyu Yabai", meta.Tags);
|
||||||
Assert.AreEqual("Renatus", meta.Title);
|
Assert.AreEqual("Renatus", meta.Title);
|
||||||
|
@ -8,6 +8,7 @@ using OpenTK.Graphics;
|
|||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Rulesets.Objects.Legacy;
|
using osu.Game.Rulesets.Objects.Legacy;
|
||||||
using osu.Game.Beatmaps.ControlPoints;
|
using osu.Game.Beatmaps.ControlPoints;
|
||||||
|
using osu.Framework;
|
||||||
|
|
||||||
namespace osu.Game.Beatmaps.Formats
|
namespace osu.Game.Beatmaps.Formats
|
||||||
{
|
{
|
||||||
@ -21,6 +22,19 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
private LegacySampleBank defaultSampleBank;
|
private LegacySampleBank defaultSampleBank;
|
||||||
private int defaultSampleVolume = 100;
|
private int defaultSampleVolume = 100;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// lazer's audio timings in general doesn't match stable. this is the result of user testing, albeit limited.
|
||||||
|
/// This only seems to be required on windows. We need to eventually figure out why, with a bit of luck.
|
||||||
|
/// </summary>
|
||||||
|
public static int UniversalOffset => RuntimeInfo.OS == RuntimeInfo.Platform.Windows ? -22 : 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not beatmap or runtime offsets should be applied. Defaults on; only disable for testing purposes.
|
||||||
|
/// </summary>
|
||||||
|
public bool ApplyOffsets = true;
|
||||||
|
|
||||||
|
private readonly int offset = UniversalOffset;
|
||||||
|
|
||||||
public LegacyBeatmapDecoder()
|
public LegacyBeatmapDecoder()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -28,6 +42,9 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
public LegacyBeatmapDecoder(string header)
|
public LegacyBeatmapDecoder(string header)
|
||||||
{
|
{
|
||||||
BeatmapVersion = int.Parse(header.Substring(17));
|
BeatmapVersion = int.Parse(header.Substring(17));
|
||||||
|
|
||||||
|
// BeatmapVersion 4 and lower had an incorrect offset (stable has this set as 24ms off)
|
||||||
|
offset += BeatmapVersion < 5 ? 24 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap)
|
protected override void ParseBeatmap(StreamReader stream, Beatmap beatmap)
|
||||||
@ -102,7 +119,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value);
|
beatmap.BeatmapInfo.AudioLeadIn = int.Parse(pair.Value);
|
||||||
break;
|
break;
|
||||||
case @"PreviewTime":
|
case @"PreviewTime":
|
||||||
metadata.PreviewTime = int.Parse(pair.Value);
|
metadata.PreviewTime = getOffsetTime(int.Parse(pair.Value));
|
||||||
break;
|
break;
|
||||||
case @"Countdown":
|
case @"Countdown":
|
||||||
beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1;
|
beatmap.BeatmapInfo.Countdown = int.Parse(pair.Value) == 1;
|
||||||
@ -257,8 +274,8 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
case EventType.Break:
|
case EventType.Break:
|
||||||
var breakEvent = new BreakPeriod
|
var breakEvent = new BreakPeriod
|
||||||
{
|
{
|
||||||
StartTime = double.Parse(split[1], NumberFormatInfo.InvariantInfo),
|
StartTime = getOffsetTime(double.Parse(split[1], NumberFormatInfo.InvariantInfo)),
|
||||||
EndTime = double.Parse(split[2], NumberFormatInfo.InvariantInfo)
|
EndTime = getOffsetTime(double.Parse(split[2], NumberFormatInfo.InvariantInfo))
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!breakEvent.HasEffect)
|
if (!breakEvent.HasEffect)
|
||||||
@ -273,7 +290,7 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
{
|
{
|
||||||
string[] split = line.Split(',');
|
string[] split = line.Split(',');
|
||||||
|
|
||||||
double time = double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo);
|
double time = getOffsetTime(double.Parse(split[0].Trim(), NumberFormatInfo.InvariantInfo));
|
||||||
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
double beatLength = double.Parse(split[1].Trim(), NumberFormatInfo.InvariantInfo);
|
||||||
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
double speedMultiplier = beatLength < 0 ? 100.0 / -beatLength : 1;
|
||||||
|
|
||||||
@ -396,7 +413,14 @@ namespace osu.Game.Beatmaps.Formats
|
|||||||
var obj = parser.Parse(line);
|
var obj = parser.Parse(line);
|
||||||
|
|
||||||
if (obj != null)
|
if (obj != null)
|
||||||
|
{
|
||||||
|
obj.StartTime = getOffsetTime(obj.StartTime);
|
||||||
beatmap.HitObjects.Add(obj);
|
beatmap.HitObjects.Add(obj);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getOffsetTime(int time) => time + (ApplyOffsets ? offset : 0);
|
||||||
|
|
||||||
|
private double getOffsetTime(double time) => time + (ApplyOffsets ? offset : 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Graphics.Containers
|
|||||||
{
|
{
|
||||||
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount;
|
Vector2 offset = (input.CurrentState.Mouse == null ? Vector2.Zero : ToLocalSpace(input.CurrentState.Mouse.NativeState.Position) - DrawSize / 2) * ParallaxAmount;
|
||||||
|
|
||||||
content.Position = Interpolation.ValueAt(Clock.ElapsedFrameTime, content.Position, offset, 0, 1000, Easing.OutQuint);
|
content.Position = Interpolation.ValueAt(MathHelper.Clamp(Clock.ElapsedFrameTime, 0, 1000), content.Position, offset, 0, 1000, Easing.OutQuint);
|
||||||
content.Scale = new Vector2(1 + ParallaxAmount);
|
content.Scale = new Vector2(1 + ParallaxAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +91,6 @@ namespace osu.Game.Rulesets.UI
|
|||||||
|
|
||||||
#region Clock control
|
#region Clock control
|
||||||
|
|
||||||
protected override bool ShouldProcessClock => false; // We handle processing the clock ourselves
|
|
||||||
|
|
||||||
private ManualClock clock;
|
private ManualClock clock;
|
||||||
private IFrameBasedClock parentClock;
|
private IFrameBasedClock parentClock;
|
||||||
|
|
||||||
@ -103,6 +101,7 @@ namespace osu.Game.Rulesets.UI
|
|||||||
//our clock will now be our parent's clock, but we want to replace this to allow manual control.
|
//our clock will now be our parent's clock, but we want to replace this to allow manual control.
|
||||||
parentClock = Clock;
|
parentClock = Clock;
|
||||||
|
|
||||||
|
ProcessCustomClock = false;
|
||||||
Clock = new FramedClock(clock = new ManualClock
|
Clock = new FramedClock(clock = new ManualClock
|
||||||
{
|
{
|
||||||
CurrentTime = parentClock.CurrentTime,
|
CurrentTime = parentClock.CurrentTime,
|
||||||
|
@ -41,7 +41,7 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private static bool hasShownNotificationOnce;
|
private static bool hasShownNotificationOnce;
|
||||||
|
|
||||||
public HUDOverlay(ScoreProcessor scoreProcessor, RulesetContainer rulesetContainer, DecoupleableInterpolatingFramedClock decoupledClock, WorkingBeatmap working, IAdjustableClock adjustableSourceClock)
|
public HUDOverlay(ScoreProcessor scoreProcessor, RulesetContainer rulesetContainer, WorkingBeatmap working, IClock offsetClock, IAdjustableClock adjustableClock)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
@ -66,13 +66,13 @@ namespace osu.Game.Screens.Play
|
|||||||
BindRulesetContainer(rulesetContainer);
|
BindRulesetContainer(rulesetContainer);
|
||||||
|
|
||||||
Progress.Objects = rulesetContainer.Objects;
|
Progress.Objects = rulesetContainer.Objects;
|
||||||
Progress.AudioClock = decoupledClock;
|
Progress.AudioClock = offsetClock;
|
||||||
Progress.AllowSeeking = rulesetContainer.HasReplayLoaded;
|
Progress.AllowSeeking = rulesetContainer.HasReplayLoaded;
|
||||||
Progress.OnSeek = pos => decoupledClock.Seek(pos);
|
Progress.OnSeek = pos => adjustableClock.Seek(pos);
|
||||||
|
|
||||||
ModDisplay.Current.BindTo(working.Mods);
|
ModDisplay.Current.BindTo(working.Mods);
|
||||||
|
|
||||||
PlayerSettingsOverlay.PlaybackSettings.AdjustableClock = adjustableSourceClock;
|
PlayerSettingsOverlay.PlaybackSettings.AdjustableClock = adjustableClock;
|
||||||
}
|
}
|
||||||
|
|
||||||
[BackgroundDependencyLoader(true)]
|
[BackgroundDependencyLoader(true)]
|
||||||
|
@ -44,14 +44,22 @@ namespace osu.Game.Screens.Play
|
|||||||
public Action OnResume;
|
public Action OnResume;
|
||||||
public Action OnPause;
|
public Action OnPause;
|
||||||
|
|
||||||
public IAdjustableClock AudioClock;
|
private readonly IAdjustableClock adjustableClock;
|
||||||
public FramedClock FramedClock;
|
private readonly FramedClock framedClock;
|
||||||
|
|
||||||
public PauseContainer()
|
public PauseContainer(FramedClock framedClock, IAdjustableClock adjustableClock)
|
||||||
{
|
{
|
||||||
|
this.framedClock = framedClock;
|
||||||
|
this.adjustableClock = adjustableClock;
|
||||||
|
|
||||||
RelativeSizeAxes = Axes.Both;
|
RelativeSizeAxes = Axes.Both;
|
||||||
|
|
||||||
AddInternal(content = new Container { RelativeSizeAxes = Axes.Both });
|
AddInternal(content = new Container
|
||||||
|
{
|
||||||
|
Clock = this.framedClock,
|
||||||
|
ProcessCustomClock = false,
|
||||||
|
RelativeSizeAxes = Axes.Both
|
||||||
|
});
|
||||||
|
|
||||||
AddInternal(pauseOverlay = new PauseOverlay
|
AddInternal(pauseOverlay = new PauseOverlay
|
||||||
{
|
{
|
||||||
@ -65,47 +73,37 @@ namespace osu.Game.Screens.Play
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Pause(bool force = false)
|
public void Pause(bool force = false) => Schedule(() => // Scheduled to ensure a stable position in execution order, no matter how it was called.
|
||||||
{
|
{
|
||||||
if (!CanPause && !force) return;
|
if (!CanPause && !force) return;
|
||||||
|
|
||||||
if (IsPaused) return;
|
if (IsPaused) return;
|
||||||
|
|
||||||
// stop the decoupled clock (stops the audio eventually)
|
// stop the seekable clock (stops the audio eventually)
|
||||||
AudioClock.Stop();
|
adjustableClock.Stop();
|
||||||
|
|
||||||
// stop processing updatess on the offset clock (instantly freezes time for all our components)
|
|
||||||
FramedClock.ProcessSourceClockFrames = false;
|
|
||||||
|
|
||||||
IsPaused = true;
|
IsPaused = true;
|
||||||
|
|
||||||
// we need to do a final check after all of our children have processed up to the paused clock time.
|
OnPause?.Invoke();
|
||||||
// this is to cover cases where, for instance, the player fails in the current processing frame.
|
pauseOverlay.Show();
|
||||||
Schedule(() =>
|
|
||||||
{
|
|
||||||
if (!CanPause) return;
|
|
||||||
|
|
||||||
lastPauseActionTime = Time.Current;
|
lastPauseActionTime = Time.Current;
|
||||||
|
});
|
||||||
OnPause?.Invoke();
|
|
||||||
pauseOverlay.Show();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Resume()
|
public void Resume()
|
||||||
{
|
{
|
||||||
if (!IsPaused) return;
|
if (!IsPaused) return;
|
||||||
|
|
||||||
IsPaused = false;
|
IsPaused = false;
|
||||||
FramedClock.ProcessSourceClockFrames = true;
|
IsResuming = false;
|
||||||
|
|
||||||
lastPauseActionTime = Time.Current;
|
lastPauseActionTime = Time.Current;
|
||||||
|
|
||||||
OnResume?.Invoke();
|
// seek back to the time of the framed clock.
|
||||||
|
// this accounts for the audio clock potentially taking time to enter a completely stopped state.
|
||||||
|
adjustableClock.Seek(framedClock.CurrentTime);
|
||||||
|
adjustableClock.Start();
|
||||||
|
|
||||||
|
OnResume?.Invoke();
|
||||||
pauseOverlay.Hide();
|
pauseOverlay.Hide();
|
||||||
AudioClock.Start();
|
|
||||||
IsResuming = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private OsuGameBase game;
|
private OsuGameBase game;
|
||||||
@ -122,6 +120,9 @@ namespace osu.Game.Screens.Play
|
|||||||
if (!game.IsActive && CanPause)
|
if (!game.IsActive && CanPause)
|
||||||
Pause();
|
Pause();
|
||||||
|
|
||||||
|
if (!IsPaused)
|
||||||
|
framedClock.ProcessFrame();
|
||||||
|
|
||||||
base.Update();
|
base.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,9 +56,12 @@ namespace osu.Game.Screens.Play
|
|||||||
public CursorContainer Cursor => RulesetContainer.Cursor;
|
public CursorContainer Cursor => RulesetContainer.Cursor;
|
||||||
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value;
|
public bool ProvidingUserCursor => RulesetContainer?.Cursor != null && !RulesetContainer.HasReplayLoaded.Value;
|
||||||
|
|
||||||
private IAdjustableClock adjustableSourceClock;
|
private IAdjustableClock sourceClock;
|
||||||
private FramedOffsetClock offsetClock;
|
|
||||||
private DecoupleableInterpolatingFramedClock decoupledClock;
|
/// <summary>
|
||||||
|
/// The decoupled clock used for gameplay. Should be used for seeks and clock control.
|
||||||
|
/// </summary>
|
||||||
|
private DecoupleableInterpolatingFramedClock adjustableClock;
|
||||||
|
|
||||||
private PauseContainer pauseContainer;
|
private PauseContainer pauseContainer;
|
||||||
|
|
||||||
@ -140,17 +143,18 @@ namespace osu.Game.Screens.Play
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
adjustableSourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock();
|
sourceClock = (IAdjustableClock)working.Track ?? new StopwatchClock();
|
||||||
decoupledClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
|
||||||
|
|
||||||
var firstObjectTime = RulesetContainer.Objects.First().StartTime;
|
var firstObjectTime = RulesetContainer.Objects.First().StartTime;
|
||||||
decoupledClock.Seek(AllowLeadIn
|
adjustableClock.Seek(AllowLeadIn
|
||||||
? Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn))
|
? Math.Min(0, firstObjectTime - Math.Max(beatmap.ControlPointInfo.TimingPointAt(firstObjectTime).BeatLength * 4, beatmap.BeatmapInfo.AudioLeadIn))
|
||||||
: firstObjectTime);
|
: firstObjectTime);
|
||||||
|
|
||||||
decoupledClock.ProcessFrame();
|
adjustableClock.ProcessFrame();
|
||||||
|
|
||||||
offsetClock = new FramedOffsetClock(decoupledClock);
|
// the final usable gameplay clock with user-set offsets applied.
|
||||||
|
var offsetClock = new FramedOffsetClock(adjustableClock);
|
||||||
|
|
||||||
userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset);
|
userAudioOffset = config.GetBindable<double>(OsuSetting.AudioOffset);
|
||||||
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
userAudioOffset.ValueChanged += v => offsetClock.Offset = v;
|
||||||
@ -160,16 +164,8 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
storyboardContainer = new Container
|
pauseContainer = new PauseContainer(offsetClock, adjustableClock)
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Clock = offsetClock,
|
|
||||||
Alpha = 0,
|
|
||||||
},
|
|
||||||
pauseContainer = new PauseContainer
|
|
||||||
{
|
|
||||||
AudioClock = decoupledClock,
|
|
||||||
FramedClock = offsetClock,
|
|
||||||
OnRetry = Restart,
|
OnRetry = Restart,
|
||||||
OnQuit = Exit,
|
OnQuit = Exit,
|
||||||
CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded,
|
CheckCanPause = () => AllowPause && ValidForResume && !HasFailed && !RulesetContainer.HasReplayLoaded,
|
||||||
@ -181,15 +177,23 @@ namespace osu.Game.Screens.Play
|
|||||||
OnResume = () => hudOverlay.KeyCounter.IsCounting = true,
|
OnResume = () => hudOverlay.KeyCounter.IsCounting = true,
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
new Container
|
storyboardContainer = new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Clock = offsetClock,
|
Alpha = 0,
|
||||||
Child = RulesetContainer,
|
|
||||||
},
|
},
|
||||||
new SkipButton(firstObjectTime) { AudioClock = decoupledClock },
|
RulesetContainer,
|
||||||
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, decoupledClock, working, adjustableSourceClock)
|
new SkipButton(firstObjectTime)
|
||||||
{
|
{
|
||||||
|
Clock = Clock, // skip button doesn't want to use the audio clock directly
|
||||||
|
ProcessCustomClock = false,
|
||||||
|
AdjustableClock = adjustableClock,
|
||||||
|
FramedClock = offsetClock,
|
||||||
|
},
|
||||||
|
hudOverlay = new HUDOverlay(scoreProcessor, RulesetContainer, working, offsetClock, adjustableClock)
|
||||||
|
{
|
||||||
|
Clock = Clock, // hud overlay doesn't want to use the audio clock directly
|
||||||
|
ProcessCustomClock = false,
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre
|
Origin = Anchor.Centre
|
||||||
},
|
},
|
||||||
@ -197,7 +201,7 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
Anchor = Anchor.Centre,
|
Anchor = Anchor.Centre,
|
||||||
Origin = Anchor.Centre,
|
Origin = Anchor.Centre,
|
||||||
Clock = decoupledClock,
|
ProcessCustomClock = false,
|
||||||
Breaks = beatmap.Breaks
|
Breaks = beatmap.Breaks
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -234,11 +238,11 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
private void applyRateFromMods()
|
private void applyRateFromMods()
|
||||||
{
|
{
|
||||||
if (adjustableSourceClock == null) return;
|
if (sourceClock == null) return;
|
||||||
|
|
||||||
adjustableSourceClock.Rate = 1;
|
sourceClock.Rate = 1;
|
||||||
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
|
foreach (var mod in Beatmap.Value.Mods.Value.OfType<IApplicableToClock>())
|
||||||
mod.ApplyToClock(adjustableSourceClock);
|
mod.ApplyToClock(sourceClock);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initializeStoryboard(bool asyncLoad)
|
private void initializeStoryboard(bool asyncLoad)
|
||||||
@ -297,7 +301,7 @@ namespace osu.Game.Screens.Play
|
|||||||
if (Beatmap.Value.Mods.Value.OfType<IApplicableFailOverride>().Any(m => !m.AllowFail))
|
if (Beatmap.Value.Mods.Value.OfType<IApplicableFailOverride>().Any(m => !m.AllowFail))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
decoupledClock.Stop();
|
adjustableClock.Stop();
|
||||||
|
|
||||||
HasFailed = true;
|
HasFailed = true;
|
||||||
failOverlay.Retries = RestartCount;
|
failOverlay.Retries = RestartCount;
|
||||||
@ -326,17 +330,19 @@ namespace osu.Game.Screens.Play
|
|||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
{
|
{
|
||||||
adjustableSourceClock.Reset();
|
sourceClock.Reset();
|
||||||
|
|
||||||
Schedule(() =>
|
Schedule(() =>
|
||||||
{
|
{
|
||||||
decoupledClock.ChangeSource(adjustableSourceClock);
|
adjustableClock.ChangeSource(sourceClock);
|
||||||
applyRateFromMods();
|
applyRateFromMods();
|
||||||
|
|
||||||
this.Delay(750).Schedule(() =>
|
this.Delay(750).Schedule(() =>
|
||||||
{
|
{
|
||||||
if (!pauseContainer.IsPaused)
|
if (!pauseContainer.IsPaused)
|
||||||
decoupledClock.Start();
|
{
|
||||||
|
adjustableClock.Start();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -363,9 +369,7 @@ namespace osu.Game.Screens.Play
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (loadedSuccessfully)
|
if (loadedSuccessfully)
|
||||||
{
|
|
||||||
pauseContainer?.Pause();
|
pauseContainer?.Pause();
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,9 @@ namespace osu.Game.Screens.Play
|
|||||||
public class SkipButton : OverlayContainer, IKeyBindingHandler<GlobalAction>
|
public class SkipButton : OverlayContainer, IKeyBindingHandler<GlobalAction>
|
||||||
{
|
{
|
||||||
private readonly double startTime;
|
private readonly double startTime;
|
||||||
public IAdjustableClock AudioClock;
|
|
||||||
|
public IAdjustableClock AdjustableClock;
|
||||||
|
public IFrameBasedClock FramedClock;
|
||||||
|
|
||||||
private Button button;
|
private Button button;
|
||||||
private Box remainingTimeBox;
|
private Box remainingTimeBox;
|
||||||
@ -60,8 +62,11 @@ namespace osu.Game.Screens.Play
|
|||||||
{
|
{
|
||||||
var baseClock = Clock;
|
var baseClock = Clock;
|
||||||
|
|
||||||
if (AudioClock != null)
|
if (FramedClock != null)
|
||||||
Clock = new FramedClock(AudioClock) { ProcessSourceClockFrames = false };
|
{
|
||||||
|
Clock = FramedClock;
|
||||||
|
ProcessCustomClock = false;
|
||||||
|
}
|
||||||
|
|
||||||
Children = new Drawable[]
|
Children = new Drawable[]
|
||||||
{
|
{
|
||||||
@ -109,7 +114,7 @@ namespace osu.Game.Screens.Play
|
|||||||
using (BeginAbsoluteSequence(beginFadeTime))
|
using (BeginAbsoluteSequence(beginFadeTime))
|
||||||
this.FadeOut(fade_time);
|
this.FadeOut(fade_time);
|
||||||
|
|
||||||
button.Action = () => AudioClock?.Seek(startTime - skip_required_cutoff - fade_time);
|
button.Action = () => AdjustableClock?.Seek(startTime - skip_required_cutoff - fade_time);
|
||||||
|
|
||||||
displayTime = Time.Current;
|
displayTime = Time.Current;
|
||||||
|
|
||||||
|
@ -33,6 +33,8 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool RemoveCompletedTransforms => false;
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
|
protected override IReadOnlyDependencyContainer CreateLocalDependencies(IReadOnlyDependencyContainer parent) =>
|
||||||
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
dependencies = new DependencyContainer(base.CreateLocalDependencies(parent));
|
||||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
public bool FlipH { get; set; }
|
public bool FlipH { get; set; }
|
||||||
public bool FlipV { get; set; }
|
public bool FlipV { get; set; }
|
||||||
|
|
||||||
|
public override bool RemoveWhenNotAlive => false;
|
||||||
|
|
||||||
protected override Vector2 DrawScale
|
protected override Vector2 DrawScale
|
||||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y);
|
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y);
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ namespace osu.Game.Storyboards.Drawables
|
|||||||
public bool FlipH { get; set; }
|
public bool FlipH { get; set; }
|
||||||
public bool FlipV { get; set; }
|
public bool FlipV { get; set; }
|
||||||
|
|
||||||
|
public override bool RemoveWhenNotAlive => false;
|
||||||
|
|
||||||
protected override Vector2 DrawScale
|
protected override Vector2 DrawScale
|
||||||
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y);
|
=> new Vector2(FlipH ? -base.DrawScale.X : base.DrawScale.X, FlipV ? -base.DrawScale.Y : base.DrawScale.Y);
|
||||||
|
|
||||||
|
@ -109,7 +109,7 @@ namespace osu.Game.Tests.Beatmaps
|
|||||||
|
|
||||||
private Beatmap getBeatmap(string name)
|
private Beatmap getBeatmap(string name)
|
||||||
{
|
{
|
||||||
var decoder = new LegacyBeatmapDecoder();
|
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
|
||||||
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
|
using (var resStream = openResource($"{resource_namespace}.{name}.osu"))
|
||||||
using (var stream = new StreamReader(resStream))
|
using (var stream = new StreamReader(resStream))
|
||||||
return decoder.DecodeBeatmap(stream);
|
return decoder.DecodeBeatmap(stream);
|
||||||
|
Loading…
Reference in New Issue
Block a user