大型物品栏射击卡顿修复

大型物品栏射击卡顿修复

修复了当你携带大量物品时射击出现的帧率下降和卡顿(全自动武器最严重)。此前每次射击都会让游戏重新排序物品栏菜单的物品列表,即使菜单已关闭也是如此。这个SFSE插件改为原地更新这些行。物品栏不变,无需更改存档。

[size=5][b]大容量物品栏射击卡顿修复[/b][/size]

你是否在射击时(尤其是使用自动武器时)掉帧或卡顿?
携带的物品越多,情况是否越严重,而在控制台输入 [b]tgm[/b](无限弹药)后卡顿是否消失?
那么这个模组就是来解决这个问题的。

[size=4][b]效果[/b][/size]
同一存档、同一地点、同一武器(约 4,500 发子弹,物品栏中大量物品):
[list]
[]不射击:109–111 fps[/]
[][b]未使用[/b]修复时射击:[b]63–82 fps[/b][/]
[][b]使用[/b]修复后射击:[b]105–108 fps[/b][/]
[/list]你的具体数值会有所不同,但射击时的帧数下降应该会消失。参见对比视频和图片。

[youtube]kq1A2AbA1-w[/youtube]

[size=4][b]为什么会发生[/b][/size]
每开一枪都会改变你的弹药数量。即使物品栏菜单处于关闭状态,游戏也会持续更新菜单的物品列表。在我的存档中,开一枪会更新约 50–90 行(弹药以及显示该弹药的武器)。

对于每一行被更新的数据,游戏会将该行从排序列表中取出,再重新插入。这两个步骤都会逐行移动[b]它之后的每一行[/b],而每一行都是一个庞大的 UI 对象(约 2 KB),需要重新注册。物品越多,需要移动的行就越多,因此帧数下降会随物品栏规模而加剧。

[b]参考:[/b]LFP Gaming 的这段视频展示了同样的问题以及旧的变通方法(将物品移出物品栏)。射击测试从 [url=https://www.youtube.com/watch?v=FVAlWpzTt58&t=149s]2:29[/url] 开始。
[youtube]FVAlWpzTt58[/youtube]

[size=4][b]此模组的作用[/b][/size]
[list]
[]如果物品在排序列表中的位置不变(几乎总是如此),则该行会[b]就地[/b]更新。不会移动任何内容。[/]
[]如果确实需要移动,则只移动旧位置与新位置之间的行。[/]
[]菜单收到的变更消息与原版相同,因此你的物品栏外观和功能保持不变。[/]
[/list]这是一个小型 SFSE 插件:仅一个 DLL,没有 ESP 或 ESM。

[size=4][b]前置要求[/b][/size]
[list]
[]Starfield [b]1.16.244[/b](Steam)[/]
[][url=https://sfse.silverlock.org/]Starfield Script Extender (SFSE)[/url][/]
[/list][b]不需要[/b] Address Library。

[size=4][b]安装[/b][/size]
使用模组管理器(Mod Organizer 2 或 Vortex)安装,或将文件复制到:
[code]Starfield\Data\SFSE\Plugins\FireInventoryFix.dll[/code]照常通过 SFSE 启动游戏。

要检查是否加载成功,打开 [i]Documents\My Games\Starfield\SFSE\Logs\sfse.txt[/i] 并查找以下行:
[code]plugin FireInventoryFix.dll (... FireInventoryFix ...) loaded correctly[/code]
[size=4][b]卸载[/b][/size]
删除该 DLL 或禁用模组。这在任何时候都是安全的:该模组只改变物品栏菜单显示数据的更新方式,不会向你的存档写入任何内容。

[size=4][b]兼容性[/b][/size]
[list]
[][b]Starfield Engine Fixes[/b]:兼容且已一同测试。其可选的 Inventory Cache 并不能修复此问题(它修改的是物品栏菜单数据的另一部分),两者可以同时正常工作。[/]
[]不编辑任何记录,因此加载顺序无关紧要。[/]
[]它只可能与另一个修补物品栏菜单代码中相同两处位置的 SFSE 插件冲突。我不知道有这样的插件。如果这些位置已被其他东西修改,或游戏版本不同,此插件不会执行任何操作。[/]
[]物品栏 UI 模组(例如 StarUI Inventory)应该可以正常工作,因为菜单收到的数据相同。尚未测试。[/]
[/list]
[size=4][b]与原版的一处小差异[/b][/size]
排序相等的物品(例如按名称排序时名称相同的多把武器)现在会保持其顺序。在原版中,被更新的那一个会跳到该组的末尾。这只是外观上的差异。

[size=4][b]游戏更新[/b][/size]
此版本仅适用于 Starfield 1.16.244。游戏更新后它将直接无法加载(不会崩溃,射击时的帧数下降只是会重新出现),直到模组更新为止。

[size=4][b]常见问题[/b][/size]
[b]它会整体提升我的 FPS 吗?[/b]
不会。它只消除物品栏发生变化时(例如射击时)发生的帧数下降。

[b]它能修复切换武器时的卡顿吗?[/b]
不能。那是另一种原因造成的。

[b]Game Pass / Xbox 版本?[/b]
不支持。仅在 Steam 版本上测试过。

[spoiler]
[b]技术细节(面向模组作者)[/b]
[list]
[]游戏版本 1.16.244。UpdateMenus(CommonLibSF ID 99438)会清空 UI 任务队列,而 PlayerInventoryDataModel::vf4(RVA 0x14E0740)会为每个发生变更的物品运行一次。[/]
[]vf4 对一个 NestedUIValue<PlayerInventoryItem> 的 vector(每个 0x8E8 字节)调用 RemoveAt(0x14E0A20),然后执行排序插入(0x14E26F0 → 0x14E4F60)。两者都会通过移动赋值来移动之后的所有元素,并重新注册每个 UI 字段。[/]
[]该插件通过 exe 旁边的一个小型 thunk 重定向 0x14E084D 和 0x14E282D 处的两个调用。RemoveAt 被延迟执行。在插入时,它使用游戏自身的比较器检查 left ≤ new < right,并就地重建该元素;否则只移动旧索引与新索引之间的元素。UI 变更列表收到的条目与原版相同(移除 i,插入 j)。[/]
[]打补丁之前,它会检查 exe 大小、两个调用点的字节以及它使用的每个游戏函数的前几个字节。任何不匹配时它都不会执行任何操作。[/]
[]在测试中,51,000+ 次行更新都是就地处理的,没有回退,也没有错误。[/]
[/list][/spoiler]

[size=4][b]制作过程[/b][/size]
我通过性能分析器和逆向工程找到了原因,并借助了 AI 助手的帮助。该插件已在游戏内测试:51,000+ 次物品栏行更新均被无错误地处理。

[size=4][b]权限[/b][/size]
你可以重新上传、修改和翻译此模组,只要注明我的署名并链接回此页面即可。

[size=4][b]鸣谢[/b][/size]
[list]
[]SFSE 团队[/]
[]CommonLibSF 贡献者,其函数名称对逆向工程有所帮助[/]
[]LFP Gaming,感谢其视频 [url=https://www.youtube.com/watch?v=FVAlWpzTt58]Lag when shooting? How to fix stutter with guns[/url],该视频说明了射击时的卡顿来自大容量物品栏[/]
[/list]