合并遗漏

This commit is contained in:
LA
2026-01-22 18:09:32 +08:00
parent 583a9bfc81
commit 93f76652c9
10 changed files with 2 additions and 762 deletions

View File

@@ -8,13 +8,10 @@ using System.Collections.Generic;
using System.Threading;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy;
using osu.Game.LAsEzExtensions.Background;
using osu.Game.LAsEzExtensions.Configuration;
using osu.Game.Rulesets.Objects;
using osu.Game.Rulesets.Objects.Types;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns;
using osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy;
using osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Objects.Legacy;
using osu.Game.Rulesets.Scoring.Legacy;
@@ -50,11 +47,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
/// </summary>
public readonly bool IsForCurrentRuleset;
/// <summary>
/// The current hit mode for mania judgement system.
/// </summary>
public static EzMUGHitMode CurrentHitMode { get; set; }
// Internal for testing purposes
internal readonly LegacyRandom Random;
@@ -68,7 +60,6 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
private ManiaBeatmapConverter(IBeatmap? beatmap, LegacyBeatmapConversionDifficultyInfo difficulty, Ruleset ruleset)
: base(beatmap!, ruleset)
{
CurrentHitMode = GlobalConfigStore.EzConfig?.Get<EzMUGHitMode>(Ez2Setting.HitMode) ?? EzMUGHitMode.Lazer;
IsForCurrentRuleset = difficulty.SourceRuleset.Equals(ruleset.RulesetInfo);
Random = new LegacyRandom((int)MathF.Round(difficulty.DrainRate + difficulty.CircleSize) * 20 + (int)(difficulty.OverallDifficulty * 41.2) + (int)MathF.Round(difficulty.ApproachRate));
TargetColumns = getColumnCount(difficulty);
@@ -141,21 +132,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
{
case ManiaHitObject maniaObj:
{
if (maniaObj is HoldNote hold && CurrentHitMode != EzMUGHitMode.Lazer)
{
yield return CurrentHitMode switch
{
EzMUGHitMode.EZ2AC => new Ez2AcHoldNote(hold),
EzMUGHitMode.Malody => new NoJudgmentHoldNote(hold),
EzMUGHitMode.O2Jam => new O2HoldNote(hold),
EzMUGHitMode.IIDX_HD => new Ez2AcHoldNote(hold),
_ => hold
};
}
else
{
yield return maniaObj;
}
yield return maniaObj;
yield break;
}
@@ -250,21 +227,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
lastPattern = newPattern;
foreach (var obj in newPattern.HitObjects)
if (obj is HoldNote hold && CurrentHitMode != EzMUGHitMode.Lazer)
{
yield return CurrentHitMode switch
{
EzMUGHitMode.EZ2AC => new Ez2AcHoldNote(hold),
EzMUGHitMode.Malody => new NoJudgmentHoldNote(hold),
EzMUGHitMode.O2Jam => new O2HoldNote(hold),
EzMUGHitMode.IIDX_HD => new Ez2AcHoldNote(hold),
_ => hold
};
}
else
{
yield return obj;
}
yield return obj;
}
}

View File

