From 458e69355d4b5fb481da05a541a10606cf31deca Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Thu, 7 May 2026 17:44:35 -0400 Subject: [PATCH 1/2] Change timing to be fixated around the update task --- Rebound/Plugin.cs | 46 ++++++++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/Rebound/Plugin.cs b/Rebound/Plugin.cs index cb8d171..deb8544 100644 --- a/Rebound/Plugin.cs +++ b/Rebound/Plugin.cs @@ -4,8 +4,10 @@ using Dalamud.IoC; using Dalamud.Plugin; using Dalamud.Plugin.Services; +using Dalamud.Utility.Signatures; using FFXIVClientStructs.FFXIV.Client.Graphics.Physics; using static FFXIVClientStructs.FFXIV.Client.Graphics.Physics.BonePhysicsUpdater; +using FFXIVClientStructs.FFXIV.Client.System.Framework; namespace Rebound; @@ -13,6 +15,9 @@ public sealed class Plugin : IDalamudPlugin { private readonly Hook? boneSimulatorUpdateHook = null!; + [Signature("F3 0F 10 89 ?? ?? ?? ?? 4C 8B C2", DetourName = nameof(TaskHook))] + private readonly Hook? taskHook = null!; + #if DEBUG /// If the fix should be enabled, it's only toggleable here for debug purposes public bool EnableFix = true; @@ -38,7 +43,7 @@ public Plugin() startTick = DateTime.Now.Ticks; boneSimulatorUpdateHook?.Enable(); - Framework.Update += Update; + taskHook?.Enable(); #if DEBUG DebugWindow = new DebugWindow(this); @@ -51,9 +56,6 @@ public Plugin() #endif } - [PluginService] - internal static IFramework Framework { get; private set; } = null!; - [PluginService] internal static IGameInteropProvider Hooking { get; private set; } = null!; @@ -74,7 +76,7 @@ public Plugin() public void Dispose() { boneSimulatorUpdateHook?.Dispose(); - Framework.Update -= Update; + taskHook?.Dispose(); #if DEBUG WindowSystem.RemoveAllWindows(); @@ -82,13 +84,24 @@ public void Dispose() #endif } - // Called every frame. - public void Update(IFramework _) + /// Our new bone simulator update function. + /// Called for each BoneSimulator, so possibly multiple times every frame. Should be kept very simple for performance reasons. + private unsafe void BoneUpdate(BonePhysicsUpdater* self, UpdateBoneSimulatorJobData* data) + { + if (!ExecutePhysics) + { + return; + } + + boneSimulatorUpdateHook!.Original(self, data); + } + + private unsafe void TaskHook(void* a1, void* a2) { #if DEBUG if (!EnableFix) { - ExecutePhysics = true; + taskHook!.Original(a1, a2); return; } #endif @@ -96,7 +109,7 @@ public void Update(IFramework _) // Don't apply our "fix" to cutscenes, the delay in updates causes animations to look buggy. if (PluginInterface.UiBuilder.CutsceneActive) { - ExecutePhysics = true; + taskHook!.Original(a1, a2); return; } @@ -118,20 +131,13 @@ public void Update(IFramework _) RanPhysics = true; ExecutePhysics = true; } - } - - /// Our new bone simulator update function. - /// Called for each BoneSimulator, so possibly multiple times every frame. Should be kept very simple for performance reasons. - private unsafe void BoneUpdate(BonePhysicsUpdater* self, UpdateBoneSimulatorJobData* data) - { - if (!ExecutePhysics) - { - return; - } - boneSimulatorUpdateHook!.Original(self, data); + taskHook!.Original(a1, a2); } + /// The detour function signature + private unsafe delegate void TaskHookDelegate(void* a1, void* a2); + #if DEBUG private void DrawUi() => WindowSystem.Draw(); #endif From afe50099471e51499f9e75b7ade0ae6b6ad22542 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Thu, 7 May 2026 17:54:38 -0400 Subject: [PATCH 2/2] Override Framework's delta time in case that fixes something --- Rebound/Plugin.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Rebound/Plugin.cs b/Rebound/Plugin.cs index deb8544..31e02c9 100644 --- a/Rebound/Plugin.cs +++ b/Rebound/Plugin.cs @@ -96,12 +96,13 @@ private unsafe void BoneUpdate(BonePhysicsUpdater* self, UpdateBoneSimulatorJobD boneSimulatorUpdateHook!.Original(self, data); } - private unsafe void TaskHook(void* a1, void* a2) + private unsafe void TaskHook(Framework* self, void* a2) { #if DEBUG if (!EnableFix) { - taskHook!.Original(a1, a2); + ExecutePhysics = true; + taskHook!.Original(self, a2); return; } #endif @@ -109,7 +110,8 @@ private unsafe void TaskHook(void* a1, void* a2) // Don't apply our "fix" to cutscenes, the delay in updates causes animations to look buggy. if (PluginInterface.UiBuilder.CutsceneActive) { - taskHook!.Original(a1, a2); + ExecutePhysics = true; + taskHook!.Original(self, a2); return; } @@ -132,11 +134,14 @@ private unsafe void TaskHook(void* a1, void* a2) ExecutePhysics = true; } - taskHook!.Original(a1, a2); + var oldDeltaTime = self->FrameDeltaTime; + self->FrameDeltaTime = 1.0f / (float)TargetFps; // Unsure if this helps at all, but just in case. + taskHook!.Original(self, a2); + self->FrameDeltaTime = oldDeltaTime; } /// The detour function signature - private unsafe delegate void TaskHookDelegate(void* a1, void* a2); + private unsafe delegate void TaskHookDelegate(Framework* self, void* a2); #if DEBUG private void DrawUi() => WindowSystem.Draw();