Apply nullability to DefaultSongProgress and clean up more stuff

This commit is contained in:
Dean Herbert
2022-07-28 18:37:17 +09:00
parent ea027eda46
commit 86c2b7e449
2 changed files with 46 additions and 50 deletions

View File

@ -1,9 +1,6 @@
// 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.
#nullable disable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
@ -32,8 +29,6 @@ namespace osu.Game.Screens.Play.HUD
private readonly SongProgressGraph graph; private readonly SongProgressGraph graph;
private readonly SongProgressInfo info; private readonly SongProgressInfo info;
public Action<double> RequestSeek;
/// <summary> /// <summary>
/// Whether seeking is allowed and the progress bar should be shown. /// Whether seeking is allowed and the progress bar should be shown.
/// </summary> /// </summary>
@ -47,14 +42,20 @@ namespace osu.Game.Screens.Play.HUD
protected override bool BlockScrollInput => false; protected override bool BlockScrollInput => false;
[Resolved(canBeNull: true)] [Resolved]
private GameplayClock gameplayClock { get; set; } private GameplayClock? gameplayClock { get; set; }
[Resolved(canBeNull: true)] [Resolved]
private Player player { get; set; } private Player? player { get; set; }
[Resolved(canBeNull: true)] [Resolved]
private DrawableRuleset drawableRuleset { get; set; } private DrawableRuleset? drawableRuleset { get; set; }
[Resolved]
private OsuConfigManager config { get; set; } = null!;
[Resolved]
private SkinManager skinManager { get; set; } = null!;
public DefaultSongProgress() public DefaultSongProgress()
{ {
@ -110,12 +111,6 @@ namespace osu.Game.Screens.Play.HUD
migrateSettingFromConfig(); migrateSettingFromConfig();
} }
[Resolved]
private OsuConfigManager config { get; set; }
[Resolved]
private SkinManager skinManager { get; set; }
/// <summary> /// <summary>
/// This setting has been migrated to a per-component level. /// This setting has been migrated to a per-component level.
/// Only take the value from the config if it is in a non-default state (then reset it to default so it only applies once). /// Only take the value from the config if it is in a non-default state (then reset it to default so it only applies once).
@ -131,29 +126,26 @@ namespace osu.Game.Screens.Play.HUD
ShowGraph.Value = configShowGraph.Value; ShowGraph.Value = configShowGraph.Value;
// This is pretty ugly, but the only way to make this stick... // This is pretty ugly, but the only way to make this stick...
if (skinManager != null) var skinnableTarget = this.FindClosestParent<ISkinnableTarget>();
if (skinnableTarget != null)
{ {
var skinnableTarget = this.FindClosestParent<ISkinnableTarget>(); // If the skin is not mutable, a mutable instance will be created, causing this migration logic to run again on the correct skin.
// Therefore we want to avoid resetting the config value on this invocation.
if (skinManager.EnsureMutableSkin())
return;
if (skinnableTarget != null) // If `EnsureMutableSkin` actually changed the skin, default layout may take a frame to apply.
// See `SkinnableTargetComponentsContainer`'s use of ScheduleAfterChildren.
ScheduleAfterChildren(() =>
{ {
// If the skin is not mutable, a mutable instance will be created, causing this migration logic to run again on the correct skin. var skin = skinManager.CurrentSkin.Value;
// Therefore we want to avoid resetting the config value on this invocation. skin.UpdateDrawableTarget(skinnableTarget);
if (skinManager.EnsureMutableSkin())
return;
// If `EnsureMutableSkin` actually changed the skin, default layout may take a frame to apply. skinManager.Save(skin);
// See `SkinnableTargetComponentsContainer`'s use of ScheduleAfterChildren. });
ScheduleAfterChildren(() =>
{
var skin = skinManager.CurrentSkin.Value;
skin.UpdateDrawableTarget(skinnableTarget);
skinManager.Save(skin); configShowGraph.SetDefault();
});
configShowGraph.SetDefault();
}
} }
} }
} }
@ -170,8 +162,7 @@ namespace osu.Game.Screens.Play.HUD
protected override void UpdateObjects(IEnumerable<HitObject> objects) protected override void UpdateObjects(IEnumerable<HitObject> objects)
{ {
if (objects != null) graph.Objects = objects;
graph.Objects = objects;
info.StartTime = FirstHitTime; info.StartTime = FirstHitTime;
info.EndTime = LastHitTime; info.EndTime = LastHitTime;

View File

@ -30,8 +30,9 @@ namespace osu.Game.Screens.Play.HUD
set set
{ {
objects = value; objects = value;
FirstHitTime = objects?.FirstOrDefault()?.StartTime ?? 0; FirstHitTime = objects.FirstOrDefault()?.StartTime ?? 0;
LastHitTime = objects?.LastOrDefault()?.GetEndTime() ?? 0; //TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list).
LastHitTime = objects.LastOrDefault()?.GetEndTime() ?? 0;
UpdateObjects(objects); UpdateObjects(objects);
} }
} }
@ -45,11 +46,10 @@ namespace osu.Game.Screens.Play.HUD
protected double FirstHitTime { get; private set; } protected double FirstHitTime { get; private set; }
//TODO: this isn't always correct (consider mania where a non-last object may last for longer than the last in the list).
protected double LastHitTime { get; private set; } protected double LastHitTime { get; private set; }
protected abstract void UpdateProgress(double progress, bool isIntro); protected abstract void UpdateProgress(double progress, bool isIntro);
protected virtual void UpdateObjects(IEnumerable<HitObject>? objects) { } protected virtual void UpdateObjects(IEnumerable<HitObject> objects) { }
[BackgroundDependencyLoader] [BackgroundDependencyLoader]
private void load() private void load()
@ -70,20 +70,25 @@ namespace osu.Game.Screens.Play.HUD
// The reference clock is used to accurately tell the playfield's time. This is obtained from the drawable ruleset. // 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. // 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; double currentTime = referenceClock?.CurrentTime ?? gameplayClockContainer?.GameplayClock.CurrentTime ?? Time.Current;
if (gameplayTime < FirstHitTime) bool isInIntro = currentTime < FirstHitTime;
if (isInIntro)
{ {
double earliest = gameplayClockContainer?.StartTime ?? 0; double introStartTime = gameplayClockContainer?.StartTime ?? 0;
double introDuration = FirstHitTime - earliest;
double currentIntroTime = gameplayTime - earliest; double introOffsetCurrent = currentTime - introStartTime;
UpdateProgress(currentIntroTime / introDuration, true); double introDuration = FirstHitTime - introStartTime;
UpdateProgress(introOffsetCurrent / introDuration, true);
} }
else else
{ {
double duration = LastHitTime - FirstHitTime; double objectOffsetCurrent = currentTime - FirstHitTime;
double currentTime = gameplayTime - FirstHitTime;
UpdateProgress(currentTime / duration, false); double objectDuration = LastHitTime - FirstHitTime;
UpdateProgress(objectOffsetCurrent / objectDuration, false);
} }
} }
} }