OpenSimulator Internals/Code Map/ScenePresence
OpenSimulator Internals/Code Map/ScenePresence
[edit]Overview
[edit]OpenSim/Region/Framework/Scenes/ScenePresence.cs
One ScenePresence instance exists per agent per region. It represents the avatar -- whether root (avatar is here) or child (avatar is elsewhere, this is a listening post for interest management). ScenePresence implements IScenePresence and EntityBase.
Lifecycle States
[edit]Governed by ScenePresenceStateMachine. The critical flag for most code paths is IsChildAgent (bool).
| State | IsChildAgent | Description |
|---|---|---|
| Child | true | Pre-seeded in neighbouring region. Tracks position updates, no physics, no full scene state. |
| Root | false | Avatar is present in this region. Full physics, full scene state, heartbeat participation. |
| Deleted | -- | IsDeleted set. Dispose() called. |
Transition from child to root happens in MakeRootAgent(), called from CompleteMovement(). Transition from root to child happens in MakeChildAgent(), called by EntityTransferModule on departure.
See OpenSimulator Internals/Walkthroughs/Avatar Rez In Region for the full transition sequence on login.
Constructor
[edit]ScenePresence(IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
- Sets IsChildAgent = true.
- Sets draw distance from client.StartFar, clamped to region MaxDrawDistance / DefaultDrawDistance.
- Sets RegionHandle, ControllingClient, name fields, UUID, LocalId.
- Fetches UserAccount -- sets m_userFlags and GodController god level. If no account found, god level 0.
- Initialises ScenePresenceAnimator and MovementAnimationOverrides.
- Sets AbsolutePosition from ControllingClient.StartPos.
- Disables child updates and reprioritization (m_childUpdatesBusy = true, m_reprioritizationBusy = true) -- re-enabled after CompleteMovement.
- Calls AdjustKnownSeeds() -- initialises m_knownChildRegions from CapsModule.
- Calls RegisterToClientEvents() -- see Event Wiring below.
- Sets Appearance from passed AvatarAppearance.
- Constructs ScenePresenceStateMachine.
- Calls ControllingClient.RefreshGroupMembership().
Event Wiring
[edit]RegisterToClientEvents() hooks the following on ControllingClient:
| Event | Handler |
|---|---|
| OnCompleteMovementToRegion | CompleteMovement() |
| OnAgentUpdate | HandleAgentUpdate() |
| OnAgentCameraUpdate | HandleAgentCamerasUpdate() |
| OnAgentRequestSit | HandleAgentRequestSit() |
| OnAgentSit | HandleAgentSit() |
| OnSetAlwaysRun | HandleSetAlwaysRun() |
| OnStartAnim | HandleStartAnim() |
| OnStopAnim | HandleStopAnim() |
| OnChangeAnim | avnHandleChangeAnim() |
| OnForceReleaseControls | HandleForceReleaseControls() |
| OnAutoPilotGo | MoveToTargetHandle() |
| OnRegionHandShakeReply | RegionHandShakeReply() |
All removed in RemoveClientEvents() on disposal.
MakeRootAgent()
[edit]private bool MakeRootAgent(Vector3 pos, bool isFlying, ref Vector3 lookat)
Called only from CompleteMovement(). Returns false if already root.
- Acquires m_completeMovementLock.
- Handles pending sit (ParentUUID set): resolves prim, re-seats avatar.
- Sets IsChildAgent = false.
- Updates RegionHandle.
- Fires EventManager.TriggerSetRootAgentScene().
- If not sitting:
- Calls CheckAndAdjustLandingPoint_OS() or _SL() -- adjusts position for telehubs, parcel landing points, ban lines.
- Clamps position to region bounds.
- Raises Z to ground height + avatar half-height.
- If ViaLogin or ViaLocation flags: raycasts downward from PhysSearchHeight (300f) using RayFilterFlags.PrimsNonPhantomAgents to find surface, avoids placing avatar inside objects.
- Sets AbsolutePosition.
- Calls AddToPhysicalScene(isFlying).
- Calls m_scene.SwapRootAgentCount(false, IsNPC).
- Resets MovementFlags = 0.
- Updates circuit: AuthenticateHandler.UpdateAgentChildStatus(circuitCode, false).
- Fires EventManager.TriggerOnMakeRootAgent(this).
Physics position search constants:
- PhysSearchHeight = 300f
- PhysMinSkipGap = 20f
- PhysSkipGapDelta = 30f
- PhysNumberCollisions = 30
MakeChildAgent()
[edit]public void MakeChildAgent(ulong newRegionHandle)
Called by EntityTransferModule when avatar departs.
- Resets m_updateAgentReceivedAfterTransferEvent.
- Clears group information and cross-update flags.
- Unhooks RegionHeartbeatEnd.
- Sets IsChildAgent = true.
- Calls m_scene.SwapRootAgentCount(true, IsNPC).
- Calls RemoveFromPhysicalScene().
- Clears parcel tracking.
- Sends kill packets to root presences that don't know the new region (won't receive the avatar as child).
- Updates circuit: AuthenticateHandler.UpdateAgentChildStatus(circuitCode, true).
- Fires EventManager.TriggerOnMakeChildAgent(this).
CompleteMovement()
[edit]public void CompleteMovement(IClientAPI client, bool openChildAgents)
Triggered by OnCompleteMovementToRegion event from viewer.
- For teleports/crossings: calls WaitForUpdateAgent() -- waits up to 10 seconds for source region's UpdateAgent to arrive (sets m_originRegionID via CopyFrom()).
- For real login (IsRealLogin() true): skips WaitForUpdateAgent().
- Calls MakeRootAgent().
- Sends RegionHandshake if not a crossing.
- Calls ControllingClient.MoveAgentIntoRegion().
- Validates baked texture cache (AvatarFactory.ValidateBakedTextureCache()); queues appearance save if invalid.
- Sends initial avatar data to all presences.
- Sends appearance and animations to self and others.
- For real login: calls Scene.AttachmentsModule.RezAttachments(this).
- For crossing with carried attachments: restarts scripts, sends attachment updates.
- For login: calls IFriendsModule.SendFriendsOnlineIfNeeded().
- Hooks RegionHeartbeatEnd for per-frame processing.
IsRealLogin() check:
(teleportFlags & (ViaLogin | ViaHGLogin)) == ViaLogin
RegionHandShakeReply() / SendInitialData()
[edit]public void RegionHandShakeReply(IClientAPI client) private void SendInitialData()
RegionHandShakeReply() sets NeedInitialData = 2 on receipt of viewer handshake reply.
SendInitialData() is called from Update() when NeedInitialData > 0. It waits for:
- ViewerFlags.SentSeeds to be set (caps seeds sent to viewer).
- NeedInitialData incremented to 6 (several heartbeat frames for viewer to process seeds).
Then fires async (Util.FireAndForget):
- Releases source region via SimulationService.ReleaseAgent() if callback URI present.
- Calls IEntityTransferModule.CloseOldChildAgents().
- Sends terrain layer data if not a teleport.
- Sends parcel info.
- Sends full avatar updates for all other root presences (SendOtherAgentsAvatarFullToMe()).
- Sends ObjectUpdate packets for all scene objects -- full updates or cache probes depending on ViewerFlags.
- Calls IEntityTransferModule.EnableChildAgents() -- seeds neighbouring regions.
- Sets m_childUpdatesBusy = false.
Update()
[edit]Called each heartbeat frame from Scene.Update() for every ScenePresence.
- If NeedInitialData > 0: calls SendInitialData() and returns.
- If IsChildAgent or IsInTransit: returns.
- Calls CheckForBorderCrossing().
- Handles MoveToTarget autopilot updates.
- Handles delayed stop.
- If avatar size changed: sends avatar data to all agents.
- If position, velocity, rotation, or collision plane changed beyond tolerance: calls SendTerseUpdateToAllClients().
- Calls CheckForSignificantMovement().
Physical Scene
[edit]AddToPhysicalScene(bool isFlying):
- Calls PhysicsScene.AddAvatar() -- creates PhysicsActor.
- Wires pa.OnCollisionUpdate → PhysicsCollisionUpdate().
- Wires pa.OnOutOfBounds → OutOfBoundsCall().
- Sets PhysicsActor = pa.
RemoveFromPhysicalScene():
- Interlocked.Exchange to null (thread-safe).
- Unwires collision and OOB events.
- Calls PhysicsScene.RemoveAvatar().
Neighbour Region Tracking
[edit]m_knownChildRegions: Dictionary<ulong, string> -- regionHandle → seed cap URL. m_knownChildRegionsSizeInfo: Dictionary<ulong, spRegionSizeInfo> -- regionHandle → (sizeX, sizeY).
Key methods:
- AddNeighbourRegion() / RemoveNeighbourRegion()
- GetChildAgentsToClose() -- computes which neighbours to close on departure, based on IsOutsideView() distance check (currently hardcoded 255 rather than RegionViewDistance).
- CloseChildAgents() -- sends CloseChildAgentConnections to computed list, drops cap seeds.
Sitting
[edit]HandleAgentRequestSit() → SendSitResponse() → HandleAgentSit() / PhysicsSit().
PhysicsSit() delegates to PhysicsScene.SitAvatar() with callback PhysicsSitResponse(). Falls back to legacy sit if physics engine doesn't support it.
On sit:
- RemoveFromPhysicalScene().
- ParentID = part.LocalId, ParentPart = part.
- part.AddSittingAvatar(this).
- Animator.SetMovementAnimations("SIT").
StandUp():
- Computes world position from sit offset and prim rotation.
- Clears ParentID, ParentPart.
- Calls AddToPhysicalScene() if addPhys true.
- part.RemoveSittingAvatar(this).
- Animator.SetMovementAnimations("STAND").
SIT_TARGET_ADJUSTMENT = (0, 0, 0.4f) -- empirically derived fudge factor matching SL behaviour (Mantis 1716).
Parcel Visibility
[edit]ParcelHideThisAvatar: true if current parcel has SeeAVs = false.
On parcel crossing (currentParcelUUID setter → ParcelCrossCheck()):
- Computes which presences need kill packets (now hidden from them or they from us).
- Computes which presences need view packets (now visible).
- Sends kills and views accordingly.
Child Agent Data Transfer
[edit]CopyTo(AgentData, isCrossUpdate): serialises full avatar state for transfer to destination region -- position, velocity, camera, appearance, animations, attachments, script controls, group info, friends online cache.
CopyFrom(AgentData): deserialises on destination side. Sets m_originRegionID, which signals WaitForUpdateAgent() to unblock CompleteMovement().
UpdateChildAgent(AgentData): called on destination when source fires UpdateAgent. Calls CopyFrom() then sets m_updateAgentReceivedAfterTransferEvent.
UpdateChildAgent(AgentPosition): lightweight position-only update for child agent interest management. Adjusts position by region offset, updates throttles with distance-based scaling factor.
Movement
[edit]HandleAgentUpdate(): main movement handler. Processes AgentUpdateArgs from viewer each packet.
- Drops updates where IsChildAgent or IsInTransit.
- Updates DrawDistance, HideTitle, MuteCollisions, mouse state, State byte.
- Computes movement vector from control flags.
- Calls AddNewMovement() → sets PhysicsActor.TargetVelocity.
- Calls Animator.UpdateMovementAnimations().
- Calls SendControlsToScripts() -- fires EventManager.TriggerControlEvent for scripted control listeners.
Autopilot: MoveToTarget() / HandleMoveToTargetUpdate() -- PID-style movement toward a target position, used by llMoveToTarget() and parcel enforcement.
Border crossing detection: CheckForBorderCrossing() -- projects position by velocity * FrameTime, if outside region bounds calls CrossToNewRegion() → Scene.CrossAgentToNewRegion().
Attachment Management
[edit]m_attachments: List<SceneObjectGroup>, locked on AttachmentsSyncLock.
AddAttachment() / RemoveAttachment() / GetAttachments() / ClearAttachments().
SendAttachmentsToAgentNF(): sends terse update then full updates for all attachments to a specific presence. SendAttachmentScheduleUpdate(): sends pending flagged updates to self and all visible presences.
Animation
[edit]Animator: ScenePresenceAnimator -- manages animation state machine. Overrides: MovementAnimationOverrides -- server-side animation override pairs.
HandleStartAnim() / HandleStopAnim() / avnHandleChangeAnim(): viewer-initiated animation control. RegionHeartbeatEnd hook: calls Animator.UpdateMovementAnimations() every 2 frames when root and not sitting.
Significant Movement
[edit]CheckForSignificantMovement():
- MOVEMENT (0.25f sq) threshold: fires EventManager.TriggerOnClientMovement().
- SIGNIFICANT_MOVEMENT (16.0f sq) threshold: fires EventManager.TriggerSignificantClientMovement().
- CHILDAGENTSCHECK_MOVEMENT (1024f sq / 32m) threshold: calls IEntityTransferModule.EnableChildAgents() to update neighbour seeds.
- CHILDUPDATES_MOVEMENT (100f sq): sends AgentPosition updates to known child regions.
Key Constants
[edit]| Constant | Value | Purpose |
|---|---|---|
| MOVEMENT | 0.25f | Minimum movement to trigger client movement event (sq distance) |
| SIGNIFICANT_MOVEMENT | 16.0f | Minimum movement to trigger significant movement event (sq distance) |
| CHILDUPDATES_MOVEMENT | 100.0f | Minimum movement to send child agent position update (sq distance) |
| CHILDAGENTSCHECK_MOVEMENT | 1024.0f | Minimum movement to recheck neighbour child agents (sq distance, ~32m) |
| CHILDUPDATES_TIME | 2000f | Minimum ms between child agent updates |
| SIT_TARGET_ADJUSTMENT | (0,0,0.4f) | Sit target fudge factor matching SL (Mantis 1716) |
| PhysSearchHeight | 300f | Ray cast start height for spawn position search |
| PhysMinSkipGap | 20f | Minimum gap between surfaces in spawn position search |
| AgentControlNormalVel | 4.096f | Normal walk speed multiplier |
| AgentControlMidVel | 0.6 * 4.096f | Slow walk speed multiplier |
Known Issues
[edit]- IncomingAttechments() typo in Scene.cs line 2976 and AttachmentsModule.cs line 384 (Mantis pending).
- GetChildAgentsToClose() uses hardcoded 255 for view distance rather than RegionViewDistance -- comment in source acknowledges this.
See Also
[edit]- OpenSimulator Internals/Code Map/Scene
- OpenSimulator Internals/Code Map/LLClientView
- OpenSimulator Internals/Code Map/LLUDP
- OpenSimulator Internals/Walkthroughs/Avatar Rez In Region
- OpenSimulator Internals/Walkthroughs/Avatar Transfer Between Regions
- OpenSimulator Internals/Walkthroughs/Avatar Logs Out