1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-11 15:07:44 +08:00

Allow mods to apply to track, not clock

This commit is contained in:
Dean Herbert 2019-12-09 17:34:04 +09:00
parent 7d6cd72a82
commit eb074b7058
12 changed files with 52 additions and 83 deletions

View File

@ -57,8 +57,8 @@ namespace osu.Game.Tests.Visual.Gameplay
beforeLoadAction?.Invoke(); beforeLoadAction?.Invoke();
Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo); Beatmap.Value = CreateWorkingBeatmap(new OsuRuleset().RulesetInfo);
foreach (var mod in Mods.Value.OfType<IApplicableToClock>()) foreach (var mod in Mods.Value.OfType<IApplicableToTrack>())
mod.ApplyToClock(Beatmap.Value.Track); mod.ApplyToTrack(Beatmap.Value.Track);
InputManager.Child = container = new TestPlayerLoaderContainer( InputManager.Child = container = new TestPlayerLoaderContainer(
loader = new TestPlayerLoader(() => loader = new TestPlayerLoader(() =>

View File

@ -261,8 +261,8 @@ namespace osu.Game.Overlays
if (allowRateAdjustments) if (allowRateAdjustments)
{ {
foreach (var mod in mods.Value.OfType<IApplicableToClock>()) foreach (var mod in mods.Value.OfType<IApplicableToTrack>())
mod.ApplyToClock(track); mod.ApplyToTrack(track);
} }
} }

View File

@ -4,8 +4,8 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Difficulty.Preprocessing; using osu.Game.Rulesets.Difficulty.Preprocessing;
using osu.Game.Rulesets.Difficulty.Skills; using osu.Game.Rulesets.Difficulty.Skills;
@ -41,10 +41,10 @@ namespace osu.Game.Rulesets.Difficulty
IBeatmap playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods); IBeatmap playableBeatmap = beatmap.GetPlayableBeatmap(ruleset.RulesetInfo, mods);
var clock = new StopwatchClock(); var track = new TrackVirtual(10000);
mods.OfType<IApplicableToClock>().ForEach(m => m.ApplyToClock(clock)); mods.OfType<IApplicableToTrack>().ForEach(m => m.ApplyToTrack(track));
return calculate(playableBeatmap, mods, clock.Rate); return calculate(playableBeatmap, mods, track.Rate);
} }
/// <summary> /// <summary>

View File

@ -3,8 +3,8 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Scoring; using osu.Game.Scoring;
@ -35,9 +35,9 @@ namespace osu.Game.Rulesets.Difficulty
protected virtual void ApplyMods(Mod[] mods) protected virtual void ApplyMods(Mod[] mods)
{ {
var clock = new StopwatchClock(); var track = new TrackVirtual(10000);
mods.OfType<IApplicableToClock>().ForEach(m => m.ApplyToClock(clock)); mods.OfType<IApplicableToTrack>().ForEach(m => m.ApplyToTrack(track));
TimeRate = clock.Rate; TimeRate = track.Rate;
} }
public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null); public abstract double Calculate(Dictionary<string, double> categoryDifficulty = null);

View File

@ -1,15 +1,15 @@
// 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 osu.Framework.Timing; using osu.Framework.Audio.Track;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
{ {
/// <summary> /// <summary>
/// An interface for mods that make adjustments to the track. /// An interface for mods that make adjustments to the track.
/// </summary> /// </summary>
public interface IApplicableToClock : IApplicableMod public interface IApplicableToTrack : IApplicableMod
{ {
void ApplyToClock(IAdjustableClock clock); void ApplyToTrack(Track track);
} }
} }

View File

@ -1,9 +1,8 @@
// 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 osu.Framework.Audio; using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Timing;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
{ {
@ -14,12 +13,9 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage Icon => FontAwesome.Solid.Question; public override IconUsage Icon => FontAwesome.Solid.Question;
public override string Description => "Whoaaaaa..."; public override string Description => "Whoaaaaa...";
public override void ApplyToClock(IAdjustableClock clock) public override void ApplyToTrack(Track track)
{ {
if (clock is IHasPitchAdjust pitchAdjust) track.Frequency.Value *= RateAdjust;
pitchAdjust.PitchAdjust *= RateAdjust;
else
base.ApplyToClock(clock);
} }
} }
} }

View File

