Skip to content

Conversation

@Chapien
Copy link
Contributor

@Chapien Chapien commented Mar 22, 2025

The reason I check if reaper is running is because it is more reliable. Pillars seems to spawn multiple processes, and I'm not sure which to track, due to how it launches. There's also a delay between when reaper launches and when the game launches. However, reaper will always close when the game closes, so it's reliable in 99.9% of cases (if a user has disabled the steam wrapper though, I'm not sure what we can do).

I'm new to Linux and bash, so let me know if this is inefficient.

Chapien added 2 commits March 22, 2025 13:14
In order to move away from the per game sleep method, I have made it so
that fix-wm-class.sh now runs as long as the reaper wrapper process is
still running. Should work in 99.9% of cases, tested with UNDERTALE and
Pillars.
@BlueManCZ
Copy link
Owner

Hello, thanks for taking the initiative on this — not bad at all for your first steps into shell scripting!

Your script works, but the main issue is that fix-wm-class.sh is now hardcoded to only handle the reaper process. That means it would break support for other games, since their pid would be empty.

To make this more generic, we should avoid using any specific process names in the script. One idea is to leverage Steam’s %command% placeholder in the game's launch options. Steam replaces this with the game’s actual executable, so we could potentially use it to spawn the game process, capture its pid, and pass it to fix-wm-class.sh as argument. Then the while loop could monitor that pid instead of relying on a hardcoded process name.

@Chapien
Copy link
Contributor Author

Chapien commented Mar 24, 2025

Hello, thanks for taking the initiative on this — not bad at all for your first steps into shell scripting!

Your script works, but the main issue is that fix-wm-class.sh is now hardcoded to only handle the reaper process. That means it would break support for other games, since their pid would be empty.

To make this more generic, we should avoid using any specific process names in the script. One idea is to leverage Steam’s %command% placeholder in the game's launch options. Steam replaces this with the game’s actual executable, so we could potentially use it to spawn the game process, capture its pid, and pass it to fix-wm-class.sh as argument. Then the while loop could monitor that pid instead of relying on a hardcoded process name.

Yeah, I figured it would be best to leverage Steam's %command% placeholder, but I wasn't sure how to actually do that. I ultimately decided to use the reaper process because unless the user has tweaked settings, the majority of games launch using the reaper process, but it's definitely very hardcoded.

Do you know of a way to get the %command% programmatically?

@Chapien
Copy link
Contributor Author

Chapien commented Apr 25, 2025

Hello, thanks for taking the initiative on this — not bad at all for your first steps into shell scripting!

Your script works, but the main issue is that fix-wm-class.sh is now hardcoded to only handle the reaper process. That means it would break support for other games, since their pid would be empty.

To make this more generic, we should avoid using any specific process names in the script. One idea is to leverage Steam’s %command% placeholder in the game's launch options. Steam replaces this with the game’s actual executable, so we could potentially use it to spawn the game process, capture its pid, and pass it to fix-wm-class.sh as argument. Then the while loop could monitor that pid instead of relying on a hardcoded process name.

I did some research into this. I recently started using a rust program called pswatch, which watches for certain applications to run and then executes scripts. When searching for Steam game processes by name, it fails to find them, regardless of if the name is right or not; however, it can find the name of reaper. I'm starting to think using the reaper might be our only chance at doing this. Thoughts?

@BlueManCZ
Copy link
Owner

Hi! Sorry for the late reply to your earlier question.

Getting the content of %command% is actually very straightforward — you don't need to do anything special, since Steam automatically replaces it before execution.

As for using process names, I’m not a big fan of that approach, just like I’m not a fan of relying on the reaper process itself. The main problem is that if you launch more than one game, it becomes difficult to tell which reaper process belongs to which game. I believe we can find a cleaner solution.

To illustrate the idea I mentioned earlier, I wrote a simple proof-of-concept script:

#!/usr/bin/env sh

LOG_FILE="/tmp/steam_watcher.log"

echo "Starting process: $@" > $LOG_FILE
"$@" &

PID=$!
echo "Process ID: $PID" >> $LOG_FILE

while kill -0 $PID 2> /dev/null; do
        echo "Process still running: $(date)" >> $LOG_FILE
        sleep 1
done

To try it out, save the following script as process_watcher.sh in your home directory and make it executable using chmod +x process_watcher.sh.

You can then test it immediately with any GUI application. For example:

./process_watcher.sh firefox

In a separate terminal, you can view the log:

cat /tmp/steam_watcher.log

You’ll see something like this, with new lines continuously added while the firefox process is running:

