/// <summary> /// Move the given scene object into a new region depending on which region its absolute position has moved /// into. /// /// This method locates the new region handle and offsets the prim position for the new region /// </summary> /// <param name="attemptedPosition">the attempted out of region position of the scene object</param> /// <param name="grp">the scene object that we're crossing</param> public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) { if (grp == null) return; if (grp.IsDeleted) return; Scene scene = grp.Scene; if (scene == null) return; 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; Vector3 EastCross = new Vector3(0.1f, 0, 0); Vector3 WestCross = new Vector3(-0.1f, 0, 0); Vector3 NorthCross = new Vector3(0, 0.1f, 0); Vector3 SouthCross = new Vector3(0, -0.1f, 0); // use this if no borders were crossed! ulong newRegionHandle = Util.UIntsToLong((uint)((thisx) * Constants.RegionSize), (uint)((thisy) * Constants.RegionSize)); Vector3 pos = attemptedPosition; int changeX = 1; int changeY = 1; if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W)) { if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) { Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); if (crossedBorderx.BorderLine.Z > 0) { pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); } else pos.X = ((pos.X + Constants.RegionSize)); Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) if (crossedBordery.BorderLine.Z > 0) { pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); } else pos.Y = ((pos.Y + Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); // x - 1 // y - 1 } else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) { Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); if (crossedBorderx.BorderLine.Z > 0) { pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); } else pos.X = ((pos.X + Constants.RegionSize)); Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) if (crossedBordery.BorderLine.Z > 0) { pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); } else pos.Y = ((pos.Y + Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); // x - 1 // y + 1 } else { Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); if (crossedBorderx.BorderLine.Z > 0) { pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); } else pos.X = ((pos.X + Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), (uint)(thisy * Constants.RegionSize)); // x - 1 } } else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E)) { if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) { pos.X = ((pos.X - Constants.RegionSize)); Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) if (crossedBordery.BorderLine.Z > 0) { pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); } else pos.Y = ((pos.Y + Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); // x + 1 // y - 1 } else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) { pos.X = ((pos.X - Constants.RegionSize)); pos.Y = ((pos.Y - Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); // x + 1 // y + 1 } else { pos.X = ((pos.X - Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), (uint)(thisy * Constants.RegionSize)); // x + 1 } } else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) { Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) if (crossedBordery.BorderLine.Z > 0) { pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); } else pos.Y = ((pos.Y + Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); // y - 1 } else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) { pos.Y = ((pos.Y - Constants.RegionSize)); newRegionHandle = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); // y + 1 } // Offset the positions for the new region across the border Vector3 oldGroupPosition = grp.RootPart.GroupPosition; // If we fail to cross the border, then reset the position of the scene object on that border. uint x = 0, y = 0; Utils.LongToUInts(newRegionHandle, out x, out y); GridRegion destination = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) { m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}",grp.UUID); // We are going to move the object back to the old position so long as the old position // is in the region oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X,1.0f,(float)Constants.RegionSize-1); oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y,1.0f,(float)Constants.RegionSize-1); oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z,1.0f,4096.0f); grp.RootPart.GroupPosition = oldGroupPosition; // Need to turn off the physics flags, otherwise the object will continue to attempt to // move out of the region creating an infinite loop of failed attempts to cross grp.UpdatePrimFlags(grp.RootPart.LocalId,false,grp.IsTemporary,grp.IsPhantom,false); grp.ScheduleGroupForFullUpdate(); } }