public override async Task StateEntry() { await _avatar.TriggerOnTransitStageChanged(TransitStage.SendEstablishChildPresence, _avatar.RideOnPrims); SimpleRegionInfo destination = _avatar.TransitArgs.DestinationRegion; //do we have a presence on the destination? if (!_avatar.ScenePresence.RemotePresences.HasPresenceOnRegion(destination.RegionHandle)) { //no, we need to establish a new presence Tuple <EstablishPresenceResult, string> result = await _avatar.ScenePresence.RemotePresences.EstablishPresenceOnRegionLocked(destination, false, true); if (result.Item1 != EstablishPresenceResult.Success) { //something broke _avatar.ScenePresence.ControllingClient.SendAlertMessage( "Unable to complete transfer to new region: " + result.Item2); throw new SendAvatarException( String.Format("Could not establish presence on remote region: {0}", result.Item2)); } RollbackActions.Push(() => { _avatar.ScenePresence.RemotePresences.DropRemotePresenceLocked(destination, true).Wait(); }); } AvatarRemotePresence remotePresence = null; _avatar.ScenePresence.RemotePresences.TryGetRemotePresenceLocked(destination.RegionHandle, (AvatarRemotePresence pres) => { remotePresence = pres; } ); if (remotePresence == null) { //something is horked throw new SendAvatarException( String.Format("Presence could not be established on new region for {0}", _avatar.ScenePresence.Name)); } //we have a presence now, we can send the child agent update await _avatar.TriggerOnTransitStageChanged(TransitStage.SendAvatarHandoff, _avatar.RideOnPrims); //the ChildAgentUpdate below will always stop attachment scripts to transmit their state //if anything from this point on fails, we need to start the scripts running again RollbackActions.Push(() => { List <SceneObjectGroup> attachments = _avatar.ScenePresence.GetAttachments(); foreach (var att in attachments) { att.EndTransit(false); } } ); // Invoke the agent2 entry point ChildAgentUpdate2Response rc = this.SendChildAgentUpdate2(); switch (rc) { case ChildAgentUpdate2Response.Ok: break; // continue normally case ChildAgentUpdate2Response.AccessDenied: throw new SendAvatarException( String.Format("Region entry denied for {0}", _avatar.ScenePresence.Name)); case ChildAgentUpdate2Response.MethodNotAvailalble: throw new SendAvatarException( String.Format("Region change not available for {0}", _avatar.ScenePresence.Name)); case ChildAgentUpdate2Response.Error: default: throw new SendAvatarException( String.Format("Region change failed for {0}", _avatar.ScenePresence.Name)); } //this avatar is now considered a child agent _avatar.ScenePresence.MakeChildAgent(_avatar.TransitArgs.DestinationRegion.RegionHandle); //if there is a failure, we will need to restore the user as a root agent Vector3 restorePos = _avatar.ScenePresence.AbsolutePosition; Util.ForceValidRegionXY(ref restorePos); RollbackActions.Push(() => { _avatar.ScenePresence.MakeRootAgent(restorePos); }); //the user is ready to be transfered IEventQueue eq = _avatar.ScenePresence.Scene.RequestModuleInterface <IEventQueue>(); bool eventWasQueued = false; switch (_avatar.TransitArgs.Type) { case TransitType.OutboundCrossing: eventWasQueued = eq.CrossRegion(_avatar.TransitArgs.DestinationRegion.RegionHandle, _avatar.TransitArgs.LocationInDestination, _avatar.ScenePresence.Velocity, _avatar.TransitArgs.DestinationRegion.ExternalEndPoint, remotePresence.PresenceInfo.FullCapsSeedURL, _avatar.ScenePresence.UUID, _avatar.ScenePresence.ControllingClient.SessionId); break; case TransitType.OutboundTeleport: eventWasQueued = eq.TeleportFinishEvent(_avatar.TransitArgs.DestinationRegion.RegionHandle, 13, _avatar.TransitArgs.DestinationRegion.ExternalEndPoint, 4, (uint)_avatar.TransitArgs.TeleportFlags, remotePresence.PresenceInfo.FullCapsSeedURL, _avatar.ScenePresence.UUID); break; default: throw new SendAvatarException(String.Format("Invalid transit type {0} for sending avatar {1}", _avatar.TransitArgs.Type)); } if (!eventWasQueued) { throw new SendAvatarException(String.Format("Unable to enqueue transfer event for {0}", _avatar.ScenePresence.Name)); } //wait for confirmation of avatar on the other side await _avatar.WaitForRelease(); //matching endtransit for all attachments List <SceneObjectGroup> sentAttachments = _avatar.ScenePresence.GetAttachments(); foreach (var att in sentAttachments) { att.EndTransit(true); } _avatar.ScenePresence.AttachmentsCrossedToNewRegion(); //unsit the SP if appropriate if (_avatar.TransitArgs.RideOnPart != null) { _avatar.TransitArgs.RideOnPart.RemoveSeatedAvatar(_avatar.ScenePresence, false); } //this avatar is history. _avatar.ScenePresence.Reset(_avatar.TransitArgs.DestinationRegion); _avatar.ScenePresence.Scene.EventManager.TriggerAvatarLeavingRegion(_avatar.ScenePresence, _avatar.TransitArgs.DestinationRegion); }