try to make SOG crossings full async. Simplify some borders checking....

UbitUmarov [2014-10-24 17:10:28]
 try to make SOG crossings full async. Simplify some borders checking....
Filename
OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
OpenSim/Region/Framework/Scenes/ScenePresence.cs
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 6385aed..6f42990 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -3865,7 +3865,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
                 {
                     SceneObjectPart part = (SceneObjectPart)update.Entity;

-                    if (part.ParentGroup.IsDeleted)
+                    if (part.ParentGroup.IsDeleted || part.ParentGroup.inTransit)
                         continue;

                     if (part.ParentGroup.IsAttachment)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index c898946..b855233 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -1385,13 +1385,61 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer


         #region Agent Crossings
-        public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos)
+
+        public bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, out string version, out string reason)
+        {
+            reason = String.Empty;
+            version = String.Empty;
+
+            UUID agentID = agent.UUID;
+            ulong destinyHandle = destiny.RegionHandle;
+
+            ExpiringCache<ulong, DateTime> r;
+            DateTime banUntil;
+            if (m_bannedRegions.TryGetValue(agentID, out r))
+            {
+                if (r.TryGetValue(destinyHandle, out banUntil))
+                {
+                    if (DateTime.Now < banUntil)
+                    {
+                        reason = "Cannot connect to region";
+                        return false;
+                    }
+                    r.Remove(destinyHandle);
+                }
+            }
+            else
+            {
+                r = null;
+            }
+
+            Scene ascene = agent.Scene;
+
+            if (!ascene.SimulationService.QueryAccess(destiny, agentID, position, out version, out reason))
+            {
+                if (r == null)
+                {
+                    r = new ExpiringCache<ulong, DateTime>();
+                    r.Add(destinyHandle, DateTime.Now + TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
+
+                    m_bannedRegions.Add(agentID, r, TimeSpan.FromSeconds(30));
+                }
+                else
+                {
+                    r.Add(destinyHandle, DateTime.Now + TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30));
+                }
+                return false;
+            }
+            return true;
+        }
+
+        public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos)
         {
             string r = String.Empty;
-            return GetDestination(scene, agentID, pos, out xDest, out yDest, out version, out newpos, out r);
+            return GetDestination(scene, agentID, pos, out version, out newpos, out r);
         }

-        public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos, out string reason)
+        public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos, out string reason)
         {
             version = String.Empty;
             reason = String.Empty;
@@ -1400,9 +1448,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
 //            m_log.DebugFormat(
 //                "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);

-            uint neighbourx = scene.RegionInfo.RegionLocX;
-            uint neighboury = scene.RegionInfo.RegionLocY;
+            RegionInfo regInfo = scene.RegionInfo;
+
+            uint neighbourx = regInfo.RegionLocX;
+            uint neighboury = regInfo.RegionLocY;
             const float boundaryDistance = 0.7f;
+
+/*
             Vector3 northCross = new Vector3(0, boundaryDistance, 0);
             Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0);
             Vector3 eastCross = new Vector3(boundaryDistance, 0, 0);
@@ -1463,11 +1515,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer

             newpos.X = Util.Clamp(newpos.X, enterDistance, maxX);
             newpos.Y = Util.Clamp(newpos.Y, enterDistance, maxY);
+*/
+            float regionSizeX = regInfo.RegionSizeX;
+            float regionSizeY = regInfo.RegionSizeY;
+
+            if (pos.X < boundaryDistance)
+                neighbourx--;
+            else if (pos.X > regionSizeX - boundaryDistance)
+                neighbourx += (uint)(regionSizeX / Constants.RegionSize);

-            xDest = neighbourx;
-            yDest = neighboury;
+            if (pos.Y < boundaryDistance)
+                neighboury--;
+            else if (pos.Y > regionSizeY - boundaryDistance)
+                neighboury += (uint)(regionSizeY / Constants.RegionSize);

-            int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize);
+            int x = (int)(neighbourx * Constants.RegionSize);
+            int y = (int)(neighboury * Constants.RegionSize);

             ulong neighbourHandle = Utils.UIntsToLong((uint)x, (uint)y);

