2022-07-27 15:19:21 +08: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.
using System.Collections.Generic ;
using System.Linq ;
using osu.Framework.Allocation ;
using osu.Framework.Graphics.Containers ;
using osu.Framework.Timing ;
using osu.Game.Rulesets.Objects ;
using osu.Game.Rulesets.UI ;
using osu.Game.Skinning ;
namespace osu.Game.Screens.Play.HUD
{
public abstract class SongProgress : OverlayContainer , ISkinnableDrawable
{
public bool UsesFixedAnchor { get ; set ; }
2022-07-28 15:12:49 +08:00
[Resolved]
private GameplayClockContainer ? gameplayClockContainer { get ; set ; }
2022-07-27 15:19:21 +08:00
[Resolved(canBeNull: true)]
2022-07-28 15:12:49 +08:00
private DrawableRuleset ? drawableRuleset { get ; set ; }
2022-07-27 15:19:21 +08:00
2022-07-28 15:12:49 +08:00
private IClock ? referenceClock ;
private IEnumerable < HitObject > ? objects ;
2022-07-27 15:19:21 +08:00
public IEnumerable < HitObject > Objects
{
2022-07-28 15:25:12 +08:00
set
{
objects = value ;
2022-07-28 15:30:45 +08:00
FirstHitTime = objects ? . FirstOrDefault ( ) ? . StartTime ? ? 0 ;
LastHitTime = objects ? . LastOrDefault ( ) ? . GetEndTime ( ) ? ? 0 ;
2022-07-28 15:25:12 +08:00
UpdateObjects ( objects ) ;
}
2022-07-27 15:19:21 +08:00
}
2022-07-28 15:25:12 +08:00
protected double FirstHitTime { get ; private set ; }
2022-07-27 15:19:21 +08:00
//TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list).
2022-07-28 15:25:12 +08:00
protected double LastHitTime { get ; private set ; }
2022-07-27 15:19:21 +08:00
2022-07-28 15:12:49 +08:00
protected abstract void UpdateProgress ( double progress , bool isIntro ) ;
2022-07-28 15:30:45 +08:00
protected abstract void UpdateObjects ( IEnumerable < HitObject > ? objects ) ;
2022-07-27 15:19:21 +08:00
[BackgroundDependencyLoader]
private void load ( )
{
if ( drawableRuleset ! = null )
{
Objects = drawableRuleset . Objects ;
referenceClock = drawableRuleset . FrameStableClock ;
}
}
protected override void Update ( )
{
base . Update ( ) ;
if ( objects = = null )
return ;
2022-07-28 15:12:49 +08:00
// The reference clock is used to accurately tell the playfield's time. This is obtained from the drawable ruleset.
// However, if no drawable ruleset is available (i.e. used in tests), we fall back to either the gameplay clock container or this drawable's own clock.
double gameplayTime = referenceClock ? . CurrentTime ? ? gameplayClockContainer ? . GameplayClock . CurrentTime ? ? Time . Current ;
2022-07-27 15:19:21 +08:00
2022-07-28 15:12:49 +08:00
if ( gameplayTime < FirstHitTime )
2022-07-27 15:19:21 +08:00
{
2022-07-28 15:12:49 +08:00
double earliest = gameplayClockContainer ? . StartTime ? ? 0 ;
double introDuration = FirstHitTime - earliest ;
double currentIntroTime = gameplayTime - earliest ;
UpdateProgress ( currentIntroTime / introDuration , true ) ;
2022-07-27 15:19:21 +08:00
}
else
{
2022-07-28 15:12:49 +08:00
double duration = LastHitTime - FirstHitTime ;
double currentTime = gameplayTime - FirstHitTime ;
UpdateProgress ( currentTime / duration , false ) ;
2022-07-27 15:19:21 +08:00
}
}
}
}