feat: Introduce scopebuddy (#2336)

* feat: Introduce gamescope-overlay-injector

This is a modified version of @coolavery's script from https://github.com/ValveSoftware/gamescope/issues/835#issuecomment-2496383830
It introduces the `scb` command which is a symlink to `scopebuddy` that will do the whole unset `LD_PRELOAD` for gamescope and re-apply it for `%command%` song and dance.

`scb` can replace `gamescope` in the launch options for games in steam
ex: `gamescope -w 1920 -h 1080 -W 2560 -H 1440 -r 180 --hdr-enabled -- %command% --nointro --etc` --> `scb -w 1920 -h 1080 -W 2560 -H 1440 -r 180 --hdr-enabled -- %command% --nointro --etc`

Furthermore if the user has a config file `~/.config/scopebuddy/scb.conf` it will be sourced before starting gamescope.
If the above file exists and a config with the games AppID exists in `~/.config/scopebuddy/AppID/` then that file will be loaded instead of the `scb.conf` unless a custom one is set through the SCB_CONF env var.

The file can set a `SCB_DEFAULT_ARGS` variable to provide `scb` with default gamescope arguments as long as the user gives `scb` no arguments before the `--` in the launch options, providing __any__ args to `scb` will make it ignore `SCB_DEFAULT_ARGS` completely and use whatever the user provides in the launch options.

This lets the user apply a default set of env vars and gamescope args that they use regularly for games to avoid messes like
`env -u LD_PRELOAD ENABLE_GAMESCOPE_WSI=0 SteamDeck=0 XKB_DEFAULT_LAYOUT=no MANGOHUD_CONFIG=read_cfg,preset=2 gamescope --mangoapp -f -w 2560 -h 1440 -W 2560 -H 1440 -e --force-grab-cursor --hdr-enabled -- env LD_PRELOAD="$LD_PRELOAD" %command%`

Instead they can define the defaults in `~/.config/scopebuddy/scb.conf` like this
```ini
export XKB_DEFAULT_LAYOUT=no
export MANGOHUD_CONFIG=read_cfg,preset=2
SCB_DEFAULT_ARGS="--mangoapp -f -w 2560 -h 1440 -W 2560 -H 1440 -r 180 --force-grab-cursor --hdr-enabled -e --adaptive-sync"
```

now this is simplified in the launch options as
`SteamDeck=0 ENABLE_GAMESCOPE_WSI=0 scb -- %command%`

If the user wants a specific config they do not need to remember for a specific game (in this example warframe) then they can make an AppID config in `~/.config/scopebuddy/AppID/230410.conf`, `230410` is the Steam App ID for warframe. In this we can add
```ini
export MANGOHUD_CONFIG=read_cfg,preset=3
export SteamDeck=0
export ENABLE_GAMESCOPE_WSI=0
SCB_DEFAULT_ARGS="--mangoapp -f -w 1920 -h 1080 -W 2560 -H 1440 -r 60 --force-grab-cursor --hdr-enabled -e --adaptive-sync"
```
So now i can set the launch options for warframe to `scb -- %command%` and it will source `~/.config/scopebuddy/scb.conf` then source `~/.config/scopebuddy/AppID/230410.conf` which will override anything set by `scb.conf` if they touch the same variables, in this example it will upscale the game from 1080p to 1440p and limit refresh rate to 60 while setting the `SteamDeck` and `ENABLE_GAMESCOPE_WSI` environment variables, change MangoHud to preset 3 and keep the XDG keyboard layout set by `scb.conf`.
This also means it will run any bash code written in the config file before launching the game too!

Then to not use the gamescope args defined in `SCB_DEFAULT_ARGS` the user just has to supply any gamescope arg like so, as they clearly do not want the defaults then. (current implementation still will apply default env vars though)
`scb -r 180 -- %command%`

The user can also define a different file that contains different defaults too by overriding `SCB_CONF` with the new filename.
`SCB_CONF=1080_180hz_upscaled_hdr.conf scb -- %command%`
this will then load the config from `~/.config/scopebuddy/1080_180hz_upscaled_hdr.conf` instead

RFC:
* Unsure if we should make the script not load the config file at all if a gamescope arg is provided or if we should make it just load the env vars
* ~~Should we preemptively have this named something else in prep for upstream fixing this issue?~~

PROS:
* Fixes overlay when using nested gamescope in most titles
* Gives users a command to use for using nested gamescope with a default set of env vars and args (giving this a purpose once it is fixed upstream)

Limitations:
* ~~`%command%` has to be in double quotes, args after `"%command%"` does not need to be quoted unless you would normally~~ fixed with 58f5bf648d
* does not fix the overlay in all games (usually games where it didn't work to begin with)
* `gamemode.conf` will be forced as the only possible default config when running inside gamemode (appid configs will still be loaded as usual if they exist)


Co-authored-by: Avery <git@avery.cafe>

* feat: only load default args if the user supplies none, but do load default env vars

* fix: output each line from gamescope-overlay-injector.gamescope.out until xwayland is initialized

* feat: Use a fifo file so we dont end up filling memory by accident

Co-authored-by: Zeglius <33781398+Zeglius@users.noreply.github.com>

* feat: rename to scopebuddy

* feat: add GAMESCOPE_BIN env var

according to @tulilirockz it will help making this work inside flatpak

Co-authored-by: Tulip Blossom <tulilirockz@outlook.com>

* chore: improve wording

* feat: make SCB_CONFFILE configurable through env vars

For advanced users

* fix: remove rogue $ in example config

* fix(scopebuddy): double quoting %command% is no longer required

* chore: remove quoted %command% from example

* chore(scopebuddy): rename SCB_CONFFILE to SCB_CONF for clairity and less to type for overriding and renamd SCB_CONFIG to SCB_CONFIGFILE for clairity in code

* feat: add support for automatic loading of configs based on Steam AppID

example:
throw a config named `230410.conf` into `~/.config/scopebuddy/AppID/` and it will automatically be loaded instead of `scb.conf`
as long as the user does not specify a custom file through the SCB_CONF env var

* chore(scopebuddy): shellcheck cleanup

* chore: remove old references to GOI

* feat: add SCB_NOSCOPE override to launch %command% without gamescope

@wolfyreload wanted to use this nonsense in gamemode :P

* feat(scopebuddy): add separate default conf file for SCB_NOSCOPE=1

* feat(scopebuddy): add support for usage inside gamemode

* chore(scopebuddy): clarify advanced example text

* fix(scopebuddy): HDR now works with gamescope spawned by scopebuddy

---------

Co-authored-by: Avery <git@avery.cafe>
Co-authored-by: Zeglius <33781398+Zeglius@users.noreply.github.com>
Co-authored-by: Tulip Blossom <tulilirockz@outlook.com>
Tested-by: Crono <39300993+EPOCHvoyager@users.noreply.github.com>
Tested-by: wolfyreload <open.chords.app@gmail.com>
This commit is contained in:
HikariKnight 2025-03-07 10:23:57 +01:00 committed by GitHub
parent 1c6e262f9b
commit 35ff028947
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 135 additions and 0 deletions

View File

@ -0,0 +1 @@
scopebuddy

View File

@ -0,0 +1,134 @@
#!/usr/bin/env bash
# Special thanks to @coolavery for the initial script for this
# https://github.com/ValveSoftware/gamescope/issues/835#issuecomment-2496383830
#
# Purpose of this script:
# * Allow launching gamescope with a default set of environment variables and gamescope args set by the user
# "~/.config/scopebuddy/scb.conf" will be created with examples after first run
# * Serve as a temporary workaround for fixing the steam overlay when using nested gamescope on desktop steam until fixed upstream
set -eo pipefail
gsout="/tmp/scopebuddy.out"
gamescope_opts=""
command=""
# Set SCB to use gamescope by default
SCB_NOSCOPE=${SCB_NOSCOPE:-0}
# Set default gamescope binary
GAMESCOPE_BIN=${GAMESCOPE_BIN:-gamescope}
# Configure SCB config
SCB_CONF=${SCB_CONF:-"scb.conf"}
SCB_CONFIGDIR="$HOME/.config/scopebuddy"
# By default we will never be in gamemode
SCB_GAMEMODE=0
# If SCB_NOSCOPE is set to 1 and we are not using a custom SCB_CONF
if [ "$SCB_NOSCOPE" -eq 1 ] && [ "$SCB_CONF" == "scb.conf" ]; then
# Use noscope.conf for default values
SCB_CONF="noscope.conf"
fi
# If steam is potentially running inside gamescope
# shellcheck disable=SC2009
if ps ax | grep -P "steam.sh -.+ -steampal" | grep -v grep || pgrep -f "gamescope-session" ; then
# If steam is potentially running in gamemode
# Force SCB_NOSCOPE to 1
SCB_NOSCOPE=1
# Set SCB_GAMEMODE to 1
SCB_GAMEMODE=1
# Use gamemode.conf for default values
SCB_CONF="gamemode.conf"
fi
# Finalize SCB_CONFIGFILE
SCB_CONFIGFILE="$SCB_CONFIGDIR/$SCB_CONF"
# Split the args at -- into gamescope_opts and command
while [[ $# -gt 0 ]]; do
if [ "${1:-}" == "--" ]; then
shift
# Add remaining args as individually double quoted args (should stop double quoting being a requirement)
while [[ $# -gt 0 ]]; do
# command variable has to be formated like this otherwise the %command% will not launch
# shellcheck disable=SC2089
command+=" \"$1\""
shift
done
# Exit loop when done
break
fi
# Add arg to gamescope_opts and go to next loop
gamescope_opts+=" $1"
shift
done
# Get the STEAM_APPID from %command%
STEAM_APPID=$(echo "$command" | perl -pe 's/.+"AppId=(\d+)"\s.+/\1/')
# Load the SCB config file if it exists then apply the default args
if [ -f "$SCB_CONFIGFILE" ]; then
# Source the config from SCB_CONF
# shellcheck disable=SC1090
source "$SCB_CONFIGFILE"
# If a config exists for this games STEAM_APPID and SCB_CONF is set to scb.conf (default)
if [ -f "$SCB_CONFIGDIR/AppID/${STEAM_APPID}.conf" ]; then
# Source the STEAM_APPID specific config, overriding any similar values set by SCB_CONF
# shellcheck disable=SC1090
source "$SCB_CONFIGDIR/AppID/${STEAM_APPID}.conf"
fi
# If the user has supplied ANY args to gamescope, do not load the SCB_DEFAULT_ARGS
if [ -z "$gamescope_opts" ]; then
gamescope_opts=$SCB_DEFAULT_ARGS
fi
else
# Make the default config file
if [ ! -d "$SCB_CONFIGDIR/AppID" ]; then
mkdir -p "$SCB_CONFIGDIR/AppID"
fi
cat << 'EOF' > "$SCB_CONFIGFILE"
# This is the config file that let's you assign defaults for gamescope when using the scopebuddy script
# lines starting with # are ignored
# Conf files matching the games Steam AppID stored in ~/.conf/scopebuddy/AppID/ will be sourced after
# ~/.config/scopebuddy/scb.conf or whichever file you specify with SCB_CONF=someotherfile.conf env var in the launch options.
#
# Example for always exporting specific environment variables for gamescope
#export XKB_DEFAULT_LAYOUT=no
#export MANGOHUD_CONFIG=read_cfg,preset=2
#
# Example for providing default gamescope arguments through scopebuddy if no arguments are given to the scopebuddy script, this does not need to be exported.
# To not use this default set of arguments, just launch scb with SCB_NOSCOPE=1 or just add any gamescope argument before the '-- %command%' then this variable will be ignored
#SCB_DEFAULT_ARGS="--mangoapp -f -w 2560 -h 1440 -W 2560 -H 1440 -r 180 --force-grab-cursor --hdr-enabled -e"
#
###
## FOR ADVANCED USE INSIDE AN APPID CONFIG
###
# The config files are treated as a bash script by scopebuddy, this means you can use bash to do simple tasks before the game runs
# or you can check which mode scopebuddy is running in and apply settings accordingly, below are some handy variables for scripting.
# $SCB_NOSCOPE will be set to 1 if we are running in no gamescope mode
# $SCB_GAMEMODE will be set to 1 if we are running inside steam gamemode (which means SCB_NOSCOPE will also be set to 1 due to nested gamescope not working in gamemode)
# $command will contain everything steam expanded %command% into
EOF
fi
# If SCB_NOSCOPE is set to 1
if [ "$SCB_NOSCOPE" -eq 1 ]; then
# If we are potentially in gamemode
if [ "$SCB_GAMEMODE" -eq 1 ]; then
# Force MANGOHUD=0
export MANGOHUD=0
fi
# Launch %command% without gamescope
eval "$command"
else
# Transfer LD_PRELOAD before we unset it
LD_PRELOAD_REAL=$LD_PRELOAD
# Unset LD_PRELOAD for gamescope (as it breaks the overlay) then start gamescope with LD_PRELOAD set for %command% instead
echo "Launching: env -u LD_PRELOAD $GAMESCOPE_BIN $gamescope_opts -- env LD_PRELOAD=$LD_PRELOAD_REAL $command"
eval "env -u LD_PRELOAD $GAMESCOPE_BIN $gamescope_opts -- env LD_PRELOAD=$LD_PRELOAD_REAL $command"
fi