@@ -1489,6 +1552,28 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
             }

             GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
+            if (neighbourRegion == null)
+            {
+                reason = "";
+                return null;
+            }
+
+            float newRegionSizeX = neighbourRegion.RegionSizeX;
+            float newRegionSizeY = neighbourRegion.RegionSizeY;
+
+            if (pos.X < boundaryDistance)
+                newpos.X += newRegionSizeX;
+            else if (pos.X > regionSizeX - boundaryDistance)
+                newpos.X -= regionSizeX;
+
+            if (pos.Y < boundaryDistance)
+                newpos.Y += newRegionSizeY;
+            else if (pos.Y > regionSizeY - boundaryDistance)
+                newpos.Y -= regionSizeY;
+
+            const float enterDistance = 0.5f;
+            newpos.X = Util.Clamp(newpos.X, enterDistance, newRegionSizeX - enterDistance);
+            newpos.Y = Util.Clamp(newpos.Y, enterDistance, newRegionSizeY - enterDistance);

             if (!scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason))
             {
@@ -1543,13 +1628,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer

             Vector3 pos = agent.AbsolutePosition + agent.Velocity;

-            GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, out x, out y, out version, out newpos, out reason);
+            GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, out version, out newpos, out reason);
             if (neighbourRegion == null)
             {
-                if (reason == String.Empty)
+                if (reason != String.Empty)
                     agent.ControllingClient.SendAlertMessage("Cannot cross to region");
-                else
-                    agent.ControllingClient.SendAlertMessage("Cannot cross to region: " + reason);
                 return agent;
             }

@@ -2346,6 +2429,62 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer

         #region Object Transfers

+        public GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition,out Vector3 newpos)
+        {
+            newpos = targetPosition;
+
+            Scene scene = grp.Scene;
+            if (scene == null)
+                return null;
+
+            RegionInfo srcRegionInfo = scene.RegionInfo;
+            int neighbourx = (int)srcRegionInfo.RegionLocX;
+            int neighboury = (int)srcRegionInfo.RegionLocY;
+            float regionSizeX = srcRegionInfo.RegionSizeX;
+            float regionSizeY = srcRegionInfo.RegionSizeY;
+
+            float edgeJitter = 0.2f;
+
+            if (targetPosition.X < edgeJitter)
+                neighbourx--;
+            else if (targetPosition.X > regionSizeX - edgeJitter)
+                neighbourx += (int)(regionSizeX / Constants.RegionSize);
+
+            if (targetPosition.Y < edgeJitter)
+                neighboury--;
+            else if (targetPosition.Y > regionSizeY - edgeJitter)
+                neighboury += (int)(regionSizeY / Constants.RegionSize);
+
+            int x = neighbourx * (int)Constants.RegionSize;
+            int y = neighboury * (int)Constants.RegionSize;
+
+            GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
+            if (neighbourRegion == null)
+            {
+                return null;
+            }
+
+            float newRegionSizeX = neighbourRegion.RegionSizeX;
+            float newRegionSizeY = neighbourRegion.RegionSizeY;
+
+            if (targetPosition.X < edgeJitter)
+                newpos.X += newRegionSizeX;
+            else if (targetPosition.X > regionSizeX - edgeJitter)
+                newpos.X -= regionSizeX;
+
+            if (targetPosition.Y < edgeJitter)
+                newpos.Y += newRegionSizeY;
+            else if (targetPosition.Y > regionSizeY - edgeJitter)
+                newpos.Y -= regionSizeY;
+
+            const float enterDistance = 0.2f;
+            newpos.X = Util.Clamp(newpos.X, enterDistance, newRegionSizeX - enterDistance);
+            newpos.Y = Util.Clamp(newpos.Y, enterDistance, newRegionSizeY - enterDistance);
+
+            return neighbourRegion;
+        }
+
+
         /// <summary>
         /// Move the given scene object into a new region depending on which region its absolute position has moved
         /// into.
@@ -2365,23 +2504,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
             if (scene == null)
                 return;

