SHA256
116 lines
4.1 KiB
C#
116 lines
4.1 KiB
C#
using System;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using ADOFAIRenderer.Core;
|
|
using HarmonyLib;
|
|
using UnityEngine;
|
|
|
|
namespace ADOFAIRenderer.Patch.Game;
|
|
|
|
// === [MARKER: FIX_SET_FRAMERATE_BUG START] ===
|
|
/// <summary>
|
|
/// Fixes the in-game and render bug where objects (floors, decorations, planets) disappear on the first frame of
|
|
/// a SetFramerate event (due to camera Z=0 near clip culling) and where parallax/tiles lag behind on subsequent frames.
|
|
/// <para>
|
|
/// Defers the manual camera rendering (<c>scrCamera.UpdateCustomFrameRateScreen</c>) to the very end of the frame
|
|
/// (execution order <c>int.MaxValue - 1</c>), after all components (<c>scrCamera</c>, <c>scrFloor</c>,
|
|
/// <c>scrDecorationManager</c>, <c>scrPlanet</c>, <c>scrParallax</c>, and <c>scrController</c>) have finished their
|
|
/// <c>LateUpdate</c>.
|
|
/// </para>
|
|
/// </summary>
|
|
[HarmonyPatch]
|
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
|
public static class CustomFrameRateDeferPatch
|
|
{
|
|
private static bool _isExecutingDeferred;
|
|
private static scrCamera? _pendingCamera;
|
|
|
|
private static readonly Action<scrCamera>? UpdateCustomFrameRateScreenInvoker =
|
|
AccessTools.MethodDelegate<Action<scrCamera>>(AccessTools.Method(typeof(scrCamera), "UpdateCustomFrameRateScreen"));
|
|
|
|
/// <summary>
|
|
/// Checks whether the SetFramerate render timing fix is enabled.
|
|
/// Active if rendering session has the option enabled, or enabled by default during normal in-game play.
|
|
/// </summary>
|
|
public static bool IsEnabled
|
|
{
|
|
get
|
|
{
|
|
if (RenderManager.IsActive && RenderManager.Instance?.Configuration?.AdvancedConfig != null)
|
|
{
|
|
return RenderManager.Instance.Configuration.AdvancedConfig.FixCustomFrameRate;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Intercepts manual camera render calls from SetCustomFrameRate (Update phase) or CheckUpdateFrameRateScreen
|
|
/// (LateUpdate phase). If not currently executing the deferred render pass, records the camera instance and
|
|
/// suppresses the premature render.
|
|
/// </summary>
|
|
[HarmonyPrefix]
|
|
[HarmonyPatch(typeof(scrCamera), "UpdateCustomFrameRateScreen")]
|
|
private static bool DeferManualRender(scrCamera __instance)
|
|
{
|
|
if (!IsEnabled) return true;
|
|
if (_isExecutingDeferred) return true;
|
|
|
|
_pendingCamera = __instance;
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensures that the runner component is attached to the camera when it starts.
|
|
/// </summary>
|
|
[HarmonyPostfix]
|
|
[HarmonyPatch(typeof(scrCamera), "Start")]
|
|
private static void AttachRunner(scrCamera __instance)
|
|
{
|
|
if (!__instance) return;
|
|
if (!__instance.gameObject.GetComponent<CustomFrameRateDeferredRunner>())
|
|
{
|
|
__instance.gameObject.AddComponent<CustomFrameRateDeferredRunner>();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invoked at the very end of LateUpdate (Order int.MaxValue - 1). If a manual render was requested during the frame,
|
|
/// executes the camera's original UpdateCustomFrameRateScreen once with all objects fully prepared.
|
|
/// </summary>
|
|
internal static void ExecuteDeferredRender()
|
|
{
|
|
if (_pendingCamera == null) return;
|
|
|
|
var cam = _pendingCamera;
|
|
_pendingCamera = null;
|
|
|
|
if (!cam) return;
|
|
|
|
_isExecutingDeferred = true;
|
|
try
|
|
{
|
|
UpdateCustomFrameRateScreenInvoker?.Invoke(cam);
|
|
}
|
|
finally
|
|
{
|
|
_isExecutingDeferred = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Runner component attached to scrCamera that executes deferred custom frame rate renders at the end of LateUpdate.
|
|
/// Execution order <c>int.MaxValue - 1</c> guarantees it runs after all normal game components (including
|
|
/// scrController at 400), but right before PostRenderHook at <c>int.MaxValue</c>.
|
|
/// </summary>
|
|
[DefaultExecutionOrder(int.MaxValue - 1)]
|
|
internal class CustomFrameRateDeferredRunner : MonoBehaviour
|
|
{
|
|
private void LateUpdate()
|
|
{
|
|
CustomFrameRateDeferPatch.ExecuteDeferredRender();
|
|
}
|
|
}
|
|
// === [MARKER: FIX_SET_FRAMERATE_BUG END] ===
|