Skip to content

Nav: props block the ground they actually stand on, the same in the game and the tools - #33

Open
dafioram wants to merge 9 commits into
mainfrom
fix/prop-footprints
Open

dafioram wants to merge 9 commits into
mainfrom
fix/prop-footprints

Conversation

@dafioram

@dafioram dafioram commented Nov 5, 2026 •

Copy link
Copy Markdown
Owner

First of four stacked nav PRs, now that hero-orders has merged. Next: nav replay tools (tools/nav-replay), then multi-floor walking and door seams, which still need playtesting.

What was wrong

  • Discs, not footprints. Mid-size props (carts, tables, beds) blocked a disc centered on their origin rather than the ground they stand on. A disc overshoots a rectangle's sides and can sit in the wrong place entirely: the farmhouse cart's disc landed on the stairs because it was anchored at the transform origin, not the placed bounding box.
  • Tools and game disagreed. The nav tools placed props with a different transform from the game (no root bind pose, no scale_multiplier), so offline replays blocked different ground from what the player saw.
  • Slow re-stamping. Marking obstacles tested every triangle on the mesh for every prop, and re-ran on every break (a krug smashing a barrel): a ~200 ms hitch each time.

What this changes

  • One footprint. PropFootprint and PropObstacle (Core) compute a prop's footprint from its placed bounding box, detecting which box axis stands up. They mark it as a capsule (fences, walls), a disc grid (wagons, stalls) or its exact rectangle (mid-size props). The game and the tools both mark through them, placing props identically (PropBindPose, moved to Core; IsRigidRootProp and ComputeRootBindPose in RenderHost now delegate to it). Covered by PropFootprintTests.
  • Exact rectangles. A rectangle obstacle blocks the triangles it actually covers, and seals a sliver only on a real crossing.
  • Faster stamps. Obstacle stamps visit only the triangles under the footprint, via the lookup grid. The break hitch is gone.
  • hero-sim. Names the prop blocking each failed walk; --broken leaves out props smashed in the session being replayed; --from/--to replays one click walk from the game log's coordinates; --dump writes the nav mesh and prop footprints around a point as text.

Relation to open work

Testing

  • dotnet build SiegeFX.sln -c Release -warnaserror: 0 warnings, 0 errors. dotnet test: all 133 pass.
  • Played (on the playtest branch): the farmhouse cart, beds and tables block where they stand; breaking barrels no longer hitches.

🤖 Generated with Claude Code

https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs

@dafioram
dafioram force-pushed the fix/prop-footprints branch 2 times, most recently from 9d0776c to db2a384 Compare November 7, 2026 20:01
dafioram and others added 9 commits November 7, 2026 23:15
Replays a single click walk with the coordinates the game log prints,
with the follower's diagnostics on, so a stuck walk from a playtest can
be stepped through offline.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
The no-corridor diagnosis listed blockers without saying which prop
they were. Each obstacle disc is now tagged with its template and scid.
--broken=<template|0xscid>,... leaves out props the player broke in the
session being replayed, which block nothing in-game.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
A does_block_path prop that is neither long and thin nor big blocked a
disc reaching its bounding box's corners. Beside a rectangle's sides
that overshoots: a farmhouse bed's 1.66u disc covered the top stair
triangles beside it and sealed the upper floor (hero-sim replay of the
field log: sealed by bed_glb_04). These props now block their oriented
footprint rectangle plus 0.1u, with the disc's rules otherwise (the
vertical band, centroid containment, edge crossings only for small
triangles). The game and hero-sim/roam-sim's mirror both change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
The 0.1u margin is for centroid containment (bodies on a tile). Applied
to the edge-crossing test it let two slivers grazing the bed's side at
the farmhouse stair top seal the stair (hero-sim replay: bed_glb_04
rect edge a=0.25 / a=0.00).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
The farmhouse stair's only links to the ground floor are three slivers
at its foot. A cart's (in-game) or the bed's (hero-sim) footprint
grazed their edges, and the edge test sealed them, cutting the stair
off from both floors (field log: every click from the stair rejected,
sealed by cart_grs_03 rect edge a=0.25/0.22/0.00). An edge crossing now
seals a small triangle only when at least 0.4u of the edge lies inside
the footprint; the blame tag records that depth.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
The farmhouse stair was still sealed (field log: every click from its
foot refused, sealed by cart_grs_03 rect edge a=0.25 in=0.45, tri
14162), just past the 0.4u edge-depth rule. Two rules for mid-size
(rectangle) props:
- An edge crossing seals a small triangle only when the triangle's
  center is within 0.3u of the footprint: a sliver that merely clips a
  corner stays walkable.
- A rectangle prop blocks surfaces up to 0.9u above its base (and no
  higher than its top + 0.5), the ground it stands on; raised floors
  and stairs beside it, across a wall, are no longer blocked.
Disc obstacles (long fences, big wagons) keep their band: one center
base height would leave a hillside fence's uphill end unblocked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
Writes every nav triangle within --near (source snode, vertices,
neighbours across each edge, extra links, and the blame tag of whatever
blocks it) and each blocking prop's footprint and Y band. Enough to
redraw a sealed stair or doorway and check it against the walls without
the game data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
A blocking prop's footprint was its mesh-space X × Z box run through its
world transform, with the height band from mesh Y. Props authored Z-up
and stood up by their root bind pose (most rigid props) are the other
way round, so their footprint spanned their height and their band their
length. The nav tools placed props without the root bind pose or
scale_multiplier at all, so a replay blocked different ground than the
game: the farmhouse stair the game blames on cart_grs_03 is open in
hero-sim, which puts that cart in the yard.

PropFootprint.FromBounds now takes the placed bounding box: the axis the
transform points most nearly up is the height, the other two span the
rectangle, and the band runs from the lowest to the highest corner.
PropObstacle.Mark holds the capsule/grid/rectangle rules, and the game and
the tools both mark through it, the tools placing each prop as the game
does (scale × root bind pose × placement × node; the bind-pose helpers
move to Core as PropBindPose). Blame tags carry the footprint's center.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
Every break (a krug smashing a barrel, the hero a door) re-stamps all
blocking props, and each disc and rectangle stamp tested every triangle
of the ~50k-triangle mesh: ~95 props (more discs for fences) x 50k
tests, a ~200ms frame each time (the field log's [perf] slow frames sit
right after each '[smash]' / 'click-break'). The stamps now take their
candidates from the mesh's XZ lookup grid (TrianglesNear, deduplicated):
the same triangles can be hit, the far ones are never visited.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FdjaHiBNBYFeCRNMsCg2Bs
@dafioram
dafioram force-pushed the fix/prop-footprints branch from db2a384 to 5d8a353 Compare November 7, 2026 23:25
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.

1 participant