-// http://wiki.secondlife.com/wiki/STATUS_DIE_AT_EDGE
-// DieAtEdge does NOT mean that objects can't cross regions.
-// It just means they die when they go off world, unless
-// RETURN_AT_EDGE is set.
-//            if (grp.RootPart.DIE_AT_EDGE)
-//            {
-//                // We remove the object here
-//                try
-//                {
-//                    scene.DeleteSceneObject(grp, false);
-//                }
-//                catch (Exception)
-//                {
-//                    m_log.Warn("[DATABASE]: exception when trying to remove the prim that crossed the border.");
-//                }
-//                return;
-//            }

             int thisx = (int)scene.RegionInfo.RegionLocX;
             int thisy = (int)scene.RegionInfo.RegionLocY;
@@ -2594,7 +2716,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
         /// true if the crossing itself was successful, false on failure
         /// FIMXE: we still return true if the crossing object was not successfully deleted from the originating region
         /// </returns>
-        protected bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent)
+        public bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent)
         {
             //m_log.Debug("  >>> CrossPrimGroupIntoNewRegion <<<");

diff --git a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
index 0c34c90..84cdc15 100644
--- a/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IEntityTransferModule.cs
@@ -93,9 +93,11 @@ namespace OpenSim.Region.Framework.Interfaces

         void EnableChildAgent(ScenePresence agent, GridRegion region);

-        GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos);
-
+        GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos);
+        GridRegion GetObjectDestination(SceneObjectGroup grp, Vector3 targetPosition, out Vector3 newpos);
+        bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, out string version, out string reason);
         void Cross(SceneObjectGroup sog, Vector3 position, bool silent);
+        bool CrossPrimGroupIntoNewRegion(GridRegion destination, Vector3 newPosition, SceneObjectGroup grp, bool silent);

         ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, string version);

diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 0eed64e..a7e7294 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -516,6 +516,10 @@ namespace OpenSim.Region.Framework.Scenes
             public uint ParentID;
         }

+
+        public bool inTransit = false;
+        public delegate SceneObjectGroup SOGCrossDelegate(SceneObjectGroup sog,Vector3 pos);
+
         /// <summary>
         /// The absolute position of this scene object in the scene
         /// </summary>