@@ -1,93 +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.
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI.Scrolling;
using osu.Game.Rulesets.UI.Scrolling.Algorithms;
namespace osu.Game.Rulesets.Mania.Mods.LAsMods
{
public class ManiaModBasicScrollSpeed : Mod, ISupportConstantAlgorithmToggle, IDrawableScrollingRuleset
{
public override string Name => "Adjust Basic Scroll Speed";
public override string Acronym => "ABSS";
public override LocalisableString Description => "LaMod: Adjust the basic scrolling speed of different keys.";
public override ModType Type => ModType.CustomMod;
public override double ScoreMultiplier => 1;
[SettingSource("Basic Scrolling Speed", "基础落速")]
public BindableNumber<double> BasicScrollingSpeed { get; } = new BindableNumber<double>
{
MinValue = 200,
MaxValue = 2000,
Default = 500,
Value = 1,
};
public BindableBool ShowSpeedChanges { get; } = new BindableBool();
public double? TimelineTimeRange { get; set; }
public required IScrollingInfo ScrollingInfo;
[BackgroundDependencyLoader]
private void load(IScrollingInfo scrollingInfo)
{
this.ScrollingInfo = scrollingInfo;
}
protected void LoadComplete()
{
ShowSpeedChanges.BindValueChanged(showChanges => VisualisationMethod = showChanges.NewValue ? ScrollVisualisationMethod.Sequential : ScrollVisualisationMethod.Constant, true);
}
public void ApplyToBeatmap(IBeatmap beatmap)
{
double currentScrollSpeed = ScrollingInfo.TimeRange.Value;
int totalKeys = beatmap.HitObjects.OfType<ManiaHitObject>().Max(h => h.Column) + 1;
double speedMultiplier = BasicScrollingSpeed.Value / 1000.0;
double newScrollSpeed = currentScrollSpeed * speedMultiplier * totalKeys;
ScrollingInfo.TimeRange.Value = newScrollSpeed;
}
private ScrollVisualisationMethod visualisationMethod = ScrollVisualisationMethod.Sequential;
public ScrollVisualisationMethod VisualisationMethod
{
get => visualisationMethod;
set
{
visualisationMethod = value;
updateScrollAlgorithm();
}
}
private void updateScrollAlgorithm()
{
switch (VisualisationMethod)
{
case ScrollVisualisationMethod.Sequential:
ScrollingInfo.Algorithm = new SequentialScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Overlapping:
ScrollingInfo.Algorithm.Value = new OverlappingScrollAlgorithm(ControlPoints);
break;
case ScrollVisualisationMethod.Constant:
ScrollingInfo.Algorithm.Value = new ConstantScrollAlgorithm();
break;
}
}
}
}

View File

