complete overhaul

This commit is contained in:
Kyle Mohr committed 2025-07-10 16:59:42 -05:00
1 parent 95623e7b0d
commit 7e2d4a981e
5 files changed
+169 -72

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
name: Package Application with Pyinstaller and Create Release
on:
push:
tags:
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Package Application
uses: JackMcKew/pyinstaller-action-linux@main
with:
path: .
spec: patcher.spec
- name: Prepare artifact
run: mv dist/patcher dist/trials_patcher
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: trials_patcher
path: dist/trials_patcher
release:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download artifact
uses: actions/download-artifact@v4
with:
name: trials_patcher
- name: Make executable
run: chmod +x trials_patcher
- name: Create and publish release
uses: ncipollo/release-action@v1
with:
artifacts: "trials_patcher"
token: ${{ secrets.GITHUB_TOKEN }}
+16
View File
@@ -1,6 +1,22 @@
# Trials-Rising-Steam-Deck-Patch # Trials-Rising-Steam-Deck-Patch
Disabling Easy Anti-Cheat in trialsrising.exe so that the game works on Linux + Steam Deck Disabling Easy Anti-Cheat in trialsrising.exe so that the game works on Linux + Steam Deck
**Updated 2025-07-10**: This patcher now works differently.
### Easy method:
Download the latest release from the releases tab, and run it on your Steam Deck. It will patch the game for you. If you've previously patched the game, go to the game's properties in Steam > Installed Files > Verify Integrity of Game Files to restore the original file, then run this patcher.
### Run from source:
via the command line on your Steam Deck/Linux machine:
```git clone https://github.com/kylemohr/Trials-Rising-Steam-Deck-Patch.git
cd Trials-Rising-Steam-Deck-Patch
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python patcher.py
```
if this fails at the `pip install` step, you may need to install `python3-pip` via `pacman`. This will likely require you to run `sudo steamos-devmode enable` first, then `sudo pacman -Syu python3-pip`. **You don't need to do this if you're using the easy method above.**
### I highly recommend using GE-Proton-9-1 for this game ### I highly recommend using GE-Proton-9-1 for this game
You can find instructions for how to do this [here](https://www.rockpapershotgun.com/how-to-install-proton-ge-on-the-steam-deck) You can find instructions for how to do this [here](https://www.rockpapershotgun.com/how-to-install-proton-ge-on-the-steam-deck)
+64 -72
View File
@@ -1,79 +1,71 @@
import os import bsdiff4
import shutil import zlib
import getpass import getpass
import shutil
from sys import exit
def modify_exe(input_path): def verify_checksum(file_path, expected_checksum):
steam_version_offset = 0x0178bac2 """
#ubisoft_connect_version_offset = 0x01789EE0 Verify the checksum of a file against an expected checksum.
expected_bytes = bytes.fromhex("40 0f b6 c7 0f 28 74 24 50 48 83 c4 68 5f 5b c3")
replacement_bytes = bytes.fromhex("31 C0 B0 01 0f 28 74 24 50 48 83 c4 68 5f 5b c3")
expected_path_linux = '/home/' + getpass.getuser() + '/.local/share/Steam/steamapps/common/Trials Rising/datapack/trialsrising.exe'
if not os.path.exists(input_path): :param file_path: Path to the file to verify.
if os.path.exists(expected_path_linux): :param expected_checksum: Expected checksum value.
input_path = expected_path_linux :return: True if the checksum matches, False otherwise.
else: """
print("Error: Could not find trialsrising.exe") try:
actual_checksum = zlib.crc32(open(file_path, 'rb').read())
print(f"Expected checksum: {expected_checksum}, Actual checksum: {actual_checksum}")
return actual_checksum == expected_checksum
except Exception as e:
print(f"Error verifying checksum: {e}")
return False return False
def apply_patch(old_file_path, new_file_path, patch_bytes):
"""
Apply a binary patch to an old file to create a new file.
:param old_file_path: Path to the old file.
:param new_file_path: Path where the new file will be saved.
:param patch_bytes: The binary patch data.
"""
try:
with open(old_file_path, 'rb') as old_file:
old_data = old_file.read()
new_data = bsdiff4.patch(old_data, patch_bytes)
with open(new_file_path, 'wb') as new_file:
new_file.write(new_data)
print(f"Patch applied successfully. New file created at {new_file_path}")
except Exception as e:
print(f"Error applying patch: {e}")
patch_bytes = b"\x42\x53\x44\x49\x46\x46\x34\x30\x3E\x00\x00\x00\x00\x00\x00\x00\x2E\x01\x00\x00\x00\x00\x00\x00\xA8\x0C\x6E\x14\x00\x00\x00\x00\x42\x5A\x68\x39\x31\x41\x59\x26\x53\x59\xED\xED\xC0\x27\x00\x00\x07\x63\x51\xC0\x44\x14\x00\x20\x00\x00\x01\x40\x00\x00\x40\x10\x00\x02\x00\x20\x00\x31\x00\xD3\x4D\x04\x34\x06\x9A\x50\xA0\xEC\x51\x46\xD7\x2F\x17\x72\x45\x38\x50\x90\xED\xED\xC0\x27\x42\x5A\x68\x39\x31\x41\x59\x26\x53\x59\xD5\x2F\x49\xC5\x00\xBD\x1A\xC9\x89\xC0\x20\x00\x10\x00\x40\x80\x40\x20\x00\x10\x00\x20\x18\x20\x00\x50\x80\x69\xA6\x81\x35\x54\x1A\x1B\x53\x28\xD7\x08\x08\x12\xEF\xA9\x49\x20\xAA\xB3\x7F\x7D\x9A\xDE\x72\xA2\xA0\x25\xF9\x8A\x0A\xC9\x32\x9A\xC8\x70\x4F\x16\xF8\x0A\xFC\x72\x00\x06\x00\x00\x00\x41\x00\x01\x84\x02\x6A\x32\x15\x01\x2D\x48\x54\x04\xB9\x8A\x0A\xC9\x32\x9A\xC8\x70\x4F\x16\xF8\x0A\xFC\x72\x00\x06\x00\x00\x00\x41\x00\x01\x84\x02\x6A\x32\x15\x01\x2D\x48\x54\x04\xB9\x8A\x0A\xC9\x32\x9A\xC8\x70\x4F\x16\xF8\x0A\xFC\x72\x00\x06\x00\x00\x00\x41\x00\x01\x84\x02\x6A\x32\x15\x01\x2D\x48\x54\x04\xB9\x8A\x0A\xC9\x32\x9A\xC8\x70\x4F\x16\xF8\x0A\xFC\x72\x00\x06\x00\x00\x00\x41\x00\x01\x84\x02\x6A\x32\x15\x01\x2D\x48\x54\x04\xB9\x8A\x0A\xC9\x32\x9A\xC8\x70\x4F\x16\xF8\x0A\xFC\x72\x00\x06\x00\x00\x00\x41\x00\x01\x84\x02\x6A\x32\x15\x01\x2D\x48\x54\x04\xB9\x8A\x0A\xC9\x32\x9A\xC8\x70\x4F\x16\xF8\x0A\xFC\x72\x00\x06\x00\x00\x00\x41\x00\x01\x84\x02\x6A\x32\x15\x01\x2D\x48\x54\x04\xB9\x8A\x0A\xC9\x32\x9A\xCB\xF2\xD1\x6B\xA0\x05\x23\x1E\x40\x06\x00\x00\x02\x00\x00\x41\x00\x01\x86\x60\x29\x4D\x35\x42\x84\x4D\x81\x14\x22\x78\xBB\x92\x29\xC2\x84\x80\xF2\xFA\xB3\xB0\x42\x5A\x68\x39\x17\x72\x45\x38\x50\x90\x00\x00\x00\x00"
expected_path = '/home/' + getpass.getuser() + '/.local/share/Steam/steamapps/common/Trials Rising/datapack/trialsrising.exe'
new_path = expected_path + '.new'
expected_checksum_before = 0xF197E04E
expected_checksum_after = 0x883925BD
if verify_checksum(expected_path, expected_checksum_before):
apply_patch(expected_path, new_path, patch_bytes)
if verify_checksum(new_path, expected_checksum_after):
print("Patch applied successfully.")
else:
print("Patch failed: checksum mismatch after patching. Please open an issue on GitHub.")
exit(1)
try: try:
with open(input_path, 'rb') as infile: shutil.move(new_path, expected_path)
data = bytearray(infile.read()) except Exception as e:
print(f"Error replacing old file with new file: {e}")
exit(1)
else:
if(verify_checksum(expected_path, expected_checksum_after)):
print("Patch has already been applied, no changes made.")
exit(0)
print("Patch failed: checksum mismatch before patching. Go to the game's properties in Steam > Installed Files > Verify integrity of game files, then try again")
print("If that doesn't work, please open an issue on GitHub.")
exit(1)
def check_and_patch(offset):
if offset + len(expected_bytes) > len(data):
return False, "Offset exceeds file size"
read_bytes = bytes(data[offset: offset + len(expected_bytes)])
# Search for the expected bytes throughout the entire file, not just at the offset
# for i in range(len(data) - len(expected_bytes)):
# read_bytes = bytes(data[i: i + len(expected_bytes)])
# if read_bytes == expected_bytes:
# print(f"Found expected bytes at offset: {hex(i)}")
# offset = i
# continue
# exit()
if read_bytes == expected_bytes:
print(f"Bytes matched at offset: {hex(offset)}. Modifying...")
for i, byte in enumerate(replacement_bytes):
data[offset + i] = byte
return True, None
elif read_bytes == replacement_bytes:
print(f"Bytes already modified at offset: {hex(offset)}, no changes made.")
return False, "Program already patched"
else:
print(f"These bytes: {read_bytes.hex()} did not match expected bytes: {expected_bytes.hex()}")
return False, "Bytes did not match"
modified, message = check_and_patch(steam_version_offset)
if not modified:
print(f"Error: {message}")
return False
if modified:
# backup original file
backup_path = os.path.splitext(input_path)[0] + "_original.exe"
shutil.copy(input_path, backup_path)
print(f"Backed up original file to: {backup_path}")
# write patched exe
with open(input_path, 'wb') as outfile:
outfile.write(data)
print(f"Successfully patched file: {input_path}")
return True
return False
except FileNotFoundError:
print(f"Error: Input file not found: {input_path}")
return False
except IOError as e:
print(f"Error: IO error occurred: {e}")
return False
if __name__ == '__main__':
input_file = input("Enter the path of the trialsrising.exe file, or press Enter to use the default path: ")
if modify_exe(input_file):
print("Process completed.")
else:
print("Process failed.")
+38
View File
@@ -0,0 +1,38 @@
# -*- mode: python ; coding: utf-8 -*-
a = Analysis(
['patcher.py'],
pathex=[],
binaries=[],
datas=[],
hiddenimports=[],
hookspath=[],
hooksconfig={},
runtime_hooks=[],
excludes=[],
noarchive=False,
optimize=0,
)
pyz = PYZ(a.pure)
exe = EXE(
pyz,
a.scripts,
a.binaries,
a.datas,
[],
name='patcher',
debug=False,
bootloader_ignore_signals=False,
strip=False,
upx=True,
upx_exclude=[],
runtime_tmpdir=None,
console=True,
disable_windowed_traceback=False,
argv_emulation=False,
target_arch=None,
codesign_identity=None,
entitlements_file=None,
)
+1
View File
@@ -0,0 +1 @@
bsdiff4