mirror of
https://github.com/SK-la/Ez2Lazer.git
synced 2026-03-13 11:20:28 +00:00
[A-B]修改mod和编辑器中的功能
This commit is contained in:
@@ -27,20 +27,20 @@ namespace osu.Game.Rulesets.Mania.Mods.LAsMods
|
||||
/// 基于凉雨的 Duplicate Mod, 解决无循环音频问题;
|
||||
/// <para></para>备注部分为我修改的内容, 增加IApplicableToPlayer, IApplicableToHUD, IPreviewOverrideProvider接口的使用
|
||||
/// </summary>
|
||||
public class ManiaModLoopPlayClip : Mod, IApplicableAfterBeatmapConversion, IHasSeed, IApplicableToPlayer, IApplicableToHUD, IPreviewOverrideProvider, ILoopTimeRangeMod
|
||||
public class ManiaModLoopPlayClip : Mod, IApplicableAfterBeatmapConversion, IHasSeed, IApplicableToPlayer, IApplicableToHUD, IPreviewOverrideProvider, ILoopTimeRangeMod, IApplicableFailOverride
|
||||
{
|
||||
private DuplicateVirtualTrack? duplicateTrack;
|
||||
private IWorkingBeatmap? pendingWorkingBeatmap;
|
||||
internal double? ResolvedCutTimeStart { get; private set; }
|
||||
internal double? ResolvedCutTimeEnd { get; private set; }
|
||||
internal double ResolvedSegmentLength { get; private set; }
|
||||
public override string Name => "LoopPlayClip";
|
||||
public override string Name => "Loop Play Clip (No Fail)";
|
||||
|
||||
public override string Acronym => "LPC";
|
||||
public override string Acronym => "LP";
|
||||
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
public override LocalisableString Description => "Cut the beatmap into a clip for loop practice.(The original is YuLiangSSS's Duplicate Mod)";
|
||||
public override LocalisableString Description => "Cut the beatmap into a clip for loop practice. (The original is YuLiangSSS's Duplicate Mod)";
|
||||
|
||||
public override IconUsage? Icon => FontAwesome.Solid.ArrowCircleDown;
|
||||
|
||||
@@ -52,10 +52,10 @@ namespace osu.Game.Rulesets.Mania.Mods.LAsMods
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return ($"{LoopCount.Value}", "Times");
|
||||
yield return ($"{LoopCount.Value}", "Loop Count");
|
||||
yield return ("Break", $"{BreakTime:N1}s");
|
||||
yield return ("Start", $"{(CutTimeStart.Value is null ? "Original Start Time" : CalculateTime((int)CutTimeStart.Value))}");
|
||||
yield return ("End", $"{(CutTimeEnd.Value is null ? "Original End Time" : CalculateTime((int)CutTimeEnd.Value))}");
|
||||
yield return ("Break", $"{BreakTime:N1}s");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -390,6 +390,10 @@ namespace osu.Game.Rulesets.Mania.Mods.LAsMods
|
||||
if (UseGlobalAbRange.Value)
|
||||
applyRangeFromStore();
|
||||
}
|
||||
|
||||
public bool PerformFail() => false;
|
||||
|
||||
public bool RestartOnFail => false;
|
||||
}
|
||||
|
||||
/*public partial class CutStart : RoundedSliderBar<double>
|
||||
|
||||
@@ -39,6 +39,18 @@ namespace osu.Game.LAsEzExtensions.Select
|
||||
private const double preview_window_length = 10000; // 10s
|
||||
private const double scheduler_interval = 16; // ~60fps
|
||||
private const double trigger_tolerance = 15; // ms 容差
|
||||
|
||||
// 外部时钟驱动(gameplay)模式下,过短的切片会导致高频 Seek/Restart,音频听感会明显“撕裂”。
|
||||
// 这里设置一个最小切片长度作为下限,避免 1ms 这类极端情况。
|
||||
private const double min_external_loop_segment_length = 200; // ms
|
||||
|
||||
// 在 gameplay 外部时钟驱动模式下,音频设备/解码缓冲会导致 Track.CurrentTime 与外部时钟存在微小漂移。
|
||||
// 若仍按 15ms 容差每帧 Seek,会产生明显的“撕裂/卡带”听感。
|
||||
// 因此对“音频轨道重同步”使用更宽容差,并加入冷却时间。
|
||||
private const double audio_resync_tolerance = 80; // ms
|
||||
private const double audio_resync_cooldown = 250; // ms
|
||||
|
||||
private double last_audio_resync_clock_time;
|
||||
private const double max_dynamic_preview_length = 30000; // 动态扩展最长 s
|
||||
private readonly SampleSchedulerState sampleScheduler = new SampleSchedulerState();
|
||||
|
||||
@@ -257,7 +269,9 @@ namespace osu.Game.LAsEzExtensions.Select
|
||||
? playback.PreviewStartTime + Math.Max(0, OverridePreviewDuration.Value)
|
||||
: playback.PreviewStartTime + preview_window_length;
|
||||
|
||||
playback.LoopSegmentLength = Math.Max(1, playback.PreviewEndTime - playback.PreviewStartTime);
|
||||
double segmentLength = playback.PreviewEndTime - playback.PreviewStartTime;
|
||||
double minSegmentLength = ExternalClock != null ? min_external_loop_segment_length : 1;
|
||||
playback.LoopSegmentLength = Math.Max(minSegmentLength, segmentLength);
|
||||
playback.LoopInterval = Math.Max(0, OverrideLoopInterval ?? 0);
|
||||
playback.EffectiveLoopCount = OverrideLoopCount ?? 1;
|
||||
// 当存在“切片/循环”相关 override 时,需要通过 updateSamples() 手动驱动 Track(Stop/Seek)。
|
||||
@@ -340,7 +354,8 @@ namespace osu.Game.LAsEzExtensions.Select
|
||||
? Math.Max(0, OverridePreviewDuration.Value)
|
||||
: dynamicEnd - playback.PreviewStartTime;
|
||||
|
||||
playback.LoopSegmentLength = Math.Max(1, segmentLength);
|
||||
double minSegmentLength = ExternalClock != null ? min_external_loop_segment_length : 1;
|
||||
playback.LoopSegmentLength = Math.Max(minSegmentLength, segmentLength);
|
||||
playback.EffectiveLoopCount = OverrideLoopCount ?? int.MaxValue;
|
||||
playback.LoopInterval = Math.Max(0, OverrideLoopInterval ?? 0);
|
||||
|
||||
@@ -516,8 +531,27 @@ namespace osu.Game.LAsEzExtensions.Select
|
||||
if (!currentTrack.IsRunning)
|
||||
currentTrack.Start();
|
||||
|
||||
if (Math.Abs(currentTrack.CurrentTime - logicalTime) > trigger_tolerance)
|
||||
currentTrack.Seek(logicalTime);
|
||||
double drift = Math.Abs(currentTrack.CurrentTime - logicalTime);
|
||||
|
||||
// 在 gameplay 外部时钟模式下,不要为了微小漂移每帧 Seek。
|
||||
// 只在漂移明显且超过冷却时间时才重同步一次。
|
||||
if (ExternalClock != null)
|
||||
{
|
||||
if (drift > audio_resync_tolerance && Clock.CurrentTime - last_audio_resync_clock_time >= audio_resync_cooldown)
|
||||
{
|
||||
currentTrack.Seek(logicalTime);
|
||||
last_audio_resync_clock_time = Clock.CurrentTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (drift > trigger_tolerance)
|
||||
currentTrack.Seek(logicalTime);
|
||||
}
|
||||
|
||||
// 记录上一次逻辑时间,供外部时钟“暂停/不推进”判定使用。
|
||||
// 否则在某些情况下会被误判为暂停,从而导致重复 Seek 到固定时间点。
|
||||
playback.LastTrackTime = logicalTime;
|
||||
|
||||
double logicalTimeForEvents = logicalTime;
|
||||
bool withinWindow = logicalTimeForEvents <= playback.PreviewEndTime + trigger_tolerance;
|
||||
|
||||
Reference in New Issue
Block a user