@ -8,7 +8,7 @@ using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
{ {
public abstract class ModDoubleTime : ModTimeAdjust, IApplicableToClock public abstract class ModDoubleTime : ModTimeAdjust
{ {
public override string Name => "Double Time"; public override string Name => "Double Time";
public override string Acronym => "DT"; public override string Acronym => "DT";

View File

@ -8,7 +8,7 @@ using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
{ {
public abstract class ModHalfTime : ModTimeAdjust, IApplicableToClock public abstract class ModHalfTime : ModTimeAdjust
{ {
public override string Name => "Half Time"; public override string Name => "Half Time";
public override string Acronym => "HT"; public override string Acronym => "HT";

View File

@ -1,9 +1,8 @@
// 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 osu.Framework.Audio; using osu.Framework.Audio.Track;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Timing;
using osu.Game.Graphics; using osu.Game.Graphics;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
@ -15,12 +14,9 @@ namespace osu.Game.Rulesets.Mods
public override IconUsage Icon => OsuIcon.ModNightcore; public override IconUsage Icon => OsuIcon.ModNightcore;
public override string Description => "Uguuuuuuuu..."; public override string Description => "Uguuuuuuuu...";
public override void ApplyToClock(IAdjustableClock clock) public override void ApplyToTrack(Track track)
{ {
if (clock is IHasPitchAdjust pitchAdjust) track.Frequency.Value *= RateAdjust;
pitchAdjust.PitchAdjust *= RateAdjust;
else
base.ApplyToClock(clock);
} }
} }
} }

View File

@ -2,23 +2,19 @@
// 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; using System;
using osu.Framework.Audio; using osu.Framework.Audio.Track;
using osu.Framework.Timing;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
{ {
public abstract class ModTimeAdjust : Mod public abstract class ModTimeAdjust : Mod, IApplicableToTrack
{ {
public override Type[] IncompatibleMods => new[] { typeof(ModTimeRamp) }; public override Type[] IncompatibleMods => new[] { typeof(ModTimeRamp) };
protected abstract double RateAdjust { get; } protected abstract double RateAdjust { get; }
public virtual void ApplyToClock(IAdjustableClock clock) public virtual void ApplyToTrack(Track track)
{ {
if (clock is IHasTempoAdjust tempo) track.TempoAdjust *= RateAdjust;
tempo.TempoAdjust *= RateAdjust;
else
clock.Rate *= RateAdjust;
} }
} }
} }

View File

@ -3,15 +3,14 @@
using System; using System;
using System.Linq; using System.Linq;
using osu.Framework.Audio; using osu.Framework.Audio.Track;
using osu.Framework.Timing;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
using osu.Game.Rulesets.Objects; using osu.Game.Rulesets.Objects;
namespace osu.Game.Rulesets.Mods namespace osu.Game.Rulesets.Mods
{ {
public abstract class ModTimeRamp : Mod, IUpdatableByPlayfield, IApplicableToClock, IApplicableToBeatmap public abstract class ModTimeRamp : Mod, IUpdatableByPlayfield, IApplicableToTrack, IApplicableToBeatmap
{ {
/// <summary> /// <summary>
/// The point in the beatmap at which the final ramping rate should be reached. /// The point in the beatmap at which the final ramping rate should be reached.
@ -24,11 +23,11 @@ namespace osu.Game.Rulesets.Mods
private double finalRateTime; private double finalRateTime;
private double beginRampTime; private double beginRampTime;
private IAdjustableClock clock; private Track track;
public virtual void ApplyToClock(IAdjustableClock clock) public virtual void ApplyToTrack(Track track)
{ {
this.clock = clock; this.track = track;
lastAdjust = 1; lastAdjust = 1;
@ -46,7 +45,7 @@ namespace osu.Game.Rulesets.Mods
public virtual void Update(Playfield playfield) public virtual void Update(Playfield playfield)
{ {
applyAdjustment((clock.CurrentTime - beginRampTime) / finalRateTime); applyAdjustment((track.CurrentTime - beginRampTime) / finalRateTime);
} }
private double lastAdjust = 1; private double lastAdjust = 1;
@ -59,23 +58,8 @@ namespace osu.Game.Rulesets.Mods
{ {
double adjust = 1 + (Math.Sign(FinalRateAdjustment) * Math.Clamp(amount, 0, 1) * Math.Abs(FinalRateAdjustment)); double adjust = 1 + (Math.Sign(FinalRateAdjustment) * Math.Clamp(amount, 0, 1) * Math.Abs(FinalRateAdjustment));
switch (clock) track.Tempo.Value /= lastAdjust;
{ track.Tempo.Value *= lastAdjust;
case IHasPitchAdjust pitch:
pitch.PitchAdjust /= lastAdjust;
pitch.PitchAdjust *= adjust;
break;
case IHasTempoAdjust tempo:
tempo.TempoAdjust /= lastAdjust;
tempo.TempoAdjust *= adjust;
break;
default:
clock.Rate /= lastAdjust;
clock.Rate *= adjust;
break;
}
lastAdjust = adjust; lastAdjust = adjust;
} }

View File

@ -28,9 +28,9 @@ namespace osu.Game.Screens.Play
private readonly IReadOnlyList<Mod> mods; private readonly IReadOnlyList<Mod> mods;
/// <summary> /// <summary>
/// The original source (usually a <see cref="WorkingBeatmap"/>'s track). /// The <see cref="WorkingBeatmap"/>'s track.
/// </summary> /// </summary>
private IAdjustableClock sourceClock; private Track track;
public readonly BindableBool IsPaused = new BindableBool(); public readonly BindableBool IsPaused = new BindableBool();
@ -72,8 +72,8 @@ namespace osu.Game.Screens.Play
RelativeSizeAxes = Axes.Both; RelativeSizeAxes = Axes.Both;
sourceClock = (IAdjustableClock)beatmap.Track ?? new StopwatchClock(); track = beatmap.Track;
(sourceClock as IAdjustableAudioComponent)?.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); track.AddAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false }; adjustableClock = new DecoupleableInterpolatingFramedClock { IsCoupled = false };
@ -127,11 +127,11 @@ namespace osu.Game.Screens.Play
{ {
Task.Run(() => Task.Run(() =>
{ {
sourceClock.Reset(); track.Reset();
Schedule(() => Schedule(() =>
{ {
adjustableClock.ChangeSource(sourceClock); adjustableClock.ChangeSource(track);
updateRate(); updateRate();
if (!IsPaused.Value) if (!IsPaused.Value)
@ -197,13 +197,13 @@ namespace osu.Game.Screens.Play
/// </summary> /// </summary>
public void StopUsingBeatmapClock() public void StopUsingBeatmapClock()
{ {
if (sourceClock != beatmap.Track) if (track != beatmap.Track)
return; return;
removeSourceClockAdjustments(); removeSourceClockAdjustments();
sourceClock = new TrackVirtual(beatmap.Track.Length); track = new TrackVirtual(beatmap.Track.Length);
adjustableClock.ChangeSource(sourceClock); adjustableClock.ChangeSource(track);
} }
protected override void Update() protected override void Update()
@ -218,18 +218,15 @@ namespace osu.Game.Screens.Play
private void updateRate() private void updateRate()
{ {
if (sourceClock == null) return; if (track == null) return;
speedAdjustmentsApplied = true; speedAdjustmentsApplied = true;
sourceClock.ResetSpeedAdjustments(); track.ResetSpeedAdjustments();
if (sourceClock is IHasTempoAdjust tempo) track.Tempo.Value = UserPlaybackRate.Value;
tempo.TempoAdjust = UserPlaybackRate.Value;
else
sourceClock.Rate = UserPlaybackRate.Value;
foreach (var mod in mods.OfType<IApplicableToClock>()) foreach (var mod in mods.OfType<IApplicableToTrack>())
mod.ApplyToClock(sourceClock); mod.ApplyToTrack(track);
} }
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
@ -237,18 +234,18 @@ namespace osu.Game.Screens.Play
base.Dispose(isDisposing); base.Dispose(isDisposing);
removeSourceClockAdjustments(); removeSourceClockAdjustments();
sourceClock = null; track = null;
} }
private void removeSourceClockAdjustments() private void removeSourceClockAdjustments()
{ {
if (speedAdjustmentsApplied) if (speedAdjustmentsApplied)
{ {
sourceClock.ResetSpeedAdjustments(); track.ResetSpeedAdjustments();
speedAdjustmentsApplied = false; speedAdjustmentsApplied = false;
} }
(sourceClock as IAdjustableAudioComponent)?.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust); (track as IAdjustableAudioComponent)?.RemoveAdjustment(AdjustableProperty.Frequency, pauseFreqAdjust);
} }
} }
} }