Starting process: firefox
Process ID: 4088
Process still running: Sat Apr 26 09:05:06 AM CEST 2025
Process still running: Sat Apr 26 09:05:07 AM CEST 2025
Process still running: Sat Apr 26 09:05:08 AM CEST 2025
...

This can also be used in a Steam game's launch options:

$HOME/process_watcher.sh %command%

Printing the log after launching the game:

cat /tmp/steam_watcher.log

will output something like this:

Starting process: /home/ivo/.local/share/Steam/ubuntu12_32/steam-launch-wrapper -- /home/ivo/.local/share/Steam/ubuntu12_32/reaper SteamLaunch AppId=312520 -- /media/ivo/m2-storage/SteamLibrary/steamapps/common/SteamLinuxRuntime_sniper/_v2-entry-point --verb=waitforexitandrun -- /home/ivo/.local/share/Steam/steamapps/common/Proton - Experimental/proton waitforexitandrun /media/ivo/m2-storage/SteamLibrary/steamapps/common/Rain World/RainWorld.exe
Process ID: 26457
Process still running: Sat Apr 26 09:12:48 CEST 2025
Process still running: Sat Apr 26 09:12:49 CEST 2025
Process still running: Sat Apr 26 09:12:50 CEST 2025
...

Do you think you'll be able to implement this into fix-wm-class.sh and test if it works? If anything is unclear or doesn't work on your end, feel free to reach out — we can go over it together.

Chapien added 2 commits April 26, 2025 10:11
…ocess is ended. It extracts the last parameter as the Window Class, so the usasge needs to be fix-wm-class.sh %command% "WM_CLASS". Additionally, it works with gamemoderun, from what little testing I did. However, gamemoderun needs to go before everything else:

gamemoderun fix-wm-class.sh %command% "WM_CLASS". Will work on the python script to fix that next.
Finds all instances of %command% in an existing launch option array, and removes them.
Strips out any excess whitespace and stores the launch options.
Instead of appending to the existing options, the options are now overridden, with any existing options (barring %command%) going before fix-wm-class.sh. This is to facilitate the usage of things like mangohod or gamemoderun.

for instance, say a game's launch options are currently gamemoderun %command%. Upon running sif.py, the new command will be gamemoderun PATH_TO_SIF/fix-wm-class.sh %command% WM_CLASS;

Tested witn UNDERTALE and Pillars of Eternity. I do not know if it will work with WM_CLASS_ALT games, as at the moment fix-wm-class treats the very last argument it receives as WM_CLASS regardless of anything else.
@Chapien
Copy link
Contributor Author

Chapien commented Apr 26, 2025

Updated both fix-wm-class.sh and sif.py. Tested with UNDERTALE and Pillars of Eternity, seems to be working. Let me know if you want anything else changed!

@Chapien
Copy link
Contributor Author

Chapien commented Apr 29, 2025

Let me know when you've had a chance to look, I'm eager to get this pull request finished

@BlueManCZ
Copy link
Owner

Hi, great work! This is looking almost ready to merge. There are just two remaining issues that need to be addressed before we can wrap this up:

  1. wm_name_alt isn't currently working, since fix-wm-class.sh doesn't make use of it. I saw you mentioned this in the commit message. Could you restore the original functionality? One possible solution might be to pass the entire %command% in double quotes, so it's treated as a single argument and that there would always be exactly three arguments in total, similar to the original code.
  2. The restore_launch_options function in sif.py also needs updating. It should restore the original launch options, but currently, it doesn't account for the new format. Could you adapt it accordingly?

@Chapien
Copy link
Contributor Author

Chapien commented Apr 30, 2025

Sure, I'll get on that as soon as I'm free

@Chapien
Copy link
Contributor Author

Chapien commented Apr 30, 2025

Update: The quote around %command% solution breaks functionality, even with double quotes, due to the command having a new line in it. I wrote a wrapper that just logs the entire %command%. Without quotes, the value of %command is:

/home/claire/.local/share/Steam/ubuntu12_32/steam-launch-wrapper -- /home/claire/.local/share/Steam/ubuntu12_32/reaper SteamLaunch AppId=391540 -- /mnt/Storage/SteamLibrary/steamapps/common/SteamLinuxRuntime_soldier/_v2-entry-point --verb=waitforexitandrun -- /mnt/Storage/SteamLibrary/steamapps/common/SteamLinuxRuntime/scout-on-soldier-entry-point-v2 -- /mnt/Storage/SteamLibrary/steamapps/common/Undertale/runner
/home/claire/.local/share/Steam/ubuntu12_32/steam-launch-wrapper
/home/claire/.local/share/Steam/ubuntu12_32/steam-launch-wrapper

With quotes (and double quotes), it becomes:

