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); }
private async Task<Tuple<EstablishPresenceResult, string>> DoEstablishPresenceOnRegion(SimpleRegionInfo region, AvatarRemotePresence initPresence) { Tuple<EstablishPresenceResult, string> establishResult; try { establishResult = await this.LaunchNewEstablishChildTask(initPresence, region); } catch (Exception e) { establishResult = new Tuple<EstablishPresenceResult, string>(EstablishPresenceResult.ErrorInformingRegion, e.Message); } bool failure = false; TryGetRemotePresenceLocked(region.RegionHandle, (AvatarRemotePresence presence) => { //success, change the status of the task if (presence != null) { if (establishResult.Item1 == EstablishPresenceResult.Success) { presence.State = RemotePresenceState.ViewerWait; } else { //failure contacting other region _remotePresences.Remove(region.RegionHandle); failure = true; } } else { failure = true; //hmm, someone stole this presence from us _log.ErrorFormat("[REMOTEPRESENCE]: Unable to update child presence established to {0} for {1}. Child presence missing.", establishResult, _sp.Name); establishResult = Tuple.Create(EstablishPresenceResult.ConnectionAborted, "Connection was aborted"); } }); if (failure) { return establishResult; } //now we need to call out to the remote region to wait for the SP to be set up bool waitSuccess = await WaitForScenePresenceEstablished(region); Tuple<EstablishPresenceResult, string> result = null; TryGetRemotePresenceLocked(region.RegionHandle, (AvatarRemotePresence presence) => { //success, change the status of the task if (presence != null) { if (waitSuccess) { presence.State = RemotePresenceState.Established; result = Tuple.Create(EstablishPresenceResult.Success, String.Empty); } else { //failure waiting for SP _remotePresences.Remove(region.RegionHandle); result = Tuple.Create(EstablishPresenceResult.ClientWaitTimeout, "Destination region never received a connection from the viewer"); } } else { //hmm, someone stole this presence from us _log.ErrorFormat("[REMOTEPRESENCE]: Unable to update child presence established to {0} for {1}. Child presence missing.", establishResult, _sp.Name); result = Tuple.Create(EstablishPresenceResult.ConnectionAborted, "Connection was aborted"); } }); return result; }
private Task<Tuple<EstablishPresenceResult, string>> LaunchNewEstablishChildTask(AvatarRemotePresence presence, SimpleRegionInfo region) { AgentCircuitData agent = _sp.ControllingClient.RequestClientInfo(); agent.BaseFolder = UUID.Zero; agent.InventoryFolder = UUID.Zero; agent.startpos = Scene.DEFAULT_CHILD_AGENT_POS; agent.child = true; agent.CapsPath = presence.PresenceInfo.CapsPath; return _scene.SceneGridService.EstablishChildConnectionToRegionAsync(_sp, agent, region); }
/// <summary> /// Attempts to establish a presence on the given region /// </summary> /// <param name="region">The region we want to establish a child presence on</param> /// <param name="forceReestablish">Whether to force a reestablishment even if we already think we have a remote presence</param> /// <param name="isFarPresence">Is this presence intentionally far away? Eg. The beginning of a remote teleport</param> /// <returns></returns> private async Task<Tuple<EstablishPresenceResult, string>> EstablishPresenceOnRegion(SimpleRegionInfo region, bool forceReestablish, bool isFarPresence) { Task<Tuple<EstablishPresenceResult, string>> establishTask = null; bool presenceExisted = false; //check if we already have or are waiting on an establish TryGetRemotePresenceLocked(region.RegionHandle, (AvatarRemotePresence presence) => { if (presence != null && !forceReestablish) { //we have a presence //if it is established just return if (presence.State == RemotePresenceState.Established) { presenceExisted = true; } else { //if not, we can await the existing callback establishTask = presence.EstablishTask; } } else { //we have no presence and we're not waiting for a callback //begin an async establish and await a callback presence = new AvatarRemotePresence { PresenceInfo = new RemotePresenceInfo { RegionInfo = region, CapsPath = CapsUtil.GetRandomCapsObjectPath() }, IsFarPresence = isFarPresence, State = RemotePresenceState.Establishing }; if (_remotePresences.ContainsKey(region.RegionHandle)) _remotePresences.Remove(region.RegionHandle); _remotePresences.Add(region.RegionHandle, presence); establishTask = DoEstablishPresenceOnRegion(region, presence); presence.EstablishTask = establishTask; } }); //nothing to do, we're already established if (presenceExisted) return Tuple.Create(EstablishPresenceResult.Success, String.Empty); return await establishTask; }