mirror of
https://github.com/SK-la/Ez2Lazer.git
synced 2026-03-13 11:20:28 +00:00
修复PS系列mod转换中潜在漏洞
This commit is contained in:
@@ -36,6 +36,9 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
public static class ManiaKeyPatternHelp
|
||||
{
|
||||
private const double add_note_alignment_tolerance = 6.0;
|
||||
private const double add_note_min_column_gap = 8.0;
|
||||
|
||||
internal readonly struct WindowContext
|
||||
{
|
||||
public readonly double BeatLength;
|
||||
@@ -475,17 +478,22 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
internal static bool TryAddNoteFromOrderedCandidates(ManiaBeatmap beatmap, IReadOnlyList<int> candidates, double time)
|
||||
{
|
||||
double alignedTime = AlignTimeToNearbyRow(beatmap, time, add_note_alignment_tolerance);
|
||||
|
||||
for (int i = 0; i < candidates.Count; i++)
|
||||
{
|
||||
int column = candidates[i];
|
||||
|
||||
if (IsHoldOccupyingColumn(beatmap, column, time))
|
||||
if (IsHoldOccupyingColumn(beatmap, column, alignedTime))
|
||||
continue;
|
||||
|
||||
if (HasNoteAtTime(beatmap, column, time))
|
||||
if (HasNoteAtTime(beatmap, column, alignedTime))
|
||||
return false;
|
||||
|
||||
beatmap.HitObjects.Add(new Note { Column = column, StartTime = time });
|
||||
if (hasAnyObjectInColumnNearTime(beatmap, column, alignedTime, add_note_min_column_gap))
|
||||
return false;
|
||||
|
||||
beatmap.HitObjects.Add(new Note { Column = column, StartTime = alignedTime });
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -498,7 +506,9 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
Random rng,
|
||||
double time)
|
||||
{
|
||||
int pickedIndex = pickIndexAvoidingHolds(beatmap, candidates, weights, rng, time);
|
||||
double alignedTime = AlignTimeToNearbyRow(beatmap, time, add_note_alignment_tolerance);
|
||||
|
||||
int pickedIndex = pickIndexAvoidingHolds(beatmap, candidates, weights, rng, alignedTime);
|
||||
if (pickedIndex < 0)
|
||||
return false;
|
||||
|
||||
@@ -506,13 +516,55 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
candidates.RemoveAt(pickedIndex);
|
||||
weights?.RemoveAt(pickedIndex);
|
||||
|
||||
if (HasNoteAtTime(beatmap, column, time))
|
||||
if (HasNoteAtTime(beatmap, column, alignedTime))
|
||||
return false;
|
||||
|
||||
beatmap.HitObjects.Add(new Note { Column = column, StartTime = time });
|
||||
if (hasAnyObjectInColumnNearTime(beatmap, column, alignedTime, add_note_min_column_gap))
|
||||
return false;
|
||||
|
||||
beatmap.HitObjects.Add(new Note { Column = column, StartTime = alignedTime });
|
||||
return true;
|
||||
}
|
||||
|
||||
internal static double AlignTimeToNearbyRow(ManiaBeatmap beatmap, double time, double tolerance = 3.0)
|
||||
{
|
||||
double bestTime = time;
|
||||
double bestDelta = tolerance;
|
||||
|
||||
foreach (var obj in beatmap.HitObjects)
|
||||
{
|
||||
double delta = Math.Abs(obj.StartTime - time);
|
||||
|
||||
if (delta > bestDelta)
|
||||
continue;
|
||||
|
||||
bestDelta = delta;
|
||||
bestTime = obj.StartTime;
|
||||
}
|
||||
|
||||
return bestTime;
|
||||
}
|
||||
|
||||
private static bool hasAnyObjectInColumnNearTime(ManiaBeatmap beatmap, int column, double time, double minGap, ManiaHitObject? ignore = null)
|
||||
{
|
||||
if (minGap <= 0)
|
||||
return false;
|
||||
|
||||
foreach (var obj in beatmap.HitObjects)
|
||||
{
|
||||
if (ReferenceEquals(obj, ignore))
|
||||
continue;
|
||||
|
||||
if (obj.Column != column)
|
||||
continue;
|
||||
|
||||
if (Math.Abs(obj.StartTime - time) < minGap)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Placement helpers (shared rule: hold occupied -> reselect, note exists -> skip).
|
||||
|
||||
internal static bool HasNoteAtTime(ManiaBeatmap beatmap, int column, double time, ManiaHitObject? ignore = null, double tolerance = 0.5)
|
||||
@@ -632,6 +684,52 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsWithinBeatFraction(double deltaTime, ManiaBeatmap beatmap, double referenceTime, double beatFraction, double tolerance = 0.5)
|
||||
{
|
||||
double beatLength = beatmap.ControlPointInfo.TimingPointAt(referenceTime).BeatLength;
|
||||
|
||||
if (beatLength <= 0)
|
||||
return false;
|
||||
|
||||
double threshold = beatLength * Math.Max(0, beatFraction);
|
||||
return deltaTime <= threshold + tolerance;
|
||||
}
|
||||
|
||||
internal static void RemoveSameColumnRunsWithinBeatFraction(ManiaBeatmap beatmap, double windowStart, double windowEnd, double beatFraction, double tolerance = 0.5)
|
||||
{
|
||||
var toRemove = new HashSet<ManiaHitObject>();
|
||||
|
||||
foreach (var group in beatmap.HitObjects.OfType<Note>().GroupBy(o => o.Column))
|
||||
{
|
||||
Note? previous = null;
|
||||
|
||||
foreach (var note in group.OrderBy(o => o.StartTime))
|
||||
{
|
||||
if (note.StartTime < windowStart - tolerance || note.StartTime > windowEnd + tolerance)
|
||||
continue;
|
||||
|
||||
if (previous == null)
|
||||
{
|
||||
previous = note;
|
||||
continue;
|
||||
}
|
||||
|
||||
double delta = note.StartTime - previous.StartTime;
|
||||
|
||||
if (IsWithinBeatFraction(delta, beatmap, previous.StartTime, beatFraction, tolerance))
|
||||
{
|
||||
toRemove.Add(note);
|
||||
continue;
|
||||
}
|
||||
|
||||
previous = note;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var obj in toRemove)
|
||||
beatmap.HitObjects.Remove(obj);
|
||||
}
|
||||
|
||||
internal static void Shuffle<T>(IList<T> list, Random rng)
|
||||
{
|
||||
for (int i = list.Count - 1; i > 0; i--)
|
||||
|
||||
@@ -24,6 +24,8 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
{
|
||||
public class ManiaModPatternShift : Mod, IApplicableAfterBeatmapConversion, IApplicableToBeatmapConverter, IHasSeed, IHasApplyOrder
|
||||
{
|
||||
private const double min_column_spacing_ms = 8;
|
||||
|
||||
public override string Name => "Pattern Shift";
|
||||
|
||||
public override string Acronym => "PS";
|
||||
@@ -250,14 +252,14 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
foreach (var note in chord.Notes)
|
||||
{
|
||||
int column = chooseColumn(keyCount, lastColumnTime, lastNote, rng, note.StartTime);
|
||||
int column = chooseColumn(keyCount, lastColumnTime, lastNote, rng, note.StartTime, min_column_spacing_ms);
|
||||
if (column < 0)
|
||||
continue;
|
||||
|
||||
if (usedColumns.Contains(column))
|
||||
continue;
|
||||
|
||||
if (hasAssignedNoteAtTime(placedNotes, column, note.StartTime))
|
||||
if (hasAssignedNoteAtTime(placedNotes, column, note.StartTime, min_column_spacing_ms))
|
||||
continue;
|
||||
|
||||
note.AssignedColumn = column;
|
||||
@@ -272,16 +274,28 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
}
|
||||
}
|
||||
|
||||
private static int chooseColumn(int keys, double[] lastUsedTime, int lastNote, Random rng, double currentTime)
|
||||
private static int chooseColumn(int keys, double[] lastUsedTime, int lastNote, Random rng, double currentTime, double minSpacingMs)
|
||||
{
|
||||
var candidates = new List<int>();
|
||||
|
||||
double safeTime = currentTime - Math.Max(0, minSpacingMs);
|
||||
|
||||
for (int i = 0; i < keys; i++)
|
||||
{
|
||||
if (lastUsedTime[i] <= currentTime)
|
||||
if (lastUsedTime[i] <= safeTime)
|
||||
candidates.Add(i);
|
||||
}
|
||||
|
||||
// 若严格最小间隔下无可用列,退化到旧逻辑,避免过多丢 note。
|
||||
if (candidates.Count == 0)
|
||||
{
|
||||
for (int i = 0; i < keys; i++)
|
||||
{
|
||||
if (lastUsedTime[i] <= currentTime)
|
||||
candidates.Add(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (candidates.Count == 0)
|
||||
return -1;
|
||||
|
||||
|
||||
@@ -101,6 +101,8 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
int direction = lastCol == firstCol ? (rng.Next(0, 2) == 0 ? -1 : 1) : (lastCol > firstCol ? 1 : -1);
|
||||
int prevTarget = firstCol;
|
||||
int lastAssignedColumn = firstCol;
|
||||
double lastAssignedTime = groups[0].time;
|
||||
|
||||
for (int g = 1; g < groups.Count; g++)
|
||||
{
|
||||
@@ -108,25 +110,48 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
if (time < windowStart - TIME_TOLERANCE || time > windowEnd + TIME_TOLERANCE)
|
||||
continue;
|
||||
|
||||
double delta = time - lastAssignedTime;
|
||||
bool forbidSameColumnWithPrevious = ManiaKeyPatternHelp.IsWithinBeatFraction(delta, beatmap, lastAssignedTime, 1.0 / 2.0, TIME_TOLERANCE);
|
||||
|
||||
int? forbiddenColumn = forbidSameColumnWithPrevious ? lastAssignedColumn : null;
|
||||
|
||||
int minCol = direction > 0 ? prevTarget + 1 : 0;
|
||||
int maxCol = direction > 0 ? totalColumns - 1 : prevTarget - 1;
|
||||
|
||||
if (!tryPickNearestColumn(beatmap, cur, time, minCol, maxCol, out int chosen))
|
||||
if (!tryPickNearestColumn(beatmap, cur, time, minCol, maxCol, out int chosen, forbiddenColumn))
|
||||
{
|
||||
// 允许保持不下降的单调(非严格)
|
||||
minCol = direction > 0 ? prevTarget : 0;
|
||||
maxCol = direction > 0 ? totalColumns - 1 : prevTarget;
|
||||
|
||||
if (!tryPickNearestColumn(beatmap, cur, time, minCol, maxCol, out chosen))
|
||||
continue;
|
||||
if (!tryPickNearestColumn(beatmap, cur, time, minCol, maxCol, out chosen, forbiddenColumn))
|
||||
{
|
||||
// 最后兜底:允许在全列找一个可用列,但仍禁止与前一个在 1/2 beat 内同列。
|
||||
if (!tryPickNearestColumn(beatmap, cur, time, 0, totalColumns - 1, out chosen, forbiddenColumn))
|
||||
{
|
||||
if (forbidSameColumnWithPrevious && cur.Column == lastAssignedColumn)
|
||||
{
|
||||
beatmap.HitObjects.Remove(cur);
|
||||
continue;
|
||||
}
|
||||
|
||||
lastAssignedColumn = cur.Column;
|
||||
lastAssignedTime = time;
|
||||
prevTarget = cur.Column;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cur.Column = chosen;
|
||||
prevTarget = chosen;
|
||||
lastAssignedColumn = chosen;
|
||||
lastAssignedTime = time;
|
||||
}
|
||||
|
||||
// 大间隙单调滑梯:首尾间隔至少 1/2 拍才添加
|
||||
tryAddLargeGapSlide(beatmap, windowObjects, groups, beatLength, rng, settings);
|
||||
ManiaKeyPatternHelp.RemoveSameColumnRunsWithinBeatFraction(beatmap, windowStart, windowEnd, 1.0 / 2.0, TIME_TOLERANCE);
|
||||
}
|
||||
|
||||
private static void tryAddLargeGapSlide(ManiaBeatmap beatmap,
|
||||
@@ -195,7 +220,8 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
double time,
|
||||
int minCol,
|
||||
int maxCol,
|
||||
out int chosen)
|
||||
out int chosen,
|
||||
int? forbiddenColumn = null)
|
||||
{
|
||||
int totalColumns = Math.Max(1, beatmap.TotalColumns);
|
||||
int clampedMin = Math.Clamp(minCol, 0, totalColumns - 1);
|
||||
@@ -209,7 +235,7 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
for (int col = clampedMin; col <= clampedMax; col++)
|
||||
{
|
||||
if (!isColumnAvailable(beatmap, obj, col, time))
|
||||
if ((forbiddenColumn.HasValue && col == forbiddenColumn.Value) || !isColumnAvailable(beatmap, obj, col, time))
|
||||
continue;
|
||||
|
||||
int dist = Math.Abs(col - obj.Column);
|
||||
|
||||
@@ -268,6 +268,8 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
Random rng,
|
||||
double timeTolerance)
|
||||
{
|
||||
double alignedTime = ManiaKeyPatternHelp.AlignTimeToNearbyRow(beatmap, time, timeTolerance);
|
||||
|
||||
// 不允许在整拍(1/1)上添加 note。
|
||||
if (addNote)
|
||||
{
|
||||
@@ -275,14 +277,14 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
if (beatLength > 0)
|
||||
{
|
||||
double mod = time % beatLength;
|
||||
double mod = alignedTime % beatLength;
|
||||
if (mod <= timeTolerance || Math.Abs(beatLength - mod) <= timeTolerance)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int totalColumns = Math.Max(1, beatmap.TotalColumns);
|
||||
var sourceNotes = ManiaKeyPatternHelp.GetNotesAtTime(windowObjects, time, timeTolerance);
|
||||
var sourceNotes = ManiaKeyPatternHelp.GetNotesAtTime(windowObjects, alignedTime, timeTolerance);
|
||||
|
||||
if (sourceNotes.Count == 0)
|
||||
return false;
|
||||
@@ -292,8 +294,8 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
for (int column = 0; column < totalColumns; column++)
|
||||
{
|
||||
bool hasPrev = time - quarter >= 0 && ManiaKeyPatternHelp.HasNoteAtTime(beatmap, column, time - quarter, null, timeTolerance);
|
||||
bool hasNext = ManiaKeyPatternHelp.HasNoteAtTime(beatmap, column, time + quarter, null, timeTolerance);
|
||||
bool hasPrev = alignedTime - quarter >= 0 && ManiaKeyPatternHelp.HasNoteAtTime(beatmap, column, alignedTime - quarter, null, timeTolerance);
|
||||
bool hasNext = ManiaKeyPatternHelp.HasNoteAtTime(beatmap, column, alignedTime + quarter, null, timeTolerance);
|
||||
|
||||
if (hasPrev && hasNext)
|
||||
bothSides.Add(column);
|
||||
@@ -339,18 +341,18 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
|
||||
if (addNote)
|
||||
{
|
||||
if (ManiaKeyPatternHelp.HasNoteAtTime(beatmap, targetColumn, time, null, timeTolerance))
|
||||
if (ManiaKeyPatternHelp.HasNoteAtTime(beatmap, targetColumn, alignedTime, null, timeTolerance))
|
||||
continue;
|
||||
|
||||
if (ManiaKeyPatternHelp.IsHoldOccupyingColumn(beatmap, targetColumn, time, null, timeTolerance))
|
||||
if (ManiaKeyPatternHelp.IsHoldOccupyingColumn(beatmap, targetColumn, alignedTime, null, timeTolerance))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ManiaKeyPatternHelp.HasNoteAtTime(beatmap, targetColumn, time, source, timeTolerance))
|
||||
if (ManiaKeyPatternHelp.HasNoteAtTime(beatmap, targetColumn, alignedTime, source, timeTolerance))
|
||||
continue;
|
||||
|
||||
if (ManiaKeyPatternHelp.IsHoldOccupyingColumn(beatmap, targetColumn, time, source, timeTolerance))
|
||||
if (ManiaKeyPatternHelp.IsHoldOccupyingColumn(beatmap, targetColumn, alignedTime, source, timeTolerance))
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -365,7 +367,7 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
available.RemoveAt(targetIndex);
|
||||
|
||||
if (addNote)
|
||||
beatmap.HitObjects.Add(new Note { Column = target, StartTime = time });
|
||||
beatmap.HitObjects.Add(new Note { Column = target, StartTime = alignedTime });
|
||||
else
|
||||
source.Column = target;
|
||||
|
||||
|
||||
@@ -32,12 +32,12 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
// beatmap.HitObjects.AddRange(resolved);
|
||||
// }
|
||||
|
||||
// 2) 去除重叠并降低密度
|
||||
// 去除重叠并降低密度
|
||||
CleanOverlapNotes(beatmap);
|
||||
// 3) 在同一列中强制最小间隙
|
||||
EnforceMinimumGaps(beatmap);
|
||||
// 4) Enforce hold-release gap and convert too-short holds to notes.
|
||||
// Enforce hold-release gap and convert too-short holds to notes.
|
||||
EnforceHoldReleaseGap(beatmap);
|
||||
// 调整/转换可能再次引入过小间距,做一次最终兜底。
|
||||
EnforceMinimumGaps(beatmap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -84,9 +84,21 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
return 0;
|
||||
|
||||
double startTime = beatmap.HitObjects.Min(h => h.StartTime);
|
||||
double beatLength = beatmap.ControlPointInfo.TimingPointAt(startTime).BeatLength;
|
||||
double gap = beatLength / beat;
|
||||
return Math.Clamp(gap, 30, beatLength / beat * 2);
|
||||
return getMinimumGapAtTime(beatmap, startTime, beat);
|
||||
}
|
||||
|
||||
private static double getMinimumGapAtTime(ManiaBeatmap beatmap, double time, int beat = 8)
|
||||
{
|
||||
int safeBeatDivisor = Math.Max(1, beat);
|
||||
double beatLength = beatmap.ControlPointInfo.TimingPointAt(time).BeatLength;
|
||||
|
||||
if (beatLength <= 0)
|
||||
return 30;
|
||||
|
||||
double beatGap = beatLength / safeBeatDivisor;
|
||||
|
||||
// 保留“按节拍”判定,同时使用 30ms 作为保守下限,避免高速段阈值过小。
|
||||
return Math.Max(30, beatGap);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -98,7 +110,6 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
if (beatmap.HitObjects.Count == 0)
|
||||
return;
|
||||
|
||||
double minGapMs = GetMinimumGapMs(beatmap);
|
||||
int targetKeys = beatmap.TotalColumns;
|
||||
|
||||
var byColumn = beatmap.HitObjects.ToList().GroupBy(o => Math.Clamp(o.Column, 0, Math.Max(0, targetKeys - 1)));
|
||||
@@ -107,53 +118,24 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
foreach (var colGroup in byColumn)
|
||||
{
|
||||
var list = colGroup.OrderBy(o => o.StartTime).ToList();
|
||||
if (list.Count == 0) continue;
|
||||
if (list.Count == 0)
|
||||
continue;
|
||||
|
||||
// 第一步:预先移除极度密集的音符(> 1/8 拍)作为快速预处理
|
||||
var denseFiltered = new List<ManiaHitObject> { list[0] };
|
||||
var kept = new List<ManiaHitObject> { list[0] };
|
||||
|
||||
for (int i = 1; i < list.Count; i++)
|
||||
{
|
||||
var prev = denseFiltered.Last();
|
||||
var curr = list[i];
|
||||
|
||||
if (curr.StartTime - prev.StartTime < minGapMs)
|
||||
continue; // 丢弃当前音符(过于密集)
|
||||
|
||||
denseFiltered.Add(curr);
|
||||
}
|
||||
|
||||
// 第二步:应用最小间隙规则,包含向前查看的三连处理
|
||||
var kept = new List<ManiaHitObject> { denseFiltered[0] };
|
||||
int idx = 0;
|
||||
|
||||
while (++idx < denseFiltered.Count)
|
||||
{
|
||||
var prev = kept.Last();
|
||||
var cur = denseFiltered[idx];
|
||||
var current = list[i];
|
||||
|
||||
double prevEnd = prev is HoldNote ph ? ph.EndTime : prev.StartTime;
|
||||
double gap = cur.StartTime - prevEnd;
|
||||
double prevEnd = prev is HoldNote prevHold ? prevHold.EndTime : prev.StartTime;
|
||||
double requiredGap = getMinimumGapAtTime(beatmap, prevEnd);
|
||||
double actualGap = current.StartTime - prevEnd;
|
||||
|
||||
if (gap >= minGapMs)
|
||||
{
|
||||
kept.Add(cur);
|
||||
if (actualGap < requiredGap)
|
||||
continue;
|
||||
}
|
||||
|
||||
// 间隙过小:尝试向前查看并删除中间音符
|
||||
if (idx + 1 < denseFiltered.Count)
|
||||
{
|
||||
var next = denseFiltered[idx + 1];
|
||||
double nextGap = next.StartTime - prevEnd;
|
||||
|
||||
if (nextGap >= minGapMs)
|
||||
{
|
||||
// 删除当前(中间)音符,前进到下一个
|
||||
idx++; // will move to next in outer loop
|
||||
kept.Add(next);
|
||||
}
|
||||
}
|
||||
kept.Add(current);
|
||||
}
|
||||
|
||||
survivors.AddRange(kept);
|
||||
@@ -172,7 +154,6 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
/// <param name="beat"></param>
|
||||
internal static void EnforceHoldReleaseGap(ManiaBeatmap beatmap, int beat = 8)
|
||||
{
|
||||
double minGapMs = GetMinimumGapMs(beatmap, beat);
|
||||
if (beatmap.HitObjects.Count == 0)
|
||||
return;
|
||||
|
||||
@@ -188,6 +169,7 @@ namespace osu.Game.Rulesets.Mania.LAsEzMania.Mods.LAsMods
|
||||
continue;
|
||||
|
||||
var next = list[i + 1];
|
||||
double minGapMs = getMinimumGapAtTime(beatmap, next.StartTime, beat);
|
||||
double gap = next.StartTime - hold.EndTime;
|
||||
|
||||
if (gap >= minGapMs)
|
||||
|
||||
Reference in New Issue
Block a user