Skip to content

Releases: playday3008/PatchFix

PatchFix Releases

Choose a tag to compare

@github-actions github-actions released this 26 Sep 20:54

Releases are published per game. Pick the latest release for your game:

Game Latest release
AC.Rogue.PatchFix ac-rogue/v3.3.1
AC.Syndicate.PatchFix ac-syndicate/v3.3.1

Releases up to v3.3.0 bundled every game under one tag.

ac-syndicate/v3.3.1

Choose a tag to compare

What's Changed

Full Changelog: v3.3.0...ac-syndicate/v3.3.1

ac-rogue/v3.3.1

Choose a tag to compare

@github-actions github-actions released this 26 Sep 20:53

What's Changed

Full Changelog: v3.3.0...ac-rogue/v3.3.1

v3.3.0

Choose a tag to compare

@github-actions github-actions released this 19 Sep 16:26
b7dd5f4

Ultrawide renders correctly in Syndicate, and Rogue's frame rate no longer slows the game down or throws the camera around.

What's New

Syndicate ultrawide (AspectRatioFix)

The engine computes the correct aspect ratio for the selected mode and stores it at +0x95C/+0x960, but the viewport code reads +0x92C/+0x930. Only the AMD SLS paths write that second block, and both are gated off on a single monitor, so it keeps the 16:9 value it was initialised with and every ultrawide render is stretched -- in fullscreen and in borderless alike.

The new AspectRatioFix hook mirrors the computed ratio and its gate bytes into the block the consumer actually reads. Confirmed at 3440x1440: fullscreen and borderless both render correctly.

[Video]
; Aspect ratio override. Auto(0) = derive from the resolution the game applies.
; Accepts ratio like 21:9, 32:9, or decimal like 2.389
AspectRatio=0

[Hooks]
AspectRatioFix=true

Leaving AspectRatio=0 derives the ratio from whatever resolution the game applies, which is what you want unless the display reports something the game misreads.

Rogue frame pacing (FPSUnlock rework)

Setting a cap above the display's own ceiling ran the game in slow motion: at Target=120 against a 60 Hz present, the simulation advanced at half speed.

Two separate causes, both in how the plugin drove the engine's timing mode:

  • Mode 3 was never an uncap. UpdateFrameTiming re-arms the frame deadline for modes 0, 1 and 3, so mode 3 paced each frame to its own 15-frame trailing average and then fed that lagging average back as the frame delta.
  • Mode 0 ignored wall time. It stepped the simulation by 1/fixed_rate regardless of how long the frame actually took, so any external limiter below the cap slowed the game in proportion.

Both uncapped and capped now go through mode 2, which keeps the measured delta and the engine's 1/15 s clamp. Its deadline period is a float with a single reference in the binary: 0 leaves the deadline at the current time so the wait loop never runs, 1000/target paces to the cap.

While a cap is set the plugin also raises the process timer resolution to 1 ms. The game never calls timeBeginPeriod itself, so Sleep(1) rounds up to roughly 15.6 ms and nothing above about 64 FPS is reachable. Uncapped there is no wait at all, so the resolution is left alone.

Measured under Proton with DXVK holding Present at 60, simulation time taken from FrameTiming.accumulated_ticks against QPC:

Build Target Present Sim speed
v3.2.0 120 60 0.50x
v3.2.0 0 60 1.00x
v3.3.0 120 60 1.00x

Refs #9.

Rogue camera lean (CameraLean)

The sprint camera sway is an additive sequence track on the CameraFXInterface roll angle, applied once per frame with no time step, so it scales directly with frame rate: a gentle lean at 30 fps becomes a 30-40 degree roll at 200 that snaps back when the sequence ends. Every camera modifier upstream of the FX pass is level, which is why this took a hardware watchpoint on the roll field to find.

The new CameraLean hook scales the track weight by frame_dt * ReferenceFPS at the sequence dispatcher, and only for additive tracks bound to that object. Measured at about 215 fps over 30 s of sprint-tapping: peak roll 24.7 deg without the hook, 6.0 deg with it at ReferenceFPS=60.

Fixes #8.

Rogue mouse smoothing (MouseSmoothing)

The counterpart to Syndicate's CameraSmoothing, but it cannot work the same way. Syndicate has a boolean gate choosing between a direct copy and a damped lerp of the look axes, so its hook flips one jnz to jmp. Rogue has no such gate -- tracing the look input end to end, the mouse delta is written raw into the virtual right stick and reaches all five consumers of that axis unfiltered. The lag that keeps the camera drifting after the mouse stops is applied further downstream, in the camera's own damping, which in this engine is data-driven. There is no branch to flip and no constant in the exe to change.

