aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs207
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs128
2 files changed, 187 insertions, 148 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index eb08257..f2850bb 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -121,8 +121,53 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
121 /// </summary> 121 /// </summary>
122 private EntityTransferStateMachine m_entityTransferStateMachine; 122 private EntityTransferStateMachine m_entityTransferStateMachine;
123 123
124 private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions = 124 // For performance, we keed a cached of banned regions so we don't keep going
125 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>(); 125 // to the grid service.
126 private class BannedRegionCache
127 {
128 private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
129 new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
130 ExpiringCache<ulong, DateTime> m_idCache;
131 DateTime m_banUntil;
132 public BannedRegionCache()
133 {
134 }
135 // Return 'true' if there is a valid ban entry for this agent in this region
136 public bool IfBanned(ulong pRegionHandle, UUID pAgentID)
137 {
138 bool ret = false;
139 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
140 {
141 if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil))
142 {
143 if (DateTime.Now < m_banUntil)
144 {
145 ret = true;
146 }
147 }
148 }
149 return ret;
150 }
151 // Add this agent in this region as a banned person
152 public void Add(ulong pRegionHandle, UUID pAgentID)
153 {
154 if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
155 {
156 m_idCache = new ExpiringCache<ulong, DateTime>();
157 m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45));
158 }
159 m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
160 }
161 // Remove the agent from the region's banned list
162 public void Remove(ulong pRegionHandle, UUID pAgentID)
163 {
164 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
165 {
166 m_idCache.Remove(pRegionHandle);
167 }
168 }
169 }
170 private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
126 171
127 private IEventQueue m_eqModule; 172 private IEventQueue m_eqModule;
128 private IRegionCombinerModule m_regionCombinerModule; 173 private IRegionCombinerModule m_regionCombinerModule;
@@ -1393,7 +1438,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1393 1438
1394 // Call the grid service to lookup the region containing the new position. 1439 // Call the grid service to lookup the region containing the new position.
1395 GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, 1440 GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
1396 presenceWorldX, presenceWorldY); 1441 presenceWorldX, presenceWorldY,
1442 Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
1397 1443
1398 if (neighbourRegion != null) 1444 if (neighbourRegion != null)
1399 { 1445 {
@@ -1402,24 +1448,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1402 (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), 1448 (float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
1403 pos.Z); 1449 pos.Z);
1404 1450
1405 // Check if banned from destination region. 1451 if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
1406 ExpiringCache<ulong, DateTime> r;
1407 DateTime banUntil;
1408 if (m_bannedRegions.TryGetValue(agentID, out r))
1409 { 1452 {
1410 if (r.TryGetValue(neighbourRegion.RegionHandle, out banUntil)) 1453 neighbourRegion = null;
1411 {
1412 if (DateTime.Now < banUntil)
1413 {
1414 // If we're banned from the destination, we just can't go there.
1415 neighbourRegion = null;
1416 }
1417 r.Remove(neighbourRegion.RegionHandle);
1418 }
1419 } 1454 }
1420 else 1455 else
1421 { 1456 {
1422 r = null; 1457 // If not banned, make sure this agent is not in the list.
1458 m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
1423 } 1459 }
1424 1460
1425 // Check to see if we have access to the target region. 1461 // Check to see if we have access to the target region.
@@ -1427,17 +1463,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1427 if (neighbourRegion != null 1463 if (neighbourRegion != null
1428 && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason)) 1464 && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason))
1429 { 1465 {
1430 if (r == null) 1466 // remember banned
1431 { 1467 m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
1432 r = new ExpiringCache<ulong, DateTime>();
1433 r.Add(neighbourRegion.RegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
1434
1435 m_bannedRegions.Add(agentID, r, TimeSpan.FromSeconds(45));
1436 }
1437 else
1438 {
1439 r.Add(neighbourRegion.RegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
1440 }
1441 neighbourRegion = null; 1468 neighbourRegion = null;
1442 } 1469 }
1443 } 1470 }
@@ -1993,14 +2020,119 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1993 0f); 2020 0f);
1994 } 2021 }
1995 2022
2023 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
2024 {
2025 // Since we don't know how big the regions could be, we have to search a very large area
2026 // to find possible regions.
2027 return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
2028 }
2029
2030 #region NotFoundLocationCache class
2031 // A collection of not found locations to make future lookups 'not found' lookups quick.
2032 // A simple expiring cache that keeps not found locations for some number of seconds.
2033 // A 'not found' location is presumed to be anywhere in the minimum sized region that
2034 // contains that point. A conservitive estimate.
2035 private class NotFoundLocationCache
2036 {
2037 private struct NotFoundLocation
2038 {
2039 public double minX, maxX, minY, maxY;
2040 public DateTime expireTime;
2041 }
2042 private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
2043 public NotFoundLocationCache()
2044 {
2045 }
2046 // Add an area to the lost of 'not found' places. The area is the snapped region
2047 // area around the added point.
2048 public void Add(double pX, double pY)
2049 {
2050 lock (m_notFoundLocations)
2051 {
2052 if (!LockedContains(pX, pY))
2053 {
2054 NotFoundLocation nfl = new NotFoundLocation();
2055 // A not found location is not found for at least a whole region sized area
2056 nfl.minX = pX - (pX % (double)Constants.RegionSize);
2057 nfl.minY = pY - (pY % (double)Constants.RegionSize);
2058 nfl.maxX = nfl.minX + (double)Constants.RegionSize;
2059 nfl.maxY = nfl.minY + (double)Constants.RegionSize;
2060 nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
2061 m_notFoundLocations.Add(nfl);
2062 }
2063 }
2064
2065 }
2066 // Test to see of this point is in any of the 'not found' areas.
2067 // Return 'true' if the point is found inside the 'not found' areas.
2068 public bool Contains(double pX, double pY)
2069 {
2070 bool ret = false;
2071 lock (m_notFoundLocations)
2072 ret = LockedContains(pX, pY);
2073 return ret;
2074 }
2075 private bool LockedContains(double pX, double pY)
2076 {
2077 bool ret = false;
2078 this.DoExpiration();
2079 foreach (NotFoundLocation nfl in m_notFoundLocations)
2080 {
2081 if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
2082 {
2083 ret = true;
2084 break;
2085 }
2086 }
2087 return ret;
2088 }
2089 private void DoExpiration()
2090 {
2091 List<NotFoundLocation> m_toRemove = null;
2092 DateTime now = DateTime.Now;
2093 foreach (NotFoundLocation nfl in m_notFoundLocations)
2094 {
2095 if (nfl.expireTime < now)
2096 {
2097 if (m_toRemove == null)
2098 m_toRemove = new List<NotFoundLocation>();
2099 m_toRemove.Add(nfl);
2100 }
2101 }
2102 if (m_toRemove != null)
2103 {
2104 foreach (NotFoundLocation nfl in m_toRemove)
2105 m_notFoundLocations.Remove(nfl);
2106 m_toRemove.Clear();
2107 }
2108 }
2109 }
2110 #endregion // NotFoundLocationCache class
2111 private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
2112
1996 // Given a world position (fractional meter coordinate), get the GridRegion info for 2113 // Given a world position (fractional meter coordinate), get the GridRegion info for
1997 // the region containing that point. 2114 // the region containing that point.
1998 // Someday this should be a method on GridService. 2115 // Someday this should be a method on GridService.
2116 // 'pSizeHint' is the size of the source region but since the destination point can be anywhere
2117 // the size of the target region is unknown thus the search area might have to be very large.
1999 // Return 'null' if no such region exists. 2118 // Return 'null' if no such region exists.
2000 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) 2119 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
2120 double px, double py, uint pSizeHint)
2001 { 2121 {
2002 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); 2122 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py);
2003 GridRegion ret = null; 2123 GridRegion ret = null;
2124 const double fudge = 2.0;
2125
2126 // One problem with this routine is negative results. That is, this can be called lots of times
2127 // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
2128 // will be quick 'not found's next time.
2129 // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
2130 // thus re-ask the GridService about the location.
2131 if (m_notFoundLocationCache.Contains(px, py))
2132 {
2133 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
2134 return null;
2135 }
2004 2136
2005 // As an optimization, since most regions will be legacy sized regions (256x256), first try to get 2137 // As an optimization, since most regions will be legacy sized regions (256x256), first try to get
2006 // the region at the appropriate legacy region location. 2138 // the region at the appropriate legacy region location.
@@ -2018,13 +2150,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2018 if (ret == null) 2150 if (ret == null)
2019 { 2151 {
2020 // If the simple lookup failed, search the larger area for a region that contains this point 2152 // If the simple lookup failed, search the larger area for a region that contains this point
2021 double range = (double)Constants.RegionSize * 2 + 2; 2153 double range = (double)pSizeHint + fudge;
2022 while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) 2154 while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
2023 { 2155 {
2024 // Get from the grid service a list of regions that might contain this point 2156 // Get from the grid service a list of regions that might contain this point.
2157 // The region origin will be in the zero direction so only subtract the range.
2025 List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID, 2158 List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
2026 (int)(px - range), (int)(px + range), 2159 (int)(px - range), (int)(px),
2027 (int)(py - range), (int)(py + range)); 2160 (int)(py - range), (int)(py));
2028 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", 2161 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
2029 LogHeader, possibleRegions.Count, range); 2162 LogHeader, possibleRegions.Count, range);
2030 if (possibleRegions != null && possibleRegions.Count > 0) 2163 if (possibleRegions != null && possibleRegions.Count > 0)
@@ -2048,6 +2181,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2048 range *= 2; 2181 range *= 2;
2049 } 2182 }
2050 } 2183 }
2184
2185 if (ret == null)
2186 {
2187 // remember this location was not found so we can quickly not find it next time
2188 m_notFoundLocationCache.Add(px, py);
2189 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
2190 }
2191
2051 return ret; 2192 return ret;
2052 } 2193 }
2053 2194
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 4efd9d5..a98baea 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -3425,6 +3425,7 @@ namespace OpenSim.Region.Framework.Scenes
3425 if (!IsInTransit) 3425 if (!IsInTransit)
3426 { 3426 {
3427 Vector3 pos2 = AbsolutePosition; 3427 Vector3 pos2 = AbsolutePosition;
3428 Vector3 origPosition = pos2;
3428 Vector3 vel = Velocity; 3429 Vector3 vel = Velocity;
3429 int neighbor = 0; 3430 int neighbor = 0;
3430 int[] fix = new int[2]; 3431 int[] fix = new int[2];
@@ -3459,128 +3460,25 @@ namespace OpenSim.Region.Framework.Scenes
3459 // Tried to make crossing happen but it failed. 3460 // Tried to make crossing happen but it failed.
3460 if (m_requestedSitTargetUUID == UUID.Zero) 3461 if (m_requestedSitTargetUUID == UUID.Zero)
3461 { 3462 {
3462 3463 m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader);
3463 Vector3 pos = AbsolutePosition; 3464 const float borderFudge = 0.1f;
3464 if (AbsolutePosition.X < 0) 3465
3465 pos.X += Velocity.X * 2; 3466 if (origPosition.X < 0)
3466 else if (AbsolutePosition.X > m_scene.RegionInfo.RegionSizeX) 3467 origPosition.X = borderFudge;
3467 pos.X -= Velocity.X * 2; 3468 else if (origPosition.X > (float)m_scene.RegionInfo.RegionSizeX)
3468 if (AbsolutePosition.Y < 0) 3469 origPosition.X = (float)m_scene.RegionInfo.RegionSizeX - borderFudge;
3469 pos.Y += Velocity.Y * 2; 3470 if (origPosition.Y < 0)
3470 else if (AbsolutePosition.Y > m_scene.RegionInfo.RegionSizeY) 3471 origPosition.Y = borderFudge;
3471 pos.Y -= Velocity.Y * 2; 3472 else if (origPosition.Y > (float)m_scene.RegionInfo.RegionSizeY)
3473 origPosition.Y = (float)m_scene.RegionInfo.RegionSizeY - borderFudge;
3472 Velocity = Vector3.Zero; 3474 Velocity = Vector3.Zero;
3473 AbsolutePosition = pos; 3475 AbsolutePosition = origPosition;
3474 3476
3475 AddToPhysicalScene(isFlying); 3477 AddToPhysicalScene(isFlying);
3476 } 3478 }
3477 } 3479 }
3478 3480
3479 } 3481 }
3480
3481 /*
3482 // Checks if where it's headed exists a region
3483 if (m_scene.TestBorderCross(pos2, Cardinals.W))
3484 {
3485 if (m_scene.TestBorderCross(pos2, Cardinals.S))
3486 {
3487 needsTransit = true;
3488 neighbor = m_scene.HaveNeighbor(Cardinals.SW, ref fix);
3489 }
3490 else if (m_scene.TestBorderCross(pos2, Cardinals.N))
3491 {
3492 needsTransit = true;
3493 neighbor = m_scene.HaveNeighbor(Cardinals.NW, ref fix);
3494 }
3495 else
3496 {
3497 needsTransit = true;
3498 neighbor = m_scene.HaveNeighbor(Cardinals.W, ref fix);
3499 }
3500 }
3501 else if (m_scene.TestBorderCross(pos2, Cardinals.E))
3502 {
3503 if (m_scene.TestBorderCross(pos2, Cardinals.S))
3504 {
3505 needsTransit = true;
3506 neighbor = m_scene.HaveNeighbor(Cardinals.SE, ref fix);
3507 }
3508 else if (m_scene.TestBorderCross(pos2, Cardinals.N))
3509 {
3510 needsTransit = true;
3511 neighbor = m_scene.HaveNeighbor(Cardinals.NE, ref fix);
3512 }
3513 else
3514 {
3515 needsTransit = true;
3516 neighbor = m_scene.HaveNeighbor(Cardinals.E, ref fix);
3517 }
3518 }
3519 else if (m_scene.TestBorderCross(pos2, Cardinals.S))
3520 {
3521 needsTransit = true;
3522 neighbor = m_scene.HaveNeighbor(Cardinals.S, ref fix);
3523 }
3524 else if (m_scene.TestBorderCross(pos2, Cardinals.N))
3525 {
3526 needsTransit = true;
3527 neighbor = m_scene.HaveNeighbor(Cardinals.N, ref fix);
3528 }
3529
3530 // Makes sure avatar does not end up outside region
3531 if (neighbor <= 0)
3532 {
3533 if (needsTransit)
3534 {
3535 if (m_requestedSitTargetUUID == UUID.Zero)
3536 {
3537 bool isFlying = Flying;
3538 RemoveFromPhysicalScene();
3539
3540 Vector3 pos = AbsolutePosition;
3541 if (AbsolutePosition.X < 0)
3542 pos.X += Velocity.X * 2;
3543 else if (AbsolutePosition.X > m_scene.RegionInfo.RegionSizeX)
3544 pos.X -= Velocity.X * 2;
3545 if (AbsolutePosition.Y < 0)
3546 pos.Y += Velocity.Y * 2;
3547 else if (AbsolutePosition.Y > m_scene.RegionInfo.RegionSizeY)
3548 pos.Y -= Velocity.Y * 2;
3549 Velocity = Vector3.Zero;
3550 AbsolutePosition = pos;
3551
3552// m_log.DebugFormat("[SCENE PRESENCE]: Prevented flyoff for {0} at {1}", Name, AbsolutePosition);
3553
3554 AddToPhysicalScene(isFlying);
3555 }
3556 }
3557 }
3558 else if (neighbor > 0)
3559 {
3560 if (!CrossToNewRegion())
3561 {
3562 if (m_requestedSitTargetUUID == UUID.Zero)
3563 {
3564 bool isFlying = Flying;
3565 RemoveFromPhysicalScene();
3566
3567 Vector3 pos = AbsolutePosition;
3568 if (AbsolutePosition.X < 0)
3569 pos.X += Velocity.X * 2;
3570 else if (AbsolutePosition.X > m_scene.RegionInfo.RegionSizeX)
3571 pos.X -= Velocity.X * 2;
3572 if (AbsolutePosition.Y < 0)
3573 pos.Y += Velocity.Y * 2;
3574 else if (AbsolutePosition.Y > m_scene.RegionInfo.RegionSizeY)
3575 pos.Y -= Velocity.Y * 2;
3576 Velocity = Vector3.Zero;
3577 AbsolutePosition = pos;
3578
3579 AddToPhysicalScene(isFlying);
3580 }
3581 }
3582 }
3583 */
3584 } 3482 }
3585 else 3483 else
3586 { 3484 {