/home/claire/.local/share/Steam/ubuntu12_32/steam-launch-wrapper -- /home/claire/.local/share/Steam/ubuntu12_32/reaper SteamLaunch AppId=391540 -- '/mnt/Storage/SteamLibrary/steamapps/common/SteamLinuxRuntime_soldier'/_v2-entry-point --verb=waitforexitandrun -- '/mnt/Storage/SteamLibrary/steamapps/common/SteamLinuxRuntime'/scout-on-soldier-entry-point-v2 -- '/mnt/Storage/SteamLibrary/steamapps/common/Undertale/runner' UNDERTALE

As you can see, UNDERTALE is here (I was testing fix-wm class), but all of the post new line output is discarded entirely if passed as a string. Amusingly, this results in the command changing the icon of steam instead of Undertale. Indeed, Undertale doesn't launch at all due to the lack of the steam-launch-wrapper properly running. Advise?

I've fixed sif.py to account for the new launch options.
I don't know much about regexes, so it *might* be a bit
hacky, feel free to change it to be more optimal. However,
I am still struggling with fix-wm-class.sh. It turns out,
if you surround %command% with quotes, steam automatically
inserts 'single quotes' around some of the arguments, breaking
the %command%. Double quoting makes it even more nested.
Regardless, fix-wm-class.sh now works with Undertale...
But not with Pillars of Eternity. The game simply never launches.
I suspect the spaces in the folder's name are responsible,
so I tried launching it without removing the single quotes
it generated. That did not change anything. Interestingly,
Steam thinks POE is running without the single quote in args;
otherwise, it instantly closes. Finally, I have to launch with
$@. "$@" causes neither Undertale nor PoE to launch. Need
advice.
@Chapien
Copy link
Contributor Author

Chapien commented May 1, 2025

Disregard #50 (comment). Turned out to be irrelevant. Still having issues, however. Please read latest commit message for details.

@BlueManCZ
Copy link
Owner

You're right - I just tested it. If I use %command% alone in the game's launch parameters, it works. But if I wrap it in double quotes like "%command%", it doesn't. Let's drop the quotes for now and consider a different approach.

Could you slightly modify the behavior, so that we always pass wm_name as first argument, wm_name_alt as second, and the rest of arguments will be %command%?

#!/usr/bin/env sh

LOG_FILE="/tmp/steam_watcher.log"

WM_NAME=$1
echo "WM_NAME: $WM_NAME" > $LOG_FILE
shift
WM_NAME_ALT=$1
echo "WM_NAME_ALT: $WM_NAME_ALT" >> $LOG_FILE
shift

echo "Starting process: $@" >> $LOG_FILE
"$@" &

PID=$!
echo "Process ID: $PID" >> $LOG_FILE

while kill -0 $PID 2> /dev/null; do
        echo "Process still running: $(date)" >> $LOG_FILE
        sleep 1
done

Please note that the sif.py script will need to be updated to always pass wm_name_alt. If it's None, we should pass wm_name in its place to ensure the argument count remains consistent.

Also, please note that I'm using the shift command to discard the first argument, rather than splitting the arguments with ${@:3}. This ensures compatibility with all POSIX-compliant shells, such as dash.

@Chapien
Copy link
Contributor Author

Chapien commented May 4, 2025

Sure thing, I'll try it out.

Should work now. One potential issue, any command line arguments after %command% will be stripped away along with everything after fix-wm-class.sh  when running SIF. I can also see a scenario where, say a game runs like:
`gamemoderun %command% --some-arg`
SIF, if fix-window-class has never been run before, will likely put
`gamemoderun --some-arg fix-wm-class.sh %command%`
I think this will not work. That said, I don't have enough experience with regexes to fix this, and it's a bit beyond the scope of this change, I think. I believe we should merge this, and handle that behavior in another PR potentially? Alternatively I can try to make it work if pointed in the right direction. For now, I added a message to the users to double check their launch options (which I think they should do anyway):
`print("\n * - added fix to game launch options. Please double check to ensure your launch options are correct.")`
@Chapien
Copy link
Contributor Author

Chapien commented May 4, 2025

Done. There's one lingering issue left detailed in the commit, but I added a user warning to hopefully mitigate it for now. I think it can be fixed separate from this PR, however.

@BlueManCZ
Copy link
Owner

Thank you for the changes. Merging

@BlueManCZ BlueManCZ changed the title Made fix-wm-class.sh run as long as reaper is running. Made fix-wm-class.sh run as long as game is running. May 5, 2025
@BlueManCZ BlueManCZ merged commit e9eb1e9 into BlueManCZ:master May 5, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants