从零添加你的第一个游戏:Sunshine 应用管理完整指南
【免费下载链接】SunshineSelf-hosted game stream host for Moonlight.项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine
你打开 Sunshine 的 Web 界面,满怀期待地准备串流昨晚刚买的 3A 大作,却发现"Applications"页面里只有孤零零的 Desktop 和 Steam Big Picture 两个预设项。别慌,这几乎是每个 Sunshine 新手都会遇到的第一道坎——游戏库管理。
Sunshine 作为一套自托管的游戏流媒体服务器,它的灵魂不在编码器,而在那个决定"按下串流键后到底运行什么"的应用配置系统。搞清楚它,你就能把任意平台、任意启动方式的游戏都变成一键串流的入口。这篇指南会带你从零搭建自己的游戏库,顺便把背后的机制也讲透。
先看结果:你最终会得到什么
配置完成后,你的"Applications"页面会长这样:每个游戏一张卡片,带图标、启动路径、编辑和删除按钮,点一下就能从 Moonlight 客户端远程启动。
注意页面顶部那句提示:"Applications are refreshed only when Client is restarted"——应用列表只在客户端重启时刷新,所以改完配置后记得在 Moonlight 里刷新一下,否则看不到新游戏。
原理速览:一个 JSON 文件驱动的应用引擎
Sunshine 的应用管理远比你想的简单。它没有数据库,没有复杂的服务注册,核心就是一个apps.json文件。整个链路是这样的:
这个文件默认位于 Sunshine 的配置目录下(通常与sunshine.conf同级),文件名就叫apps.json,对应源码里的APPS_JSON_PATH常量。它是个标准的 JSON 数组,每个元素描述一个应用:叫什么名字、运行什么命令、要不要提前做点什么、图标在哪。
你完全可以在 Web UI 里图形化编辑,也可以直接手写这个文件——两种方式殊途同归。理解了这个机制,你就明白为什么说"Sunshine 应用管理 = 管理一个 JSON 数组"。
分步实操:添加第一个游戏
我们以最常见的 Steam 游戏为例,走一遍完整流程。Steam 游戏推荐用URI 方式启动,也就是steam://rungameid/<游戏ID>,因为它绕开了 Steam 自身的更新进程和路径问题,最稳定。
第一步:找到游戏 ID
在 Steam 商店页面或游戏库中,右键游戏属性,或者直接看商店 URL——https://store.steampowered.com/app/1091500/Cyberpunk_2077/里的1091500就是游戏 ID。记下它。
第二步:在 Web UI 中添加应用
- 打开 Sunshine Web UI(默认
https://localhost:47990),进入Applications页面 - 点击右下角蓝色的Add New按钮
- 填写表单:
- Application Name:填游戏名,比如 "Cyberpunk 2077"
- Image:可选,填应用图标文件名,也可以不填(留空会显示默认占位图)
- Detached Commands:填入
steam://rungameid/1091500
- 保存
第三步:理解"分离命令"而非"主命令"
这里有个新手最容易踩的坑:为什么填的是 Detached 而不是 Command?
因为 Steam 启动游戏时会先自更新,然后由新进程接管,最初那个进程会退出。如果填在主命令(Command)里,Sunshine 检测到"目标进程退出"就会立刻结束串流会话——游戏刚开就被掐断。
分离命令(detached)的意思是:Sunshine 只管把这个命令"发射"出去,不追踪它的生命周期,串流会话继续维持。这就是为什么所有 Steam 类游戏都推荐 detached 方式。
第四步:直连二进制游戏的方式
如果你有独立运行的游戏(比如 Epic 商店下载的或直接解压的绿色版),就用主命令方式:
{ "name": "Surviving Mars", "cmd": "MarsEpic.exe", "working-dir": "C:\\Program Files\\Epic Games\\SurvivingMars", "image-path": "surviving-mars.png" }上面这段配置里:
cmd是主执行程序,Sunshine 会持续追踪它的进程状态,进程结束串流就结束working-dir指定工作目录——不填的话,Sunshine 默认取命令所在目录,所以要么写全路径,要么保证工作目录正确image-path是显示在 Web UI 和应用列表里的图标
💡 小结:URI 启动(Steam/Epic)填 detached,直接执行程序填 cmd。前者"发射不管",后者"跟踪到结束"。
参数速查表:一张表看懂所有字段
以下字段在 Web UI 里都能对应找到,直接写 JSON 时也通用:
| 字段名 | 类型 | 说明 | 示例 |
|---|---|---|---|
name | string | 应用显示名称(必填) | "Cyberpunk 2077" |
cmd | string/array | 主执行命令,进程退出即结束串流 | "game.exe" |
detached | array | 分离命令,发射后不追踪 | ["steam://rungameid/1091500"] |
prep-cmd | array | 预备命令,启动前执行/结束后撤销 | [{"do": "...", "undo": "..."}] |
working-dir | string | 工作目录,默认取命令所在目录 | "C:\\Games\\Cyberpunk" |
image-path | string | 应用图标路径 | "cyberpunk.png" |
elevated | bool | 是否以管理员权限运行(Windows) | true |
auto-detach | bool | 启动后5秒内退出则自动转为分离模式 | true |
wait-all | bool | 是否等待所有子进程退出 | false |
exit-timeout | int | 收到退出信号后强制结束的等待秒数 | 3 |
exclude-global-prep-cmd | bool | 是否跳过全局预备命令 | true |
全局预备命令是什么?在 Configuration 页面的Command Preparations里配置,会对所有应用生效。某个应用想跳过它,就设置"exclude-global-prep-cmd": true。
进阶技巧:预备命令与环境变量让串流更聪明
预备命令(prep-cmd)是 Sunshine 应用管理里最有价值的功能:在游戏启动前执行do,在串流结束后执行undo。最典型的用途是动态切换分辨率。
动态分辨率调整(Windows)
不同客户端设备分辨率不同,你在 4K 电视和 1080p 笔记本之间切换时,总不能每次手动改系统分辨率。用预备命令加环境变量就能全自动:
{ "name": "Cyberpunk 2077", "cmd": "game.exe", "prep-cmd": [ { "do": "cmd /C \"C:\\Tools\\QRes.exe /X:%SUNSHINE_CLIENT_WIDTH% /Y:%SUNSHINE_CLIENT_HEIGHT% /R:%SUNSHINE_CLIENT_FPS%\"", "undo": "C:\\Tools\\QRes.exe /X:1920 /Y:1080 /R:60" } ] }do里的%SUNSHINE_CLIENT_WIDTH%、%SUNSHINE_CLIENT_HEIGHT%、%SUNSHINE_CLIENT_FPS%是 Sunshine 注入的环境变量,取的是当前发起串流的客户端请求的分辨率和帧率undo在会话结束后把分辨率恢复成你平时使用的 1920x1080@60,别忘了写 undo,否则串流结束你的显示器分辨率就回不来了
Linux X11 环境的分辨率设置
Linux 下思路一样,换成xrandr即可:
{ "prep-cmd": [ { "do": "sh -c \"xrandr --output HDMI-1 --mode ${SUNSHINE_CLIENT_WIDTH}x${SUNSHINE_CLIENT_HEIGHT} --rate ${SUNSHINE_CLIENT_FPS}\"", "undo": "xrandr --output HDMI-1 --mode 3840x2160 --rate 120" } ] }注意 Linux 下环境变量要用${}展开,并用sh -c包裹,而 Windows 用%VAR%,别混用。
常用环境变量一览
这些变量来自源码process.cpp中的进程环境注入逻辑,凡是通过 Sunshine 启动的进程都能读到:
| 环境变量 | 描述 | 示例值 |
|---|---|---|
SUNSHINE_APP_NAME | 当前应用名称 | Cyberpunk 2077 |
SUNSHINE_APP_ID | 当前应用在列表中的序号 | 3 |
SUNSHINE_CLIENT_WIDTH | 客户端请求的宽度 | 1920 |
SUNSHINE_CLIENT_HEIGHT | 客户端请求的高度 | 1080 |
SUNSHINE_CLIENT_FPS | 客户端请求的帧率 | 60 |
SUNSHINE_CLIENT_HDR | 客户端是否启用 HDR | true/false |
在预备命令脚本里自由组合它们,你甚至可以按客户端分辨率自动决定启动哪个版本的配置文件。
💡 小结:prep-cmd 的
do/undo是对称的一对,只写do不写undo等于给系统留下了一个"脏状态"。
避坑指南:三个高频故障的排查思路
故障一:游戏启动后串流立刻结束
症状是:你刚在 Moonlight 上点启动,画面闪一下就退回主界面。十有八九是命令方式选错了——Steam/Epic 这类带自更新进程的游戏填进了cmd而非detached。自查顺序:
- 改用
detached方式启动 - 或者设置
"auto-detach": true,让 Sunshine 在检测到启动后 5 秒内进程退出时自动转为分离模式 - 确认命令本身能独立运行(先在主机上手动执行一次)
故障二:游戏启动了但手柄/键鼠完全没反应
检查方向要分平台:
- Linux:Sunshine 运行用户必须加入
input组,否则无法创建虚拟输入设备。执行sudo usermod -a -G input 你的用户名后注销重登 - Windows:确认虚拟手柄驱动已安装,串流期间拔插手柄会中断虚拟设备绑定,先重插再重连串流
故障三:串流分辨率跟客户端不匹配
画面拉伸变形或黑边,多半是没做动态分辨率切换。按上面的 prep-cmd 方案配置,并检查两点:预备命令里的变量名拼写是否正确、目标显示器是否支持该分辨率模式(不支持时 xrandr 会直接报错,注意查看 Sunshine 日志)。
最佳实践清单:把游戏库管得井井有条
- ☐能走 URI 就走 URI:Steam、Epic 等平台游戏一律用 URI 启动,比定位 exe 稳定得多
- ☐Windows 游戏路径用双反斜杠:
"C:\\Program Files\\...",单个反斜杠会被 JSON 转义吃掉 - ☐每个应用都配图标:用
image-path指定 PNG 图标,库一多你就知道这多重要 - ☐prep-cmd 务必成对:写
do的同时写undo,退出后恢复现场 - ☐新应用添加后重启客户端:Moonlight 端刷新应用列表再测试,避免"看不到新游戏"的假故障
- ☐改完配置先测命令行:把
cmd/detached里的命令拿到终端里手动跑一遍,确认能启动再填进配置,能省一半排查时间 - ☐定期备份 apps.json:重装系统或迁移主机时,拷走这一个文件就带走了整个游戏库
延伸阅读:往深处挖一挖
想彻底掌握应用管理的实现细节,可以从这些入口继续:
- 官方示例库:docs/app_examples.md,包含 Steam、Epic、各类模拟器、甚至自定义脚本的跨平台配置案例
- 配置字段完整文档:docs/configuration.md,所有配置项的权威说明
- 应用解析与执行源码:src/config.cpp(JSON 解析与字段读取)和 src/process.cpp(进程启动、环境变量注入、分离命令逻辑)
- Web 界面源码:src_assets/common/assets/web/apps.html,看完你就知道 UI 上每个字段背后对应哪个 JSON 键
现在,打开你的 Sunshine Web UI,Add New 一个 Steam 游戏试试——记得先看游戏 ID,填进 Detached Commands,保存,然后回 Moonlight 刷新。等串流画面里游戏顺利跑起来的那一刻,你会觉得这十分钟的配置完全值得。🚀
【免费下载链接】SunshineSelf-hosted game stream host for Moonlight.项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考