Skip to content

DoD Studio window: every tab shows how far the demo and its highlights have loaded, and highlights start loading as soon as a demo plays (#797) - #804

Merged
ccoventry merged 9 commits into
devfrom
feat/load-strip-797
Oct 18, 2026
Merged

ccoventry merged 9 commits into
devfrom
feat/load-strip-797

Conversation

@ccoventry

@ccoventry ccoventry commented Oct 17, 2026 •

Copy link
Copy Markdown
Owner

Release note: New: The in-game DoD Studio window shows how far the demo and its highlights have loaded along the top of every tab, and the highlights start loading as soon as a demo plays; the Highlights tab is simpler (no status line or Min kills, the Player box names a POV demo's player).

Closes #797

Changed after the user's POST test (2026-10-17)

Test DLL now local\test-797e\ (head 62b2068, dev merged in).

  • Highlights tab: the status line at the top and Min kills are gone; the list moves up. The Player box shows for every demo: HLTV narrows the list, POV holds the recording player's name, greyed out. No demo / no kills / failures go on the hint line beside Go.
  • Player filter: lists the matching streaks again in highlight order instead of hiding rows (a row SetItemVisible shows again goes to the end of the list, so rows came back out of order). No heading sort forced; a clicked heading still sorts. Leaks the rows per keystroke as it did per demo: Free the Highlights tab's list rows instead of leaking them #812.
  • Parse errors read as words: analysis passes its parse error through integrity::parse_error_reason (now pub), and the hook does the same to an older Studio's text. Seen on hltv-2508021304-dod_solitude_b2 (server crashed mid-recording; reading up to the break is Analyze a damaged demo up to the point where it breaks #811).
  • Capture runs: kept as is (demos a capture plays are already cached from the Capture page).
  • Remaining test: POST re-test of the above, then PRE.

What changes

  • Highlights start on their own. hook::poll() now calls load_strip::request_highlights() every frame, before the "no window yet" early return: once demo_reload::current_demo() is Some, it asks streaks::request for that demo (once per demo name, so the path is worked out once). Window open or closed, any tab. The Highlights tab only shows the result now; its own request call stays and is a no-op.
  • The demo load needed nothing (measured in the issue: same rate with the window closed). Only the showing was missing.
  • The loading strip. A new LoadStrip label in DodStudio.res, shown on every tab while either load runs: Loading: Demo 45% Highlights 60% (only the parts still running). Gone, and the tabs back to full height, once both are done.
    • Demo percent: load_progress::demo_percent(), factored out of the Playback tab's update, which now uses it too, so the strip and the Playback bar (While a demo loads, the demo player bar shows how far along it is (#465) #758) say the same number. It no longer depends on the Playback page being visible.
    • Highlights percent: new streaks::loading_percent() (the same PERCENT atomic the Highlights tab's bar reads, without cloning the streaks found every frame). While the worker holds the job lock for a frame, the strip keeps its last number.
    • Text from a pure load_strip_text(demo, highlights) with unit tests; placement from load_strip_bounds(page_wide), tested too.
  • The Playback tab's LoadLabel/LoadProgress and the Highlights tab's StreakProgress + status line stay as they were.

Layout approach

The strip goes on the page showing, over the top of the page area, and the page's controls move down under it:

  • load_strip::update (run before fit_pages, only while the window shows) reparents the LoadStrip label from the window onto whichever page is visible (set_parent, as loans do) and places it at (8, 2, page_wide - 16, 18) in page coordinates. On the page rather than the window because a page paints over whatever of the window lies under it, so a window child overlapping the page area would sit under it.
  • fit_pages fits each tab's controls to the page height less LOAD_STRIP_TALL (20 px) and adds 20 to every control's y while the strip shows; 0 otherwise. Lent controls follow their slots as before, and a list that fills the tab's height (FILL_HEIGHT) loses those 20 px.
  • The sheet, tab row and help line are untouched (fit_sheet unchanged).
  • A user-edited DodStudio.res without LoadStrip gets no strip and no inset.

No console names were added; none is needed.

Things to check / open questions

  • Capture runs: the analysis now starts for any demo played with the hook loaded, including demos Studio plays while capturing. It runs at lowered priority and refuses demos too big for the game's memory, but it does use CPU and memory during a capture. There is no "a capture is running" flag in the hook to gate on; say if it should wait for one.
  • Build mode: saving a tab in vgui build mode while the strip is on it would write a LoadStrip entry into that tab's .res. Harmless (it would be found and used first), but unusual.

Local checks (worktree, own target dir)

  • rustup run 1.98.1 cargo fmt --all --check: clean
  • rustup run 1.98.1 cargo clippy -p goldsrc-hooks --all-targets --locked --target i686-pc-windows-msvc -- -D warnings: clean
  • rustup run 1.98.1 cargo clippy -p goldsrc-hooks --all-targets --locked -- -D warnings (host): clean
  • cargo test -p goldsrc-hooks --target i686-pc-windows-msvc --locked: 578 passed, 1 ignored (incl. the two new strip tests)
  • cargo build -p goldsrc-hooks --release --target i686-pc-windows-msvc --lib --locked: built; DLL at local\test-797\dodstudio_goldsrc_hooks.dll in the main checkout

Not tested in the game yet.

Live test plan

DLL: local\test-797\dodstudio_goldsrc_hooks.dll. Run on PRE (Half-Life - PRE-Anniversary for Movies) first, then POST (Half-Life - POST-Anniversary for Movies). Demo: wsod25_grp2_h1_hltv in PRE's dod\ (copy it to POST's dod\ for the second run). For the highlights half to show progress, the demo must not be in the analyzer cache yet (else it shows Ready at once): rename its cache entry aside, or pick another uncached demo.

  1. dodstudio_viewdemo_in_panel 1, then viewdemo wsod25_grp2_h1_hltv. The window opens on Playback: a line along the top reads Loading: Demo NN% Highlights NN%, and the Playback controls sit ~20 px lower than usual. The Playback tab's own "Loading the demo: NN%" says the same demo number as the strip.
  2. Click through Demos, Highlights, Console, Settings, Commands, Studio, Review while it loads: the strip is on every tab, controls below it, nothing overlapping. On Highlights, its own "Finding the highlights ... NN%" says the same number as the strip.
  3. Wait for both to finish: the strip goes and every tab's controls are back where they were (the Demos and Highlights lists full height again). Console line: studio_panel: loading strip: gone, both loads done in the hook log.
  4. Window closed: dodstudio_viewdemo_in_panel 0, viewdemo the demo again (renamed cache entry back aside first), never open the window for ~20 s, then ESC -> DoD Studio -> Highlights: the analysis is already well past 0% (or done), so it started without the tab.
  5. Resize the window smaller and larger while the strip shows: the strip spans the tab, the controls stay below it.

🤖 Generated with Claude Code

… loading, and the highlights start finding as soon as a demo plays (#797)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…w and progress bar (#797)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Live-tested unattended (game_probe, Brain account, DLL local\test-797\ from 9a24ced), PRE and POST, with temp demos/bandits-ktps5w10-map2-anzio-over-allies-milo (91 MB; its highlights are in the analyzer cache, so only the demo half of the strip was seen):

  • viewdemo from the console with the window closed: the hook log gets loading strip: Loading: Demo 0% at once and streaks: 22 streaks in ... without any tab opened. Pass both.
  • Demos tab and Highlights tab while loading: Loading: Demo 51% in a strip under the tab row, the tab's controls 20 px lower, list shorter. Pass both.
  • After Demo file completely loaded: strip gone (loading strip: gone, both loads done), Playback tab back at its usual layout. Pass both.
  • Not seen: the Highlights NN% half (needs an uncached demo) and the Playback tab's own bar beside the strip (the window did not open on its own at 5 s in the probe; opened by command instead).

Left for a decision (cosmetic): on the Highlights tab the status label (StreakStatus, wrap 1 since #684) wraps with the long bandits filename. The first build drew its second line over the Min kills row; 9a24ced makes it one line tall while the filters show, which stops the overlap, but the top few pixels of the wrapped second line still peek out above "Min kills" (local\game-probe\20261016-201229\s3-highlights.png PRE, 20261016-201305\s3-highlights.png POST). Options: wrap 0 in Highlights.res (loses #684's wrapped failure messages) or a shorter ready text that fits one line.

Also for a decision, from the PR body: the highlights analysis now starts for every demo the hook sees playing, including the ones Studio plays while capturing.

…OV demo's player, greyed out (#797)

The status line wrapped under the filter row, and once the loading strip
says how far the analysis is, it only repeated the file name. Messages
with nothing to list (no demo, no kills, a failure) go on the hint line
beside Go instead. The Player box shows for every demo: an HLTV demo's
narrows the list, a POV demo's holds the recording player's name and is
disabled. The list moves up into the freed rows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

User live test on POST (DLL local\test-797\): pass: strip on every tab with both halves, Playback's own number matches, strip goes when both loads finish.

Decisions from the test:

  • Status line: removed (it wrapped under the filter row once the window was narrower, and repeated the file name). Min kills removed too. The Player box now shows for every demo: HLTV narrows as before; POV holds the recording player's name, greyed out. No-demo / no-kills / failure messages go on the hint line beside Go. Commit a9c70a8, DLL local\test-797b\.
  • Capture runs: keep as is: the demos a capture plays are already in the analyzer cache from the Capture page, so nothing is analysed then.

Seen during the test, not this PR: some demos sit at Demo 99% for 10-15 s. load_percent clamps at 99 until "Demo file completely loaded", so the buffered time reaches the directory's playback length well before the reading ends (the same number the Playback bar from #758 shows).

ccoventry and others added 4 commits October 17, 2026 01:07
… in words, not a byte dump (#797)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ting it (#797)

ListPanel::SetItemVisible puts a row shown again at the end of the
visible rows, so narrowing and widening the Player filter shuffled them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…w # order, with no heading sort forced (#797)

Instead of hiding rows (SetItemVisible puts a row shown again at the
end) and then sorting by Row #, typing in the Player box refills the
list with the matching streaks in highlight order. A heading the user
clicked still sorts it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ccoventry

Copy link
Copy Markdown
Owner Author

Probe test of 62b2068 (DLL local\test-797e\), POST and PRE: pass

Run by Claude with game_probe on the Brain account, overnight 2026-10-17.

POST (Half-Life - POST-Anniversary for Movies), wsod25_grp2_h1_hltv (from PRE's dod\ via ../../):

  • Highlights tab: no status line, no Min kills; Player box at the top, list right under it.
  • Typed epy in the Player box: only Yesterdays.epyon's rows (6, 13, 19, 44, 52, 59, 66). Deleted the letters: rows back in Row # order, no arrow on any heading.
  • Clicked Kills (▲, then ▼): sorted by kills. Typed dic: only dicE rows, still by Kills ▼. Deleted: all rows, still by Kills ▼.
  • POV demo ktps8w1-element_soul_lenn_h1: Player box reads dicE[: :]element, greyed out; typing does nothing; no Player column.
  • Damaged demo hltv-2508021304-dod_solitude_b2: hint line reads "Could not find the highlights: DoD Studio could not read it: message length…" (cut at the window's edge; the tooltip has the rest). No Player box on that tab (no players to pick), empty list.

PRE (Half-Life - PRE-Anniversary for Movies): the same steps on the same demos: all the same results.

  • Loading strip on PRE (only POST was tested by you): viewdemo "temp demos/bandits-ktps5w10-map2-anzio-over-allies-milo" (91 MB). Strip read "Loading: Demo 38%" on Highlights, "52%" on Demos, "67%" on Playback, and was gone once loaded. The Player box stayed visible under the strip.

Nothing found to fix. Over to you for the look and "merge 804".

Side note for #810: the same PRE run took 90% → loaded in ~8 s while 80% → 90% took 2.1 s, so about 6 s sat at 99%.

@ccoventry

Copy link
Copy Markdown
Owner Author

Probe test on today's dev, together with #820 #806 #804 #816 #814 (2026-10-18)

One local build of dev b7603c4 (with #734 kill-feed scale, #838, #840) + #820 + #806 + #804 + #816 + #814 merged (local\test-batch-1018\; #814's conflict with #806 in studio_panel.rs / verify_studio_panel.py was two comment blocks, both kept; verify_studio_panel.py: OFFSETS VERIFIED). game_probe on the Brain account, POST then PRE (ktps7finalsgoldharringtonside2, POST's dod\, PRE through ../../):

Check POST PRE
#806: drag the Demo File heading's edge 100 px right column widens, the others move right same
#820: dodstudio_spec_match_pov 1, seek 424, in-eye on player 6 stabbed or swung line same
#804/#814: Highlights tab after the demo loads 195 of 195 streaks listed, rows shown same
Crash none none

Frames: local\game-probe\batch-post-sheet.png, batch-pre-sheet.png.

@ccoventry
ccoventry merged commit bd014b0 into dev Oct 18, 2026
5 checks passed
@ccoventry
ccoventry deleted the feat/load-strip-797 branch October 18, 2026 08:07
ccoventry added a commit that referenced this pull request Oct 19, 2026
The stock bar's progress now reads load_progress::demo_percent(), the
number #804's loading strip and #816's lead-in fix share, so all three
displays agree. console_commands_data.js regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

In-game window: demo and highlight loads start right away, both bars on the main window

1 participant