public void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq) { if (reg == null || finalDestination == null) { sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); return; } m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Request Teleport to {0} ({1}) {2}/{3}", reg.ServerURI, finalDestination.ServerURI, finalDestination.RegionName, position); uint newRegionX = (uint)(reg.RegionHandle >> 40); uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); ulong destinationHandle = finalDestination.RegionHandle; // Let's do DNS resolution only once in this process, please! // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, // it's actually doing a lot of work. IPEndPoint endPoint = finalDestination.ExternalEndPoint; if (endPoint.Address != null) { // Fixing a bug where teleporting while sitting results in the avatar ending up removed from // both regions if (sp.ParentID != (uint)0) sp.StandUp(); if (!sp.ValidateAttachments()) m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Failed validation of all attachments for teleport of {0} from {1} to {2}. Continuing.", sp.Name, sp.Scene.RegionInfo.RegionName, finalDestination.RegionName); // if (!sp.ValidateAttachments()) // { // sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); // return; // } string reason; string version; if (!m_aScene.SimulationService.QueryAccess(finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) { sp.ControllingClient.SendTeleportFailed("Teleport failed: " + reason); return; } m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Destination is running version {0}", version); sp.ControllingClient.SendTeleportStart(teleportFlags); // the avatar.Close below will clear the child region list. We need this below for (possibly) // closing the child agents, so save it here (we need a copy as it is Clear()-ed). //List<ulong> childRegions = avatar.KnownRegionHandles; // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport // failure at this point (unlike a border crossing failure). So perhaps this can never fail // once we reach here... //avatar.Scene.RemoveCapsHandler(avatar.UUID); string capsPath = String.Empty; AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); agentCircuit.startpos = position; agentCircuit.child = true; agentCircuit.Appearance = sp.Appearance; if (currentAgentCircuit != null) { agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; agentCircuit.IPAddress = currentAgentCircuit.IPAddress; agentCircuit.Viewer = currentAgentCircuit.Viewer; agentCircuit.Channel = currentAgentCircuit.Channel; agentCircuit.Mac = currentAgentCircuit.Mac; agentCircuit.Id0 = currentAgentCircuit.Id0; } if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) { // brand new agent, let's create a new caps seed agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } // Let's create an agent there if one doesn't exist yet. bool logout = false; if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) { sp.ControllingClient.SendTeleportFailed(String.Format("Destination refused: {0}", reason)); return; } // OK, it got this agent. Let's close some child agents sp.CloseChildAgents(newRegionX, newRegionY); IClientIPEndpoint ipepClient; if (NeedsNewAgent(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY)) { //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); #region IP Translation for NAT // Uses ipepClient above if (sp.ClientView.TryGet(out ipepClient)) { endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); } #endregion capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); if (eq != null) { eq.EnableSimulator(destinationHandle, endPoint, sp.UUID); // ES makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(200); eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); } else { sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); } } else { agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); capsPath = finalDestination.ServerURI + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } SetInTransit(sp.UUID); // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); sp.CopyTo(agent); agent.Position = position; SetCallbackURL(agent, sp.Scene.RegionInfo); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); if (!UpdateAgent(reg, finalDestination, agent)) { // Region doesn't take it m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1}. Returning avatar to source region.", sp.Name, finalDestination.RegionName); Fail(sp, finalDestination); return; } sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, sp.UUID); if (eq != null) { eq.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); } else { sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, teleportFlags, capsPath); } // Let's set this to true tentatively. This does not trigger OnChildAgent sp.IsChildAgent = true; // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we close things here. if (!WaitForCallback(sp.UUID)) { m_log.WarnFormat( "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} failed due to no callback from destination region. Returning avatar to source region.", sp.Name, finalDestination.RegionName); Fail(sp, finalDestination); return; } // For backwards compatibility if (version == "Unknown" || version == string.Empty) { // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it m_log.DebugFormat("[ENTITY TRANSFER MODULE]: Old simulator, sending attachments one by one..."); CrossAttachmentsIntoNewRegion(finalDestination, sp, true); } // May need to logout or other cleanup AgentHasMovedAway(sp, logout); // Well, this is it. The agent is over there. KillEntity(sp.Scene, sp.LocalId); // Now let's make it officially a child agent sp.MakeChildAgent(); // sp.Scene.CleanDroppedAttachments(); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(sp.DrawDistance, oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { Thread.Sleep(5000); sp.Close(); sp.Scene.IncomingCloseAgent(sp.UUID); } else { // now we have a child agent in this region. sp.IsInTransit = false; // not sure :( sp.Reset(); } // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! if (sp.Scene.NeedSceneCacheClear(sp.UUID)) { m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", sp.UUID); } } else { sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); } }
public async Task <Tuple <EstablishPresenceResult, string> > EstablishChildConnectionToRegionAsync(ScenePresence avatar, AgentCircuitData a, SimpleRegionInfo reg) { string capsPath = CapsUtil.GetFullCapsSeedURL(reg.InsecurePublicHTTPServerURI, a.CapsPath); Tuple <bool, string> createResult = await m_interregionCommsOut.SendCreateRemoteChildAgentAsync(reg, a); if (createResult.Item1) { IPEndPoint endPoint = reg.ExternalEndPoint; IEventQueue eq = avatar.Scene.RequestModuleInterface <IEventQueue>(); if (!eq.EnableSimulator(reg.RegionHandle, endPoint, avatar.UUID)) { m_log.ErrorFormat("[INTERGRID]: Could not enqueue eq.EnableSimulator for {0}", avatar.Name); return(Tuple.Create(EstablishPresenceResult.ClientSignallingFailed, "Could not enqueue EnableSimulator")); } if (!eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath)) { m_log.ErrorFormat("[INTERGRID]: Could not enqueue eq.EstablishAgentCommunication for {0}", avatar.Name); return(Tuple.Create(EstablishPresenceResult.ClientSignallingFailed, "Could not enqueue EstablishAgentCommunication")); } return(Tuple.Create(EstablishPresenceResult.Success, String.Empty)); } else { return(Tuple.Create(EstablishPresenceResult.ErrorInformingRegion, createResult.Item2)); } }
public virtual void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq) { sp.ControllingClient.SendTeleportProgress(teleportFlags, "sending_dest"); if (reg == null || finalDestination == null) { sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); return; } m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Request Teleport to {0}:{1}:{2}/{3}", reg.ExternalHostName, reg.HttpPort, finalDestination.RegionName, position); uint newRegionX = (uint)(reg.RegionHandle >> 40); uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); ulong destinationHandle = finalDestination.RegionHandle; // Let's do DNS resolution only once in this process, please! // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, // it's actually doing a lot of work. IPEndPoint endPoint = finalDestination.ExternalEndPoint; if (endPoint.Address != null) { sp.ControllingClient.SendTeleportProgress(teleportFlags, "arriving"); if (m_cancelingAgents.Contains(sp.UUID)) { Cancel(sp); return; } // Fixing a bug where teleporting while sitting results in the avatar ending up removed from // both regions if (sp.ParentID != UUID.Zero) sp.StandUp(); if (!sp.ValidateAttachments()) { sp.ControllingClient.SendTeleportProgress(teleportFlags, "missing_attach_tport"); sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); return; } string capsPath = String.Empty; AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); agentCircuit.startpos = position; agentCircuit.child = true; agentCircuit.Appearance = sp.Appearance; if (currentAgentCircuit != null) { agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; agentCircuit.IPAddress = currentAgentCircuit.IPAddress; agentCircuit.Viewer = currentAgentCircuit.Viewer; agentCircuit.Channel = currentAgentCircuit.Channel; agentCircuit.Mac = currentAgentCircuit.Mac; agentCircuit.Id0 = currentAgentCircuit.Id0; } if (NeedsNewAgent(oldRegionX, newRegionX, oldRegionY, newRegionY)) { // brand new agent, let's create a new caps seed agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } string reason = String.Empty; // Let's create an agent there if one doesn't exist yet. bool logout = false; if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason, out logout)) { sp.ControllingClient.SendTeleportFailed(String.Format("Destination refused: {0}", reason)); return; } // OK, it got this agent. Let's close some child agents sp.CloseChildAgents(newRegionX, newRegionY); if (NeedsNewAgent(oldRegionX, newRegionX, oldRegionY, newRegionY)) { //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Creating agent..."); #region IP Translation for NAT IClientIPEndpoint ipepClient; if (sp.ClientView.TryGet(out ipepClient)) { capsPath = "http://" + NetworkUtil.GetHostFor(ipepClient.EndPoint, finalDestination.ExternalHostName) + ":" + finalDestination.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } else { capsPath = "http://" + finalDestination.ExternalHostName + ":" + finalDestination.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } #endregion if (eq != null) { #region IP Translation for NAT // Uses ipepClient above if (sp.ClientView.TryGet(out ipepClient)) { endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); } #endregion eq.EnableSimulator(destinationHandle, endPoint, sp.UUID); // ES makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(200); eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); } else { sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); } } else { agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); capsPath = "http://" + finalDestination.ExternalHostName + ":" + finalDestination.HttpPort + "/CAPS/" + agentCircuit.CapsPath + "0000/"; } if (m_cancelingAgents.Contains(sp.UUID)) { Cancel(sp); return; } SetInTransit(sp.UUID); // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); sp.CopyTo(agent); agent.Position = position; SetCallbackURL(agent, sp.Scene.RegionInfo); //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); if (!UpdateAgent(reg, finalDestination, agent)) { // Region doesn't take it Fail(sp, finalDestination); return; } m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, sp.UUID); if (eq != null) { eq.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID, teleportFlags); } else { sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, teleportFlags, capsPath); } // Let's set this to true tentatively. This does not trigger OnChildAgent sp.IsChildAgent = true; // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we send the attachments and close things here. //OpenSim sucks at callbacks, disable it for now if (!WaitForCallback(sp.UUID)) { /*//Make sure the client hasn't TPed back in this time. ScenePresence SP = m_aScene.GetScenePresence(sp.UUID); if (SP != null && SP.IsChildAgent) { //Disabling until this actually helps and doesn't kill clients //Fail(sp, finalDestination); return; } else if (SP == null) { //Err.. this happens somehow. return; }*/ } /*//Make sure the client hasn't TPed back in this time. ScenePresence newSP = m_aScene.GetScenePresence(sp.UUID); if (newSP != null && !newSP.IsChildAgent) { //They are root again, don't cross them! return; } else if (newSP == null) { //Err.. this happens somehow. return; }*/ // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it CrossAttachmentsIntoNewRegion(finalDestination, sp, true); // Well, this is it. The agent is over there. KillEntity(sp.Scene, sp.LocalId); // May need to logout or other cleanup AgentHasMovedAway(sp.ControllingClient.SessionId, logout); // Now let's make it officially a child agent sp.MakeChildAgent(); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { Thread.Sleep(5000); sp.Close(); sp.Scene.IncomingCloseAgent(sp.UUID); } else // now we have a child agent in this region. sp.Reset(); //If they canceled too late, remove them so the next tp does not fail. if (m_cancelingAgents.Contains(sp.UUID)) m_cancelingAgents.Remove(sp.UUID); } else { sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); } }
protected void DoTeleport(ScenePresence sp, GridRegion reg, GridRegion finalDestination, Vector3 position, Vector3 lookAt, uint teleportFlags, IEventQueue eq) { if (reg == null || finalDestination == null) { sp.ControllingClient.SendTeleportFailed("Unable to locate destination"); return; } m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Request Teleport to {0}:{1}:{2}/{3}", reg.ExternalHostName, reg.HttpPort, finalDestination.RegionName, position); uint newRegionX = (uint)(reg.RegionHandle >> 40); uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); ulong destinationHandle = finalDestination.RegionHandle; if (eq == null) sp.ControllingClient.SendTeleportLocationStart(); // Let's do DNS resolution only once in this process, please! // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, // it's actually doing a lot of work. IPEndPoint endPoint = finalDestination.ExternalEndPoint; if (endPoint.Address != null) { // Fixing a bug where teleporting while sitting results in the avatar ending up removed from // both regions if (sp.ParentID != (uint)0) sp.StandUp(); if (!sp.ValidateAttachments()) { sp.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); return; } // the avatar.Close below will clear the child region list. We need this below for (possibly) // closing the child agents, so save it here (we need a copy as it is Clear()-ed). //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList()); // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport // failure at this point (unlike a border crossing failure). So perhaps this can never fail // once we reach here... //avatar.Scene.RemoveCapsHandler(avatar.UUID); string capsPath = String.Empty; AgentCircuitData currentAgentCircuit = sp.Scene.AuthenticateHandler.GetAgentCircuitData(sp.ControllingClient.CircuitCode); AgentCircuitData agentCircuit = sp.ControllingClient.RequestClientInfo(); agentCircuit.startpos = position; agentCircuit.child = true; agentCircuit.Appearance = sp.Appearance; if (currentAgentCircuit != null) { agentCircuit.ServiceURLs = currentAgentCircuit.ServiceURLs; agentCircuit.Viewer = currentAgentCircuit.Viewer; } if (NeedsNewAgent(oldRegionX, newRegionX, oldRegionY, newRegionY)) { // brand new agent, let's create a new caps seed agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } string reason = String.Empty; // Let's create an agent there if one doesn't exist yet. if (!CreateAgent(sp, reg, finalDestination, agentCircuit, teleportFlags, out reason)) { sp.ControllingClient.SendTeleportFailed(String.Format("Destination refused: {0}", reason)); return; } // OK, it got this agent. Let's close some child agents sp.CloseChildAgents(newRegionX, newRegionY); if (NeedsNewAgent(oldRegionX, newRegionX, oldRegionY, newRegionY)) { #region IP Translation for NAT IClientIPEndpoint ipepClient; if (sp.ClientView.TryGet(out ipepClient)) { capsPath = "http://" + NetworkUtil.GetHostFor(ipepClient.EndPoint, finalDestination.ExternalHostName) + ":" + finalDestination.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } else { capsPath = "http://" + finalDestination.ExternalHostName + ":" + finalDestination.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); } #endregion if (eq != null) { #region IP Translation for NAT // Uses ipepClient above if (sp.ClientView.TryGet(out ipepClient)) { endPoint.Address = NetworkUtil.GetIPFor(ipepClient.EndPoint, endPoint.Address); } #endregion eq.EnableSimulator(destinationHandle, endPoint, sp.UUID); // ES makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(200); eq.EstablishAgentCommunication(sp.UUID, endPoint, capsPath); } else { sp.ControllingClient.InformClientOfNeighbour(destinationHandle, endPoint); } } else { agentCircuit.CapsPath = sp.Scene.CapsModule.GetChildSeed(sp.UUID, reg.RegionHandle); capsPath = "http://" + finalDestination.ExternalHostName + ":" + finalDestination.HttpPort + "/CAPS/" + agentCircuit.CapsPath + "0000/"; } // Expect avatar crossing is a heavy-duty function at the destination. // That is where MakeRoot is called, which fetches appearance and inventory. // Plus triggers OnMakeRoot, which spawns a series of asynchronous updates. //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, // position, false); //{ // avatar.ControllingClient.SendTeleportFailed("Problem with destination."); // // We should close that agent we just created over at destination... // List<ulong> lst = new List<ulong>(); // lst.Add(reg.RegionHandle); // SendCloseChildAgentAsync(avatar.UUID, lst); // return; //} SetInTransit(sp.UUID); // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); sp.CopyTo(agent); agent.Position = position; SetCallbackURL(agent, sp.Scene.RegionInfo); UpdateAgent(reg, finalDestination, agent); m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} to client {1}", capsPath, sp.UUID); if (eq != null) { eq.TeleportFinishEvent(destinationHandle, 13, endPoint, 0, teleportFlags, capsPath, sp.UUID); } else { sp.ControllingClient.SendRegionTeleport(destinationHandle, 13, endPoint, 4, teleportFlags, capsPath); } // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we send the attachments and close things here. if (!WaitForCallback(sp.UUID)) { // Client never contacted destination. Let's restore everything back sp.ControllingClient.SendTeleportFailed("Problems connecting to destination."); ResetFromTransit(sp.UUID); // Yikes! We should just have a ref to scene here. //sp.Scene.InformClientOfNeighbours(sp); EnableChildAgents(sp); // Finally, kill the agent we just created at the destination. m_aScene.SimulationService.CloseAgent(finalDestination, sp.UUID); return; } // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it CrossAttachmentsIntoNewRegion(finalDestination, sp, true); KillEntity(sp.Scene, sp.LocalId); sp.MakeChildAgent(); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone if (NeedsClosing(oldRegionX, newRegionX, oldRegionY, newRegionY, reg)) { Thread.Sleep(5000); sp.Close(); sp.Scene.IncomingCloseAgent(sp.UUID); } else // now we have a child agent in this region. sp.Reset(); // REFACTORING PROBLEM. Well, not a problem, but this method is HORRIBLE! if (sp.Scene.NeedSceneCacheClear(sp.UUID)) { m_log.DebugFormat( "[ENTITY TRANSFER MODULE]: User {0} is going to another region, profile cache removed", sp.UUID); } } else { sp.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); } }
/// <summary> /// Try to teleport an agent to a new region. /// </summary> /// <param name="remoteClient"></param> /// <param name="RegionHandle"></param> /// <param name="position"></param> /// <param name="lookAt"></param> /// <param name="flags"></param> public override void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID)) { return; } bool destRegionUp = true; IEventQueue eq = avatar.Scene.RequestModuleInterface <IEventQueue>(); // Reset animations; the viewer does that in teleports. avatar.ResetAnimations(); if (regionHandle == m_regionInfo.RegionHandle) { // Teleport within the same region if (position.X < 0 || position.X > Constants.RegionSize || position.Y < 0 || position.Y > Constants.RegionSize || position.Z < 0) { Vector3 emergencyPos = new Vector3(128, 128, 128); m_log.WarnFormat( "[HGSceneCommService]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", position, avatar.Name, avatar.UUID, emergencyPos); position = emergencyPos; } // TODO: Get proper AVG Height float localAVHeight = 1.56f; float posZLimit = (float)avatar.Scene.Heightmap[(int)position.X, (int)position.Y]; float newPosZ = posZLimit + localAVHeight; if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) { position.Z = newPosZ; } // Only send this if the event queue is null if (eq == null) { avatar.ControllingClient.SendTeleportLocationStart(); } avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); avatar.Teleport(position); } else { RegionInfo reg = RequestNeighbouringRegionInfo(regionHandle); if (reg != null) { uint newRegionX = (uint)(reg.RegionHandle >> 40); uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40); uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8); /// /// Hypergrid mod start /// /// bool isHyperLink = m_hg.IsHyperlinkRegion(reg.RegionHandle); bool isHomeUser = true; ulong realHandle = regionHandle; CachedUserInfo uinfo = m_commsProvider.UserProfileCacheService.GetUserDetails(avatar.UUID); if (uinfo != null) { isHomeUser = HGNetworkServersInfo.Singleton.IsLocalUser(uinfo.UserProfile); realHandle = m_hg.FindRegionHandle(regionHandle); m_log.Debug("XXX ---- home user? " + isHomeUser + " --- hyperlink? " + isHyperLink + " --- real handle: " + realHandle.ToString()); } /// /// Hypergrid mod stop /// /// if (eq == null) { avatar.ControllingClient.SendTeleportLocationStart(); } // Let's do DNS resolution only once in this process, please! // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, // it's actually doing a lot of work. IPEndPoint endPoint = reg.ExternalEndPoint; if (endPoint.Address == null) { // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses. destRegionUp = false; } if (destRegionUp) { // Fixing a bug where teleporting while sitting results in the avatar ending up removed from // both regions if (avatar.ParentID != (uint)0) { avatar.StandUp(); } if (!avatar.ValidateAttachments()) { avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); return; } // the avatar.Close below will clear the child region list. We need this below for (possibly) // closing the child agents, so save it here (we need a copy as it is Clear()-ed). //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList()); // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport // failure at this point (unlike a border crossing failure). So perhaps this can never fail // once we reach here... //avatar.Scene.RemoveCapsHandler(avatar.UUID); string capsPath = String.Empty; AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo(); agentCircuit.BaseFolder = UUID.Zero; agentCircuit.InventoryFolder = UUID.Zero; agentCircuit.startpos = position; agentCircuit.child = true; if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) { // brand new agent, let's create a new caps seed agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } string reason = String.Empty; //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit)) if (!m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, agentCircuit, out reason)) { avatar.ControllingClient.SendTeleportFailed(String.Format("Destination is not accepting teleports: {0}", reason)); return; } // Let's close some agents if (isHyperLink) // close them all except this one { List <ulong> regions = new List <ulong>(avatar.KnownChildRegionHandles); regions.Remove(avatar.Scene.RegionInfo.RegionHandle); SendCloseChildAgentConnections(avatar.UUID, regions); } else // close just a few { avatar.CloseChildAgents(newRegionX, newRegionY); } if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink) { capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); if (eq != null) { eq.EnableSimulator(realHandle, endPoint, avatar.UUID); // ES makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(2000); eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath); } else { avatar.ControllingClient.InformClientOfNeighbour(realHandle, endPoint); // TODO: make Event Queue disablable! } } else { // child agent already there agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle); capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + "/CAPS/" + agentCircuit.CapsPath + "0000/"; } //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, // position, false); //if (!m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, // position, false)) //{ // avatar.ControllingClient.SendTeleportFailed("Problem with destination."); // // We should close that agent we just created over at destination... // List<ulong> lst = new List<ulong>(); // lst.Add(realHandle); // SendCloseChildAgentAsync(avatar.UUID, lst); // return; //} SetInTransit(avatar.UUID); // Let's send a full update of the agent. This is a synchronous call. AgentData agent = new AgentData(); avatar.CopyTo(agent); agent.Position = position; agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort + "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionHandle.ToString() + "/release/"; m_interregionCommsOut.SendChildAgentUpdate(reg.RegionHandle, agent); m_log.DebugFormat( "[CAPS]: Sending new CAPS seed url {0} to client {1}", agentCircuit.CapsPath, avatar.UUID); /// /// Hypergrid mod: realHandle instead of reg.RegionHandle /// /// if (eq != null) { eq.TeleportFinishEvent(realHandle, 13, endPoint, 4, teleportFlags, capsPath, avatar.UUID); } else { avatar.ControllingClient.SendRegionTeleport(realHandle, 13, endPoint, 4, teleportFlags, capsPath); } /// /// Hypergrid mod stop /// // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation // that the client contacted the destination before we send the attachments and close things here. if (!WaitForCallback(avatar.UUID)) { // Client never contacted destination. Let's restore everything back avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination."); ResetFromTransit(avatar.UUID); // Yikes! We should just have a ref to scene here. avatar.Scene.InformClientOfNeighbours(avatar); // Finally, kill the agent we just created at the destination. m_interregionCommsOut.SendCloseAgent(reg.RegionHandle, avatar.UUID); return; } // Can't go back from here if (KiPrimitive != null) { KiPrimitive(avatar.LocalId); } avatar.MakeChildAgent(); // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone /// /// Hypergrid mod: extra check for isHyperLink /// if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink) { Thread.Sleep(5000); avatar.Close(); CloseConnection(avatar.UUID); } // if (teleport success) // seems to be always success here // the user may change their profile information in other region, // so the userinfo in UserProfileCache is not reliable any more, delete it if (avatar.Scene.NeedSceneCacheClear(avatar.UUID) || isHyperLink) { m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID); m_log.DebugFormat( "[HGSceneCommService]: User {0} is going to another region, profile cache removed", avatar.UUID); } } else { avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); } } else { // TP to a place that doesn't exist (anymore) // Inform the viewer about that avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' uint regX, regY; Utils.LongToUInts(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); block.X = (ushort)(regX / Constants.RegionSize); block.Y = (ushort)(regY / Constants.RegionSize); block.Access = 254; // == not there List <MapBlockData> blocks = new List <MapBlockData>(); blocks.Add(block); avatar.ControllingClient.SendMapBlock(blocks, 0); } } }