@@ -1,293 +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.
using System;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Localisation;
using osu.Game.Configuration;
using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Mods.LAsMods
{
public class ManiaModFreeHit : Mod, IHitWindows
{
public override string Name => "Custom HitWindows";
public override string Acronym => "CH";
public override double ScoreMultiplier => 1;
public override bool Ranked => false;
public override LocalisableString Description => @"LaMod: Custom HitWindows. Free Hit ms.";
public override ModType Type => ModType.CustomMod;
[SettingSource("Adaptive Judgement(No Active)")]
public BindableBool AdaptiveJudgement { get; } = new BindableBool();
[SettingSource("Easy Style Judgement")]
public BindableBool UseEasyTemplate { get; } = new BindableBool();
[SettingSource("Hard Style Judgement")]
public BindableBool UseHardTemplate { get; } = new BindableBool();
[SettingSource("Perfect Offset (ms)")]
public BindableNumber<double> PerfectOffset { get; } = new BindableDouble(22)
{
MinValue = 1,
MaxValue = 60,
Precision = 1
};
[SettingSource("Great Offset (ms)")]
public BindableNumber<double> GreatOffset { get; } = new BindableDouble(42)
{
MinValue = 10,
MaxValue = 120,
Precision = 1
};
[SettingSource("Good Offset (ms)")]
public BindableNumber<double> GoodOffset { get; } = new BindableDouble(82)
{
MinValue = 20,
MaxValue = 180,
Precision = 1
};
[SettingSource("Ok Offset (ms)")]
public BindableNumber<double> OkOffset { get; } = new BindableDouble(120)
{
MinValue = 40,
MaxValue = 240,
Precision = 1
};
[SettingSource("Meh Offset (ms)")]
public BindableNumber<double> MehOffset { get; } = new BindableDouble(150)
{
MinValue = 60,
MaxValue = 300,
Precision = 1
};
[SettingSource("Miss Offset (ms)")]
public BindableNumber<double> MissOffset { get; } = new BindableDouble(180)
{
MinValue = 80,
MaxValue = 500,
Precision = 1
};
[Resolved]
private ScoreProcessor scoreProcessor { get; set; } = null!;
public ManiaModFreeHit()
{
// HitWindows.SetCustomRanges(this);
UseEasyTemplate.BindValueChanged(e =>
{
if (e.NewValue)
{
applyTemplate(HitWindowTemplates.EASY);
UseHardTemplate.Value = false;
AdaptiveJudgement.Value = false;
}
});
UseHardTemplate.BindValueChanged(e =>
{
if (e.NewValue)
{
applyTemplate(HitWindowTemplates.HARD);
UseEasyTemplate.Value = false;
AdaptiveJudgement.Value = false;
}
});
AdaptiveJudgement.BindValueChanged(e =>
{
if (e.NewValue)
{
UseHardTemplate.Value = false;
UseEasyTemplate.Value = false;
scoreProcessor?.Accuracy.BindValueChanged(acc => UpdateHitWindowsBasedOnScore(acc.NewValue), true);
}
// else
// {
// scoreProcessor.Accuracy.UnbindAll();
// }
}, true);
PerfectOffset.BindValueChanged(_ => updateHitWindows());
GreatOffset.BindValueChanged(_ => updateHitWindows());
GoodOffset.BindValueChanged(_ => updateHitWindows());
OkOffset.BindValueChanged(_ => updateHitWindows());
MehOffset.BindValueChanged(_ => updateHitWindows());
MissOffset.BindValueChanged(_ => updateHitWindows());
}
~ManiaModFreeHit()
{
HitWindows.SetModActive(false);
}
private void updateHitWindows()
{
HitWindows.SetModActive(true);
HitWindows.SetCustomRanges(this);
}
// public void ApplyToScoreProcessor(ScoreProcessor scoreProcessor)
// {
// }
// public AdjustRank(ScoreRank rank, double accuracy)
// {
// return rank;
// }
private void applyTemplate(HitWindowTemplate template)
{
PerfectOffset.Value = template.PerfectOffset;
GreatOffset.Value = template.GreatOffset;
GoodOffset.Value = template.GoodOffset;
OkOffset.Value = template.OkOffset;
MehOffset.Value = template.MehOffset;
MissOffset.Value = template.MissOffset;
}
public class HitWindowTemplate
{
public double PerfectOffset { get; set; }
public double GreatOffset { get; set; }
public double GoodOffset { get; set; }
public double OkOffset { get; set; }
public double MehOffset { get; set; }
public double MissOffset { get; set; }
}
public static class HitWindowTemplates
{
public static readonly HitWindowTemplate EASY = new HitWindowTemplate
{
PerfectOffset = 50,
GreatOffset = 100,
GoodOffset = 150,
OkOffset = 200,
MehOffset = 250,
MissOffset = 300
};
public static readonly HitWindowTemplate HARD = new HitWindowTemplate
{
PerfectOffset = 20,
GreatOffset = 40,
GoodOffset = 60,
OkOffset = 80,
MehOffset = 100,
MissOffset = 120
};
// 可以添加更多模板
}
public void UpdateHitWindowsBasedOnScore(double accuracy)
{
if (accuracy != 0)
{
if (accuracy > 0.95)
{
// 缩小判定区间
PerfectOffset.Value = 10;
GreatOffset.Value = 20;
GoodOffset.Value = 21;
OkOffset.Value = 90;
MehOffset.Value = 100;
MissOffset.Value = 120;
}
else if (accuracy < 0.95)
{
// 放宽判定区间
PerfectOffset.Value = 30;
GreatOffset.Value = 60;
GoodOffset.Value = 100;
OkOffset.Value = 150;
MehOffset.Value = 151;
MissOffset.Value = 200;
}
}
}
public bool IsHitResultAllowed(HitResult result)
{
return result switch
{
HitResult.Perfect => true,
HitResult.Great => true,
HitResult.Good => true,
HitResult.Ok => true,
HitResult.Meh => true,
HitResult.Miss => true,
_ => false,
};
}
public double WindowFor(HitResult result)
{
switch (result)
{
case HitResult.Perfect:
return PerfectOffset.Value;
case HitResult.Great:
return GreatOffset.Value;
case HitResult.Good:
return GoodOffset.Value;
case HitResult.Ok:
return OkOffset.Value;
case HitResult.Meh:
return MehOffset.Value;
case HitResult.Miss:
return MissOffset.Value;
default:
throw new ArgumentException("Unknown enum member", nameof(result));
}
}
public DifficultyRange[] GetRanges() => new[]
{
new DifficultyRange(HitResult.Perfect, PerfectOffset.Value, PerfectOffset.Value, PerfectOffset.Value),
new DifficultyRange(HitResult.Great, GreatOffset.Value, GreatOffset.Value, GreatOffset.Value),
new DifficultyRange(HitResult.Good, GoodOffset.Value, GoodOffset.Value, GoodOffset.Value),
new DifficultyRange(HitResult.Ok, OkOffset.Value, OkOffset.Value, OkOffset.Value),
new DifficultyRange(HitResult.Meh, MehOffset.Value, MehOffset.Value, MehOffset.Value),
new DifficultyRange(HitResult.Miss, MissOffset.Value, MissOffset.Value, MissOffset.Value),
};
public override string SettingDescription
{
get
{
string perfect = $"Perfect {PerfectOffset.Value}";
string great = $"Great {GreatOffset.Value}";
string good = $"Good {GoodOffset.Value}";
string ok = $"Ok {OkOffset.Value}";
string meh = $"Meh {MehOffset.Value}";
string miss = $"Miss {MissOffset.Value}";
return string.Join(", ", new[]
{
perfect,
great,
good,
ok,
meh,
miss
}.Where(s => !string.IsNullOrEmpty(s)));
}
}
}
}

