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 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");
            }
        }
Example #4
0
        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);
        }
        /// <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);
                }
            }
        }