capture: a setup slot, for the moment before the scene ages
$WOW_CAPTURE_SETUP runs a chunk at the first aging frame -- early enough to change a setting or create a frame and still have the scene settle around it. $WOW_CAPTURE_EVAL keeps the shutter, where a read and the pixels it explains come from the same frame; anything created there is a frame too late to be in the image. The deep-zoom map shot needed it. OpenMapClassic resolves minimap tiles by FileDataID by default and this client has none, so its own status reports "loaded YES=0 NO=8"; it already carries a path mode for exactly that, asking for textures\Minimap\<folder>\map<col>_<row>, of which this install ships 10,884. Switching to it raised, because S.ResetMinimapTiles reads lodPieces/lodPool sixteen lines before they are declared and so bound them to nil globals -- an upstream bug, and the only two callers are the two switches that reach the mode. Port edits mirrored to Addon_Ports/openmap_port/: the declaration moved above its use, and the tile mode defaulted to the one that can work here. Captured at zoom 40: the minimap's terrain draws through the map. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
@@ -869,32 +869,39 @@ struct LateCapture<'w> {
|
||||
script: Option<NonSendMut<'w, benilla_ui::script::UiScript>>,
|
||||
}
|
||||
|
||||
/// `$WOW_CAPTURE_EVAL=<lua>`: run a chunk in the capture's own VM at the shutter and log what it
|
||||
/// answers, as `capture eval:` lines.
|
||||
/// Run a chunk in the capture's own VM and log what it answers, as `capture <label>:` lines.
|
||||
///
|
||||
/// Two slots, because a capture has exactly two moments worth reaching:
|
||||
///
|
||||
/// * **`$WOW_CAPTURE_SETUP`**, at the first aging frame — early enough to change a setting, open
|
||||
/// something or create a frame, and still have the scene settle around it before the shutter.
|
||||
/// * **`$WOW_CAPTURE_EVAL`**, at the shutter — the settled state, so a number and the pixels it
|
||||
/// explains come from the same frame. Reads only: a frame created here is one frame too late
|
||||
/// to be in the image.
|
||||
///
|
||||
/// A capture is the only harness that has both a renderer and a player's interface, and it had no
|
||||
/// way to be *asked* anything — every question about what a shot shows had to be answered by
|
||||
/// looking at the picture. A chunk here is read at the one instant the image is taken, so a number
|
||||
/// and the pixels it explains come from the same frame. `\n` in the answer is split across lines,
|
||||
/// so a probe can return a block.
|
||||
fn capture_eval(script: Option<NonSendMut<benilla_ui::script::UiScript>>) {
|
||||
let Ok(chunk) = std::env::var("WOW_CAPTURE_EVAL") else {
|
||||
fn capture_lua(var: &str, label: &str, script: Option<NonSendMut<benilla_ui::script::UiScript>>) {
|
||||
let Ok(chunk) = std::env::var(var) else {
|
||||
return;
|
||||
};
|
||||
if chunk.is_empty() {
|
||||
return;
|
||||
}
|
||||
let Some(script) = script else {
|
||||
warn!("capture eval: no interface in this capture, nothing to ask");
|
||||
warn!("capture {label}: no interface in this capture, nothing to ask");
|
||||
return;
|
||||
};
|
||||
match script.eval::<String>(&chunk) {
|
||||
Ok(out) => {
|
||||
for line in out.lines() {
|
||||
info!("capture eval: {line}");
|
||||
info!("capture {label}: {line}");
|
||||
}
|
||||
}
|
||||
Err(e) => warn!("capture eval: raised: {e}"),
|
||||
Err(e) => warn!("capture {label}: raised: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,6 +1057,9 @@ fn drive_capture(
|
||||
}
|
||||
}
|
||||
Phase::Aging(n) => {
|
||||
if n == 0 {
|
||||
capture_lua("WOW_CAPTURE_SETUP", "setup", late.script.take());
|
||||
}
|
||||
// No restart on late arrivals: the image already stopped changing before release.
|
||||
if n + 1 < age_frames() {
|
||||
Phase::Aging(n + 1)
|
||||
@@ -1078,7 +1088,7 @@ fn drive_capture(
|
||||
);
|
||||
Phase::ProbeWarmup(0)
|
||||
} else {
|
||||
capture_eval(late.script.take());
|
||||
capture_lua("WOW_CAPTURE_EVAL", "eval", late.script.take());
|
||||
commands
|
||||
.spawn(Screenshot::primary_window())
|
||||
.observe(save_to_disk(ctx.out.clone()));
|
||||
|
||||
@@ -2951,3 +2951,42 @@ The palette is now read as "as much as the file has", and an index past the end
|
||||
black, which is what an unused index means. `every_world_map_texture_in_the_chain_decodes` walks
|
||||
the whole folder: **3553 textures, 7 failures before, 0 after.** It fails on the old decoder,
|
||||
which is the only reason to trust it.
|
||||
|
||||
## The deep zoom: the minimap over the map
|
||||
|
||||
"Zoom in all the way into the minimap mapped out over the map" was one of the two things grom
|
||||
named. OpenMapClassic already has the mechanism for a client without FileDataIDs — `/omc tilemode`
|
||||
picks between `fdid` (Forever's numeric ids) and `twm`, which asks for
|
||||
`textures\Minimap\<folder>\map<col>_<row>`. This install ships **10,884** of those. `/omc status`
|
||||
on the fdid default reports `terrain sample summary: loaded YES=0 NO=8`, which is what a client
|
||||
with no FileDataIDs has to report.
|
||||
|
||||
Switching it raised:
|
||||
|
||||
```
|
||||
Close.lua:196: bad argument #1 to `pairs' (table expected, got nil)
|
||||
```
|
||||
|
||||
`local lodPieces, lodPool, wantedLOD` is declared at line 212 and read by `S.ResetMinimapTiles` at
|
||||
196. Lua binds a name at compile time, so inside that function the three resolved to the
|
||||
**globals** of those names — nil — and every call raised. Its only two callers are `/omc tilemode`
|
||||
and `/omc layer close|lod`, so the one switch this client needs could not be thrown. An upstream
|
||||
bug; the port edit moves the declaration above the function.
|
||||
|
||||
Two port edits, both mirrored at `Addon_Ports/openmap_port/`:
|
||||
|
||||
- `Map/Close.lua:194` — the declaration moved above its use.
|
||||
- `Map/Close.lua:26` — `minimapTileMode` defaults to `"twm"`. Not a preference: `fdid` cannot
|
||||
resolve a tile on a client that has no FileDataIDs. The blend itself stays off by default,
|
||||
which is upstream's choice (`/omc minimap on`).
|
||||
|
||||
Captured at zoom 40 with the blend on: the minimap's own terrain draws through the map's
|
||||
parchment, roads and ridges and all, under the zone's labels.
|
||||
|
||||
### A second slot on the capture harness
|
||||
|
||||
`$WOW_CAPTURE_SETUP=<lua>` runs at the **first aging frame**, early enough to change a setting,
|
||||
open something or create a frame and still have the scene settle around it. `$WOW_CAPTURE_EVAL`
|
||||
keeps the shutter, where a read and the pixels it explains come from the same frame. The deep-zoom
|
||||
shot needed the first: the tile mode has to be switched before anything draws, and a chunk at the
|
||||
shutter is a frame too late to appear in the image.
|
||||
|
||||
Reference in New Issue
Block a user