- Startseite
- Plugins
- Nur zum Spaß
- dsh-plugin-genshin-launch
dsh-plugin-genshin-launch
link258qaq/dsh-plugin-genshin-launch
Erkennt bei jedem DSH-Start den GUI-Port und lädt den Installer des Genshin Impact-Launchers auf den Desktop. Eine Größenprüfung weist Links zurück, deren Datei um mehr als 50 MB vom erwarteten Wert von etwa 224 MB abweicht. Bei fehlgeschlagenem Download wird die offizielle Downloadseite geöffnet.
Installation
dsh plugin --profile web add github:link258qaq/dsh-plugin-genshin-launchREADME
dsh-plugin-genshin-launch
原神,启动! —— 给 DeepSeek Harness(DSH)装一个插件:每次打开 DSH,先零配置看看本机有没有装《原神》——
- 装了 → 停止下载,直接把游戏本体拉起来(本体起不来自动改起米哈游启动器)。这就是「打开 DSH 就启动原神」。
- 正在装 / 更新(登记了位置但本体还没下完)→ 也不下载,改为启动米哈游启动器让它继续。
- 没装 → 把启动器安装包下载到桌面,带 224MB 体积安全闸;下载不成退化成打开官方下载页。
一句话简介(可直接用作 GitHub 仓库 About):
DSH 插件:打开 DSH 时零配置探测本机《原神》,装了就直接启动游戏本体(起不来自动改起米哈游启动器),没装就下载启动器安装包到桌面。
╔══════════════════════════════════════════════════════════╗
║ 原神,启动! ║
╚══════════════════════════════════════════════════════════╝
[genshin-launch] 识别到 DSH 端口:3080(http://127.0.0.1:3080)
[genshin-launch] 探测 · HoYoPlay 启动器安装目录:D:\…\miHoYo Launcher
[genshin-launch] 探测 · → 采用 D:\…\YuanShen.exe(来源:registry:hyp:hk4e_cn)
[genshin-launch] 检测到已安装的原神(国服 / B 服):D:\…\YuanShen.exe
[genshin-launch] 已安装 → 停止自动下载,改为「打开 DSH 就启动原神」
[genshin-launch] 启动原神(gui-open):D:\…\YuanShen.exe(方式 spawn)
[genshin-launch] 原神已启动(pid 21456)
网页右下角还有一个金边小面板,实时显示「原神,启动! + DSH 端口 + 探测到的本体(掩码路径)+ 启动结果 / 下载进度」。
特性
方案二:打开 DSH 就启动原神
- 零配置探测:用户什么都不用设置。按「先快后慢、命中即停」的顺序找(见下),最快一档约 400ms,实测整条快档 0.5 秒跑完。
- 触发时机 = 浏览器真的把界面渲染出来的那一刻,不是宿主进程启动的那一刻。原因是本 profile 开了
patchReload: live:挂在宿主apply上的话,你每改一次配置就会再弹一次原神。 - 每个 DSH 进程只启动一次:落盘标记以「宿主 pid + 进程启动时刻」为键,热重载不会重复启动,刷新页面也不会重开游戏。
- 秒退就改起启动器:启动后守一个观察窗(默认 3 秒)。本体在窗口内就退出(典型原因:客户端版本过低要先更新)→ 自动改起米哈游启动器;启动器也起不来才报错。
- 已经在跑就不重复启动:用进程名问一次(尽力而为,问不到就当没在跑,绝不因为问不到而拒绝启动)。
- 绝不静默提权,但会请你授权:插件不会用
runas悄悄提权。真机实测:YuanShen.exe与launcher.exe的清单都是requireAdministrator,用spawn(CreateProcess 语义)去起它不会弹 UAC,系统直接拒绝、Node 报EACCES。所以spawn一旦被这类权限问题拦下,插件自动改走一次shell(等价于双击),由 Windows 弹 UAC——你点同意才提权,点拒绝就不启动。不想回退可以设retryShellOnElevation: false。 - 不把 DSH 的秘密交给游戏:启动游戏时用脱敏后的环境变量(
*KEY*/*PASSWORD*/*SECRET*/*TOKEN*/DSH_*全部剔除,口径与@deepseek-ai/dsh-subprocess的scrubbedParentEnv一致)。游戏不该拿到你的 API key。 - 路径隐私:日志、网页面板、独立窗口、状态文件里的路径一律掩码成「盘符:\…\末段文件名」;手填/扫盘得到的本体地址在盘上按当前用户 DPAPI 加密存储;启动器路径不落盘(用时现探测);详见 隐私。
方案一:没装就把安装包下到桌面
- 端口识别:注入宿主
webServer服务读host/port,--port 0由系统分配端口也能拿到;DSH_WEB_URL兜底。 - 自动找最新版:候选直链可用时,还会在同一版本目录里向上探测更新的
pcbackup序号(实测 319 → 320)。 - 体积安全闸:启动器安装包约 224 MiB。凡是体积与预期相差超过 50 MiB 的链接——不管它来自候选、缓存还是探测——都会被整条拒绝:不下载、不续传,连已经下了一半的
.part一起删掉。体积拿不到也默认拒绝。 - 断点续传 / 落盘后复检 / 优雅退化 / 零依赖:同 v0.2。
怎么找到「已安装的原神」:五档阶梯
全程本地只读:读注册表字符串、existsSync 判存在、列目录项名字。不读文件内容、不联网、不发给任何模型。
| 档 | 做什么 | 实测开销 |
|---|---|---|
0 config | 配置里手填的 gameExe / gamePath(最高优先级,自测也用它) | 0ms |
1 registry | 读 HoYoPlay 的 HYP 树,取 hk4e_* 键下所有像盘符路径的值;再点查 3 个卸载记录根 × 4 个可能键名 | ~400ms |
2 paths | 每个盘根 + 每个顶层目录 × 几个常见安装目录名 | ~50ms |
3 scan | 卸载记录全量扫描(3 次 reg query /s)+ 有界扫盘(默认深度 ≤ 4,预算 20s) | 数秒 ~ 20s,只在前两档全落空时才跑,结果落盘 |
想彻底关掉扫盘:detectSources: ['config','registry','paths']。首次跑完会把「没找到」这个结论缓存 24 小时,之后每次开 DSH 都秒开。
几个实测踩出来的坑(决定了上面的设计)
- 注册表和卸载记录会残留,绝不能单独采信。 一台机器上「鸣潮」早卸载了卸载记录还在;
HKCU\Software\Classes\BetterGI指着一个已经删掉的目录;米哈游自己的HYP\standalone\14_0\hk4e_cn键存在但一个值都没有(现役布局其实在HYP\1_1)。所以任何读到的路径都必须立刻用文件系统复核。 - 值名不猜。 实测现役 HoYoPlay 1.18.0.380 把游戏路径记在
HKCU\Software\miHoYo\HYP\1_1\hk4e_cn的GameInstallPath下;但代码不按值名取,只要求「在hk4e_*键下、长得像盘符路径」——米哈游哪天改了值名也不会瞎。 - 不查
HKCU\Software\miHoYo\原神。 那个键里全是游戏自己的 Unity PlayerPrefs 和MIHOYOSDK_*加密 blob,不含安装路径(把全部REG_BINARY按 UTF-8/UTF-16 解过一遍找盘符路径,0 命中),而reg query它要跑 20 秒(输出 929KB 的十六进制倾倒)。放进阶梯等于每次开 DSH 塞一颗 20 秒的地雷。 reg.exe的输出编码跟着控制台代码页走。 中文 Windows 常见 936(GBK),也可能是 65001(UTF-8);直接按 UTF-8 解会把中文安装路径解成乱码。做法:统一先chcp 65001再查,输出就是确定的 UTF-8。- 进程启动开销才是大头。 点查「3 个卸载记录根 × 4 个键名」如果各起一次
cmd+reg,全落空时白花 800ms;串成一条cmd /c之后只剩一次进程启动。同理,固定候选路径从「每个组合一次existsSync(500 多次 stat,4.5 秒)」改成「每个顶层目录只readdir一次再比对(几十次,50ms)」。
「装了」「正在装」「没装」是三件事
中间那档很容易被忽略,但代价很实在:本体 exe 还没下下来时,如果只判「没装」,插件会去下一个 224MB 的启动器安装包——而启动器早就装好了。
所以探测结果有三个状态:
| 状态 | 判据 | 插件行为 |
|---|---|---|
ready | YuanShen.exe(国服/B服)或 GenshinImpact.exe(国际服)在位 | 启动本体 |
incomplete | 结构指纹 ≥ 2 条:有 YuanShen_Data\、有 pkg_version、有 mhypbase.dll/rtlbase.dll、config.ini 里有 game_version= | 不下载,启动米哈游启动器让它继续 |
| 没找到 | 上面都不满足 | 下载启动器安装包(方案一) |
要求「≥ 2 条指纹」是有意的:原神本体 60GB+,把随便一个带 config.ini 的目录误判成原神,代价比漏判高得多。
安装
从 GitHub 直接装(推荐,可固定版本):
dsh plugin --profile web add github:Link258QAQ/dsh-plugin-genshin-launch
# 固定到某个 tag:
dsh plugin --profile web add github:Link258QAQ/dsh-plugin-genshin-launch#v0.4.0
本地开发用 link::
dsh plugin --profile web add "link:D:\path\to\dsh-plugin-genshin-launch"
装完下一次 dsh --profile web 启动时自动跑一遍。
卸载:
dsh plugin --profile web remove dsh-plugin-genshin-launch
插件 ID 是
genshin-launch,包名dsh-plugin-genshin-launch。 用link:安装时,改本目录的代码下次启动就生效,不用重装。 也可以在 DSH Market 里搜dsh-plugin-genshin-launch(收录审核通过后可见)。
装之前请注意
- 如果本机装了原神,这个插件会在你每次打开 DSH 界面时把游戏拉起来。嫌烦就在配置里把
launchGame设成false,或者直接卸掉插件。 - 没装原神时,它真的会下 224 MB 到你的桌面(可以改成别的目录或改成只打开链接)。
- 从 v0.3 及更早版本升级:首次启动会自动做一次隐私迁移——桌面上老配置的本体地址搬进加密存储(
%LOCALAPPDATA%\dsh-genshin-launch),老配置里的冗余明文路径字段被清除,桌面遗留的dsh-genshin-launch-*.json(status/detect/session)会被删掉。功能不变,只是这些明文文件从此消失。 - 如果安装时 pnpm 需要重新解析依赖树,而你的网络访问不了 GitHub(
codeload.github.com),安装会失败并回滚。先确认 GitHub 通,或者按下面的「不动 pnpm 的装法」手工接线。
不动 pnpm 的装法(离线、零依赖重算)
link: 安装本质就是「package.json 加一条依赖 + bundles 登记 + 目录联接」,可以手工做:
- 在
$DSH_HOME\profiles\web\package.json的dependencies里加:
并在"dsh-plugin-genshin-launch": "link:D:/path/to/dsh-plugin-genshin-launch"dsh.profile.bundles数组里加一项"dsh-plugin-genshin-launch"。 - 建目录联接:
cmd /c mklink /J "$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-plugin-genshin-launch" "D:\path\to\dsh-plugin-genshin-launch" - 重启 DSH。
自检(装原神之前就能先验证启动链路)
插件带一个不依赖 DSH 的自检命令,把探测阶梯和启动各跑一遍并打印全过程:
# 只探测,看每一档查了什么、为什么没命中
node tools/selfcheck.mjs
# 拿任意一个程序当靶子,连「启动」一起验证(--kill 跑完把它收掉,别留窗口)
node tools/selfcheck.mjs --exe "D:\games\Shawarma\Shawarma Legend.exe" --launch --kill
# 换另一种启动通道(cmd /c start,双击语义)
node tools/selfcheck.mjs --exe "...\某程序.exe" --launch --kill --method shell
# 跳过最贵的扫盘那一档
node tools/selfcheck.mjs --no-scan
# 需要拿完整路径排错时(默认掩码成「盘符:\…\末段」,方便把输出直接贴进工单)
node tools/selfcheck.mjs --no-mask
退出码:找到(并启动成功)= 0,否则 1。
配置
在 $DSH_HOME/profiles/web/cordis.patch.yml 里按 id 覆盖:
- id: genshin-launch
name: dsh-plugin-genshin-launch
config:
# —— 方案二:打开 DSH 就启动原神 ——
launchGame: true # false = 不自动启动
launchTrigger: gui # gui = 浏览器打开界面时启动;host = 宿主进程一启动就启动
launchMethod: spawn # spawn = 直接起 exe(可判定成败);shell = cmd /c start(双击语义)
retryShellOnElevation: true # spawn 因「清单要管理员」被拦(EACCES)时,自动改走 shell 弹 UAC 一次
launchWatchMs: 3000 # 观察窗:这段时间内就退出算失败 → 回退去起启动器
fallbackToLauncher: true # 本体没起来就改起米哈游启动器
launchOncePerSession: true # 每个 DSH 进程最多启动一次
# —— 零配置探测 ——
gameExe: '' # 手填 exe 全路径(最高优先级)
gamePath: '' # 手填安装目录
detectSources: ['config', 'registry', 'paths', 'scan']
scanMaxDepth: 4
scanBudgetMs: 20000
extraRoots: [] # 额外的扫描 / 候选根目录
detectionCacheHours: 168 # 命中结果的缓存时长
negativeCacheHours: 24 # 「没找到」的缓存时长(只用来跳过扫盘那一档)
# —— 方案一:没装时下载 ——
download: true # false = 只打开下载链接
downloadDir: 'C:\Users\你\Desktop'
stateDir: '' # 状态/配置/缓存目录;默认隐藏的 %LOCALAPPDATA%\dsh-genshin-launch
expectedInstallerBytes: 234881024
sizeToleranceBytes: 52428800
openFileWhenDone: true
openFallbackWhenFailed: true
skipIfInstalled: true # false = 无视安装状态,照旧下载
方案二
| 字段 | 默认 | 说明 |
|---|---|---|
launchGame | true | 总开关;false 时只探测不启动 |
launchTrigger | gui | gui = 浏览器把界面渲染出来时启动(推荐);host = 宿主进程一启动就启动 |
launchMethod | spawn | spawn = spawn(exe, {detached, stdio:'ignore'}),能拿到 pid 与 error/exit,是唯一能判定「秒退」的通道;shell = cmd /c start "" <exe>,走 ShellExecute(清单要求管理员时由系统弹 UAC),代价是拿不到子进程句柄、只能靠进程名轮询 |
retryShellOnElevation | true | spawn 被系统按「需要提权」拦下(EACCES / 错误码 740)时,自动改走一次 shell 弹 UAC。设 false 则不自动回退(仍会先试 spawn,只是权限失败后不再自己走 shell) |
launchWatchMs | 3000 | 观察窗长度 |
fallbackToLauncher | true | 本体没起来就改起米哈游启动器 |
launchOncePerSession | true | 每个 DSH 进程最多启动一次 |
gameExe / gamePath | 空 | 手填路径,优先级最高(自测 / 特殊布局用)。落盘时按当前用户加密;界面里只回显掩码形式 |
detectSources | 全开 | 想关掉扫盘就删掉 'scan' |
scanMaxDepth / scanBudgetMs | 4 / 20000 | 有界扫盘的深度与时间预算 |
extraRoots | [] | 额外的扫描 / 候选根 |
detectionCacheHours / negativeCacheHours | 168 / 24 | 命中缓存 / 未命中缓存时长 |
方案一 / 通用
| 字段 | 默认 | 说明 |
|---|---|---|
enabled | true | 总开关;false 时插件完全不动作,网页面板也不出现 |
download | true | false = 只打开直链 |
downloadDir | 桌面 | 目标目录;留空则自动找 Desktop / 桌面 / OneDrive 桌面 |
stateDir | %LOCALAPPDATA%\dsh-genshin-launch | 状态/配置/缓存目录(含加密后的本体地址);测试或特殊环境可指到别处 |
url | 内置国服启动器直链 | 第一优先候选 |
extraUrls | [] | 追加候选直链 |
probeLatest / probeStart / probeAhead | true / 0 / 1 | pcbackup 序号向上探测 |
resume | true | 断点续传 |
expectedInstallerBytes | 224 MiB | 体积安全闸的预期值 |
sizeToleranceBytes | 50 MiB | 允许的体积偏差;超出 → 整条链接拒绝 |
minInstallerBytes / maxInstallerBytes | 0(自动推导) | 想直接指定上下限就填这里 |
allowUnknownSize | false | 服务端不给 Content-Length 时是否放行 |
openFileWhenDone | false | 下载完打开文件所在目录 |
openFallbackWhenFailed | true | 失败时打开官方下载页 |
fallbackUrls | ['https://ys.mihoyo.com/launcher', ...] | 兜底打开的页面 |
useCache / cacheTtlHours | true / 168 | 安装包链接解析缓存 |
skipIfInstalled | true | 装了原神是否跳过下载(false = 无视安装状态照旧下载) |
clientNotice / clientNoticeSeconds | true / 20 | 网页右下角面板 / 终态后自动关闭秒数 |
链接为什么会「自动更新」
米哈游没有给启动器安装包提供公开的“最新版”接口:游戏包有 hyp-connect API
(getGamePackages / getGameBranches),但启动器安装包只挂在 CDN 的版本目录下,
目录名是「时间戳_随机 token」,无法推导。实际可用的规律是:
- 你给的直链只要还活着就继续用(
HEAD检查 200 + 体积检查); - 同一版本目录下的
pcbackup<NNN>是顺序发布的安装包备份序号,号越大越新 (同一个安装器版本会同时挂 316/317/318/319/320 多个备份)。
所以插件先用你的直链,再顺手往上探一位,能拿到更新的就用更新的(实测 319 → 320); 如果你的直链失效了,就一直往上找到还存在的最大的序号。探测结果缓存 7 天。
诚实的边界:如果米哈游换了整个版本目录(新的时间戳 + token)并下掉旧目录,
pcbackup 往上探也没用,这时插件会按设计退化成打开官方下载页。
隐私与数据处理
本插件只在你本机工作,全程不联网上传任何个人信息(下载方案一从米哈游官方 CDN 拉公开安装包除外)。v0.4.0 起,对「可能沾到用户隐私的落盘与显示」做了系统整改:
落盘(磁盘上留什么)
- 只保留两样必须持久化的东西:① 原神本体地址(
gameExe,功能上必须知道它在哪才能启动);② 没装时下载的安装包地址(官方 CDN 直链,是公开链接、不含个人信息)。 - 本体地址在盘上按当前 Windows 用户加密(DPAPI
CurrentUser作用域,见lib/privacy.js)。别的用户 / 别的机器拿到这个文件解不开。DPAPI 不可用时(极端受限环境)如实降级为明文并在encryption字段标出来,绝不假装加密。 - 启动器路径不落盘:本体起不来要「改起启动器」时,从本体目录现推一次(
locateLauncherNear),用完即走。 - 配置格式 v1→v2 自动迁移:老版本把
scanFoundExe / installDir / gameDir / launcherPath等一堆明文路径写在桌面 JSON 里。v0.4 打开老配置时会自动把这些冗余字段清掉、把本体地址并进加密的secrets,并删除桌面上遗留的老状态文件(status / detect / session / window 脚本)。 - 临时残留自动清扫:注册表 / 进程列表的捕获输出(
%TEMP%\dsh-genshin-launch-*.out)在插件启动时扫一遍,删掉上一进程的残留(60 秒内的在途文件不动,避免抢正在写的那份)。 - 状态目录从桌面挪到隐藏的
%LOCALAPPDATA%\dsh-genshin-launch(可用stateDir覆盖;桌面里那种「谁都能翻一眼」的明文 JSON 从此不再产生)。
显示(日志与界面露什么)
- 日志和界面(网页面板、DSH 插件卡、独立窗口)里的路径一律掩码:完整路径压成「盘符:\…\末段文件名」,例如
C:\Users\example\Games\…\YuanShen.exe→C:\…\YuanShen.exe。用户名、中间目录结构都不出现。 - URL(
http://127.0.0.1:3080、官方下载页)不受影响——它们不是文件路径,不会被误掩码。 - 想改路径:因为界面只显示掩码,需重新粘贴完整路径(不能拿掩码串回填,否则会把
C:\…\xxx.exe当完整路径写回去;这一点在网页面板和独立窗口里都做了处理)。 - 自检
tools/selfcheck.mjs默认也掩码,方便你把输出直接贴进工单而不泄露本机目录;要排错拿全路径时加--no-mask。
一句话:盘上只留功能必需的两类地址且能加密就加密,其余能不存就不存;日志和界面只显示掩码。
已知限制与风险(请在装之前读一遍)
- 反作弊很在意「谁把你拉起来的」。 社区实测(2025 年「千星奇域」之后):第三方启动器会在进入游戏约 3 分钟后触发游戏内弹窗「检测到非法工具,请重启机器。错误码:10612-4001」;把自写程序改名成已知第三方工具的名字能复现,说明它至少部分依赖父进程名字黑名单。DSH/Node 不在已知名单里(Collapse 这类正经第三方启动器据报也不在),所以判断风险较低,但这属于会动到检测规则的东西,不是我们能保证的。
- 想更保守:
launchMethod: shell(父进程变成短命的cmd.exe,语义等于双击),代价是失去「秒退判定」。 - 真要完全规避:
launchGame: false,只用方案一。
- 想更保守:
- 原神本体与米哈游启动器都要求管理员权限(真机已确认)。
YuanShen.exe/launcher.exe的清单是requireAdministrator:用spawn直接起会被系统拒(EACCES),不会弹 UAC。插件的处理是——spawn因权限失败后自动改走一次shell,由 Windows 弹 UAC,你点同意才提权;点「否」就什么都不做。插件自己从不静默runas(守「绝不主动提权」)。不想自动回退就设retryShellOnElevation: false。 - 直接起游戏本体会跳过启动器的更新检查。 客户端版本过低时游戏会自己报错退出——这时观察窗会捕获「秒退」并自动改起启动器。
tasklist在某些受限环境里会被拒(Access denied)。 这时「是否已在运行」判定退化为「不知道」,插件会选择照常启动而不是拒绝启动。- HoYoPlay 的注册表布局会变。 我们已经见过
HYP\standalone\14_0\hk4e_cn(空残留)和HYP\1_1\hk4e_cn(现役)两种;代码枚举整棵树并靠叶子名认游戏,但米哈游再改一次结构仍可能需要更新插件。 - 有界扫盘只认目录名和几个结构指纹,不读文件内容、不联网。装在极其古怪的目录里仍可能漏;这时用
gamePath/gameExe手填,或把它加进extraRoots。
自测
npm test # 体积安全闸 + 配置 v2 加密/迁移 + 隐私模块(掩码/DPAPI/临时清扫)+ 探测/启动纯逻辑
npm run smoke # 宿主半侧集成冒烟:会真的启动一次靶子程序,跑完自动收掉(状态隔离在临时目录)
npm run smoke 用假的 ctx 把 apply() 拉起来,然后像浏览器那样走一遍路由,覆盖:四条浏览器侧接线是否注册、token 注入与幂等、启动路由的四种拒绝(错 token / 跨站 Origin / 非 POST / 非回环)、GUI 触发、启动成功、幂等(第二次触发不重复拉起)、状态文件落盘、秒退识别、目标不存在时报错而非崩溃。
验证记录
| 项 | 结果 |
|---|---|
| 端口识别 | 真实启动 dsh --profile web --no-open --port 3099,插件打印 识别到 DSH 端口:3099;/dsh-genshin-launch/status 返回 endpoint.port = 3099 |
| 最新版解析 | 种子 pcbackup319 可用 → 向上探测发现 pcbackup320 → 实际下载 320 那份 |
| 下载 | 223.5 MB 用时约 15s,落盘字节数与 CDN 一致,文件头是 MZ(合法 PE) |
| 体积安全闸 | 2 MiB / 900 MiB / 体积未知 → 全部拒绝;234382248 字节的真实安装包 → 放行;把预期改成 2 MiB 后同一文件放行(闸门可配置,不是写死) |
| 断点续传 | 造 1.5 MiB .part 后重跑,最终字节数与完整下载一致 |
| 落盘复检 | 体积不符会删文件并报错,不会把半截文件当成功 |
| 桌面不可写 | 自动改到工作区下载并打开资源管理器(模拟不可写目录实测通过) |
| index 注入 | 带 token 打开页面,HTML 里确实多出 <script defer src="/dsh-genshin-launch/client.js?token=…"></script> |
| 安装/卸载 | dsh plugin add/remove 均干净,卸载后 profile 的依赖与 bundles 完全还原 |
| 零配置探测(真实安装) | 真机装了 HoYoPlay 1.18.0.380 + 原神:从 HYP\1_1\hk4e_cn\GameInstallPath 读到游戏目录,并从 HYP\1_1\InstallPath 精确找到 launcher.exe;快档 0.5 秒跑完 |
| 「安装中」识别 | 真机在本体还没下完时(有 YuanShen_Data\、pkg_version、mhypbase.dll、rtlbase.dll、config.ini 里 game_version=,但 YuanShen.exe 不在)→ 判定 incomplete,不会去白下 224MB 安装包 |
| 启动通道自验证 | 用「靶子程序自己写标记文件」的方式验证(不靠数窗口):spawn ✅、cmd /c start ✅、explorer.exe file-uri ❌、rundll32 FileProtocolHandler ❌、Start-Process ❌(后三者在 DSH 沙箱内起不来;宿主里未必如此,但不作为主通道) |
| 真启动一次 | spawn 起真实 GUI 程序 → 拿到 pid、窗口出现、MainWindowTitle 正确;shell 通道 → cmd 退出码 0 |
| 注册表编码 | 中文 Windows 下 reg.exe 按 OEM 代码页输出:实测本机是 65001 而常见中文机是 936;统一 chcp 65001 后输出确定为 UTF-8 |
| 性能 | 探测快档 21s → 0.5s(砍掉 20 秒的 HKCU\Software\miHoYo\原神、把 12 次注册表查询合成 1 次、固定候选路径从 500+ 次 stat 改成几十次 readdir) |
| 环境变量脱敏 | 单测断言 *KEY* / *TOKEN* / DSH_* 不会传给游戏进程,PATH 保留 |
| 幂等 | 标记文件以「宿主 pid + 进程启动时刻」为键;patchReload: live 下热重载不会重复启动 |
| 宿主半侧集成冒烟 | npm run smoke:四条浏览器接线注册 ✅、token 注入且幂等 ✅、启动路由 4 种拒绝 ✅、GUI 触发→启动成功(拿到真实 pid)✅、第二次触发被幂等挡住 ✅、状态文件落盘 ✅、秒退识别为 early-exit ✅、目标不存在报 spawn-error 不崩 ✅ |
| 路径掩码(日志+界面+状态文件) | tests/privacy.test.mjs + 冒烟实测:宿主日志 / 状态 JSON / 网页面板 / 独立窗口 / DSH 配置卡 / 自检输出都只见 盘符:\…\末段;断言盘上没有用户名和中间目录;URL(http://127.0.0.1:3080)不被误伤 ✅ |
| 配置 v2 加密落盘 + v1 自动迁移 | 单测:gameExe/gamePath 不再以明文字段落盘(进 secrets,DPAPI 可用=dpapi 前缀密文,不可用=标注 plain);老 v1 明文配置(含 scanFoundExe/launcherPath/installDir 等冗余字段)打开即迁移、冗余字段清除、桌面遗留老文件删除(stateDir 为默认时)✅ |
| 启动器不落盘 | 代码走查:探测缓存 v2 只留 {found,registered,secrets(加密 exePath),flavor,source,checkedAt,scanDone},读旧缓存时 installDir/gameDir/launcherPath 一律丢弃;回退起启动器走 locateLauncherNear 现场推 ✅ |
| %TEMP% 残留清扫 | tests/privacy.test.mjs:造一个 5 分钟前的 dsh-genshin-launch-*.out 与一个新鲜的,跑一次 sweep——旧的删、新的(60s 内)不动 ✅ |
| DPAPI 真机 | 沙箱里 spawnSync powershell.exe EPERM → 按设计降级明文(round-trip 仍通,测试两种分支都覆盖);真机 DPAPI 加密路径由用户自行验证(本轮整改后首次在真机打开 DSH 时看 %LOCALAPPDATA%\dsh-genshin-launch\dsh-genshin-launch-config.json 的 encryption 字段应为 dpapi) |
目录结构
dsh-plugin-genshin-launch/
├── package.json # dsh.bundle.patch 声明,DSH 凭它识别为 profile 层
├── cordis.patch.yml # 挂载声明(insert 一行 genshin-launch)
├── lib/
│ ├── index.js # 宿主半侧:编排、分流、路由、index 注入、启动路由
│ ├── detect.js # 零配置探测阶梯 + 结构指纹复核 + 有界扫盘 + 启动器现探(不落盘)
│ ├── registry.js # 只读注册表:编码处理、解析、批量查询
│ ├── launch.js # 启动通道:spawn / shell、观察窗、进程轮询、环境变量脱敏
│ ├── download.js # 下载器:Range 续传、进度、大小校验(方案一)
│ ├── size-guard.js # 体积安全闸:224MB ± 50MB,越界整条拒绝(方案一)
│ ├── resolve.js # 链接解析:候选校验 + pcbackup 向上探测 + 缓存(方案一)
│ ├── exec.js # 子进程执行 + 文件式输出捕获(避开沙箱的管道限制)
│ ├── store.js # 配置持久化:v2 格式,路径进 DPAPI 加密 secrets,v1 明文自动迁移
│ ├── privacy.js # 隐私原语:maskPath / maskPathsInText / protect / unprotect / sweepTempFiles
│ ├── questions.js # 问答通道(扫盘同意、体积宽档确认——面板和独立窗口共用)
│ ├── window.js # 独立 WinForms 窗口的拉起 / 置顶 / 收尾
│ └── client.js # 浏览器半侧:右下角面板 + 「界面已打开」上报
├── client/
│ └── index.js # DSH 插件栏里的 React 配置卡
├── assets/
│ └── standalone-window.ps1 # 独立窗口的 WinForms 脚本(渲染掩码状态、不回填掩码路径)
├── tools/
│ └── selfcheck.mjs # 不依赖 DSH 的自检命令(默认掩码,--no-mask 看全路径)
└── tests/
├── size-guard.test.mjs
├── store.test.mjs # v2 加密格式、v1→v2 迁移、坏文件兜底
├── privacy.test.mjs # 掩码不泄露 / DPAPI round-trip 或降级 / 临时残留清理
├── detect.test.mjs
└── apply.smoke.mjs # 宿主半侧集成冒烟(用 stateDir 隔离到临时目录)
免责声明
本项目是 DSH 的第三方插件,与米哈游 / HoYoverse / DeepSeek 无任何关联。 它做两件事:零配置定位本机已安装的《原神》并按你的设置启动它;或在没装时把官方 CDN 上的公开安装包直链下载到你指定目录(下载不成则打开官方下载页)。 《原神》及相关名称、素材归米哈游所有;请遵守游戏官方的用户协议。使用本插件启动游戏所产生的任何后果(包括但不限于反作弊判定)由使用者自行承担。