public override async Task StateEntry() { //no matter what happens at this point we want to make sure the avatar doesnt try to immediately recross should we have //a failure. bounce them off the border if (_avatar.TransitArgs.Type == TransitType.OutboundCrossing && _avatar.TransitArgs.RideOnGroup == null) { Vector3 backVel = -_avatar.ScenePresence.Velocity; RollbackActions.Push(() => { Vector3 newpos = _avatar.ScenePresence.AbsolutePosition + (backVel * 2.0f); Util.ForceValidRegionXYZ(ref newpos); _avatar.ScenePresence.AbsolutePosition = newpos; }); } //assert that this avatar is fully in this region before beginning a send if (_avatar.ScenePresence.Connection.State != OpenSim.Framework.AvatarConnectionState.Established) { throw new InvalidOperationException("An avatar can not begin transition to a new region while already in transit"); } //assert that this avatar is not currently establishing connections to other regions if (_avatar.ScenePresence.RemotePresences.HasConnectionsEstablishing()) { // _avatar.ScenePresence.ControllingClient.SendAlertMessage("Can not move to a new region, connections are still being established"); throw new InvalidOperationException("An avatar can not begin transition to a new region while connections are being established to neighbor regions"); } //if we're riding on a prim, wait for the all clear before moving on if (_avatar.TransitArgs.RideOnPart != null) { bool success = await _avatar.WaitForRemoteObjectCreation(); if (!success) { _avatar.ScenePresence.ControllingClient.SendAlertMessage("Unable to create object in remote region"); throw new SendAvatarException("Remote object creation failed"); } } //listeners to this event will stop all traffic and suspend physics for the avatar //there is nothing else we need to do in this state await _avatar.TriggerOnTransitStageChanged(TransitStage.SendBegin, _avatar.RideOnPrims); RollbackActions.Push(() => { var task = _avatar.TriggerOnTransitStageChanged(TransitStage.SendError, _avatar.RideOnPrims); task.Wait(); }); var nextState = new SendAvatarState(_avatar, this); await _avatar.SetNewState(nextState); }
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); }