Files
ADOFAIRenderer/Patch/Engine/AsyncInputPatches.cs
T
2026-10-15 16:17:13 +09:00

41 lines
2.2 KiB
C#

using ADOFAIRenderer.Core;
using HarmonyLib;
namespace ADOFAIRenderer.Patch.Engine;
/// <summary>
/// Makes the async input clock offset follow the render clock immediately.
/// <para>
/// Patched member: <c>AsyncInputUtils.UpdateOffsetTime(long fixDivider = 1)</c>. The async input system maps wall-clock ticks
/// (<c>AsyncInputManager.currFrameTick</c> = <c>DateTime.Now.Ticks</c>, 100 ns units) to conductor time with
/// <c>AsyncInputManager.offsetTick</c> = currFrameTick - <c>scrConductor.dspTime</c> * 10^7. With <c>fixDivider</c> 1 the
/// offset is set directly; otherwise it moves by 1 / fixDivider of the difference per call. <c>scrConductor</c> calls it every
/// frame with divider 100 (damped); <c>scrController</c> calls it with divider 1.
/// </para>
/// <para>
/// Active while <see cref="RenderManager.IsActive"/> (stage &gt;= OnScene). From stage Render the conductor time follows the
/// patched <c>AudioSettings.dspTime</c> (offline render clock, a fixed step per frame independent of wall-clock time), so the
/// difference changes every frame; the damped update would lag behind it. The prefix always applies the divider-1 update.
/// </para>
/// <para>Reference: https://learn.microsoft.com/en-us/dotnet/api/system.datetime.ticks</para>
/// </summary>
[HarmonyPatch(typeof(AsyncInputUtils), "UpdateOffsetTime")]
// ReSharper disable once InconsistentNaming
public static class AsyncInputPatches
{
/// <summary>
/// Prefix of <c>AsyncInputUtils.UpdateOffsetTime</c>. While rendering, sets <c>offsetTick</c> to
/// currFrameTick - dspTime * 10^7 (10^7 = 100 ns ticks per second) and <c>offsetTickUpdated</c> to true, for any divider.
/// </summary>
/// <returns>True to run the original method (not rendering); false to skip it (rendering).</returns>
[HarmonyPrefix]
// ReSharper disable once InconsistentNaming
public static bool Prefix()
{
if (!RenderManager.IsActive) return true;
// Force offsetTick to match instantly without 1/100 damping division when rendering
AsyncInputManager.offsetTick = AsyncInputManager.currFrameTick - (long)(scrConductor.instance.dspTime * 10000000.0);
AsyncInputManager.offsetTickUpdated = true;
return false; // Skip the original damped offset calculation
}
}