diff options
author | Robert Adams | 2015-03-22 21:53:02 -0700 |
---|---|---|
committer | Robert Adams | 2015-03-22 21:53:02 -0700 |
commit | 9f18e3ba80a6469b7ff03c7cca595a0a3b999592 (patch) | |
tree | c2ace74c3ffc6eab80b94bfbe4e6a2d37197eb28 /OpenSim/Region/CoreModules/Framework/EntityTransfer | |
parent | Allow setting the size of the wearables array from config, for core compatibi... (diff) | |
download | opensim-SC_OLD-9f18e3ba80a6469b7ff03c7cca595a0a3b999592.zip opensim-SC_OLD-9f18e3ba80a6469b7ff03c7cca595a0a3b999592.tar.gz opensim-SC_OLD-9f18e3ba80a6469b7ff03c7cca595a0a3b999592.tar.bz2 opensim-SC_OLD-9f18e3ba80a6469b7ff03c7cca595a0a3b999592.tar.xz |
Varregion: first cut at removing Border class checks for region crossings.
Added Scene.PositionIsInCurrentRegion(pos) to sense when new position needs some crossing work.
Many changes made to EntityTransferModule to accomodate new crossing sense logic.
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework/EntityTransfer')
-rw-r--r-- | OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 840 |
1 files changed, 382 insertions, 458 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index b32a169..0f6c507 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; |
@@ -337,6 +382,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
337 | "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name); | 382 | "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name); |
338 | } | 383 | } |
339 | 384 | ||
385 | // Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle). | ||
340 | public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) | 386 | public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) |
341 | { | 387 | { |
342 | if (sp.Scene.Permissions.IsGridGod(sp.UUID)) | 388 | if (sp.Scene.Permissions.IsGridGod(sp.UUID)) |
@@ -418,7 +464,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
418 | sp.Name, position, sp.Scene.RegionInfo.RegionName); | 464 | sp.Name, position, sp.Scene.RegionInfo.RegionName); |
419 | 465 | ||
420 | // Teleport within the same region | 466 | // Teleport within the same region |
421 | if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) | 467 | if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0) |
422 | { | 468 | { |
423 | Vector3 emergencyPos = new Vector3(128, 128, 128); | 469 | Vector3 emergencyPos = new Vector3(128, 128, 128); |
424 | 470 | ||
@@ -437,10 +483,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
437 | float posZLimit = 22; | 483 | float posZLimit = 22; |
438 | 484 | ||
439 | // TODO: Check other Scene HeightField | 485 | // TODO: Check other Scene HeightField |
440 | if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) | 486 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; |
441 | { | ||
442 | posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y]; | ||
443 | } | ||
444 | 487 | ||
445 | posZLimit += localHalfAVHeight + 0.1f; | 488 | posZLimit += localHalfAVHeight + 0.1f; |
446 | 489 | ||
@@ -484,9 +527,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
484 | ScenePresence sp, ulong regionHandle, Vector3 position, | 527 | ScenePresence sp, ulong regionHandle, Vector3 position, |
485 | Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) | 528 | Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) |
486 | { | 529 | { |
487 | uint x = 0, y = 0; | 530 | // Get destination region taking into account that the address could be an offset |
488 | Utils.LongToUInts(regionHandle, out x, out y); | 531 | // region inside a varregion. |
489 | GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); | 532 | GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position); |
490 | 533 | ||
491 | if (reg != null) | 534 | if (reg != null) |
492 | { | 535 | { |
@@ -537,12 +580,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
537 | 580 | ||
538 | // and set the map-tile to '(Offline)' | 581 | // and set the map-tile to '(Offline)' |
539 | uint regX, regY; | 582 | uint regX, regY; |
540 | Utils.LongToUInts(regionHandle, out regX, out regY); | 583 | Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY); |
541 | 584 | ||
542 | MapBlockData block = new MapBlockData(); | 585 | MapBlockData block = new MapBlockData(); |
543 | block.X = (ushort)(regX / Constants.RegionSize); | 586 | block.X = (ushort)(regX / Constants.RegionSize); |
544 | block.Y = (ushort)(regY / Constants.RegionSize); | 587 | block.Y = (ushort)(regY / Constants.RegionSize); |
545 | block.Access = 254; // == not there | 588 | block.Access = (byte)SimAccess.Down; // == not there |
546 | 589 | ||
547 | List<MapBlockData> blocks = new List<MapBlockData>(); | 590 | List<MapBlockData> blocks = new List<MapBlockData>(); |
548 | blocks.Add(block); | 591 | blocks.Add(block); |
@@ -550,6 +593,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
550 | } | 593 | } |
551 | } | 594 | } |
552 | 595 | ||
596 | // The teleport address could be an address in a subregion of a larger varregion. | ||
597 | // Find the real base region and adjust the teleport location to account for the | ||
598 | // larger region. | ||
599 | private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position) | ||
600 | { | ||
601 | uint x = 0, y = 0; | ||
602 | Util.RegionHandleToWorldLoc(regionHandle, out x, out y); | ||
603 | |||
604 | // Compute the world location we're teleporting to | ||
605 | double worldX = (double)x + position.X; | ||
606 | double worldY = (double)y + position.Y; | ||
607 | |||
608 | // Find the region that contains the position | ||
609 | GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY); | ||
610 | |||
611 | if (reg != null) | ||
612 | { | ||
613 | // modify the position for the offset into the actual region returned | ||
614 | position.X += x - reg.RegionLocX; | ||
615 | position.Y += y - reg.RegionLocY; | ||
616 | } | ||
617 | |||
618 | return reg; | ||
619 | } | ||
620 | |||
553 | // Nothing to validate here | 621 | // Nothing to validate here |
554 | protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) | 622 | protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) |
555 | { | 623 | { |
@@ -650,10 +718,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
650 | return; | 718 | return; |
651 | } | 719 | } |
652 | 720 | ||
653 | uint newRegionX = (uint)(reg.RegionHandle >> 40); | 721 | uint newRegionX, newRegionY, oldRegionX, oldRegionY; |
654 | uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); | 722 | Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY); |
655 | uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); | 723 | Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY); |
656 | uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8); | ||
657 | 724 | ||
658 | ulong destinationHandle = finalDestination.RegionHandle; | 725 | ulong destinationHandle = finalDestination.RegionHandle; |
659 | 726 | ||
@@ -675,8 +742,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
675 | 742 | ||
676 | string reason; | 743 | string reason; |
677 | string version; | 744 | string version; |
745 | string myversion = string.Format("{0}/{1}", OutgoingTransferVersionName, MaxOutgoingTransferVersion); | ||
678 | if (!Scene.SimulationService.QueryAccess( | 746 | if (!Scene.SimulationService.QueryAccess( |
679 | finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) | 747 | finalDestination, sp.ControllingClient.AgentId, position, out version, out reason)) |
680 | { | 748 | { |
681 | sp.ControllingClient.SendTeleportFailed(reason); | 749 | sp.ControllingClient.SendTeleportFailed(reason); |
682 | 750 | ||
@@ -1274,6 +1342,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1274 | return region; | 1342 | return region; |
1275 | } | 1343 | } |
1276 | 1344 | ||
1345 | // This returns 'true' if the new region already has a child agent for our | ||
1346 | // incoming agent. The implication is that, if 'false', we have to create the | ||
1347 | // child and then teleport into the region. | ||
1277 | protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) | 1348 | protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) |
1278 | { | 1349 | { |
1279 | if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) | 1350 | if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) |
@@ -1298,20 +1369,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1298 | return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); | 1369 | return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); |
1299 | } | 1370 | } |
1300 | 1371 | ||
1301 | protected virtual bool IsOutsideRegion(Scene s, Vector3 pos) | ||
1302 | { | ||
1303 | if (s.TestBorderCross(pos, Cardinals.N)) | ||
1304 | return true; | ||
1305 | if (s.TestBorderCross(pos, Cardinals.S)) | ||
1306 | return true; | ||
1307 | if (s.TestBorderCross(pos, Cardinals.E)) | ||
1308 | return true; | ||
1309 | if (s.TestBorderCross(pos, Cardinals.W)) | ||
1310 | return true; | ||
1311 | |||
1312 | return false; | ||
1313 | } | ||
1314 | |||
1315 | #endregion | 1372 | #endregion |
1316 | 1373 | ||
1317 | #region Landmark Teleport | 1374 | #region Landmark Teleport |
@@ -1390,214 +1447,80 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1390 | 1447 | ||
1391 | #region Agent Crossings | 1448 | #region Agent Crossings |
1392 | 1449 | ||
1393 | public bool checkAgentAccessToRegion(ScenePresence agent, GridRegion destiny, Vector3 position, out string version, out string reason) | ||
1394 | { | ||
1395 | reason = String.Empty; | ||
1396 | version = String.Empty; | ||
1397 | |||
1398 | UUID agentID = agent.UUID; | ||
1399 | ulong destinyHandle = destiny.RegionHandle; | ||
1400 | |||
1401 | ExpiringCache<ulong, DateTime> r; | ||
1402 | DateTime banUntil; | ||
1403 | if (m_bannedRegions.TryGetValue(agentID, out r)) | ||
1404 | { | ||
1405 | if (r.TryGetValue(destinyHandle, out banUntil)) | ||
1406 | { | ||
1407 | if (DateTime.Now < banUntil) | ||
1408 | { | ||
1409 | reason = "Cannot connect to region"; | ||
1410 | return false; | ||
1411 | } | ||
1412 | r.Remove(destinyHandle); | ||
1413 | } | ||
1414 | } | ||
1415 | else | ||
1416 | { | ||
1417 | r = null; | ||
1418 | } | ||
1419 | |||
1420 | Scene ascene = agent.Scene; | ||
1421 | |||
1422 | if (!ascene.SimulationService.QueryAccess(destiny, agentID, position, out version, out reason)) | ||
1423 | { | ||
1424 | if (r == null) | ||
1425 | { | ||
1426 | r = new ExpiringCache<ulong, DateTime>(); | ||
1427 | r.Add(destinyHandle, DateTime.Now + TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); | ||
1428 | |||
1429 | m_bannedRegions.Add(agentID, r, TimeSpan.FromSeconds(30)); | ||
1430 | } | ||
1431 | else | ||
1432 | { | ||
1433 | r.Add(destinyHandle, DateTime.Now + TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(30)); | ||
1434 | } | ||
1435 | return false; | ||
1436 | } | ||
1437 | return true; | ||
1438 | } | ||
1439 | |||
1440 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos) | 1450 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos) |
1441 | { | 1451 | { |
1442 | string r = String.Empty; | 1452 | string r = String.Empty; |
1443 | return GetDestination(scene, agentID, pos, out version, out newpos, out r); | 1453 | return GetDestination(scene, agentID, pos, out version, out newpos, out r); |
1444 | } | 1454 | } |
1445 | 1455 | ||
1446 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos, out string reason) | 1456 | // Given a position relative to the current region (which has previously been tested to |
1457 | // see that it is actually outside the current region), find the new region that the | ||
1458 | // point is actually in. | ||
1459 | // Returns the coordinates and information of the new region or 'null' of it doesn't exist. | ||
1460 | public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, | ||
1461 | out string version, out Vector3 newpos, out string failureReason) | ||
1447 | { | 1462 | { |
1448 | version = String.Empty; | 1463 | version = String.Empty; |
1449 | reason = String.Empty; | ||
1450 | newpos = pos; | 1464 | newpos = pos; |
1465 | failureReason = string.Empty; | ||
1451 | 1466 | ||
1452 | // m_log.DebugFormat( | 1467 | // m_log.DebugFormat( |
1453 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); | 1468 | // "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); |
1454 | 1469 | ||
1455 | RegionInfo regInfo = scene.RegionInfo; | 1470 | // Compute world location of the object's position |
1471 | double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X; | ||
1472 | double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y; | ||
1456 | 1473 | ||
1457 | uint neighbourx = regInfo.RegionLocX; | 1474 | // Call the grid service to lookup the region containing the new position. |
1458 | uint neighboury = regInfo.RegionLocY; | 1475 | GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, |
1459 | const float boundaryDistance = 0.7f; | 1476 | presenceWorldX, presenceWorldY, |
1460 | 1477 | Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY)); | |
1461 | /* | ||
1462 | Vector3 northCross = new Vector3(0, boundaryDistance, 0); | ||
1463 | Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0); | ||
1464 | Vector3 eastCross = new Vector3(boundaryDistance, 0, 0); | ||
1465 | Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0); | ||
1466 | 1478 | ||
1467 | // distance into new region to place avatar | 1479 | if (neighbourRegion != null) |
1468 | const float enterDistance = 0.5f; | ||
1469 | const float maxX = Constants.RegionSize - enterDistance; | ||
1470 | const float maxY = Constants.RegionSize - enterDistance; | ||
1471 | |||
1472 | if (scene.TestBorderCross(pos + westCross, Cardinals.W)) | ||
1473 | { | 1480 | { |
1474 | if (scene.TestBorderCross(pos + northCross, Cardinals.N)) | 1481 | // Compute the entity's position relative to the new region |
1475 | { | 1482 | newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX), |
1476 | Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); | 1483 | (float)(presenceWorldY - (double)neighbourRegion.RegionLocY), |
1477 | neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); | 1484 | pos.Z); |
1478 | newpos.Y -= Constants.RegionSize; | ||
1479 | } | ||
1480 | else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) | ||
1481 | { | ||
1482 | neighboury--; | ||
1483 | newpos.Y += Constants.RegionSize; | ||
1484 | } | ||
1485 | |||
1486 | neighbourx--; | ||
1487 | newpos.X += Constants.RegionSize; | ||
1488 | } | ||
1489 | else if (scene.TestBorderCross(pos + eastCross, Cardinals.E)) | ||
1490 | { | ||
1491 | Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); | ||
1492 | neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); | ||
1493 | newpos.X -= Constants.RegionSize; | ||
1494 | 1485 | ||
1495 | if (scene.TestBorderCross(pos + southCross, Cardinals.S)) | 1486 | if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID)) |
1496 | { | 1487 | { |
1497 | neighboury--; | 1488 | failureReason = "Cannot region cross into banned parcel"; |
1498 | newpos.Y += Constants.RegionSize; | 1489 | neighbourRegion = null; |
1499 | } | 1490 | } |
1500 | else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) | 1491 | else |
1501 | { | 1492 | { |
1502 | Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); | 1493 | // If not banned, make sure this agent is not in the list. |
1503 | neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); | 1494 | m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID); |
1504 | newpos.Y -= Constants.RegionSize; | ||
1505 | } | 1495 | } |
1506 | } | ||
1507 | else if (scene.TestBorderCross(pos + southCross, Cardinals.S)) | ||
1508 | { | ||
1509 | Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S); | ||
1510 | neighboury--; | ||
1511 | newpos.Y += Constants.RegionSize; | ||
1512 | } | ||
1513 | else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) | ||
1514 | { | ||
1515 | Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N); | ||
1516 | neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); | ||
1517 | newpos.Y -= Constants.RegionSize; | ||
1518 | } | ||
1519 | 1496 | ||
1520 | newpos.X = Util.Clamp(newpos.X, enterDistance, maxX); | 1497 | // Check to see if we have access to the target region. |
1521 | newpos.Y = Util.Clamp(newpos.Y, enterDistance, maxY); | 1498 | string myversion = string.Format("{0}/{1}", OutgoingTransferVersionName, MaxOutgoingTransferVersion); |
1522 | */ | 1499 | if (neighbourRegion != null |
1523 | float regionSizeX = regInfo.RegionSizeX; | 1500 | && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out failureReason)) |
1524 | float regionSizeY = regInfo.RegionSizeY; | ||
1525 | |||
1526 | if (pos.X < boundaryDistance) | ||
1527 | neighbourx--; | ||
1528 | else if (pos.X > regionSizeX - boundaryDistance) | ||
1529 | neighbourx += (uint)(regionSizeX / Constants.RegionSize); | ||
1530 | |||
1531 | if (pos.Y < boundaryDistance) | ||
1532 | neighboury--; | ||
1533 | else if (pos.Y > regionSizeY - boundaryDistance) | ||
1534 | neighboury += (uint)(regionSizeY / Constants.RegionSize); | ||
1535 | |||
1536 | int x = (int)(neighbourx * Constants.RegionSize); | ||
1537 | int y = (int)(neighboury * Constants.RegionSize); | ||
1538 | |||
1539 | ulong neighbourHandle = Utils.UIntsToLong((uint)x, (uint)y); | ||
1540 | |||
1541 | ExpiringCache<ulong, DateTime> r; | ||
1542 | DateTime banUntil; | ||
1543 | |||
1544 | if (m_bannedRegions.TryGetValue(agentID, out r)) | ||
1545 | { | ||
1546 | if (r.TryGetValue(neighbourHandle, out banUntil)) | ||
1547 | { | 1501 | { |
1548 | if (DateTime.Now < banUntil) | 1502 | // remember banned |
1549 | return null; | 1503 | m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID); |
1550 | r.Remove(neighbourHandle); | 1504 | neighbourRegion = null; |
1551 | } | 1505 | } |
1552 | } | 1506 | } |
1553 | else | 1507 | else |
1554 | { | 1508 | { |
1555 | r = null; | 1509 | // The destination region just doesn't exist |
1510 | failureReason = "Cannot cross into non-existent region"; | ||
1556 | } | 1511 | } |
1557 | 1512 | ||
1558 | GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); | ||
1559 | if (neighbourRegion == null) | 1513 | if (neighbourRegion == null) |
1560 | { | 1514 | m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}", |
1561 | reason = ""; | 1515 | LogHeader, scene.RegionInfo.RegionName, |
1562 | return null; | 1516 | scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, |
1563 | } | 1517 | scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY, |
1564 | 1518 | pos); | |
1565 | float newRegionSizeX = neighbourRegion.RegionSizeX; | 1519 | else |
1566 | float newRegionSizeY = neighbourRegion.RegionSizeY; | 1520 | m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>", |
1567 | if (newRegionSizeX == 0) | 1521 | LogHeader, neighbourRegion.RegionName, |
1568 | newRegionSizeX = Constants.RegionSize; | 1522 | neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY, |
1569 | if (newRegionSizeY == 0) | 1523 | newpos.X, newpos.Y); |
1570 | newRegionSizeY = Constants.RegionSize; | ||
1571 | |||
1572 | if (pos.X < boundaryDistance) | ||
1573 | newpos.X += newRegionSizeX; | ||
1574 | else if (pos.X > regionSizeX - boundaryDistance) | ||
1575 | newpos.X -= regionSizeX; | ||
1576 | |||
1577 | if (pos.Y < boundaryDistance) | ||
1578 | newpos.Y += newRegionSizeY; | ||
1579 | else if (pos.Y > regionSizeY - boundaryDistance) | ||
1580 | newpos.Y -= regionSizeY; | ||
1581 | |||
1582 | const float enterDistance = 0.5f; | ||
1583 | newpos.X = Util.Clamp(newpos.X, enterDistance, newRegionSizeX - enterDistance); | ||
1584 | newpos.Y = Util.Clamp(newpos.Y, enterDistance, newRegionSizeY - enterDistance); | ||
1585 | |||
1586 | if (!scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason)) | ||
1587 | { | ||
1588 | if (r == null) | ||
1589 | { | ||
1590 | r = new ExpiringCache<ulong, DateTime>(); | ||
1591 | r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | ||
1592 | |||
1593 | m_bannedRegions.Add(agentID, r, TimeSpan.FromSeconds(45)); | ||
1594 | } | ||
1595 | else | ||
1596 | { | ||
1597 | r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15)); | ||
1598 | } | ||
1599 | return null; | ||
1600 | } | ||
1601 | 1524 | ||
1602 | return neighbourRegion; | 1525 | return neighbourRegion; |
1603 | } | 1526 | } |
@@ -1632,15 +1555,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1632 | uint y; | 1555 | uint y; |
1633 | Vector3 newpos; | 1556 | Vector3 newpos; |
1634 | string version; | 1557 | string version; |
1635 | string reason; | 1558 | string failureReason; |
1636 | 1559 | ||
1637 | Vector3 pos = agent.AbsolutePosition + agent.Velocity; | 1560 | Vector3 pos = agent.AbsolutePosition + agent.Velocity; |
1638 | 1561 | ||
1639 | GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, out version, out newpos, out reason); | 1562 | GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, |
1563 | out version, out newpos, out failureReason); | ||
1640 | if (neighbourRegion == null) | 1564 | if (neighbourRegion == null) |
1641 | { | 1565 | { |
1642 | if (reason != String.Empty) | 1566 | if (failureReason != String.Empty) |
1643 | agent.ControllingClient.SendAlertMessage("Cannot cross to region"); | 1567 | agent.ControllingClient.SendAlertMessage(failureReason); |
1644 | return agent; | 1568 | return agent; |
1645 | } | 1569 | } |
1646 | 1570 | ||
@@ -1678,7 +1602,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1678 | 1602 | ||
1679 | agent.Scene.RequestTeleportLocation( | 1603 | agent.Scene.RequestTeleportLocation( |
1680 | agent.ControllingClient, | 1604 | agent.ControllingClient, |
1681 | Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize), | 1605 | Util.RegionLocToHandle(regionX, regionY), |
1682 | position, | 1606 | position, |
1683 | agent.Lookat, | 1607 | agent.Lookat, |
1684 | (uint)Constants.TeleportFlags.ViaLocation); | 1608 | (uint)Constants.TeleportFlags.ViaLocation); |
@@ -1688,11 +1612,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1688 | if (im != null) | 1612 | if (im != null) |
1689 | { | 1613 | { |
1690 | UUID gotoLocation = Util.BuildFakeParcelID( | 1614 | UUID gotoLocation = Util.BuildFakeParcelID( |
1691 | Util.UIntsToLong( | 1615 | Util.RegionLocToHandle(regionX, regionY), |
1692 | (regionX * | ||
1693 | (uint)Constants.RegionSize), | ||
1694 | (regionY * | ||
1695 | (uint)Constants.RegionSize)), | ||
1696 | (uint)(int)position.X, | 1616 | (uint)(int)position.X, |
1697 | (uint)(int)position.Y, | 1617 | (uint)(int)position.Y, |
1698 | (uint)(int)position.Z); | 1618 | (uint)(int)position.Z); |
@@ -1745,8 +1665,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1745 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. | 1665 | /// Calls an asynchronous method to do so.. so it doesn't lag the sim. |
1746 | /// </summary> | 1666 | /// </summary> |
1747 | public ScenePresence CrossAgentToNewRegionAsync( | 1667 | public ScenePresence CrossAgentToNewRegionAsync( |
1748 | ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, | 1668 | ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, |
1749 | bool isFlying, string version) | 1669 | bool isFlying, string version) |
1750 | { | 1670 | { |
1751 | if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) | 1671 | if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) |
1752 | { | 1672 | { |
@@ -1893,11 +1813,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
1893 | // Next, let's close the child agent connections that are too far away. | 1813 | // Next, let's close the child agent connections that are too far away. |
1894 | uint neighbourx; | 1814 | uint neighbourx; |
1895 | uint neighboury; | 1815 | uint neighboury; |
1896 | 1816 | Util.RegionHandleToRegionLoc(neighbourRegion.RegionHandle, out neighbourx, out neighboury); | |
1897 | Utils.LongToUInts(neighbourRegion.RegionHandle, out neighbourx, out neighboury); | ||
1898 | |||
1899 | neighbourx /= Constants.RegionSize; | ||
1900 | neighboury /= Constants.RegionSize; | ||
1901 | 1817 | ||
1902 | agent.CloseChildAgents(neighbourx, neighboury); | 1818 | agent.CloseChildAgents(neighbourx, neighboury); |
1903 | 1819 | ||
@@ -2059,7 +1975,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2059 | 1975 | ||
2060 | if (m_regionInfo != null) | 1976 | if (m_regionInfo != null) |
2061 | { | 1977 | { |
2062 | neighbours = RequestNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); | 1978 | neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); |
2063 | } | 1979 | } |
2064 | else | 1980 | else |
2065 | { | 1981 | { |
@@ -2216,15 +2132,195 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2216 | } | 2132 | } |
2217 | } | 2133 | } |
2218 | 2134 | ||
2135 | // Computes the difference between two region bases. | ||
2136 | // Returns a vector of world coordinates (meters) from base of first region to the second. | ||
2137 | // The first region is the home region of the passed scene presence. | ||
2219 | Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) | 2138 | Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) |
2220 | { | 2139 | { |
2221 | int rRegionX = (int)sp.Scene.RegionInfo.RegionLocX; | 2140 | /* |
2222 | int rRegionY = (int)sp.Scene.RegionInfo.RegionLocY; | 2141 | int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX; |
2142 | int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY; | ||
2223 | int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; | 2143 | int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; |
2224 | int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; | 2144 | int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; |
2225 | int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; | 2145 | int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; |
2226 | int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; | 2146 | int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; |
2227 | return new Vector3(shiftx, shifty, 0f); | 2147 | return new Vector3(shiftx, shifty, 0f); |
2148 | */ | ||
2149 | return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX, | ||
2150 | sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY, | ||
2151 | 0f); | ||
2152 | } | ||
2153 | |||
2154 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py) | ||
2155 | { | ||
2156 | // Since we don't know how big the regions could be, we have to search a very large area | ||
2157 | // to find possible regions. | ||
2158 | return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize); | ||
2159 | } | ||
2160 | |||
2161 | #region NotFoundLocationCache class | ||
2162 | // A collection of not found locations to make future lookups 'not found' lookups quick. | ||
2163 | // A simple expiring cache that keeps not found locations for some number of seconds. | ||
2164 | // A 'not found' location is presumed to be anywhere in the minimum sized region that | ||
2165 | // contains that point. A conservitive estimate. | ||
2166 | private class NotFoundLocationCache | ||
2167 | { | ||
2168 | private struct NotFoundLocation | ||
2169 | { | ||
2170 | public double minX, maxX, minY, maxY; | ||
2171 | public DateTime expireTime; | ||
2172 | } | ||
2173 | private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>(); | ||
2174 | public NotFoundLocationCache() | ||
2175 | { | ||
2176 | } | ||
2177 | // Add an area to the list of 'not found' places. The area is the snapped region | ||
2178 | // area around the added point. | ||
2179 | public void Add(double pX, double pY) | ||
2180 | { | ||
2181 | lock (m_notFoundLocations) | ||
2182 | { | ||
2183 | if (!LockedContains(pX, pY)) | ||
2184 | { | ||
2185 | NotFoundLocation nfl = new NotFoundLocation(); | ||
2186 | // A not found location is not found for at least a whole region sized area | ||
2187 | nfl.minX = pX - (pX % (double)Constants.RegionSize); | ||
2188 | nfl.minY = pY - (pY % (double)Constants.RegionSize); | ||
2189 | nfl.maxX = nfl.minX + (double)Constants.RegionSize; | ||
2190 | nfl.maxY = nfl.minY + (double)Constants.RegionSize; | ||
2191 | nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30); | ||
2192 | m_notFoundLocations.Add(nfl); | ||
2193 | } | ||
2194 | } | ||
2195 | |||
2196 | } | ||
2197 | // Test to see of this point is in any of the 'not found' areas. | ||
2198 | // Return 'true' if the point is found inside the 'not found' areas. | ||
2199 | public bool Contains(double pX, double pY) | ||
2200 | { | ||
2201 | bool ret = false; | ||
2202 | lock (m_notFoundLocations) | ||
2203 | ret = LockedContains(pX, pY); | ||
2204 | return ret; | ||
2205 | } | ||
2206 | private bool LockedContains(double pX, double pY) | ||
2207 | { | ||
2208 | bool ret = false; | ||
2209 | this.DoExpiration(); | ||
2210 | foreach (NotFoundLocation nfl in m_notFoundLocations) | ||
2211 | { | ||
2212 | if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY) | ||
2213 | { | ||
2214 | ret = true; | ||
2215 | break; | ||
2216 | } | ||
2217 | } | ||
2218 | return ret; | ||
2219 | } | ||
2220 | private void DoExpiration() | ||
2221 | { | ||
2222 | List<NotFoundLocation> m_toRemove = null; | ||
2223 | DateTime now = DateTime.Now; | ||
2224 | foreach (NotFoundLocation nfl in m_notFoundLocations) | ||
2225 | { | ||
2226 | if (nfl.expireTime < now) | ||
2227 | { | ||
2228 | if (m_toRemove == null) | ||
2229 | m_toRemove = new List<NotFoundLocation>(); | ||
2230 | m_toRemove.Add(nfl); | ||
2231 | } | ||
2232 | } | ||
2233 | if (m_toRemove != null) | ||
2234 | { | ||
2235 | foreach (NotFoundLocation nfl in m_toRemove) | ||
2236 | m_notFoundLocations.Remove(nfl); | ||
2237 | m_toRemove.Clear(); | ||
2238 | } | ||
2239 | } | ||
2240 | } | ||
2241 | #endregion // NotFoundLocationCache class | ||
2242 | private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache(); | ||
2243 | |||
2244 | // Given a world position (fractional meter coordinate), get the GridRegion info for | ||
2245 | // the region containing that point. | ||
2246 | // Someday this should be a method on GridService. | ||
2247 | // 'pSizeHint' is the size of the source region but since the destination point can be anywhere | ||
2248 | // the size of the target region is unknown thus the search area might have to be very large. | ||
2249 | // Return 'null' if no such region exists. | ||
2250 | public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, | ||
2251 | double px, double py, uint pSizeHint) | ||
2252 | { | ||
2253 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py); | ||
2254 | GridRegion ret = null; | ||
2255 | const double fudge = 2.0; | ||
2256 | |||
2257 | // One problem with this routine is negative results. That is, this can be called lots of times | ||
2258 | // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they | ||
2259 | // will be quick 'not found's next time. | ||
2260 | // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and | ||
2261 | // thus re-ask the GridService about the location. | ||
2262 | if (m_notFoundLocationCache.Contains(px, py)) | ||
2263 | { | ||
2264 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py); | ||
2265 | return null; | ||
2266 | } | ||
2267 | |||
2268 | // As an optimization, since most regions will be legacy sized regions (256x256), first try to get | ||
2269 | // the region at the appropriate legacy region location. | ||
2270 | uint possibleX = (uint)Math.Floor(px); | ||
2271 | possibleX -= possibleX % Constants.RegionSize; | ||
2272 | uint possibleY = (uint)Math.Floor(py); | ||
2273 | possibleY -= possibleY % Constants.RegionSize; | ||
2274 | ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY); | ||
2275 | if (ret != null) | ||
2276 | { | ||
2277 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}", | ||
2278 | LogHeader, possibleX, possibleY, ret.RegionName); | ||
2279 | } | ||
2280 | |||
2281 | if (ret == null) | ||
2282 | { | ||
2283 | // If the simple lookup failed, search the larger area for a region that contains this point | ||
2284 | double range = (double)pSizeHint + fudge; | ||
2285 | while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize)) | ||
2286 | { | ||
2287 | // Get from the grid service a list of regions that might contain this point. | ||
2288 | // The region origin will be in the zero direction so only subtract the range. | ||
2289 | List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID, | ||
2290 | (int)(px - range), (int)(px), | ||
2291 | (int)(py - range), (int)(py)); | ||
2292 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}", | ||
2293 | LogHeader, possibleRegions.Count, range); | ||
2294 | if (possibleRegions != null && possibleRegions.Count > 0) | ||
2295 | { | ||
2296 | // If we found some regions, check to see if the point is within | ||
2297 | foreach (GridRegion gr in possibleRegions) | ||
2298 | { | ||
2299 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>", | ||
2300 | LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY); | ||
2301 | if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX) | ||
2302 | && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY)) | ||
2303 | { | ||
2304 | // Found a region that contains the point | ||
2305 | ret = gr; | ||
2306 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName); | ||
2307 | break; | ||
2308 | } | ||
2309 | } | ||
2310 | } | ||
2311 | // Larger search area for next time around if not found | ||
2312 | range *= 2; | ||
2313 | } | ||
2314 | } | ||
2315 | |||
2316 | if (ret == null) | ||
2317 | { | ||
2318 | // remember this location was not found so we can quickly not find it next time | ||
2319 | m_notFoundLocationCache.Add(px, py); | ||
2320 | m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py); | ||
2321 | } | ||
2322 | |||
2323 | return ret; | ||
2228 | } | 2324 | } |
2229 | 2325 | ||
2230 | private void InformClientOfNeighbourCompleted(IAsyncResult iar) | 2326 | private void InformClientOfNeighbourCompleted(IAsyncResult iar) |
@@ -2310,22 +2406,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2310 | /// <param name='neCorner'></param> | 2406 | /// <param name='neCorner'></param> |
2311 | private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner) | 2407 | private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner) |
2312 | { | 2408 | { |
2313 | Border[] northBorders = Scene.NorthBorders.ToArray(); | ||
2314 | Border[] eastBorders = Scene.EastBorders.ToArray(); | ||
2315 | |||
2316 | Vector2 extent = Vector2.Zero; | 2409 | Vector2 extent = Vector2.Zero; |
2317 | for (int i = 0; i < eastBorders.Length; i++) | 2410 | |
2318 | { | 2411 | if (m_regionCombinerModule != null) |
2319 | extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X; | ||
2320 | } | ||
2321 | for (int i = 0; i < northBorders.Length; i++) | ||
2322 | { | 2412 | { |
2323 | extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y; | 2413 | Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID); |
2414 | extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X); | ||
2415 | extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y); | ||
2324 | } | 2416 | } |
2325 | 2417 | ||
2326 | // Loss of fraction on purpose | ||
2327 | extent.X = ((int)extent.X / (int)Constants.RegionSize); | ||
2328 | extent.Y = ((int)extent.Y / (int)Constants.RegionSize); | ||
2329 | 2418 | ||
2330 | swCorner.X = Scene.RegionInfo.RegionLocX - 1; | 2419 | swCorner.X = Scene.RegionInfo.RegionLocX - 1; |
2331 | swCorner.Y = Scene.RegionInfo.RegionLocY - 1; | 2420 | swCorner.Y = Scene.RegionInfo.RegionLocY - 1; |
@@ -2340,56 +2429,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2340 | /// <param name="pRegionLocX"></param> | 2429 | /// <param name="pRegionLocX"></param> |
2341 | /// <param name="pRegionLocY"></param> | 2430 | /// <param name="pRegionLocY"></param> |
2342 | /// <returns></returns> | 2431 | /// <returns></returns> |
2343 | protected List<GridRegion> RequestNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) | 2432 | protected List<GridRegion> GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) |
2344 | { | 2433 | { |
2345 | Scene pScene = avatar.Scene; | 2434 | Scene pScene = avatar.Scene; |
2346 | RegionInfo m_regionInfo = pScene.RegionInfo; | 2435 | RegionInfo m_regionInfo = pScene.RegionInfo; |
2436 | List<GridRegion> neighbours; | ||
2347 | 2437 | ||
2348 | // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't | 2438 | // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't |
2349 | // clear what should be done with a "far view" given that megaregions already extended the | 2439 | // clear what should be done with a "far view" given that megaregions already extended the |
2350 | // view to include everything in the megaregion | 2440 | // view to include everything in the megaregion |
2351 | if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) | 2441 | if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) |
2352 | { | 2442 | { |
2353 | int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; | 2443 | // The area to check is as big as the current region. |
2444 | // We presume all adjacent regions are the same size as this region. | ||
2445 | uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance, | ||
2446 | Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY)); | ||
2354 | 2447 | ||
2355 | dd--; | 2448 | uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2; |
2449 | uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2; | ||
2356 | 2450 | ||
2357 | // region center | 2451 | uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2; |
2358 | int endX = (int)pRegionLocX * (int)Constants.RegionSize + (int)(Constants.RegionSize / 2); | 2452 | uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2; |
2359 | int endY = (int)pRegionLocY * (int)Constants.RegionSize + (int)(Constants.RegionSize / 2); | ||
2360 | |||
2361 | int startX = endX - dd; | ||
2362 | int startY = endY - dd; | ||
2363 | |||
2364 | endX += dd; | ||
2365 | endY += dd; | ||
2366 | 2453 | ||
2367 | if (startX < 0) startX = 0; | 2454 | neighbours |
2368 | if (startY < 0) startY = 0; | 2455 | = avatar.Scene.GridService.GetRegionRange( |
2456 | m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY); | ||
2369 | 2457 | ||
2370 | List<GridRegion> neighbours = | ||
2371 | avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); | ||
2372 | |||
2373 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); | ||
2374 | return neighbours; | ||
2375 | } | 2458 | } |
2376 | else | 2459 | else |
2377 | { | 2460 | { |
2378 | Vector2 swCorner, neCorner; | 2461 | Vector2 swCorner, neCorner; |
2379 | GetMegaregionViewRange(out swCorner, out neCorner); | 2462 | GetMegaregionViewRange(out swCorner, out neCorner); |
2380 | 2463 | ||
2381 | List<GridRegion> neighbours | 2464 | neighbours |
2382 | = pScene.GridService.GetRegionRange( | 2465 | = pScene.GridService.GetRegionRange( |
2383 | m_regionInfo.ScopeID, | 2466 | m_regionInfo.ScopeID, |
2384 | (int)swCorner.X * (int)Constants.RegionSize, | 2467 | (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X), |
2385 | (int)neCorner.X * (int)Constants.RegionSize, | 2468 | (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y)); |
2386 | (int)swCorner.Y * (int)Constants.RegionSize, | 2469 | } |
2387 | (int)neCorner.Y * (int)Constants.RegionSize); | ||
2388 | 2470 | ||
2389 | neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); | 2471 | // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1). |
2472 | neighbours.RemoveAll( r => r.RegionID == m_regionInfo.RegionID ); | ||
2390 | 2473 | ||
2391 | return neighbours; | 2474 | return neighbours; |
2392 | } | ||
2393 | } | 2475 | } |
2394 | /* not in use | 2476 | /* not in use |
2395 | private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) | 2477 | private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) |
@@ -2509,8 +2591,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2509 | /// | 2591 | /// |
2510 | /// This method locates the new region handle and offsets the prim position for the new region | 2592 | /// This method locates the new region handle and offsets the prim position for the new region |
2511 | /// </summary> | 2593 | /// </summary> |
2512 | /// <param name="attemptedPosition">the attempted out of region position of the scene object</param> | ||
2513 | /// <param name="grp">the scene object that we're crossing</param> | 2594 | /// <param name="grp">the scene object that we're crossing</param> |
2595 | /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is | ||
2596 | /// relative to the region the object currently is in.</param> | ||
2597 | /// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param> | ||
2514 | public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) | 2598 | public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent) |
2515 | { | 2599 | { |
2516 | if (grp == null) | 2600 | if (grp == null) |
@@ -2522,209 +2606,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
2522 | if (scene == null) | 2606 | if (scene == null) |
2523 | return; | 2607 | return; |
2524 | 2608 | ||
2609 | // Remember the old group position in case the region lookup fails so position can be restored. | ||
2610 | Vector3 oldGroupPosition = grp.RootPart.GroupPosition; | ||
2525 | 2611 | ||
2526 | int thisx = (int)scene.RegionInfo.RegionLocX; | 2612 | // Compute the absolute position of the object. |
2527 | int thisy = (int)scene.RegionInfo.RegionLocY; | 2613 | double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X; |
2528 | Vector3 EastCross = new Vector3(0.1f, 0, 0); | 2614 | double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y; |
2529 | Vector3 WestCross = new Vector3(-0.1f, 0, 0); | ||
2530 | Vector3 NorthCross = new Vector3(0, 0.1f, 0); | ||
2531 | Vector3 SouthCross = new Vector3(0, -0.1f, 0); | ||
2532 | |||
2533 | |||
2534 | // use this if no borders were crossed! | ||
2535 | ulong newRegionHandle | ||
2536 | = Util.UIntsToLong((uint)((thisx) * Constants.RegionSize), | ||
2537 | (uint)((thisy) * Constants.RegionSize)); | ||
2538 | |||
2539 | Vector3 pos = attemptedPosition; | ||
2540 | |||
2541 | int changeX = 1; | ||
2542 | int changeY = 1; | ||
2543 | |||
2544 | if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W)) | ||
2545 | { | ||
2546 | if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | ||
2547 | { | ||
2548 | |||
2549 | Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); | ||
2550 | |||
2551 | if (crossedBorderx.BorderLine.Z > 0) | ||
2552 | { | ||
2553 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
2554 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
2555 | } | ||
2556 | else | ||
2557 | pos.X = ((pos.X + Constants.RegionSize)); | ||
2558 | |||
2559 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | ||
2560 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
2561 | |||
2562 | if (crossedBordery.BorderLine.Z > 0) | ||
2563 | { | ||
2564 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
2565 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2566 | } | ||
2567 | else | ||
2568 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2569 | |||
2570 | |||
2571 | |||
2572 | newRegionHandle | ||
2573 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), | ||
2574 | (uint)((thisy - changeY) * Constants.RegionSize)); | ||
2575 | // x - 1 | ||
2576 | // y - 1 | ||
2577 | } | ||
2578 | else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | ||
2579 | { | ||
2580 | Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); | ||
2581 | |||
2582 | if (crossedBorderx.BorderLine.Z > 0) | ||
2583 | { | ||
2584 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | ||
2585 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
2586 | } | ||
2587 | else | ||
2588 | pos.X = ((pos.X + Constants.RegionSize)); | ||
2589 | |||
2590 | |||
2591 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | ||
2592 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
2593 | |||
2594 | if (crossedBordery.BorderLine.Z > 0) | ||
2595 | { | ||
2596 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
2597 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2598 | } | ||
2599 | else | ||
2600 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2601 | |||
2602 | newRegionHandle | ||
2603 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), | ||
2604 | (uint)((thisy + changeY) * Constants.RegionSize)); | ||
2605 | // x - 1 | ||
2606 | // y + 1 | ||
2607 | } | ||
2608 | else | ||
2609 | { | ||
2610 | Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W); | ||
2611 | 2615 | ||
2612 | if (crossedBorderx.BorderLine.Z > 0) | 2616 | // Ask the grid service for the region that contains the passed address |
2613 | { | 2617 | GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID, |
2614 | pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); | 2618 | objectWorldLocX, objectWorldLocY); |
2615 | changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize); | ||
2616 | } | ||
2617 | else | ||
2618 | pos.X = ((pos.X + Constants.RegionSize)); | ||
2619 | 2619 | ||
2620 | newRegionHandle | 2620 | Vector3 pos = Vector3.Zero; |
2621 | = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), | 2621 | if (destination != null) |
2622 | (uint)(thisy * Constants.RegionSize)); | ||
2623 | // x - 1 | ||
2624 | } | ||
2625 | } | ||
2626 | else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E)) | ||
2627 | { | 2622 | { |
2628 | if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | 2623 | // Adjust the object's relative position from the old region (attemptedPosition) |
2629 | { | 2624 | // to be relative to the new region (pos). |
2630 | 2625 | pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX), | |
2631 | pos.X = ((pos.X - Constants.RegionSize)); | 2626 | (float)(objectWorldLocY - (double)destination.RegionLocY), |
2632 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | 2627 | attemptedPosition.Z); |
2633 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
2634 | |||
2635 | if (crossedBordery.BorderLine.Z > 0) | ||
2636 | { | ||
2637 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
2638 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2639 | } | ||
2640 | else | ||
2641 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2642 | |||
2643 | |||
2644 | newRegionHandle | ||
2645 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), | ||
2646 | (uint)((thisy - changeY) * Constants.RegionSize)); | ||
2647 | // x + 1 | ||
2648 | // y - 1 | ||
2649 | } | ||
2650 | else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | ||
2651 | { | ||
2652 | pos.X = ((pos.X - Constants.RegionSize)); | ||
2653 | pos.Y = ((pos.Y - Constants.RegionSize)); | ||
2654 | newRegionHandle | ||
2655 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), | ||
2656 | (uint)((thisy + changeY) * Constants.RegionSize)); | ||
2657 | // x + 1 | ||
2658 | // y + 1 | ||
2659 | } | ||
2660 | else | ||
2661 | { | ||
2662 | pos.X = ((pos.X - Constants.RegionSize)); | ||
2663 | newRegionHandle | ||
2664 | = Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize), | ||
2665 | (uint)(thisy * Constants.RegionSize)); | ||
2666 | // x + 1 | ||
2667 | } | ||
2668 | } | 2628 | } |
2669 | else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) | ||
2670 | { | ||
2671 | Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); | ||
2672 | //(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize) | ||
2673 | 2629 | ||
2674 | if (crossedBordery.BorderLine.Z > 0) | 2630 | if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) |
2675 | { | ||
2676 | pos.Y = ((pos.Y + crossedBordery.BorderLine.Z)); | ||
2677 | changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize); | ||
2678 | } | ||
2679 | else | ||
2680 | pos.Y = ((pos.Y + Constants.RegionSize)); | ||
2681 | |||
2682 | newRegionHandle | ||
2683 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize)); | ||
2684 | // y - 1 | ||
2685 | } | ||
2686 | else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N)) | ||
2687 | { | 2631 | { |
2632 | m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID); | ||
2688 | 2633 | ||
2689 | pos.Y = ((pos.Y - Constants.RegionSize)); | 2634 | // We are going to move the object back to the old position so long as the old position |
2690 | newRegionHandle | 2635 | // is in the region |
2691 | = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); | 2636 | oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1)); |
2692 | // y + 1 | 2637 | oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1)); |
2693 | } | 2638 | oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight); |
2694 | 2639 | ||
2695 | // Offset the positions for the new region across the border | 2640 | grp.AbsolutePosition = oldGroupPosition; |
2696 | Vector3 oldGroupPosition = grp.RootPart.GroupPosition; | 2641 | grp.Velocity = Vector3.Zero; |
2642 | if (grp.RootPart.PhysActor != null) | ||
2643 | grp.RootPart.PhysActor.CrossingFailure(); | ||
2697 | 2644 | ||
2698 | // If we fail to cross the border, then reset the position of the scene object on that border. | 2645 | if (grp.RootPart.KeyframeMotion != null) |
2699 | uint x = 0, y = 0; | 2646 | grp.RootPart.KeyframeMotion.CrossingFailure(); |
2700 | Utils.LongToUInts(newRegionHandle, out x, out y); | ||
2701 | GridRegion destination = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y); | ||
2702 | 2647 | ||
2703 | if (destination != null) | 2648 | grp.ScheduleGroupForFullUpdate(); |
2704 | { | ||
2705 | if (CrossPrimGroupIntoNewRegion(destination, pos, grp, silent)) | ||
2706 | return; // we did it | ||
2707 | } | 2649 | } |
2708 | |||
2709 | // no one or failed lets go back and tell physics to go on | ||
2710 | oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 0.5f, (float)Constants.RegionSize - 0.5f); | ||
2711 | oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 0.5f, (float)Constants.RegionSize - 0.5f); | ||
2712 | // oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 0.5f, 4096.0f); | ||
2713 | |||
2714 | grp.AbsolutePosition = oldGroupPosition; | ||
2715 | grp.Velocity = Vector3.Zero; | ||
2716 | |||
2717 | if (grp.RootPart.PhysActor != null) | ||
2718 | grp.RootPart.PhysActor.CrossingFailure(); | ||
2719 | |||
2720 | if (grp.RootPart.KeyframeMotion != null) | ||
2721 | grp.RootPart.KeyframeMotion.CrossingFailure(); | ||
2722 | |||
2723 | grp.ScheduleGroupForFullUpdate(); | ||
2724 | } | 2650 | } |
2725 | 2651 | ||
2726 | |||
2727 | |||
2728 | /// <summary> | 2652 | /// <summary> |
2729 | /// Move the given scene object into a new region | 2653 | /// Move the given scene object into a new region |
2730 | /// </summary> | 2654 | /// </summary> |