So MouseSmoothing hooks the input update where the delta is live -- after the cursor-mode filter, before the event consumers -- and pre-emphasises it to invert a first-order lag. Feeding estimate + (raw - estimate) / factor makes the downstream filter land on raw.

It is gated on is_in_game(), because menus drive the hardware cursor from the same DIMOUSESTATE buffer and amplifying deltas there makes the cursor unusable.

Debuggers can attach to Syndicate

VMProtect's debugger check redirects ntdll!DbgUiRemoteBreakin to a stub whose entire body is TerminateProcess(0xDEADC0DE), so the thread the OS injects on DebugActiveProcess killed the game instead of raising the breakpoint a debugger expects.

The plugin now restores the function's 5-byte prologue from the copy of ntdll on disk, putting it back to what the loader mapped. Verified live: Cheat Engine attaches, the game keeps running, and the bytes still read clean afterwards, so the packer does not reapply its patch. Useful if you want to poke at the game yourself.

Codebase audit

A full audit against the real binaries through the IDA databases, rather than inferred from source. The parts that affect you:

  • ResolutionFix could crash. Its early return used trampoline_rsp = rsp + 8, which points at shadow space rather than the return address, so filtering a mode jumped to whatever that slot held. Only reachable on a display that publishes a non-standard mode.
  • A VMProtect race. The CreateThread hook was armed before its result was stored, so a thread entering that window called through an unset hook and never reached the real CreateThread.
  • Config parsing was too permissive. AspectRatio = 1.7abc parsed as 1.7, and nan and inf were accepted. Values are now trimmed, fully consumed and checked finite, falling back to the declared default.
  • Deleting an INI key did nothing until restart -- the field kept its old value. It now restores its default on reload.
  • Silent partial hooks. An optional signature that stopped matching left part of a hook inactive with no way to tell that from a hook working as intended. The registry now warns per unresolved signature, by name, after install.

Builds are warnings-as-errors in CI, and the test suite runs under CTest with 37 passing tests in both configurations.

Configuration

New keys, both games. An existing INI works unchanged -- missing keys fall back to the defaults -- but copy the shipped INI if you want the new entries documented in place.

AC.Rogue.PatchFix.ini:

[CameraLean]
; Frame rate the lean was tuned for. At this rate the fix changes nothing; the
; game shipped capped at 30, so 30 reproduces the sway as designed and 60 keeps
; the stronger sway an unlocked 60 fps machine had. 0 removes the lean entirely.
ReferenceFPS=30

[Input]
; The engine's blend coefficient, measured by feel. 1.0 disables the
; compensation entirely. Lower it until the camera stops when the mouse stops;
; too low overshoots and the camera snaps back. Values below 0.02 are treated
; as off and logged. This is a per-frame coefficient: if the feel changes after
; changing [FPS] Target, retune it.
SmoothingFactor=0.1

[Hooks]
CameraLean=true
MouseSmoothing=true

AC.Syndicate.PatchFix.ini:

[Video]
; Aspect ratio override. Auto(0) = derive from the resolution the game applies.
; Accepts ratio like 21:9, 32:9, or decimal like 2.389
AspectRatio=0

[Hooks]
AspectRatioFix=true

Assets

File Description
AC.Rogue.PatchFix.asi Rogue plugin (Windows)
AC.Rogue.PatchFix-wine.asi Rogue plugin (Wine/Proton cross-compiled)
AC.Rogue.PatchFix.ini Rogue default configuration
AC.Syndicate.PatchFix.asi Syndicate plugin (Windows)
AC.Syndicate.PatchFix-wine.asi Syndicate plugin (Wine/Proton cross-compiled)
AC.Syndicate.PatchFix.ini Syndicate default configuration

What's Changed

Full Changelog: v3.2.0...v3.3.0

v3.2.0

Choose a tag to compare

@github-actions github-actions released this 04 Sep 17:56

Syndicate camera smoothing can be turned off, so the camera follows the mouse directly.

What's New

Syndicate camera smoothing toggle

The camera lerps toward its target orientation instead of snapping to it, which reads as mouse smoothing and adds input latency to every look movement. The engine already carries a flag that bypasses the interpolation, checked by a jnz immediately before it:

mov   rcx, [r13+0xA20]
cmp   byte [rcx+0x104], 0
jnz   skip_smoothing        ; patched to jmp
...
movss xmm0, [rbx+0xA0]
call  <lerp>
movss [rax+0xA0], xmm0

The new CameraSmoothing hook rewrites that opcode from 0x75 to 0xEB, keeping the displacement, so the smoothing block is always skipped and the target orientation is written straight through. Restoring 0x75 re-enables it, which makes the setting hot-reloadable - edit the INI while the game runs and the change applies without a restart.

install() refuses to patch unless the byte actually reads 0x75, so a signature that drifts on a future game build fails loudly instead of corrupting an instruction.