View File

@@ -1,59 +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.
using System;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
public partial class Ez2AcDrawableLNTail : DrawableHoldNoteTail
{
public override bool DisplayResult => false;
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
if (!HoldNote.Head.IsHit)
{
return;
}
if (timeOffset >= 0 && HoldNote.IsHolding.Value)
{
ApplyMaxResult();
return;
}
else if (timeOffset > 0)
{
ApplyMinResult();
return;
}
}
}
public partial class Ez2AcDrawableNote : DrawableNote
{
protected override void CheckForResult(bool userTriggered, double timeOffset)
{
// if (userTriggered && HitObject.HitWindows is ManiaHitWindows ezWindows)
// {
// double missWindow = double.Abs(ezWindows.WindowFor(HitResult.Miss));
// double poolEarlyWindow = missWindow + 500;
// double poolLateWindow = missWindow + 150;
//
// // 提前按下timeOffset < 0且在提前 Pool 窗口内
// if ((timeOffset < 0 && missWindow <= poolEarlyWindow) ||
// (timeOffset > 0 && timeOffset <= poolLateWindow))
// ApplyResult(HitResult.Pool);
// }
if (userTriggered && (timeOffset < -500 || timeOffset > 200))
{
ApplyResult(HitResult.Pool);
}
base.CheckForResult(userTriggered, timeOffset);
}
}
}

View File

@@ -1,126 +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.
using System.Threading;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Scoring;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
// 注意注册顺序必须是:头 尾 身体
public class Ez2AcHoldNote : HoldNote
{
public Ez2AcHoldNote(HoldNote hold)
{
StartTime = hold.StartTime;
Duration = hold.Duration;
Column = hold.Column;
NodeSamples = hold.NodeSamples;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
{
AddNested(Head = new HeadNote
{
StartTime = StartTime,
Column = Column,
Samples = GetNodeSamples(0),
});
AddNested(Tail = new Ez2AcLNTail
{
StartTime = EndTime,
Column = Column,
Samples = GetNodeSamples((NodeSamples?.Count - 1) ?? 1),
});
AddNested(Body = new HoldNoteBody
{
StartTime = StartTime,
Column = Column
});
// double interval = new BeatInterval().GetCurrentQuarterBeatInterval();
//
// // 按1/4节拍添加身体判定节点
// for (double time = StartTime + interval; time < EndTime; time += interval)
// {
// AddNested(new NoMissLNBody
// {
// StartTime = time,
// Column = Column
// });
// }
}
}
public class Ez2AcLNHead : HeadNote
{
}
public class Ez2AcLNTail : TailNote
{
public override Judgement CreateJudgement() => new NoComboBreakTailJudgement();
public class NoComboBreakTailJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.IgnoreHit;
public override HitResult MinResult => HitResult.ComboBreak;
}
}
public class Ez2AcNote : Note
{
public Ez2AcNote(Note note)
{
StartTime = note.StartTime;
Column = note.Column;
Samples = note.Samples;
}
// public override Judgement CreateJudgement() => new Ez2AcJudgement();
// protected override HitWindows CreateHitWindows() => new Ez2AcHitWindows();
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
{
}
}
public class Ez2AcJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.Perfect;
public override HitResult MinResult => HitResult.Pool;
protected override double HealthIncreaseFor(HitResult result)
{
switch (result)
{
case HitResult.Pool:
// Pool 判定应用严格扣血
return -DEFAULT_MAX_HEALTH_INCREASE * 5;
case HitResult.Miss:
return -DEFAULT_MAX_HEALTH_INCREASE * 3;
case HitResult.Meh:
return -DEFAULT_MAX_HEALTH_INCREASE * 2;
case HitResult.Ok:
return -DEFAULT_MAX_HEALTH_INCREASE * 1;
case HitResult.Good:
return DEFAULT_MAX_HEALTH_INCREASE * 0.1;
case HitResult.Great:
return DEFAULT_MAX_HEALTH_INCREASE * 0.8;
case HitResult.Perfect:
return DEFAULT_MAX_HEALTH_INCREASE;
default:
return base.HealthIncreaseFor(result);
}
}
}
}

