Compare commits

..

17 commits

Author SHA1 Message Date
gurrgur
98aa86767c
Add Linux HDR example 2024-07-18 15:04:36 +02:00
gurrgur
3ca1d96c9b
Merge pull request #78 from metinc/main
Avoid deleting eldenring.exe while it is running
2024-07-18 14:37:50 +02:00
Metin Çelik
adf3fe57aa Retry deleting eldenring.exe if it is still running 2024-07-14 11:56:59 +02:00
Metin Çelik
e9f39e6ae3 Avoid deleting eldenring.exe while it is locked 2024-07-08 00:46:14 +02:00
Metin Çelik
ebc316f9e3 Use new executable name for Seamless Co-op example 2024-07-07 16:56:18 +02:00
gurrgur
808bf71966
Merge pull request #71 from polsrepo/patch-3
Fix for crash on death with --disable-rune-loss + potential fix for 60Hz fullscreen lock
2024-06-21 16:34:00 +02:00
polsrepo
9c22a9cd1b
Potential fix for crash on death with --disable-rune-loss and 60Hz lock on full screen
Updated the hex pattern in patch.disable_rune_loss to potentially fix the crash on death. Updated the patch.remove_60hz_fullscreen function and hex pattern to potentially fix the 60hz lock in full screen
2024-06-21 12:13:11 +02:00
gurrgur
f2c55ad352
Merge pull request #67 from polsrepo/patch-2
Update README.md for Windows users
2024-06-20 20:08:39 +02:00
polsrepo
05a5425654
Update README.md for Windows users
Added Note 2
2024-06-20 14:01:48 +02:00
gurrgur
2fb795c305
Merge pull request #65 from polsrepo/patch-1
Update er-patcher for v1.12
2024-06-20 13:48:57 +02:00
polsrepo
a388b09bee
Update er-patcher for v1.12
Updated hex pattern for patch.rate, fixed the offset value for patch.remove_60hz_fullscreen
2024-06-20 13:25:04 +02:00
gurrgur
e8be93b2e2
Merge pull request #59 from gurrgur/python-3-9-regression-fix
fix regression on python 3.9
2024-01-12 02:44:23 +01:00
Marcus Gursch
98cf4aeaa8 use old link_to api when running on python 3.9 or older 2024-01-12 02:40:36 +01:00
gurrgur
a82a9d6e01
Merge pull request #56 from gurrgur/python-3-12-compat
Adapt to python 3.12 changes
2023-12-23 14:32:43 +01:00
Marcus Gursch
569917cb4b adapt to python 3.12 changes
Co-authored-by: mtnorthcott <matthew@northcott.nz>
2023-11-20 11:37:46 +01:00
gurrgur
1a3e191ee9
Merge pull request #47 from arminveres/fix/spelling
Fixed vignette spelling
2022-12-27 14:47:44 +01:00
Armin Veres
7faf4c4f25 Fixed vignette spelling 2022-12-27 12:30:36 +01:00
2 changed files with 58 additions and 16 deletions

View file

