Skip to content

Global collision/hybrid live collision#9

Merged
infuse21 merged 7 commits into
So-I-dont-Fuck-The-Walker-KEKfrom
global-collision/hybrid-Live-collision
Jul 23, 2026
Merged

Global collision/hybrid live collision#9
infuse21 merged 7 commits into
So-I-dont-Fuck-The-Walker-KEKfrom
global-collision/hybrid-Live-collision

Conversation

@infuse21

Copy link
Copy Markdown
Owner

No description provided.

infuse21 and others added 7 commits July 23, 2026 10:20
Adds an immutable live-collision overlay on top of the static SplitFlagMap so
pathfinding and smoothing can reflect the loaded scene, gated by a config flag
that defaults OFF. Out-of-scene routing is unchanged — the static map still
owns global routes.

New pathfinder/live package:
- LiveCollisionSnapshot: immutable, world-addressed, known/value per edge so the
  scene rim reads as unknown and falls back to the static map.
- LiveCollisionOverlay: shared, atomically-swapped volatile holder read lock-free
  by every CollisionMap.
- LiveCollisionCapture: client-thread builder mirroring Rs2Tile's CollisionDataFlag
  translation; instances return null (static fallback) pending dedicated chunk
  mapping.

CollisionMap.get() consults a per-search pinned snapshot then the static map, so
both neighbour expansion and PathSmoother pick it up from one place. PathfinderConfig
owns the shared overlay behind its ThreadLocal<CollisionMap>; Pathfinder.run() pins
the snapshot per search so a mid-search swap cannot mix two scenes. ShortestPathPlugin
rebuilds the snapshot on scene-base change from the onGameTick client thread (no
per-tick allocation).

With the flag off a CollisionMap reads byte-for-byte as the static-only map, so the
existing shortestpath suite is unchanged. New LiveCollisionTest covers the flag
translation (walls, symmetry, full-block closing all four edges), rim/out-of-scene
fallback, overlay-wins-in-scene, and no-overlay determinism. Guardrail stays green.

Stage 2 (door/openable-edge preservation) and Stage 3 (debounced scene-change
recalc) follow.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ge 2)

A closed door blocks its doorway in RuneLite's live collision, so with the
overlay on the pathfinder would route around an openable door instead of
walking up and opening it — the static map treats the doorway as passable and
the runtime door subsystem (Rs2Walker.handleDoors) opens the physical door as
the path crosses it.

LiveCollisionCapture now scans the loaded scene on the client thread for wall
objects with a door action (open / go-through / walk-through / pass / pick-lock
/ pay-toll, incl. multiloc impostors) and leaves every edge touching such a
tile UNKNOWN in the snapshot. Unknown edges already fall back to the static map
in CollisionMap.get, so the existing door pipeline keeps owning doors unchanged
— no CollisionMap change needed.

Transports need no handling: getNeighbors adds transport edges independently of
the collision traversability check, so a live-blocked walking edge never removes
a transport edge. That, plus the door exemption, covers the false-"unreachable"
cases without a blanket fallback that would defeat live blocking of genuine new
obstacles.

Tests: door-tile edges stay unknown even when live flags block all four sides;
null door mask matches the no-door path. Full suite and guardrail green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
GET /live-collision[?x=&y=&plane=] reports whether the live-collision overlay is
enabled and captured, the snapshot's scene base, and per-tile the overlay's own
edge readings (overlayRaw: true/false/null=defer-to-static), the resolved edges
the pathfinder uses, and the static-only edges. Where resolved differs from
static, live collision is changing routing.

The overlay and pathfinder are otherwise not observable over HTTP; this exists to
verify the hybrid live-collision work against a running client. Logic lives in
PathfinderConfig.liveCollisionDiagnostics (immutable reads, any thread); the
handler is thin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
RuneLite's collision for the outer ring of the loaded scene is incomplete while
adjacent chunks are only partially loaded. Verified against a running client: the
border produced a uniform band of ~1260 false walls out to about five tiles deep,
while the deep interior matched reality. Stage 1's rim handling only exempted the
outermost neighbour-out-of-scene edges, so those false walls leaked into the
overlay and would fabricate obstacles near every scene boundary.

LiveCollisionCapture now treats any tile within SCENE_BORDER_MARGIN (8) of the
scene edge as unknown, deferring to the static map there. The scene always loads
centred on the player (~tile 52 of 104), so the trusted ~88x88 interior still
covers everything near the player, and the border recentres before the player
reaches it. Eight gives headroom over the ~5 tiles of artifact observed (real
live-vs-static differences began at ~24 tiles in, a clean gap).

Re-verified live after the fix: border diffs 1260 -> 0, while the genuine
interior corrections (incl. 3 stale-static unblocks) are preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…stage 3)

Stage 1 refreshed the overlay only on scene-base change, so a door closing or a
temporary object appearing mid-scene was not picked up until the next reload, and
the walker would walk into it and stall.

Now object spawn/despawn (game + wall) mark the snapshot dirty, and refreshLiveCollision
rebuilds it at most once per tick. After a mid-scene rebuild it validates the walker's
remaining route against the fresh overlay via LiveRouteValidator and, if a walking step
within a 15-tile look-ahead is now blocked, calls the walker's public recalculatePath()
so it routes around before stalling. Cooldown-gated (3s) so churn cannot spam recalcs.

Driven entirely from the plugin's onGameTick (client thread) using public walker API —
the walker's internal loop is untouched. Openable doors and transports are skipped by
LiveRouteValidator (door edges are unknown in the overlay, transport jumps are
non-adjacent), so this never fights the runtime door handler. Scene reloads do not
trigger a proactive recalc (they usually just recenter); the walker's own machinery
picks up the fresh snapshot there.

LiveRouteValidator is a pure helper with unit tests: nearest-index, detects a live-blocked
walking step, skips transport/cross-plane jumps, respects the look-ahead bound. The four
object subscribers only set a volatile flag (no client reads), so the guardrail is
unaffected. Full suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@infuse21 infuse21 self-assigned this Jul 23, 2026
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: d4cad350-b2bf-4ccb-8d86-e9eede903d0b

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch global-collision/hybrid-Live-collision

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@infuse21
infuse21 merged commit c2257d1 into So-I-dont-Fuck-The-Walker-KEK Jul 23, 2026
2 of 3 checks passed
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