View File

@@ -1,21 +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.
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
public class NoComboBreakLNTail : TailNote
{
public override Judgement CreateJudgement() => new NoComboBreakTailJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
public class NoComboBreakTailJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.IgnoreHit;
public override HitResult MinResult => HitResult.ComboBreak;
}
}
}

View File

@@ -1,21 +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.
using System.Threading;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
public class NoJudgementNote : Note
{
public NoJudgementNote(Note note)
{
StartTime = note.StartTime;
Column = note.Column;
Samples = note.Samples;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
{
}
}
}

View File

@@ -1,46 +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.
using System;
using System.Threading;
using osu.Game.Beatmaps;
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
public class NoJudgmentHoldNote : HoldNote
{
public NoJudgmentHoldNote(HoldNote hold)
{
StartTime = hold.StartTime;
Duration = hold.Duration;
Column = hold.Column;
NodeSamples = hold.NodeSamples;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
{
AddNested(Head = new HeadNote
{
StartTime = StartTime,
Column = Column,
Samples = GetNodeSamples(0),
});
AddNested(Tail = new NoComboBreakLNTail
{
StartTime = EndTime,
Column = Column,
Samples = GetNodeSamples((NodeSamples?.Count - 1) ?? 1),
});
AddNested(Body = new NoMissLNBody
{
StartTime = StartTime,
Column = Column,
});
}
}
}

View File

@@ -1,21 +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.
using osu.Game.Rulesets.Judgements;
using osu.Game.Rulesets.Mania.Judgements;
using osu.Game.Rulesets.Scoring;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
public class NoMissLNBody : HoldNoteBody
{
public override Judgement CreateJudgement() => new NoMissBodyJudgement();
protected override HitWindows CreateHitWindows() => HitWindows.Empty;
public class NoMissBodyJudgement : ManiaJudgement
{
public override HitResult MaxResult => HitResult.IgnoreHit;
public override HitResult MinResult => HitResult.IgnoreMiss;
}
}
}

View File

@@ -1,43 +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.
using System.Threading;
namespace osu.Game.Rulesets.Mania.Objects.EzCurrentHitObject
{
public class O2HoldNote : HoldNote
{
public O2HoldNote(HoldNote hold)
{
StartTime = hold.StartTime;
Duration = hold.Duration;
Column = hold.Column;
NodeSamples = hold.NodeSamples;
}
protected override void CreateNestedHitObjects(CancellationToken cancellationToken)
{
AddNested(Head = new O2LNHead
{
StartTime = StartTime,
Column = Column,
Samples = GetNodeSamples(0)
});
AddNested(Tail = new O2LNTail
{
StartTime = EndTime,
Column = Column,
Samples = GetNodeSamples(NodeSamples?.Count - 1 ?? 1)
});
AddNested(Body = new HoldNoteBody
{
StartTime = StartTime,
Column = Column
});
}
public override double MaximumJudgementOffset => base.MaximumJudgementOffset / TailNote.RELEASE_WINDOW_LENIENCE;
}
}