
EquipmentTimers
在原版 GTFO 装备名左侧显示状态:READY、RELOAD、近战蓄力、BioTracker 冷却、GlueGun 蓄力与哨戒炮备弹。每个完成提示音都能自定义(原生事件、角色语音、本地 WAV)。客户端只读模组。EquipmentTimers
在原版 GTFO 装备列表(右上角)内部绘制常驻状态与倒计时:紧贴每一件装备名称的左侧,所有行共用一条左对齐的列。武器弹匣满时显示绿色 READY,未满时显示黄色 RELOAD,空弹匣显示红色 RELOAD,换弹过程中显示剩余秒数。BioTracker 只要扫描可用就显示绿色 READY。准星上不添加任何内容,也没有独立面板。
| 计时对象 | 标签含义 |
|---|---|
| 主武器 / 副武器 | 绿色 READY(弹匣满)、黄色 RELOAD(未满)、红色 RELOAD(空);换弹过程中显示剩余秒数 |
| BioTracker / 职业工具 | 就绪时绿色 READY;冷却中显示距离下次可扫描的秒数 |
| 近战武器 | 仅在 MWS_ChargeUp 内存在:显示到满伤害的秒数,满后绿色 READY,m_releaseWarning 为真时显示红色 ! |
| GlueGun | 仅在按住蓄力时显示:3x 1.2s——原生连发弹数与已累计的蓄力时间 |
当计时真正完成时,该行会变绿并短暂显示 READY,同时播放一次原版 UI 音效。仅仅倒数到零不算完成;弹匣满 / BioTracker 就绪这类原生状态也不会播放音效。
功能特性
- 原版外观:同一 TMP 字体资源、字型与排序层,镜像原生的 transform 缩放,并按实测字形高度适配。计时字形偏矮时至少放大到原生高度,并额外留 10% 可读性余量。
- 同时锚定原生的两种名称状态,因此既能跟随选中的完整名称,也能跟随紧凑的 slim 名称;切换装备时会重新锚定。
- 自动跟随 HUD 缩放、分辨率变化与原生槽位重排,因为标签与原生文本是同一个 canvas 内的兄弟节点。
- 最多四行(主武器、副武器、工具、近战),每个槽位一个标签,从不重复。
- 倒计时/未知状态使用中性色(继承原生名称颜色);真正的完成与原生「弹匣满 / BioTracker 就绪」状态为绿色;弹匣未满为黄色;空弹匣或需要立刻挥出的蓄力为红色。
- 共用一条左列:所有标签都左对齐(TMP
Left、左 pivot)在同一条左边缘上,并且该边缘还会预留最宽标签加配置间距,使整列结束于最左侧原生名称字形左边缘的左边,而不是从那里开始。各行在世界/屏幕空间比较,再各自投影回自己的父级(含父级 anchor 参考点),因此不同的父级缩放或偏移都不会破坏对齐。 - 纯客户端、只读:不写任何游戏数值、不发送任何网络包,换弹速度、蓄力速度、伤害与扫描冷却都不受影响。
- 有界日志:默认每局最多 40 行(
VerboseLog时 400 行),从不逐帧记录。
哨戒炮备弹行(1.0.9)
手持哨戒炮时,该行显示你自己的职业弹药池 当前/总。当你有哨戒炮已部署时,这个比例继续显示,并在主/副武器原生弹药百分比所在的同一列上额外显示一个百分比,数值来自该已部署炮台自身的 Ammo/AmmoMaxCap(实例值不可读时,只有数值改用同步快照 LastSyncData.ammo)。容量为零/非法、数值不可读,或无法证明该炮台属于你时,只隐藏百分比——你的比例照常显示,你的备弹也绝不会被当作炮台弹药。
完成提示音(1.0.9)
BepInEx/plugins/EquipmentTimers/Assets/Audio/ready-sounds.json 决定每个计时完成时播放什么声音。随包默认:BioTracker 播放当前角色自己的原生 Scan 台词(PLAY_CL_SCAN,经游戏语音系统),武器与近战 cue 沿用此前的原生 ReadySoundEvent。每个 cue 可设为:
native——配置中的ReadySoundEvent(原有行为);playerVoice——角色原生台词(PLAY_CL_SCAN);wwise——白名单内的原版 Wwise 事件;wav——该目录下你自己的文件(PCM 8/16/24/32-bit 或 float32,单/双声道,≤ 30 秒,≤ 32 MB);none——静音(绿色 READY 标签仍会出现)。
自定义文件只从该目录读取、只在本地播放:不下载、不发网络包,也不修改游戏数据。文件损坏或缺失时只记一条警告并回退到原生事件。该目录的 README.txt 说明了格式;修改后请重启 GTFO。
安装
- 安装 BepInExPack_GTFO(唯一依赖)。
- 把
EquipmentTimers.dll放进BepInEx/plugins/(本包已使用BepInEx/plugins/EquipmentTimers/EquipmentTimers.dll这一布局)。 - 启动 GTFO。每个已占用且启用的装备行都会显示其原生状态;武器与 BioTracker 空闲时显示 READY/RELOAD,换弹/蓄力/冷却时显示倒计时。
配置
BepInEx/config/HawChow.EquipmentTimers.cfg(也可用配置编辑器):
| 段 | 键 | 默认 | 说明 |
|---|---|---|---|
| General | Enabled |
true |
总开关;关闭后立刻隐藏全部标签 |
| General | ShowMeleeCharge |
true |
近战蓄力倒计时 |
| General | ShowReload |
true |
换弹倒计时 |
| General | ShowScanner |
true |
BioTracker 冷却倒计时 |
| General | ShowGlueGun |
true |
GlueGun 连发弹数与已累计蓄力时间 |
| General | ShowSentryAmmo |
true |
哨戒炮行:手持显示职业弹药池 当前/总,已部署时同时显示炮台实例的弹药百分比 |
| General | PlayReadySound |
true |
是否播放一次完成提示音 |
| General | ReadySoundEvent |
IMPLANTREADY |
原版 Wwise 事件:IMPLANTREADY、IMPLANTREADYSMALL、HUD_SCAN_COMPLETE_INDICATION、BUTTONGENERICBLIPACTIVATED、BUTTONGENERICBLIPONE、None |
| General | CustomReadySounds |
true |
是否读取 Assets/Audio/ready-sounds.json;false 时全部 cue 都走 ReadySoundEvent |
| General | ReadyHoldSeconds |
0.6 |
READY 在屏幕上的保持时长(0.2–3 秒) |
| General | OverrunGraceSeconds |
2.5 |
原生动作迟迟不结束时的静默丢弃阈值(0.5–10 秒) |
| Layout | GapRatio |
0.22 |
与原生名称的间距,按原生字号的比例 |
| Layout | MinGap / MaxGap |
2 / 40 |
该间距的上下限(canvas 单位) |
| Layout | LabelWidthRatio |
4 |
标签框宽度,字号倍数 |
| Layout | MinLabelWidth |
24 |
该宽度的下限 |
| Layout | ReadyColor |
#6BF25A |
#RRGGBB 或 r,g,b(0-1 或 0-255) |
| Layout | NeutralAlpha |
0.92 |
中性色倒计时的透明度 |
| Debug | VerboseLog |
false |
日志预算提高到 400 行 |
已知限制与精度
- GTFO 没有暴露换弹时间戳:只有
IsReloading与ReloadTime。第一段换弹从IsReloading上升沿起按ReloadTime倒数;之后每一段用两次插入之间的实测间隔估算,并在文本前加~(例如~0.5s),因此估算值不会被误认为原生窗口。只有当原生会话结束、确实完成时该行才会变绿。 - 换弹只有在弹匣已满或本段会话中弹匣增长且开始时非空的备弹现在确实为空(可证明的自然耗尽)时才算完成。因此换弹中途开火绝不会让该行变绿,读取不到的备弹也绝不会被假定为空。
- 倒计时归零但原生动作仍在进行时显示
--而不是猜测值,同时继续观察;采样被取消/读取失败期间保持--;被中断的有效动作在其终止帧显示--,随后回到中性 idle READY。之后真正到来的完成仍会变绿并只响一次。 - 主菜单中,原生 HUD 每秒会重建自身数千次(实测约 3.5 kHz),并且传出的 HUD 实例经常已经销毁。本 MOD 只把这些调用当作失效提示:从不缓存、从不解引用,而是通过限频探测重新获取 HUD。这正是 2026-10-25 启动崩溃的路径;修复后菜单可连续稳定 211–217 秒(见项目内
reports/runtime-startup-failure.md)。 - 在 MOD 能观察到之前就已经开始的蓄力或换弹(关卡中途注入、关卡加载时正在换弹)仍会显示数字,但会静默结束——这是设计如此:MOD 没有亲眼看到开始的完成,绝不播放提示音。
- 工具倒计时跟随扫描仪自身的
m_recharging/m_rechargeStartTime/m_rechargeDuration;不使用这些字段的模组工具不会显示倒计时。 - GlueGun 读数只在原生蓄力状态运行时绘制(
m_fireButtonDown && !m_reCharging && !m_firing && m_pressure > 0)。连发弹数取原生GetShotCount()对游戏所用同一归一化压力的回答;低于m_pressureProgressToFire时武器还不能开火,因此计数为0。读不到计数(无 owner、分母退化、任何 interop 拒绝)时显示中性占位符,而不是编造数字。 - GlueGun 的时钟是已经过去的蓄力时间(
m_pressure x TimeToMaxpressure),绝不是剩余时间;蓄力一结束该行立即消失——没有 idleREADY,也没有倒计时。 - 近战行只在
MWS_ChargeUp内存在;离开该状态(挥出、取消、换武器)时在同一帧隐藏,因此不会残留--、idleREADY或过期绿色。 - 每个装备行只读取自己的槽位:
PlayerBackpackManager.TryGetItem(_player.Owner, slot, out BackpackItem bp),并以bp.IsLoaded、存活的bp.Instance与item.ItemDataBlock.inventorySlot == slot作为身份证明,因此未手持的武器/工具行也能显示其原生状态。其中任一步失败,该行就脱离并不显示任何内容,而不是使用缓存猜测;近战行保留已验证的FPItemHolder.m_meleeWeapon兜底,用于背包实例缺失或不是装备的情况。 - 近战「满蓄力保持」时间有意不显示:计时在满蓄力时停止。
验证状态(v1.0.9)
- 固定 SDK 的 Release 构建、无头计时/状态映射/音频/生命周期测试(560 条断言)、图标、manifest、程序集元数据与源码守卫,均在已安装的 GTFO interop 集(Test profile 的 BepInEx)上通过。
- 1.0.6 曾在 Test 中加载且标签出现,但实机检查发现标签比装备名小、空闲时不可见。1.0.7 镜像原生 TMP 缩放并按实测字形高度适配;1.0.8 增加了武器 READY/RELOAD 状态、常驻 BioTracker READY、近战蓄力状态门控与 GlueGun 弹数/蓄力行,全部在同一共享列左对齐。
- 1.0.8 与 1.0.9 都没有声称通过实机验证:该构建仍需在 GTFO 内做安装后检查。对 1.0.9 而言,这包括原生 Scan 提示音与实际用户 WAV 的听感/音量,以及哨戒炮百分比在屏幕上的位置——这三项在此均为静态结论。
- 1.0.0 的主菜单运行及其 211/217 秒稳定性结果属于历史记录,不能用于验证本构建。
- 包内未附带实机截图。包图标是美术作品,不构成实机渲染证据。
致谢与许可
- 行为参考:Zose 的 ReloadTimerPlus 与 long_walter 的 MeleeTimer。未使用 ReloadTimerPlus 的任何代码或素材(其发布时没有明确许可)。MeleeTimer 为 MIT 许可,在此致谢其「remaining = AutoAttackTime − elapsed,字体取自原生 HUD」的思路;本 MOD 自行实现 tracker、HUD 锚定与完成判定,并从实时蓄力状态读取
MWS_ChargeUp.m_maxDamageTime,而不是读取动画数据块。 - 此处使用的名称、字段与事件均为游戏自身(
PUI_InventoryItem、Gear.MWS_ChargeUp、ItemEquippable、Gear.EnemyScanner、AK.EVENTS);本包不重新分发任何游戏程序集。