From c126c46e2d25bcf2b1853ef80b869a230a9bb8ff Mon Sep 17 00:00:00 2001 From: Dan Balasescu Date: Fri, 24 Nov 2023 15:43:57 +0900 Subject: [PATCH] Remove legacy implementations (moved to osu-tools) --- .../Scoring/LegacyCatchHealthProcessor.cs | 237 ------------------ .../Scoring/LegacyOsuHealthProcessor.cs | 215 ---------------- 2 files changed, 452 deletions(-) delete mode 100644 osu.Game.Rulesets.Catch/Scoring/LegacyCatchHealthProcessor.cs delete mode 100644 osu.Game.Rulesets.Osu/Scoring/LegacyOsuHealthProcessor.cs diff --git a/osu.Game.Rulesets.Catch/Scoring/LegacyCatchHealthProcessor.cs b/osu.Game.Rulesets.Catch/Scoring/LegacyCatchHealthProcessor.cs deleted file mode 100644 index ef13ba222c..0000000000 --- a/osu.Game.Rulesets.Catch/Scoring/LegacyCatchHealthProcessor.cs +++ /dev/null @@ -1,237 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Collections.Generic; -using System.Linq; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Timing; -using osu.Game.Rulesets.Catch.Objects; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Objects.Types; -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Rulesets.Catch.Scoring -{ - /// - /// Reference implementation for osu!stable's HP drain. - /// Cannot be used for gameplay. - /// - public partial class LegacyCatchHealthProcessor : DrainingHealthProcessor - { - private const double hp_bar_maximum = 200; - private const double hp_combo_geki = 14; - private const double hp_hit_300 = 6; - private const double hp_slider_tick = 3; - - public Action? OnIterationFail; - public Action? OnIterationSuccess; - public bool ApplyComboEndBonus { get; set; } = true; - - private double lowestHpEver; - private double lowestHpEnd; - private double lowestHpComboEnd; - private double hpRecoveryAvailable; - private double hpMultiplierNormal; - private double hpMultiplierComboEnd; - - public LegacyCatchHealthProcessor(double drainStartTime) - : base(drainStartTime) - { - } - - public override void ApplyBeatmap(IBeatmap beatmap) - { - lowestHpEver = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 195, 160, 60); - lowestHpComboEnd = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 198, 170, 80); - lowestHpEnd = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 198, 180, 80); - hpRecoveryAvailable = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 8, 4, 0); - - base.ApplyBeatmap(beatmap); - } - - protected override void ApplyResultInternal(JudgementResult result) - { - if (!IsSimulating) - throw new NotSupportedException("The legacy catch health processor is not supported for gameplay."); - } - - protected override void RevertResultInternal(JudgementResult result) - { - if (!IsSimulating) - throw new NotSupportedException("The legacy catch health processor is not supported for gameplay."); - } - - protected override void Reset(bool storeResults) - { - hpMultiplierNormal = 1; - hpMultiplierComboEnd = 1; - - base.Reset(storeResults); - } - - protected override double ComputeDrainRate() - { - double testDrop = 0.05; - double currentHp; - double currentHpUncapped; - - List<(HitObject hitObject, bool newCombo)> allObjects = enumerateHitObjects(Beatmap).Where(h => h.hitObject is Fruit || h.hitObject is Droplet || h.hitObject is Banana).ToList(); - - do - { - currentHp = hp_bar_maximum; - currentHpUncapped = hp_bar_maximum; - - double lowestHp = currentHp; - double lastTime = DrainStartTime; - int currentBreak = 0; - bool fail = false; - int comboTooLowCount = 0; - string failReason = string.Empty; - - for (int i = 0; i < allObjects.Count; i++) - { - HitObject h = allObjects[i].hitObject; - - // Find active break (between current and lastTime) - double localLastTime = lastTime; - double breakTime = 0; - - // Subtract any break time from the duration since the last object - if (Beatmap.Breaks.Count > 0 && currentBreak < Beatmap.Breaks.Count) - { - BreakPeriod e = Beatmap.Breaks[currentBreak]; - - if (e.StartTime >= localLastTime && e.EndTime <= h.StartTime) - { - // consider break start equal to object end time for version 8+ since drain stops during this time - breakTime = (Beatmap.BeatmapInfo.BeatmapVersion < 8) ? (e.EndTime - e.StartTime) : e.EndTime - localLastTime; - currentBreak++; - } - } - - reduceHp(testDrop * (h.StartTime - lastTime - breakTime)); - - lastTime = h.GetEndTime(); - - if (currentHp < lowestHp) - lowestHp = currentHp; - - if (currentHp <= lowestHpEver) - { - fail = true; - testDrop *= 0.96; - failReason = $"hp too low ({currentHp / hp_bar_maximum} < {lowestHpEver / hp_bar_maximum})"; - break; - } - - switch (h) - { - case Fruit: - if (ApplyComboEndBonus && (i == allObjects.Count - 1 || allObjects[i + 1].newCombo)) - { - increaseHp(hpMultiplierComboEnd * hp_combo_geki + hpMultiplierNormal * hp_hit_300); - - if (currentHp < lowestHpComboEnd) - { - if (++comboTooLowCount > 2) - { - hpMultiplierComboEnd *= 1.07; - hpMultiplierNormal *= 1.03; - fail = true; - failReason = $"combo end hp too low ({currentHp / hp_bar_maximum} < {lowestHpComboEnd / hp_bar_maximum})"; - } - } - } - else - increaseHp(hpMultiplierNormal * hp_hit_300); - - break; - - case Banana: - increaseHp(hpMultiplierNormal / 2); - break; - - case TinyDroplet: - increaseHp(hpMultiplierNormal * hp_slider_tick * 0.1); - break; - - case Droplet: - increaseHp(hpMultiplierNormal * hp_slider_tick); - break; - } - - if (fail) - break; - } - - if (!fail && currentHp < lowestHpEnd) - { - fail = true; - testDrop *= 0.94; - hpMultiplierComboEnd *= 1.01; - hpMultiplierNormal *= 1.01; - failReason = $"end hp too low ({currentHp / hp_bar_maximum} < {lowestHpEnd / hp_bar_maximum})"; - } - - double recovery = (currentHpUncapped - hp_bar_maximum) / allObjects.Count; - - if (!fail && recovery < hpRecoveryAvailable) - { - fail = true; - testDrop *= 0.96; - hpMultiplierComboEnd *= 1.02; - hpMultiplierNormal *= 1.01; - failReason = $"recovery too low ({recovery / hp_bar_maximum} < {hpRecoveryAvailable / hp_bar_maximum})"; - } - - if (fail) - { - OnIterationFail?.Invoke($"FAILED drop {testDrop / hp_bar_maximum}: {failReason}"); - continue; - } - - OnIterationSuccess?.Invoke($"PASSED drop {testDrop / hp_bar_maximum}"); - return testDrop / hp_bar_maximum; - } while (true); - - void reduceHp(double amount) - { - currentHpUncapped = Math.Max(0, currentHpUncapped - amount); - currentHp = Math.Max(0, currentHp - amount); - } - - void increaseHp(double amount) - { - currentHpUncapped += amount; - currentHp = Math.Max(0, Math.Min(hp_bar_maximum, currentHp + amount)); - } - } - - private IEnumerable<(HitObject hitObject, bool newCombo)> enumerateHitObjects(IBeatmap beatmap) - { - return enumerateRecursively(beatmap.HitObjects); - - static IEnumerable<(HitObject hitObject, bool newCombo)> enumerateRecursively(IEnumerable hitObjects) - { - foreach (var hitObject in hitObjects) - { - // The combo end will either be attached to the hitobject itself if it has no children, or the very first child if it has children. - bool newCombo = (hitObject as IHasComboInformation)?.NewCombo ?? false; - - foreach ((HitObject nested, bool _) in enumerateRecursively(hitObject.NestedHitObjects)) - { - yield return (nested, newCombo); - - // Since the combo was attached to the first child, don't attach it to any other child or the parenting hitobject itself. - newCombo = false; - } - - yield return (hitObject, newCombo); - } - } - } - } -} diff --git a/osu.Game.Rulesets.Osu/Scoring/LegacyOsuHealthProcessor.cs b/osu.Game.Rulesets.Osu/Scoring/LegacyOsuHealthProcessor.cs deleted file mode 100644 index e92c3c9b97..0000000000 --- a/osu.Game.Rulesets.Osu/Scoring/LegacyOsuHealthProcessor.cs +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System; -using System.Linq; -using osu.Game.Beatmaps; -using osu.Game.Beatmaps.Timing; -using osu.Game.Rulesets.Judgements; -using osu.Game.Rulesets.Objects; -using osu.Game.Rulesets.Osu.Objects; -using osu.Game.Rulesets.Scoring; - -namespace osu.Game.Rulesets.Osu.Scoring -{ - /// - /// Reference implementation for osu!stable's HP drain. - /// Cannot be used for gameplay. - /// - public partial class LegacyOsuHealthProcessor : DrainingHealthProcessor - { - private const double hp_bar_maximum = 200; - private const double hp_combo_geki = 14; - private const double hp_hit_300 = 6; - private const double hp_slider_repeat = 4; - private const double hp_slider_tick = 3; - - public Action? OnIterationFail; - public Action? OnIterationSuccess; - public bool ApplyComboEndBonus { get; set; } = true; - - private double lowestHpEver; - private double lowestHpEnd; - private double lowestHpComboEnd; - private double hpRecoveryAvailable; - private double hpMultiplierNormal; - private double hpMultiplierComboEnd; - - public LegacyOsuHealthProcessor(double drainStartTime) - : base(drainStartTime) - { - } - - public override void ApplyBeatmap(IBeatmap beatmap) - { - lowestHpEver = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 195, 160, 60); - lowestHpComboEnd = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 198, 170, 80); - lowestHpEnd = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 198, 180, 80); - hpRecoveryAvailable = IBeatmapDifficultyInfo.DifficultyRange(beatmap.Difficulty.DrainRate, 8, 4, 0); - - base.ApplyBeatmap(beatmap); - } - - protected override void ApplyResultInternal(JudgementResult result) - { - if (!IsSimulating) - throw new NotSupportedException("The legacy osu! health processor is not supported for gameplay."); - } - - protected override void RevertResultInternal(JudgementResult result) - { - if (!IsSimulating) - throw new NotSupportedException("The legacy osu! health processor is not supported for gameplay."); - } - - protected override void Reset(bool storeResults) - { - hpMultiplierNormal = 1; - hpMultiplierComboEnd = 1; - - base.Reset(storeResults); - } - - protected override double ComputeDrainRate() - { - double testDrop = 0.05; - double currentHp; - double currentHpUncapped; - - do - { - currentHp = hp_bar_maximum; - currentHpUncapped = hp_bar_maximum; - - double lowestHp = currentHp; - double lastTime = DrainStartTime; - int currentBreak = 0; - bool fail = false; - int comboTooLowCount = 0; - string failReason = string.Empty; - - for (int i = 0; i < Beatmap.HitObjects.Count; i++) - { - HitObject h = Beatmap.HitObjects[i]; - - // Find active break (between current and lastTime) - double localLastTime = lastTime; - double breakTime = 0; - - // Subtract any break time from the duration since the last object - if (Beatmap.Breaks.Count > 0 && currentBreak < Beatmap.Breaks.Count) - { - BreakPeriod e = Beatmap.Breaks[currentBreak]; - - if (e.StartTime >= localLastTime && e.EndTime <= h.StartTime) - { - // consider break start equal to object end time for version 8+ since drain stops during this time - breakTime = (Beatmap.BeatmapInfo.BeatmapVersion < 8) ? (e.EndTime - e.StartTime) : e.EndTime - localLastTime; - currentBreak++; - } - } - - reduceHp(testDrop * (h.StartTime - lastTime - breakTime)); - - lastTime = h.GetEndTime(); - - if (currentHp < lowestHp) - lowestHp = currentHp; - - if (currentHp <= lowestHpEver) - { - fail = true; - testDrop *= 0.96; - failReason = $"hp too low ({currentHp / hp_bar_maximum} < {lowestHpEver / hp_bar_maximum})"; - break; - } - - double hpReduction = testDrop * (h.GetEndTime() - h.StartTime); - double hpOverkill = Math.Max(0, hpReduction - currentHp); - reduceHp(hpReduction); - - if (h is Slider slider) - { - for (int j = 0; j < slider.RepeatCount + 2; j++) - increaseHp(hpMultiplierNormal * hp_slider_repeat); - foreach (var _ in slider.NestedHitObjects.OfType()) - increaseHp(hpMultiplierNormal * hp_slider_tick); - } - else if (h is Spinner spinner) - { - foreach (var _ in spinner.NestedHitObjects.Where(t => t is not SpinnerBonusTick)) - increaseHp(hpMultiplierNormal * 1.7); - } - - if (hpOverkill > 0 && currentHp - hpOverkill <= lowestHpEver) - { - fail = true; - testDrop *= 0.96; - failReason = $"overkill ({currentHp / hp_bar_maximum} - {hpOverkill / hp_bar_maximum} <= {lowestHpEver / hp_bar_maximum})"; - break; - } - - if (ApplyComboEndBonus && (i == Beatmap.HitObjects.Count - 1 || ((OsuHitObject)Beatmap.HitObjects[i + 1]).NewCombo)) - { - increaseHp(hpMultiplierComboEnd * hp_combo_geki + hpMultiplierNormal * hp_hit_300); - - if (currentHp < lowestHpComboEnd) - { - if (++comboTooLowCount > 2) - { - hpMultiplierComboEnd *= 1.07; - hpMultiplierNormal *= 1.03; - fail = true; - failReason = $"combo end hp too low ({currentHp / hp_bar_maximum} < {lowestHpComboEnd / hp_bar_maximum})"; - break; - } - } - } - else - increaseHp(hpMultiplierNormal * hp_hit_300); - } - - if (!fail && currentHp < lowestHpEnd) - { - fail = true; - testDrop *= 0.94; - hpMultiplierComboEnd *= 1.01; - hpMultiplierNormal *= 1.01; - failReason = $"end hp too low ({currentHp / hp_bar_maximum} < {lowestHpEnd / hp_bar_maximum})"; - } - - double recovery = (currentHpUncapped - hp_bar_maximum) / Beatmap.HitObjects.Count; - - if (!fail && recovery < hpRecoveryAvailable) - { - fail = true; - testDrop *= 0.96; - hpMultiplierComboEnd *= 1.02; - hpMultiplierNormal *= 1.01; - failReason = $"recovery too low ({recovery / hp_bar_maximum} < {hpRecoveryAvailable / hp_bar_maximum})"; - } - - if (fail) - { - OnIterationFail?.Invoke($"FAILED drop {testDrop / hp_bar_maximum}: {failReason}"); - continue; - } - - OnIterationSuccess?.Invoke($"PASSED drop {testDrop / hp_bar_maximum}"); - return testDrop / hp_bar_maximum; - } while (true); - - void reduceHp(double amount) - { - currentHpUncapped = Math.Max(0, currentHpUncapped - amount); - currentHp = Math.Max(0, currentHp - amount); - } - - void increaseHp(double amount) - { - currentHpUncapped += amount; - currentHp = Math.Max(0, Math.Min(hp_bar_maximum, currentHp + amount)); - } - } - } -}