@@ -525,8 +529,8 @@ namespace OpenSim.Region.Framework.Scenes
             set
             {
                 Vector3 val = value;
-
-                if (Scene != null)
+
+                if (Scene != null && !inTransit)
                 {
                     if (
                         // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E)
@@ -543,130 +547,10 @@ namespace OpenSim.Region.Framework.Scenes
                             || Scene.TestBorderCross(val, Cardinals.S))
                         && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
                     {
-                        IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
-                        uint x = 0;
-                        uint y = 0;
-                        string version = String.Empty;
-                        Vector3 newpos = Vector3.Zero;
-                        OpenSim.Services.Interfaces.GridRegion destination = null;
-
-                        if (m_rootPart.DIE_AT_EDGE || m_rootPart.RETURN_AT_EDGE)
-                        {
-                            // this should delete the grp in this case
-                            m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
-                            // actually assume this sog was removed from simulation
-                            return;
-                        }
-
-                        if (m_rootPart.KeyframeMotion != null)
-                            m_rootPart.KeyframeMotion.StartCrossingCheck();
-
-                        bool canCross = true;
-
-                        foreach (ScenePresence av in m_linkedAvatars)
-                        {
-                            // We need to cross these agents. First, let's find
-                            // out if any of them can't cross for some reason.
-                            // We have to deny the crossing entirely if any
-                            // of them are banned. Alternatively, we could
-                            // unsit banned agents....
-
-
-                            // We set the avatar position as being the object
-                            // position to get the region to send to
-                            if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
-                            {
-                                canCross = false;
-                                break;
-                            }
-
-                            m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
-                        }
-
-                        if (canCross)
-                        {
-                            // We unparent the SP quietly so that it won't
-                            // be made to stand up
-
-                            List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
-
-                            foreach (ScenePresence av in m_linkedAvatars)
-                            {
-                                avtocrossInfo avinfo = new avtocrossInfo();
-                                SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
-                                if (parentPart != null)
-                                    av.ParentUUID = parentPart.UUID;
-
-                                avinfo.av = av;
-                                avinfo.ParentID = av.ParentID;
-                                avsToCross.Add(avinfo);
-
-                                av.PrevSitOffset = av.OffsetPosition;
-                                av.ParentID = 0;
-                            }
-
-                            //                            m_linkedAvatars.Clear();
-                            m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
-
-                            // Normalize
-                            if (val.X >= Constants.RegionSize)
-                                val.X -= Constants.RegionSize;
-                            if (val.Y >= Constants.RegionSize)
-                                val.Y -= Constants.RegionSize;
-                            if (val.X < 0)
-                                val.X += Constants.RegionSize;
-                            if (val.Y < 0)
-                                val.Y += Constants.RegionSize;
-
-                            // If it's deleted, crossing was successful
-                            if (IsDeleted)
-                            {
-                                //                                foreach (ScenePresence av in m_linkedAvatars)
-                                foreach (avtocrossInfo avinfo in avsToCross)
-                                {
-                                    ScenePresence av = avinfo.av;
-                                    if (!av.IsInTransit) // just in case...
-                                    {
-                                        m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
-
-                                        av.IsInTransit = true;
-
-                                        CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
-                                        d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
-                                    }
-                                    else
-                                        m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
-                                }
-                                avsToCross.Clear();
-                                return;
-                            }
-                            else // cross failed, put avas back ??
-                            {
-                                foreach (avtocrossInfo avinfo in avsToCross)
-                                {
-                                    ScenePresence av = avinfo.av;
-                                    av.ParentUUID = UUID.Zero;
-                                    av.ParentID = avinfo.ParentID;
-                                    //                                    m_linkedAvatars.Add(av);
-                                }
-                            }
-                            avsToCross.Clear();
-                        }
-                        else
-                        {
-                            if (m_rootPart.KeyframeMotion != null)
-                                m_rootPart.KeyframeMotion.CrossingFailure();
-
-                            if (RootPart.PhysActor != null)
-                            {
-                                RootPart.PhysActor.CrossingFailure();
-                            }
-                        }
-                        Vector3 oldp = AbsolutePosition;
-                        val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
-                        val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
-                        // dont crash land StarShips
-                        // val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
+                        inTransit = true;
+                        SOGCrossDelegate d = CrossAsync;
+                        d.BeginInvoke(this, val, CrossAsyncCompleted, d);
+                        return;
                     }
                 }

@@ -714,46 +598,197 @@ namespace OpenSim.Region.Framework.Scenes
                         part.TriggerScriptChangedEvent(Changed.POSITION);
                     }
                 }
+
+                Scene.EventManager.TriggerParcelPrimCountTainted();
+            }
+        }

