fix: Batman: Arkham City starts with full x87 precision under FEX (#792)

Arkham City (BatmanAC.exe) stopped with Unreal's "Fatal error!" about
1.5 s after start: an access violation in BatmanAC.exe right after
steam.dll loads. The game leans on x87 and needs full precision under
FEX (FEX wiki), while the default FEX preset sets
FEX_X87REDUCEDPRECISION=1. Engine fixes sit above the shared preset and
below the player's own game profile, so a fix keyed on BatmanAC.exe
beside the started exe (BatmanAC.exe or BmLauncher.exe) restores
x87 precision for this game only. Arkham Asylum, which shares
BmLauncher.exe but not BatmanAC.exe, keeps the preset.
This commit is contained in:
Tjebbe Kerstens authored and GitHub committed 2026-10-14 13:52:01 -04:00
1 parent e45d6f7192
commit 7b018e6c42
2 files changed
+27

No files matched your search

@@ -98,6 +98,14 @@ def godot_sentry(game):
return {"WINEDLLOVERRIDES": ";".join(n + "=d" for n in sentry)}, [], "Godot: Sentry crash handler off"
@fix
def arkham_city_x87(game):
"""Batman: Arkham City (BatmanAC.exe, also started through BmLauncher.exe beside it) leans on x87
and stops with Unreal's "Fatal error!" right after start when FEX reduces its precision."""
if "batmanac.exe" in game.files:
return {"FEX_X87REDUCEDPRECISION": "0"}, [], "Batman: Arkham City: FEX with full x87 precision"
def skip_red_launcher(command):
"""Cyberpunk 2077's prelauncher opens REDlauncher, a Qt WebEngine window that hands over to the
game half a minute later and then stays up beside it, well over a core busy for as long as the
+19
View File
@@ -173,6 +173,25 @@ class GameEnvironmentTest(unittest.TestCase):
(other / "Other.exe").touch()
self.assertEqual(MODULE["engine_fixes"](str(other / "Other.exe"), []), ({}, [], []))
def test_arkham_city_gets_full_x87_precision_over_the_preset(self):
with tempfile.TemporaryDirectory() as tmp:
city = Path(tmp) / "Batman Arkham City GOTY/Binaries/Win32"
city.mkdir(parents=True)
for name in ("BatmanAC.exe", "BmLauncher.exe"):
(city / name).touch()
for exe in ("BatmanAC.exe", "BmLauncher.exe"):
env, extra, notes = MODULE["engine_fixes"](str(city / exe), [])
self.assertEqual((env, extra), ({"FEX_X87REDUCEDPRECISION": "0"}, []))
config = {"version": 1, "shared": {"FEX_X87REDUCEDPRECISION": "1"}}
self.assertEqual(MODULE["apply_config"]({}, config, "200260", env)["FEX_X87REDUCEDPRECISION"], "0")
config["games"] = {"200260": {"FEX_X87REDUCEDPRECISION": "1"}}
self.assertEqual(MODULE["apply_config"]({}, config, "200260", env)["FEX_X87REDUCEDPRECISION"], "1")
asylum = Path(tmp) / "Batman Arkham Asylum GOTY/Binaries"
asylum.mkdir(parents=True)
for name in ("ShippingPC-BmGame.exe", "BmLauncher.exe"):
(asylum / name).touch()
self.assertEqual(MODULE["engine_fixes"](str(asylum / "BmLauncher.exe"), []), ({}, [], []))
def test_a_new_fix_only_needs_registering(self):
with tempfile.TemporaryDirectory() as tmp:
(Path(tmp) / "Game.exe").touch()