[Input]
; CameraSmoothing: Disable the camera smoothing the game applies to look
; input, so the camera follows the mouse directly instead of lerping toward
; it. Hot-reloadable - unlike the [Hooks] toggle below, which only decides
; whether the hook installs at startup, this key takes effect immediately.
DisableCameraSmoothing=true

[Hooks]
CameraSmoothing=true

Both default to true. An existing AC.Syndicate.PatchFix.ini works unchanged - missing keys fall back to the defaults - but copy the shipped INI if you want the new entries documented in place.

Rogue was checked for the same mechanism and does not have it: its camera path has no equivalent bypass flag, so there is no Rogue-side counterpart in this release.

Credit: the branch was identified by @lnx00 in game-patches.

Assets

File Description
AC.Rogue.PatchFix.asi Rogue plugin (Windows)
AC.Rogue.PatchFix-wine.asi Rogue plugin (Wine/Proton cross-compiled)
AC.Rogue.PatchFix.ini Rogue default configuration
AC.Syndicate.PatchFix.asi Syndicate plugin (Windows)
AC.Syndicate.PatchFix-wine.asi Syndicate plugin (Wine/Proton cross-compiled)
AC.Syndicate.PatchFix.ini Syndicate default configuration

What's Changed

Full Changelog: v3.1.0...v3.2.0

v3.1.0

Choose a tag to compare

@github-actions github-actions released this 04 Sep 17:38
46242e9

Rogue display fixes - every refresh rate is selectable, and the settings menu no longer crashes.

What's New

Rogue display mode fixes

The game built its resolution list by keeping at most one entry per resolution, preferring whichever mode sat within 1 Hz of 60. On a high refresh rate display that dropped every native-refresh entry, so the saved mode no longer resolved to a list index. The menu then indexed its mode array with -1 and read roughly 4 GB past the end of it.

Symptoms: the resolution selector showed undefined, the game rewrote RefreshRate back to 60 on every save, and any settings interaction that refreshed the apply button (switching away from fullscreen, for one) crashed at ACC.exe+0x6D8C39.

Two new hooks, both toggleable in [Hooks]:

Hook What it does
FullModeList Replaces the list builder. Keeps every mode the monitor reports, sorted by (width, height, refresh) as the game's own binary search expects. Same output format, same DXGI_ENUM_MODES_SCALING flag, same 800x600 floor as the engine.
ModeIndexGuard Clamps the display mode index the settings menu reads, mirroring the clamp the mode setter already does, and returns zeroed output when the list is empty. Also covers a stale index left in an existing INI.
[Hooks]
; Clamps the display mode index the settings menu reads, which the game
; does not bounds check.
ModeIndexGuard=true
; Lists every display mode the monitor reports instead of one per
; resolution at 60 Hz.
FullModeList=true

Both default to true. An existing AC.Rogue.PatchFix.ini works unchanged - missing keys fall back to the defaults - but copy the shipped INI if you want the new entries documented in place.

Crash diagnostics

The exception handler previously logged only faults whose instruction pointer landed inside the plugin or a registered patch, so a crash anywhere else in the game left no record at all. It now also logs a bounded number of faults from outside plugin code, which is what located the bug above.

Assets

File Description
AC.Rogue.PatchFix.asi Rogue plugin (Windows)
AC.Rogue.PatchFix-wine.asi Rogue plugin (Wine/Proton cross-compiled)
AC.Rogue.PatchFix.ini Rogue default configuration
AC.Syndicate.PatchFix.asi Syndicate plugin (Windows)
AC.Syndicate.PatchFix-wine.asi Syndicate plugin (Wine/Proton cross-compiled)
AC.Syndicate.PatchFix.ini Syndicate default configuration

What's Changed

  • build(deps): bump actions/cache from 5 to 6 by @dependabot[bot] in #6
  • build(deps): bump actions/checkout from 6 to 7 by @dependabot[bot] in #5
  • fix(rogue): show every display mode and stop the settings menu crashing by @playday3008 in #12

Full Changelog: v3.0.0...v3.1.0

v3.0.0

Choose a tag to compare

@github-actions github-actions released this 02 Jun 21:13

Multi-game support -- AC Syndicate joins the family.

What's New

Assassin's Creed Syndicate support

Six hooks, all configurable via AC.Syndicate.PatchFix.ini:

Hook What it does
PlatformSpecsFix Stubs DxDiag COM initialization to prevent startup freeze/deadlock
DS4v2Fix Recognizes DualShock 4 v2 controllers (PID 0x09CC) for correct PlayStation prompts
PromptOverride Force Xbox or PlayStation button prompts regardless of connected controller
ResolutionFix Filters non-standard aspect ratio resolutions (e.g., 4096×2160 / 17:9) from the display mode list
FPSUnlock Configurable frame rate cap -- uncap or set a target (e.g., Target=60 for London Drift perk)
LanguageUnlock All languages available regardless of purchase region (enabled by default)