-/*
-    This seems not needed and should not be needed:
-    sp absolute position depends on sit part absolute position fixed above.
-    sp ParentPosition is not used anywhere.
-    Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
-    Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
-
-                if (!m_dupeInProgress)
+        public SceneObjectGroup CrossAsync(SceneObjectGroup sog, Vector3 val)
+        {
+            Scene sogScene = sog.m_scene;
+            IEntityTransferModule entityTransfer = sogScene.RequestModuleInterface<IEntityTransferModule>();
+
+            Vector3 newpos = Vector3.Zero;
+            OpenSim.Services.Interfaces.GridRegion destination = null;
+
+            if (sog.RootPart.DIE_AT_EDGE)
+            {
+                try
+                {
+                    sogScene.DeleteSceneObject(sog, false);
+                }
+                catch (Exception)
+                {
+                    m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border.");
+                }
+                return sog;
+            }
+
+            if (sog.RootPart.RETURN_AT_EDGE)
+            {
+                // We remove the object here
+                try
+                {
+                    List<uint> localIDs = new List<uint>();
+                    localIDs.Add(sog.RootPart.LocalId);
+                    sogScene.AddReturn(sog.OwnerID, sog.Name, sog.AbsolutePosition,
+                        "Returned at region cross");
+                    sogScene.DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, UUID.Zero);
+                }
+                catch (Exception)
+                {
+                    m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border.");
+                }
+                return sog;
+            }
+
+            if (sog.m_rootPart.KeyframeMotion != null)
+                sog.m_rootPart.KeyframeMotion.StartCrossingCheck();
+
+            if (entityTransfer == null)
+                return sog;
+
+            destination = entityTransfer.GetObjectDestination(sog, val, out newpos);
+            if (destination == null)
+                return sog;
+
+            if (sog.m_linkedAvatars.Count == 0)
+            {
+                entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true);
+                return sog;
+            }
+
+            string reason = String.Empty;
+            string version = String.Empty;
+
+            foreach (ScenePresence av in sog.m_linkedAvatars)
+            {
+                // We need to cross these agents. First, let's find
+                // out if any of them can't cross for some reason.
+                // We have to deny the crossing entirely if any
+                // of them are banned. Alternatively, we could
+                // unsit banned agents....
+
+                // We set the avatar position as being the object
+                // position to get the region to send to
+                if(!entityTransfer.checkAgentAccessToRegion(av, destination, newpos, out version, out reason))
+                {
+                    return sog;
+                }
+                m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
+            }
+
+            // We unparent the SP quietly so that it won't
+            // be made to stand up
+
+            List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
+
+            foreach (ScenePresence av in sog.m_linkedAvatars)
+            {
+                avtocrossInfo avinfo = new avtocrossInfo();
+                SceneObjectPart parentPart = sogScene.GetSceneObjectPart(av.ParentID);
+                if (parentPart != null)
+                    av.ParentUUID = parentPart.UUID;
+
+                avinfo.av = av;
+                avinfo.ParentID = av.ParentID;
+                avsToCross.Add(avinfo);
+
+                av.PrevSitOffset = av.OffsetPosition;
+                av.ParentID = 0;
+            }
+
+            if (entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true))
+            {
+                foreach (avtocrossInfo avinfo in avsToCross)
                 {
-                    foreach (ScenePresence av in m_linkedAvatars)
+                    ScenePresence av = avinfo.av;
+                    if (!av.IsInTransit) // just in case...
                     {
-                        SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
-                        if (p != null && m_parts.TryGetValue(p.UUID, out p))
+                        m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
+
+                        av.IsInTransit = true;
+
+//                        CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
+//                        d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
+                        entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, av.Flying, version);
+                        if(av.IsChildAgent)
                         {
-                            Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
-                            av.AbsolutePosition += offset;
-//                            av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
-                            av.SendAvatarDataToAllAgents();
+                            if (av.ParentUUID != UUID.Zero)
+                            {
+                                av.ClearControls();
+                                av.ParentPart = null;
+                            }
                         }
+                        av.ParentUUID = UUID.Zero;
+                        // In any case
+                        av.IsInTransit = false;
+
+                        m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname);
                     }
+                    else
+                        m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar already in transit {0} to {1}", av.Name, val);
+                }
+                avsToCross.Clear();
+                return sog;
+            }
+            else // cross failed, put avas back ??
+            {
+                foreach (avtocrossInfo avinfo in avsToCross)
+                {
+                    ScenePresence av = avinfo.av;
+                    av.ParentUUID = UUID.Zero;
+                    av.ParentID = avinfo.ParentID;
                 }
-*/
-                //if (m_rootPart.PhysActor != null)
-                //{
-                //m_rootPart.PhysActor.Position =
-                //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y,
-                //m_rootPart.GroupPosition.Z);
-                //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
-                //}
-
-                if (Scene != null)
-                    Scene.EventManager.TriggerParcelPrimCountTainted();
             }
+            avsToCross.Clear();
+
+            return sog;
         }