@ -15,9 +15,22 @@ A tool aimed at enhancing the experience when playing the game on linux through
1. Copy the file `er-patcher` to the game directory. 1. Copy the file `er-patcher` to the game directory.
2. In steam, set the game launch options to `python er-patcher ARGS -- %command%` See [Features](#features) for available options. 2. In steam, set the game launch options to `python er-patcher ARGS -- %command%` See [Features](#features) for available options.
- Example: `python er-patcher --all --rate 30 --disable-rune-loss -- %command%` - Example:
- Example using the [seamless co-op](https://www.nexusmods.com/eldenring/mods/510) mod: `python er-patcher --all --executable launch_elden_ring_seamlesscoop.exe -- %command%`
- Example using [MangoHud](https://github.com/flightlessmango/MangoHud) and wine fullscreen FSR: `python er-patcher --rate 144 -uvca -- env WINE_FULLSCREEN_FSR=1 MANGOHUD=1 MANGOHUD_CONFIG=histogram %command%` `python er-patcher --all --rate 30 --disable-rune-loss -- %command%`
- Example using the [Seamless Co-op](https://www.nexusmods.com/eldenring/mods/510) mod:
`python er-patcher --all --executable ersc_launcher.exe -- %command%`
- Example using [MangoHud](https://github.com/flightlessmango/MangoHud) and wine fullscreen FSR:
`python er-patcher --rate 144 -uvca -- env WINE_FULLSCREEN_FSR=1 MANGOHUD=1 MANGOHUD_CONFIG=histogram %command%`
- Example for enabling HDR using gamescope on Linux (reported to work on Plasma 6.1):
`ENABLE_GAMESCOPE_WSI=1 DXVK_HDR=1 gamescope -W 3440 -H 1440 -f -r 165 --hdr-enabled -- python er-patcher --all --rate 165 -- %command%`
3. Launch the game through steam. `er-patcher` automatically launches a patched version of `eldenring.exe` with EAC disabled. 3. Launch the game through steam. `er-patcher` automatically launches a patched version of `eldenring.exe` with EAC disabled.
Note: There might be some distros (e.g. older Ubuntu releases) that launch python 2 instead of 3 when running `python`. In that case you'll need to replace `python` with `python3` in the launch option line. Note: There might be some distros (e.g. older Ubuntu releases) that launch python 2 instead of 3 when running `python`. In that case you'll need to replace `python` with `python3` in the launch option line.
@ -32,7 +45,7 @@ Note: There might be some distros (e.g. older Ubuntu releases) that launch pytho
| `--disable-rune-loss` | Disable losing runes upon death. | | `--disable-rune-loss` | Disable losing runes upon death. |
| `--all` | Enable all options except `--rate`, `--executable`, and<br>gameplay changes like `--disable-rune-loss`. | | `--all` | Enable all options except `--rate`, `--executable`, and<br>gameplay changes like `--disable-rune-loss`. |
| `-u` or `--ultrawide` | Remove black bars. | | `-u` or `--ultrawide` | Remove black bars. |
| `-v` or `--disable-vigniette` | Remove the vigniette overlay. | | `-v` or `--disable-vignette` | Remove the vignette overlay. |
| `-c` or `--disable-ca` | Disable chromatic abberation. | | `-c` or `--disable-ca` | Disable chromatic abberation. |
| `-a` or `--increase-animation-distance` | Fix low frame rate animations at screen<br>edges or for distant entities. | | `-a` or `--increase-animation-distance` | Fix low frame rate animations at screen<br>edges or for distant entities. |
| `-s` or `--skip-intro` | Skip intro logos at game start. | | `-s` or `--skip-intro` | Skip intro logos at game start. |
@ -47,6 +60,8 @@ The patcher works just as well on windows. The following launch option line work
Note: This spawns a python console which will close by itself after the game has finished running. If you find this annoying you can try using `pythonw` instead. In any case `python` needs to be in PATH for windows to find it. Note: This spawns a python console which will close by itself after the game has finished running. If you find this annoying you can try using `pythonw` instead. In any case `python` needs to be in PATH for windows to find it.
Note 2: Ensure Vertical Sync is turned off for Elden Ring in Nvidia Control Panel / AMD Radeon Software / Intel Graphics Command Center, otherwise the custom framerate limit feature won't work.
## How it works ## How it works
When the game is launched through steam, the tool creates a patched version of `eldenring.exe` in a temporary subdirectory while leaving the original intact. As long the flag `--with-eac` is not set, the tool modifies the steam launch command to launch the patched executable instead of `start_protected_game.exe`, thefore ensuring that the patched exe is never run with EAC enabled. After the game is closed, the patched executable is removed. When the game is launched through steam, the tool creates a patched version of `eldenring.exe` in a temporary subdirectory while leaving the original intact. As long the flag `--with-eac` is not set, the tool modifies the steam launch command to launch the patched executable instead of `start_protected_game.exe`, thefore ensuring that the patched exe is never run with EAC enabled. After the game is closed, the patched executable is removed.
@ -57,7 +72,7 @@ When the game is launched through steam, the tool creates a patched version of `
- frame time limit adjustment - frame time limit adjustment
- black bar removal - black bar removal
- [Flawless Widescreen](https://www.flawlesswidescreen.org) - [Flawless Widescreen](https://www.flawlesswidescreen.org)
- vigniette and ca removal - vignette and ca removal
- animation distance increase - animation distance increase
- [DarkSouls3RemoveIntroScreens](https://github.com/bladecoding/DarkSouls3RemoveIntroScreens): intro logo skip - [DarkSouls3RemoveIntroScreens](https://github.com/bladecoding/DarkSouls3RemoveIntroScreens): intro logo skip
- [EldenRingMods](https://github.com/techiew/EldenRingMods) + [EldenRingFpsUnlockAndMore](https://github.com/uberhalit/EldenRingFpsUnlockAndMore) - [EldenRingMods](https://github.com/techiew/EldenRingMods) + [EldenRingFpsUnlockAndMore](https://github.com/uberhalit/EldenRingFpsUnlockAndMore)

View file

@ -7,7 +7,23 @@ from pathlib import Path
import struct import struct
import re import re
from shutil import rmtree from shutil import rmtree
import os
import time
def cleanup(game_dir_patched):
if game_dir_patched.exists():
eldenring_path = game_dir_patched / "eldenring.exe"
while eldenring_path.exists():
try:
os.remove(eldenring_path)
break
except PermissionError:
# eldenring.exe is still running, retry in 3 s
time.sleep(3)
except Exception as e:
print(f"er-patcher: could not delete {eldenring_path}: {e}")
break
rmtree(game_dir_patched)
if __name__ == "__main__": if __name__ == "__main__":
@ -21,7 +37,7 @@ if __name__ == "__main__":
parser.add_argument("--disable-rune-loss", action='store_true', help="Disable losing runes upon death.") parser.add_argument("--disable-rune-loss", action='store_true', help="Disable losing runes upon death.")
parser.add_argument("--all", action='store_true', help="Enable all options except rate adjustment and gamplay changes like `--disable-rune-loss`.") parser.add_argument("--all", action='store_true', help="Enable all options except rate adjustment and gamplay changes like `--disable-rune-loss`.")
parser.add_argument("-u", "--ultrawide", action='store_true', help="Removes black bars when using a resolution with an aspect ratio other than 16:9.") parser.add_argument("-u", "--ultrawide", action='store_true', help="Removes black bars when using a resolution with an aspect ratio other than 16:9.")
parser.add_argument("-v", "--disable-vigniette", action='store_true', help="Disables the vigniette overlay.") parser.add_argument("-v", "--disable-vignette", action='store_true', help="Disables the vignette overlay.")
parser.add_argument("-c", "--disable-ca", action='store_true', help="Disables chromatic abberation.") parser.add_argument("-c", "--disable-ca", action='store_true', help="Disables chromatic abberation.")
parser.add_argument("-a", "--increase-animation-distance", action='store_true', help="Increase animation distance.") parser.add_argument("-a", "--increase-animation-distance", action='store_true', help="Increase animation distance.")
parser.add_argument("-s", "--skip-intro", action='store_true', help="Skip intro logos.") parser.add_argument("-s", "--skip-intro", action='store_true', help="Skip intro logos.")
@ -37,7 +53,7 @@ if __name__ == "__main__":
exe_hex = f.read().hex() exe_hex = f.read().hex()
if patch.rate != 60 and patch.rate > 0: if patch.rate != 60 and patch.rate > 0:
r_pattern = "c7 43 20 89 88 88 3c eb 43 89 73 18 eb ca 89 73 18".replace(" ", "") r_pattern = "c7 43 1c 89 88 88 3c eb 6d 89 73 18 eb c7 89 73 18".replace(" ", "")
if (res := re.search(r_pattern, exe_hex)) is not None: if (res := re.search(r_pattern, exe_hex)) is not None:
r_addr = res.span()[0] + 6 r_addr = res.span()[0] + 6
r_patch = struct.pack('<f', 1 / patch.rate).hex() r_patch = struct.pack('<f', 1 / patch.rate).hex()
@ -46,9 +62,9 @@ if __name__ == "__main__":
print("er-patcher: rate pattern scan failed") print("er-patcher: rate pattern scan failed")
if patch.disable_rune_loss: if patch.disable_rune_loss:
rl_pattern = "b0 01 .. 8b .. e8 .. .. .. .. .. 8b .. .. .. 32 c0 .. 83 .. 28 c3".replace(" ", "") rl_pattern = "41 .. 01 48 .. .. e8 .. .. .. .. 48 .. .. .. .. 32 c0".replace(" ", "")
if (res := re.search(rl_pattern, exe_hex)) is not None: if (res := re.search(rl_pattern, exe_hex)) is not None:
rl_addr = res.span()[0] + 6 rl_addr = res.span()[0] + 12
rl_patch = "90 90 90 90 90".replace(" ", "") # NOP rl_patch = "90 90 90 90 90".replace(" ", "") # NOP
exe_hex = exe_hex[:rl_addr] + rl_patch + exe_hex[rl_addr + len(rl_patch):] exe_hex = exe_hex[:rl_addr] + rl_patch + exe_hex[rl_addr + len(rl_patch):]
else: else:
@ -63,14 +79,14 @@ if __name__ == "__main__":
else: else:
print("er-patcher: ultrawide pattern scan failed") print("er-patcher: ultrawide pattern scan failed")
if patch.disable_vigniette or patch.all: if patch.disable_vignette or patch.all:
v_pattern = 'f3 0f 10 .. .. f3 0f 59 .. .. .. .. .. e8 .. .. .. .. f3 41 0f .. .. f3 45 0f .. .. 4c 8d .. .. .. .. .. .. 48'.replace(" ", "") v_pattern = 'f3 0f 10 .. .. f3 0f 59 .. .. .. .. .. e8 .. .. .. .. f3 41 0f .. .. f3 45 0f .. .. 4c 8d .. .. .. .. .. .. 48'.replace(" ", "")
if (res := re.search(v_pattern, exe_hex)) is not None: if (res := re.search(v_pattern, exe_hex)) is not None:
v_addr = res.span()[0] + 46 v_addr = res.span()[0] + 46
v_patch = "f3 0f 5c c0 90".replace(" ", "") # SUBSS XMM0,XMM0; NOP; all NOP does work too v_patch = "f3 0f 5c c0 90".replace(" ", "") # SUBSS XMM0,XMM0; NOP; all NOP does work too
exe_hex = exe_hex[:v_addr] + v_patch + exe_hex[v_addr + len(v_patch):] exe_hex = exe_hex[:v_addr] + v_patch + exe_hex[v_addr + len(v_patch):]
else: else:
print("er-patcher: disable_vigniette pattern scan failed") print("er-patcher: disable_vignette pattern scan failed")
if patch.disable_ca or patch.all: if patch.disable_ca or patch.all:
ca_pattern = "0f 11 43 60 48 8d 8b 80 00 00 00 0f 10 87 a0 00 00 00 0f 11 41 f0 48 8d 87 b0 00 00 00 0f 10 08 0f 11 09".replace(" ", "") ca_pattern = "0f 11 43 60 48 8d 8b 80 00 00 00 0f 10 87 a0 00 00 00 0f 11 41 f0 48 8d 87 b0 00 00 00 0f 10 08 0f 11 09".replace(" ", "")
@ -102,15 +118,23 @@ if __name__ == "__main__":
print("er-patcher: skip_intro pattern scan failed") print("er-patcher: skip_intro pattern scan failed")
if patch.remove_60hz_fullscreen or patch.all: if patch.remove_60hz_fullscreen or patch.all:
fs_pattern = "c7 45 ef 3c 00 00 00".replace(" ", "") fs_pattern = "eb .. c7 .. .. 3c 00 00 00 c7 .. .. 01 00 00 00".replace(" ", "")
if (res := re.search(fs_pattern, exe_hex)) is not None: if (res := re.search(fs_pattern, exe_hex)) is not None:
fs_addr = res.span()[0] + 6 fs_addr = res.span()[0] + 10
fs_patch = "00" fs_patch = "00"
exe_hex = exe_hex[:fs_addr] + fs_patch + exe_hex[fs_addr + len(fs_patch):] exe_hex = exe_hex[:fs_addr] + fs_patch + exe_hex[fs_addr + len(fs_patch):]
fs_addr_2 = res.span()[0] + 24
fs_patch_2 = "00"
exe_hex = exe_hex[:fs_addr_2] + fs_patch_2 + exe_hex[fs_addr_2 + len(fs_patch_2):]
else: else:
print("er-patcher: remove_60hz_fullscreen pattern scan failed") print("er-patcher: remove_60hz_fullscreen pattern scan failed")
game_dir_patched = Path("er-patcher-tmp") game_dir_patched = Path("er-patcher-tmp")
# make sure a fresh directory is used
cleanup(game_dir_patched)
if not game_dir_patched.is_dir(): if not game_dir_patched.is_dir():
game_dir_patched.mkdir() game_dir_patched.mkdir()
@ -134,6 +158,9 @@ if __name__ == "__main__":
if f.name in ["eldenring.exe", "er-patcher"]: if f.name in ["eldenring.exe", "er-patcher"]:
continue continue
if not (game_dir_patched / f).is_file(): if not (game_dir_patched / f).is_file():
if sys.version_info.minor >= 10:
(game_dir_patched / f).hardlink_to(f)
else:
f.link_to(game_dir_patched / f) f.link_to(game_dir_patched / f)
# start patched exe directly to avoid EAC # start patched exe directly to avoid EAC
@ -141,5 +168,5 @@ if __name__ == "__main__":
steam_cmd[-1] = Path(steam_cmd[-1]).parent.absolute() / game_dir_patched / ("start_protected_game.exe" if patch.with_eac else patch.executable) steam_cmd[-1] = Path(steam_cmd[-1]).parent.absolute() / game_dir_patched / ("start_protected_game.exe" if patch.with_eac else patch.executable)
subprocess.run(steam_cmd, cwd=steam_cmd[-1].parent.absolute()) subprocess.run(steam_cmd, cwd=steam_cmd[-1].parent.absolute())
# cleanup # try to remove game_dir_patched
rmtree(game_dir_patched) cleanup(game_dir_patched)