Rogue improvements

  • UI language override -- set UILanguage in the INI to force a specific language (requires game restart to take effect)
  • FrameTiming struct writes -- FPS unlock now writes directly to the game's timing struct instead of patching code, with timestamp priming to prevent first-frame hangs

Crash diagnostics

Built-in diagnostics for all games:

  • Crash reports with register dump and stack traces -- written to the game directory as .log files
  • Minidump generation (.dmp) for post-mortem analysis
  • Crash attribution -- identifies which hook was active when a crash occurred
  • Crash journal -- tracks hook installation state across the session

If you experience a crash, check the game directory for .log and .dmp files and include them in bug reports.

Build & infrastructure

  • Embedded version number (check file properties or log output)
  • Security hardening flags (CFG, DEP, ASLR, GS)
  • Unit tests via Catch2
  • Ninja Multi-Config presets (debug + release coexist)

Installation

  1. Install an ASI loader (x64) into the game directory
  2. Place the .asi and .ini for your game into <game>/plugins/:
    • Rogue: AC.Rogue.PatchFix.asi + AC.Rogue.PatchFix.ini
    • Syndicate: AC.Syndicate.PatchFix.asi + AC.Syndicate.PatchFix.ini
  3. Edit the INI to configure
  4. Launch the game

Steam Deck / Proton: Add WINEDLLOVERRIDES="version.dll=n,b" %command% to launch options. Use the -wine.asi variant if the standard build doesn't load.

Assets

File Description
AC.Rogue.PatchFix.asi Rogue plugin (Windows)
AC.Rogue.PatchFix-wine.asi Rogue plugin (Wine/Proton cross-compiled)
AC.Rogue.PatchFix.ini Rogue default configuration
AC.Syndicate.PatchFix.asi Syndicate plugin (Windows)
AC.Syndicate.PatchFix-wine.asi Syndicate plugin (Wine/Proton cross-compiled)
AC.Syndicate.PatchFix.ini Syndicate default configuration

Full Changelog: v2.1.0...v3.0.0

v2.1.0

Choose a tag to compare

@github-actions github-actions released this 26 May 22:14

What's New

FPS Unlock

Removes the game's ~63.8 FPS cap at runtime -- no patched exe needed. Replaces the Nexus mod with a configurable, hot-reloadable INI setting.

[FPS]
; 0 = uncapped (removes frame limiter entirely)
; Any positive value = cap to that FPS (e.g. 60, 120, 144)
Target=0
  • Uncapped (Target=0): bypasses the game's sleep-loop frame limiter
  • Capped (Target=N): rewrites the internal frame time constant to match the target FPS, using the game's own frame pacer
  • Hot-reload: change the INI while the game is running -- no restart needed

Full Changelog: v2.0.0...v2.1.0

v2.0.0

Choose a tag to compare

@github-actions github-actions released this 25 May 23:29

Complete rewrite -- new architecture, new features, new build system.

What's New

Language Unlock

  • All 22 languages available regardless of purchase region -- no more region-locked audio/subtitles
  • Game ID detection preserved so DLC entitlements stay valid
  • Optional UI language override (force any language independent of registry)

FOV Correction

  • Three modes: Auto, Vert+, Hor+
  • Adjustable multiplier on top of the correction

Multi-Monitor / Triple-Screen

  • Automatic detection (aspect ratio ≥ 4.0 threshold)
  • Manual override: Single, Multi/Triple

UI Scaling

  • Configurable horizontal/vertical stretch (0.0-1.0)
  • Fill pillarbox (ultrawide) or letterbox (narrow) areas

Hot-Reload & Per-Hook Toggles

  • Edit AC.Rogue.PatchFix.ini while the game is running -- changes apply immediately
  • Enable/disable individual hooks at runtime via [Hooks] section

Installation

  1. Install an ASI loader into the game directory
  2. Place AC.Rogue.PatchFix.asi and AC.Rogue.PatchFix.ini into <game>/plugins/
  3. Edit the INI to taste
  4. Launch the game

Steam Deck / Proton: Add WINEDLLOVERRIDES="version.dll=n,b" %command% to launch options.

Assets

File Description
AC.Rogue.PatchFix.asi Plugin (Windows build)
AC.Rogue.PatchFix-linux.asi Plugin (Linux cross-compiled)
AC.Rogue.PatchFix.ini Default configuration

Read description

Choose a tag to compare

@playday3008 playday3008 released this 06 May 04:39

Partially fixed target position, disable black bars when not in game

If you know hot to fix it properly, you're welcome to open a pull request