2019-01-24 17:43:03 +09:00
// 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.
2018-04-13 18:19:50 +09:00
using System.Collections.Generic ;
2020-04-28 19:23:33 +09:00
using System.Linq ;
2018-04-13 18:19:50 +09:00
using osu.Framework.Allocation ;
2020-04-28 19:23:33 +09:00
using osu.Framework.Audio.Track ;
2019-02-21 19:04:31 +09:00
using osu.Framework.Bindables ;
2018-04-13 18:19:50 +09:00
using osu.Framework.Extensions.IEnumerableExtensions ;
2024-02-02 03:56:38 +03:00
using osu.Framework.Extensions.ObjectExtensions ;
2018-04-13 18:19:50 +09:00
using osu.Framework.Input ;
2024-07-10 17:24:03 +02:00
using osu.Framework.Platform ;
2024-02-02 03:56:38 +03:00
using osu.Framework.Threading ;
2024-07-10 17:24:03 +02:00
using osu.Framework.Utils ;
2018-04-13 18:19:50 +09:00
using osu.Game.Beatmaps ;
2020-04-03 13:16:01 +09:00
using osu.Game.Beatmaps.ControlPoints ;
2018-04-13 18:19:50 +09:00
using osu.Game.Input.Handlers ;
2018-11-28 17:20:37 +09:00
using osu.Game.Replays ;
2018-04-13 18:19:50 +09:00
using osu.Game.Rulesets.Mania.Beatmaps ;
using osu.Game.Rulesets.Mania.Configuration ;
using osu.Game.Rulesets.Mania.Objects ;
using osu.Game.Rulesets.Mania.Replays ;
2023-12-26 12:46:21 +09:00
using osu.Game.Rulesets.Mania.Skinning ;
2019-04-08 18:32:05 +09:00
using osu.Game.Rulesets.Mods ;
2019-09-10 13:29:50 +09:00
using osu.Game.Rulesets.Objects ;
2018-04-13 18:19:50 +09:00
using osu.Game.Rulesets.Objects.Drawables ;
using osu.Game.Rulesets.UI ;
using osu.Game.Rulesets.UI.Scrolling ;
2020-12-14 16:52:14 +09:00
using osu.Game.Scoring ;
2024-02-08 02:16:08 +09:00
using osu.Game.Screens.Play ;
2023-12-26 12:46:21 +09:00
using osu.Game.Skinning ;
2018-04-13 18:19:50 +09:00
namespace osu.Game.Rulesets.Mania.UI
{
2024-05-06 15:24:32 +08:00
[Cached]
2022-11-24 14:32:20 +09:00
public partial class DrawableManiaRuleset : DrawableScrollingRuleset < ManiaHitObject >
2018-04-13 18:19:50 +09:00
{
2020-04-03 18:25:01 +09:00
/// <summary>
2023-05-29 21:14:03 +09:00
/// The minimum time range. This occurs at a <see cref="ManiaRulesetSetting.ScrollSpeed"/> of 40.
2020-04-03 18:25:01 +09:00
/// </summary>
2021-07-16 18:22:34 +09:00
public const double MIN_TIME_RANGE = 290 ;
2020-04-03 18:25:01 +09:00
/// <summary>
2023-05-29 21:14:03 +09:00
/// The maximum time range. This occurs with a <see cref="ManiaRulesetSetting.ScrollSpeed"/> of 1.
2020-04-03 18:25:01 +09:00
/// </summary>
2021-07-16 18:22:34 +09:00
public const double MAX_TIME_RANGE = 11485 ;
2020-04-03 18:25:01 +09:00
2024-05-06 15:24:32 +08:00
public new ManiaPlayfield Playfield = > ( ManiaPlayfield ) base . Playfield ;
2019-03-20 11:29:16 +09:00
2018-04-13 18:19:50 +09:00
public new ManiaBeatmap Beatmap = > ( ManiaBeatmap ) base . Beatmap ;
public IEnumerable < BarLine > BarLines ;
2019-08-26 12:51:23 +09:00
protected override bool RelativeScaleBeatLengths = > true ;
2019-01-25 11:14:37 +01:00
protected new ManiaRulesetConfigManager Config = > ( ManiaRulesetConfigManager ) base . Config ;
2018-06-08 20:13:24 +09:00
2018-11-06 15:46:36 +09:00
private readonly Bindable < ManiaScrollingDirection > configDirection = new Bindable < ManiaScrollingDirection > ( ) ;
2023-05-29 21:14:03 +09:00
private readonly BindableInt configScrollSpeed = new BindableInt ( ) ;
2024-07-10 17:24:03 +02:00
private double currentTimeRange ;
protected double TargetTimeRange ;
2020-04-28 19:23:33 +09:00
// Stores the current speed adjustment active in gameplay.
2020-04-29 14:27:21 +09:00
private readonly Track speedAdjustmentTrack = new TrackVirtual ( 0 ) ;
2018-11-06 15:46:36 +09:00
2024-02-05 14:52:08 +01:00
private ISkinSource currentSkin = null ! ;
2023-12-26 12:46:21 +09:00
2024-07-10 17:24:03 +02:00
[Resolved]
private GameHost gameHost { get ; set ; } = null ! ;
2024-02-05 14:52:08 +01:00
public DrawableManiaRuleset ( Ruleset ruleset , IBeatmap beatmap , IReadOnlyList < Mod > ? mods = null )
2019-04-08 18:32:05 +09:00
: base ( ruleset , beatmap , mods )
2018-04-13 18:19:50 +09:00
{
2019-09-24 23:03:55 +02:00
BarLines = new BarLineGenerator < BarLine > ( Beatmap ) . BarLines ;
2023-05-29 21:14:03 +09:00
TimeRange . MinValue = 1 ;
TimeRange . MaxValue = MAX_TIME_RANGE ;
2018-04-13 18:19:50 +09:00
}
[BackgroundDependencyLoader]
2024-02-02 03:56:38 +03:00
private void load ( ISkinSource source )
2018-04-13 18:19:50 +09:00
{
2024-02-02 03:56:38 +03:00
currentSkin = source ;
currentSkin . SourceChanged + = onSkinChange ;
skinChanged ( ) ;
2020-04-28 19:23:33 +09:00
foreach ( var mod in Mods . OfType < IApplicableToTrack > ( ) )
mod . ApplyToTrack ( speedAdjustmentTrack ) ;
2020-04-03 13:16:01 +09:00
bool isForCurrentRuleset = Beatmap . BeatmapInfo . Ruleset . Equals ( Ruleset . RulesetInfo ) ;
foreach ( var p in ControlPoints )
{
// Mania doesn't care about global velocity
p . Velocity = 1 ;
2021-10-02 12:34:29 +09:00
p . BaseBeatLength * = Beatmap . Difficulty . SliderMultiplier ;
2020-04-03 13:16:01 +09:00
// For non-mania beatmap, speed changes should only happen through timing points
if ( ! isForCurrentRuleset )
2021-09-01 18:19:25 +09:00
p . EffectPoint = new EffectControlPoint ( ) ;
2020-04-03 13:16:01 +09:00
}
2018-04-13 18:19:50 +09:00
BarLines . ForEach ( Playfield . Add ) ;
2018-07-17 16:55:50 +09:00
2019-01-25 11:14:37 +01:00
Config . BindWith ( ManiaRulesetSetting . ScrollDirection , configDirection ) ;
2019-02-22 20:13:38 +09:00
configDirection . BindValueChanged ( direction = > Direction . Value = ( ScrollingDirection ) direction . NewValue , true ) ;
2018-11-07 17:24:05 +09:00
2023-05-29 21:14:03 +09:00
Config . BindWith ( ManiaRulesetSetting . ScrollSpeed , configScrollSpeed ) ;
2024-07-10 17:24:03 +02:00
configScrollSpeed . BindValueChanged ( speed = > TargetTimeRange = ComputeScrollTime ( speed . NewValue ) ) ;
2018-04-13 18:19:50 +09:00
2024-07-10 17:24:03 +02:00
TimeRange . Value = TargetTimeRange = currentTimeRange = ComputeScrollTime ( configScrollSpeed . Value ) ;
2024-05-06 15:24:32 +08:00
2024-05-14 19:28:14 +08:00
KeyBindingInputManager . Add ( new ManiaTouchInputArea ( ) ) ;
2020-04-03 18:25:01 +09:00
}
2023-05-29 21:14:03 +09:00
protected override void AdjustScrollSpeed ( int amount ) = > configScrollSpeed . Value + = amount ;
2020-04-03 18:25:01 +09:00
2020-04-28 19:23:33 +09:00
protected override void Update ( )
{
base . Update ( ) ;
updateTimeRange ( ) ;
}
2024-02-05 14:52:08 +01:00
private ScheduledDelegate ? pendingSkinChange ;
2024-02-02 03:56:38 +03:00
private float hitPosition ;
private void onSkinChange ( )
2023-12-26 12:46:21 +09:00
{
2024-02-02 03:56:38 +03:00
// schedule required to avoid calls after disposed.
// note that this has the side-effect of components only performing a skin change when they are alive.
pendingSkinChange ? . Cancel ( ) ;
pendingSkinChange = Scheduler . Add ( skinChanged ) ;
}
private void skinChanged ( )
{
hitPosition = currentSkin . GetConfig < ManiaSkinConfigurationLookup , float > (
new ManiaSkinConfigurationLookup ( LegacyManiaSkinConfigurationLookups . HitPosition ) ) ? . Value
? ? Stage . HIT_TARGET_POSITION ;
pendingSkinChange = null ;
}
2023-12-26 12:46:21 +09:00
2024-02-02 03:56:38 +03:00
private void updateTimeRange ( )
{
2023-12-26 12:46:21 +09:00
const float length_to_default_hit_position = 768 - LegacyManiaSkinConfiguration . DEFAULT_HIT_POSITION ;
float lengthToHitPosition = 768 - hitPosition ;
// This scaling factor preserves the scroll speed as the scroll length varies from changes to the hit position.
float scale = lengthToHitPosition / length_to_default_hit_position ;
2024-07-10 17:24:03 +02:00
// we're intentionally using the game host's update clock here to decouple the time range tween from the gameplay clock (which can be arbitrarily paused, or even rewinding)
currentTimeRange = Interpolation . DampContinuously ( currentTimeRange , TargetTimeRange , 50 , gameHost . UpdateThread . Clock . ElapsedFrameTime ) ;
TimeRange . Value = currentTimeRange * speedAdjustmentTrack . AggregateTempo . Value * speedAdjustmentTrack . AggregateFrequency . Value * scale ;
2023-12-26 12:46:21 +09:00
}
2023-05-29 21:14:03 +09:00
/// <summary>
/// Computes a scroll time (in milliseconds) from a scroll speed in the range of 1-40.
/// </summary>
/// <param name="scrollSpeed">The scroll speed.</param>
/// <returns>The scroll time.</returns>
public static double ComputeScrollTime ( int scrollSpeed ) = > MAX_TIME_RANGE / scrollSpeed ;
2020-04-28 19:23:33 +09:00
2019-03-31 01:29:37 +09:00
public override PlayfieldAdjustmentContainer CreatePlayfieldAdjustmentContainer ( ) = > new ManiaPlayfieldAdjustmentContainer ( ) ;
2019-03-26 13:31:49 +09:00
protected override Playfield CreatePlayfield ( ) = > new ManiaPlayfield ( Beatmap . Stages ) ;
2018-04-13 18:19:50 +09:00
2019-02-28 19:07:43 +09:00
public override int Variant = > ( int ) ( Beatmap . Stages . Count = = 1 ? PlayfieldType . Single : PlayfieldType . Dual ) + Beatmap . TotalColumns ;
2018-04-13 18:19:50 +09:00
2019-03-19 20:21:31 +09:00
protected override PassThroughInputManager CreateInputManager ( ) = > new ManiaInputManager ( Ruleset . RulesetInfo , Variant ) ;
2018-04-13 18:19:50 +09:00
2024-02-05 14:52:08 +01:00
public override DrawableHitObject < ManiaHitObject > ? CreateDrawableRepresentation ( ManiaHitObject h ) = > null ;
2018-04-13 18:19:50 +09:00
protected override ReplayInputHandler CreateReplayInputHandler ( Replay replay ) = > new ManiaFramedReplayInputHandler ( replay ) ;
2020-03-24 14:55:49 +09:00
2020-12-14 16:52:14 +09:00
protected override ReplayRecorder CreateReplayRecorder ( Score score ) = > new ManiaReplayRecorder ( score ) ;
2024-02-02 03:56:38 +03:00
2024-02-08 02:16:08 +09:00
protected override ResumeOverlay CreateResumeOverlay ( ) = > new DelayedResumeOverlay ( ) ;
2024-02-02 03:56:38 +03:00
protected override void Dispose ( bool isDisposing )
{
base . Dispose ( isDisposing ) ;
if ( currentSkin . IsNotNull ( ) )
currentSkin . SourceChanged - = onSkinChange ;
}
2018-04-13 18:19:50 +09:00
}
}