complete overhaul
This commit is contained in:
1 parent
95623e7b0d
commit
7e2d4a981e
5 files changed
+168
-71
No files matched your search
@@ -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 }}
|
||||
@@ -1,6 +1,22 @@
|
||||
# Trials-Rising-Steam-Deck-Patch
|
||||
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
|
||||
You can find instructions for how to do this [here](https://www.rockpapershotgun.com/how-to-install-proton-ge-on-the-steam-deck)
|
||||
|
||||
|
||||
+63
-71
@@ -1,79 +1,71 @@
|
||||
import os
|
||||
import shutil
|
||||
import bsdiff4
|
||||
import zlib
|
||||
import getpass
|
||||
import shutil
|
||||
from sys import exit
|
||||
|
||||
def modify_exe(input_path):
|
||||
steam_version_offset = 0x0178bac2
|
||||
#ubisoft_connect_version_offset = 0x01789EE0
|
||||
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'
|
||||
def verify_checksum(file_path, expected_checksum):
|
||||
"""
|
||||
Verify the checksum of a file against an expected checksum.
|
||||
|
||||
if not os.path.exists(input_path):
|
||||
if os.path.exists(expected_path_linux):
|
||||
input_path = expected_path_linux
|
||||
else:
|
||||
print("Error: Could not find trialsrising.exe")
|
||||
:param file_path: Path to the file to verify.
|
||||
:param expected_checksum: Expected checksum value.
|
||||
:return: True if the checksum matches, False otherwise.
|
||||
"""
|
||||
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
|
||||
|
||||
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:
|
||||
with open(input_path, 'rb') as infile:
|
||||
data = bytearray(infile.read())
|
||||
|
||||
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"
|
||||
shutil.move(new_path, expected_path)
|
||||
except Exception as e:
|
||||
print(f"Error replacing old file with new file: {e}")
|
||||
exit(1)
|
||||
else:
|
||||
print(f"These bytes: {read_bytes.hex()} did not match expected bytes: {expected_bytes.hex()}")
|
||||
return False, "Bytes did not match"
|
||||
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)
|
||||
|
||||
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.")
|
||||
@@ -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,
|
||||
)
|
||||
@@ -0,0 +1 @@
|
||||
bsdiff4
|
||||
Reference in new issue
Block a user