Files
obsidian-vault/family/how-to/htpc-steam-nonsteam-shortcuts.md
T

212 lines
9.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Non-Steam Shortcuts через VDF
## Главное правило
**Steam должен быть выключен** перед записью shortcuts.vdf. Если Steam работает — он перезапишет файл из памяти при следующем запуске.
## Подводные камни native Linux shortcut'ов (Worms W.M.D case)
### Проблема: Steam не видит `/run/media/system/Data/`
Steam, запущенный через `gamescope-session-plus`, работает в изолированном mount namespace. Путь `/run/media/system/Data/` (btrfs-подраздел) может быть **не виден** Steam-процессу.
**Симптом:** нажимаешь Play → `chdir` в логах есть, `exit code 0` мгновенно, игра не стартует. `/tmp/worms_stderr.log` не создаётся — значит `run.sh` даже не запустился.
**Причина:** Steam проверяет существование `exe` файла перед запуском native shortcut. Если файл не найден — `steam-launch-wrapper` завершается с кодом 0 без ошибки. Для Proton shortcut'ов эта проверка не делается — Steam передаёт путь внутрь Proton.
**Решение:** не указывать `exe` на `/run/media/system/Data/...`. Вместо этого:
1. Создать symlink в `/home/bazzite/`:
```bash
ln -sf /run/media/system/Data/Games/.../run.sh /home/bazzite/game_name.sh
```
2. В VDF прописать `exe = /home/bazzite/game_name.sh`, `StartDir = /home/bazzite/`.
3. `/home/bazzite/` виден из любого mount namespace.
### Проблема: `run.sh` глушит stderr
Многие native Linux игры (особенно старые MojoSetup-инсталляторы) имеют в `run.sh`:
```sh
exec ./binary 2>/dev/null "$@"
```
`2>/dev/null` скрывает все ошибки. Steam логи не показывают stderr дочернего процесса.
**Решение:** убрать `2>/dev/null` из `run.sh`. Если нужно дебажить — перенаправить в файл:
```sh
exec ./binary 2>/tmp/game_stderr.log "$@"
```
### Проблема: старая `libmp3lame.so.0` без нужного символа
Старые native игры тащат свою `libmp3lame.so.0` (2019-2020), в которой нет символа `lame_encode_buffer_interleaved_int`. Системная `libsndfile.so.1` (Fedora 43) требует этот символ.
**Симптом:** `symbol lookup error: /lib64/libsndfile.so.1: undefined symbol: lame_encode_buffer_interleaved_int`
**Причина:** линковщик загружает игровую `libmp3lame.so.0` из `data/lib/` (старая, без символа), а `libsndfile.so.1` из `/lib64/` — и находит уже загруженную старую копию.
**Решение:** заменить игровую `libmp3lame.so.0` на системную:
```bash
cp /lib64/libmp3lame.so.0 /run/media/system/Data/Games/.../data/lib/libmp3lame.so.0
```
### Статус Worms W.M.D (native Linux)
- **Версия:** MojoSetup-инсталлятор с rutracker (Worms W.M.D [239.583366] [Native])
- **Путь:** `/run/media/system/Data/Games/Worms W.M.D Native/Worms W.M.D/`
- **Symlink:** `/home/bazzite/worms_wmd.sh → .../run.sh`
- **Steam shortcut:** entry 109, appid = -364361099 (unsigned: 3930606197)
- **LaunchOptions:** `%command%`
- **Статус:** ✅ запускается
## Остановка Steam (Bazzite game session)
```bash
systemctl --user stop gamescope-session-plus@steam.service
sleep 2
systemctl --user is-active gamescope-session-plus@steam.service # должен вернуть "inactive"
# правишь VDF
systemctl --user start gamescope-session-plus@steam.service
```
Если после stop Steam всё ещё активен — повторить.
## Единственный правильный способ — vdf.binary_load
Использовать модуль `vdf` (установлен на HTPC через pip). **Никогда** не редактировать бинарный VDF через ручную сборку байтов или замену строк — это ломает файл.
```python
import os, vdf, shutil, binascii, struct
vdf_path = os.path.expanduser('~/.steam/steam/userdata/147839491/config/shortcuts.vdf')
# 1. Бэкап
shutil.copy2(vdf_path, vdf_path + '.bak')
# 2. Загрузить существующий
with open(vdf_path, 'rb') as f:
data = vdf.binary_load(f)
shortcuts = data.get('shortcuts', {})
# 3. Вычислить appid (алгоритм Steam)
def compute_appid(name, exe):
key = exe + name
top = binascii.crc32(key.encode('utf-8')) | 0x80000000
return struct.unpack('i', struct.pack('I', top))[0]
# 4. Создать entry
next_idx = str(len(shortcuts))
shortcuts[next_idx] = {
'AppName': 'Game Name',
'Exe': '/path/to/game.exe',
'StartDir': '/path/to/',
'LaunchOptions': '',
'appid': compute_appid('Game Name', '/path/to/game.exe'),
'IsHidden': 0,
'AllowDesktopConfig': 1,
'AllowOverlay': 1,
'OpenVR': 0,
'Devkit': 0,
'DevkitGameID': '',
'DevkitOverrideAppID': 0,
'LastPlayTime': 0,
'FlatpakAppID': '',
'sortas': '',
'tags': {},
}
# 5. Записать
data['shortcuts'] = shortcuts
with open(vdf_path, 'wb') as f:
vdf.binary_dump(data, f)
```
## CompatToolMapping (Proton) в config.vdf
После добавления shortcut нужно прописать Proton в текстовом `config.vdf`:
```python
import vdf
CONFIG_PATH = os.path.expanduser('~/.local/share/Steam/config/config.vdf')
with open(CONFIG_PATH, 'r') as f:
config = vdf.load(f)
compat_map = config['InstallConfigStore']['Software']['Valve']['Steam'].setdefault('CompatToolMapping', {})
compat_map[str(appid_signed)] = {
'name': 'GE-Proton10-34', # или 'proton_experimental'
'config': '',
'Priority': '250',
}
with open(CONFIG_PATH, 'w') as f:
vdf.dump(config, f)
```
## Полный скилл
Вся процедура (shortcuts + Proton + artwork) описана в скилле `steam-emulator-shortcuts`. Смотреть там.
## Бэкап
```bash
cp ~/.steam/steam/userdata/*/config/shortcuts.vdf{,.bak}
```
Автоматический бэкап `shortcuts.vdf` делается ежедневно скриптом `backup-saves.sh` на HTPC, версии хранятся в `/run/media/bazzite/Data/backups/saves/shortcuts/` (последние 30 копий).
## Перезагрузка Steam
После записи VDF — перезапустить Steam, чтобы он подхватил изменения.
## Wide Steam Grid Posters
При добавлении новой не-Steam игры — сразу скачивай и **wide** (920×430, `{appid}.png`), а не только poster (600×900, `{appid}p.png`).
Без wide постером игра выглядит как пустая белая заглушка в основном режиме библиотеки.
### Naming convention
Файлы кладутся в `~/.steam/steam/userdata/147839491/config/grid/`:
| Размер | Формат файла | Назначение |
|--------|-------------|------------|
| 920×430 | `{unsigned_appid}.png` | Wide — основная карточка в библиотеке |
| 600×900 | `{unsigned_appid}p.png` | Poster — вертикальный, при наведении |
| 1920×620 | `{unsigned_appid}_hero.png` | Hero — фон на странице игры |
| 1200×351 | `{unsigned_appid}_logo.png` | Логотип на hero |
**Unsigned appid** = `signed_appid & 0xFFFFFFFF`. Пример: `-1321720074` → `2973247222`.
### Процедура (как делал Whale)
1. **Найти постеры на SteamGridDB** — зайти на `https://www.steamgriddb.com/game/<ID>`, отфильтровать по 920×430.
- Для новых игр: поискать `<игра> site:steamgriddb.com`
- Wide grids часто меньше по количеству чем posters (600×900), их ищем в секции Grids → фильтр `Dimensions: 920×430`
2. **Получить прямую ссылку CDN** — thumbnails на странице grid'a ведут на `cdn2.steamgriddb.com/thumb/<hash>.jpg`, а полный файл лежит по `cdn2.steamgriddb.com/grid/<hash>.png`.
3. **Скачать локально:**
```bash
curl -s -o /tmp/<appid>.png "https://cdn2.steamgriddb.com/grid/<hash>.png"
```
4. **Закинуть на HTPC** через scp в `/tmp/`:
```bash
scp /tmp/<appid>.png bazzite@192.168.1.86:/tmp/<appid>.png
```
5. **Скопировать в grid-директорию Steam:**
```bash
ssh bazzite@192.168.1.86
cp /tmp/<appid>.png ~/.steam/steam/userdata/147839491/config/grid/<appid>.png
```
6. **Перезапустить Steam** (Steam перечитывает grid-файлы свежими при старте, но часто подхватывает и без перезапуска):
```bash
systemctl --user stop gamescope-session-plus@steam.service
systemctl --user start gamescope-session-plus@steam.service
```
### SteamGridDB ключ API
`5f0a7cb3366dede2c10860a95795ce60` — для программного доступа.