Files
MetaCrate/docs/agent-movement.md
Chili Palmer 0791e0a69e
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
Implement native agent movement and teleportation (#60)
2026-08-09 23:07:30 +00:00

3.8 KiB

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.