
EquipmentTimers
Status left of the native GTFO equipment names: green READY, yellow/red RELOAD, melee charge, BioTracker recharge, and GlueGun shots + charge time. Client-side, read-only.EquipmentTimers
Persistent status and countdowns drawn inside the native GTFO equipment list (top right), immediately to the
left of each equipment name, all of them left-aligned in one shared column. A weapon shows a green READY while its
magazine is full, a yellow RELOAD while it is not, a red RELOAD when it is empty, and the remaining seconds while
it reloads. The BioTracker shows a green READY whenever the scan is available. Nothing is added to the crosshair,
and there is no separate panel.
| Timed item | What the label means |
|---|---|
| Primary / secondary weapon | Green READY (full magazine), yellow RELOAD (not full), red RELOAD (empty); the remaining seconds while reloading |
| BioTracker / class tool | Green READY when ready; seconds until the scan can be used again while recharging |
| Melee weapon | Only inside MWS_ChargeUp: seconds until full damage, then green READY, and a red ! when m_releaseWarning is set |
| GlueGun | Only while the charge is held: 3x 1.2s - the native burst shot count and the charge time already elapsed |
When a timer really completes, the row turns green and shows READY for a moment, and one
vanilla UI sound is played. A countdown that merely reaches zero never counts as a completion, and a
green magazine-full / BioTracker-ready state never plays the sound either.
Features
- Native look: same TMP font asset/style/sorting layer, mirrored native transform scale, and measured glyph-height fit. A shorter timer glyph is scaled to at least native height with a 10% readability margin.
- Anchored to both native name states, so it follows the selected full name and the compact slim name, and re-anchors when you switch gear.
- Follows HUD scaling, resolution changes and native slot repositioning, because the label is a sibling of the native text inside the same canvas.
- At most four rows (primary, secondary, tool, melee), one label per slot, no duplicates.
- Neutral colour for countdown/unknown status (inherits the native name colour), green for a real completion and for the native "full magazine / BioTracker ready" state, yellow for a partial magazine, red for an empty one or a charge that wants the thrust released.
- One shared left column: every label is left-aligned (TMP
Left, left pivot) on the same left edge, and that edge also reserves the widest label plus the configured gap, so the whole column ends left of the leftmost native name's glyph left edge instead of starting there. Rows are compared in world/screen space and each one is projected back into its own parent (including that parent's anchor reference point), so different parent scales or offsets cannot break the alignment. - Client-side and read-only: no gameplay value is written, no packet is sent, reload speed, charge speed, damage and scan cooldown are untouched.
- Bounded logging: at most 40 lines per session by default (400 with
VerboseLog), never per frame.
Installation
- Install BepInExPack_GTFO (this is the only dependency).
- Drop
EquipmentTimers.dllintoBepInEx/plugins/(the package already usesBepInEx/plugins/EquipmentTimers/EquipmentTimers.dll). - Start GTFO. Every occupied, enabled gear row shows its native state; weapons and the BioTracker read READY/RELOAD when idle, and the numbers count down during reload/charge/recharge.
Configuration
BepInEx/config/HawChow.EquipmentTimers.cfg (or a config editor):
| Section | Key | Default | Meaning |
|---|---|---|---|
| General | Enabled |
true |
Master switch; off hides every label immediately |
| General | ShowMeleeCharge |
true |
Melee charge-up countdown |
| General | ShowReload |
true |
Reload countdown |
| General | ShowScanner |
true |
BioTracker recharge countdown |
| General | ShowGlueGun |
true |
GlueGun shot count and elapsed charge time |
| General | PlayReadySound |
true |
Play the one-shot ready cue |
| General | ReadySoundEvent |
IMPLANTREADY |
Vanilla Wwise event: IMPLANTREADY, IMPLANTREADYSMALL, HUD_SCAN_COMPLETE_INDICATION, BUTTONGENERICBLIPACTIVATED, BUTTONGENERICBLIPONE, None |
| General | ReadyHoldSeconds |
0.6 |
How long READY stays on screen (0.2–3 s) |
| General | OverrunGraceSeconds |
2.5 |
Drop a countdown silently if the native action never ends (0.5–10 s) |
| Layout | GapRatio |
0.22 |
Gap to the native name, as a fraction of the native font size |
| Layout | MinGap / MaxGap |
2 / 40 |
Clamps for that gap, in canvas units |
| Layout | LabelWidthRatio |
4 |
Label box width as a multiple of the font size |
| Layout | MinLabelWidth |
24 |
Lower clamp for that width |
| Layout | ReadyColor |
#6BF25A |
#RRGGBB or r,g,b (0-1 or 0-255) |
| Layout | NeutralAlpha |
0.92 |
Opacity of the neutral countdown |
| Debug | VerboseLog |
false |
Raise the log budget to 400 lines |
Known limits and accuracy
- GTFO exposes no reload timestamp: only
IsReloadingandReloadTime. The first reload segment counts downReloadTimefrom theIsReloadingrising edge; each further segment is estimated from the observed interval between two inserts and is prefixed with~(for example~0.5s), so an estimate can never be mistaken for the native window. The row only turns green once, on the native end of the session. - A reload counts as completed only when the magazine is full or the clip grew during the session and the reserve that was non-empty at the start is now empty (provable natural exhaustion). Firing mid-reload therefore never turns the row green, and an unreadable reserve is never assumed empty.
- A countdown that reaches zero while the native action is still running shows
--instead of a guessed value but keeps watching; canceled/failed samples remain--while reads fail, and a valid interrupted action shows--on its terminal frame before returning to neutral idle READY. The real completion that lands later still turns green and beeps exactly once. - The native HUD rebuilds itself thousands of times per second in the main menu (measured ~3.5 kHz)
and hands out HUD instances that are frequently already destroyed. The mod treats those calls as
an invalidation hint only: it never caches or dereferences them, and re-acquires the HUD through a
throttled probe. This was the 2026-10-25 startup-crash path; with the fix the menu stays stable for
211-217 s in a row (see the project's
reports/runtime-startup-failure.md). - A charge or reload that started before the mod could observe it (attaching mid-level, reloading while a level loads) still shows a number but ends silently, by design: the ready cue is never played for a completion the mod did not watch from the start.
- The tool countdown follows the scanner's own
m_recharging/m_rechargeStartTime/m_rechargeDuration; modded tools that do not use those fields will not show a countdown. - The GlueGun read-out is only drawn while the native charge state runs (
m_fireButtonDown && !m_reCharging && !m_firing && m_pressure > 0). The burst size is the nativeGetShotCount()answer for the same normalized pressure the game uses; belowm_pressureProgressToFirethe weapon cannot fire yet, so the count is0. If the count cannot be read (no owner, degenerate denominator, any interop refusal) the label shows a neutral placeholder instead of a fabricated number. - The GlueGun clock is the charge time already elapsed (
m_pressure x TimeToMaxpressure), never a remaining time, and the row disappears the moment the charge ends - no idleREADY, no countdown. - The melee row only exists inside
MWS_ChargeUp; leaving the state (release, cancel, weapon swap) hides it on that same frame, so no--, idleREADYor stale green window survives. - Every gear row reads its own slot:
PlayerBackpackManager.TryGetItem(_player.Owner, slot, out BackpackItem bp)withbp.IsLoaded, a livebp.Instanceanditem.ItemDataBlock.inventorySlot == slotas the identity proof, so the non-wielded weapon/tool rows show their native state too. If any of that fails the row detaches and shows nothing rather than a cached guess; the melee row keeps the verifiedFPItemHolder.m_meleeWeaponfallback for a missing / non-gear backpack instance. - Melee "max charge hold" time is intentionally not shown: the timer stops at full charge.
Verification status (v1.0.8)
- The fixed-SDK Release build, head-less timer/state-mapping tests (386 assertions), icon, manifest, assembly metadata and source guards pass against the installed GTFO interop set (Test-profile BepInEx).
- 1.0.6 was loaded in Test and its labels appeared, but the in-game check found them smaller than equipment names and hidden while idle. 1.0.7 mirrored native TMP scale and fitted the measured glyph height; 1.0.8 adds the weapon READY/RELOAD states, the persistent BioTracker READY, the melee charge-state gate and the GlueGun shot/charge line, all left-aligned in one shared column.
- No in-game visual pass is claimed for 1.0.8: the exact build still needs its post-install check in GTFO. The 1.0.0 main-menu run and its 211/217-second stability result are historical and do not verify this build.
- No gameplay screenshot is bundled. The package icon is artwork, not evidence of in-game rendering.
Credits and licence
- Behaviour reference: ReloadTimerPlus by Zose and MeleeTimer by long_walter. No code or asset
from ReloadTimerPlus is used (it ships without an explicit licence). MeleeTimer is MIT licensed and
is credited as the source of the "remaining = AutoAttackTime − elapsed, font taken from the native
HUD" idea; this mod implements its own tracker, HUD anchoring and completion policy and reads
MWS_ChargeUp.m_maxDamageTimefrom the live charge state instead of the animation data block. - All names, fields and events used here are the game's own (
PUI_InventoryItem,Gear.MWS_ChargeUp,ItemEquippable,Gear.EnemyScanner,AK.EVENTS); no game assembly is redistributed with this package.