Implement native agent movement and teleportation (#60)
All checks were successful
Native code generation / deterministic (push) Successful in 12m6s
Imaging and meshing gate / native (push) Successful in 4m6s
Native Rust workspace compile / compile (push) Successful in 4m10s

This commit is contained in:
2026-08-09 23:07:30 +00:00
parent 9c9d5b91f1
commit 0791e0a69e
13 changed files with 4060 additions and 936 deletions

65
docs/agent-movement.md Normal file
View File

@@ -0,0 +1,65 @@
# Agent movement, camera, teleport, and region crossing
`AgentManager::movement` is backed by native Rust state and emits the same
LLUDP messages as LibreMetaverse's C# `AgentMovement`. The 32 control flags keep
their protocol bit positions. `ResetControlFlags` preserves away, fly,
mouselook, and crouch (`UP_NEG`), and automatic reset happens only after an
`AgentUpdate` was actually sent. Duplicate idle updates are limited to the same
ten transmissions as the reference implementation.
The camera retains the reference `CoordinateFrame` behavior, including the
public wrapper's deliberate axis mapping: `AtAxis` exposes frame Y and
`LeftAxis` exposes frame X, while `LookDirection` writes the requested forward
vector to frame X. Roll, pitch, yaw, heading, look-at, and orthonormalization
are native floating-point operations. Non-finite inputs return the mapped
argument error instead of placing invalid values on the wire.
## Update lifecycle
The update worker starts after a successful login only when
`SendUpdatesRegularly` is enabled. It uses the configured
`AgentUpdateInterval`, wakes immediately when that interval changes, pauses on
disconnect, and is joined by `Dispose` or normal destruction. A condition variable
drives cadence and shutdown, so the implementation neither polls nor
uses arbitrary sleeps. Manual updates remain available when periodic updates
are disabled. Both paths refuse to send before simulator movement/handshake
completion, as required by their respective C# methods.
Locomotion methods send real packets: flying, crouching, jumping, standing,
ground sitting, object sitting, always-run, FOV, and autopilot use
`AgentUpdate`, `AgentRequestSit`, `AgentSit`, `SetAlwaysRun`, `AgentFOV`, and
`GenericMessage` with the reference field layout and reliability choices.
## Teleports and simulator crossings
Landmark, location, named-region, and lure requests share a generation-tagged
teleport waiter. UDP `TeleportStart`, `TeleportProgress`, `TeleportFailed`,
`TeleportCancel`, `TeleportLocal`, and `TeleportFinish` packets, together with
their CAPS finish/failure equivalents, update status before raising
`TeleportProgress`. Finish, failure, cancellation, timeout, disposal, and a
superseding request all resolve the waiter exactly once. Cancellation and
timeouts are executor-driven and do not leave a task or callback registered.
`CrossedRegion` starts a bounded native state machine with the C# states and
failure reasons. It connects the destination simulator, retries failed
connections up to three times, waits for that simulator's
`AgentMovementComplete`, restores the old simulator after rejection, timeout,
or manual cancellation, disconnects a partial destination, and raises
`RegionCrossed` after state mutation. `GetCrossingState`,
`GetCrossingFailureReason`, `GetCrossingDetails`, `IsCrossing`, and
`CancelCrossing` expose the same diagnostic surface. Crossing and periodic
update threads use weak ownership, cancellation wakeups, and joined handles.
When `MultipleSims` is enabled, movement completion also snapshots presence,
position, rotation, and update time per simulator. Velocity near a region edge
raises `RegionCrossingPredicted` with the matching cardinal direction, and the
reference child-agent request bookkeeping is maintained with its 30-second
deduplication and two-minute expiry windows. Border-object visibility is
tracked through `TrackObjectInSimulator`, `UntrackObjectInSimulator`, and
`GetSimulatorsForObject`; disconnected simulator entries are pruned without
holding locks while callbacks run.
Tests use paused Tokio time for teleport timeout/cancellation and loopback UDP
fake grids for packet-level movement. They decode the emitted control flags,
camera/FOV values, always-run state, and invariant-culture autopilot parameters
rather than accepting method invocation alone as evidence.