-        public override Vector3 Velocity
+        public void CrossAsyncCompleted(IAsyncResult iar)
         {
-            get { return RootPart.Velocity; }
-            set { RootPart.Velocity = value; }
+            SOGCrossDelegate icon = (SOGCrossDelegate)iar.AsyncState;
+            SceneObjectGroup sog = icon.EndInvoke(iar);
+
+            if (sog.IsDeleted)
+            {
+                sog.inTransit = false; // just in case...
+            }
+            else
+            {
+                SceneObjectPart rootp = sog.m_rootPart;
+                Vector3 oldp = rootp.GroupPosition;
+                oldp.X = Util.Clamp<float>(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f);
+                oldp.Y = Util.Clamp<float>(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f);
+                rootp.GroupPosition = oldp;
+
+                SceneObjectPart[] parts = sog.m_parts.GetArray();
+
+                foreach (SceneObjectPart part in parts)
+                {
+                    if (part != rootp)
+                        part.GroupPosition = oldp;
+                }
+
+                foreach (ScenePresence av in sog.m_linkedAvatars)
+                {
+                    av.sitSOGmoved();
+                }
+
+                sog.Velocity = Vector3.Zero;
+
+                if (sog.m_rootPart.KeyframeMotion != null)
+                    sog.m_rootPart.KeyframeMotion.CrossingFailure();
+
+                if (sog.RootPart.PhysActor != null)
+                {
+                    sog.RootPart.PhysActor.CrossingFailure();
+                }
+
+                sog.inTransit = false;
+                sog.ScheduleGroupForFullUpdate();
+            }
         }

         private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
@@ -784,6 +819,12 @@ namespace OpenSim.Region.Framework.Scenes
             m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
         }

