Skip to content

Instantly share code, notes, and snippets.

@CrackerJackMack
Last active October 28, 2024 15:57
Show Gist options
  • Save CrackerJackMack/374f49b4ad98e14c0a7e8bbcac668d63 to your computer and use it in GitHub Desktop.
Save CrackerJackMack/374f49b4ad98e14c0a7e8bbcac668d63 to your computer and use it in GitHub Desktop.
Linux steam proton multiplayer desync script

I wanted to play Sins of the solar Empire 2 with my friends. Proton and Lutris works great for SP, but MP was broke.

First blocker was forcing the CPU architecture: (you can also edit this via ctrl+shift+s while in game)

The second was that there were desync issues, which the community found and fixed for other games. These desync issues seem to be fairly common with multiplayer games using proton. So you can always try this and copy the backup files back (.bak) if it didn't work. This version adds sha256 checksums of the .exe files. If you run into issues with "command not found", try dos2unix steam_patch_mp_desync.sh then retry.

The below script is a more agnostic version of the original script to be more generic and work with most games by passing the APP ID

chmod +x steam_patch_mp_desync.sh
./steam_patch_mp_desync.sh 111011

To get a list of installed apps run it without a app id

./steam_patch_mp_desync.sh

Provide a steam ID from below
1493710		Proton Experimental
1575940		Sins of a Solar Empire II
1628350		Steam Linux Runtime 3.0 (sniper)
1782120		ZERO Sievert
1794680		Vampire Survivors
228980		Steamworks Common Redistributables
250900		The Binding of Isaac: Rebirth
2805730		Proton 9.0
2828860		The Forever Winter
427520		Factorio
469600		Legion TD 2


example for 'Legion TD 2' would be ./steam_patch_mp_desync.sh

For deck users just override the STEAM_USER variable while running it if it doesn't default to the right user.

STEAM_USER=deck ./steam_patch_mp_desync.sh 11011

If you have additional drives setup in steam you'll need to set the full path to steamapps directory

STEAM_DIR="/mnt/games/steam/steamapps" ./steam_patch_mp_desync.sh 11011
#!/bin/bash
set -e
APP_ID=${1}
STEAM_USER=$USER
STEAM_DIR="/home/${STEAM_USER}/.steam/steam/steamapps"
APP_DIR="${STEAM_DIR}/compatdata/${APP_ID}"
WIN_DIR="${APP_DIR}/pfx/drive_c/windows"
WIN_SYS32_DIR="${WIN_DIR}/system32"
WIN_SYS64_DIR="${WIN_DIR}/syswow64"
VC_REDIST_x64_CKSUM=5eea714e1f22f1875c1cb7b1738b0c0b1f02aec5ecb95f0fdb1c5171c6cd93a3
VC_REDIST_x86_CKSUM=fdd1e1f0dcae2d0aa0720895eff33b927d13076e64464bb7c7e5843b7667cd14
function list_apps() {
echo "Provide a steam ID from below"
for d in ${STEAM_DIR}/appmanifest*.acf; do
id=$(sed -rn 's/\s+"appid"\s+"(.+)\"/\1/p' < $d)
name=$(sed -rn 's/\s+"name"\s+"(.+)\"/\1/p' < $d)
echo -e "$id\t\t$name"
done
echo
echo
echo example for \'$name\' would be $0 $appid
echo
}
function check_deps() {
which sha256sum > /dev/null || (echo "sha256sum is required (on Ubuntu you can install it with 'sudo apt-get install coreutils')" && exit 1)
which curl > /dev/null || (echo "curl is required (on Ubuntu you can install it with 'sudo apt-get install curl')" && exit 1)
which cabextract > /dev/null || (echo "cabextract is required (on Ubuntu you can install it with 'sudo apt-get install cabextract')" && exit 1)
test -d ${APP_DIR} || ( echo "$APP_DIR does not exist; application is not supported or installed" && exit 1)
test -d ${WIN_DIR} || ( echo "$WIN_DIR does not exist; application is not supported or installed" && exit 1)
}
function cleanup() {
local arch=$1
rm -f vc_redist.$arch.exe
rm -rf 0 a{0..11} u{0..31}
}
function backup() {
files="ucrtbase.dll concrt140.dll msvcp140.dll vcamp140.dll vccorlib140.dll vcomp140.dll vcruntime140.dll"
for f in $files; do
test -f $f || continue
echo "Backing up $f => ${f}.bak"
cp -n $f ${f}.bak 2> /dev/null || true
done
}
function download_and_replace() {
local arch=$1
echo "Downloading vc_redist.$arch.exe"
curl -s -O https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.$arch.exe
echo "Validating archive"
csum="VC_REDIST_${arch}_CKSUM"
rm -f tmp.sha256
echo "${!csum} vc_redist.$arch.exe" > tmp.sha256
sha256sum -c tmp.sha256 || rm -f tmp.sha256
echo "Extracting archive"
cabextract -q vc_redist.$arch.exe 2>/dev/null
cabextract -q a10 2>/dev/null
echo "Extraction done"
}
function replace_dlls() {
local dir=$1
local arch=$2
echo "Patching $dir with arch $2"
pushd "${dir}" > /dev/null
backup
cleanup $arch
download_and_replace $arch
cleanup $arch
popd > /dev/null
echo "Patching complete!"
}
if [ -z "${APP_ID}" ]; then
list_apps
exit 1
fi
check_deps
replace_dlls "${WIN_SYS32_DIR}" x64
replace_dlls "${WIN_SYS64_DIR}" x86
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment