mirror of
https://github.com/ppy/osu.git
synced 2025-01-12 17:35:10 +08:00
Cleanup
This commit is contained in:
parent
7713da499f
commit
98e6b7744b
@ -16,7 +16,7 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
/// Reference implementation for osu!stable's HP drain.
|
/// Reference implementation for osu!stable's HP drain.
|
||||||
/// Cannot be used for gameplay.
|
/// Cannot be used for gameplay.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class LegacyOsuHealthProcessor : LegacyDrainingHealthProcessor
|
public partial class LegacyOsuHealthProcessor : DrainingHealthProcessor
|
||||||
{
|
{
|
||||||
private const double hp_bar_maximum = 200;
|
private const double hp_bar_maximum = 200;
|
||||||
private const double hp_combo_geki = 14;
|
private const double hp_combo_geki = 14;
|
||||||
@ -24,6 +24,9 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
private const double hp_slider_repeat = 4;
|
private const double hp_slider_repeat = 4;
|
||||||
private const double hp_slider_tick = 3;
|
private const double hp_slider_tick = 3;
|
||||||
|
|
||||||
|
public Action<string>? OnIterationFail;
|
||||||
|
public Action<string>? OnIterationSuccess;
|
||||||
|
|
||||||
private double lowestHpEver;
|
private double lowestHpEver;
|
||||||
private double lowestHpEnd;
|
private double lowestHpEnd;
|
||||||
private double lowestHpComboEnd;
|
private double lowestHpComboEnd;
|
||||||
@ -187,13 +190,11 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
|
|
||||||
if (fail)
|
if (fail)
|
||||||
{
|
{
|
||||||
if (Log)
|
OnIterationFail?.Invoke($"FAILED drop {testDrop / hp_bar_maximum}: {failReason}");
|
||||||
Console.WriteLine($"FAILED drop {testDrop / hp_bar_maximum}: {failReason}");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Log)
|
OnIterationSuccess?.Invoke($"PASSED drop {testDrop / hp_bar_maximum}");
|
||||||
Console.WriteLine($"PASSED drop {testDrop / hp_bar_maximum}");
|
|
||||||
return testDrop / hp_bar_maximum;
|
return testDrop / hp_bar_maximum;
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
using osu.Game.Beatmaps.Timing;
|
using osu.Game.Beatmaps.Timing;
|
||||||
using osu.Game.Rulesets.Judgements;
|
using osu.Game.Rulesets.Judgements;
|
||||||
@ -12,8 +13,11 @@ using osu.Game.Rulesets.Scoring;
|
|||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Scoring
|
namespace osu.Game.Rulesets.Osu.Scoring
|
||||||
{
|
{
|
||||||
public partial class OsuHealthProcessor : LegacyDrainingHealthProcessor
|
public partial class OsuHealthProcessor : DrainingHealthProcessor
|
||||||
{
|
{
|
||||||
|
public Action<string>? OnIterationFail;
|
||||||
|
public Action<string>? OnIterationSuccess;
|
||||||
|
|
||||||
private double lowestHpEver;
|
private double lowestHpEver;
|
||||||
private double lowestHpEnd;
|
private double lowestHpEnd;
|
||||||
private double hpRecoveryAvailable;
|
private double hpRecoveryAvailable;
|
||||||
@ -141,13 +145,11 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
|||||||
|
|
||||||
if (fail)
|
if (fail)
|
||||||
{
|
{
|
||||||
if (Log)
|
OnIterationFail?.Invoke($"FAILED drop {testDrop}: {failReason}");
|
||||||
Console.WriteLine($"FAILED drop {testDrop}: {failReason}");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Log)
|
OnIterationSuccess?.Invoke($"PASSED drop {testDrop}");
|
||||||
Console.WriteLine($"PASSED drop {testDrop}");
|
|
||||||
return testDrop;
|
return testDrop;
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
|
@ -41,15 +41,29 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private const double max_health_target = 0.4;
|
private const double max_health_target = 0.4;
|
||||||
|
|
||||||
private IBeatmap beatmap;
|
/// <summary>
|
||||||
private double gameplayEndTime;
|
/// The drain rate as a proportion of the total health drained per millisecond.
|
||||||
|
/// </summary>
|
||||||
|
public double DrainRate { get; private set; } = 1;
|
||||||
|
|
||||||
private readonly double drainStartTime;
|
/// <summary>
|
||||||
private readonly double drainLenience;
|
/// The beatmap.
|
||||||
|
/// </summary>
|
||||||
|
protected IBeatmap Beatmap { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time at which health starts draining.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly double DrainStartTime;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An amount of lenience to apply to the drain rate.
|
||||||
|
/// </summary>
|
||||||
|
protected readonly double DrainLenience;
|
||||||
|
|
||||||
private readonly List<(double time, double health)> healthIncreases = new List<(double, double)>();
|
private readonly List<(double time, double health)> healthIncreases = new List<(double, double)>();
|
||||||
|
private double gameplayEndTime;
|
||||||
private double targetMinimumHealth;
|
private double targetMinimumHealth;
|
||||||
private double drainRate = 1;
|
|
||||||
|
|
||||||
private PeriodTracker noDrainPeriodTracker;
|
private PeriodTracker noDrainPeriodTracker;
|
||||||
|
|
||||||
@ -63,8 +77,8 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
/// A value of 1 completely removes drain.</param>
|
/// A value of 1 completely removes drain.</param>
|
||||||
public DrainingHealthProcessor(double drainStartTime, double drainLenience = 0)
|
public DrainingHealthProcessor(double drainStartTime, double drainLenience = 0)
|
||||||
{
|
{
|
||||||
this.drainStartTime = drainStartTime;
|
DrainStartTime = drainStartTime;
|
||||||
this.drainLenience = Math.Clamp(drainLenience, 0, 1);
|
DrainLenience = Math.Clamp(drainLenience, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
@ -75,16 +89,16 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
// When jumping in and out of gameplay time within a single frame, health should only be drained for the period within the gameplay time
|
// When jumping in and out of gameplay time within a single frame, health should only be drained for the period within the gameplay time
|
||||||
double lastGameplayTime = Math.Clamp(Time.Current - Time.Elapsed, drainStartTime, gameplayEndTime);
|
double lastGameplayTime = Math.Clamp(Time.Current - Time.Elapsed, DrainStartTime, gameplayEndTime);
|
||||||
double currentGameplayTime = Math.Clamp(Time.Current, drainStartTime, gameplayEndTime);
|
double currentGameplayTime = Math.Clamp(Time.Current, DrainStartTime, gameplayEndTime);
|
||||||
|
|
||||||
if (drainLenience < 1)
|
if (DrainLenience < 1)
|
||||||
Health.Value -= drainRate * (currentGameplayTime - lastGameplayTime);
|
Health.Value -= DrainRate * (currentGameplayTime - lastGameplayTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ApplyBeatmap(IBeatmap beatmap)
|
public override void ApplyBeatmap(IBeatmap beatmap)
|
||||||
{
|
{
|
||||||
this.beatmap = beatmap;
|
Beatmap = beatmap;
|
||||||
|
|
||||||
if (beatmap.HitObjects.Count > 0)
|
if (beatmap.HitObjects.Count > 0)
|
||||||
gameplayEndTime = beatmap.HitObjects[^1].GetEndTime();
|
gameplayEndTime = beatmap.HitObjects[^1].GetEndTime();
|
||||||
@ -105,7 +119,7 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
targetMinimumHealth = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, min_health_target, mid_health_target, max_health_target);
|
targetMinimumHealth = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, min_health_target, mid_health_target, max_health_target);
|
||||||
|
|
||||||
// Add back a portion of the amount of HP to be drained, depending on the lenience requested.
|
// Add back a portion of the amount of HP to be drained, depending on the lenience requested.
|
||||||
targetMinimumHealth += drainLenience * (1 - targetMinimumHealth);
|
targetMinimumHealth += DrainLenience * (1 - targetMinimumHealth);
|
||||||
|
|
||||||
// Ensure the target HP is within an acceptable range.
|
// Ensure the target HP is within an acceptable range.
|
||||||
targetMinimumHealth = Math.Clamp(targetMinimumHealth, 0, 1);
|
targetMinimumHealth = Math.Clamp(targetMinimumHealth, 0, 1);
|
||||||
@ -125,15 +139,15 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
{
|
{
|
||||||
base.Reset(storeResults);
|
base.Reset(storeResults);
|
||||||
|
|
||||||
drainRate = 1;
|
DrainRate = 1;
|
||||||
|
|
||||||
if (storeResults)
|
if (storeResults)
|
||||||
drainRate = computeDrainRate();
|
DrainRate = ComputeDrainRate();
|
||||||
|
|
||||||
healthIncreases.Clear();
|
healthIncreases.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private double computeDrainRate()
|
protected virtual double ComputeDrainRate()
|
||||||
{
|
{
|
||||||
if (healthIncreases.Count <= 1)
|
if (healthIncreases.Count <= 1)
|
||||||
return 0;
|
return 0;
|
||||||
@ -152,17 +166,17 @@ namespace osu.Game.Rulesets.Scoring
|
|||||||
for (int i = 0; i < healthIncreases.Count; i++)
|
for (int i = 0; i < healthIncreases.Count; i++)
|
||||||
{
|
{
|
||||||
double currentTime = healthIncreases[i].time;
|
double currentTime = healthIncreases[i].time;
|
||||||
double lastTime = i > 0 ? healthIncreases[i - 1].time : drainStartTime;
|
double lastTime = i > 0 ? healthIncreases[i - 1].time : DrainStartTime;
|
||||||
|
|
||||||
// Subtract any break time from the duration since the last object
|
// Subtract any break time from the duration since the last object
|
||||||
if (beatmap.Breaks.Count > 0)
|
if (Beatmap.Breaks.Count > 0)
|
||||||
{
|
{
|
||||||
// Advance the last break occuring before the current time
|
// Advance the last break occuring before the current time
|
||||||
while (currentBreak + 1 < beatmap.Breaks.Count && beatmap.Breaks[currentBreak + 1].EndTime < currentTime)
|
while (currentBreak + 1 < Beatmap.Breaks.Count && Beatmap.Breaks[currentBreak + 1].EndTime < currentTime)
|
||||||
currentBreak++;
|
currentBreak++;
|
||||||
|
|
||||||
if (currentBreak >= 0)
|
if (currentBreak >= 0)
|
||||||
lastTime = Math.Max(lastTime, beatmap.Breaks[currentBreak].EndTime);
|
lastTime = Math.Max(lastTime, Beatmap.Breaks[currentBreak].EndTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply health adjustments
|
// Apply health adjustments
|
||||||
|
@ -1,90 +0,0 @@
|
|||||||
// 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.
|
|
||||||
|
|
||||||
#nullable disable
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using osu.Game.Beatmaps;
|
|
||||||
using osu.Game.Rulesets.Objects;
|
|
||||||
using osu.Game.Utils;
|
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Scoring
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// A <see cref="HealthProcessor"/> which continuously drains health.<br />
|
|
||||||
/// At HP=0, the minimum health reached for a perfect play is 95%.<br />
|
|
||||||
/// At HP=5, the minimum health reached for a perfect play is 70%.<br />
|
|
||||||
/// At HP=10, the minimum health reached for a perfect play is 30%.
|
|
||||||
/// </summary>
|
|
||||||
public abstract partial class LegacyDrainingHealthProcessor : HealthProcessor
|
|
||||||
{
|
|
||||||
protected double DrainStartTime { get; }
|
|
||||||
protected double GameplayEndTime { get; private set; }
|
|
||||||
|
|
||||||
protected IBeatmap Beatmap { get; private set; }
|
|
||||||
protected PeriodTracker NoDrainPeriodTracker { get; private set; }
|
|
||||||
|
|
||||||
public bool Log { get; set; }
|
|
||||||
|
|
||||||
public double DrainRate { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new <see cref="DrainingHealthProcessor"/>.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="drainStartTime">The time after which draining should begin.</param>
|
|
||||||
protected LegacyDrainingHealthProcessor(double drainStartTime)
|
|
||||||
{
|
|
||||||
DrainStartTime = drainStartTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Update()
|
|
||||||
{
|
|
||||||
base.Update();
|
|
||||||
|
|
||||||
if (NoDrainPeriodTracker?.IsInAny(Time.Current) == true)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// When jumping in and out of gameplay time within a single frame, health should only be drained for the period within the gameplay time
|
|
||||||
double lastGameplayTime = Math.Clamp(Time.Current - Time.Elapsed, DrainStartTime, GameplayEndTime);
|
|
||||||
double currentGameplayTime = Math.Clamp(Time.Current, DrainStartTime, GameplayEndTime);
|
|
||||||
|
|
||||||
Health.Value -= DrainRate * (currentGameplayTime - lastGameplayTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void ApplyBeatmap(IBeatmap beatmap)
|
|
||||||
{
|
|
||||||
Beatmap = beatmap;
|
|
||||||
|
|
||||||
if (beatmap.HitObjects.Count > 0)
|
|
||||||
GameplayEndTime = beatmap.HitObjects[^1].GetEndTime();
|
|
||||||
|
|
||||||
NoDrainPeriodTracker = new PeriodTracker(beatmap.Breaks.Select(breakPeriod => new Period(
|
|
||||||
beatmap.HitObjects
|
|
||||||
.Select(hitObject => hitObject.GetEndTime())
|
|
||||||
.Where(endTime => endTime <= breakPeriod.StartTime)
|
|
||||||
.DefaultIfEmpty(double.MinValue)
|
|
||||||
.Last(),
|
|
||||||
beatmap.HitObjects
|
|
||||||
.Select(hitObject => hitObject.StartTime)
|
|
||||||
.Where(startTime => startTime >= breakPeriod.EndTime)
|
|
||||||
.DefaultIfEmpty(double.MaxValue)
|
|
||||||
.First()
|
|
||||||
)));
|
|
||||||
|
|
||||||
base.ApplyBeatmap(beatmap);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Reset(bool storeResults)
|
|
||||||
{
|
|
||||||
base.Reset(storeResults);
|
|
||||||
|
|
||||||
DrainRate = 1;
|
|
||||||
|
|
||||||
if (storeResults)
|
|
||||||
DrainRate = ComputeDrainRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract double ComputeDrainRate();
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user