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.