+        public override Vector3 Velocity
+        {
+            get { return RootPart.Velocity; }
+            set { RootPart.Velocity = value; }
+        }
+
         public override uint LocalId
         {
             get { return m_rootPart.LocalId; }
@@ -2620,7 +2661,7 @@ namespace OpenSim.Region.Framework.Scenes
             // an object has been deleted from a scene before update was processed.
             // A more fundamental overhaul of the update mechanism is required to eliminate all
             // the race conditions.
-            if (IsDeleted)
+            if (IsDeleted || inTransit)
                 return;

             // Even temporary objects take part in physics (e.g. temp-on-rez bullets)
@@ -2736,7 +2777,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// </summary>
         public void SendGroupRootTerseUpdate()
         {
-            if (IsDeleted)
+            if (IsDeleted || inTransit)
                 return;

             RootPart.SendTerseUpdateToAllClients();
@@ -2755,7 +2796,7 @@ namespace OpenSim.Region.Framework.Scenes
         /// </summary>
         public void SendGroupTerseUpdate()
         {
-            if (IsDeleted)
+            if (IsDeleted || inTransit)
                 return;

             if (IsAttachment)
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 4cc4d94..56c3b52 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -1123,6 +1123,11 @@ namespace OpenSim.Region.Framework.Scenes
                     if (part == null)
                     {
                         m_log.ErrorFormat("[SCENE PRESENCE]: Can't find prim {0} to sit on", ParentUUID);
+                        ParentID = 0;
+                        ParentPart = null;
+                        PrevSitOffset = Vector3.Zero;
+                        ClearControls();
+                        IsLoggingIn = false;
                     }
                     else
                     {
@@ -1216,13 +1221,6 @@ namespace OpenSim.Region.Framework.Scenes
                 else
                     AddToPhysicalScene(isFlying);

-                // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a
-                // location outside the 'root region' (the south-west 256x256 corner).  This is the earlist we can do it
-                // since it requires a physics actor to be present.  If it is left any later, then physics appears to reset
-                // the value to a negative position which does not trigger the border cross.
-                // This may not be the best location for this.
-                CheckForBorderCrossing();
-
                 if (ForceFly)
                 {
                     Flying = true;
@@ -1231,12 +1229,18 @@ namespace OpenSim.Region.Framework.Scenes
                 {
                     Flying = false;
                 }
-            }
-            // Don't send an animation pack here, since on a region crossing this will sometimes cause a flying
-            // avatar to return to the standing position in mid-air.  On login it looks like this is being sent
-            // elsewhere anyway
-            // Animator.SendAnimPack();

+                // XXX: This is to trigger any secondary teleport needed for a megaregion when the user has teleported to a
+                // location outside the 'root region' (the south-west 256x256 corner).  This is the earlist we can do it
+                // since it requires a physics actor to be present.  If it is left any later, then physics appears to reset
+                // the value to a negative position which does not trigger the border cross.
+                // This may not be the best location for this.
+
+
+                // its not
+//                CheckForBorderCrossing();
+            }
+
             m_log.DebugFormat("[MakeRootAgent] position and physical: {0}ms", Util.EnvironmentTickCountSubtract(ts));
             m_scene.SwapRootAgentCount(false);

@@ -2734,7 +2738,6 @@ namespace OpenSim.Region.Framework.Scenes
                 ParentID = 0;
                 ParentPart = null;

-
                 if (part.SitTargetAvatar == UUID)
                     standRotation = standRotation * part.SitTargetOrientation;
                 else
@@ -2761,12 +2764,6 @@ namespace OpenSim.Region.Framework.Scenes

                 Vector3 standPos = sitPartWorldPosition + adjustmentForSitPose;

-//                m_log.DebugFormat(
-//                    "[SCENE PRESENCE]: Setting stand to pos {0}, (adjustmentForSitPosition {1}, adjustmentForSitPose {2}) rotation {3} for {4} in {5}",
-//                    standPos, adjustmentForSitPosition, adjustmentForSitPose, standRotation, Name, Scene.Name);
-
-                standPos.X = Util.Clamp<float>(standPos.X, 0.5f, (float)Constants.RegionSize - 0.5f);
-                standPos.Y = Util.Clamp<float>(standPos.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
                 m_pos = standPos;
             }

@@ -3308,6 +3305,8 @@ namespace OpenSim.Region.Framework.Scenes

             if (IsChildAgent == false)
             {
+                CheckForBorderCrossing();
+
                 if (IsInTransit)
                     return;

@@ -3329,8 +3328,6 @@ namespace OpenSim.Region.Framework.Scenes
                     m_lastVelocity = Velocity;
                 }

-                CheckForBorderCrossing();
-
                 CheckForSignificantMovement(); // sends update to the modules.
             }
         }
@@ -3847,7 +3844,7 @@ namespace OpenSim.Region.Framework.Scenes
         protected void CheckForBorderCrossing()
         {
             // Check that we we are not a child
-            if (IsChildAgent)
+            if (IsChildAgent || IsInTransit)
                 return;

             // If we don't have a PhysActor, we can't cross anyway
@@ -3857,25 +3854,22 @@ namespace OpenSim.Region.Framework.Scenes
             if (ParentID != 0 || PhysicsActor == null || ParentUUID != UUID.Zero)
                 return;

-            if (IsInTransit)
-                return;
-
             Vector3 pos2 = AbsolutePosition;
             Vector3 vel = Velocity;
-            int neighbor = 0;
-            int[] fix = new int[2];

             float timeStep = 0.1f;
-            pos2.X = pos2.X + (vel.X * timeStep);
-            pos2.Y = pos2.Y + (vel.Y * timeStep);
-            pos2.Z = pos2.Z + (vel.Z * timeStep);
-
+            pos2.X += vel.X * timeStep;
+            pos2.Y += vel.Y * timeStep;
+            pos2.Z += vel.Z * timeStep;

             //                    m_log.DebugFormat(
             //                        "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
             //                        pos2, Name, Scene.Name);
-
+/*
             // Checks if where it's headed exists a region
+            int neighbor = 0;
+            int[] fix = new int[2];
+
             bool needsTransit = false;
             if (m_scene.TestBorderCross(pos2, Cardinals.W))
             {
@@ -3925,59 +3919,55 @@ namespace OpenSim.Region.Framework.Scenes
             }

             // Makes sure avatar does not end up outside region
+
             if (neighbor <= 0)
             {
                 if (needsTransit)
                 {
-                    if (m_requestedSitTargetUUID == UUID.Zero)
-                    {
-                        bool isFlying = Flying;
-                        RemoveFromPhysicalScene();
-
-                        Vector3 pos = AbsolutePosition;
-                        if (AbsolutePosition.X < 0)
-                            pos.X += Velocity.X * 2;
-                        else if (AbsolutePosition.X > Constants.RegionSize)
-                            pos.X -= Velocity.X * 2;
-                        if (AbsolutePosition.Y < 0)
-                            pos.Y += Velocity.Y * 2;
-                        else if (AbsolutePosition.Y > Constants.RegionSize)
-                            pos.Y -= Velocity.Y * 2;
-                        Velocity = Vector3.Zero;
-                        AbsolutePosition = pos;
-
-                        //                                m_log.DebugFormat("[SCENE PRESENCE]: Prevented flyoff for {0} at {1}", Name, AbsolutePosition);
-
-                        AddToPhysicalScene(isFlying);
-                    }
+                    CrossToNewRegionFail();
                 }
             }
             else if (neighbor > 0)
             {
                 if (!CrossToNewRegion())
                 {
-                    if (m_requestedSitTargetUUID == UUID.Zero)
-                    {
-                        bool isFlying = Flying;
-                        RemoveFromPhysicalScene();
-
-                        Vector3 pos = AbsolutePosition;
-                        if (AbsolutePosition.X < 0)
-                            pos.X += Velocity.X * 2;
-                        else if (AbsolutePosition.X > Constants.RegionSize)
-                            pos.X -= Velocity.X * 2;
-                        if (AbsolutePosition.Y < 0)
-                            pos.Y += Velocity.Y * 2;
-                        else if (AbsolutePosition.Y > Constants.RegionSize)
-                            pos.Y -= Velocity.Y * 2;
-                        Velocity = Vector3.Zero;
-                        AbsolutePosition = pos;
-
-                        AddToPhysicalScene(isFlying);
-                    }
+                    CrossToNewRegionFail();
                 }
             }
+ */
+            bool needsTransit = false;
+
+            if (pos2.X < 0)
+                needsTransit = true;
+            else if (pos2.X > m_scene.RegionInfo.RegionSizeX)
+                needsTransit = true;
+            else if (pos2.Y < 0)
+                needsTransit = true;
+            else if (pos2.Y > m_scene.RegionInfo.RegionSizeY)
+                needsTransit = true;
+
+            if (needsTransit)
+            {
+                if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero)
+                {
+                    // we don't have entity transfer module
+                    Vector3 pos = AbsolutePosition;
+                    float px = pos.X;
+                    if (px < 0)
+                        pos.X += Velocity.X * 2;
+                    else if (px > m_scene.RegionInfo.RegionSizeX)
+                        pos.X -= Velocity.X * 2;

+                    float py = pos.Y;
+                    if (py < 0)
+                        pos.Y += Velocity.Y * 2;
+                    else if (py > m_scene.RegionInfo.RegionSizeY)
+                        pos.Y -= Velocity.Y * 2;
+
+                    Velocity = Vector3.Zero;
+                    AbsolutePosition = pos;
+                }
+            }
         }

         public void CrossToNewRegionFail()
@@ -3988,14 +3978,18 @@ namespace OpenSim.Region.Framework.Scenes
                 RemoveFromPhysicalScene();

                 Vector3 pos = AbsolutePosition;
-                if (AbsolutePosition.X < 0)
+                float px = pos.X;
+                if (px < 0)
                     pos.X += Velocity.X * 2;
-                else if (AbsolutePosition.X > Constants.RegionSize)
+                else if (px > m_scene.RegionInfo.RegionSizeX)
                     pos.X -= Velocity.X * 2;
-                if (AbsolutePosition.Y < 0)
+
+                float py = pos.Y;
+                if (py < 0)
                     pos.Y += Velocity.Y * 2;
-                else if (AbsolutePosition.Y > Constants.RegionSize)
+                else if (py > m_scene.RegionInfo.RegionSizeY)
                     pos.Y -= Velocity.Y * 2;
+
                 Velocity = Vector3.Zero;
                 AbsolutePosition = pos;
ViewGit