Windows 游戏优化 + DLSS 帧生成管理(由 GameBoost v1.0.5 与 DLSSG-Tool v1.1.0 合并重构,现迭代至 v3.3.x)
一句话:一键把系统调到适合游戏的状态,并给 RTX 20/30 系游戏接上 NVIDIA 只给 40 系开的帧生成。
| 问题 | 本工具的答案 |
|---|---|
| 3A 游戏帧数低 | 电源/调度/GPU/网络/内存全方位优化 + DLSS 帧生成(3060 Ti 也能开) |
| 竞技 FPS 手感黏、延迟高 | 驱动配置自动化(低延迟=超高、电源=最高性能)+ 0.5ms 定时器(仅 FPS 档)+ 网络/网卡优化 |
| 二游/3A 着色器编译卡顿 | NVIDIA 着色器缓存=无限制 + 游戏期电源联动 |
| 黑屏/掉帧找不到原因 | nvlddmkm 崩溃取证、C 盘守护、网络哨兵、覆盖层规避 |
| 帧生成装了没用 | 运行诊断:日志 + 进程模块双证据,直接告诉你代理有没有真正激活 |
Fluxion/
├── src/
│ ├── Core.cs 逻辑层:配置、优化执行、监控看门狗、游戏联动、NVAPI、备份/还原
│ ├── Dlssg.cs 帧生成模块:游戏扫描、代理装卸、入口选择、日志诊断、参数、下载
│ ├── Ui.cs 界面层:简约浅色 UI(系统标题栏 + 侧栏导航 + 白色分区 + 原生控件)
│ └── app.manifest UAC 清单:requireAdministrator(安装版必需)
├── compile.ps1 csc 编译脚本(三文件 + icon + manifest)
├── rebuild.bat 一键:编译 → 停旧实例 → 部署到 <部署目录>(便携版)
├── make_installer.bat 一键:构建安装包 Setup.exe(需 Inno Setup 6)
├── installer/ Inno Setup 安装脚本(Fluxion.iss)
├── check.bat 静态预检(不依赖编译器,编译前先跑这个)
├── config.json 全部开关与参数(优化项分节 + dlssg 段)
├── tools/ 静态校验脚本(Python)
│ ├── static_check.py 语法合规/括号平衡/符号引用/重复成员/隐式转换/CS0136/CS0108
│ ├── member_check.py 自定义控件的成员访问(CS1061 风险,作用域感知 + 按基类自动推导)
│ ├── type_ref_check.py 静态类型成员引用(Theme./Native./Program./Dlssg.,CS0117 风险)
│ ├── layout_check.py 绝对坐标越界与兄弟控件相交(旧布局机制的兜底)
│ ├── orphan_check.py 孤儿控件与空分区(新布局机制的兜底)
│ └── iss_check.py 安装脚本校验(BOM/段名/引号转义/Source/Tasks/提权守卫)
├── legacy/ 重构前的旧源码备份(仅存档,不参与编译)
└── icon/icon.ico
分层原则:UI 只管画和点击,所有系统操作都在 Core/Dlssg 里;UI 通过 Program.ApplyAll() 这一类编排方法调用逻辑,不再像 v1.x 那样把 13 个优化调用散在窗体的点击处理器里。
双击 rebuild.bat
它会做四件事:编译 → 停掉正在运行的实例 → 部署到 <部署目录>\ → 提示完成(首次部署时同时复制 config.json)。
- 编译失败会在
compile_result.txt里留下完整 csc 报错,把这个文件发给助手即可定位。 - 启动需要管理员权限(要改注册表/电源/网卡)。编译产物带 UAC 清单(
src/app.manifest,requireAdministrator),由系统在进程创建时弹一次提权确认、快捷方式显示盾牌;代码里原有的自提升逻辑现在只作兜底(已提权则自动跳过)。 - 配置文件已存在时不会被覆盖,你的自定义设置会保留。
双击 check.bat
它不需要编译器,只做静态扫描,能提前发现绝大多数低级编译错误:
| 检查项 | 对应真实编译错误 |
|---|---|
C# 6+ 语法($"" 插值、?.、表达式体成员、nameof、using static) |
CS1026 / CS1525 |
| 括号 / 花括号 / 方括号平衡 | CS1513 / CS1022 |
跨文件符号引用(Program.X / Dlssg.X / Theme.X 是否存在) |
CS0117 / CS1061 |
| 同一类型内签名完全相同的重复成员(合法重载不报) | CS0102 / CS0111 |
new byte[long表达式] 这类隐式转换(长→整型) |
CS0266 |
| 自绘控件上的成员访问是否真的存在(作用域感知,避免同名局部变量误报) | CS1061 |
局部变量作用域冲突(外层变量 vs 嵌套块内同名变量 / foreach·for·using 头部变量重名) |
CS0136 |
自定义类成员与 WinForms 基类成员重名(遮蔽 Control.Right / Panel.Tag 等) |
CS0108 |
| 调用本项目自己的方法时实参个数不匹配 | CS1501 / CS1729 |
两个脚本的判定规则都做过反向测试(人为注入已知错误,确认全部命中;再对真实源码跑出 PASS),所以 PASS 是有意义的信号,不是空转。反向测试不只是"能抓到",还要零多余告警 —— 探针应恰好报出注入的那几条。
- 用
python tools/static_check.py src/python tools/member_check.py src/python tools/iss_check.py installer/Fluxion.iss .单独跑也行,退出码 0 = 通过。 python tools/syncheck.py= 编译冒烟(编成一个临时 library,只看编译器怎么说,不产也不替换任何产物)。 它同时跑一段「runner 收尾自检」:19 个run_*.py必须统一用tools/_probe_runner.py的finish(<探针进程>, verdict=True|False)收尾,且声明verdict=True的那些探针源码里必须有 「按 FAIL 返回非 0」的那一行。为什么值得单独盯:这些 runner 曾经无论探针红不红都退出 0 ("跑一遍全绿"其实是"跑一遍没看结果"),第一版补丁靠在模块全局里猜结果变量名 —— 谁改个 变量名就又失效了。现在收尾只有一份实现,且必须显式传参。- 注意:这是辅助手段,不能替代编译器。类型推断、重载决策、泛型约束等仍以编译器为准。
双击 make_installer.bat
产物:installer_out\Fluxion-Setup-<版本号>.exe(带命令行的静默打包可用
ISCC.exe /O<输出目录> installer\Fluxion.iss 直接跑,本机 ISCC 在 %LocalAppData%\Programs\Inno Setup 6\)。
前置:先跑过一次 rebuild.bat(安装包直接用编译好的 Fluxion.exe)。机器上没有 Inno Setup 时,脚本会打印安装指引并询问是否用 winget 自动装(winget install --id JRSoftware.InnoSetup -e),也可以自己去 https://jrsoftware.org/isdl.php 下载。
安装包行为:
| 项 | 行为 |
|---|---|
| 安装位置 | C:\Program Files\Fluxion(64 位,安装时提权)。建议保持默认,别指到 rebuild.bat 的部署目录(见下方排错) |
| 快捷方式 | 开始菜单 +「创建桌面快捷方式」可选任务 |
| 开机自启 | 可选任务 → 建提权计划任务(schtasks /SC ONLOGON /RL HIGHEST),不在每次登录弹 UAC;与应用内「开机自启」开关共用同一任务名 |
| 数据目录 | 安装时创建 C:\ProgramData\Fluxion\ 并放入 config.json(已存在则不覆盖) |
| 卸载 | 控制面板/「应用」里可见;配置、日志、备份不会被删除,卸载完成会提示路径 |
| 升级 | AppId 固定,再次运行新版本安装包即识别为升级覆盖 |
| 运行中安装 | 靠互斥体 Fluxion_SingleInstance 检测到程序在跑,会先要求关闭 |
| 便携版 | 安装版 | |
|---|---|---|
| 判定条件 | exe 同目录有 config.json |
没有,且 %ProgramData%\Fluxion 存在 |
| 数据位置 | exe 同目录 | %ProgramData%\Fluxion\(config / logs / backup / dlssg) |
| 侧栏底部 | 显示「便携版」 | 显示「安装版」 |
之所以要分流:Program Files 是只读的程序目录。把备份和日志写在那里,卸载会被一并删除、升级也可能被覆盖 —— 而备份正是用来还原系统的,丢了就没意义了。
Fluxion.exe 带 requireAdministrator 清单,而 Inno Setup 的 postinstall 运行步骤故意以原用户(未提权)身份执行 —— 直接 CreateProcess 一个要求提权的 exe 会被系统拒绝,740 就是 ERROR_ELEVATION_REQUIRED。修法:给该 [Run] 条目加 shellexec 标志,改走 ShellExecuteEx,由系统接管 UAC 提示。
同一轮复查还修掉两个自己埋的隐患:
| 问题 | 原写法 | 现在 |
|---|---|---|
| 每次登录弹 UAC | 写注册表 Run 键(由 shell 启动,命中提权清单 → UAC) | 建提权计划任务,无提示;名字与应用内开关一致 |
| 卸载可能删掉真实备份 | [UninstallDelete] 删 {app}\logs、{app}\backup |
整段删除(万一安装目录被指到便携版目录,那段会连真实备份一起删) |
tools/iss_check.py 会在出包前把这些点全查一遍(BOM / 行尾 / 段名 / 引号转义 / 续行 / [Files] Source 存在性 / Tasks 引用 / AppMutex 一致性 / postinstall 提权守卫),并把转义后的真实命令行打印出来核对:
python tools/iss_check.py installer/Fluxion.iss .
⚠️ 不要把安装目录改成rebuild.bat的部署目录(<部署目录>)。那是便携版/开发的输出目录:装进去会得到「已安装 + 便携」混合状态 —— 目录里同时有unins000.exe和便携版config.json,程序会按便携版模式就地读写,而下次rebuild.bat部署又会覆盖已安装的 exe。安装包保持默认的C:\Program Files\Fluxion即可。
| 模块 | 优化项 | 依据 |
|---|---|---|
| 电源 | 卓越性能计划、处理器 100%、关 USB 选择性暂停/PCIe ASPM/睡眠休眠硬盘超时 | 消除低负载降频与链路节能毛刺 |
| 电源 | 游戏期临时电源联动(进游戏切档、退出还原) | 办公零影响 |
| 调度 | Win32PrioritySeparation=38(短量子+前台增强) | 前台游戏输入响应 |
| 调度 | 异类线程调度策略(混合架构首选 P 核) | Intel Thread Director 官方做法(v2.0 新增,替代 v1.x 的硬绑) |
| GPU | 关闭 GameDVR、Windows 游戏模式、HAGS 开关 | 消除录制开销 / 前台优先 / 降帧时间波动 |
| GPU | NVAPI 驱动配置自动化(竞技档 / 3A 档双档) | 等价 NVIDIA 面板手动设置,全自动 |
| 网络 | 关 Nagle、关流量节流、SystemResponsiveness=10、网卡节能全关 | 小包即时发送 + 前台优先 |
| 内存 | DisablePagingExecutive(内核不换页) | 减少缺页卡顿 |
| 服务 | SysMain 禁用(SSD 场景) | 减少后台 IO 抖动 |
| 输入 | 关闭鼠标加速 | 读系统鼠标的游戏更跟手 |
| 后台 | 游戏加速包:挂起后台进程 + 内存整理 + 暂停 Windows 更新下载 | 参考成熟产品做法,退出完整恢复 |
| 定时器 | 游戏期 0.5ms 定时器(仅 FPS 档,退出还原) | 降低输入延迟 |
| 安全 | Defender 游戏进程排除(默认关,安全权衡项) | 避免实时扫描 IO 尖峰 |
| 桌面 | 关拖拽实时渲染 / 透明 / 动画 | DWM 合成开销 |
| 监控 | nvlddmkm 崩溃取证、C 盘守护、网络哨兵、NVIDIA 覆盖层规避 | 故障定位 |
检测但不修改:内核隔离/VBS 状态(调研结论:收益不确定且明显降低安全性,交由你自行决定)。
一键优化给的是「程序认为的最优值」,但很多项的最优值本来就因人而异(着色器缓存上限、DLSS 强制预设、 量子长度……)。所以 v3.6.0 起,凡是「能给出具体档位」的项,档位全部摊开让你自己选。
三个入口(都在「性能优化」页):
| 入口 | 位置 | 用途 |
|---|---|---|
| 双击带 ⚙ 的行 | 优化项明细表 | 直接跳到该项的档位选择 |
| 「调整选中项」 | 表格上方按钮 | 同上,键盘 / 鼠标都顺手 |
| 「取值细调…」 | 表格上方按钮 /「自定义项」对话框 | 完整清单,18 项一次看完 |
体检表总行数随环境变化(驱动层要能读到 nvdrsdb、异类策略只在混合架构 CPU 上出现; 本机是 51 行)。其中 19 行带 ⚙(可调),其余是只读核验 —— 表下方直接写明这个区分。
18 个可调项:着色器缓存开关 / 缓存大小上限(12 档:0、128MB、256MB、512MB、1GB、4GB、 5GB、8GB、10GB、16GB、100GB、无限制)/ DLSS 模型覆盖 / 强制预设字母 / 预设档 / 竞技档·预渲染帧数 / 竞技档·电源管理 / 竞技档·垂直同步 / 竞技档·纹理过滤质量 / 3A·MMO·二游档取值 / 后台帧率上限 / HAGS / Win32PrioritySeparation / 处理器最小状态 / 处理器最大状态 / 前台响应优先级 / Nagle / 网络流量节流。 另有「HAGS × 竞技游戏(A/B 建议)」一行也带 ⚙ —— 它与「硬件加速GPU计划(HAGS)」共用同一个旋钮。
默认值 = 改造前的硬编码值,所以升级后行为零变化 —— 只有你主动改了才会变。
哪些坚决不给旋钮:HPET 强制、GPU 中断绑核、MSI 强制转换、rBAR 全局强开、异类策略。 理由是多来源明确警告:这类项改错的代价是设备从系统里消失或系统起不来。 「给用户权限」不等于「给用户自毁按钮」—— 只读核验的价值是让你知道现状,不是让你去动它。
nvdrsdb 后重启游戏才生效;HAGS 与量子长度需重启系统;
把某项改回默认不会自动撤销已写入系统的值(例如 Nagle 已写进网卡)—— 整体回退用「恢复备份」。
① 「HAGS × 竞技游戏(A/B 建议)」这一行为什么没反应、为什么顶着红徽章?
它是建议,不是缺陷:只在「RTX 30/20 系 + HAGS 已开 + 有竞技档游戏」时出现,意思是「现状已是推荐值,但值得你自己 A/B 验一次」。v3.6.0 之前它有两个毛病:状态写的是 🟡,而界面只认 ✅/⚠️ 两种开头 —— 开头不是这两个的一律渲染成红色「需处理」,于是这一行里写着「HAGS 已开」、徽章却在报错;而且它没挂可调键,双击没有任何反应。
现在状态分成四档,并且这一行也挂上了 hags.enable(看到「可以 A/B」就能当场切,切完要重启系统):
| 徽章 | 含义 |
|---|---|
| 已生效(绿) | 当前值与优化目标一致 |
| 未生效(橙) | 该生效却没生效(系统更新 / 驱动重置) |
| 待确认(灰) | 不是缺陷:可选 / 不适用 / 读不到(DPC 计数器不可用、HAGS 的 A/B 建议……) |
| 需处理(红) | 读取失败或需要管理员权限 |
② 滚动时「有的色块更白、更割裂」
三个原因叠在一起,都已修掉:
| 原因 | 修法 |
|---|---|
行底色是逐格铺的(一格一个 DrawSubItem),格与格之间的 1px 接缝、最右列右侧的空档没人画 |
改到 DrawItem 整行铺一次 |
斑马纹是 #FFFFFF / #F8FAFC(只差 3%):看不出「这是交替条纹」,只看得出「这些行颜色不一样」 |
去掉斑马纹,所有行同色 + 底部一条极浅分隔线 |
ListView 是原生控件,Control.DoubleBuffered 对它无效 —— 滚动时先擦成白底再逐行重绘,中间那一帧就是一片更白 |
打原生扩展样式 LVS_EX_DOUBLEBUFFER(探针读回确认:扩展样式 0x00010020) |
顺带修掉一个自 3.x 就存在的隐性问题:自绘里判断「是否选中」用的是 e.State / e.ItemState,而实测在部分绘制路径下它会把 Selected 位给到每一行(tools/ui_snapshot.py light lst 1 可复现:控件里没有任何一行被选中,绘制回调里的 Selected 位却行行都有)—— 按它画,整个列表会被涂成「选中态」底色并给每行加一条绿色强调条,看起来就是「这些行为什么跟别的不一样」。现在改成读行自己的 e.Item.Selected。
NVIDIA 官方帧生成只给 40 系(SM90)编译了可执行内核;20/30 系(SM86/SM75)运行时里没有对应 cubin。本模块接入开源项目 dlssg_for_sm86:以 DLL 代理方式接管游戏对 nvngx_dlssg.dll 的加载请求,换成补齐 SM86/SM75 内核的运行时(AI 模型仍是 NVIDIA 原厂)。
- 设置页确认下载代理(国内需 Clash/FlClash 的 7890 端口),点「下载运行时」
- 帧生成页点「扫描游戏」,列表会标出每个游戏是否集成 DLSS 帧生成(
nvngx_dlssg.dll/sl.dlss_g.dll)以及是否自带 FSR3 - 点选游戏 → 「开启选中」;不想要了「关闭选中」完全还原
- 进游戏 → 画面设置 → 帧生成 → 选 DLSS Frame Generation → 关垂直同步、帧率上限设无限
| 参数 | 取值 | 建议 |
|---|---|---|
| 架构 Router | SM86(30 系)/ SM75(20 系) | 按显卡选 |
| 内核类型 | PTX(驱动 JIT,通用)/ Auto / Cubin | 默认 PTX,异常再试 Auto |
| 光流精度 | 0 精确 / 1 近似 | 画质优先 0 |
| 最大生成帧 | 1/2/3 | 实测这是上限,实际倍率由游戏请求决定;显存占用随输出分辨率而非倍率变化(2.10.2 修正) |
| 日志级别 | 0~3 | 排错调 2~3,日志在游戏目录 dlssg_sm86\logs\*.jsonl |
- Cyberpunk 2077 (2.31) 必须用 winmm.dll 入口:该游戏导入
version.dll但运行中从不调用其函数 → 代理的延迟初始化永不触发,表现为「DLL 在进程里、零日志、帧生成无效且掉帧」。换 winmm 后立即激活,实测基准 135 → 190 帧。本模块内置该映射并自动处理。 - 判定代理是否真的在工作,唯一可靠依据是日志目录出现
runtime_redirect/feature_created/evaluate事件 —— 「运行诊断」按钮会读日志 + 查进程模块,直接给结论。 - 代理加载了但没日志 → 点「换入口重试」换一个入口 DLL(游戏只加载不调用某个入口时,代理永不初始化);日志出现但没补帧 → 等游戏内开启帧生成。
- ⚠ 本模块不是把 DLSS 帧生成转成 FSR3:代理装上的是 NVIDIA 原厂 DLSS-G 运行时 + 自研 SM86/SM75 内核。若游戏内只出现「FSR 帧生成」,那是代理没被激活(见上一条),不是它本来就只能给 FSR。
- 带内核反作弊的游戏(绝区零 / 鸣潮 / 终末地 等)自动改用
d3d12.dll入口(v2.1.0):这类反作弊会按【文件名】拦掉version.dll/winmm.dll等常规入口(上游 issue #111),而d3d12.dll是 DX12 游戏必须加载的系统库,拦不掉。工具会落三件套(代理 + 系统原件 + 载体),框架细节见第 ⑮ 节。可在帧生成页用「反作弊游戏自动改用 d3d12 入口」开关关掉。 - 反作弊若把代理改名隔离(形如
version.dll.1271877294),文件不再被加载却白占 15 MB —— 点「清理残留」回收(「关闭选中」也会一并清)。 - 扫描识别到但被忽略清单挡住的游戏会灰显在列表里,选中点「开启选中」即可恢复收录(不会再静默消失)。
- 必须开启 HAGS(设置→系统→显示→图形→硬件加速 GPU 计划),本工具会检测并提示
- 基础帧低于 40 不建议开:会明显发糊、延迟增大;先用 DLSS 超分把基础帧拉到 60 再开
- 竞技射击不要开(CS2/Valorant/三角洲):帧生成引入额外延迟,得不偿失 —— 这些游戏用优化模块即可
- 8GB 显存:1080p 约需 320MB、1440p 约 490MB 显存余量(占用随输出分辨率变化,与倍率基本无关)
- 游戏更新覆盖代理文件后需要重新开启;代理只往游戏目录放 1~2 个文件(
d3d12入口为 3 个 + 1 个 ini),删除即还原,也可用 Steam「验证文件完整性」
代理包每发一版,"这一版是什么"这件事在本工具里分成三层,缺一层就会出现 "代码说 0.3.5、磁盘还是 0.3.2" 而无人发现:
| 层 | 位置 | 谁会读它 |
|---|---|---|
| 判据(体积档 / 入口名单 / 签名白名单 / 版本结论) | %ProgramData%\Fluxion\catalog.json |
Pack.Classify、Dlssg030.IsProxySize/CodeOf、ProxySign.Of、Plan.OwnerOf/EntryNames |
| 磁盘事实(资源包里那份到底多大、是哪一版) | 量出来的,不存 | 帧生成页「运行时状态」第三行;Dlssg030.PackActual() |
| 导入账本(哪来的、什么时候、每个文件体积 + sha + 指纹) | %ProgramData%\Fluxion\dlssg030-pack\pack.json |
只由「拖入导入」写;PackActual() 读它比对 |
- 判据外置:
catalog.json缺失或读不动时一律回落代码里的内置默认,并在启动日志写一行判据来源:…—— 读坏了静默用默认值是最难查的那类错,所以必须留痕。 这份文件没有界面入口(它属于开发期手段,不该占用户界面):要改就照Catalog.DefaultJson()输出的形状手写一份,存盘即生效、不用重新编译;删掉它就回到内置默认。 字段:proxy.ver/proxy.bands[](体积→哪一版,闭区间)/proxy.windows[](是不是本方案, 开区间)/proxy.legacy、proxy.sourceSize(旧版 0.2.x 的两个窗口)/proxy.entries[]/proxy.signs(作者与 NVIDIA 两张证书的指纹)/knowledge[](只在某些版本成立的上游实测结论)。 给新版本加档时 bands 与 windows 要一起加:IsProxySize只看 windows, 只加细档会出现"代号认得、体积不认"。 - 知识条目集中在
knowledge[]:UI 里那句"绝区零要不要伪装"以前是按版本手改文案, 同一个结论在功能缺口与路线图.md里还有几处。现在由Catalog.Knowledge(id)按当前proxy.ver挑那一条成立的,挑不出来就退回中性说法(宁可少说一句,不要说错一句)。 其中一条就是升级路径:别按版本号顺序升级 —— 0.3.3 让 NVIDIA 自家 NGX 模型也吃到 架构改写导致 GPU 挂起(上游 #535/#538/#540/#542),0.3.4 才修;可升级路径只有 0.3.2 或 0.3.5+。 - 入口巡检:帧生成页「停放遗留项」旁边那行会说清"这个目录里有几套代理并存"。
两代代理同时在场 = 两套帧生成抢同一个入口(插件打架那一类故障),以前只有点部署才会顺带处理,
平时看不见。巡检是只读的;停放只把文件改名成
<原名>.parked.<方案>,不删文件。 - 备份与回收:部署 / 换包 / 卸载会往
dlssg030-pack\_backup、xess-pack\_backup、xess-pack\_removed里堆东西(2026-09-21 实测 1.48 GB / 15 项)。设置页「备份与回收」 按归属统计占用,回收一律送回收站,并且每个归属(整包一份 / 每个游戏一份)里 最新那一份永久保留 —— 卸载和换方案回滚要读的就是它。- 「回收范围」下拉的每一项后面会回填当前统计出的条数与体积。这不是装饰:默认档是 30 天, 而刚换完包留下的备份通常只有几天 —— 不回填的话用户看到"点了没反应",只会以为功能坏了。 真要清那 1 GB 得选「7 天前」或「不限时长」(保留策略保护的那 484 MB 仍然不动)。
- 两个不可逆感最强的确认框(「送回收站」「停放遗留代理」)默认键是取消, 手快连按两下不会把东西清掉;两个动作本身都可逆(回收站可还原 / 停放只是改名)。
- 刻意没做的事:日志目录(
logs\,本机 931 个文件 / 1.3 MB)不做回收入口 —— 为 1.3 MB 多一个按钮 + 一套接口不值得,这是"别把工具做冗余"的一条。
dlssg\source\只放旧版 0.2.x 的下载源件(体积 15.5~15.8 MB,配套altnative\)。 0.3.x 走dlssg030-pack\{common,alts},不读这个目录。SourceReady()现在除了File.Exists还校验体积:源位上躺着 0.3.x 的件时不再误报"运行时已就绪", 并且界面上会写明为什么不算。
合并:DLSSG-Tool 全部能力(扫描/装卸/入口选择/日志诊断/参数/下载)以原生 C# 模块并入,不再是第二个程序。
界面:完全重做 —— 系统标题栏 + 侧栏导航(仪表盘/性能优化/帧生成/实时监控/设置)+ 白色分区 + 纵向滚动,配色为浅色极简(底 #F3F5F7、卡片白、1px 描边 #E2E5E9、主色 #0969DA)。
控件全部用系统原生:浅色主题下原生外观本来就是正确外观,不需要再靠自绘去对齐色板 —— 这也正是深色版反复出现"色准不一致"的根源(复选框、下拉框、滚动条、提示框在深色下永远是浅色皮肤)。
详见 7.1 ⑦。
纠错(依据官方文档/白皮书):
- P 核硬绑默认关闭 → 改用「异类线程调度策略」。Intel Thread Director 白皮书明确不建议混合架构手动钉核,硬绑会破坏动态调度决策。保留开关仅供对比测试。
- 一键优化编排下沉到逻辑层(
Program.ApplyAll),不再散落在 UI 点击处理器里;备份序列与执行序列绑定在一处,避免以后加项漏备份。 - 字体 GDI 句柄缓存:自绘控件每帧取字体改为缓存复用,避免长时间运行后句柄耗尽。
新增:异类线程调度策略、内核隔离/VBS 状态检测、帧生成运行时与接入数状态项、帧生成运行诊断(日志+进程双证据)、配置写回支持字符串/整数型。
精简:移除了窗体上的 CLI 按钮(体检/监控改为界面内原生展示,不再弹 PowerShell 窗口)。
静态审查中当场修掉的 2 个真实编译错误(都是同类:long 不能隐式转 int 做数组长度,会报 CS0266):
Dlssg.cs读超长日志(>4MB 只读尾部)时new byte[fs.Length - fs.Position]→ 改为先int tail = (int)(...)再建数组Ui.cs日志跟随(FollowLog)里new byte[len - lastLogLen]→ 同样改为先截断为int
首次真机编译后修掉的 3 个问题(csc 实际报出,说明静态审查有盲区,已补进 tools/ 与 check.bat):
| 严重性 | 问题 | 修法 |
|---|---|---|
| 🔴 CS0136 中断构建 | Core.cs 里 diskGuard 段的 dg 在 if 子作用域中,之后 dlssg 段又在方法体里声明 var dg → 外层声明会改变内层 dg 的含义 |
dlssg 段改名 dlssgSec(只动新增代码) |
| 🟡 CS0108 | StatBar.Right 遮蔽 Control.Right(右边缘 X 坐标),基类语义被静默改变 |
改名 RightText |
| 🟡 CS0108 | RowItem.Tag 遮蔽 Panel.Tag(object 通用载荷) |
改名 TagText(自定义载荷走已有的 Data 字段) |
- 所有注册表/电源/网卡修改写入前自动备份到
backup\ - 「恢复备份」= 还原到优化前;「恢复默认」= 恢复 Windows 出厂值(两者不同)
- 帧生成:
dlssg\state.json记录安装信息,卸载时用「入口名 + 体积 + SHA256」三重校验后才删除,不会误删别人的文件;被占用的同名文件会先备份再替换
现象:启动后左栏导航、右侧 CPU/内存/GPU 进度条、若干卡片出现白底方块(WinForms 的绘制失败标记)。
根因:Theme.F()/FB()/Mono() 返回的是全局共享的缓存 Font 实例(缓存本身是为了不泄漏 GDI 句柄),
但首版有 10 处写成 using (var f = Theme.FB(10f)) { … DrawString … } —— using 结束会 Dispose 掉这个共享字体。
此后所有同字号的绘制都在已销毁的 GDI 句柄上操作,GDI+ 返回 InvalidParameter,抛出 ArgumentException: 参数无效。;
WinForms 对 UserPaint 自绘控件绘制失败的兜底,是把该控件区域填成系统色并打叉。
证据:程序自己的日志每次启动都有恰好 14 条 UNCAUGHT_THREAD: ArgumentException: 参数无效。;
而同时刻旧版 v1.0.5 的日志里一条都没有 —— 直接锁定是界面层新引入的,与此前怀疑的"显示管线伪影"无关。
修法:10 处全部改为普通局部变量(缓存字体永不 Dispose);Theme 字体缓存处加了醒目警告注释;
tools/static_check.py 新增 CACHED-FONT-USING 规则兜底(已做反向测试),以后再犯会在编译前被拦下。
| 影响面 | 说明 |
|---|---|
| 10 处 | Card 卡片标题、NavBtn 导航图标、StatBar 标题与数值、Chart 标题、RowItem 徽标/副标题/右侧标签、自绘标题栏主副标题 |
| 连带受害者 | 所有 Font = Theme.F(8.5f) 等被赋值过的 Label / ComboBox / TextBox(字体实例被别人的 using 销毁) |
不是本程序去启动它,而是 v1.0.5 自己的看门狗还在:
| 环节 | 事实 |
|---|---|
| 启动项 | %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\GameBoostGuard.vbs(登录时静默拉起 Guard.ps1) |
| 判据 | 每 30 秒检查一次「进程名 = GameBoost」,不在就 Start-Process <旧版部署目录>\GameBoost.exe --minimized`` |
| 实况 | 19:07:53 旧版被退出 → 19:07:58 / 19:08:29 / 19:08:59 被看门狗连拉 3 次 |
处置(已做,全部可逆):<旧版部署目录>\guard.config.json 的 keepAlive.enable 改为 false
(原文件备份为 guard.config.json.bak-20260911);启动项先改名 GameBoostGuard.vbs.disabled,
2026-09-12 又从启动文件夹移出至 backup\GameBoostGuard.vbs.disabled(.disabled 扩展名会导致
Windows 登录时每次弹「选择应用」对话框,故必须移走,未删除可随时放回)。
v2.0 自带同等的看门狗模块(黑屏取证 / 磁盘守护 / 网络哨兵 / 覆盖层规避),关掉旧版不丢能力。
⚠️ 那个已经在运行的看门狗进程需要你自己结束一次(它只在启动时读配置):重启电脑即可; 或在任务管理器里结束那个隐藏的脚本宿主进程。重启后旧版不会自启(其「开机自启」已在 19:08 从旧版界面里取消)。
rebuild.bat 原来无条件把 config.json 复制到部署目录。若该目录正是安装版
(存在 unins000.exe,例如你现在的 <部署目录>),这一步会让程序下次判定为「便携版」,
把配置/日志/备份从 %ProgramData% 挪进程序目录。已加判断:检测到 unins000.exe 就跳过复制。
反馈截图的现象是:整屏糊成一坨黑、输入框像挖了个洞、复选框是系统白方块。 根因不是「配色不好看」,而是层次丢失 —— 旧色板里 窗口底(13,17,23) / 侧栏(17,22,30) / 卡片(22,27,34) 三层亮度只差 4~5 级,等于没有分层;描边 (33,38,45) 也几乎与卡片同色,圆角轮廓看不见 = 卡片"没有形状"。
| 现象 | 根因 | 修法 |
|---|---|---|
| 整屏一坨黑、卡片没轮廓 | 三层背景只差 4~5 级;描边与卡片几乎同色 | 重做色板:底 #090C11 < 侧栏 #0E1219 < 卡片 #181E27,描边提到 #2E3846;卡片加顶部 1px 内高光 |
| 输入框像"黑洞" | 原生 TextBox 写死纯黑底 (11,15,20) + FixedSingle 白边 |
新增 FlatInput:Panel 外壳自绘圆角凹槽 + 无边框 TextBox,聚焦时描边转主色 |
| 复选框是系统白方块 | 原生 CheckBox 在深色下仍按系统皮肤绘制 |
新增 FlatCheck:整块自绘,14px 圆角框 + 手绘对勾,选中态主色实心 |
| 导航图标高低不齐 | ◈ ⚡ ◉ ▤ ⚙ 在 Microsoft YaHei UI 里缺字,会静默 fallback 到 Segoe UI Symbol,字号/基线/笔画全不同 |
改为 16×16 几何自绘图标(NavBtn.Icon16),统一 1.5px 圆头笔画 |
| 实心按钮像"发光虚边" | Primary 描边 (88,166,255) 比填充 (31,111,235) 亮太多 | 实心按钮改上下微渐变 + 同色系描边,顶部略亮、底部略暗 |
| 正文偏灰、状态栏字小 | TextDim(139,148,158) 在卡片上对比度约 4.6:1 | 提到 (150,161,175) ≈ 5.7:1;状态栏 8.5 → 9pt |
上一轮遗留的「ComboBox 仍是系统方角」已在 ⑤ 中解决(
FlatCombo)。目前仍为系统外观的只剩: 托盘右键菜单(ContextMenuStrip,需要自定义ToolStripRenderer)与MessageBox弹窗 —— 都是系统级控件, 换肤成本高于观感收益,暂不做。
工具同步:
tools/static_check.py的 CS0108 规则增加override豁免 —— 覆写基类 virtual 成员是合法行为, 不该按"遮蔽"报错(FlatInput.Text覆写Panel.Text属此类)。已用「注入真实遮蔽 → 应报错」反向验证规则未被削弱。
反馈截图:标题栏出现 Fluxion优化 这样的重影、各页文字压在一起 / 被裁掉半句、下拉框里有发白的方块。
根因不是坐标写错,而是 进程 DPI 感知与硬编码像素布局之间的矛盾:
Core.Main里调了Native.SetProcessDPIAware()(为了字清晰),于是 GDI+ 按真实 DPI 渲染字体;- 而界面所有坐标/尺寸都是硬编码像素(窗体
1160x764、卡片 932 宽、MakeLabel写死200x20…)。
在 125% 缩放的屏幕上,字大了 25%、容器一点没变 → 文字溢出色块、互相压字、被硬裁半句。
标题栏副标题写死 x=158,主标题变宽后正好压上去,就是那团重影。
| 现象 | 根因 | 修法 |
|---|---|---|
标题栏 Fluxion优化 重影 |
副标题 x 写死 158px,主标题随 DPI 变宽后压上去 | 副标题位置改成"主标题实测宽度 + 间距"(TextRenderer.MeasureText) |
| 文字压在一起 / 各页参差不齐 | 字体按 DPI 放大,控件尺寸不变 | 新增 Theme.Scale(=实际DPI/96)+ Theme.Fit(this):整棵控件树构建完成后只放大一次;Theme.S() 用于自绘偏移量,Theme.TextTop() 用 Font.Height 做垂直居中 |
GitHub 直连通常被墙,可走本地代 半句消失 |
MakeLabel 写死 200×20,且 20px 高装不下 125% 的字 |
改为按字体实测宽度定尺寸(MeasureLabel),并关掉 UseMnemonic |
| 下拉框里有发白方块 / 方角 | ComboBox 的边框、按钮、箭头由系统主题绘制,深色下必然亮灰 | 新增 FlatCombo(保留 ComboBox 类型,WndProc 拦 WM_PAINT 后整块重画,调用点零改动);下拉项走 OwnerDraw |
| 复选框文字忽明忽暗 | 旧逻辑 on ? Text : ForeColor —— 勾选态把标签也点亮 |
标签固定 TextDim(hover 才提亮),状态只由方框表达 |
| 字边发虚、有色偏 | 深色底 + ClearType 亚像素抗锯齿 → 笔画边缘红蓝描边 | 所有自绘入口统一 Theme.Prep(g) → 灰度抗锯齿 AntiAliasGridFit |
顺手修掉的两个真实布局缺陷(这次是静态查出来的,肉眼不一定注意到):
- 「帧生成」页的 开启选中 / 关闭选中 / 运行诊断 三个按钮和"已选:…"提示,y 坐标(316/322)超出了 所在卡片高度(280),被父容器裁剪 → 等于根本看不见;同页参数卡片的标签压在输入框上 4~5px。
- 「仪表盘」页
GPU 温度状态条超出卡片 4px 被裁;多张卡片的说明文字框右边缘超出卡片内边距。
DPI 自助开关:若自动缩放不合意,在数据目录(
%ProgramData%\Fluxion\或便携版 exe 同目录) 放一个ui.scale文件,内容写1.0/1.25即可强制指定倍率。 启动日志会打印界面缩放 1.25x(120 DPI),窗口 1450x955,可用来确认是否按预期生效。
工具同步(本轮新增/加强 2 个校验器,因为编译只能在用户本机跑):
- 新增
tools/layout_check.py:纯文本分析绝对坐标布局,检查「子控件是否逃出父卡片」与 「同父兄弟是否相交」。它能精确复现上面那个"按钮被裁掉"的缺陷(注入回归 4 处命中)。- 加强
tools/member_check.py:原来OUR_TYPES是手写清单,新加的FlatCombo/FlatCheck/FlatInput没登记 → 这三个类的调用点全部绕过校验。改成按基类自动推导(含继承闭包),校验覆盖从 275 处涨到 363 处; 反向验证:注入cbFgAutoEntry.Checkd/cbScene.SelectedIndx均被精确命中。check.bat从 3 步扩到 4 步(syntax → member → layout → installer)。
报错原文(compile_result.txt,用户机器上跑出来的):
COMPILE_FAIL: csc failed: src\Ui.cs(547,21): error CS0136:
不能在此范围内声明名为"box"的局部变量,因为这样会使"box"具有不同的含义,
而它已在"父级或当前"范围中表示其他内容了
根因:FlatCheck.OnPaint 里第 506 行已经有 var box = new Rectangle(0, by, bs, bs);(复选框方框),
第 547 行在 using (var b = …) { … } 块里又写了 var box = new RectangleF(…)(标签文字框)。
C# 里局部变量的声明空间是整个所在块,嵌套块内不允许出现同名局部变量 —— 与谁先谁后无关。
修法:内层改名为 textBox。
为什么校验器没拦住(这是本条的真正价值):static_check.py 里 CS0136 规则曾经存在且能跑,
但它给"两个同名声明所在块互为嵌套"额外加了一个前提 —— 外层声明必须晚于内层声明。
而实际发生的是最常见的形态:外层先声明、内层后声明,于是这条规则在真实案例上给出了 PASS。
已删除该顺序条件(嵌套关系本身就足够判定),并把报错位置改指向内层那一处,
使行号与编译器一致(编译器报 547,校验器现在也报同一处)。
顺带补上同一漏洞的另一半:局部变量与方法参数同名(void M(int x) { int x = 1; },同样是 CS0136),
以前完全没检查。两条规则都做了注入回归验证,且真实源码零误报。
还有一个会让人白跑一趟的缺陷:rebuild.bat 原来靠 if not exist Fluxion.exe 判断成败 ——
但上一次编译出来的 exe 还在,所以编译失败时它会打印 OK 并把旧 exe 复制过去,
用户看到的是"编译成功、程序没变化"。现已改为:编译前删掉旧报告 → 看 compile.ps1 退出码 →
再从 compile_result.txt 里确认出现 COMPILE_OK,任一不满足就打印真实编译器输出并中止。
- 新增
tools/type_ref_check.py:静态类型的Type.Member引用校验。之前只校验Program / Dlssg / Config,本轮往Theme/Native里加了不少成员(S/SF/Prep/Fit/TextTop/SFLeftPublic…), 这些引用全部绕过校验(这正是"编译器报 CS0117 之前完全没提示"的盲区)。现覆盖 5 个类型。- 修正
type_ref_check.py自身的剥离器 bug:第一版用正则先删注释再删字符串,于是字符串里的///*被当成真注释,一路吞掉后面的代码 ——Program/Dlssg两个类型直接被吞成"未找到"(假阴性)。 已改为单遍扫描、字符串优先、等长空白替换(与static_check.py的实现等价)。check.bat从 4 步扩到 5 步:syntax → member → type-ref → layout → installer。
为什么要换:深色版的错位与色准问题修了三轮仍有残留,根因不在"哪个坐标写错了",而在路线本身:
| 深色路线的固有代价 | 后果 |
|---|---|
| 系统原生控件(复选框、下拉框、滚动条、消息框、右键菜单)在深色下永远是浅色皮肤 | 只能一个个自绘去盖;盖不干净 = "色准不一致",且每加一个自绘控件就多一处错位风险 |
界面全部硬编码像素 + 构建完成后整体缩放一次(Theme.Fit) |
两套坐标系并存:字号按真实 DPI 放大、容器按倍率缩放,任何"漏换算"的地方都表现为文字压字/被裁 |
| 自绘标题栏 | 拖动、圆角 Region、最小化按钮三处都要自己实现,且窗口比工作区大时还要额外收口 |
换成了什么:
- 浅色极简配色:底
#F3F5F7、白色分区 + 1px 描边#E2E5E9、正文#1F2328、次级#57606A、一处主色#0969DA。 层级靠"白卡浮在浅灰底上"表达,不靠明暗渐变;文字对比度 7:1 ~ 14:1。 - 控件全部用系统原生:
Label / ComboBox / TextBox / CheckBox / Button / ListView / RichTextBox / FlowLayoutPanel / TableLayoutPanel。 自绘只剩三个小组件(扁平按钮、细进度条、迷你折线),且每个都只在自己边界内绘制。 列表也从"自绘行"换成原生ListView(列宽按 DPI 换算),少掉一大块绘制代码。 - 纵向位置全部由实测高度推导(新
Sec分区容器): 用法var s = new Sec("标题"); s.Row("标签", 控件); s.Body("说明"); p.Add(s);—— 分行只有四种(标签+控件 / 说明文字 / 整行控件 / 按钮行),没有一个写死的 y 坐标; 标签与控件在各自行内垂直居中,所以"字压在框上"这类问题在结构上不可能发生。 说明文字的高度用TextRenderer.MeasureText(..., WordBreak)现量,与 Label 实际渲染同一套 GDI 度量。 - 窗口骨架用
TableLayoutPanel显式行列(侧栏 / 内容 / 底栏),不再依赖 Dock 的 z-order 规则。 - 系统标题栏,不做自绘标题栏;时钟移到右下状态栏(由 1 秒定时器刷新)。
- DPI 只换算一次:固定像素尺寸(行高、间距、列宽、列表高度)在创建时走
Theme.S(); 仍然支持数据目录下放ui.scale覆盖倍率。 - 页面可滚动:内容超过窗口高度时出现滚动条,不会再有"控件被父容器裁掉看不见"的问题。
重做过程中查出并修掉的自身回归(都是编译器与静态检查都看不见的):
- 关闭窗口不再收进托盘 —— 旧版
FormClosing挂在自绘标题栏里,换掉标题栏时一起丢了; 漏掉的表现是"点 X 直接退出程序",属于功能级回归。已补回(含首次提示气泡)。 - 运行期改文案会被旧高度裁掉 ——
Sec.Body()的高度在排版时确定,之后lbl.Text = ...不会重新量高度,长文案(诊断结果、扫描结果、系统摘要)会被截断。 新增SetBody(label, text)作为唯一入口:文字没变直接返回(高频 tick 零开销), 变了就重排所属分区;12 处运行期文案更新已全部改用它。
新增 tools/orphan_check.py:新布局机制下唯一的失效模式是"控件建好了但没挂上去"
(编译通过、运行不报错,用户看不见)。该脚本检查:① Build* 方法里 new 出来的控件之后是否再没被引用;
② 分区是否挂到了页面上;③ 分区里是否一条内容都没加。注入回归精确命中 2/2。
check.bat 从 5 步扩到 6 步:syntax → member → type-ref → layout → orphan → installer。
另修 member_check.py / type_ref_check.py 的一个共性漏洞:泛型方法的声明识别 ——
public T Block<T>(T c, int h) 这类方法名后面直接跟 <,旧正则匹配不到,会把合法调用误报成 CS1061。
第 ⑦ 条做完后,六个静态检查(syntax / member / type-ref / layout / orphan / installer)全部 PASS, 但真编译器一句话就否了:
src\Ui.cs(1239,30): error CS1061: "Fluxion.Sec" 不包含 "Resync" 的定义
两个配套缺失(⑦ 里描述的功能其实一直是空转的):
Sec.Resync()只有调用、没有定义 —— 第 ⑦ 条写的"说明文字变长不会被裁掉"从未真正生效。- 更隐蔽的是:
SetBody()靠l.Tag as Sec反查所属分区,而Sec.Body()从没给标签订过Tag。 就算把Resync()补上,s仍然是null,照样静默失效。
也就是说:"改了 12 处调用"只说明调用点改对了,不说明被调用的东西存在。
| 盲区 | 表现 | 修法 |
|---|---|---|
| 强制转换式声明从不登记 | var s = l.Tag as Sec; 之后 s.任意东西 全部不校验 —— s.Resync() 正是这样溜过去的 |
补 v = ... as T 与 v = (T)... 两类声明(转换目标即确定类型,无推断误差) |
| 控件字段(跨方法访问)从不校验 | 旧注释写的是"找不到声明就跳过,不臆测",但本项目控件几乎全是字段:一个方法里 new、另一个方法里用。实际等于放掉了一大半访问点 |
新增类字段类型表:类体顶层 Bar barCpu, barMem, barGpu; 这类只声明不初始化的字段也登记类型 |
覆盖数从 155 处升到 191 处(新增的 36 处全是字段路径)。建字段表时又踩了一个自己挖的坑:
Pg[] pages 的元素类型是 Pg 但不是 Pg,pages.Length 合法 —— 按元素类型校验会误报,已显式跳过数组字段。
反向验证(三个探针 3/3 命中,基线 PASS):
探针一 as 强转 + 不存在的方法 -> Ui.cs:1251 s.ResyncX_Probe (var s : Sec) CS1061 risk
探针二 (T) 强转 + 不存在的方法 -> Ui.cs:1251 s.ResyncY_Probe (var s : Sec) CS1061 risk
探针三 控件字段跨方法访问 -> Ui.cs:1368 spCpu.PushX_Probe (var spCpu: Spark) CS1061 risk
数组误报防回归:基线里 Ui.cs 有 3 处 pages.Length(Pg[] 字段),基线仍 PASS
Bash 通道会被安全策略拦下(csc.exe 被视同"可编译任意代码",等同于 Add-Type),
但 PowerShell 通道可以正常调起 compile.ps1 —— 本次就是这样编出 COMPILE_OK 的。
所以流程调整为一句话:改完源码 → check.bat 六项预检 → 真编译一次 → 才敢说"改好了"。
静态检查的定位是"提前预警、缩小范围",它永远是编译器的补充,不是替代品。
另外 rebuild.bat 的第 2~4 步(停进程 → 拷到 <部署目录> → 拷图标)不需要编译器,可单独执行。
用户反馈三件事:① 扫描把一堆非游戏收进列表(Clash Verge / Context Menu Manager Plus / dotnet / FlClash / Git / GitHub CLI); ② 希望能手动添加/删除游戏路径;③ 「网络流量节流」「异类线程调度策略」两项一键优化后仍显示未生效。
| 项 | 根因 | 修法 |
|---|---|---|
| 网络流量节流 | WriteReg(..., 0xFFFFFFFF, DWord) —— 0xFFFFFFFF 是 uint 字面量,而 RegistryKey.SetValue 的 DWord 只收 int,直接抛 ArgumentException 被吞 → 注册表里根本没写进去(实测回读确认"NOT SET") |
改传 -1(int),落盘即 0xFFFFFFFF |
| 异类线程调度策略 | apply 和 check 用的 GUID 93b8b6dc-… 这台机器上不存在(powercfg /q 报"指定的电源方案、子组或设置不存在",错误被吞);真正存在的设置是 bae08b81-… = 异类短运行线程调度策略(SHORTSCHEDPOLICY),游戏线程正是短运行线程 —— 旧版 apply 实际只把它设成了一半,check 却查着那个不存在的 GUID,永远返回"?" → 永远显示未应用 |
apply/check 全部对齐到 bae08b81,并当场回读确认(AC 索引实测已是 1 = 高性能处理器/P 核) |
排查方法值得记:别猜。直接在目标机上
powercfg /q SCHEME_CURRENT SUB_PROCESSOR枚举 + 注册表回读,两个"未生效"的根因 5 分钟就实锤了。 顺带:0x00000001在这套枚举里是"高性能处理器"(强制 P 核),0x00000002才是"首选高性能处理器"——旧版注释把 1/2 标反了。
- 帧生成页新增两个按钮:「添加游戏…」(选游戏主程序 exe,信任收录、不走游戏性判定;会向上再探两级目录找补帧组件,兼容选到
bin\x64里的真主程序)和**「移除选中」**。 - 持久化在数据目录新文件
games.json(不动 config.json——那边是文本手术式改键,数组不好维护):custom:手动添加的游戏(exe 路径),启动时自动加载,不用等扫描;ignored:手动移除的自动扫描目录 → 加入忽略清单,下次扫描不再出现。
- 列表里手动添加的条目标注「手动添加」。
旧规则下 C:\Program Files 里任何一个带 exe 的目录都会被收录。新规则两层:
- 工具名黑名单一票否决(目录名 / exe 名):clash / mihomo / v2ray / xray / singbox / dotnet / powershell / steamcmd / github cli / discord / wechat / feishu / geforce / nvidia / bandizip / context menu / steam++ / igamecenter / thunder network…
短词(git / gh / bash / cmd / obs / jdk / java / adb)用词边界匹配——
git会子串命中 "Digital"。 - 结构性特征(任一命中才算游戏,主程序体积完全退出判定):
UnityPlayer.dll/GameAssembly.dll(Unity)、≥50MB 的.pak或Engine目录(Unreal)、game.js/www(RPG Maker)、.rpa/renpy目录(Ren'Py)、.pck(Godot)、data.win(GameMaker)、steam_api(64).dll、EAC/BattlEye、*-shipping.exe(UE 打包成品)、以及本工具的目标特征(DLSS 帧生成/超分/FSR3 DLL)。
⚠️ 体积为什么退出判定:第一版"≥30MB 的 exe +2 分"在你机器上实测混进了 8 个工具 —— Office(74MB)、迅雷(192MB)、MCHOSE HUB(172MB)、Hihonornote(168MB)、HONOR(31MB)、iGameCenter(72MB)、Steam++、Netease。 工具的主程序同样几十上百 MB,大小只能当佐证、不能当主证。 另外.pak特征也踩过一次:Edge 的 Chromium 资源包resources.pak有 38MB,把Program Files (x86)\Microsoft误判成游戏 —— 所以.pak还要求 ≥50MB 且排除resources.pak/*_percent.pak命名。
在本机真实数据上的验证(规则镜像成脚本跑真实目录):
负样本:C:\Program Files + Program Files (x86) 全部 76 个目录 → 0 误报
(此前被收进列表的 6 个全部命中黑名单或零特征)
正样本:Steam 库 6 个真游戏 → 6/6 接受
(Unity ×3 / steam_api ×2 / Ren'Py ×1;各引擎特征都有覆盖)
仍会被拒的边缘情况:不带任何引擎特征的独立小游戏(如部分 GOG 老游戏)→ 点「添加游戏…」手动加即可,手动条目不走判定。 六个此前误收的条目重新扫描后不会出现;不想等的话,选中后点「移除选中」,它就会立即从列表消失(并进忽略清单)。
用户反馈三件事:① 扫描读不出二游(绝区零 / 鸣潮);② 修完①之后鸣潮能力判错、绝区零注入后反而更卡;③ Cyberpunk 2077 从列表里消失了(代理其实还装着)。
扫描根只有 Steam 库 + 写死的常见目录,而二游全走自家启动器、装在自定义路径:
绝区零在 <启动器安装目录>、鸣潮在 <游戏安装目录>\Wuthering Waves —— 任何一个扫描根都覆盖不到。
(排查姿势:reg.exe 被安全中心拉黑,改用 Python winreg 枚举卸载表 InstallLocation,5 分钟实锤。)
- 枚举 HKLM(64/32 位视图)+ HKCU 的
Uninstall键,只对命中启动器关键词的条目深挖 (mihoyo / hoyo / kuro / wuthering / 原神 / 鸣潮 / 绝区零 / 崩坏 / 幻塔 / 尘白…),不会把每个已装程序翻一遍; - 启动器根向下探测(深度 ≤4)全子树收集过门候选 → 打分 → 贪心收录:
帧生成组件 +4 / FSR3 +4 / 超分 +2 /
*-shipping.exe+3;同分时目录更深者优先, 祖先/后代目录互斥 —— 鸣潮真身(Game\Client\Binaries\Win64\Client-Win64-Shipping.exe,13 分,深度 4) 压过存根目录与启动器根(06 分、深度 01),而绝区零靠"更深"赢过启动器根的同分候选(6 分 vs 6 分)。
鸣潮是 UE 打包,NVIDIA 插件在 <游戏根>\Engine\Plugins\Runtime\Nvidia\StreamlineCore\Binaries\ThirdParty\Win64\
(第 7 层),exe 旁边的 FindFile(depth 3) 根本够不着 → 明明原生支持却显示"无 DLSS 帧生成"。
新增 ProbeUePlugins():从 exe 目录向上 ≤5 级找到游戏根(含 Engine 者),再在 Engine\Plugins
里定点搜索(跳过 Content/Paks 等资源目录,只走插件目录,开销极小)。
CP2077 根目录只有 REDprelauncher.exe(真身在 bin\x64,但那是子目录、不在浅层挑选范围),
把 launcher 列入硬跳过名单后该目录连一个候选 exe 都没有 → 条目直接消失(而代理还装着)。
改为降级备选:launcher 类仅在目录里没有其它候选 exe 时才采用;unins/setup/crash/redist/safemode/bootstrap/install 仍硬跳过。
NiceTitle()旧实现只向上走 3 跳就耗尽、且跳出后把原名返回 → 鸣潮一直显示成「Win64」;改为最多 8 跳并正确返回第一个非结构名。- 新增二游注入风险确认(
Dlssg.InjectionRiskNote+ UI 确认框):命中二游关键词时, 点「开启帧生成」先弹提示 —— 内核反作弊注入有封号风险;原生已带帧生成(FSR3 / DLSS FG)时叠加注入 会同时占用显存与帧生成流水线,实测表现为"游戏内用的还是 FSR 帧生成,但明显更卡"。 建议二游只用「一键优化」的驱动层设置,帧生成走游戏内原生选项。
== Steam 根(Inspect 直扫)==
Cyberpunk 2077 (REDprelauncher.exe) score=10 DLSS 帧生成 √ · DLSS 超分 √ · FSR3 帧生成 √ [启动器降级]
== 启动器根: <游戏安装目录>\Wuthering Waves ==
Wuthering Waves Game (Client-Win64-Shipping.exe) depth=4 score=13 DLSS 帧生成 √ · DLSS 超分 √ · FSR3 帧生成 √
== 启动器根: <启动器安装目录> ==
ZenlessZoneZero Game (ZenlessZoneZero.exe) depth=2 score=6 DLSS 帧生成 √ · DLSS 超分 √
| 游戏 | 收录条目 | 能力 | 说明 |
|---|---|---|---|
| 鸣潮 | Wuthering Waves Game(Client-Win64-Shipping.exe) | DLSS 帧生成 ✓ · DLSS 超分 ✓ · FSR3 帧生成 ✓ | 本体原生三支持(FSR3 在 exe 旁,DLSS 系在 Engine\Plugins) |
| 绝区零 | ZenlessZoneZero Game(ZenlessZoneZero.exe) | DLSS 帧生成 ✓ · DLSS 超分 ✓ | 不注入:内核反作弊 + 原生已有帧生成 |
| CP2077 | Cyberpunk 2077(REDprelauncher.exe) | DLSS 帧生成 ✓ · 超分 ✓ · FSR3 ✓ | 代理(winmm.dll)仍装着,条目恢复显示 |
| 米哈游启动器根 | — | — | 不再被收录(启动器根 + 注入残留已清理) |
注:
<游戏安装目录>\SkyrimSE是已删游戏,忽略清单同步清理。
用户反馈:新装的原神怎么都扫不出来;识别不能实时更新,每次都得手点「扫描游戏」。
门禁此前只认 UnityPlayer.dll / GameAssembly.dll。原神(YuanShen.exe 411 MB)把 Unity 引擎静态编进主程序,
根目录根本没有 UnityPlayer.dll,结构特征一个都不沾 → 整款游戏被判定为"不是游戏"而丢弃。
- 新增签名
<游戏名>_Data\globalgamemanagers(Unity 独有文件,工具类目录造不出来) - 新增签名
mhypbase.dll(米哈游引擎基座,原神 / 星铁 / 绝区零通用) - 顺带把
HoYoKProtect.sys/mhyprot*计入反作弊特征,喂给注入风险提示
绝区零用的是 amd_fidelityfx_framegeneration_dx12.dll,而名单里只写了 amd_fidelityfx_dx12.dll
——「普通目录探测」与「UE 插件探测」两处各写一份名单,两边都漏。现收口为单一常量
(FgDllNames / UpDllNames / FsrDllNames),绝区零正确显示 FSR3 帧生成 ✓。
- 启动即后台静默扫描一遍(不阻塞界面,只打一行汇总日志)
- 窗口重新激活时按需重扫:距上次扫描完成 ≥10 分钟才扫;游戏运行中不抢磁盘 IO
- 汇总日志列出新增条目,例:
自动扫描完成:游戏目录 12 个,其中集成 DLSS 帧生成 4 个;新增 Genshin Impact Game
<启动器安装目录> 这类目录是装游戏的容器(下挂 games\,内含原神/绝区零/星铁)。
此前被误注入 —— 一次注入同时作用于容器下所有游戏,且它们全是内核反作弊。现在 Install() 直接拒绝并提示改选游戏本体。
== 启动器根: <启动器安装目录> ==
ZenlessZoneZero Game (ZenlessZoneZero.exe) depth=2 score=10 DLSS 帧生成 √ · DLSS 超分 √ · FSR3 帧生成 √
Genshin Impact Game (YuanShen.exe) depth=2 score=0 无帧生成组件
== 期望命中自检 ==
OK <启动器安装目录>\games\Genshin Impact Game
OK <启动器安装目录>\games\ZenlessZoneZero Game
OK 启动器根未被收录(应无): 无
| 游戏 | 收录条目 | 能力 |
|---|---|---|
| 原神 | Genshin Impact Game(YuanShen.exe) | 无帧生成组件(本体原生无 DLSS/FSR3,属事实非 bug) |
| 绝区零 | ZenlessZoneZero Game(ZenlessZoneZero.exe) | DLSS 帧生成 ✓ · DLSS 超分 ✓ · FSR3 帧生成 ✓(本次修正) |
| 鸣潮 | Wuthering Waves Game(Client-Win64-Shipping.exe) | DLSS 帧生成 ✓ · DLSS 超分 ✓ · FSR3 帧生成 ✓ |
| CP2077 | Cyberpunk 2077(REDprelauncher.exe) | DLSS 帧生成 ✓ · DLSS 超分 ✓ · FSR3 帧生成 ✓ |
原神本体不带 DLSS / FSR3 的 DLL(原生无帧生成),所以能力列显示"无 DLSS 帧生成"是事实而非缺陷; 它仍会被收录、被「一键优化」的驱动层设置覆盖,需要注入时再点「开启」。
用户反馈:2.0.6 装完,原神还是识别不出来;另外希望关窗口时能选"退出还是最小化"。
日志写着 扫描完成:识别 11 个游戏目录,列表却只有 10 个 —— 少的那个正是原神:
C:\ProgramData\Fluxion\games.json
ignored: ["<游戏安装目录>\SkyrimSE", "<启动器安装目录>\\games\\Genshin Impact Game"]
扫描扫到了原神,合并层按 ignored 把它滤掉了。而这份清单:
- 没有任何 UI 入口能把它捞回来(只能改
games.json) - 文件在
C:\ProgramData,由提权进程创建,普通权限连改名都拒绝访问(实测WinError 5)
即:误点一次「移除选中」= 这款游戏永久消失,用户视角就是"识别不出来"。静默丢弃 + 无法恢复,两个都得治。
- 帧生成页新增 「忽略清单」 按钮:列出全部被忽略目录 + 磁盘现状
(
可收录 · YuanShen.exe/目录不存在(可放行清理)/目录在,但未通过游戏性判定) - 支持放行选中 / 全部放行,放行后自动重扫,游戏当场回到列表
- 扫描完成时不再静默丢弃:日志追加
>>> 注意:有 1 个已扫到的游戏目录在忽略清单里、未显示:Genshin Impact Game(G:\...) → 点「忽略清单」可放行
点右上角 X 现在弹框二选一,样式与主界面一致:
最小化到通知区域图标(后台继续运行)← 默认退出程序(联动与告警一并停止)- 勾「记住我的选择,不再询问」后不再弹;想恢复询问,到「关闭窗口时询问」开关里改回(该开关现位于 设置 → 窗口与托盘,v3.2.1 起搬入)
细节:系统关机 / 任务管理器结束时一律不弹框(弹了会卡住关机流程),直接收进托盘;
托盘的「退出」菜单永远直接退出。偏好存 config.json 的 ui.closeAsk / ui.closeToTray。
配置写回靠 IndexOf("\"services\"") 定位节,而 gameAware.remoteApps 里恰好有
"services": ["GameViewerService"] —— 于是**「服务优化」的开关被写到了「CPU 调度」节上**
(想关 services.enable,结果写动了 scheduler.enable),而且全程不报错。
- 节定位改为按花括号深度 = 1 判定顶层节 + 键与
{之间只允许冒号/空白(FindSectionBlock) - 布尔/字符串/整数三种写回合并到同一处
WriteConfigKey,不再各写一份定位代码 - 写回前先整份解析一遍:写坏宁可拒绝(2026-09 有过一次配置文件被写坏、全部配置静默回默认的事故)
顺带解决"新键存不下来":安装包对 config.json 用的是 onlyifdoesntexist(升级不覆盖用户那份),
所以老安装里没有 ui 节 —— 现在节缺失会自动整节追加、键缺失会自动补键。
配置写回是文本手术,编译通过 ≠ 写回正确。脚本对着真实 config.json 断言 6 件事:
services 节不落在 gameAware 内、改 services.enable 不动 scheduler.enable、无 ui 节能整节追加、
节在键缺能补键、旧配置逐键补写、改 power.enable 不动 power.gameAwareSwitch。
这个脚本在本次开发中直接抓出了一个真 bug:补键函数的返回值不含结尾
}(调用方接回去), 但校验时只验了残块 → 永远验不过 → 补键静默失效。
[1] services 节定位 ... 是否误落在 gameAware 内部: False
[2] 改 services.enable -> replaced | services.enable = False | scheduler.enable = True
[3] 无 ui 节时写入 -> appended-section | ui = {'closeAsk': False}
[4] 节在键缺 -> inserted-key
[5] 旧配置(无 ui) 逐键补写: appended-section / inserted-key
[6] power.enable -> replaced | gameAwareSwitch = True
RESULT: PASS
用户反馈:2.0.7 装上了,原神还是识别不出来。
2.0.7 的日志明明已经给出了答案,甚至给出了操作指引:
[11:56:35] 扫描完成:识别 11 个游戏目录
[11:56:35] >>> 扫描完成:游戏目录 10 个,其中集成 DLSS 帧生成 4 个
[11:56:35] >>> 注意:有 1 个已扫到的游戏目录在忽略清单里、未显示:Genshin Impact Game(<启动器安装目录>\games\Genshin Impact Game) → 点「忽略清单」可放行
但 Ui.cs 里这一行:
FlatBtn btnAddGame, btnDelGame, btnIgnored;btnIgnored 只声明、从没 new、也从没进过任何 Buttons(...);配套的 ShowIgnoredDialog() 全文件没有任何调用。
结果就是:按钮在界面上根本不存在,而日志让用户去点它。—— 编译通过、四个静态校验器全 PASS、功能静默消失。
btnIgnored实例化并接线Click -> ShowIgnoredDialog();按钮排布改两行 (FlowLayoutPanel设的是WrapContents = false,6 个按钮塞一行会在 1056 宽的窗口里溢出被裁掉):- 第一行:
开启选中/关闭选中/添加游戏…/移除选中 - 第二行:
运行诊断/忽略清单
- 第一行:
- 「移除选中」补二次确认——它就是原神进忽略清单的来源,且是列表里唯一有持久副作用的动作, 确认框里直接写明"不会删文件 / 怎么恢复收录"
这个 bug 能出厂,是因为校验器只覆盖了「局部控件建了就扔」和「分区没挂上」, 没覆盖类字段和私有方法。新增:
| 新检查 | 含义 |
|---|---|
DEAD-FIELD |
控件/组件类型的类字段只声明、从未赋值 → 控件不存在 |
DEAD-METHOD |
方法定义了但全文件没有任何引用 → 入口没接线(用"总出现次数 ≤ 1"判定,委托传参也算引用) |
验证方式:拿一份把本次修复回退掉的 Ui.cs 副本跑新校验器,两条都被抓出来:
fields scanned : 49 methods scanned: 63
RESULT: 2 suspect item(s)
- Ui.cs:541 DEAD-FIELD -> FlatBtn btnIgnored 只声明、从未赋值(控件不存在,功能静默消失)
- Ui.cs:1755 DEAD-METHOD -> ShowIgnoredDialog() 定义了但全文件没有任何引用(入口没接线)
教训:"声明了"不等于"存在"。自绘 UI 的失效模式是"代码在、界面没有", 而编译器对未赋值的字段、未被调用的私有方法一声不吭 —— 必须由静态检查兜住。
用户反馈:我就要用该插件的功能,用 DLSS 的帧生成,这样延迟会低一点也不会卡。不要用 fsr。
以及 自动扫描游戏做的还是不够好,原神还是识别不出来。
2.0.9 那一版我写错了一个根本事实,还把它固化进了界面文案。真实情况:
| 事实 | 说明 |
|---|---|
| 本工具接的是什么 | 社区项目 dlssg_for_sm86(github.com/sdli1995/dlssg_for_sm86):给 Ampere/Turing 补一份 SM86/SM75 内核,并内嵌 NVIDIA 自己的 DLSS-G 运行时 |
| 它跑的是什么管线 | NVIDIA 原生 DLSS 帧生成(含 2X/3X/4X),不是 FSR 转发。ini 里 Router=SM86 指"路由到 SM86 内核" |
| 「官方不支持」的含义 | NVIDIA 官方确实不给 20/30 系开放 DLSS 帧生成(GpuSupportsDlssFg() 判断的就是这一层)—— 但官方不支持 ≠ 用不了,本工具存在的意义正是绕开这条 |
| 那"注入后还是 FSR"是怎么回事 | 代理没被激活:入口 DLL 只被游戏加载、从未被调用时,代理永不初始化,游戏内自然只剩它自带的 FSR 帧生成 |
铁证是项目自己的文件头注释与源码地址:
接管游戏对 nvngx_dlssg.dll 的加载请求,换成补齐 SM86/SM75 内核的运行时; 代理容器source\version.dll(15.7 MB)与source\altnative\{winmm,dxgi,dinput8,winhttp}.dll体积一致, 正是该项目 0.2.4 的产物。感谢用户坚持 —— 上一版结论是错的。
先例:CP2077 对 version.dll 只加载不调用,代理延迟初始化永不触发(DLL 在进程里、零日志、FG 无效),
换成 winmm.dll 后立即激活,实测 135 → 190 帧。二游大概率是同一类问题,所以这版加了「换入口重试」。
Install拆成Install(自动选入口)+InstallAt(指定入口);新增EntryOrder/EntryUsable/NextEntry- 按钮点一下:卸掉当前入口 → 用下一个可用入口重装(跳过源文件没下载、或入口名被非本工具 DLL 占用的)
- 换入口时保留
dlssg_sm86\logs\日志目录(Uninstall(g, keepLogs: true)),方便对比换入口前后的诊断 - 「运行诊断」的两条提示改成可执行动作:
代理已加载但未激活 → 点「换入口重试」/尚无日志目录 → 先启动一次游戏
2.0.7/2.0.8 的做法是「被忽略就不显示,日志里提一句」—— 用户视角仍然是"识别不出来"。
现在 MergeScan 保留被忽略条目并打上 Ignored 标记:
| 位置 | 行为 |
|---|---|
| 游戏列表 | 灰显 + [已忽略] 前缀,状态列写「已忽略(选中点「开启选中」即恢复收录)」 |
| 「开启选中」 | 命中忽略态时先自动放行(UnignoreDirs)再继续开启流程,不需要用户去翻 ProgramData 里的 json |
| 「移除选中」 | 已在忽略清单里的条目直接拒绝(本来就在忽略清单里,无需再移除) |
| 「换入口重试」 | 忽略态同样先拦下,提示先「开启选中」恢复收录 |
| 底部统计 | 分开算「可接入 N 个」与「被忽略 M 个(列表里灰显)」 |
| 扫描日志 | 游戏目录 11 个(可接入 10 个)… + 注意:有 1 个目录在忽略清单里(列表中已灰显) |
教训:"不显示"等于"不存在"。凡是会被隐藏的状态,都必须同时给出可见的标记与一键恢复的入口。
去掉两条错误判据(HasFsr3 → 注入零收益、显卡不支持 DLSS FG → 注入也只能得到 FSR3),改为:
| 判据 | 维度 | 结论 |
|---|---|---|
GachaWords 命中 |
反作弊 | 内核反作弊(mhyprot / HoYoKProtect / ACE)→ 封号风险,最高优先级;社区已记录 ACE 直接拦截代理 DLL 加载的案例 |
!g.HasFrameGen |
能力 | 目录里没有 nvngx_dlssg.dll / sl.dlss_g.dll → 没有可接管的调用,装了不生效 |
GpuSupportsDlssFg() == false |
路径 | 走的是社区补内核方案(非官方),可能选项不出现 / 崩溃 / 画面异常,NVIDIA 更新后可能失效 —— 但不是"没用" |
写清三件事:① 跑的是 NVIDIA 原生 DLSS-G,不是 FSR;② 生效判据 = 游戏内出现「DLSS 帧生成」+ dlssg_sm86\logs\*.jsonl 有 runtime_redirect / feature_created / evaluate;
③ 只有 FSR 选项时该做什么(换入口)。并明确提示:帧生成只提高显示帧率,不会降低延迟,想要低延迟请开 Reflex 并保证基础帧率。
static_check.py 的 MEMBER_RE / RE_METHOD_DECL 与 orphan_check.py 的方法白名单都不认可空标记 ?,
于是 public static bool? GpuSupportsDlssFg() 整条不被登记,引用处被误报 UNRESOLVED,
DEAD-METHOD 检查也会静默失效。补上可选 ? 后:
修复前:RESULT: 1 issue(s) - UNRESOLVED Dlssg.GpuSupportsDlssFg (referenced in Ui.cs)
修复后:RESULT: PASS - no static issue found
验证修复没有放松检测:把 Dlssg.HardwareFgNote() 改成不存在的名字跑,仍报 UNRESOLVED(exit 1);还原后 PASS。
教训一:校验器自己也会漏。出现新语法(可空类型、泛型…)时先确认校验器的正则认得它,否则"全绿"是假的。 教训二:别把"官方不支持"写成"技术上做不到"。差之毫厘,用户照着做就会得出错误结论。
不依赖 WMI(本机安全中心禁了系统级工具),改读注册表
HKLM\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-…}\0000\DriverDesc,并跳过虚拟显示适配器。实测:
0000 => NVIDIA GeForce RTX 3060 Ti
0001 => GameViewer Virtual Display Adapter ← 跳过
0002 => Honor Virtual Display Device ← 跳过
背景:绝区零、鸣潮在 2.0.x 里怎么换入口都不生效。上游 issue #111 给出了原因,而且是实测结论:
绝区零的反作弊会识别到
version.dll等的名词,从而使其失效。
issue #387(同日,明日方舟:终末地)5 个入口全部重现了同样的症状 —— 5 个入口要么报"非法劫持模块"、要么能进游戏但菜单里没有选项。这是国产二游 ACE 类反作弊的通用行为,不是操作错误。
d3d12.dll 是 DX12 游戏必须加载的系统库,反作弊没法按文件名拉黑它。但上游 dlssg_for_sm86 只发 5 个入口(README 原话:"五种已签名代理入口保持不变"),没有 d3d12 —— 所以本版自己造一个。
| 表 | 内容 | 作用 |
|---|---|---|
| 导出表 | 系统 d3d12.dll 的全部 18 个函数 → 转发到 d3d12_orig.dll 同名函数 |
对游戏完全透明,D3D12 调用照常落到微软签名副本上 |
| 导入表 | dinput8.dll!DirectInput8Create |
Windows 加载代理时必须先解析它 → 自动把上游的 dinput8.dll(15.6 MB,真正的帧生成运行时)拉进进程 |
安装时落三个文件(三件套,缺一件游戏启动即崩):
d3d12.dll 3,584 B 代理(本工具内嵌字节:导出转发 + 导入载体)
d3d12_orig.dll 146,176 B 转发目标 = 本机 C:\Windows\System32\d3d12.dll 的副本
dinput8.dll 15,666,496 B 载体 = 上游 altnative/dinput8.dll(一个字节没改)
与社区流传的"抖音那条路"(ASI 加载器注入)的差别:那边需要一个第三方 ASI 加载器把 DLL 注进去;这边靠 Windows 自己的导入解析机制把 dlssg 拽进来,不需要加载器,也不需要编译器。
| # | 改动 | 位置 |
|---|---|---|
| 1 | D3d12Entry / D3d12Orig / D3d12Carrier 三个常量 + 内嵌代理字节 D3d12ProxyBlob |
Dlssg.cs |
| 2 | EntryOrder():反作弊游戏把 d3d12 排在所有入口之前 |
Dlssg.cs |
| 3 | InstallD3d12():写三件套(占用先备份)+ 写配置 + 假成功校验 |
Dlssg.cs |
| 4 | VerifyD3d12() + PeImports():解析 PE 导入表,确认"代理↔载体"真的接上 |
Dlssg.cs |
| 5 | ScanResidue():扫被反作弊改名隔离的残留(version.dll.1271877294) |
Dlssg.cs |
| 6 | Uninstall():d3d12 三件套 + 残留一起清(d3d12_orig.dll 要先与系统原件比对长度才删) |
Dlssg.cs |
| 7 | IsAntiCheat():反作弊名单收口为唯一来源(GachaWords) |
Dlssg.cs |
| 8 | 帧生成页:d3d12 状态行 + 「清理残留」按钮 + 「反作弊游戏自动改用 d3d12」开关 | Ui.cs |
| 9 | 配置项 dlssg.antiCheatD3d12(默认 true) |
Core.cs / config.json |
| 级别 | 问题 | 后果 |
|---|---|---|
| 🔴 | install.cmd 拷贝 dxgi.dll,包里却是 dinput8.dll |
d3d12.dll 的导入解析失败 → 游戏启动即崩 |
| 🟡 | 部署用 ini 缺 [Compatibility] 段,且写了上游不存在的键 EvaluateEvery=120 |
参数静默失效 |
| 🟡 | make_d3d12_proxy.py 文件头注释仍写"静态依赖 dxgi.dll" |
文档与实现相反 |
教训与 2.0.6 的 FSR 组件名同源:同一份清单写在两处,必然漏一处。 现已加生成期守卫 —— 拷贝清单与文件常量不一致时,脚本直接报错退出。
系统 d3d12.dll 导出 18 个 == 代理导出 18 个(无缺失、无多余)
18 个导出全部转发到 d3d12_orig.dll
代理导入表 = ['dinput8.dll'] ← 闭合
内嵌字节 == deploy 包字节(3,584 B,可解析为合法 PE)
临时目录落盘演练:三件套齐全,导出 18 / 导入 dinput8.dll
🟡 绕开的是文件名识别,不是反作弊本身。注入未签名 DLL 仍是违约行为,理论上可封号,封的是你的账号,工具无法撤销。
🟡 若反作弊连 d3d12.dll 都拦(表现为游戏目录下始终不出现 dlssg_sm86 日志目录),那就是社区无解的边界 —— issue #81 的结论仍然成立。
🟢 「关闭选中」可一键回滚(含 d3d12_orig.dll 与改名残留)。
真机首测发现的问题(2.1.0 部署到绝区零/鸣潮后):鸣潮代理激活成功(日志 configuration + ngx_driver_connected,ACE 没拦 d3d12 链路),绝区零被 HoYoKProtect 掐在加载前(连日志都没有)。但两个游戏菜单都没有帧生成开关。
根因:菜单露不露出开关由游戏第 1 层判定决定——游戏先问"硬件支不支持",不少游戏这一问读的是注册表里的显卡名,30 系名字直接被判"不支持",开关根本不渲染。dlssg 代理只接管第 2 层(真跑帧生成),够不到第 1 层。
改动(Dlssg.GpuDisguise + 帧生成页「伪装显卡名 / 还原显卡名」按钮):
- 扫描注册表三处分支(显示类子键、
Enum\PCI、Control\Video)里所有含真名的字符串值 - 一键全部替换为
NVIDIA GeForce RTX 4070;原值完整备份到ProgramData\Fluxion\disguise.json - 再点一次按钮即从备份逐条还原;状态行常显"真名 / 伪装中"
- 全局可见(设备管理器/DXDiag/WMI 都显示 40 系名),杀软可能告警,驱动更新会重置注册表
诚实声明:能否骗过具体某个游戏取决于它读不读这些键值——NVAPI 走内核 ioctl 的判定改注册表无效。这是实验性功能,效果要真机验证(鸣潮是首选目标;绝区零在"游戏侧请求帧生成"那一步就断了,伪装无意义)。
产物:installer_out\Fluxion-Setup-2.1.1.exe
背景:2.1.x 的 d3d12 复合入口在绝区零被 HoYoKProtect 拦死(三次不同入口:version.dll 按名拦 / dinput8 链 / 签名版,全挂 11008);鸣潮的 dlssg 直接安装后,在 DX12 命令列表阶段崩溃。社区整合包(B 站教程)在两款游戏上实机跑通,本版直接固化该方案。
| 游戏 | 入口 | 配置 | 实测 |
|---|---|---|---|
| 绝区零 | d3d12.dll(OptiScaler 25.6MB) |
伪装 RTX 5090 · 上采样 DLSS · 帧生成 DLSSG→XeFG(2-6X) | 绕开按名拦截,帧生成可用 |
| 鸣潮 | dxgi.dll(OptiScaler 0.7.7) |
5090 伪装 · dlss 上采样 · DLSSG 进出(含 dlssg_sm86 子目录) | 帧生成可用 |
用法:帧生成页 → 游戏列表选中游戏 → 「XeSS 多帧生成」区点部署;点卸载完整还原(覆盖的游戏自带件自动备份恢复)。游戏内 F10 呼出 OptiScaler 面板。
资源包(约 850 MB,不内嵌 exe):%ProgramData%\Fluxion\xess-pack\{zzz,wuwa}\。换机部署时把资源包放入该目录即可。
关键机制:绝区零用 d3d12.dll 名(DX12 游戏必加载的系统库名,反作弊无法按名拦);帧生成走 FGInput=DLSSG → FGOutput=XeFG(游戏原生 DLSS 帧生成调用被拦截后由 Intel XeSS FG 引擎执行)。
踩过的坑(写进代码里):
- 鸣潮 exe 在 3 层目录(Client\Binaries\Win64),识别需递归查找 —— 首版只找 1-2 层漏了
- 清理 mod 时误删游戏自带件(绝区零的 nvngx_dlss.dll)导致黑屏 —— 卸载逻辑改为备份清单制:安装前备份被覆盖文件,卸载时恢复
- DLSS 5 神经渲染(nvngx_dlssnr)在老卡上开销大,本方案只用其帧生成路径
启动器(帧生成页 · 游戏列表):
- 列表左侧显示游戏图标(提取 exe 图标,按路径缓存)——解决英文名难辨认
- 双击列表项直接启动游戏;另加「启动游戏」(推荐按钮)/「打开目录」按钮
- 直接跑游戏 exe,绕开官方启动器的文件完整性校验弹窗(鸣潮这类装了 mod 的游戏必需)
- 游戏列表来源:常见安装目录 + Steam 库 + 注册表卸载项(第三方安装的游戏多数有)+ 启动器根目录 + 自定义目录 + 手动添加,覆盖绝大多数安装位置
显卡名伪装说明修正(研究结论,来源见下):
- 任务管理器 / 设备管理器的 GPU 名读的是注册表设备描述符(
Enum\PCI\DeviceDesc、Class\...\DriverDesc)——改这些 + 重启电脑后两者同步显示新名字 - 之前"改了没变"是因为没重启电脑;OptiScaler 的 SpoofedGPUName 只在游戏进程内生效,系统层永远显示真名(两回事)
- 工具已把「显卡名伪装」的提示改为"重启电脑后任务管理器 / 设备管理器同步显示"
界面(参考 GamesDeck / Playnite 封面库):
- 游戏列表从 ListView 换成封面卡片网格:每张卡片 = 封面/图标(132px)+ 名称 + 状态徽章,单击选中(蓝框高亮)、双击启动
- 封面优先取
%ProgramData%\Fluxion\covers\<游戏名>.png(自己放图即自动使用,GamesDeck 式个人封面库),没有则用 exe 图标
全电脑游戏识别:
- 新增「添加目录…」按钮:把任意目录(如
<个人目录>)加入扫描根,写入 config 的dlssg.extraRoots,下次扫描自动包含 - 自定义目录采用宽松收录:跳过游戏性判定(RPG Maker / Ren'Py 这类引擎特征不在名单里,但用户指定了目录就是要它进库),只保留工具名黑名单与安装器排除。实测
<个人目录>16 套里收录 14 套(另 2 套是存档目录/无 exe)
技术说明重写(帧生成页常驻文案):写明实际技术栈与三层链路 —— OptiScaler(github.com/optiscaler/OptiScaler)+ dlss-unlocked(ShyVortex)+ dlssg_for_sm86(sdli1995)+ fakenvapi + Intel XeSS-FG; ① 伪装 RTX 5090 让菜单出现开关 → ② 拦截游戏的原生 DLSS 帧生成调用 → ③ 由 XeSS 帧生成引擎实际插帧(2-6 倍)。
移除:「伪装显卡」功能整体删除(OptiScaler 插件已内置 GPU 伪装,系统层伪装不再需要)。
用户反馈三条,逐条定位到根因并修:
| 反馈 | 根因 | 修法 |
|---|---|---|
| 卡片图好糊 | 取图标用的是 Icon.ExtractAssociatedIcon(),它只返回 32×32,拉到 132 的卡片上就是一团糊 |
改 PrivateExtractIcons 主动要 256×256,在多个候选尺寸里取实际像素最大的一张;缩放统一走 GameIcon.Scale()(HighQualityBicubic + TileFlipXY)。实测:鸣潮/绝区零/2077/极限竞速 + <个人目录> 全部游戏 32×32 → 256×256 |
| 页面中部整片空白、只显示底下一个分区、还多出横向滚动条 | ① Pg 容器没开双缓冲,而子控件全开了 —— AutoScroll 滚动是位图位移,父子缓冲不同步就留空白带;② Reflow() 在忙时把再入请求直接丢弃,尺寸变化永久丢失,布局停在半成品;③ 没给竖向滚动条预留宽度,竖条一出现就把内容挤出横条 |
Pg 开双缓冲 + 重排改「挂起标记 + 迭代到收敛」+ 按竖条可见性预留宽度;OnScroll 强制整页重绘;封面网格换双缓冲子类 BufferedFlow |
| 鸣潮「可接入」到底是哪个插件 / 绝区零用的什么方案 | 卡片状态只写了泛化词:可接入 = 目录里有 DLSS 帧生成组件(不代表装了任何插件);绝区零那条 已开启(d3d12.dll) 是 state.json 里的旧记录在作祟(15:34 装的 3.5 KB 代理早被 XeSS 套件的 25.6 MB d3d12.dll 取代) |
卡片状态改为读实际方案:XeSS 多帧生成(d3d12) / XeSS 多帧生成(dxgi);新增 PruneStale() 扫描前清理失效记录(判据是体积,不是「文件在不在」);统计口径不再用「可接入 N 个」而按方案分列 |
顺带加的护栏:这两个游戏装了 XeSS 套件时,「关闭选中」会拒绝执行并提示改用「XeSS 多帧生成 → 卸载」——两者入口文件同名(d3d12.dll / dxgi.dll),混用会留下装了一半的状态(旧的 libxess、fakenvapi 还在,游戏可能起不来)。
封面库:数据目录 covers\ 现在会在启动时自动创建;把图片按「卡片标题.png」放进去即自动用作封面,没放则用 exe 图标。
一、界面重排(用户三条反馈,均已定位到代码级根因)
| 反馈 | 根因 | 修法 |
|---|---|---|
| 页面能往上滑出空白 | 滚动区由子控件边界推导,长文被窄宽测量过会撑出超长内容 | Pg 双缓冲 + 重排用自己算出的内容高夹紧 + 重排后逐分区重绘 |
| 两个滑条太麻烦 | 帧生成页 5 分区 / 8 个文字块;卡片网格还自带内层滑条 | 帧生成页瘦身成「运行时状态 + 目标游戏下拉 + 操作按钮 + 参数」;游戏库、说明各自独立成页;网格关掉内层滚动(整页单滚动条) |
| 点卡片强制跳回最上面 | 点击 → 状态行文案变 → Sec.Resync() → 整页重排;且重排时 maxSy 读 WinForms 延迟更新的 DisplayRectangle.Height,读到 0 就把滚动归零 |
状态行改固定高度(不参与高度推导);Reflow() 内容没变直接返回;maxSy 改用自算内容高 |
页面从 5 页扩到 7 页:仪表盘 / 性能优化 / 帧生成 / 游戏库 / 实时监控 / 说明 / 设置。
页面索引改为常量 P_DASH…P_SET(避免插页时裸数字错位)。长文(技术栈、三层原理、用法判据、使用须知、反作弊、封面库、数据与隐私)全部移到「说明」页。
二、移植用户自研启动器 GameLauncher 的能力(Python 逻辑改写为 C#,不引入任何运行时依赖)
| 能力 | 来源 | 效果(本机实测) |
|---|---|---|
| Steam 官方游戏名 | appmanifest_*.acf |
「the dreamland of I…」→ 「尸姬之梦」;原神/绝区零/鸣潮 也拿到中文名 |
| 全部 Steam 库 | libraryfolders.vdf + 逐库扫 acf |
补回第二个 Steam 库(D:)里漏掉的作品 |
| WeGame | 注册表卸载项 + rail_apps 识别 |
新增 卡拉彼丘 / 无畏契约(此前完全扫不到) |
| Epic / 育碧 / EA / 战网 / GOG | 各平台注册表与 manifests | 按平台归类并可筛选 |
| 主程序挑选 | 名称匹配 > 提示名 > UE Shipping > 体积 | 修掉 CS2 被 18.9MB 的 source1import.exe 挤掉(现为 cs2.exe);新增工具类 exe 黑名单(ffmpeg / source1import / vconsole / TinyDL…) |
| Steam 官方封面 | 官方 CDN library_600x900.jpg |
卡片显示官方竖版封面;无封面时按游戏名哈希生成渐变卡(含 exe 图标) |
| 库管理 | 收藏 / 私密 / 隐藏 / 重命名 / 最近游玩 | 「游戏库」页工具条:搜索 + 平台分类(含收藏/私密/二次元)+ 排序;私密不进「全部」,隐藏需勾选才可见 |
扫描结果:11 款 → 16 款(Steam 11 + 本地 3 + WeGame 2),与用户启动器一致。
三、新增文件与数据结构
src\Lib.cs:库标记存储(library.json,与games.json分开,不动现有忽略清单逻辑)、Steam/Epic/育碧/EA/注册表扫描、封面管线(下载 + 渐变生成 + 缓存)DlssgGame增字段:Platform / AppId / Genre / Id / Favorite / Private / Hidden / LastPlayed%ProgramData%\Fluxion\library.json:收藏 / 私密 / 隐藏 / 重命名 / 平台与 appid;covers\:封面缓存- 网络只访问 Steam 官方域名(白名单校验),走「设置」页配置的代理;可在设置里关闭联网封面
四、封面库用法:把图片按「卡片标题.png / .jpg」放进 covers\ 即自动生效;或在游戏库页点「获取封面」联网补齐。
用户五条反馈,逐条处理:
| 反馈 | 处理 |
|---|---|
| 底部那排操作按钮要翻到最下面才能用 | 全部搬进卡片右键菜单(启动 / 打开目录 / 收藏 / 重命名 / 私密 / 隐藏 / 帧生成 / 移除);页面底部整块「选中游戏」区删除,改为顶部一行状态 + 「启动选中」按钮 |
| 游戏太多会生成一大块白色区域 | CardGrid 新增:每次布局都按当前宽度算出应有的行数并设置高度。原来只在外部按旧宽度算一次,首次布局/窗口变窄时行数偏大 → 网格留出大片空白 |
| 有的封面大小不匹配、违和 | 卡片封面区从 132×176 改为 132×198(正好 2:3),与 Steam 官方竖版封面(600×900 / 300×450)完全对齐;新增 CoverArt.Fit() 按比例裁切填满,不再出现留边 |
| 能联网获取封面吗 | 能。实测:Steam 封面 CDN(steamstatic)直连可用,3/3 成功;失败原因是原来只按配置单路走且静默吞异常。现改为直连/代理双路自动回退,失败原因写进日志。「按名称搜封面」用 steamcommunity,需代理开着 |
| 联动只对网游 | 本来就是:gameAware.gameProcesses 只有 CS2 / 无畏契约 / 三角洲,二游与 3A 不会触发远控暂停。设置页开关文案已写明这一点 |
设置页「帧生成下载源」改名「下载源与联网封面」,新增联网封面开关(关闭后只用本地图标与按名字生成的颜色卡)。
用户三条反馈:有的游戏没封面、边角太锋利(希望沿用《游戏启动器》的美术语言)、标题与页面一体性差。 逐条定位到代码级根因,并按"离屏渲染亲眼核对"的方式验证。
游戏启动器的 token 是 --radius: 14px(卡片)/ 11px(按钮)/ 10px(输入)/ 999(胶囊)。本版把它移植成一等公民:
| token | 值 | 用在哪 |
|---|---|---|
Theme.RCard / RPanel |
14px | 游戏卡片、内容分区 |
Theme.RBtn |
10px | 按钮、侧栏导航胶囊 |
Theme.RField |
10px | 输入框、下拉框 |
Theme.RPic |
10px | 卡片封面 |
新增自绘控件(原生控件画不了圆角,这是根因):
CoverBox:圆角裁切的封面框(原来是PictureBox,只能直角)NavBtn:圆角胶囊导航项 + 左侧强调条RoundField:圆角输入框宿主(TextBox 自身无圆角能力)RoundCombo:圆角下拉框。原生 ComboBox 的箭头由系统绘制,深色主题下是刺眼白块, 还会破坏圆角观感 —— 自绘字段 + chevron + 用主题化菜单做下拉面板RoundCheck:圆角复选框(同上,系统方框在深色下是白块)
配套:Theme.Round/FillRound/EdgeRound/SoftShadow/ClipRound 与 ThemedMenuRenderer
(右键菜单、下拉面板、托盘菜单统一走主题色)。
Theme 的 350+ 处引用全部集中在 Theme.X,所以做成双调色板只需一个开关:
- 浅色保持原有观感(输入底改极浅灰:纯白面板上的纯白输入框等于看不见边界)
- 深色取自《游戏启动器》:底色
#0A0C12,强调色紫→蓝→青(#8A7CFF → #4DA3FF → #3DD6FF) - Windows 11 下调用
DwmSetWindowAttribute让窗口圆角 + 标题栏/边框跟着主题着色 (CORNER_PREFERENCE=33/CAPTION_COLOR=35/TEXT_COLOR=36/BORDER_COLOR=34, 旧系统调用失败会被吞掉,自动回退系统默认外观) - 入口:设置 → 界面主题。切换需重启程序(部分控件在构造期就固化了配色),
保存后弹框可选「立即重启」。配置写在
ui.theme,老配置由InsertKeyBlock自动补键。
- 页面标题不再只躺在系统标题栏里。新增
HeadBox:大标题 + 副标题 + 细分隔线,每页一个 - 系统标题栏文案简化为
Fluxion v2.6.0(页面名交给页内标题头承载) - 标题头高度固定,副标题更新只重绘不参与布局 —— 不碰 2.5.x 修好的"点卡片跳回顶部"那条链
实测(2026-09-14)对用户库里 4 个拿不到封面的 Steam appid 做多主机多路径穷举:
appid 2483190 library_600x900 404 / header 404 / capsule 404 … library_hero 200 (250KB) ← 有!
appid 3527290 同上 → library_hero 命中 (351KB)
appid 3548580 同上 → library_hero 命中 (219KB)
appid 4262610 全部主机 × 全部路径 均不可用(该 appid 在 CDN 上确实没有任何资源)
根因:旧代码只试了两条路径(library_600x900 → header),没有的永远没有。
改为按"竖版优先"依次尝试 7 条官方路径。
另外两项:
- 横版图不再硬裁:比例与 2:3 相差过大(横版头图 / 宽幅 hero / 方形 logo)时, 改用模糊铺满做底 + 完整图居中(Spotify / Playnite 的通行做法), 解决"封面有点违和、大小不匹配";比例接近则仍直接裁切填满
- 生成卡统一色系:无封面时从固定的 6 组渐变(紫→蓝→青家族,按名字哈希取一组)里生成, 配斜向高光 + 底部压暗 + 居中图标 —— 不会 16 张卡五颜六色各自为政
- 手动兜底:卡片右键新增「设置封面…」(本地任意图片,拷成
<游戏名>.png优先使用)、 「重新下载官方封面」、「打开封面目录」。「获取封面」也会在库内 appid 失败后按名字搜一个替代 appid 再试。
新增探针 StyleProbe(与源码同编,可访问 internal 类型),把真实 MainForm 的
每一页渲染成 PNG 再逐张核对。本版据此修掉两个"编译通过但观感不对"的问题:
- 复选框文字被省略号截断(自绘方框比系统字形宽,预留宽度不够)
- 浅色下输入框与白卡片分不清(
Field从纯白改极浅灰)
实测:浅色 / 深色 × 游戏库 / 仪表盘 / 设置页 四张渲染图逐张核对通过
封面多路径:4 个修复目标中 3 个成功(第 4 个 CDN 确实无资源 → 生成卡 + 手动兜底)
用户反馈三条:侧栏出现黑框、文字重影、"像叠了好几层"、封面参差不齐、标题重复 + 旁边多了条滚动条。
侧栏用的是 FlowLayoutPanel,它的 AutoScroll 默认为开。窗口偏矮(或侧栏内容变高)时,
它会在侧栏右侧冒出一条竖滚动条 —— 就是截图里"旁边那条"。侧栏本来就不该滚动,直接:
flow.AutoScroll = false;
flow.HorizontalScroll.Visible = false;
flow.VerticalScroll.Visible = false;矮窗口(520px 高)离屏渲染复验:侧栏再无滚动条。
这类现象是"控件自己的矩形没被画满、留下上一帧残留"。自绘控件确实必须遵守一条纪律:
一旦设置
UserPaint + AllPaintingInWmPaint,WinForms 不再帮你擦背景(WM_ERASEBKGND被跳过), 控件必须把自己的整块矩形画满 —— 包括圆角之外那点角落。
所以本版给 9 个自绘控件(FlatBtn / NavBtn / RoundField / RoundCombo / RoundCheck / HeadBox / Sec / GameCard / CoverBox)统一在 OnPaint 开头铺满自身矩形,并加上 ControlStyles.Opaque
(自己铺满就不需要父级再画一遍,同时减少闪烁)。
但要说清楚:我做了反向测试(故意移除 NavBtn 的背景填充再渲染),
离屏探针并没有复现出黑框 —— 因为 DrawToBitmap 走 WM_PRINT,仍会铺一次背景,
这类重绘撕裂它抓不到(这是探针的真实盲区,写在这里免得以后误信)。
所以这一条是"按正确做法落地",不是"已验证的根因"。同时补了两处能确认的重绘加固:
- 窗体与
root / main / side / foot / content容器统一开启双缓冲(Panel 的DoubleBuffered是 protected,通过反射设置)—— 拖窗、切页、缩放时的撕裂残影会明显减少 - 侧栏不再有滚动条(见 ①)
如果装上 2.6.1 后仍能复现:请再截图,并顺便告诉我"鼠标动一下/缩放一下窗口后是否消失" —— 能消失就是重绘撕裂,不消失就是布局或绘制错误,两条线的查法完全不同。
v2.6.0 的生成卡是亮青色渐变 + 浮在中间的小图标,跟真实盒装封面(基本都暗调)摆在一起 就显得空、像贴纸。v3 改成:
- 底色换成一族深色渐变(深靛/深蓝/深青/深紫,低明度),按名字哈希取一组 —— 同款游戏颜色恒定
- 中央品牌色辉光把图标"托"起来
- 图标画成 18px 圆角的磁贴(占宽 62%),带投影与 1px 亮描边 —— 看起来像真正的应用磁贴
- 斜向高光 + 底部压暗收边
封面来源现在是三级回退:
| 级别 | 来源 | 说明 |
|---|---|---|
| ① | Steam 官方 CDN | 按 appid 试 7 种官方尺寸,实测直连可用 |
| ② | 按名字搜 Steam appid | 走 steamcommunity,需要代理 |
| ③ | 联网搜图兜底 | Bing 图片搜索,只取竖版大图;会访问任意 https 图片站 |
实现要点:
- Bing 结果里图片直链的形式实测是
"murl":"https://…"(JSON 被 HTML 转义过)。 用这个 HTML 实体当定界符,源码里连一个转义双引号都不用写 —— v2.6.1 头一版就是在这儿 写坏了正则,编译器报CS1010 常量中有换行符。 - 三重过滤:域名黑名单 + 最小尺寸(500×640)+ 竖版比例 0.58~0.78。 初版放宽到 0.95,结果"无畏契约"收到一张三格拼图宣传图 —— 收紧后这类东西被拦住。
- 入口:卡片右键「联网搜寻封面」单款重抓;「获取封面」批量时作为最后一步; 「重新下载官方封面」也带这一步兜底。
实测(本机 16 款库):5 款原本没封面的游戏全部拿到真实主视觉 —— 原神(官方 600×900 竖版 key art)、绝区零(1.4MB)、鸣潮、卡拉彼丘、无畏契约。
页内标题头(HeadBox)显示当前页名,侧栏高亮同一项 —— 这是导航的标准形态,不是重复渲染。
真正会看起来"重复/重影"的是 ② 那个重绘问题。若确实希望页内标题头消失,说一声即可去掉。
用户四条反馈:封面明显不适合做封面、左右不居中、边缘与字体锯齿严重、多处衔接割裂,
并要求继续参照 <个人目录>\GameLauncher。这一版按它的 CSS 逐条对齐。
启动器的 .card 是:封面铺满整张卡(object-fit: cover)→ 底部渐变遮罩 → 名称与平台压在图上。
我们原来是「上方封面 + 下方两行文字」的两段式 —— 两段之间天然有条接缝,整排看过去必然割裂。
现在改成:
| 项 | 做法(对应启动器) |
|---|---|
| 封面 | 铺满整卡、cover 语义裁切(.card-img) |
| 名称 | 压在封面底部,最多两行,超出省略(.card-name) |
| 平台 / 状态 | 彩色小方块 + 「平台 · 状态」一行(.card-plat::before) |
| 遮罩 | 底部 52% 高的深色渐变,保证任何封面上文字都读得清(.card-shade) |
| 交互 | 悬停轻提亮 + 强调描边 1.6px;选中 2.6px;★ 收藏角标 |
| 结构 | 整张卡只有一个绘制面(无子控件)—— 顺带少了一类子控件重绘问题 |
尺寸从 132×198 提到 148×222(仍是 2:3),网格间距 14px。
启动器的 #topbar 是 space-between:左搜索框、右排序,外面没有面板。
现在游戏库页也按这个来,并给 Sec 加了「工具条模式」:标题传空字符串即为工具条 ——
不画面板底与描边、不留标签列缩进;新增 Sec.Bar2(左控件, 右控件组…) 实现两端对齐。
卡片区同样不再套面板(启动器就是「标题 + 裸网格」)。
v2.6.0/2.6.1 对横版图用「模糊铺满 + 完整图居中」,结果上下两条模糊带非常显眼 ——
用户原话"这个明显不适合做封面"。现在一律按 object-fit: cover 裁切填满,
横版图纵向取景 42%(关键视觉通常偏上,取正中容易切掉角色头)。
两个独立的根因:
- 封面圆角:之前用
Graphics.SetClip(path)裁切 —— 那是区域裁剪,不做抗锯齿,圆角边缘就是硬锯齿。 改为FillPath + TextureBrush把圆角烘焙进封面位图(边缘带 alpha 过渡),绘制时直接 1:1 贴图。 - 文字:标题头等处用的是
Graphics.DrawString(GDI+ 默认渲染,明显发糊)。 改为TextRenderer.DrawText(GDI,ClearType 亚像素抗锯齿)。4 倍放大实测:字缘有正常的亚像素过渡,不再是硬边。
- 侧栏与内容区之间的 1px 硬分隔线直接去掉(底色本身已有区分)
- 标题头、页脚顶边:用 3 段
ColorBlend的左淡出渐变线替代整条硬线 - 页面标题头文字改用 GDI 渲染,与页面观感统一
Sec.Bar2右侧控件组用的是FlowLayoutPanel,首次排版时PreferredSize可能还没算出来, 高度为 0 → 整组控件"隐形"(表现:筛选下拉全不见了)。改为显式给高度。- 卡片
Margin被设成 0:CellW 里假设了 14px 间距,于是卡片贴在一起、每行数量也算错, 连带"居中"失效。已恢复Margin = 7(2×7 = 14 与 CellW 一致)。
离屏探针新增 geom 模式,直接打印网格真实几何(比看截图靠谱):
grid Left=18 Width=862 ClientW=862 Padding.Left=26 CellW=162 Count=16
perRow=5 leftover=52 期望 Padding.Left=26 -> 卡片实际占 [33, 829](左右各留 33px = 居中)
Core.cs / Lib.cs 是 CRLF,Ui.cs 是 LF。用 newline='' 读写时我插入的 \n
会和文件原有的 \r\n 混在一起,导致后续多行锚点全部匹配失败(本轮为此浪费了两次来回)。
以后跨文件做多行替换前,先把换行统一再处理,写回时按原风格还原。
- 工具条白补丁:Sec 的标签/按钮流底色写死 Theme.Panel(白),在工具条模式(透明、页面灰底)下就是一块块白补丁——按模式区分(盒式=Panel / 工具条=Bg)。
- 卡片"上下两半"三连根因:①卡片遮罩 52% 高 + α234 太重 → 降到 40% / α208;②生成磁贴自带底部压暗与卡片遮罩叠加、图标正好压在遮罩中线上 → 去掉自带压暗、图标上移、缓存升 gen4;③steam.jpg 混着横版 library_hero/header(Forza 是风景照横幅)→ 新增 tools\cover_refetch.py:官方竖版优先 → Bing 竖版(0.58~0.78)兜底,实测修复 Forza 等;PEAK / Chill 无竖版资源,退回重新设计的生成磁贴。
- 全息卡面:tools\cover_holo.py 用 create-holographic-card skill 的材质资产(spectral-lines / pearl / star-holo / micro-grain)+ material-api 配方(高饱和→彩虹 / 低饱和→银),把烫箔/星闪/眩光静态烘焙进封面;原图备份 covers_originals\。
- 新程序图标:闪电 + GPU 芯片,紫→青渐变(AI 生成、裁水印、多尺寸 .ico);exe(/win32icon)与安装包同步,旧图标备份 icon\icon_old.ico。
用 redesign-existing-projects skill 的流程对 7 个页面逐页离屏渲染审计(浅色+深色),修复清单:
- 深色模式白色滚动条(最扎眼的"抠图"残留):uxtheme
DarkMode_Explorer主题把 Panel / ListView / RichTextBox / ListBox 的原生滚动条和表头一起染黑(Win10 1809+,旧系统静默回退)。实现在Theme.ScrollThemeTree,句柄创建即染色。 - 性能优化页 ListView:FixedSingle 黑框 → 无框、字号 9→9.5(行距更松)、深色下表头/滚动条随主题。
- 设置页代理输入框:原生方角 TextBox → RoundField 圆角输入框,与全套控件统一。
- 实时监控页空态:三张曲线图无数据时显示「等待采样…」(原来只有三条淡线像没画完);日志框去横向滚动条 + 「暂无日志」占位文字。
- 侧栏底部数据路径:
%ProgramData%字面量 → 真实路径两行折行(C:\ProgramData\…\ + Fluxion)。 - 方法论沉淀:编译通过 ≠ 观感正确,全部改动以
tools\ui_snapshot.py的 14 张离屏渲染逐页目检确认。
- 两道杠真凶(抓了三版才定位):
GameCard遮罩的LinearGradientBrush画刷矩形只有底部 40%,FillPath却填整卡路径 —— GDI+ 画刷默认WrapMode.Tile,把遮罩渐变在卡片上部周期性平铺成两道半透明暗杠。修法一行:WrapMode.Clamp。同款问题在GradientCard斜向高光(画刷矩形 ≠ 填充矩形)一并修掉。 - 方法论教训:这个 bug 藏了三版,因为离屏渲染里它看起来"像封面本来就是深色下半"。破案靠的是渲染卡片 vs 源图并排比对(
ui-snapshots\debug_cs2_compare2.png)—— 比对一做,杠不在源图里立刻实锤是渲染层。 - 封面来源治理:新增
SaveCoverBytes竖版门禁(<400x560 或比例超出 0.50~0.85 范围直接拒绝写入),任何路径都不能再用方图/横图顶掉好封面;tools\cover_refetch.py支持按标题强制重抓。 - 全息加工 v2:v1 把 spectral-lines(横向光谱线)材质烙进封面 = 缩略图上的条纹源;glare 用 point(max(0,v-120)) 产生硬阈值斜边。v2 改为缩略图友好配方(珍珠光泽平滑 10% + 平滑眩光 10% + 底部补偿),18 张已重烙,原图备份
covers\_originals\。 - 工具条白角:RoundField / RoundCombo 的
BackColor写死 Panel(白),在透明工具条上四角露白 →SetCorner(contentBg)按所在分区取色。 - PEAK / Chill with You / Wannabe Galgame God 无官方封面:appmanifest appid 核实无误,Steam CDN 7 路径 × 4 主机全 404,本地
appcache\librarycache只有 32px 图标(0 字节占位)—— Steam 自己就没给这三款下发封面图,保留设计感生成磁贴;有社区图需求可右键「设置封面…」手动指定。
作者更新到 0.3.0,三个实质变化直接改变了我们之前的结论:
| 变化 | 内容 |
|---|---|
| 回归代理模式 | native(自建 NGX host)兼容性差,0.3.0 改回代理 DLL 内嵌未修改的原厂 DLSS-G 运行库,只拦截 nvngx_dlssg.dll 的加载 → 游戏侧调用不变,跑的是真 DLSS 帧生成(不是 XeFG 转译) |
| 运行库 310.9 + 6X | MaxGeneratedFrames 上限 3→5(4X→6X),Dynamic MFG 游戏可跑到 6X |
| 官方提供 d3d12 入口 | 供替换注入\ 新增 d3d12.dll / dbghelp.dll(各 17.5MB),附作者按游戏的建议表(绝区零 d3d12、鸣潮 version/dxgi、燕云十六声 version→dxgi) |
包真实性核验:version.dll SHA-256 = a22d2453f25d7df3…(与作者 README 声明的 310.9 版逐位一致);两个代理的签名者均为 CN=DLSSG for SM86 (self-signed),指纹 85BA6676…,与 README 声明一致(自签名 = 不提供默认信任,SmartScreen 仍会提示,属性正常)。
工具侧整合(本版新增):Dlssg030 类 + 帧生成页新区块「DLSS MFG 0.3.0 · 真 DLSS 多帧生成(代理模式)」
- 部署 = 按游戏选入口(绝区零
d3d12.dll/ 鸣潮dxgi.dll/ 其它version.dll)+ 复制dlssg_sm86.ini与nvngx_dlss*运行库;覆盖前自动备份游戏自带件 - 卸载 = 恢复备份、删除本方案新增文件
- 与 XeSS 方案互斥守卫:已装 XeSS 的游戏点 0.3.0 部署会被拒绝并提示先卸载(反之亦然)
- 资源包:
%ProgramData%\Fluxion\dlssg030-pack\{common,alts}(约 164 MB,含 6 个入口代理)
绝区零已实测换装:卸载 XeSS 套件(备份 backup\zzz_xess_20260915)+ 部署 0.3.0(d3d12 入口)+ 游戏自带 nvngx 备份(backup\zzz_game_nvngx_20260915)。鸣潮维持 XeSS 方案不变,可随时用工具一键切换。
日志位置:<游戏目录>\dlssg_sm86\logs\loader_<pid>.jsonl(INI [Logging] Level 默认 1 只记错误,排查改 2/3)。
用户截图:「切全屏后无法选下面的游戏了」。用新增的 hit 模式探针按"先窗口→再全屏→再退回"
的真实操作顺序复现,拿到硬证据:
== ① 窗口 1180x1000 Pg 960x909 AutoScrollMinSize={0,1213} DisplayRect=943x1213 滚轮可达
== ② 改成 1920x1080 Pg 1700x989 AutoScrollMinSize={0,741} DisplayRect=1700x989 (内容装得下)
== ④ 退回 1180x1000 Pg 960x909 AutoScrollMinSize={0,1213} DisplayRect=**1686x892**
第 ④ 步是病灶:DisplayRect.Width=1686 而客户区只有 960,Height=892 正是客户区高度
—— WinForms 认定"没有东西要滚",于是竖滚动条消失(VScroll.Visible=False,
尽管内容 1213 > 视口 892),AutoScrollPosition 也设不动。下半页既看不到也点不到。
来源是 LayoutOnce 里那句 AutoScrollMinSize = new Size(0, 1) 的"先复位":
它会让 WinForms 用当时的子控件并集去重算 DisplayRectangle,而那一瞬间子控件还是全屏布局
(宽 1636)留下的旧几何 → 缓存下 1686×892,之后再没人纠正它。
修法不是再补一层矫正,而是不再把滚动交给 WinForms:
AutoScroll = false,Pg自己持一个VScrollBar(Dock=Right);LayoutOnce把子控件整体放在y - ScrollY(子控件是真的被移动的,命中测试自然跟着走);SyncScrollRange()按"内容总高 vs 视口高"给滚动条定价;Reflow()里那圈PerformLayout()矫正整段删掉(它存在的唯一理由就是刷 WinForms 的缓存)。
顺带修掉一个坑:ScrollBar.Value 的 setter 越界时是抛 ArgumentOutOfRangeException、
不是夹紧 —— 传 int.MaxValue 会被 catch 吞掉,滚动位置纹丝不动。SetScrollY() 现在自己夹紧。
验收(探针 hit 模式,同一会话跑完五个阶段):
| 阶段 | ScrollY | 命中失败 | 视口外 |
|---|---|---|---|
| ① 窗口 1180×1000 | 0 | 0 | 1 |
| ② 切全屏 1920×1080 | 0 | 0 | 0 |
| ③ 全屏下滚到底 | 0(内容装得下,正确) | 0 | 0 |
| ④ 退回 1180×1000 | 0 | 0 | 1 |
| ⑤ 窗口下滚到底 | 304(= 内容 1213 − 视口 909) | 0 | 0 |
用户要求"参照或复刻 D://DLSS5//DLSS 5 Swapper"。从它的 resources/app.asar 解出
src/renderer/style.css(137 KB)与 index.html,把 :root[data-theme=light|dark]
两套变量逐项对到 Theme 上:
| Swapper 变量 | 本工具 | 浅色 | 深色 |
|---|---|---|---|
--accent |
Theme.Accent |
#6CC10A | #6CC10A(同一色相) |
--bg-1 |
Theme.Bg |
#EEF1F4 | #05070A |
--panel |
Theme.Panel |
#FFFFFF | #12171F |
--panel-2 |
Theme.Hover |
#F1F5F8 | #1B222C |
--bg-3 |
Theme.Subtle |
#F7F9FA | #0C1016 |
--text / --muted / --dim |
Text / TextDim / TextFaint |
#1B2229 / #6B7885 / #93A0AD | #F0F4F9 / #9AA7B6 / #626E7C |
--radius / --radius-sm |
RCard·RPanel / RBtn·RField |
18px / 12px | 同 |
同时把 FlatBtn 里写死的蓝(按压 #0654B2 / 悬停 #1476E2)、监控页两条紫色曲线
(Color.FromArgb(130,80,223))、DWM 标题栏与边框色全部收到主题 token 上,
并改掉设置页里那句过时的说明(还写着"底色 #0A0C12、紫→蓝→青、14px/10px")。
设计语言两条约定的原文(来自它的 CSS 注释):强调色浅深共用同一色相;
深色底是"近黑 + 每层抬一级"(#05070A → #0C1016 → #12171F),
旧实现把整屏压在一个灰蓝平面上、什么都看不出层级。
tools/ui_snapshot.py 新增 hit 模式(StyleProbe.exe light hit 3 1180 1000 1920 1080):
先按窗口布局、再改成全屏尺寸、再退回,每阶段用 WinForms 自己的
GetChildAtPoint 逐层问"这个点最深处是谁",断言命中控件就是那张卡。
7 页 × 浅/深共 14 张离屏渲染全部 rc=0。
用户截图三张,逐个查实:
uxtheme 的 DarkMode_Explorer 对独立滚动条控件不生效(只对 Panel/ListView/TextBox 那类有效),
所以 2.10.0 新加的原生 VScrollBar 在深色下就是一整条白底。既然滚动已经自己管了,
滚动条也自绘:新增 FlatScroll(10px 细条 + 圆角滑块 + 悬停变亮 + 拖动/点轨道翻页),
取值对齐 DLSS 5 Swapper 的 --scroll(浅色 rgba(16,24,32,.20)、深色 rgba(255,255,255,.13))。
ListView 的表头是单独的 SysHeader32 子窗口,只给 ListView 本身设主题它不跟着变。
必须在句柄创建后单独染一次:SetWindowTheme(SendMessage(lv.Handle, LVM_GETHEADER, 0, 0), "DarkMode_Explorer", null)。
新增探针 capture 模式(GetDC + BitBlt 直接读窗口表面)复现:
1180x1000 → 1744x537(用户那次 1744×537)之后,卡片网格在被压扁的中间态位置画过一帧,
那一块之后再没被失效,于是留在表面上。
⚠️ 这正是为什么此前所有修正都"看不到问题":DrawToBitmap会强制整棵树重绘, 残影类 bug 在它面前是隐形的。要验这类问题必须读真实表面。
根因:这套自绘控件族(Pg / Sec / CardGrid / GameCard 全是 Opaque + UserPaint +
AllPaintingInWmPaint)父容器不擦背景,孩子移动时留下的旧像素没人负责擦;
而 WinForms 的失效区在连续 resize / 最大化那一帧会被系统重绘吞掉。
修法:MainForm.OnResize 里用 BeginInvoke 等布局落定,再 Invalidate(true) + Update()
把整棵立刻刷一次(Update() 是同步刷,光 Invalidate 不够)。
验收:同一组 capture 序列重跑,顶部那条卡片残影消失;深色 p1 表头变深、深色 p3 滚动条变细变深。
用户截图指出「最大生成帧」下拉只有 1 · 2X / 2 · 3X / 3 · 4X。查证结果:用户是对的,工具错了。
作者 0.3.0 的 README 原话:
310.9 运行库新增 6X(
MaxGeneratedFrames上限由 3 提到 5)。
| 发布包 | 内嵌运行库 | 帧生成上限 | version.dll 大小 || dlssg-release-x64-310.9 | 310.9.1.0 | 6X | 17,529,120 |
出厂 ini 注释:
Frame-generation multiplier ceiling: 5 = up to 6X, 3 = up to 4X. … Clamped to what the bundled runtime supports: 6X on the 310.9 build, 4X on the 310.1 build.
本工具 dlssg030-pack\common\version.dll = 17,529,120 字节(这是 0.3.0 时代量到的数,只在这条历史记录里成立;现在哪一版、多少字节以帧生成页「运行时状态」那行与日志里的实测值为准,见 5.6),即 310.9 → 本来就能 6X,
但 UI 把下拉写死成 3 项,把 6X 挡在了界面之外。
改的三处(外加两处顺手纠错)
| 位置 | 原 | 现 |
|---|---|---|
Ui.cs 下拉项 |
1·2X / 2·3X / 3·4X |
… / 4·5X / 5·6X(5 项) |
Ui.cs 索引夹取 |
Math.Min(2, …) |
Math.Min(4, …) |
Core.cs 读配置 |
原样接受任意值 | 夹到 1..5(老配置里的越界值会让下拉索引越界) |
Core.cs 字段注释 |
1/2/3 → 2X/3X/4X |
1..5 → 2X..6X(上限由运行库决定) |
| 使用须知文案 | 「8GB 显存建议 2X」 | 删掉。作者实测:「帧生成的显存增量只随输出分辨率变化,与倍率无关(2X 与 6X 占用相同)」——旧文案是错的 |
新增 Dlssg030.SetMaxFrames(gameDir, n):0.3.0 的 INI 格式与旧版不同(多了 Enabled /
Optimized / Preset / Directory / Mode 这几个键),所以不能用旧版 BuildIni() 覆盖,
否则会丢键。该方法只改 MaxGeneratedFrames 那一行,其余原样保留;键缺失时插到 [FrameGeneration] 之后。
DoApplyFgCfg() 现在会同时对 0.3.0 处于部署态的游戏调用它,日志里逐游戏回执。
验证(两个探针,均 ALL PASS)
tools/mfg_probe.cs—— 沙盒里造Wuthering Waves Game\Client\Binaries\Win64\(放一个假 exe 就能让XeMfg.Detect认作鸣潮),真跑SetMaxFrames:5→2、2→5、越界 99→5 / 0→1、 键整行缺失时插入位置正确、ini 不存在给友好提示、非支持目录被拒; 6 组 24 条断言全过,且每次都断言 0.3.0 的 7 个独有键一个不丢。tools/mfg_items_probe.cs—— 只读反射cbMaxFrames,断言下拉项恰好 5 项 且为[1 · 2X][2 · 3X][3 · 4X][4 · 5X][5 · 6X]。 故意不调用DoApplyFgCfg()—— 那会真往游戏目录写 ini,拿用户配置做实验不可接受。
两句要澄清的话(此前说错)
- 「跨代兼容版 NR 模型要你自己去 RenoDX 拿」—— 说错了。
C://ProgramData//Fluxion//xess-pack//wuwa//nvngx_dlssnr.dll的 SHA-256 =E67DEE20…(ShortFuse 跨代版),工具自己的资源包里就是这一份, 与鸣潮游戏根目录那份逐位一致。所以大概率是本工具部署时放进去的。 - 放开上限 ≠ 游戏一定给 6X。 上限只是天花板,实际倍率由游戏自己的帧生成菜单决定; 作者也写明「强制 6X」的做法「逐游戏、依赖游戏侧闭源插件、较脆弱」。诊断页已加提示行说明这一点。
用户第三次反馈同一处:全屏后游戏库页顶部横向出现一条约 11px 高的封面条(截图里能认出 FORZA 等封面),
在标题与搜索框之间,且不消失。先承认一件事:上一版我说"修好了"是错的 —— 当时我用的是
DrawToBitmap 渲染验收,它会强制整棵树重绘到一张新位图上,残影/错位类问题在它面前是隐形的。
这一轮把方法换掉了,并如实说清结论:
| 手段 | 结果 |
|---|---|
读真实窗口表面(GetDC + BitBlt,探针 capture 模式) |
我这边顶部干净 |
| 差分测试(同一状态抓两次表面,中间强制整树重绘,逐像素比对)9 个时序:窗口→最大化、最大化→还原→再最大化、最小化→还原、先最大化再切页、启动即最大化、一步跳全屏、先压成 400x300 再跳、在别的页切全屏、以及基线 | 全部 0 差异 |
| 摆放矩阵 6 种尺寸(含你窗口的实际 1752×566):量网格的 Pg 坐标 Y 与高度、卡片有没有跑到搜索框上方 | 全部正常(网格 Y=249、高=476、越位卡片 0) |
结论:我怀疑触发条件是"分辨率/DPI 与我这台不同",但在本机始终未能复现(我这边最大只能到 1920×1009)。
但你截图里的东西不是"画完没擦"的残影 —— 已查明 Sec / HeadBox 的 OnPaint 本来就铺满整块矩形(第 932/1269 行),
所以那条带只可能是网格控件本身被摆到了错误的 Y、且高度只剩十几像素:子控件会被裁到父容器范围内,
露出来的正好是每个封面的顶端一条 —— 与截图完全吻合。也就是说,这是布局卡在了错误状态,不是绘制问题。
Pg.Reflow() 有一道早退闸,为了避免"点一下卡片就跳回最上面"而加:
if (lastCount == secs.Count && lastW == ClientSize.Width && lastTotal == ContentHeight()) return;问题在于 lastTotal 等三个缓存数是 LayoutOnce() 跑完之后才写入的。万一某次布局在中途被打断
(或某个分区高度被算成 0),缓存可能已经写成"最终值"而控件还停在坏位置上 ——
此后每次 Reflow() 都命中早退闸,坏布局永久留在屏幕上。这正好解释"出现后不消失"。
- 早退闸从"盲信缓存"改成"缓存一致 且 几何正确":新增
Pg.GeometryLooksRight(), 逐个核对 head/sec 的Top是否等于算出来的累积位置、高度是否塌陷(head < 20px / sec < 30px)。 不通过就强制重排,并写一条[布局自检]日志(含 Pg 尺寸、内容高、每个分区的高:位置、ScrollY)。 LayoutOnce对塌陷高度就地纠正:分区高度小于 30px 时按最小高度重设并重跑一次DoLayout()。OnResize改成两遍「重排 + 整树重绘 + 自检」(第二遍排到下一轮消息之后)—— 2.10.1 只做了一遍,而"布局落定"可能比那次重绘更晚。另加MainForm.CheckLayoutHealth(), 只在几何异常时写日志,便于在真机上留证。
| 造法 | 结果 |
|---|---|
| A) 只把分区搬到 y=18(高度不变 → 三个缓存数全都一致,旧代码必然早退卡死) | 破坏后 Top=18 → Reflow() 后 Top=245(期望 245)、网格 Top=4(期望 4)→ PASS |
| B) 把分区高度压成 11px(复刻截图那条带的尺寸) | Reflow() 后 H=482(期望 ≥30)→ PASS |
| C) 再全量校验:卡片有没有落在网格矩形之外 | 越位 0 张 → PASS |
回归:残影差分 9 个时序全部 0 差异;摆放矩阵 6 尺寸全部正常;7 页 × 浅/深 14 张渲染全过。
新版本遇到该状态会在日志里留下一行 [布局自检] ...(含全部几何数据)。
日志位置:%ProgramData%\Fluxion\logs\fluxion_*.log。
把那一行(连同你的触发步骤:是点最大化按钮 / 双击标题栏 / Win+↑ / 还是切换主题之后)
发我,就能定位到具体是哪一次布局被打断的。
用户截图指出帧生成页同时列出「XeSS 多帧生成 · 绝区零 / 鸣潮(已部署 · 鸣潮)」与 「DLSS MFG 0.3.0(未部署 · 鸣潮)」,问会不会冲突。核实结论:不会同时生效(互斥守卫是对的), 但界面文案认错了自己的部署,而且「卸载」会不可逆地删掉用户的 DLSS 5 NR 套件。
鸣潮那套「XeSS 多帧生成」就是本工具自己部署的 OptiScaler 包,不是「XeSS 帧生成转译」:
| 文件 | 游戏目录 | 工具 xess-pack\wuwa |
|---|---|---|---|
| dxgi.dll | 26,116,608 | 26,116,608 | 逐字节相同 |
| nvngx_dlssnr.dll | 165,840,496 | 165,840,496(E67DEE20… 跨代版) | 逐字节相同 |
| nvngx.dll_dlssnr.dll | 151,552 | 151,552 | 逐字节相同 |
而 WuwaFiles 里的 Spoofing/Dxgi=auto + FrameGen/External=true + DLSSG/AmpereMfgUnlock=true
意味着帧生成走的是游戏原生 DLSSG(由 SM86 解锁),不是 DLSSG→XeFG。
包内还含 DLSS 5 神经渲染(NR,位置在超分之后、帧生成之前),日志已实证
ApplyToFinishedPicture: 3600 frames。所以鸣潮这一套本来就同时提供「帧生成 + NR」。
区块标题与部署确认框写的「XeSS 多帧生成 / OptiScaler + fakenvapi + XeSS 运行库 / 鸣潮:DLSSG 进出」 只对绝区零成立,对鸣潮是错的 —— 已按实际构成改写(区块改名为「帧生成方案 A · OptiScaler 注入」)。
XeMfg.Uninstall 对每个目标文件走 if (备份存在) 还原 else File.Delete。
而 xess-pack\_backup 下只有 _backup\zzz\d3d12.dll,根本没有 _backup\wuwa ——
鸣潮部署时游戏里本来没有这些文件,没得备份。所以原实现会直接删掉:
dxgi.dll(26 MB 入口代理)nvngx_dlssnr.dll+OptiScaler\streamline\nvngx_dlssnr.dll(两份 165 MB 的跨代 NR 模型)nvngx.dll_dlssnr.dll(NR 转发器)OptiScaler\dlssg_sm86\dlssg_sm86.dll(15.7 MB SM86 多帧生成运行库)及 OptiScaler 其余组件OptiScaler.ini—— 里面装着调好的Spoofing/Dxgi与[DlssNr]参数
雪上加霜的是:Dlssg030.Install 的互斥守卫原本提示「请先在 XeSS 区块点「卸载」,再部署 0.3.0」——
跟着做就会把 NR 弄丢,而 0.3.0 的包里没有 nvngx_dlssnr.dll,只提供帧生成。
也就是说那条提示实际是在劝用户做一次功能降级。
- 卸载改为「移入隔离区」:新增
XeMfg.Retire(),把无备份可还原的文件File.Move到xess-pack\_removed\<kind>-<时间戳>\,按原相对路径存放, 回执里直接给出隔离区路径 —— 误点一次也能原样拷回。 OptiScaler.ini视为用户配置:卸载时原位保留(没有入口代理它不会被读取), 部署时若已存在则不覆盖(资源包里那份是出厂值Dxgi=auto/DlssNr=auto, 盖上去会让帧生成选项再次消失)。- 三处文案改成说真话:区块 A 标题与说明、区块 A 的部署/卸载确认框(列出会移走什么)、 以及 0.3.0 的互斥守卫(明确写出「0.3.0 只提供帧生成、不含 NR,换成它属于功能降级」)。
探针 tools/uninst_probe.cs —— 全程在 %TEMP% 沙盒里造一个假鸣潮目录(只放一个 stub exe
就能让 XeMfg.Detect 认作鸣潮),绝不碰用户真实游戏目录。16 条断言 ALL PASS:
| 组 | 断言 |
|---|---|
| 卸载 | OptiScaler.ini 原地保留且内容未变;dxgi.dll / nvngx_dlssnr.dll 已不在游戏目录;IsInstalled 转 false |
| 隔离区 | 已创建;含 dxgi.dll、含 nvngx_dlssnr.dll;保留了 OptiScaler\streamline\nvngx_dlssnr.dll 这样的原相对路径;不含 OptiScaler.ini |
| 部署 | 覆盖前先存在的 ini 未被出厂值覆盖(53 → 53 字节,内容逐字相同);回执里说明了保留 |
| 全新目录 | ini 不存在时仍会正常铺入(不影响首装) |
7 页 × 浅/深渲染回归通过;帧生成页新增的三行说明不破版。
用户反馈两点:绝区零设置里没有 DLSS 选项(断言 0.3.0 无法实现);鸣潮用方案 A 进不去。
xess-pack\_removed\ 下出现了两份不是我建的目录:
| 目录 | 含义 |
|---|---|
wuwa-20260916-002133 |
用户 00:21:33 点了鸣潮的「卸载」(内含 dxgi.dll / nvngx_dlssnr.dll / OptiScaler\ / Licenses\) |
zzz-20260916-002933 |
用户 00:29:33 点了绝区零的「卸载」(内含 fakenvapi / libxess / libxess_fg / libxell / Remove_OptiScaler.bat) |
也就是说:是工具自己的提示把用户引到这条路上的 —— 0.3.0 部署被互斥守卫拒绝时,原来那句 「请先在 XeSS 区块点『卸载』,再部署 0.3.0」用户照做了。(2.10.4 加的隔离区机制正好接住了这次事故, 文件一个没丢,已全部取回。)
它的 DLSS / 帧生成选项本身就是方案 A 的显卡名伪装换来的。 撤掉方案 A 之后,绝区零看到真实的 RTX 3060 Ti,于是判定不支持、设置里干脆不显示 DLSS。
而 0.3.0 完全不负责伪装。把它的出厂 dlssg_sm86.ini(2099 字节)整份读出来,只有:
[General] Enabled=1
[FrameGeneration] Optimized=1 / MaxGeneratedFrames=5
[Compatibility] Preset=Auto
[Logging] Level=1 / Directory=dlssg_sm86\logs
[Runtime] Mode=Bundled / CacheDirectory=
—— 一个 spoof 项都没有;README 的硬件段也只写「GPU:RTX 30 系列(SM86)」。 0.3.0 只做一件事:让 NGX 能在 30 系上创建帧生成,前提是游戏自己已经显示出并请求了帧生成。
所以「0.3.0 无法实现」这个判断是对的,但原因不是它坏了,而是它不提供绝区零最需要的那个能力。
顺带查出的第二个缺陷:绝区零那份 0.3.0 出厂 INI 被覆盖了 —— 出厂的 2099 字节(带 Enabled=1、
Mode=Bundled、Preset=Auto)实际生效的只剩 261 字节(旧版路径 Dlssg.BuildIni() 的模板),
[General] Enabled=1 等键全丢。
另一条无害的痕迹:绝区零日志里有 DeviceFPManager::CheckInvalidDeviceFpValue, invalid devicefp key is: MIHOYOSDK_GPU_NAME, value is: NVIDIA GeForce RTX 5090 —— 那是伪装时期存下的旧指纹。已搜遍注册表
(HKCU 深度 4 / HKLM 相关子树)没有任何持久化的 5090 记录,属 SDK 自己的历史值。
OptiScaler 日志(00:24:07 启动那次):
[00:24:07] Spoofing.Dxgi: true / SpoofedGPUName: NVIDIA GeForce RTX 5090
[00:24:07] DLSSG.AmpereMfgUnlock: true / AmpereMfgMaxFrames: 3
[00:24:07] AmpereMfgLoader: Router selected: SM86 for GPU: NVIDIA GeForce RTX 3060 Ti
[00:24:07] AmpereMfgLoader: Loading ...\OptiScaler\dlssg_sm86\dlssg_sm86.dll
[00:28:00] NVSDK_NGX_D3D12_CreateFeature Passthrough to native NGX CreateFeature for feature 11 ← 帧生成 feature 建成功
[00:28:05~00:29:15] LibraryLoadHooks::LoadLibraryCheckW dxgi.dll call, returning this dll! ← 只剩刷屏
(00:29:15 之后日志彻底停止 = 卡死那一刻)
配置全对、帧生成 feature 都建成功了,却在之后卡死。原因在同一目录里:还有第二套 SM86 代理 ——
dinput8.dll(15,666,496 B,09-11 22:27),字符串里含 native_ 与 MaxGeneratedFrames,
是工具 09-11「换入口重试」时留下的旧版 dlssg_for_sm86。而 OptiScaler 自己也加载了
OptiScaler\dlssg_sm86\dlssg_sm86.dll(Native 0.2.3)—— 两套 SM86 运行时同时挂在一个进程里。
再加上 00:29 工具刚写回 root dlssg_sm86.ini,等于又给旧代理补上了配置。
| 对象 | 动作 |
|---|---|
| 鸣潮 | dinput8.dll + root dlssg_sm86.ini 移入隔离区 → 只剩 OptiScaler 一套(已验证 dxgi.dll 26,116,608 在位) |
| 绝区零 | 撤掉 0.3.0 的 d3d12.dll,恢复方案 A 全套 13 个文件(d3d12.dll 25,656,288 + fakenvapi + libxess + libxess_fg + libxess_dx11 + libxell + D3D12_Optiscaler + Licenses),保留用户原有的 OptiScaler.ini(Dxgi=true / SpoofedGPUName=RTX 5090 / FGInput=DLSSG → FGOutput=XeFG) |
- 「应用参数」不再覆盖 0.3.0 的出厂 INI:对处于 0.3.0 路线的游戏跳过
Dlssg.BuildIni()那一步 (改倍率交给Dlssg030.SetMaxFrames,它只改一行、保留其余键)。 - 新增
Dlssg030.EnsureFactoryIni():0.3.0 部署完成后检查一次,只要dlssg_sm86.ini缺[General]就用资源包里的 2099 字节出厂版换回去(旧文件备份成dlssg_sm86.ini.bak-oldtemplate)。 - 三处提示改成说真话:0.3.0 的互斥守卫(列出三条"不建议换"的理由,含「0.3.0 不做伪装」)、 区块 A 的说明(点明绝区零的选项来自本方案的伪装)、卸载确认框(写明撤下后鸣潮失去 FG+NR、 绝区零的 DLSS 选项会直接消失且 0.3.0 补不回来)。
用户要求:别再用「卸载」这个说法,而且要在两套帧生成方案之间随时来回切换。
原来的语义确实不对 —— 「卸载」在实现里会移动/删除运行库文件,用户看到这个词自然以为"装不回来了"; 而它也确实会带走 NR 模型与 SM86 运行库(用户已因此误点两次)。改造后:
| 旧 | 新 | 实际动作 |
|---|---|---|
| 部署 / 卸载 | 切换到本方案 / 停放(回到原生) | 切换 = 把别人的入口代理改名成 <入口>.parked.<方案>,把自己的改回原名;一个文件都不删 |
实现(Dlssg.cs 新增 Plan 类):
Plan.OwnerOf(path)—— 按文件名后缀 + 体积双重判定一个 DLL 属于哪套方案 (>20MB = OptiScaler 入口、17–20MB = 0.3.0 入口、15–17MB = 早期dlssg_for_sm86); 不是代理就返回空串,绝不碰游戏自带文件。Plan.Current(gameDir)—— 先看主入口,主入口被停放就扫全部入口名 (dxgi / d3d12 / version / dinput8 / winmm / winhttp / dbghelp),返回opti/030/legacy/none之一。Plan.ParkOthers(gameDir, kind, keep)—— 把"不是目标方案"的入口代理改名停放。Plan.SwitchTo(gameDir, target)—— 目标方案文件已在目录(只是被停放)→ 只改名,秒完成; 不齐才走一次真正的安装。
界面上两处「当前状态」也都改成读同一个 Plan.Current,所以不会出现"两个区块各说各话":
当前:方案 A · OptiScaler 注入(dxgi.dll 槽位) ← 本方案在用
当前:DLSS MFG 0.3.0(d3d12.dll 槽位) ← 切到本方案会把它改名停放
当前:原生(所有代理都已停放) ← 代理已停放,游戏跑原生
验证:tools/plan_probe.cs(_run_planprobe.py 编译运行)在 %TEMP% 沙盒里造
假鸣潮 / 假绝区零目录,真跑切换逻辑,10 条断言 ALL PASS:
| 断言 | 结果 |
|---|---|
方案 A 在用 → Current = opti |
PASS |
切到 0.3.0 → Current = 030,且 A 的入口被改名为 .parked.opti |
PASS |
再切到"原生" → Current = none,入口变为 .parked.030 |
PASS |
再切回方案 A → Current = opti,.parked.opti 改回原名 |
PASS |
| 全程文件总数不变(7 → 7)、没有任何文件消失 | PASS |
只装旧版代理 → Current = legacy(早期 dlssg_for_sm86 也能识别) |
PASS |
绝区零槽位(d3d12.dll)同样可切、可切回 |
PASS |
同时清掉界面上残留的「卸载」措辞(含数据目录说明、0.3.0 的互斥守卫、各条回执)。
一句话选型(用户问的):
两个二游都用「方案 A · OptiScaler 注入」 —— 绝区零只能用它(它的 DLSS / 帧生成选项就是靠这套的显卡名伪装出现的); 鸣潮也用它(同一套同时给「帧生成」和「DLSS 5 神经渲染」,且实测 6X 可用)。 「DLSS MFG 0.3.0」留着备用:它不含 NR,也不做显卡名伪装,换过去等于功能降级。
用户看到两个 B 站视频(BV1Fje56tEKn 绝区零 0.3.0 / BV1cnYy6VETE 0.3.1)后问:
「这个是不是只能给 3A 用」。
结论:不是。0.3.x 与游戏类型无关,只与"游戏自己会不会去请求 DLSS 帧生成"有关。
它做的唯一一件事是拦截 nvngx_dlssg.dll 的加载并换成内嵌的原厂运行库 ——
游戏侧调用不变,所以任何会请求 FG 的游戏都能用。
真正的分水岭是单机 / 网游(作者自己也是这么分的):
| 单机 3A | 网游(绝区零 / 鸣潮) | |
|---|---|---|
| 装法 | 丢 version.dll + dlssg_sm86.ini 进渲染 exe 目录,开箱即用 |
多两步:① 常需改显卡名为 RTX 5090;② 用带数字签名的入口 |
| 作者证据 | README「实测反馈」:黑神话悟空 / 赛博朋克 2077 / FH6 可开 4X;Resonance 在 310.9 下默认 6X | 视频简介原话「NVIDIA GeForce RTX 5090(修改显卡名称,一般网游才需要)」;归档目录名「部分网游需要数字签名才可以使用,单机一般不需要」 |
对用户的绝区零意味着什么:它的菜单里根本没有帧生成选项 —— 卡在第①步(没改显卡名)。
0.3.0 不负责伪装,所以它补不上这一环;而方案 A(OptiScaler)自带 SpoofedGPUName + Dxgi 伪装,
所以绝区零的选项是它换来的。这条已在 2.10.6 的实测里确证过。
0.3.1 的结论:视频简介原话「0.3.1 添加 20 系支持,30 系无其它功能变化,
30 系使用 0.3.0 或者 0.3.1 无区别」。所以本机(3060 Ti)不需要换包 ——
本工具带的就是 310.9 / 6X 那一版。顺带两个前提:视频强调要开「GPU 硬件加速计划」(本工具
运行时状态里已有 HAGS 检测,本机已开启 ✓);装新版要先删旧版 version 与 sm86 文件(部署时自动清)。
工具侧改动:
- 0.3.0 区块标题改为
DLSS MFG 0.3.0 / 0.3.1,正文补四行「适用面」(单机开箱即用 / 网游两道门槛 / 作者实测清单 / 0.3.1 对 30 系无区别)。 - 措辞一致性收口:界面上残留的「XeSS 多帧生成」全部改为 「方案 A 注入」
(卡面短标签、页面副标题、状态栏计数、
XeMfg.ShortTag、XeMfg.Status); 0.3.0 区块里"与 XeSS 方案互斥"改为"与方案 A 互斥"。 - 说明页的"三层工作链路"原先只写了绝区零那种走法,现改为按游戏分述:
绝区零 → 插帧交给 Intel XeSS 帧生成引擎(
FGOutput=XeFG); 鸣潮 → 仍走游戏原生 DLSSG,由 SM86 解锁让它在 30 系上能跑(FGOutput=DLSSG,实测 6X)。
验证:静态检查 PASS、编译 OK、7 页 × 浅/深共 14 张离屏渲染全部 rc=0。
用户纠正 + 两个实测问题:
这个也能给 3A 用的,我看视频就是这么说的,要不然现在这个状况我的 2077 只能开 4 倍帧生成。地平线 6 卡在这进不去游戏。
① 我上一轮的说法没错,但工具根本没给这条路。 XeMfg.Detect() 只认绝区零 / 鸣潮,
其余游戏一律"不在支持列表" —— 选中 2077 / FH6 时 0.3.0 区块只会显示「原生(所有代理都已停放)」,
等于把作者文档里"单机只放两个文件"的那条路堵死了。本轮开放:
Plan/XeMfg.TargetDir支持kind == "":落地目录 = 扫描认定的 exe 所在目录。Dlssg030.InstallGeneric(dir, entry, maxFrames):只放入口 + dlssg_sm86.ini 两个文件, 不覆盖游戏自带的 nvngx(实测 CP2077 的nvngx_dlssg.dll7,607,336、FH6 的 7,499,376 都比包内那份新)。- 界面新增「通用游戏入口(3A 单机)」下拉:
version.dll / winmm.dll / dbghelp.dll / dinput8.dll / dxgi.dll / d3d12.dll(作者alternatives/README.md的 6 选 1);游戏不加载默认入口时换一个即可。 - 方案 A 仍然只对绝区零 / 鸣潮开放 —— 选中其它游戏时该区块会直说原因。
② 真凶:应用参数 把 5 写进了装着旧版代理的游戏 → FH6 卡死。
旧版 dlssg_for_sm86(14.94 MB,内嵌 310.1 运行库)只认 MaxGeneratedFrames = 1..3。
而 DoApplyFgCfg() 里的条件只排除了「0.3.0 部署态」,没有排除旧版代理,于是:
用户在帧生成页把「最大生成帧」设成 5 · 6X 并点「应用参数」→ 工具把
MaxGeneratedFrames=5 写进 FH6 的 dlssg_sm86.ini(261 B 旧模板)→ 代理报
{"event":"configuration_error","message":"Invalid INI integer"}(dlssg_sm86\logs\native_10932.jsonl,只有这一行)
→ FH6 停在加载界面进不去。同一个动作也写到了 CP2077 的根目录(那里不是渲染 exe 目录,无害)。
修法:
DoApplyFgCfg()改成逐游戏先认代理、再决定写什么(Plan.OwnerOf): 目录里没有我们的代理 → 一律不碰(并计数报告);认出来是旧版 → 用新增的Dlssg.BuildIniFor(m, log),上限夹到 3(并在日志里说明"要 6X 请先升级到 0.3.x"); 认出来是 0.3.x → 走Dlssg030.SetMaxFrames(只改一行,保留[General]等键)。Plan.LooksProxy下限 15 MB → 14 MB:旧版代理是 14.94 MB, 按 15 MB 划界会整类漏掉 —— 既认不出它,也拦不住"两个代理同时生效"。Plan.OwnerOf的 0.3.x 阈值 17 MB → 16 MB:0.3.x 入口是17,529,120 B = 16.72 MB, 原来的 17 MB 阈值会让它掉进 legacy(探针新断言抓到的,不是猜的)。
③ 已直接修复的两台机器现场(本次会话内完成)
| 游戏 | 处理 | 结果 |
|---|---|---|
| ForzaHorizon6 | 停放旧版 version.dll(14.94 MB)→ 换成 0.3.x 的 version.dll(17,529,120 / SHA A22D2453…)+ 2099 B 出厂 INI |
生效代理只剩一个,[General] Enabled=1、MaxGeneratedFrames=5 |
Cyberpunk 2077 bin\x64 |
同上,并把同目录的旧版 winmm.dll 改名停放(两个代理同时生效是作者明令禁止的) |
同上;根目录的历史残留 ini 也移走 |
备份一律就地保留(version.dll.bak-<时间戳>、winmm.dll.parked.legacy),可随时还原。
④ 验证:tools/plan_probe.cs 扩到 10 组 20 条断言,全部 PASS,新增三组专门盯这次的坑:
- 14.94 MB 的旧版代理必须被认成
legacy(旧代码认不出); - 通用游戏(假 FH6 目录)从旧版切到 0.3.x:入口换成 17,529,120、ini 换成含
[General]的出厂版、 游戏自带的nvngx_dlssg.dll未被覆盖、旧代理改名为.parked.legacy、还能停放回原生; BuildIniFor(5)必须写出=3(写 5 就是本次事故),BuildIniFor(0)兜到 1。
⑤ 顺带说明 6X 的边界(作者 README 原文口径):上限由游戏侧插件决定 ——
游戏自带较新插件(支持 Dynamic MFG)时,装 310.9 + MaxGeneratedFrames=5 可跑到 6X;
游戏只支持 4X 时,本项目无法把它抬上去。作者实测表里 2077 与 FH6 都在"可开 4X"那一档;
装好后 dlssg_sm86\logs\native_*.jsonl 里的 generated_count 会直接给出答案(3 = 4X,5 = 6X)。
用户三条要求:① UI 有遮挡、② 插件太多希望直接给推荐、③ 解释文字太多挡视线(并顺手找别的 bug)。
DoLayout() 的 KRow 分支里,控件位置写的是
if (it.B != null) { it.B.Left = (it.A == null) ? padX : padX + labelW; ... } // labelW = Theme.S(102)labelW 是固定值 102px,而标签是不透明底色(BackColor = contentBg)。
标题一旦比 102px 长,就会直接盖住右侧控件 —— 用户截图里那个只剩 n.dll 的下拉就是这么来的
(version.dll 左半被「通用游戏入口(3A 单机)」这个长标题糊掉了,不是控件窄)。
修:标签宽度按真实文字量算(Math.Max(labelW, it.A.Width + 8)),控件放不下就缩宽(下限 48px),
宁可窄也不重叠。另外把「通用游戏入口」这一项单独占一行(Block 铺满),彻底避开挤压。
新增区块「方案推荐 · 按游戏类型挑」,两行动态文字由 Dlssg.RecommendLine(DlssgGame) 生成
(档位取自配置里已有的三张名单:二游 / 3A / 竞技,不靠猜):
| 档位 | 推荐 | 理由(原文摘) |
|---|---|---|
| 竞技网游(CS2 / 无畏契约 / 三角洲) | 不建议装(只做电源 / 加速包联动) | 内核反作弊,注入类封号风险自负,收益也不值当 |
| 二游(绝区零 / 鸣潮) | 方案 A · OptiScaler 注入 | 绝区零的 DLSS 选项靠它的显卡名伪装才会出现;鸣潮同一套同时给帧生成 + DLSS 5 NR |
| 3A 单机(2077 / 地平线 6 / 黑神话…) | 0.3.x 通用模式 | 只放两个文件、不需要改显卡名;要 6X 就用自带的 310.9 版并把「最大生成帧」设成 5 |
| 未归类 | 0.3.x 通用模式(可试) | 只拦截 nvngx_dlssg.dll 的加载,装错最多不生效 |
状态栏也补了「0.3.x 通用:N 个」计数;卡片短标签新增 DLSS MFG 0.3.x(通用),
让 3A 游戏装没装成功在列表里一眼可见。
两个方案区块的正文压到 2–3 行,只留"当前状态 + 关键差异 + 与谁互斥";
适用面 / 前置条件 / 6X 边界 / 各游戏实测清单 / 旧版代理上限这些整段搬到「说明」页
的新区块「帧生成方案详解(怎么选 / 前置条件 / 6X 边界)」。说明页里那句过时的
「② 开启选中」也改成了实际按钮名。
| 位置 | 问题 | 处理 |
|---|---|---|
Dlssg030.ShortTag |
3A 游戏装了 0.3.x 在卡片上没有标签(看不见是否成功) | 新增 GenericInstalled() 判据 + DLSS MFG 0.3.x(通用) |
| 状态栏 | 只统计方案 A 的接入数,0.3.x 通用完全没算 | 补 0.3.x 通用:N 个 |
Dlssg030.Status |
3A 游戏点开显示"不在支持列表" | 交由 RecommendLine 给出通用模式结论 |
验证:静态检查 PASS、编译 OK、7 页 × 浅/深共 14 张离屏渲染全部 rc=0。
| 类别 | 已有 | 缺(按性价比排序) |
|---|---|---|
| 库管理 | 多平台扫描(Steam / 注册表卸载项 / 常见目录)、标签收藏、忽略、封面自定义 | 元数据抓取(发行年份 / 类型 / 开发商)、按状态分类(在玩 / 通关 / 弃坑)、多平台账号导入(Epic / GOG / Xbox) |
| 启动 | 双击卡片启动、管理员启动开关 | 每游戏启动参数与环境变量(沙盒)、批量启动一组、全局热键唤出、鼠标边缘触发 |
| 存档 | — | 存档备份 / 还原(最高性价比,且与"反复重装"直接相关) |
| 数据 | 游戏时长、配置导出 / 导入 | 成就记录、游玩历史时间线 |
| 性能 | 实时监控(CPU / GPU / 帧)、性能档位联动 | 游戏内 OSD(帧率 / 帧生成状态)、按游戏自动切换性能档 |
| 其它 | 崩溃日志、错误捕获、深色 / 浅色主题 | 插件 / 脚本扩展、手柄与全屏模式、自动更新 |
结论:最该补的两项是「存档备份 / 还原」与「每游戏启动参数 + 环境变量」 —— 前者直接解决"重装一次就丢东西"的焦虑,后者是 Playnite / Steam 用户的硬需求。
用户反馈三件事:2077 显示 4X 却有 300 帧;绝区零还是没帧生成;FH6 启动不了;并抱怨界面"越优化越乱"。
日志(native_7728.jsonl):max_generated=3、generated_count=3×101 帧 —— 游戏菜单请求的就是 4X
(2077 的 Streamline 插件上限 4X,作者实测表也列在 4X 档)。300 帧 = 基础 ~75fps × 4,4X 在正常工作。
0.3.x 的 6X 只是天花板,游戏不请求就没有;作者原话:游戏仅支持 4X 时本项目无法抬到 6X。
| 证据 | 结论 |
|---|---|
| OptiScaler.log 从未存在(每次游戏启动后都没有) | 代理从未初始化 |
游戏日志 MIHOYOSDK_GPU_NAME = NVIDIA GeForce RTX 3060 Ti(02:40 那次) |
伪装从未生效 |
| 隔离实验:把探针 exe 放进绝区零目录 LoadLibrary("d3d12.dll") → 加载成功且立刻写日志 | dll 本身没问题、路径解析没问题 |
| version.dll / dinput8.dll 在本机被强制解析到 System32(实验证实) | "换入口重试"从来就不可能成功 |
| 02:40 那次游戏启动:方案A 在位、游戏照常运行、无任何代理日志 | 游戏进程内拦截了未签名 DLL |
结论:绝区零的反作弊拦截未签名 DLL —— 方案A(OptiScaler,未签名)在绝区零永远不可能生效。 作者包里写明的"自带数字签名"就是为这个准备的。绝区零唯一可行路径 = 作者签名版 0.3.x d3d12 + 注册表显卡名伪装 (0.3.x 不做伪装,游戏看到 3060 Ti 就不会显示帧生成选项)。
已执行:方案A 全套移入隔离区(可恢复);部署签名版 d3d12.dll(17,529,632 B)+ 出厂 ini;
生成 <个人目录>\绝区零-显卡名伪装\(开启/还原 .reg + README)。
此前"绝区零必须用方案A"的判断正式推翻。
FH6 的 dlssg_sm86.ini 是 261B 旧模板(含 Router=SM86)—— 0.3.x 代理把 Router 当整数解析,
直接报 {"event":"configuration_error","message":"Invalid INI integer"} → 游戏卡死在加载界面。
已恢复出厂 2099B ini(备份 .bak-oldtemplate-*)。
工具日志显示 02:05-02:40 之间 DoApplyFgCfg 跑了 10+ 次,每次都把绝区零/鸣潮判成
"装的是旧版代理"并写入 4X 旧模板。根源:分类逻辑的 else 分支同时接住了 Legacy 和 Opti ——
方案A 在用的游戏也被当旧版代理写 ini。修:else → else if (own == Plan.Legacy),
Opti 计数跳过;D030 分支写前先 EnsureFactoryIni 修复被污染的 ini。
「方案推荐」移到帧生成页最顶;推荐文案改为今天的实测结论(鸣潮=方案A / 绝区零=0.3.x+伪装 / 3A=0.3.x / 竞技=不装);RecommendLine 二游分支按游戏拆分;方案A 区块标题/说明、停放确认框、 0.3.0 部署警告、前置条件结论全部改说真话。
用户三条要求:① 改显卡能不能内置(不想每次出去双击 .reg);② 绝区零两个方案都没有帧生成; ③ 方案推荐还是模棱两可、没有推荐度,要"强调色显示 + 自动识别自动选择"。
ZenlessZoneZero_Data\il2cpp_data\Metadata\global-metadata.dat(119 MB)里同时存在
DLSS / FrameGeneration / FrameGen / SuperResolution / FSR3 字符串 →
游戏本体是支持的,问题在"游戏看不到自己被支持"。这条决定了后面的方向。
实测 HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs(38 项),
d3d12.dll / d3d11.dll / dxgi.dll / version.dll / dinput8.dll / winmm.dll / winhttp.dll / dbghelp.dll
全都不在名单里。所以此前"version.dll / dinput8.dll 被系统强制解析到 System32,换入口重试从来不可能成功"
这句是错的,撤回。
仍然成立的是事实部分:绝区零目录里从来没有生成过 OptiScaler.log —— 方案 A 的代理确实没被加载过。
原因待定,但 0.3.x 的作者包注明"自带数字签名",对反作弊游戏是更合理的赌注,所以本轮把绝区零切到了
签名版 0.3.x 的 d3d12.dll(方案 A 全套 9 个文件 + 2 个目录移入隔离区,可原样拷回)。
| 能力 | 说明 |
|---|---|
Detect() |
只认 Service=nvlddmkm 的设备 —— VEN_10DE 下面还挂着 HD Audio 控制器(Service 是 HDAudBus),按厂商号盲改会改到声卡上 |
Apply() / Restore() |
写 DeviceDesc + FriendlyName;还原时把 FriendlyName 整个删掉(只改回 DeviceDesc 会残留伪装名) |
EnsureBackup() |
一进帧生成页就把"原始显卡名"存成 gpu-spoof-original.txt —— 即使用户从没点过开启,还原也有精确值 |
RestartAdapter() |
pnputil /restart-device PCI\VEN_10DE&DEV_xxxx\...,不用重启系统就让伪装生效(失败则提示重启电脑) |
StatusLine() |
界面上一行显示"当前显卡名 / 已伪装·未伪装" |
界面上是一个独立区块(② 显卡名伪装):开启伪装 / 还原真实显卡名 / 重启显卡设备 三个按钮, 副作用(全系统可见、驱动升级后要重做)直接写在按钮上方。
探针抓到的实现缺陷(已修):Enum 键里没有 InfPath —— 它在驱动键
Class\{4d36e968-...}\000N 里,要用 Enum 键的 Driver 值找过去。少了这一步,重建出来的"原始名"
会丢掉 @oem28.inf,%nvidia_dev.2486%; 前缀(还原后名字虽然能显示,但不再是原样)。
tools/spoof_probe.cs 现在 9 条断言 ALL PASS,且断言备份内容 = 精确原始值、不含 5090。
会话里没有管理员权限,写 HKLM 的实测由 app 自己完成(它以 requireAdministrator 运行)。 探针只做只读验证,不会去动用户的注册表。
区块移到帧生成页最上方,只给三行:
推荐:DLSS MFG 0.3.x(作者签名版)+ 显卡名伪装 ← 大号强调色(柠檬绿)
★★★★☆ 推荐 · 当前 DLSS MFG 0.3.0 ← 适用度
绝区零会拦未签名 DLL……两步都已经内置,可一键完成。 ← 一句话理由
[ 一键应用(0.3.x + 伪装) ] [ 查看详解 ]
Dlssg.BuildRec() 返回 Rec(Head / Stars / Verdict / State / Why / Btn / Action / Bad),
Action 告诉界面该执行哪个动作(opti / 030 / 030spoof / none),
"一键应用推荐方案"直接照它做,用户不用再去下面找对应区块的按钮。
不推荐的情形(竞技网游)整块文字转告警色、按钮变灰写"无需安装"。
判定链(RecommendCategory)本轮加固:
- 工具认得游戏(绝区零 / 鸣潮)→ 二游;
- 否则用 exe 名 / 目录名 / 标题 三个候选去匹配名单,归一化后比较 —— 目录名是「Cyberpunk 2077」,名单里写的是「Cyberpunk2077」,不归一化就整类掉进"未归类" (本轮渲染实测到的:2077 从"未归类 ★★★☆☆"变成了"3A ★★★★★");
- 竞技关键词兜底(cs2/csgo/valorant/deltaforce/riotclient/完美世界/5eclient)——
用户的库里 FPS 项目叫「完美世界竞技平台」「5EClient」,而配置里
fpsGames是空的; - 最后按事实兜底:有
nvngx_dlssg.dll/sl.dlss_g.dll→ 按 3A 对待(★★★★☆); 只有 FSR3 组件 → ★★☆☆☆「可选:游戏自带 FSR3,不必装」;两个都没有 → ★☆☆☆☆「不推荐」。
- 目标游戏那一行原来读
games.json里上次扫描留下的Entry字段,我们在外面换过文件之后就过期了 (显示"入口 winmm.dll"而实际生效的是 version.dll)。改为Plan.StatusOf(dir)按目录里真实文件判定。 Plan.OwnerOf/LooksProxy的阈值校准:旧版代理 14.94 MB、0.3.x 入口 16.72 MB、OptiScaler 25.6/26.1 MB。
| 验证项 | 结果 |
|---|---|
| 静态检查 / 编译 | PASS / COMPILE_OK |
tools/spoof_probe.cs(伪装只读) |
9 条 ALL PASS |
tools/plan_probe.cs(方案切换,沙盒) |
28 条 ALL PASS |
| 7 页 × 浅/深渲染 | 14 张全过 |
推荐区块(新增探针模式 recgame) |
绝区零 ★★★★☆ 推荐 / 鸣潮 ★★★★★ / 2077 ★★★★★ / 完美世界 ★☆☆☆☆ 不推荐 |
| 对象 | 动作 |
|---|---|
| 绝区零 | 方案 A 的 d3d12.dll(25.6 MB)改名停放 → 签名版 0.3.x(17,529,632 B)上岗;方案 A 配套 9 个文件 + 2 个目录移入隔离区 |
| 地平线 6 | 停用重复的旧版代理 winmm.dll(15,678,272 B,一个目录里两个代理同时生效是作者明令禁止的) |
| 2077 | 复查 dbghelp.dll(1.8 MB)确认是游戏自带文件、不是代理,因此未动 |
用户一句话点破:完美世界 与 5E 是 CS2 的对战平台(负责匹配与反作弊),不是游戏。
我上一轮把它们塞进了"竞技网游"关键词,于是界面上给了一段「竞技网游带内核反作弊、封号风险自负」的
封号警告 —— 理由完全不对。
PlatformScan.NonGamePat(注册表卸载项 / Steam appmanifest 名称过滤)原来有
^steam$|epic games launcher|^wegame$|gog galaxy|battle.net$|ubisoft connect|ea app|launcher$|启动器$,
但没有覆盖国内的对战平台。补上:
\b5e(client|box|对战|平台)|perfectworld|完美世界|对战平台|电竞平台
RecommendCategory 里平台判定排在最前(认出绝区零 / 鸣潮之后、进名单匹配之前):
不用装:这不是游戏,是对战平台 / 启动器 对战平台(5E / 完美世界竞技平台这类)负责匹配与反作弊,本身没有帧生成 —— 注入进去既没收益、还可能被它的反作弊盯上。要装的是它启动的那个游戏(例如 cs2.exe)。
版式上新增中性色(Rec.Dim)—— 平台既不是"推荐"(绿)也不是"风险"(红),用灰。
第一版用"包含"匹配写出了三个误判,全部在这一轮修掉:
| 误判 | 原因 | 修法 |
|---|---|---|
| 无畏契约被判成平台 | 它的条目 exe 是 aclos-launcher.exe,我写了 EndsWith("launcher") |
删掉这条规则 —— 游戏自己的启动器不是平台(渲染实测抓到的) |
SteamWorld Dig 会被判成平台 |
关键词 steam 用包含匹配 |
通用名只允许完全等于(steam / wegame / origin / mumu / 模拟器) |
刺客信条:起源 / Origins 会被判成平台 |
关键词 origin 用包含匹配 |
同上 |
最终:PlatformExact(完全等于)+ PlatformPart(足够独特,可包含)
= 5eclient / 5ebox / 5e对战 / perfectworld / 完美世界 / 对战平台 / 电竞平台 / epicgames / goggalaxy / battlenet / ubisoftconnect / eadesktop / eaapp / gameviewer / steamclient / 平台。
新增探针模式 recdump(StyleProbe.exe light recdump 2),把库里每一条游戏的
Exe / Title / Dir / HasFrameGen / HasFsr3 / HasUpscaler / 分类 / 推荐结论 落成一张表
(ui-snapshots\recdump.txt)。一跑就看出两个问题:
| 条目 | 原来 | 现在 |
|---|---|---|
PUBG: BATTLEGROUNDS(TslGame.exe) |
未归类 → "0.3.x 可试 ★★☆☆☆" | 竞技网游 → 不推荐安装(名单补 pubg / tslgame / 绝地求生) |
| P5R / PEAK / 以撒 / 尸姬之梦 / Esports Manager / Chill with You / Wannabe Galgame God | 都在推荐 "0.3.x 可试" | 不用装:没检测到帧生成组件(目录里没有 nvngx_dlssg.dll/sl.dlss_g.dll,代理没有可接管的调用) |
判定口诀:先看"是不是游戏"→ 再看"有没有可接管的调用"→ 最后才谈装哪套。 顺序错了就会出现今天这种"给对战平台发封号警告、给没有帧生成的游戏推荐装帧生成"。
| 档位 | 条目 | 结论 |
|---|---|---|
| 3A 单机 | Cyberpunk 2077、Forza Horizon 6 | 推荐 0.3.x 通用 ★★★★★ |
| 二游 | 绝区零 | 推荐 0.3.x 签名版 + 显卡名伪装 ★★★★☆ |
| 二游 | 鸣潮 | 推荐 方案 A · OptiScaler 注入 ★★★★★ |
| 二游 | 原神 | 不用装:游戏没有 DLSS 帧生成 |
| 竞技 | PUBG、CS2、卡拉彼丘、无畏契约 | 不推荐安装(保持原生) |
| 平台 | 5EClient、perfectworldarena | 不用装:这不是游戏 |
| 其它 | P5R、PEAK、以撒、尸姬之梦、Esports Manager、Chill with You、Wannabe Galgame God | 不用装:没检测到帧生成组件 |
验证:静态检查 PASS、编译 OK、plan_probe 28 条 ALL PASS、spoof_probe 9 条 ALL PASS、
7 页 × 浅/深 14 张渲染全过。仍未打包(用户要求)。
用户一句话点出的是判定生命周期问题:前面那套判定(是不是游戏 / 有没有可接管的调用 / 该装哪套) 只在"当时那份库"上成立 —— 以后新下载的游戏得靠用户自己去改名单,等于没生效。
查出来的三处缺口(都在"新加的游戏"上暴露):
| # | 缺口 | 后果 |
|---|---|---|
| 1 | Program.AutoCategory(联动档位)完全不看游戏库,只查四张静态名单,而且未命中一律 return "fps" |
新装的游戏被判成竞技网游 → 玩它时 UU远程 被暂停(和"启动二游也杀远控"同源) |
| 2 | AllGameProcesses() = 四张名单的并集 |
新加的游戏根本不算"游戏":电源联动 / 加速包 / 定时器 / 亲和性 / P 核绑定全轮不到它,手动档位下拉里也看不到它 |
| 3 | MergeScan 只对"手动添加"的条目重探能力;FillGameList 又按对象引用比较高亮 |
绕过扫描进来的条目带着过期字段;每次扫描(对象全换新)后选中项丢失、推荐块继续渲染旧对象 |
修法(核心思路:判定只留一个计算点,两个消费者读同一个值):
| 位置 | 改动 |
|---|---|
Dlssg.Library |
新增静态引用,只由 MergeScan 写入(唯一入口,避免多处各维护一份而走样) |
DlssgGame.RecCat |
每次合并重算并缓存分类 —— AllGameProcesses() 在每次进程快照里被调十几次,不能在里面做目录探测 |
MergeScan |
每一条都重探能力字段并重算分类(不再只探手动条目);盘根目录跳过(Inspect 会递归整块盘) |
Dlssg.FindByProcess |
按进程名找库条目(先比 exe 名,再退一步比目录末段) |
Dlssg.LinkCategory |
把推荐分类映射成联动档位;platform → ""(不是游戏,不参与任何联动) |
Core.AutoCategory |
先问游戏库(与「方案推荐」共用同一套规则)→ 再静态名单兜底 → 未知不再默认 fps |
Core.AllGameProcesses |
并入库里"是游戏"的条目(排除对战平台),并全部改成 null 安全 |
Core.GameDisplayName |
新游戏的显示名取自库标题(否则手动档位下拉里会出现 REDprelauncher 这类原始进程名) |
Ui.FillGameList |
重建列表后按目录重新定位 selected(否则高亮丢失、推荐块渲染旧字段) |
顺手修掉两个真 bug(都是探针先抓到、不是我推出来的):
Cfg.MmoGames为 null 时AutoCategory直接抛NullReferenceException—— 覆盖层config.local.json缺这个键时反序列化就给 null(旧代码里早有这一行,只是从没被撞上)。 现在全链路 null 安全,并在Config.Load补了MmoGames非空兜底。MergeScan信任上游的探测结果 —— 任何没走扫描的条目都会带着过期的HasFrameGen, 判定跟着错。现在合并层自己重探,不依赖调用者。
验证:tools/link_probe.cs(由 tools/run_link_probe.py 编译运行),在 %TEMP% 造 5 个假游戏
(新 3A / 新竞技 / 对战平台 / 能力字段过期的手动条目 / 无帧生成组件),31 条断言 ALL PASS:
| 断言 | 结果 |
|---|---|
新 3A(有 FG 组件、不在任何名单)→ 分类 aaa、联动档位 aaa |
PASS |
新 3A 不再被判成 fps(旧代码会让 UU远程 被暂停) |
PASS |
新竞技(TurboValorantClone,配置名单里没有)→ fps(关键词兜底) |
PASS |
对战平台 → 档位 "",且不在 AllGameProcesses() |
PASS |
新加的 3A / 竞技 / 手动条目都在 AllGameProcesses()(否则电源与加速包轮不到它) |
PASS |
完全未知的进程 → 不再默认 fps |
PASS |
| 再合并一次 → 新游戏立刻被认到、档位已算好、旧对象不受影响 | PASS |
界面层:列表重建后 selected 换成新对象、结论与重建前一致、新对象上确实带上了能力字段 |
PASS |
回归:方案切换 28 条 ALL PASS · 显卡名伪装 9 条 ALL PASS · 14 张渲染无失败 · 真实库 18 条判定表与改动前完全一致(无回归)。
仍未打包(按用户要求)。说一声就出 3.1.0。
承「优化项盘点与遗漏清单」的 5 条建议,逐条落地。改动集中在 Core.cs(1 处 Dlssg.cs),
不动 UI 结构;能只读的绝不写。
Native 新增 DEVMODE + EnumDisplaySettingsW,Program 新增
DisplayMode(out w, out h, out hz) / RefreshHz()。
| 项 | 说明 |
|---|---|
| 为什么要 | 帧生成的倍率上限由显示器刷新率决定(生成帧超过刷新率就是无效帧)。此前工具连刷新率都不读,"6X 值不值得开"无从回答 |
| 本机实测 | 1920×1080 @165Hz(已是最高刷新率) |
| 交叉验证 | 探针(C# P/Invoke)与独立 Python 脚本两套实现读出的值一致 → 165 |
新增 9 行,全部是"以前写了但看不到"的:
| 新增行 | 读的是 |
|---|---|
| 显示器刷新率(帧生成上限) | EnumDisplaySettings(只读) |
| 鼠标加速(提高指针精确度) | HKCU\Control Panel\Mouse MouseSpeed/MouseThreshold1 |
| 禁止内核换页出内存 | DisablePagingExecutive |
| 网卡节能(挂起/EEE) | 网卡类键 PnPCapabilities==24 的个数 |
| 已禁用服务数 | Services\<名>\Start==4 的个数 |
| 全屏优化(独占全屏) | GameDVR_FSEBehaviorMode + GameDVR_HonorUserFSEBehaviorMode |
| 进程电源节流 | Session Manager\Power\PowerThrottlingOff |
| 优化模块(行为/监控型) | 6 个纯行为/监控模块的开关状态(无系统设置可回读) |
| NVIDIA 驱动版本 | 当前版本 + 基线比对 |
新增 Dlssg.RefreshHint(),接在两条"推荐"结论后面。本机输出:
(显示器 165Hz:生成帧超过 165 就是无效帧 —— 基础帧 40 时 4X 就够,6X 要基础帧 ≤27 才不浪费。)
依据是 NVIDIA 官方口径(6X 面向 240Hz+)与超能网实测文("6x 是为 360Hz 以上或 4K 高刷准备的"); 只读刷新率、不猜帧率(本工具不采集帧率)。
| 新写入 | 位置 | 本机现状(改动前) |
|---|---|---|
GameDVR_HonorUserFSEBehaviorMode=1 |
HKCU\System\GameConfigStore |
已存在但值是 0 → 只写 FSEBehaviorMode=2 很可能被系统忽略 |
PowerThrottlingOff=1 |
HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Power |
值不存在(= 节流默认开着) |
两者都进了 ApplyAll 的备份列表与 RestoreSystemDefaults 的还原范围(还原 = 删除值)。
新增 Program.DriverVerNow() / MarkDriverBaseline():一键优化时记录当前驱动为基线,
版本变化则返回提示(治"更新驱动后第一次进游戏特别卡")。只记录 + 提示,不自动执行任何动作。
体检表只比对、不写入(读函数不产生副作用)。
Ui.cs 的状态分类是「非 ✅ 非
顺带发现(未改):既有 8 行也用 🟡 表达"已停用/未接入"(游戏联动、定时器联动、加速包、 Windows 游戏模式、内核隔离、帧生成运行时、帧生成接入、全局定时器请求)。按现在的显示规则 它们会呈现为红色"需处理",语义偏重。因涉及既有语义决策、且用户未提出,本轮不动,仅记录。
新增 tools/opt_probe.cs + tools/run_opt_probe.py,36 条断言 ALL PASS:
| 组 | 断言 |
|---|---|
| 刷新率 | 可读、>0、与 DisplayMode 一致、与独立 Python 实现一致、范围合理 |
| 体检表 | 不抛异常、项数 31、四列全非空、9 个新增行都在 |
| 状态取值不变式 | 9 个新增行的状态都以 ✅/ |
| 倍率建议 | 含本机刷新率、含 ≤hz/6 门槛、含基础帧 40 的结论倍率 |
| 驱动基线 | 首次不误报、重复调用幂等、版本变化给提示(含新旧值与原因);用例结束把基线文件恢复原状 |
| 只读纪律 | 新增的两项系统写入只读不写(写 HKLM 要管理员且会改用户系统,不在测试里做) |
回归:方案切换 28 条 · 显卡名伪装 9 条 · 新游戏判定 31 条 · 优化项补全 36 条 —— 全 ALL PASS; 7 页 × 浅/深 14 张离屏渲染无失败;库判定表 18 条与改动前一致。
注意:这两项新写入尚未在本机生效(体检表如实显示 全屏优化 ⚠️ 未应用 / 进程电源节流 ⚠️ 未应用),
点一次「一键优化」即会应用并转为 ✅。
用户自己改了界面(Ui.cs 20:05、随后自己编译运行过),要求"看看功能都正常不、还缺啥,完善后打包"。
| 项 | 改前 | 改后 |
|---|---|---|
深色底 Bg |
#05070A | #0B0F17(沉浸曜石黑) |
深色卡片 Panel |
#12171F | #131B26(深空钛灰) |
深色悬浮 Hover |
#1B222C | #182230 |
强调色 Accent |
#6CC10A(柠檬绿) | #00DC82(电竞极光绿),浅色 #10B981 |
新增 Accent2 / Cyan |
— | #059669 / #38BDF8(科技天青);AccentGrad 深色走 绿→天青 渐变 |
| 文字色 | 旧 slate 值 | 统一到 slate 系(#F1F5F9 / #94A3B8 / #64748B) |
自述视觉系统为「Obsidian Cyber Studio」。核对结论:改动自洽 —— 设置页那段说明里的
#00DC82 / #38BDF8 / #0B0F17 → #131B26 → #182230 与 Theme 的实际取值逐项对得上。
(我第一遍读截图时把 #00DC82 误读成 #00DDC82 并差点当成笔误 —— 小字一律以源码为准。)
| 判据 | 结果 |
|---|---|
tools/build.py 静态检查 + 编译 |
PASS(44 个顶层类型)/ COMPILE_OK |
接线审计(新增探针模式 wiredump,反射查每个可交互控件挂没挂事件) |
65 个控件;49 个 FlatBtn 的 Click 全在 |
源码静态扫描(每个 new RoundCheck/RoundCombo 找它的消费者) |
25 个开关/下拉,0 个死控件 |
| 离屏渲染 7 页 × 浅/深 14 张 | 全部 rc=0,界面结构完好 |
| 运行日志(20:06 / 20:08 两次启动) | 无异常、无 UNCAUGHT;扫描 18 款、切主题正常、有序退出 |
顺带纠正一个探针缺陷:
wiredump最初把 23 个控件误报成"未接线"。原因是 ① 自定义控件(RoundCombo)用的是显式声明的事件,编译成同名实例字段,不是框架的EventXxx静态键;② 部分控件本就该由「保存」/「应用参数」按钮统一读取(如"使用代理下载")。 已改成"任意相关事件挂了就算接线",并明确以源码静态扫描为权威判据。
用户换了整套配色后,暴露出 5 处散落在绘制函数里的硬编码色 —— 它们是针对旧深色配色手调的,
没有跟着 Theme 走(例如 OkSoft 深色 Theme 是 #102A24,代码里却写死 #12201C;
斑马纹写死 #0E141C,而 Theme.Subtle 是 #0E141D,差 1)。
新增 5 个语义字段:OkFill / ErrFill / CheckOn / GridHead / GridAlt,
取值与原硬编码逐位相同,只是不再散落各处 —— 以后换配色改一处即可全局生效。
验收方式:改动前先备份 14 张基线图,改完重渲后逐像素对比 → 差异只出现在动态区域(右下角时钟、CPU 负载百分比、监控曲线), 改动涉及的按钮底 / 表头 / 勾选框区域零差异。
回答那句最常被问的话——"帧生成到底生效没"。代理会把每帧的生成情况写进 jsonl:
{"event":"configuration", …, "max_generated":3, …} ← 上限(3 → 4X)
{"event":"evaluate", "generated_count":1, …} ← 每生成一帧一行;取最大值 = 实际倍率
仪表盘「帧生成(DLSSG)」卡片新增一行结论:
最近生效:Cyberpunk 2077 · 实际 4X(09-16 01:35)
最近一次:Forza Horizon 6 · 未见帧生成调用(09-16 17:37)|最近成功:鸣潮 · 实际 2X(09-13 20:31)
尚无代理日志 —— 进游戏跑一局后回来看(代理会自己写记录)
判定规则(以"最近一次代理活动"为准,0 字节日志也有意义 = 代理加载过但没产生生成调用):
| 最近一份日志 | 输出 |
|---|---|
有 evaluate |
最近生效:X · 实际 NX(时间) ← 强调色 |
只有 configuration |
最近一次:X · 上限 NX,但没读到生成记录 |
configuration_error |
最近一次:X · 配置被拒(INI 里有代理不认的值…) |
| 0 字节 + 同游戏更早成功过 | …未见帧生成调用(时间);上次成功:实际 NX(时间) |
| 0 字节 + 成功记录属于别的游戏 | …未见帧生成调用(时间)|最近成功:Y · 实际 NX(时间) ← 不能用"上次" |
最后两条是两次修正的结果:一开始只看"最近一份有内容的日志",会把 0 字节的新日志忽略掉 (地平线 6 就会一直显示修复前的旧错误);改成"最新优先"后,又发现跨游戏拼接出的时间线 会被读成同一款游戏的历史 —— 所以同游戏说"上次"、跨游戏说"最近"。
本机实测情报(本次自检读出):2077 的 native_7728.jsonl 里有 135 条 evaluate、
generated_count 最大 3 → 4X 确实跑起来过;而换成 0.3.x 之后,绝区零 / 2077 / 地平线 6
的最新日志全是 0 字节(代理加载了、没产生帧生成调用),鸣潮最近的成功记录是 09-13 的 2X。
plan_probe 28 · spoof_probe 9 · link_probe 31 · opt_probe 36 · fg_probe 31(新增)
= 135 条断言 ALL PASS;14 张渲染无失败;静态检查 PASS。
问题:用户点 X 时不再被询问(因为以前勾过「记住我的选择」),想改回来却发现设置页里没有入口 —— 该开关被塞在「性能优化页 → 自定义项」对话框的 17 项列表里(第 17 项,与「电源计划」「Defender 排除」并列)。
这是分类错误:关闭窗口行为属于「程序自身行为」,不是「系统优化项」。用户找不到是必然的。
设置页新增独立分区「窗口与托盘」,一个三态下拉:
| 选项 | 含义 | 写入的配置 |
|---|---|---|
| 每次询问 | 弹框让你选「最小化到托盘 / 退出程序」 | ui.closeAsk=true(closeToTray 保留作为弹框默认选中项) |
| 直接最小化到托盘 | 点 X 就收进托盘,联动与告警继续跑 | ui.closeAsk=false + ui.closeToTray=true |
| 直接退出程序 | 点 X 直接退,联动与告警一并停止 | ui.closeAsk=false + ui.closeToTray=false |
配套三处:
- 「自定义项」对话框删掉该行(17 → 16 项)—— 它不是优化项,混在里面用户找不到,也不该由优化流程执行。
- 询问框文案改指向:原来写「到『自定义优化项』里重新勾上」,现改为「到『设置 → 窗口与托盘』把 『关闭窗口时』选回第一项」。
- 弹框勾「记住我的选择」后同步下拉(
RefreshCloseCombo())—— 否则弹框改了配置、设置页还显示旧值, 两处不一致会让人以为没生效。
实现要点:三态 ↔ 两个配置字段的映射收在 CloseComboIndex() / CloseComboText() 一处,
设置页下拉、关闭流程、日志文案共用它。下拉项文案与 CloseComboText() 的输出逐字一致
(探针 close_probe 专门盯这条 —— 两处各写一套就会出现「日志说 A、界面显示 B」)。
| 组 | 断言 |
|---|---|
| 映射全组合 | (询问=T,托盘=T)→0、(询问=T,托盘=F)→0、(询问=F,托盘=T)→1、(询问=F,托盘=F)→2 |
| 下拉实况 | 字段存在 / 恰好 3 项 / 三项文案与 CloseComboText() 逐字一致 / 初值与真实配置一致 |
| 分支等价 | 选中任一态 → 用同一映射能反推回同一行为(覆盖询问 / 托盘 / 退出三种) |
| 同步回调 | RefreshCloseCombo() 存在,且在下拉被 Dispose 时调用也不抛异常 |
全程只读 + 反射,不触发 SelectedIndexChanged(那会写用户真实的 config.json)。
opt_probe 的驱动基线往返测试原先直接操作数据目录里的真实基线文件
(%ProgramData%\Fluxion\nv-driver.txt)。两处问题:
① 那是用户真实数据;② 本机该目录对普通权限只允许新建、不允许覆盖(实测覆盖直接 Errno 13),
所以探针在非管理员下必然失败 —— 那是环境限制,不该记成 FAIL。
改法:Core 给基线路径加一个 internal static DriverFileOverride 测试沙盒出口,探针把路径指到
%TEMP%\gb_drv_test\ 做完整往返,并新增一条断言验证真实文件未被改动(610.88 → 610.88)。
用户从方向 A 的 6 个受控变体里选了 A1(推进器小方兽 · 机身绿 / 喷焰青)。
旧 icon.ico 是上一套配色的产物(黑底 + 紫青渐变闪电 + 盾形芯片轮廓),与用户新做的
Obsidian Cyber 主题(极光绿 #00DC82 + 曜石黑 #0B0F17)已经完全不是一套;
且 32×32 下盾形边框与芯片针脚糊成一团。
先把 A1 量清楚:角色最右 x=819,身体下沿出血到 y=1024,青焰顶端 y=104, 生成端水印在 x≥903 / y≥963(即角色之外的纯背景区)。
| 变量 | 取值 | 依据 |
|---|---|---|
| 裁切范围 | (0, 14, 860, 874) → 860×860 |
右侧留 41px(>819)、青焰上方留 90px 头部空间;身体下沿照旧出血,与原构图一致 |
| 圆角 | 20% | 满幅直角的版本在 16px 下像"被裁的照片";圆角让它在任何桌面上都有明确轮廓 |
| 留白 | 不留 | 实测 8% 留白会浪费小尺寸的可读面积 |
候选对比图(含「角落 × 两色分配」「满幅/圆角/留白/圆形」三组变量)留在
icon\candidates\_preview_crop.png、_preview_headroom.png、_preview_32px.png。
水印的处理方式:避开,而不是擦除。 水印在角色之外的背景区,所以把它裁到画面外即可 —— 没有做任何修补/美化,构图与像素来自原图本身。这条很重要:生成端加的"AI生成"水印, 能用裁切解决就不要用修复工具,前者不引入任何发明出来的像素。
第一版 ICO 容器我把 7 帧全写成 PNG(Vista+ 支持,且体积小)。PIL 回读完全正常, 但走 Windows 自己的图标 API 一验就露馅:
取样 RGB(81,26,235) ← 紫色
取样 RGB(197,186,144) ← 土黄
角 alpha = 112 / 95 / 93 / 189 ← 圆角应该接近 0
我的图里根本没有紫色和土黄。 原因是 GDI+ 对"非 256 的 PNG 帧"不认 —— 它会按 DIB 的布局去解 PNG 数据,于是整幅错位成噪声。
正解(业界标准做法):
| 帧 | 容器格式 | 体积 |
|---|---|---|
| 16 / 24 / 32 / 48 / 64 / 128 | DIB(40 字节 BITMAPINFOHEADER + 自下而上 32 位 BGRA + 1bpp AND 掩码) | 1.1KB … 67.6KB |
| 256 | PNG | 56.8KB |
改完再验,取样变成角色真实的 RGB(5,174,110)、四角 alpha 0–3、exe 内嵌图标与文件帧逐像素 0 差异。
⚠️ 教训(这条最值钱):"第三方库能读"不能作为验收依据。 PIL 对 ICO 的宽容度远高于 Windows,PNG 帧它照读不误。 交付给 Windows 的图标,必须走 Windows 自己的 API(System.Drawing.Icon/ExtractAssociatedIcon)验一遍,并把 ICO 目录按字节解析验一遍容器结构。 新增tools/icon_probe.cs+tools/run_icon_probe.py固化这两条(40 条断言 ALL PASS)。
用三种容器分别试(我们的 PNG256 / 我们的 DIB256 / 上一版旧图标),
请求 256 全部返回 128 → 是 System.Drawing.Icon 的上限。Explorer 走 shell 自己的加载器,
能用到 256 帧;Program.GetAppIcon()(托盘)本来只用 16/32。所以这不是缺陷,探针里如实标注放行。
icon\icon.ico(7 帧 / 158,991 B,旧文件留档 icon.ico.bak-oldtheme、icon.ico.bak-pngframes)
一处替换,四处自动跟随:exe 内嵌图标(build.py 的 /win32icon)、
安装包图标(.iss 的 SetupIconFile)、托盘与窗体(Program.GetAppIcon() → ExtractAssociatedIcon)、
{app}\icon\icon.ico(安装包会拷进去)。
回归:7 个探针 192 条断言 ALL PASS(方案切换 28 / 显卡名伪装 9 / 新游戏判定 31 / 优化项补全 37 / 帧生成自检 31 / 关闭窗口 16 / 图标端到端 40),14 张离屏渲染无失败。
用户反馈三件事:鸣潮进不去(UE4 GPUCrash)、绝区零没有帧生成、方案 A 区块里「为什么只写一个鸣潮」, 外加一个疑点「每次启动鸣潮时默认把 DLSS5 打开了」。
Saved\Crashes\...\CrashContext.runtime-xml:
CrashType GPUCrash
ErrorMessage Fatal error: [File:Unknown] [Line: 690]
hr failed at .../D3D12RHI/Private/D3D12Resources.cpp:596
with error DXGI_ERROR_DEVICE_REMOVED with Reason: DXGI_ERROR_DEVICE_HUNG
两次(21:31 / 21:47),都在启动鸣潮后约 1.5 分钟。崩溃前的 OptiScaler.log 显示 NR 一直在跑
(DlssNr.Enabled: true 是每次启动自动生效),21:46:38 帧生成 feature 创建成功,9 秒后日志停止。
根因链三层叠加:
[DlssNr] Enabled=true被 2.9.1 固化 —— 用户那句「每次启动鸣潮时默认把 dlss5 打开了」就是这个。 NR 每帧跑一遍 158 MB 模型,RTX 20/30 走更重的 FP16 路径。- 上游文档自己写明风险:
wilsjo2/OptiScaler-DLSSNR-PreSR-Multipass([DlssNr]段的真正出处) 的设计说明里有一条 「Never free under the GPU … Both rules were paid for with device hangs」。 驱动门槛不满足:该文档要求 驱动 ≥ 616.56;本机 610.88。
(2026-09-16 23:30 撤回这一条 —— 我读错了,见下方「驱动门槛纠正」)≥616.56只对 RTX 50 是硬门槛;对 3060 Ti 不成立,610.88 不是崩溃的原因。
处置:[DlssNr] Enabled 改回 false(备份 OptiScaler.ini.bak-nr-20260916-230749),
并在工具里做成可调项(帧生成参数 → 「DLSS 5 神经渲染 NR」下拉,默认「关闭(推荐)」)。
关闭 NR 不影响帧生成。
时间线(工具日志):用户 21:25:51 点了「关闭帧生成」→ 回执明写
「已移除 dlssg_sm86.ini;已清理日志目录」(删除,不是停放)。之后 21:25:58 与 21:27:38 两次
「切换到本方案」,走的都是 Plan.SwitchTo 的快速路径——入口 DLL 还在(只是被停放成
d3d12.dll.parked.030),于是「改回原名、秒完成」,谁也没重新补上配套文件 → dlssg_sm86.ini
永久缺失 → 代理读不到配置、连 dlssg_sm86\logs 都不建 → 游戏里始终没有帧生成选项。
两处修复:
Dlssg030.EnsureFactoryIni:原来if (!File.Exists(ini)) return(文件不在就直接放弃)→ 改为从出厂包补回 2099 字节版(含[General] Enabled=1)。Plan.SwitchTo:切到 0.3.x 之后无条件调一次EnsureFactoryIni(dir), 不再假设"入口到位就万事俱备"。
已现场修复:绝区零目录补回 dlssg_sm86.ini(2099 B)。
顺带一条实测现象(重要):21:26:03 写入伪装 → 21:27:06 重启显卡设备 → 21:27:44 启动绝区零 → 21:28:10 游戏日志读到的仍是 "RTX 3060 Ti";而更早那次「导入 .reg + 重启电脑」之后,
游戏日志确实读到了 "RTX 5090"(03:46:48 / 10:50:42 两条)。
→ 改完伪装请重启电脑;「重启显卡设备」不足以让它生效(界面说明已按此更正)。
原标题 帧生成方案 A · OptiScaler 注入(鸣潮) + 正文写死「绝区零不适用本方案…鸣潮 = dxgi 入口…」——
用户质问「为什么只写一个鸣潮」。改为:
- 标题:
帧生成方案 A · OptiScaler 注入(不带游戏名) - 正文:新增
Dlssg.OptiNote(选中游戏),切游戏就变,且带上该游戏的 NR 状态 —— 绝区零 → 「不用本方案,改用签名版 0.3.x + 显卡名伪装」;鸣潮 → 「本方案在用,dxgi 入口…」。
| 事实 | 来源 |
|---|---|
NR 段的出处是 wilsjo2/OptiScaler-DLSSNR-PreSR-Multipass(基于 OptiScaler + Dagherbou 的 NR fork,配色合成都取自 RenoDX) |
该项目 README |
硬前提(仅 RTX 50):驱动 ≥ 616.56;RTX 20/30/40 用 ShortFuse 跨代 310.8 运行库(E67DEE20…),旧驱动也能跑 |
INSTALL-DLSSNR.md + DLSS5-Swapper src/core/install-guards.js |
| 起步姿势:先关 NR + 2X 帧生成,再逐层加 | DLSS-FRAME-GENERATION.md |
| NR 的设计约束原文「were paid for with device hangs」 | OptiScaler/dlssnr/README.md |
| 官方 0.9.x 不含 NR(NR 只存在于社区 fork)→ 升级官方版会把 NR 弄没 | OptiScaler releases |
| Reflex 的 FPS 上限会连带限制生成帧(150 的限制在 4X 下把渲染压到约 37.5fps),提倍率不会抬高这个上限 | 同上 |
菜单能开但点不动 → 试 [Hotfix] ManualInputPolling=true,并排除冲突的覆盖层 |
INSTALL-DLSSNR.md |
验证:8 个探针 240 条断言 ALL PASS(方案切换 28 / 显卡名伪装 9 / 新游戏判定 31 / 优化项补全 37 / 帧生成自检 31 / 关闭窗口 16 / 图标 40 / NR 与切换 24(新增)); 下拉反射探针 18 条 ALL PASS;14 张离屏渲染无失败。
用户问「616.56 或者以上的驱动有哪一个适合 3060ti」。查完之后发现 我在 3.3.0 里把这条读错了, 并且写进了源码 6 处 + 本文档 2 处。这是本轮最重要的产出:纠正一个会导致误操作的结论。
DLSS5-Swapper(rakanki911,★4.8k)的 src/core/install-guards.js 里有两个常量,
我上一轮只摘了第一个去看:
const OPTI_DRIVER = 61656; // 我据此写成"驱动 ≥616.56 是硬门槛" ← 错在这
const NEURAL_FAULT_DRIVER = 61664; // 这个才是"任何 N 卡都要避开"的但 OPTI_DRIVER 的判据是 driverSupported:
function driverSupported(rows) { return rows.some(row => blackwell(row) && driverNumber(row) >= OPTI_DRIVER); }
// ^^^^^^^^^^^^^^^^ ← 必须是 RTX 50而它上方的注释写得更直白(原文):
Two separate questions, because only one of them is a hard requirement. The card is: DLSS-NR runs on the RTX 50 path. The driver is not: the model file (
nvngx_dlssnr.dll) ships with this app rather than being taken from the installed driver, so an older driver still runs an OptiScaler install — which is what people who rolled back off 616.x to keep RenoDX working are seeing.
→ 模型随应用提供、不取自本机已安装的驱动,旧驱动照样能跑。 对 3060 Ti(Ampere)根本不是门槛。
// Measured upstream by the Feeder author across three machines: with the RenoDX DLSS 5 consumer (v4.6 and
// v4.7), every neural evaluate faults inside NVIDIA's own NGX runtime on 616.64 and 616.86, while 616.56
// completes. Reported as DLSS5-Feeder issue #54. This only warns ...
const NEURAL_FAULT_DRIVER = 61664;
function driverNeuralFault(rows) {
return (rows || []).some(row => /nvidia|rtx|gtx/i.test(row.name) && driverNumber(row) >= NEURAL_FAULT_DRIVER);
}注意它的正则是 /nvidia|rtx|gtx/i —— 对任何 N 卡生效,不限于 50 系。
所以约束是「≥616.56 且 <616.64」,也就是只剩 616.56 一个版本。
| 版本 | 日期 | 3060 Ti | NR | 备注 |
|---|---|---|---|---|
| 610.88(本机) | 07-22 | ✅ | 能跑(模型不取自驱动) | 现状,已实测鸣潮 6X + NR 可用过 |
| 616.56 | 08-26 | ✅ 支持清单内 | ✅ completes | 唯一"达标且能跑完"的版本 |
| 616.64 | 09-03 | ✅ 支持清单内 | ❌ fault | NBA 2K27 首发 DLSS 5(那是给 50 系的) |
| 616.86 | 09-04 | ✅ | ❌ fault | Hotfix,不通过 NVIDIA App 推送 |
| 616.92(最新) | 09-09 | ✅ | ❌ fault | 007 First Light 等 |
不是"哪个版本最好",而是唯一达标的那版恰好有两个对你致命的已知问题:
| 616.56 的已知问题 | 对这台机器的影响 |
|---|---|
| 升级后远程桌面(RDP)黑屏 | 🔴 你常驻 UU远程(GameViewer) |
| 升级后无法创建虚拟显示器 | 🔴 远控/虚拟屏软件依赖这个 |
| 「优先最高性能」电源模式可能不生效 | 🟡 工具 NVAPI 竞技档就写这一项 |
修好前两条问题的 616.86 hotfix,以及最新的 616.92,都 ≥616.64 → NR 会 fault。 也就是说:想同时要「NR 可用」和「远控正常」,在 R616 里无解。
而且更根本的一点:这次鸣潮 GPUCrash 不是驱动版本造成的 —— 崩溃真因是 NR 与 4X 帧生成同开 (上游明写其约束「were paid for with device hangs」),升级驱动解决不了。NR 已改为默认关闭并做成开关。
源码 6 处(Core.cs 字段注释 / Ui.cs cbNr 注释 / Ui.cs 说明页前置条件 / Dlssg.cs NrHint /
Dlssg.cs 说明页 / Dlssg.cs PrereqReport),以及本文档 2 处。
其中 PrereqReport 的驱动行改为调用新增的 Dlssg.NoteDriver(drv),按档位给结论:
< 591.86→ 低于作者下限,先升级591.86 ~ 616.55→ 正常区,明确告诉你"不必为了 NR 升级"616.56→ 唯一既达标、NR 又能跑完的版本≥ 616.64→ 警告 NR 会 fault,要用 NR 就回退到 616.56
教训(写给以后的我):看到源码里的阈值常量,必须连同它的判定函数一起读。 只摘常量不读判据,就会把一个"只针对 A 类硬件"的门槛说成"人人都要满足", 然后据此劝用户做一个既没收益、又带已知风险的升级。
用户问「能分享给别人吗?会根据别人的显卡和电脑状况来做推荐吗」—— 核实后两个答案都需要补课。
installer\Fluxion.iss 原来打的是项目根 config.json —— 那是便携模式配置,里面带着本机个人设置:
| 键 | 本机值 | 对别人意味着 |
|---|---|---|
dlssg.useProxy=true + proxy=http://127.0.0.1:7890 |
本机 FlClash | 「下载运行时」必失败(别人没有这个代理) |
gameAware.remoteApps |
用户的 UU远程 exe 路径 + 长注释 | 机器特定,无意义 |
ui.closeToTray=true |
用户点过「记住我的选择」 | 别人点 X 直接收托盘且不知为何 |
cleanup.killList |
用户的 MuMu/百度网盘名单 | 个人习惯 |
dlssg.maxGeneratedFrames=3 |
用户选的 4X | 出厂应为 2 |
修:新增 installer\config.default.json(由根 config 生成、上述键全部回出厂值),.iss 改指向它。
根 config.json 原样保留(它仍是便携模式配置)。安装器语义不变(onlyifdoesntexist,不覆盖已有配置)。
BuildRec / RecommendCategory 原来只看游戏类型与组件,不看对方的卡:
给 RTX 40/50 用户照样推「一键应用 0.3.x + 伪装」——他们原生就有帧生成,且把 4090 改名 5090 是降级;
给 GTX / AMD / Intel 用户也照样推荐 —— 装了也不会有任何选项。
新增(Dlssg):GpuTierFromName(name)(纯函数,可测)→ GpuTier()(读 Program.GpuDisplayName,
unknown 不缓存——WMI 探测可能未完成)→ GpuGateRec(tier)。BuildRec 在 platform/fps 分支之后、
gacha/aaa 分类之前过门禁(platform/fps 本来就"不推荐安装",结论与显卡无关,保持不变):
| 对方显卡 | 推荐结论 |
|---|---|
| RTX 40 / 50 | 中性灰「不用装:这张卡原生支持 DLSS 帧生成」+ 点名「伪装对 40 系是降级」,按钮禁用 |
| GTX / 其他 NVIDIA | 红色「用不了:不在 RTX 20/30 系支持范围」,按钮禁用 |
| AMD / Intel | 红色「用不了」+ 指向游戏自带的 FSR3 / XeSS |
| RTX 20 / 30 | 不拦 —— 原有推荐不变(本机 RTX 3060 Ti 实测回归通过) |
| 未识别(探测中/未知) | 不拦 —— 不误伤 |
PrereqReport(前置条件检查)补「显卡代际」一行。顺带:Program.GpuName 是多变量声明
(string CpuName = …, GpuName = …),自研静态检查器只登记首个变量名 → 跨类引用被误报
UNRESOLVED;加单声明属性 Program.GpuDisplayName 绕开(不动检查器)。
- 补丁脚本
sys.exit(1)在save()之前 → 前面的 rep 全部没落盘,而后续探针读到的是 上一轮的旧结果文件,"222 PASS" 是假的。多步补丁必须先写完再退出;探针结果文件要核对时间戳。 - 探针加载真实配置 → 用户
config.local.json里genericEntry=d3d12.dll(UI 下拉选过), plan_probe section 9 断言 version.dll 必 FAIL。沙盒探针必须显式固定被测输入,不该信任宿主机器的配置。
安装包 2.6MB,不含帧生成资源包(0.3.x 签名版 + OptiScaler 套件 ≈ 270MB,在数据目录)。 对方装完后帧生成功能需要资源包才完整;「下载运行时」按钮目前只覆盖旧版运行库的下载源。 要么把资源包打进安装包(体积会到 ~272MB),要么给 0.3.x/OptiScaler 加下载源 —— 都等用户拍板。
验证:8 探针 238 条断言 ALL PASS(link_probe 新增 16 条门禁断言),14 张渲染无失败。
- 本工具不修改游戏本体、不注入竞技游戏、不以绕过反作弊为目的 —— 代理替换的是游戏自身的 DLSS 加载链,能否生效仍取决于反作弊是否放行
- 帧生成模块仅建议用于单机 3A;在带内核级反作弊的网游上使用第三方 DLL 代理有封号风险,请自行判断
- Defender 排除是安全权衡项,默认关闭
- VBS/内存完整性只做检测不代改 —— 关闭它会降低系统安全基线,需要时请自行在「内核隔离」里操作