aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules
diff options
context:
space:
mode:
authorUbitUmarov2015-08-19 08:48:50 +0100
committerUbitUmarov2015-08-19 08:48:50 +0100
commit0b105da626ae8c2fb519a817b827f90534ed7d08 (patch)
tree509e6d091fb12f38fd09528335e51aeedbe59c08 /OpenSim/Region/CoreModules
parentMerge branch 'master' into ubitworkmaster (diff)
parentvarregion: update MapImageServiceModule to upload multiple map tiles for larg... (diff)
downloadopensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.zip
opensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.tar.gz
opensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.tar.bz2
opensim-SC_OLD-0b105da626ae8c2fb519a817b827f90534ed7d08.tar.xz
Merge branch 'mbworkvar2' into ubitvar
Diffstat (limited to 'OpenSim/Region/CoreModules')
-rw-r--r--OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs6
-rw-r--r--OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs833
-rw-r--r--OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs9
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs82
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs63
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandObject.cs176
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs36
-rw-r--r--OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs11
-rw-r--r--OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs8
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs35
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs4
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs2
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs488
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs32
24 files changed, 1093 insertions, 762 deletions
diff --git a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
index dcfc630..9d70063 100644
--- a/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/Chat/ChatModule.cs
@@ -213,8 +213,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
213 IScene scene = c.Scene; 213 IScene scene = c.Scene;
214 UUID destination = c.Destination; 214 UUID destination = c.Destination;
215 Vector3 fromPos = c.Position; 215 Vector3 fromPos = c.Position;
216 Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, 216 Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0);
217 scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
218 217
219 bool checkParcelHide = false; 218 bool checkParcelHide = false;
220 UUID sourceParcelID = UUID.Zero; 219 UUID sourceParcelID = UUID.Zero;
@@ -424,8 +423,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
424 { 423 {
425 Vector3 fromRegionPos = fromPos + regionPos; 424 Vector3 fromRegionPos = fromPos + regionPos;
426 Vector3 toRegionPos = presence.AbsolutePosition + 425 Vector3 toRegionPos = presence.AbsolutePosition +
427 new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, 426 new Vector3(presence.Scene.RegionInfo.WorldLocX, presence.Scene.RegionInfo.WorldLocY, 0);
428 presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
429 427
430 int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos); 428 int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
431 429
diff --git a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
index db8405b..7177d9b 100644
--- a/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
+++ b/OpenSim/Region/CoreModules/Avatar/UserProfiles/UserProfileModule.cs
@@ -663,8 +663,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
663 663
664 Vector3 avaPos = p.AbsolutePosition; 664 Vector3 avaPos = p.AbsolutePosition;
665 // Getting the global position for the Avatar 665 // Getting the global position for the Avatar
666 Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X, 666 Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.WorldLocX + avaPos.X,
667 remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y, 667 remoteClient.Scene.RegionInfo.WorldLocY + avaPos.Y,
668 avaPos.Z); 668 avaPos.Z);
669 669
670 string landOwnerName = string.Empty; 670 string landOwnerName = string.Empty;
@@ -1353,4 +1353,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
1353 } 1353 }
1354 #endregion Web Util 1354 #endregion Web Util
1355 } 1355 }
1356} \ No newline at end of file 1356}
diff --git a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
index 6e0fd03..f615c6b 100644
--- a/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/Caps/CapabilitiesModule.cs
@@ -317,9 +317,7 @@ namespace OpenSim.Region.CoreModules.Framework
317 foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID]) 317 foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID])
318 { 318 {
319 uint x, y; 319 uint x, y;
320 Utils.LongToUInts(kvp.Key, out x, out y); 320 Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
321 x = x / Constants.RegionSize;
322 y = y / Constants.RegionSize;
323 m_log.Info(" >> "+x+", "+y+": "+kvp.Value); 321 m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
324 } 322 }
325 } 323 }
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index b32a169..c81e5aa 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -121,8 +121,57 @@ 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 this.Add(pRegionHandle, pAgentID, 45, 15);
155 }
156 public void Add(ulong pRegionHandle, UUID pAgentID, double newTime, double extendTime)
157 {
158 if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
159 {
160 m_idCache = new ExpiringCache<ulong, DateTime>();
161 m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(newTime));
162 }
163 m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(extendTime), TimeSpan.FromSeconds(extendTime));
164 }
165 // Remove the agent from the region's banned list
166 public void Remove(ulong pRegionHandle, UUID pAgentID)
167 {
168 if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
169 {
170 m_idCache.Remove(pRegionHandle);
171 }
172 }
173 }
174 private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
126 175
127 private IEventQueue m_eqModule; 176 private IEventQueue m_eqModule;
128 private IRegionCombinerModule m_regionCombinerModule; 177 private IRegionCombinerModule m_regionCombinerModule;
@@ -337,6 +386,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
337 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name); 386 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
338 } 387 }
339 388
389 // 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) 390 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
341 { 391 {
342 if (sp.Scene.Permissions.IsGridGod(sp.UUID)) 392 if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@@ -418,7 +468,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
418 sp.Name, position, sp.Scene.RegionInfo.RegionName); 468 sp.Name, position, sp.Scene.RegionInfo.RegionName);
419 469
420 // Teleport within the same region 470 // Teleport within the same region
421 if (IsOutsideRegion(sp.Scene, position) || position.Z < 0) 471 if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0)
422 { 472 {
423 Vector3 emergencyPos = new Vector3(128, 128, 128); 473 Vector3 emergencyPos = new Vector3(128, 128, 128);
424 474
@@ -437,10 +487,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
437 float posZLimit = 22; 487 float posZLimit = 22;
438 488
439 // TODO: Check other Scene HeightField 489 // TODO: Check other Scene HeightField
440 if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize) 490 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 491
445 posZLimit += localHalfAVHeight + 0.1f; 492 posZLimit += localHalfAVHeight + 0.1f;
446 493
@@ -484,9 +531,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
484 ScenePresence sp, ulong regionHandle, Vector3 position, 531 ScenePresence sp, ulong regionHandle, Vector3 position,
485 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination) 532 Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination)
486 { 533 {
487 uint x = 0, y = 0; 534 // Get destination region taking into account that the address could be an offset
488 Utils.LongToUInts(regionHandle, out x, out y); 535 // region inside a varregion.
489 GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y); 536 GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position);
490 537
491 if (reg != null) 538 if (reg != null)
492 { 539 {
@@ -537,12 +584,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
537 584
538 // and set the map-tile to '(Offline)' 585 // and set the map-tile to '(Offline)'
539 uint regX, regY; 586 uint regX, regY;
540 Utils.LongToUInts(regionHandle, out regX, out regY); 587 Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY);
541 588
542 MapBlockData block = new MapBlockData(); 589 MapBlockData block = new MapBlockData();
543 block.X = (ushort)(regX / Constants.RegionSize); 590 block.X = (ushort)(regX);
544 block.Y = (ushort)(regY / Constants.RegionSize); 591 block.Y = (ushort)(regY);
545 block.Access = 254; // == not there 592 block.Access = (byte)SimAccess.Down; // == not there
546 593
547 List<MapBlockData> blocks = new List<MapBlockData>(); 594 List<MapBlockData> blocks = new List<MapBlockData>();
548 blocks.Add(block); 595 blocks.Add(block);
@@ -550,6 +597,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
550 } 597 }
551 } 598 }
552 599
600 // The teleport address could be an address in a subregion of a larger varregion.
601 // Find the real base region and adjust the teleport location to account for the
602 // larger region.
603 private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position)
604 {
605 uint x = 0, y = 0;
606 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
607
608 // Compute the world location we're teleporting to
609 double worldX = (double)x + position.X;
610 double worldY = (double)y + position.Y;
611
612 // Find the region that contains the position
613 GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY);
614
615 if (reg != null)
616 {
617 // modify the position for the offset into the actual region returned
618 position.X += x - reg.RegionLocX;
619 position.Y += y - reg.RegionLocY;
620 }
621
622 return reg;
623 }
624
553 // Nothing to validate here 625 // Nothing to validate here
554 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason) 626 protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
555 { 627 {
@@ -650,10 +722,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
650 return; 722 return;
651 } 723 }
652 724
653 uint newRegionX = (uint)(reg.RegionHandle >> 40); 725 uint newRegionX, newRegionY, oldRegionX, oldRegionY;
654 uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); 726 Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY);
655 uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40); 727 Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY);
656 uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8);
657 728
658 ulong destinationHandle = finalDestination.RegionHandle; 729 ulong destinationHandle = finalDestination.RegionHandle;
659 730
@@ -675,8 +746,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
675 746
676 string reason; 747 string reason;
677 string version; 748 string version;
749 string myversion = string.Format("{0}/{1}", OutgoingTransferVersionName, MaxOutgoingTransferVersion);
678 if (!Scene.SimulationService.QueryAccess( 750 if (!Scene.SimulationService.QueryAccess(
679 finalDestination, sp.ControllingClient.AgentId, Vector3.Zero, out version, out reason)) 751 finalDestination, sp.ControllingClient.AgentId, position, out version, out reason))
680 { 752 {
681 sp.ControllingClient.SendTeleportFailed(reason); 753 sp.ControllingClient.SendTeleportFailed(reason);
682 754
@@ -1274,6 +1346,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1274 return region; 1346 return region;
1275 } 1347 }
1276 1348
1349 // This returns 'true' if the new region already has a child agent for our
1350 // incoming agent. The implication is that, if 'false', we have to create the
1351 // child and then teleport into the region.
1277 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY) 1352 protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
1278 { 1353 {
1279 if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) 1354 if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
@@ -1298,20 +1373,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1298 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY); 1373 return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
1299 } 1374 }
1300 1375
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 1376 #endregion
1316 1377
1317 #region Landmark Teleport 1378 #region Landmark Teleport
@@ -1398,42 +1459,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1398 UUID agentID = agent.UUID; 1459 UUID agentID = agent.UUID;
1399 ulong destinyHandle = destiny.RegionHandle; 1460 ulong destinyHandle = destiny.RegionHandle;
1400 1461
1401 ExpiringCache<ulong, DateTime> r; 1462 if (m_bannedRegionCache.IfBanned(destinyHandle, agentID))
1402 DateTime banUntil;
1403 if (m_bannedRegions.TryGetValue(agentID, out r))
1404 { 1463 {
1405 if (r.TryGetValue(destinyHandle, out banUntil)) 1464 reason = "Cannot connect to region";
1406 { 1465 return false;
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 } 1466 }
1419 1467
1420 Scene ascene = agent.Scene; 1468 Scene ascene = agent.Scene;
1421 1469
1422 if (!ascene.SimulationService.QueryAccess(destiny, agentID, position, out version, out reason)) 1470 if (!ascene.SimulationService.QueryAccess(destiny, agentID, position, out version, out reason))
1423 { 1471 {
1424 if (r == null) 1472 m_bannedRegionCache.Add(destinyHandle, agentID, 30.0, 30.0);
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; 1473 return false;
1436 } 1474 }
1475
1437 return true; 1476 return true;
1438 } 1477 }
1439 1478
@@ -1443,161 +1482,74 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1443 return GetDestination(scene, agentID, pos, out version, out newpos, out r); 1482 return GetDestination(scene, agentID, pos, out version, out newpos, out r);
1444 } 1483 }
1445 1484
1446 public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version, out Vector3 newpos, out string reason) 1485 // Given a position relative to the current region (which has previously been tested to
1486 // see that it is actually outside the current region), find the new region that the
1487 // point is actually in.
1488 // Returns the coordinates and information of the new region or 'null' of it doesn't exist.
1489 public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos,
1490 out string version, out Vector3 newpos, out string failureReason)
1447 { 1491 {
1448 version = String.Empty; 1492 version = String.Empty;
1449 reason = String.Empty;
1450 newpos = pos; 1493 newpos = pos;
1494 failureReason = string.Empty;
1451 1495
1452// m_log.DebugFormat( 1496// m_log.DebugFormat(
1453// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name); 1497// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
1454 1498
1455 RegionInfo regInfo = scene.RegionInfo; 1499 // Compute world location of the object's position
1456 1500 double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X;
1457 uint neighbourx = regInfo.RegionLocX; 1501 double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y;
1458 uint neighboury = regInfo.RegionLocY;
1459 const float boundaryDistance = 0.7f;
1460 1502
1461/* 1503 // Call the grid service to lookup the region containing the new position.
1462 Vector3 northCross = new Vector3(0, boundaryDistance, 0); 1504 GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
1463 Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0); 1505 presenceWorldX, presenceWorldY,
1464 Vector3 eastCross = new Vector3(boundaryDistance, 0, 0); 1506 Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
1465 Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0);
1466
1467 // distance into new region to place avatar
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 {
1474 if (scene.TestBorderCross(pos + northCross, Cardinals.N))
1475 {
1476 Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
1477 neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
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 1507
1486 neighbourx--; 1508 if (neighbourRegion != null)
1487 newpos.X += Constants.RegionSize;
1488 }
1489 else if (scene.TestBorderCross(pos + eastCross, Cardinals.E))
1490 { 1509 {
1491 Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E); 1510 // Compute the entity's position relative to the new region
1492 neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize); 1511 newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX),
1493 newpos.X -= Constants.RegionSize; 1512 (float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
1513 pos.Z);
1494 1514
1495 if (scene.TestBorderCross(pos + southCross, Cardinals.S)) 1515 if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
1496 { 1516 {
1497 neighboury--; 1517 failureReason = "Cannot region cross into banned parcel";
1498 newpos.Y += Constants.RegionSize; 1518 neighbourRegion = null;
1499 } 1519 }
1500 else if (scene.TestBorderCross(pos + northCross, Cardinals.N)) 1520 else
1501 { 1521 {
1502 Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N); 1522 // If not banned, make sure this agent is not in the list.
1503 neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize); 1523 m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
1504 newpos.Y -= Constants.RegionSize;
1505 } 1524 }
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
1520 newpos.X = Util.Clamp(newpos.X, enterDistance, maxX);
1521 newpos.Y = Util.Clamp(newpos.Y, enterDistance, maxY);
1522*/
1523 float regionSizeX = regInfo.RegionSizeX;
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 1525
1531 if (pos.Y < boundaryDistance) 1526 // Check to see if we have access to the target region.
1532 neighboury--; 1527 string myversion = string.Format("{0}/{1}", OutgoingTransferVersionName, MaxOutgoingTransferVersion);
1533 else if (pos.Y > regionSizeY - boundaryDistance) 1528 if (neighbourRegion != null
1534 neighboury += (uint)(regionSizeY / Constants.RegionSize); 1529 && !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out failureReason))
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 { 1530 {
1548 if (DateTime.Now < banUntil) 1531 // remember banned
1549 return null; 1532 m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
1550 r.Remove(neighbourHandle); 1533 neighbourRegion = null;
1551 } 1534 }
1552 } 1535 }
1553 else 1536 else
1554 { 1537 {
1555 r = null; 1538 // The destination region just doesn't exist
1539 failureReason = "Cannot cross into non-existent region";
1556 } 1540 }
1557 1541
1558 GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
1559 if (neighbourRegion == null) 1542 if (neighbourRegion == null)
1560 { 1543 m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}",
1561 reason = ""; 1544 LogHeader, scene.RegionInfo.RegionName,
1562 return null; 1545 scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
1563 } 1546 scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY,
1564 1547 pos);
1565 float newRegionSizeX = neighbourRegion.RegionSizeX; 1548 else
1566 float newRegionSizeY = neighbourRegion.RegionSizeY; 1549 m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>",
1567 if (newRegionSizeX == 0) 1550 LogHeader, neighbourRegion.RegionName,
1568 newRegionSizeX = Constants.RegionSize; 1551 neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY,
1569 if (newRegionSizeY == 0) 1552 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 1553
1602 return neighbourRegion; 1554 return neighbourRegion;
1603 } 1555 }
@@ -1632,15 +1584,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1632 uint y; 1584 uint y;
1633 Vector3 newpos; 1585 Vector3 newpos;
1634 string version; 1586 string version;
1635 string reason; 1587 string failureReason;
1636 1588
1637 Vector3 pos = agent.AbsolutePosition + agent.Velocity; 1589 Vector3 pos = agent.AbsolutePosition + agent.Velocity;
1638 1590
1639 GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos, out version, out newpos, out reason); 1591 GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, pos,
1592 out version, out newpos, out failureReason);
1640 if (neighbourRegion == null) 1593 if (neighbourRegion == null)
1641 { 1594 {
1642 if (reason != String.Empty) 1595 if (failureReason != String.Empty)
1643 agent.ControllingClient.SendAlertMessage("Cannot cross to region"); 1596 agent.ControllingClient.SendAlertMessage(failureReason);
1644 return agent; 1597 return agent;
1645 } 1598 }
1646 1599
@@ -1678,7 +1631,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1678 1631
1679 agent.Scene.RequestTeleportLocation( 1632 agent.Scene.RequestTeleportLocation(
1680 agent.ControllingClient, 1633 agent.ControllingClient,
1681 Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize), 1634 Util.RegionLocToHandle(regionX, regionY),
1682 position, 1635 position,
1683 agent.Lookat, 1636 agent.Lookat,
1684 (uint)Constants.TeleportFlags.ViaLocation); 1637 (uint)Constants.TeleportFlags.ViaLocation);
@@ -1688,11 +1641,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1688 if (im != null) 1641 if (im != null)
1689 { 1642 {
1690 UUID gotoLocation = Util.BuildFakeParcelID( 1643 UUID gotoLocation = Util.BuildFakeParcelID(
1691 Util.UIntsToLong( 1644 Util.RegionLocToHandle(regionX, regionY),
1692 (regionX *
1693 (uint)Constants.RegionSize),
1694 (regionY *
1695 (uint)Constants.RegionSize)),
1696 (uint)(int)position.X, 1645 (uint)(int)position.X,
1697 (uint)(int)position.Y, 1646 (uint)(int)position.Y,
1698 (uint)(int)position.Z); 1647 (uint)(int)position.Z);
@@ -1745,8 +1694,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1745 /// Calls an asynchronous method to do so.. so it doesn't lag the sim. 1694 /// Calls an asynchronous method to do so.. so it doesn't lag the sim.
1746 /// </summary> 1695 /// </summary>
1747 public ScenePresence CrossAgentToNewRegionAsync( 1696 public ScenePresence CrossAgentToNewRegionAsync(
1748 ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, 1697 ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
1749 bool isFlying, string version) 1698 bool isFlying, string version)
1750 { 1699 {
1751 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion)) 1700 if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
1752 { 1701 {
@@ -1893,11 +1842,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
1893 // Next, let's close the child agent connections that are too far away. 1842 // Next, let's close the child agent connections that are too far away.
1894 uint neighbourx; 1843 uint neighbourx;
1895 uint neighboury; 1844 uint neighboury;
1896 1845 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 1846
1902 agent.CloseChildAgents(neighbourx, neighboury); 1847 agent.CloseChildAgents(neighbourx, neighboury);
1903 1848
@@ -2059,7 +2004,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2059 2004
2060 if (m_regionInfo != null) 2005 if (m_regionInfo != null)
2061 { 2006 {
2062 neighbours = RequestNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY); 2007 neighbours = GetNeighbours(sp, m_regionInfo.RegionLocX, m_regionInfo.RegionLocY);
2063 } 2008 }
2064 else 2009 else
2065 { 2010 {
@@ -2216,15 +2161,195 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2216 } 2161 }
2217 } 2162 }
2218 2163
2164 // Computes the difference between two region bases.
2165 // Returns a vector of world coordinates (meters) from base of first region to the second.
2166 // The first region is the home region of the passed scene presence.
2219 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour) 2167 Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour)
2220 { 2168 {
2221 int rRegionX = (int)sp.Scene.RegionInfo.RegionLocX; 2169 /*
2222 int rRegionY = (int)sp.Scene.RegionInfo.RegionLocY; 2170 int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX;
2171 int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY;
2223 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize; 2172 int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize;
2224 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize; 2173 int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize;
2225 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize; 2174 int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize;
2226 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize; 2175 int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize;
2227 return new Vector3(shiftx, shifty, 0f); 2176 return new Vector3(shiftx, shifty, 0f);
2177 */
2178 return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX,
2179 sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY,
2180 0f);
2181 }
2182
2183 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
2184 {
2185 // Since we don't know how big the regions could be, we have to search a very large area
2186 // to find possible regions.
2187 return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
2188 }
2189
2190 #region NotFoundLocationCache class
2191 // A collection of not found locations to make future lookups 'not found' lookups quick.
2192 // A simple expiring cache that keeps not found locations for some number of seconds.
2193 // A 'not found' location is presumed to be anywhere in the minimum sized region that
2194 // contains that point. A conservitive estimate.
2195 private class NotFoundLocationCache
2196 {
2197 private struct NotFoundLocation
2198 {
2199 public double minX, maxX, minY, maxY;
2200 public DateTime expireTime;
2201 }
2202 private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
2203 public NotFoundLocationCache()
2204 {
2205 }
2206 // Add an area to the list of 'not found' places. The area is the snapped region
2207 // area around the added point.
2208 public void Add(double pX, double pY)
2209 {
2210 lock (m_notFoundLocations)
2211 {
2212 if (!LockedContains(pX, pY))
2213 {
2214 NotFoundLocation nfl = new NotFoundLocation();
2215 // A not found location is not found for at least a whole region sized area
2216 nfl.minX = pX - (pX % (double)Constants.RegionSize);
2217 nfl.minY = pY - (pY % (double)Constants.RegionSize);
2218 nfl.maxX = nfl.minX + (double)Constants.RegionSize;
2219 nfl.maxY = nfl.minY + (double)Constants.RegionSize;
2220 nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
2221 m_notFoundLocations.Add(nfl);
2222 }
2223 }
2224
2225 }
2226 // Test to see of this point is in any of the 'not found' areas.
2227 // Return 'true' if the point is found inside the 'not found' areas.
2228 public bool Contains(double pX, double pY)
2229 {
2230 bool ret = false;
2231 lock (m_notFoundLocations)
2232 ret = LockedContains(pX, pY);
2233 return ret;
2234 }
2235 private bool LockedContains(double pX, double pY)
2236 {
2237 bool ret = false;
2238 this.DoExpiration();
2239 foreach (NotFoundLocation nfl in m_notFoundLocations)
2240 {
2241 if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
2242 {
2243 ret = true;
2244 break;
2245 }
2246 }
2247 return ret;
2248 }
2249 private void DoExpiration()
2250 {
2251 List<NotFoundLocation> m_toRemove = null;
2252 DateTime now = DateTime.Now;
2253 foreach (NotFoundLocation nfl in m_notFoundLocations)
2254 {
2255 if (nfl.expireTime < now)
2256 {
2257 if (m_toRemove == null)
2258 m_toRemove = new List<NotFoundLocation>();
2259 m_toRemove.Add(nfl);
2260 }
2261 }
2262 if (m_toRemove != null)
2263 {
2264 foreach (NotFoundLocation nfl in m_toRemove)
2265 m_notFoundLocations.Remove(nfl);
2266 m_toRemove.Clear();
2267 }
2268 }
2269 }
2270 #endregion // NotFoundLocationCache class
2271 private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
2272
2273 // Given a world position (fractional meter coordinate), get the GridRegion info for
2274 // the region containing that point.
2275 // Someday this should be a method on GridService.
2276 // 'pSizeHint' is the size of the source region but since the destination point can be anywhere
2277 // the size of the target region is unknown thus the search area might have to be very large.
2278 // Return 'null' if no such region exists.
2279 public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
2280 double px, double py, uint pSizeHint)
2281 {
2282 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py);
2283 GridRegion ret = null;
2284 const double fudge = 2.0;
2285
2286 // One problem with this routine is negative results. That is, this can be called lots of times
2287 // for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
2288 // will be quick 'not found's next time.
2289 // NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
2290 // thus re-ask the GridService about the location.
2291 if (m_notFoundLocationCache.Contains(px, py))
2292 {
2293 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
2294 return null;
2295 }
2296
2297 // As an optimization, since most regions will be legacy sized regions (256x256), first try to get
2298 // the region at the appropriate legacy region location.
2299 uint possibleX = (uint)Math.Floor(px);
2300 possibleX -= possibleX % Constants.RegionSize;
2301 uint possibleY = (uint)Math.Floor(py);
2302 possibleY -= possibleY % Constants.RegionSize;
2303 ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY);
2304 if (ret != null)
2305 {
2306 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}",
2307 LogHeader, possibleX, possibleY, ret.RegionName);
2308 }
2309
2310 if (ret == null)
2311 {
2312 // If the simple lookup failed, search the larger area for a region that contains this point
2313 double range = (double)pSizeHint + fudge;
2314 while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
2315 {
2316 // Get from the grid service a list of regions that might contain this point.
2317 // The region origin will be in the zero direction so only subtract the range.
2318 List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
2319 (int)(px - range), (int)(px),
2320 (int)(py - range), (int)(py));
2321 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
2322 LogHeader, possibleRegions.Count, range);
2323 if (possibleRegions != null && possibleRegions.Count > 0)
2324 {
2325 // If we found some regions, check to see if the point is within
2326 foreach (GridRegion gr in possibleRegions)
2327 {
2328 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>",
2329 LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY);
2330 if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX)
2331 && py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY))
2332 {
2333 // Found a region that contains the point
2334 ret = gr;
2335 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName);
2336 break;
2337 }
2338 }
2339 }
2340 // Larger search area for next time around if not found
2341 range *= 2;
2342 }
2343 }
2344
2345 if (ret == null)
2346 {
2347 // remember this location was not found so we can quickly not find it next time
2348 m_notFoundLocationCache.Add(px, py);
2349 m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
2350 }
2351
2352 return ret;
2228 } 2353 }
2229 2354
2230 private void InformClientOfNeighbourCompleted(IAsyncResult iar) 2355 private void InformClientOfNeighbourCompleted(IAsyncResult iar)
@@ -2310,22 +2435,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2310 /// <param name='neCorner'></param> 2435 /// <param name='neCorner'></param>
2311 private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner) 2436 private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
2312 { 2437 {
2313 Border[] northBorders = Scene.NorthBorders.ToArray();
2314 Border[] eastBorders = Scene.EastBorders.ToArray();
2315
2316 Vector2 extent = Vector2.Zero; 2438 Vector2 extent = Vector2.Zero;
2317 for (int i = 0; i < eastBorders.Length; i++) 2439
2318 { 2440 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 { 2441 {
2323 extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y; 2442 Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID);
2443 extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X);
2444 extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y);
2324 } 2445 }
2325 2446
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 2447
2330 swCorner.X = Scene.RegionInfo.RegionLocX - 1; 2448 swCorner.X = Scene.RegionInfo.RegionLocX - 1;
2331 swCorner.Y = Scene.RegionInfo.RegionLocY - 1; 2449 swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
@@ -2340,56 +2458,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2340 /// <param name="pRegionLocX"></param> 2458 /// <param name="pRegionLocX"></param>
2341 /// <param name="pRegionLocY"></param> 2459 /// <param name="pRegionLocY"></param>
2342 /// <returns></returns> 2460 /// <returns></returns>
2343 protected List<GridRegion> RequestNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY) 2461 protected List<GridRegion> GetNeighbours(ScenePresence avatar, uint pRegionLocX, uint pRegionLocY)
2344 { 2462 {
2345 Scene pScene = avatar.Scene; 2463 Scene pScene = avatar.Scene;
2346 RegionInfo m_regionInfo = pScene.RegionInfo; 2464 RegionInfo m_regionInfo = pScene.RegionInfo;
2465 List<GridRegion> neighbours;
2347 2466
2348 // Leaving this as a "megaregions" computation vs "non-megaregions" computation; it isn't 2467 // 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 2468 // clear what should be done with a "far view" given that megaregions already extended the
2350 // view to include everything in the megaregion 2469 // view to include everything in the megaregion
2351 if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID)) 2470 if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
2352 { 2471 {
2353 int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance; 2472 // The area to check is as big as the current region.
2354 2473 // We presume all adjacent regions are the same size as this region.
2355 dd--; 2474 uint dd = Math.Max((uint)avatar.Scene.DefaultDrawDistance,
2356 2475 Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
2357 // region center
2358 int endX = (int)pRegionLocX * (int)Constants.RegionSize + (int)(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 2476
2364 endX += dd; 2477 uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2;
2365 endY += dd; 2478 uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2;
2366 2479
2367 if (startX < 0) startX = 0; 2480 uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2;
2368 if (startY < 0) startY = 0; 2481 uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2;
2369 2482
2370 List<GridRegion> neighbours = 2483 neighbours
2371 avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY); 2484 = avatar.Scene.GridService.GetRegionRange(
2485 m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY);
2372 2486
2373 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; });
2374 return neighbours;
2375 } 2487 }
2376 else 2488 else
2377 { 2489 {
2378 Vector2 swCorner, neCorner; 2490 Vector2 swCorner, neCorner;
2379 GetMegaregionViewRange(out swCorner, out neCorner); 2491 GetMegaregionViewRange(out swCorner, out neCorner);
2380 2492
2381 List<GridRegion> neighbours 2493 neighbours
2382 = pScene.GridService.GetRegionRange( 2494 = pScene.GridService.GetRegionRange(
2383 m_regionInfo.ScopeID, 2495 m_regionInfo.ScopeID,
2384 (int)swCorner.X * (int)Constants.RegionSize, 2496 (int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X),
2385 (int)neCorner.X * (int)Constants.RegionSize, 2497 (int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y));
2386 (int)swCorner.Y * (int)Constants.RegionSize, 2498 }
2387 (int)neCorner.Y * (int)Constants.RegionSize);
2388 2499
2389 neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; }); 2500 // The r.RegionFlags == null check only needs to be made for simulators before 2015-01-14 (pre 0.8.1).
2501 neighbours.RemoveAll( r => r.RegionID == m_regionInfo.RegionID );
2390 2502
2391 return neighbours; 2503 return neighbours;
2392 }
2393 } 2504 }
2394/* not in use 2505/* not in use
2395 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours) 2506 private List<ulong> NewNeighbours(List<ulong> currentNeighbours, List<ulong> previousNeighbours)
@@ -2509,8 +2620,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2509 /// 2620 ///
2510 /// This method locates the new region handle and offsets the prim position for the new region 2621 /// This method locates the new region handle and offsets the prim position for the new region
2511 /// </summary> 2622 /// </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> 2623 /// <param name="grp">the scene object that we're crossing</param>
2624 /// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is
2625 /// relative to the region the object currently is in.</param>
2626 /// <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) 2627 public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
2515 { 2628 {
2516 if (grp == null) 2629 if (grp == null)
@@ -2522,209 +2635,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2522 if (scene == null) 2635 if (scene == null)
2523 return; 2636 return;
2524 2637
2638 // Remember the old group position in case the region lookup fails so position can be restored.
2639 Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
2525 2640
2526 int thisx = (int)scene.RegionInfo.RegionLocX; 2641 // Compute the absolute position of the object.
2527 int thisy = (int)scene.RegionInfo.RegionLocY; 2642 double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X;
2528 Vector3 EastCross = new Vector3(0.1f, 0, 0); 2643 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 2644
2612 if (crossedBorderx.BorderLine.Z > 0) 2645 // Ask the grid service for the region that contains the passed address
2613 { 2646 GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
2614 pos.X = ((pos.X + crossedBorderx.BorderLine.Z)); 2647 objectWorldLocX, objectWorldLocY);
2615 changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
2616 }
2617 else
2618 pos.X = ((pos.X + Constants.RegionSize));
2619 2648
2620 newRegionHandle 2649 Vector3 pos = Vector3.Zero;
2621 = Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize), 2650 if (destination != null)
2622 (uint)(thisy * Constants.RegionSize));
2623 // x - 1
2624 }
2625 }
2626 else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E))
2627 { 2651 {
2628 if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S)) 2652 // Adjust the object's relative position from the old region (attemptedPosition)
2629 { 2653 // to be relative to the new region (pos).
2630 2654 pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX),
2631 pos.X = ((pos.X - Constants.RegionSize)); 2655 (float)(objectWorldLocY - (double)destination.RegionLocY),
2632 Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S); 2656 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 } 2657 }
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
2674 if (crossedBordery.BorderLine.Z > 0)
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 2658
2682 newRegionHandle 2659 if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
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 { 2660 {
2661 m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID);
2688 2662
2689 pos.Y = ((pos.Y - Constants.RegionSize)); 2663 // We are going to move the object back to the old position so long as the old position
2690 newRegionHandle 2664 // is in the region
2691 = Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize)); 2665 oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1));
2692 // y + 1 2666 oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1));
2693 } 2667 oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight);
2694 2668
2695 // Offset the positions for the new region across the border 2669 grp.AbsolutePosition = oldGroupPosition;
2696 Vector3 oldGroupPosition = grp.RootPart.GroupPosition; 2670 grp.Velocity = Vector3.Zero;
2671 if (grp.RootPart.PhysActor != null)
2672 grp.RootPart.PhysActor.CrossingFailure();
2697 2673
2698 // If we fail to cross the border, then reset the position of the scene object on that border. 2674 if (grp.RootPart.KeyframeMotion != null)
2699 uint x = 0, y = 0; 2675 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 2676
2703 if (destination != null) 2677 grp.ScheduleGroupForFullUpdate();
2704 {
2705 if (CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
2706 return; // we did it
2707 } 2678 }
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 } 2679 }
2725 2680
2726
2727
2728 /// <summary> 2681 /// <summary>
2729 /// Move the given scene object into a new region 2682 /// Move the given scene object into a new region
2730 /// </summary> 2683 /// </summary>
diff --git a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
index d943b20..4e7ad75 100644
--- a/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/EMailModules/EmailModule.cs
@@ -213,8 +213,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules
213 if (part != null) 213 if (part != null)
214 { 214 {
215 ObjectRegionName = s.RegionInfo.RegionName; 215 ObjectRegionName = s.RegionInfo.RegionName;
216 uint localX = (s.RegionInfo.RegionLocX * (int)Constants.RegionSize); 216 uint localX = s.RegionInfo.WorldLocX;
217 uint localY = (s.RegionInfo.RegionLocY * (int)Constants.RegionSize); 217 uint localY = s.RegionInfo.WorldLocY;
218 ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")"; 218 ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")";
219 return part; 219 return part;
220 } 220 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
index 31ef79b..8ccad39 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/LocalGridServiceConnector.cs
@@ -268,11 +268,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
268 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); 268 caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key);
269 List<GridRegion> regions = kvp.Value.GetNeighbours(); 269 List<GridRegion> regions = kvp.Value.GetNeighbours();
270 foreach (GridRegion r in regions) 270 foreach (GridRegion r in regions)
271 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); 271 caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY));
272 } 272 }
273 } 273 }
274 274
275 MainConsole.Instance.Output(caps.ToString()); 275 MainConsole.Instance.Output(caps.ToString());
276 } 276 }
277 } 277 }
278} \ No newline at end of file 278}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
index 9172536..ae76288 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/RegionCache.cs
@@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
66 return; 66 return;
67 67
68 m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}", 68 m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}",
69 m_scene.RegionInfo.RegionName, otherRegion.RegionName, otherRegion.RegionLocX / Constants.RegionSize, otherRegion.RegionLocY / Constants.RegionSize); 69 m_scene.RegionInfo.RegionName, otherRegion.RegionName, Util.WorldToRegionLoc((uint)otherRegion.RegionLocX), Util.WorldToRegionLoc((uint)otherRegion.RegionLocY));
70 70
71 m_neighbours[otherRegion.RegionHandle] = otherRegion; 71 m_neighbours[otherRegion.RegionHandle] = otherRegion;
72 } 72 }
@@ -82,11 +82,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
82 return new List<GridRegion>(m_neighbours.Values); 82 return new List<GridRegion>(m_neighbours.Values);
83 } 83 }
84 84
85 // Get a region given its base coordinates (in meters).
86 // NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
87 // be the base coordinate of the region.
88 // The snapping is technically unnecessary but is harmless because regions are always
89 // multiples of the legacy region size (256).
85 public GridRegion GetRegionByPosition(int x, int y) 90 public GridRegion GetRegionByPosition(int x, int y)
86 { 91 {
87 uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize; 92 uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize;
88 uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize; 93 uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize;
89 ulong handle = Utils.UIntsToLong(xsnap, ysnap); 94 ulong handle = Util.RegionWorldLocToHandle(xsnap, ysnap);
90 95
91 if (m_neighbours.ContainsKey(handle)) 96 if (m_neighbours.ContainsKey(handle))
92 return m_neighbours[handle]; 97 return m_neighbours[handle];
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
index 4338133..6a49ca7 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/Tests/GridConnectorsTests.cs
@@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
141 Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null"); 141 Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null");
142 Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match"); 142 Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match");
143 143
144 result = m_LocalConnector.GetRegionByPosition(UUID.Zero, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); 144 result = m_LocalConnector.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000));
145 Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null"); 145 Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null");
146 Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match"); 146 Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match");
147 147
@@ -197,4 +197,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
197 Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected"); 197 Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected");
198 } 198 }
199 } 199 }
200} \ No newline at end of file 200}
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
index 96182cd..da74f30 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs
@@ -57,6 +57,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
57 { 57 {
58 private static readonly ILog m_log = 58 private static readonly ILog m_log =
59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 59 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 private static string LogHeader = "[MAP IMAGE SERVICE MODULE]";
60 61
61 private bool m_enabled = false; 62 private bool m_enabled = false;
62 private IMapImageService m_MapService; 63 private IMapImageService m_MapService;
@@ -192,47 +193,94 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
192 m_lastrefresh = Util.EnvironmentTickCount(); 193 m_lastrefresh = Util.EnvironmentTickCount();
193 } 194 }
194 195
196 public void UploadMapTile(IScene scene, Bitmap mapTile)
197 {
198 m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.Name);
199
200 // mapTile.Save( // DEBUG DEBUG
201 // String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY),
202 // ImageFormat.Jpeg);
203 // If the region/maptile is legacy sized, just upload the one tile like it has always been done
204 if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
205 {
206 ConvertAndUploadMaptile(mapTile, scene,
207 scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY);
208 }
209 else
210 {
211 // For larger regions (varregion) we must cut the region image into legacy sized
212 // pieces since that is how the maptile system works.
213 // Note the assumption that varregions are always a multiple of legacy size.
214 for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
215 {
216 for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
217 {
218 // Images are addressed from the upper left corner so have to do funny
219 // math to pick out the sub-tile since regions are numbered from
220 // the lower left.
221 Rectangle rect = new Rectangle(
222 (int)xx,
223 mapTile.Height - (int)yy - (int)Constants.RegionSize,
224 (int)Constants.RegionSize, (int)Constants.RegionSize);
225 using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
226 {
227 ConvertAndUploadMaptile(subMapTile, scene,
228 scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize),
229 scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize)
230 );
231 }
232 }
233 }
234 }
235 }
236
195 ///<summary> 237 ///<summary>
196 /// 238 ///
197 ///</summary> 239 ///</summary>
198 public void UploadMapTile(IScene scene) 240 public void UploadMapTile(IScene scene)
199 { 241 {
200 m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: upload maptile for {0}", scene.RegionInfo.RegionName); 242 m_log.DebugFormat("{0}: upload maptile for {1}", LogHeader, scene.RegionInfo.RegionName);
201 243
202 // Create a JPG map tile and upload it to the AddMapTile API 244 // Create a JPG map tile and upload it to the AddMapTile API
203 byte[] jpgData = Utils.EmptyBytes;
204 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>(); 245 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
205 if (tileGenerator == null) 246 if (tileGenerator == null)
206 { 247 {
207 m_log.Warn("[MAP IMAGE SERVICE MODULE]: Cannot upload PNG map tile without an ImageGenerator"); 248 m_log.WarnFormat("{0} Cannot upload map tile without an ImageGenerator", LogHeader);
208 return; 249 return;
209 } 250 }
210 251
211 using (Image mapTile = tileGenerator.CreateMapTile()) 252 using (Bitmap mapTile = tileGenerator.CreateMapTile())
212 { 253 {
213 // XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there 254 // XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there
214 // is no static map tile. 255 // is no static map tile.
215 if (mapTile == null) 256 if (mapTile == null)
216 return; 257 return;
217 258
218 using (MemoryStream stream = new MemoryStream()) 259 UploadMapTile(scene, mapTile);
219 {
220 mapTile.Save(stream, ImageFormat.Jpeg);
221 jpgData = stream.ToArray();
222 }
223 } 260 }
261 }
262
263 private void ConvertAndUploadMaptile(Image tileImage, IScene scene, uint locX, uint locY)
264 {
265 byte[] jpgData = Utils.EmptyBytes;
224 266
225 if (jpgData == Utils.EmptyBytes) 267 using (MemoryStream stream = new MemoryStream())
226 { 268 {
227 m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Tile image generation failed"); 269 tileImage.Save(stream, ImageFormat.Jpeg);
228 return; 270 jpgData = stream.ToArray();
229 } 271 }
230 272 if (jpgData != Utils.EmptyBytes)
231 string reason = string.Empty; 273 {
232 if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, scene.RegionInfo.ScopeID, out reason)) 274 string reason = string.Empty;
275 if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, scene.RegionInfo.ScopeID, out reason))
276 {
277 m_log.DebugFormat("{0} Unable to upload tile image for {1} at {2}-{3}: {4}", LogHeader,
278 scene.RegionInfo.RegionName, locX, locY, reason);
279 }
280 }
281 else
233 { 282 {
234 m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: Unable to upload tile image for {0} at {1}-{2}: {3}", 283 m_log.WarnFormat("{0} Tile image generation failed for region {1}", LogHeader, scene.RegionInfo.RegionName);
235 scene.RegionInfo.RegionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, reason);
236 } 284 }
237 } 285 }
238 } 286 }
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs
index fd89428..bda354f 100644
--- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Neighbour/LocalNeighbourServiceConnector.cs
@@ -125,14 +125,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour
125 public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion) 125 public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion)
126 { 126 {
127 uint x, y; 127 uint x, y;
128 Utils.LongToUInts(regionHandle, out x, out y); 128 Util.RegionHandleToRegionLoc(regionHandle, out x, out y);
129 129
130 foreach (Scene s in m_Scenes) 130 foreach (Scene s in m_Scenes)
131 { 131 {
132 if (s.RegionInfo.RegionHandle == regionHandle) 132 if (s.RegionInfo.RegionHandle == regionHandle)
133 { 133 {
134 m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", 134 m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}",
135 thisRegion.RegionName, s.Name, x / Constants.RegionSize, y / Constants.RegionSize); 135 thisRegion.RegionName, s.Name, x, y );
136 136
137 //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour"); 137 //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour");
138 return s.IncomingHelloNeighbour(thisRegion); 138 return s.IncomingHelloNeighbour(thisRegion);
diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
index 7a844f4..cd95ee9 100644
--- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
+++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequest.cs
@@ -533,7 +533,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
533 if (isMegaregion) 533 if (isMegaregion)
534 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); 534 size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
535 else 535 else
536 size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); 536 size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY);
537 537
538 xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); 538 xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
539 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); 539 xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index 9279066..4aee6a5 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -64,6 +64,12 @@ namespace OpenSim.Region.CoreModules.World.Land
64 public class LandManagementModule : INonSharedRegionModule 64 public class LandManagementModule : INonSharedRegionModule
65 { 65 {
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
68
69 /// <summary>
70 /// Minimum land unit size in region co-ordinates.
71 /// </summary>
72 public const int landUnit = 4;
67 73
68 private static readonly string remoteParcelRequestPath = "0009/"; 74 private static readonly string remoteParcelRequestPath = "0009/";
69 75
@@ -74,15 +80,10 @@ namespace OpenSim.Region.CoreModules.World.Land
74 protected IPrimCountModule m_primCountModule; 80 protected IPrimCountModule m_primCountModule;
75 protected IDialogModule m_Dialog; 81 protected IDialogModule m_Dialog;
76 82
77 // Minimum for parcels to work is 64m even if we don't actually use them.
78 #pragma warning disable 0429
79 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
80 #pragma warning restore 0429
81
82 /// <value> 83 /// <value>
83 /// Local land ids at specified region co-ordinates (region size / 4) 84 /// Local land ids at specified region co-ordinates (region size / 4)
84 /// </value> 85 /// </value>
85 private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; 86 private int[,] m_landIDList;
86 87
87 /// <value> 88 /// <value>
88 /// Land objects keyed by local id 89 /// Land objects keyed by local id
@@ -123,7 +124,7 @@ namespace OpenSim.Region.CoreModules.World.Land
123 public void AddRegion(Scene scene) 124 public void AddRegion(Scene scene)
124 { 125 {
125 m_scene = scene; 126 m_scene = scene;
126 m_landIDList.Initialize(); 127 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
127 landChannel = new LandChannel(scene, this); 128 landChannel = new LandChannel(scene, this);
128 129
129 parcelInfoCache = new Cache(); 130 parcelInfoCache = new Cache();
@@ -235,7 +236,7 @@ namespace OpenSim.Region.CoreModules.World.Land
235 public void UpdateLandObject(int local_id, LandData data) 236 public void UpdateLandObject(int local_id, LandData data)
236 { 237 {
237 LandData newData = data.Copy(); 238 LandData newData = data.Copy();
238 newData.LocalID = local_id; 239 newData.LocalID = local_id;
239 240
240 ILandObject land; 241 ILandObject land;
241 lock (m_landList) 242 lock (m_landList)
@@ -264,7 +265,7 @@ namespace OpenSim.Region.CoreModules.World.Land
264 { 265 {
265 m_landList.Clear(); 266 m_landList.Clear();
266 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 267 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
267 m_landIDList.Initialize(); 268 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
268 } 269 }
269 } 270 }
270 271
@@ -274,11 +275,11 @@ namespace OpenSim.Region.CoreModules.World.Land
274 /// <returns>The parcel created.</returns> 275 /// <returns>The parcel created.</returns>
275 protected ILandObject CreateDefaultParcel() 276 protected ILandObject CreateDefaultParcel()
276 { 277 {
277 m_log.DebugFormat( 278 m_log.DebugFormat("{0} Creating default parcel for region {1}", LogHeader, m_scene.RegionInfo.RegionName);
278 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
279 279
280 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); 280 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
281 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); 281 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0,
282 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY));
282 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 283 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
283 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); 284 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
284 285
@@ -569,9 +570,9 @@ namespace OpenSim.Region.CoreModules.World.Land
569 new_land.LandData.LocalID = newLandLocalID; 570 new_land.LandData.LocalID = newLandLocalID;
570 571
571 bool[,] landBitmap = new_land.GetLandBitmap(); 572 bool[,] landBitmap = new_land.GetLandBitmap();
572 for (int x = 0; x < landArrayMax; x++) 573 for (int x = 0; x < landBitmap.GetLength(0); x++)
573 { 574 {
574 for (int y = 0; y < landArrayMax; y++) 575 for (int y = 0; y < landBitmap.GetLength(1); y++)
575 { 576 {
576 if (landBitmap[x, y]) 577 if (landBitmap[x, y])
577 { 578 {
@@ -601,9 +602,9 @@ namespace OpenSim.Region.CoreModules.World.Land
601 ILandObject land; 602 ILandObject land;
602 lock (m_landList) 603 lock (m_landList)
603 { 604 {
604 for (int x = 0; x < 64; x++) 605 for (int x = 0; x < m_landIDList.GetLength(0); x++)
605 { 606 {
606 for (int y = 0; y < 64; y++) 607 for (int y = 0; y < m_landIDList.GetLength(1); y++)
607 { 608 {
608 if (m_landIDList[x, y] == local_id) 609 if (m_landIDList[x, y] == local_id)
609 { 610 {
@@ -656,9 +657,9 @@ namespace OpenSim.Region.CoreModules.World.Land
656 bool[,] landBitmapSlave = slave.GetLandBitmap(); 657 bool[,] landBitmapSlave = slave.GetLandBitmap();
657 lock (m_landList) 658 lock (m_landList)
658 { 659 {
659 for (int x = 0; x < 64; x++) 660 for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
660 { 661 {
661 for (int y = 0; y < 64; y++) 662 for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
662 { 663 {
663 if (landBitmapSlave[x, y]) 664 if (landBitmapSlave[x, y])
664 { 665 {
@@ -695,20 +696,23 @@ namespace OpenSim.Region.CoreModules.World.Land
695 int x; 696 int x;
696 int y; 697 int y;
697 698
698 if (x_float > Constants.RegionSize || x_float < 0 || y_float > Constants.RegionSize || y_float < 0) 699 if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0)
699 return null; 700 return null;
700 701
701 try 702 try
702 { 703 {
703 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); 704 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit));
704 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); 705 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit));
705 } 706 }
706 catch (OverflowException) 707 catch (OverflowException)
707 { 708 {
708 return null; 709 return null;
709 } 710 }
710 711
711 if (x >= 64 || y >= 64 || x < 0 || y < 0) 712 if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit)
713 || y >= (m_scene.RegionInfo.RegionSizeY / landUnit)
714 || x < 0
715 || y < 0)
712 { 716 {
713 return null; 717 return null;
714 } 718 }
@@ -740,20 +744,20 @@ namespace OpenSim.Region.CoreModules.World.Land
740 int avx = (int)x; 744 int avx = (int)x;
741 if (avx < 0) 745 if (avx < 0)
742 avx = 0; 746 avx = 0;
743 else if (avx >= (int)Constants.RegionSize) 747 else if (avx >= m_scene.RegionInfo.RegionSizeX)
744 avx = (int)Constants.RegionSize - 1; 748 avx = (int)Constants.RegionSize - 1;
745 749
746 int avy = (int)y; 750 int avy = (int)y;
747 if (avy < 0) 751 if (avy < 0)
748 avy = 0; 752 avy = 0;
749 else if (avy >= (int)Constants.RegionSize) 753 else if (avy >= m_scene.RegionInfo.RegionSizeY)
750 avy = (int)Constants.RegionSize - 1; 754 avy = (int)Constants.RegionSize - 1;
751 755
752 lock (m_landIDList) 756 lock (m_landIDList)
753 { 757 {
754 try 758 try
755 { 759 {
756 return m_landList[m_landIDList[avx / 4, avy / 4]]; 760 return m_landList[m_landIDList[avx / landUnit, avy / landUnit]];
757 } 761 }
758 catch (IndexOutOfRangeException) 762 catch (IndexOutOfRangeException)
759 { 763 {
@@ -764,7 +768,7 @@ namespace OpenSim.Region.CoreModules.World.Land
764 768
765 public ILandObject GetLandObject(int x, int y) 769 public ILandObject GetLandObject(int x, int y)
766 { 770 {
767 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) 771 if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0)
768 { 772 {
769 // These exceptions here will cause a lot of complaints from the users specifically because 773 // These exceptions here will cause a lot of complaints from the users specifically because
770 // they happen every time at border crossings 774 // they happen every time at border crossings
@@ -1057,9 +1061,10 @@ namespace OpenSim.Region.CoreModules.World.Land
1057 int byteArrayCount = 0; 1061 int byteArrayCount = 0;
1058 int sequenceID = 0; 1062 int sequenceID = 0;
1059 1063
1060 for (int y = 0; y < Constants.RegionSize; y += 4) 1064 // Layer data is in landUnit (4m) chunks
1065 for (int y = 0; y < m_scene.RegionInfo.RegionSizeY; y += landUnit)
1061 { 1066 {
1062 for (int x = 0; x < Constants.RegionSize; x += 4) 1067 for (int x = 0; x < m_scene.RegionInfo.RegionSizeX; x += landUnit)
1063 { 1068 {
1064 byte tempByte = 0; //This represents the byte for the current 4x4 1069 byte tempByte = 0; //This represents the byte for the current 4x4
1065 1070
@@ -1769,7 +1774,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1769 { 1774 {
1770 // most likely still cached from building the extLandData entry 1775 // most likely still cached from building the extLandData entry
1771 uint x = 0, y = 0; 1776 uint x = 0, y = 0;
1772 Utils.LongToUInts(data.RegionHandle, out x, out y); 1777 Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y);
1773 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); 1778 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
1774 } 1779 }
1775 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. 1780 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
index a3cd4a5..5858d6c 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs
@@ -45,15 +45,13 @@ namespace OpenSim.Region.CoreModules.World.Land
45 #region Member Variables 45 #region Member Variables
46 46
47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 #pragma warning disable 0429 48 private static readonly string LogHeader = "[LAND OBJECT]";
49 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64; 49
50 #pragma warning restore 0429 50 private readonly int landUnit = 4;
51 private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax];
52 51
53 private int m_lastSeqId = 0; 52 private int m_lastSeqId = 0;
54 private int m_expiryCounter = 0; 53 private int m_expiryCounter = 0;
55 54
56 protected LandData m_landData = new LandData();
57 protected Scene m_scene; 55 protected Scene m_scene;
58 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); 56 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
59 protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); 57 protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>();
@@ -61,6 +59,7 @@ namespace OpenSim.Region.CoreModules.World.Land
61 protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); 59 protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>();
62 protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds 60 protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds
63 61
62 private bool[,] m_landBitmap;
64 public bool[,] LandBitmap 63 public bool[,] LandBitmap
65 { 64 {
66 get { return m_landBitmap; } 65 get { return m_landBitmap; }
@@ -76,6 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Land
76 return free; 75 return free;
77 } 76 }
78 77
78 protected LandData m_landData;
79 public LandData LandData 79 public LandData LandData
80 { 80 {
81 get { return m_landData; } 81 get { return m_landData; }
@@ -94,12 +94,12 @@ namespace OpenSim.Region.CoreModules.World.Land
94 { 94 {
95 get 95 get
96 { 96 {
97 for (int y = 0; y < landArrayMax; y++) 97 for (int y = 0; y < LandBitmap.GetLength(1); y++)
98 { 98 {
99 for (int x = 0; x < landArrayMax; x++) 99 for (int x = 0; x < LandBitmap.GetLength(0); x++)
100 { 100 {
101 if (LandBitmap[x, y]) 101 if (LandBitmap[x, y])
102 return new Vector3(x * 4, y * 4, 0); 102 return new Vector3(x * landUnit, y * landUnit, 0);
103 } 103 }
104 } 104 }
105 105
@@ -111,13 +111,13 @@ namespace OpenSim.Region.CoreModules.World.Land
111 { 111 {
112 get 112 get
113 { 113 {
114 for (int y = landArrayMax - 1; y >= 0; y--) 114 for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--)
115 { 115 {
116 for (int x = landArrayMax - 1; x >= 0; x--) 116 for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--)
117 { 117 {
118 if (LandBitmap[x, y]) 118 if (LandBitmap[x, y])
119 { 119 {
120 return new Vector3(x * 4 + 4, y * 4 + 4, 0); 120 return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
121 } 121 }
122 } 122 }
123 } 123 }
@@ -128,9 +128,21 @@ namespace OpenSim.Region.CoreModules.World.Land
128 128
129 #region Constructors 129 #region Constructors
130 130
131 public LandObject(LandData landData, Scene scene)
132 {
133 LandData = landData.Copy();
134 m_scene = scene;
135 }
136
131 public LandObject(UUID owner_id, bool is_group_owned, Scene scene) 137 public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
132 { 138 {
133 m_scene = scene; 139 m_scene = scene;
140 if (m_scene == null)
141 LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
142 else
143 LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
144
145 LandData = new LandData();
134 LandData.OwnerID = owner_id; 146 LandData.OwnerID = owner_id;
135 if (is_group_owned) 147 if (is_group_owned)
136 LandData.GroupID = owner_id; 148 LandData.GroupID = owner_id;
@@ -155,9 +167,9 @@ namespace OpenSim.Region.CoreModules.World.Land
155 /// <returns>Returns true if the piece of land contains the specified point</returns> 167 /// <returns>Returns true if the piece of land contains the specified point</returns>
156 public bool ContainsPoint(int x, int y) 168 public bool ContainsPoint(int x, int y)
157 { 169 {
158 if (x >= 0 && y >= 0 && x < Constants.RegionSize && y < Constants.RegionSize) 170 if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
159 { 171 {
160 return (LandBitmap[x / 4, y / 4] == true); 172 return LandBitmap[x / landUnit, y / landUnit];
161 } 173 }
162 else 174 else
163 { 175 {
@@ -197,10 +209,10 @@ namespace OpenSim.Region.CoreModules.World.Land
197 else 209 else
198 { 210 {
199 // Normal Calculations 211 // Normal Calculations
200 int parcelMax = (int)((long)LandData.Area 212 int parcelMax = (int)( (long)LandData.Area
201 * (long)m_scene.RegionInfo.ObjectCapacity 213 * (long)m_scene.RegionInfo.ObjectCapacity
202 * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus 214 * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus
203 / 65536L); 215 / (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) );
204 //m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax); 216 //m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax);
205 return parcelMax; 217 return parcelMax;
206 } 218 }
@@ -231,8 +243,9 @@ namespace OpenSim.Region.CoreModules.World.Land
231 else 243 else
232 { 244 {
233 //Normal Calculations 245 //Normal Calculations
234 int simMax = (int)((long)LandData.SimwideArea 246 int simMax = (int)( (long)LandData.SimwideArea
235 * (long)m_scene.RegionInfo.ObjectCapacity / 65536L); 247 * (long)m_scene.RegionInfo.ObjectCapacity
248 / (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) );
236 // m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}", LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax); 249 // m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}", LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax);
237 return simMax; 250 return simMax;
238 } 251 }
@@ -597,8 +610,8 @@ namespace OpenSim.Region.CoreModules.World.Land
597 try 610 try
598 { 611 {
599 over = 612 over =
600 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), 613 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
601 Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); 614 Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
602 } 615 }
603 catch (Exception) 616 catch (Exception)
604 { 617 {
@@ -752,9 +765,9 @@ namespace OpenSim.Region.CoreModules.World.Land
752 int max_y = Int32.MinValue; 765 int max_y = Int32.MinValue;
753 int tempArea = 0; 766 int tempArea = 0;
754 int x, y; 767 int x, y;
755 for (x = 0; x < 64; x++) 768 for (x = 0; x < LandBitmap.GetLength(0); x++)
756 { 769 {
757 for (y = 0; y < 64; y++) 770 for (y = 0; y < LandBitmap.GetLength(1); y++)
758 { 771 {
759 if (LandBitmap[x, y] == true) 772 if (LandBitmap[x, y] == true)
760 { 773 {
@@ -766,23 +779,25 @@ namespace OpenSim.Region.CoreModules.World.Land
766 max_x = x; 779 max_x = x;
767 if (max_y < y) 780 if (max_y < y)
768 max_y = y; 781 max_y = y;
769 tempArea += 16; //16sqm peice of land 782 tempArea += landUnit * landUnit; //16sqm peice of land
770 } 783 }
771 } 784 }
772 } 785 }
786 int tx = min_x * landUnit;
787 if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
788 tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
773 789
774 int tx = min_x * 4;
775 int htx; 790 int htx;
776 if (tx == ((int)Constants.RegionSize)) 791 if (tx >= ((int)m_scene.RegionInfo.RegionSizeX))
777 htx = tx - 1; 792 htx = (int)m_scene.RegionInfo.RegionSizeX - 1;
778 else 793 else
779 htx = tx; 794 htx = tx;
780 795
781 int ty = min_y * 4; 796 int ty = min_y * landUnit;
782 int hty; 797 int hty;
783 798
784 if (ty == ((int)Constants.RegionSize)) 799 if (ty >= ((int)m_scene.RegionInfo.RegionSizeY))
785 hty = ty - 1; 800 hty = (int)m_scene.RegionInfo.RegionSizeY - 1;
786 else 801 else
787 hty = ty; 802 hty = ty;
788 803
@@ -791,17 +806,17 @@ namespace OpenSim.Region.CoreModules.World.Land
791 (float)(tx), (float)(ty), m_scene != null ? (float)m_scene.Heightmap[htx, hty] : 0); 806 (float)(tx), (float)(ty), m_scene != null ? (float)m_scene.Heightmap[htx, hty] : 0);
792 807
793 max_x++; 808 max_x++;
794 tx = max_x * 4; 809 tx = max_x * landUnit;
795 if (tx == ((int)Constants.RegionSize)) 810 if (tx >= ((int)m_scene.RegionInfo.RegionSizeX))
796 htx = tx - 1; 811 htx = (int)m_scene.RegionInfo.RegionSizeX - 1;
797 else 812 else
798 htx = tx; 813 htx = tx;
799 814
800 max_y++; 815 max_y++;
801 ty = max_y * 4; 816 ty = max_y * 4;
802 817
803 if (ty == ((int)Constants.RegionSize)) 818 if (ty >= ((int)m_scene.RegionInfo.RegionSizeY))
804 hty = ty - 1; 819 hty = (int)m_scene.RegionInfo.RegionSizeY - 1;
805 else 820 else
806 hty = ty; 821 hty = ty;
807 822
@@ -819,20 +834,11 @@ namespace OpenSim.Region.CoreModules.World.Land
819 /// <summary> 834 /// <summary>
820 /// Sets the land's bitmap manually 835 /// Sets the land's bitmap manually
821 /// </summary> 836 /// </summary>
822 /// <param name="bitmap">64x64 block representing where this land is on a map</param> 837 /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
823 public void SetLandBitmap(bool[,] bitmap) 838 public void SetLandBitmap(bool[,] bitmap)
824 { 839 {
825 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) 840 LandBitmap = bitmap;
826 { 841 ForceUpdateLandInfo();
827 //Throw an exception - The bitmap is not 64x64
828 //throw new Exception("Error: Invalid Parcel Bitmap");
829 }
830 else
831 {
832 //Valid: Lets set it
833 LandBitmap = bitmap;
834 ForceUpdateLandInfo();
835 }
836 } 842 }
837 843
838 /// <summary> 844 /// <summary>
@@ -846,14 +852,16 @@ namespace OpenSim.Region.CoreModules.World.Land
846 852
847 public bool[,] BasicFullRegionLandBitmap() 853 public bool[,] BasicFullRegionLandBitmap()
848 { 854 {
849 return GetSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize); 855 return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY);
850 } 856 }
851 857
852 public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) 858 public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
853 { 859 {
854 bool[,] tempBitmap = new bool[64,64]; 860 // Empty bitmap for the whole region
861 bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
855 tempBitmap.Initialize(); 862 tempBitmap.Initialize();
856 863
864 // Fill the bitmap square area specified by state and end
857 tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); 865 tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
858 return tempBitmap; 866 return tempBitmap;
859 } 867 }
@@ -871,19 +879,13 @@ namespace OpenSim.Region.CoreModules.World.Land
871 public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, 879 public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
872 bool set_value) 880 bool set_value)
873 { 881 {
874 if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
875 {
876 //Throw an exception - The bitmap is not 64x64
877 //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
878 }
879
880 int x, y; 882 int x, y;
881 for (y = 0; y < 64; y++) 883 for (y = 0; y < land_bitmap.GetLength(1); y++)
882 { 884 {
883 for (x = 0; x < 64; x++) 885 for (x = 0; x < land_bitmap.GetLength(0); x++)
884 { 886 {
885 if (x >= start_x / 4 && x < end_x / 4 887 if (x >= start_x / landUnit && x < end_x / landUnit
886 && y >= start_y / 4 && y < end_y / 4) 888 && y >= start_y / landUnit && y < end_y / landUnit)
887 { 889 {
888 land_bitmap[x, y] = set_value; 890 land_bitmap[x, y] = set_value;
889 } 891 }
@@ -900,21 +902,21 @@ namespace OpenSim.Region.CoreModules.World.Land
900 /// <returns></returns> 902 /// <returns></returns>
901 public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) 903 public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
902 { 904 {
903 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) 905 if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
904 { 906 || bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
905 //Throw an exception - The bitmap is not 64x64 907 || bitmap_add.Rank != 2
906 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); 908 || bitmap_base.Rank != 2)
907 }
908 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
909 { 909 {
910 //Throw an exception - The bitmap is not 64x64 910 throw new Exception(
911 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps"); 911 String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
912 LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
913 );
912 } 914 }
913 915
914 int x, y; 916 int x, y;
915 for (y = 0; y < 64; y++) 917 for (y = 0; y < bitmap_base.GetLength(1); y++)
916 { 918 {
917 for (x = 0; x < 64; x++) 919 for (x = 0; x < bitmap_add.GetLength(0); x++)
918 { 920 {
919 if (bitmap_add[x, y]) 921 if (bitmap_add[x, y])
920 { 922 {
@@ -931,14 +933,14 @@ namespace OpenSim.Region.CoreModules.World.Land
931 /// <returns></returns> 933 /// <returns></returns>
932 private byte[] ConvertLandBitmapToBytes() 934 private byte[] ConvertLandBitmapToBytes()
933 { 935 {
934 byte[] tempConvertArr = new byte[512]; 936 byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
935 int tempByte = 0; 937 int tempByte = 0;
936 int x, y, i, byteNum = 0; 938 int i, byteNum = 0;
937 int mask = 1; 939 int mask = 1;
938 i = 0; 940 i = 0;
939 for (y = 0; y < 64; y++) 941 for (int y = 0; y < LandBitmap.GetLength(1); y++)
940 { 942 {
941 for (x = 0; x < 64; x++) 943 for (int x = 0; x < LandBitmap.GetLength(0); x++)
942 { 944 {
943 if (LandBitmap[x, y]) 945 if (LandBitmap[x, y])
944 tempByte |= mask; 946 tempByte |= mask;
@@ -971,25 +973,45 @@ namespace OpenSim.Region.CoreModules.World.Land
971 973
972 private bool[,] ConvertBytesToLandBitmap() 974 private bool[,] ConvertBytesToLandBitmap()
973 { 975 {
974 bool[,] tempConvertMap = new bool[landArrayMax, landArrayMax]; 976 bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
975 tempConvertMap.Initialize(); 977 tempConvertMap.Initialize();
976 byte tempByte = 0; 978 byte tempByte = 0;
977 int x = 0, y = 0, i = 0, bitNum = 0; 979 // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
978 for (i = 0; i < 512; i++) 980 int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
981 int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
982
983 if (bitmapLen == 512)
984 {
985 // Legacy bitmap being passed in. Use the legacy region size
986 // and only set the lower area of the larger region.
987 xLen = (int)(Constants.RegionSize / landUnit);
988 }
989 // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
990
991 int x = 0, y = 0;
992 for (int i = 0; i < bitmapLen; i++)
979 { 993 {
980 tempByte = LandData.Bitmap[i]; 994 tempByte = LandData.Bitmap[i];
981 for (bitNum = 0; bitNum < 8; bitNum++) 995 for (int bitNum = 0; bitNum < 8; bitNum++)
982 { 996 {
983 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); 997 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
984 tempConvertMap[x, y] = bit; 998 try
999 {
1000 tempConvertMap[x, y] = bit;
1001 }
1002 catch (Exception)
1003 {
1004 m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
1005 }
985 x++; 1006 x++;
986 if (x > 63) 1007 if (x >= xLen)
987 { 1008 {
988 x = 0; 1009 x = 0;
989 y++; 1010 y++;
990 } 1011 }
991 } 1012 }
992 } 1013 }
1014
993 return tempConvertMap; 1015 return tempConvertMap;
994 } 1016 }
995 1017
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
index bc52a43..c7ffeaf 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/MapImageModule.cs
@@ -102,7 +102,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
102 102
103 terrainRenderer.Initialise(m_scene, m_config); 103 terrainRenderer.Initialise(m_scene, m_config);
104 104
105 mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); 105 mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height,
106 System.Drawing.Imaging.PixelFormat.Format24bppRgb);
106 //long t = System.Environment.TickCount; 107 //long t = System.Environment.TickCount;
107 //for (int i = 0; i < 10; ++i) { 108 //for (int i = 0; i < 10; ++i) {
108 terrainRenderer.TerrainToBitmap(mapbmp); 109 terrainRenderer.TerrainToBitmap(mapbmp);
@@ -277,7 +278,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
277 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) 278 private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
278 { 279 {
279 int tc = 0; 280 int tc = 0;
280 double[,] hm = whichScene.Heightmap.GetDoubles(); 281 ITerrainChannel hm = whichScene.Heightmap;
281 tc = Environment.TickCount; 282 tc = Environment.TickCount;
282 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); 283 m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
283 EntityBase[] objs = whichScene.GetEntities(); 284 EntityBase[] objs = whichScene.GetEntities();
@@ -363,7 +364,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
363 Vector3 pos = part.GetWorldPosition(); 364 Vector3 pos = part.GetWorldPosition();
364 365
365 // skip prim outside of retion 366 // skip prim outside of retion
366 if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f) 367 if (!m_scene.PositionIsInCurrentRegion(pos))
367 continue; 368 continue;
368 369
369 // skip prim in non-finite position 370 // skip prim in non-finite position
@@ -388,7 +389,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
388 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z); 389 Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
389 Vector3 scale = new Vector3(); 390 Vector3 scale = new Vector3();
390 Vector3 tScale = new Vector3(); 391 Vector3 tScale = new Vector3();
391 Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z); 392 Vector3 axPos = new Vector3(pos.X, pos.Y, pos.Z);
392 393
393 Quaternion llrot = part.GetWorldRotation(); 394 Quaternion llrot = part.GetWorldRotation();
394 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z); 395 Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
@@ -406,9 +407,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
406 int mapdrawendY = (int)(pos.Y + scale.Y); 407 int mapdrawendY = (int)(pos.Y + scale.Y);
407 408
408 // If object is beyond the edge of the map, don't draw it to avoid errors 409 // If object is beyond the edge of the map, don't draw it to avoid errors
409 if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1) 410 if (mapdrawstartX < 0
410 || mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0 411 || mapdrawstartX > (hm.Width - 1)
411 || mapdrawendY > ((int)Constants.RegionSize - 1)) 412 || mapdrawendX < 0
413 || mapdrawendX > (hm.Width - 1)
414 || mapdrawstartY < 0
415 || mapdrawstartY > (hm.Height - 1)
416 || mapdrawendY < 0
417 || mapdrawendY > (hm.Height - 1))
412 continue; 418 continue;
413 419
414 #region obb face reconstruction part duex 420 #region obb face reconstruction part duex
@@ -530,11 +536,11 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
530 for (int i = 0; i < FaceA.Length; i++) 536 for (int i = 0; i < FaceA.Length; i++)
531 { 537 {
532 Point[] working = new Point[5]; 538 Point[] working = new Point[5];
533 working[0] = project(FaceA[i], axPos); 539 working[0] = project(hm, FaceA[i], axPos);
534 working[1] = project(FaceB[i], axPos); 540 working[1] = project(hm, FaceB[i], axPos);
535 working[2] = project(FaceD[i], axPos); 541 working[2] = project(hm, FaceD[i], axPos);
536 working[3] = project(FaceC[i], axPos); 542 working[3] = project(hm, FaceC[i], axPos);
537 working[4] = project(FaceA[i], axPos); 543 working[4] = project(hm, FaceA[i], axPos);
538 544
539 face workingface = new face(); 545 face workingface = new face();
540 workingface.pts = working; 546 workingface.pts = working;
@@ -609,17 +615,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
609 return mapbmp; 615 return mapbmp;
610 } 616 }
611 617
612 private Point project(Vector3 point3d, Vector3 originpos) 618 private Point project(ITerrainChannel hm, Vector3 point3d, Vector3 originpos)
613 { 619 {
614 Point returnpt = new Point(); 620 Point returnpt = new Point();
615 //originpos = point3d; 621 //originpos = point3d;
616 //int d = (int)(256f / 1.5f); 622 //int d = (int)(256f / 1.5f);
617 623
618 //Vector3 topos = new Vector3(0, 0, 0); 624 //Vector3 topos = new Vector3(0, 0, 0);
619 // float z = -point3d.z - topos.z; 625 // float z = -point3d.z - topos.z;
620 626
621 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); 627 returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d);
622 returnpt.Y = (int)(((int)Constants.RegionSize - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); 628 returnpt.Y = (int)((hm.Width - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d)));
623 629
624 return returnpt; 630 return returnpt;
625 } 631 }
diff --git a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
index cb06fd4..708286c 100644
--- a/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
+++ b/OpenSim/Region/CoreModules/World/LegacyMap/ShadedMapTileRenderer.cs
@@ -31,6 +31,7 @@ using System.Reflection;
31using log4net; 31using log4net;
32using Nini.Config; 32using Nini.Config;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Region.Framework.Interfaces;
34using OpenSim.Region.Framework.Scenes; 35using OpenSim.Region.Framework.Scenes;
35 36
36namespace OpenSim.Region.CoreModules.World.LegacyMap 37namespace OpenSim.Region.CoreModules.World.LegacyMap
@@ -39,8 +40,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
39 { 40 {
40 private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); 41 private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95);
41 42
42 private static readonly ILog m_log = 43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]";
44 45
45 private Scene m_scene; 46 private Scene m_scene;
46 //private IConfigSource m_config; // not used currently 47 //private IConfigSource m_config; // not used currently
@@ -53,19 +54,26 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
53 54
54 public void TerrainToBitmap(Bitmap mapbmp) 55 public void TerrainToBitmap(Bitmap mapbmp)
55 { 56 {
57 m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
56 int tc = Environment.TickCount; 58 int tc = Environment.TickCount;
57 m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Terrain");
58 59
59 double[,] hm = m_scene.Heightmap.GetDoubles(); 60 ITerrainChannel hm = m_scene.Heightmap;
61
62 if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height)
63 {
64 m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>",
65 LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height);
66 }
67
60 bool ShadowDebugContinue = true; 68 bool ShadowDebugContinue = true;
61 69
62 bool terraincorruptedwarningsaid = false; 70 bool terraincorruptedwarningsaid = false;
63 71
64 float low = 255; 72 float low = 255;
65 float high = 0; 73 float high = 0;
66 for (int x = 0; x < (int)Constants.RegionSize; x++) 74 for (int x = 0; x < hm.Width; x++)
67 { 75 {
68 for (int y = 0; y < (int)Constants.RegionSize; y++) 76 for (int y = 0; y < hm.Height; y++)
69 { 77 {
70 float hmval = (float)hm[x, y]; 78 float hmval = (float)hm[x, y];
71 if (hmval < low) 79 if (hmval < low)
@@ -77,12 +85,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
77 85
78 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; 86 float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
79 87
80 for (int x = 0; x < (int)Constants.RegionSize; x++) 88 for (int x = 0; x < hm.Width; x++)
81 { 89 {
82 for (int y = 0; y < (int)Constants.RegionSize; y++) 90 for (int y = 0; y < hm.Height; y++)
83 { 91 {
84 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left 92 // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
85 int yr = ((int)Constants.RegionSize - 1) - y; 93 int yr = ((int)hm.Height - 1) - y;
86 94
87 float heightvalue = (float)hm[x, y]; 95 float heightvalue = (float)hm[x, y];
88 96
@@ -109,12 +117,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
109 // . 117 // .
110 // 118 //
111 // Shade the terrain for shadows 119 // Shade the terrain for shadows
112 if (x < ((int)Constants.RegionSize - 1) && yr < ((int)Constants.RegionSize - 1)) 120 if (x < (hm.Width - 1) && yr < (hm.Height - 1))
113 { 121 {
114 float hfvalue = (float)hm[x, y]; 122 float hfvalue = (float)hm[x, y];
115 float hfvaluecompare = 0f; 123 float hfvaluecompare = 0f;
116 124
117 if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) 125 if ((x + 1 < hm.Width) && (y + 1 < hm.Height))
118 { 126 {
119 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there 127 hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there
120 } 128 }
@@ -179,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
179 187
180 if (ShadowDebugContinue) 188 if (ShadowDebugContinue)
181 { 189 {
182 if ((x - 1 > 0) && (yr + 1 < (int)Constants.RegionSize)) 190 if ((x - 1 > 0) && (yr + 1 < hm.Height))
183 { 191 {
184 color = mapbmp.GetPixel(x - 1, yr + 1); 192 color = mapbmp.GetPixel(x - 1, yr + 1);
185 int r = color.R; 193 int r = color.R;
@@ -233,7 +241,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
233 terraincorruptedwarningsaid = true; 241 terraincorruptedwarningsaid = true;
234 } 242 }
235 Color black = Color.Black; 243 Color black = Color.Black;
236 mapbmp.SetPixel(x, ((int)Constants.RegionSize - y) - 1, black); 244 mapbmp.SetPixel(x, (hm.Width - y) - 1, black);
237 } 245 }
238 } 246 }
239 } 247 }
@@ -242,4 +250,4 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
242 m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); 250 m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
243 } 251 }
244 } 252 }
245} \ No newline at end of file 253}
diff --git a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
index d4e4c25..014c845 100644
--- a/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
+++ b/OpenSim/Region/CoreModules/World/Objects/BuySell/BuySellModule.cs
@@ -151,14 +151,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
151 break; 151 break;
152 152
153 case 2: // Sell a copy 153 case 2: // Sell a copy
154 Vector3 inventoryStoredPosition = new Vector3 154 Vector3 inventoryStoredPosition = new Vector3(
155 (((group.AbsolutePosition.X > (int)Constants.RegionSize) 155 Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6),
156 ? 250 156 Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6),
157 : group.AbsolutePosition.X)
158 ,
159 (group.AbsolutePosition.X > (int)Constants.RegionSize)
160 ? 250
161 : group.AbsolutePosition.X,
162 group.AbsolutePosition.Z); 157 group.AbsolutePosition.Z);
163 158
164 Vector3 originalPosition = group.AbsolutePosition; 159 Vector3 originalPosition = group.AbsolutePosition;
diff --git a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
index 616fe98..928755d 100644
--- a/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
+++ b/OpenSim/Region/CoreModules/World/Permissions/PermissionsModule.cs
@@ -1571,10 +1571,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
1571 float X = position.X; 1571 float X = position.X;
1572 float Y = position.Y; 1572 float Y = position.Y;
1573 1573
1574 if (X > ((int)Constants.RegionSize - 1)) 1574 if (X > ((int)m_scene.RegionInfo.RegionSizeX - 1))
1575 X = ((int)Constants.RegionSize - 1); 1575 X = ((int)m_scene.RegionInfo.RegionSizeX - 1);
1576 if (Y > ((int)Constants.RegionSize - 1)) 1576 if (Y > ((int)m_scene.RegionInfo.RegionSizeY - 1))
1577 Y = ((int)Constants.RegionSize - 1); 1577 Y = ((int)m_scene.RegionInfo.RegionSizeY - 1);
1578 if (X < 0) 1578 if (X < 0)
1579 X = 0; 1579 X = 0;
1580 if (Y < 0) 1580 if (Y < 0)
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
index 7186dd7..80396c4 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/Effects/DefaultTerrainGenerator.cs
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects
42 for (y = 0; y < map.Height; y++) 42 for (y = 0; y < map.Height; y++)
43 { 43 {
44 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; 44 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10;
45 double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2, Constants.RegionSize / 2, 50) * 0.01; 45 double spherFac = TerrainUtil.SphericalFactor(x, y, map.Width / 2, map.Height / 2, 50) * 0.01;
46 if (map[x, y] < spherFac) 46 if (map[x, y] < spherFac)
47 { 47 {
48 map[x, y] = spherFac; 48 map[x, y] = spherFac;
@@ -53,4 +53,4 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects
53 53
54 #endregion 54 #endregion
55 } 55 }
56} \ No newline at end of file 56}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
index d78ade5..d5c77ec 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/GenericSystemDrawing.cs
@@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
67 { 67 {
68 using (Bitmap bitmap = new Bitmap(filename)) 68 using (Bitmap bitmap = new Bitmap(filename))
69 { 69 {
70 ITerrainChannel retval = new TerrainChannel(true); 70 ITerrainChannel retval = new TerrainChannel(w, h);
71 71
72 for (int x = 0; x < retval.Width; x++) 72 for (int x = 0; x < retval.Width; x++)
73 { 73 {
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
index b5c7d33..a7e4d9f 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FileLoaders/Terragen.cs
@@ -154,10 +154,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
154 154
155 public ITerrainChannel LoadStream(Stream s) 155 public ITerrainChannel LoadStream(Stream s)
156 { 156 {
157 157 // Set to default size
158 int w = (int)Constants.RegionSize; 158 int w = (int)Constants.RegionSize;
159 int h = (int)Constants.RegionSize; 159 int h = (int)Constants.RegionSize;
160 160
161 // create a dummy channel (in case data is bad)
161 TerrainChannel retval = new TerrainChannel(w, h); 162 TerrainChannel retval = new TerrainChannel(w, h);
162 163
163 BinaryReader bs = new BinaryReader(s); 164 BinaryReader bs = new BinaryReader(s);
@@ -165,8 +166,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
165 bool eof = false; 166 bool eof = false;
166 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") 167 if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ")
167 { 168 {
168// int fileWidth = w;
169// int fileHeight = h;
170 169
171 // Terragen file 170 // Terragen file
172 while (eof == false) 171 while (eof == false)
@@ -175,31 +174,29 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
175 switch (tmp) 174 switch (tmp)
176 { 175 {
177 case "SIZE": 176 case "SIZE":
178// int sztmp = bs.ReadInt16() + 1; 177 w = bs.ReadInt16() + 1;
179// fileWidth = sztmp; 178 h = w;
180// fileHeight = sztmp;
181 bs.ReadInt16();
182 bs.ReadInt16(); 179 bs.ReadInt16();
183 break; 180 break;
184 case "XPTS": 181 case "XPTS":
185// fileWidth = bs.ReadInt16(); 182 w = bs.ReadInt16();
186 bs.ReadInt16();
187 bs.ReadInt16(); 183 bs.ReadInt16();
188 break; 184 break;
189 case "YPTS": 185 case "YPTS":
190// fileHeight = bs.ReadInt16(); 186 h = bs.ReadInt16();
191 bs.ReadInt16();
192 bs.ReadInt16(); 187 bs.ReadInt16();
193 break; 188 break;
194 case "ALTW": 189 case "ALTW":
195 eof = true; 190 eof = true;
196 Int16 heightScale = bs.ReadInt16(); 191 // create new channel of proper size (now that we know it)
197 Int16 baseHeight = bs.ReadInt16(); 192 retval = new TerrainChannel(w, h);
193 double heightScale = (double)bs.ReadInt16() / 65536.0;
194 double baseHeight = (double)bs.ReadInt16();
198 for (int y = 0; y < h; y++) 195 for (int y = 0; y < h; y++)
199 { 196 {
200 for (int x = 0; x < w; x++) 197 for (int x = 0; x < w; x++)
201 { 198 {
202 retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0; 199 retval[x, y] = baseHeight + (double)bs.ReadInt16() * heightScale;
203 } 200 }
204 } 201 }
205 break; 202 break;
@@ -257,17 +254,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
257 bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); 254 bs.Write(enc.GetBytes("TERRAGENTERRAIN "));
258 255
259 bs.Write(enc.GetBytes("SIZE")); 256 bs.Write(enc.GetBytes("SIZE"));
260 bs.Write(Convert.ToInt16(Constants.RegionSize)); 257 bs.Write(Convert.ToInt16(map.Width));
261 bs.Write(Convert.ToInt16(0)); // necessary padding 258 bs.Write(Convert.ToInt16(0)); // necessary padding
262 259
263 //The XPTS and YPTS chunks are not needed for square regions 260 //The XPTS and YPTS chunks are not needed for square regions
264 //but L3DT won't load the terrain file properly without them. 261 //but L3DT won't load the terrain file properly without them.
265 bs.Write(enc.GetBytes("XPTS")); 262 bs.Write(enc.GetBytes("XPTS"));
266 bs.Write(Convert.ToInt16(Constants.RegionSize)); 263 bs.Write(Convert.ToInt16(map.Width));
267 bs.Write(Convert.ToInt16(0)); // necessary padding 264 bs.Write(Convert.ToInt16(0)); // necessary padding
268 265
269 bs.Write(enc.GetBytes("YPTS")); 266 bs.Write(enc.GetBytes("YPTS"));
270 bs.Write(Convert.ToInt16(Constants.RegionSize)); 267 bs.Write(Convert.ToInt16(map.Height));
271 bs.Write(Convert.ToInt16(0)); // necessary padding 268 bs.Write(Convert.ToInt16(0)); // necessary padding
272 269
273 bs.Write(enc.GetBytes("SCAL")); 270 bs.Write(enc.GetBytes("SCAL"));
@@ -283,11 +280,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
283 bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min 280 bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min
284 bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point 281 bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point
285 282
283 double factor = 65536.0 / horizontalScale; // avoid computing this on each iteration
284
286 for (int y = 0; y < map.Height; y++) 285 for (int y = 0; y < map.Height; y++)
287 { 286 {
288 for (int x = 0; x < map.Width; x++) 287 for (int x = 0; x < map.Width; x++)
289 { 288 {
290 float elevation = (float)((map[x,y] - baseHeight) * 65536 ) / (float)horizontalScale; // see LoadStream for inverse 289 float elevation = (float)((map[x,y] - baseHeight) * factor); // see LoadStream for inverse
291 290
292 // clamp rounding issues 291 // clamp rounding issues
293 if (elevation > Int16.MaxValue) 292 if (elevation > Int16.MaxValue)
diff --git a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
index 630473e..d3e2533 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/FloodBrushes/NoiseArea.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
45 { 45 {
46 if (fillArea[x, y]) 46 if (fillArea[x, y])
47 { 47 {
48 double noise = TerrainUtil.PerlinNoise2D((double) x / Constants.RegionSize, (double) y / Constants.RegionSize, 8, 1.0); 48 double noise = TerrainUtil.PerlinNoise2D((double) x / map.Width, (double) y / map.Height, 8, 1.0);
49 49
50 map[x, y] += noise * strength; 50 map[x, y] += noise * strength;
51 } 51 }
@@ -55,4 +55,4 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
55 55
56 #endregion 56 #endregion
57 } 57 }
58} \ No newline at end of file 58}
diff --git a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
index 989b7d8..e7df3f8 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/PaintBrushes/NoiseSphere.cs
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
53 z *= z; 53 z *= z;
54 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); 54 z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry));
55 55
56 double noise = TerrainUtil.PerlinNoise2D(x / (double) Constants.RegionSize, y / (double) Constants.RegionSize, 8, 1.0); 56 double noise = TerrainUtil.PerlinNoise2D(x / (double) map.Width, y / (double) map.Height, 8, 1.0);
57 57
58 if (z > 0.0) 58 if (z > 0.0)
59 map[x, y] += noise * z * duration; 59 map[x, y] += noise * z * duration;
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 4d738a5..9a88804 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -71,6 +71,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
71 71
72 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 72 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
73 73
74#pragma warning disable 414
75 private static readonly string LogHeader = "[TERRAIN MODULE]";
76#pragma warning restore 414
77
74 private readonly Commander m_commander = new Commander("terrain"); 78 private readonly Commander m_commander = new Commander("terrain");
75 79
76 private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = 80 private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects =
@@ -81,8 +85,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
81 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = 85 private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
82 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); 86 new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
83 87
84 private ITerrainChannel m_channel;
85 private Dictionary<string, ITerrainEffect> m_plugineffects; 88 private Dictionary<string, ITerrainEffect> m_plugineffects;
89 private ITerrainChannel m_channel;
86 private ITerrainChannel m_revert; 90 private ITerrainChannel m_revert;
87 private Scene m_scene; 91 private Scene m_scene;
88 private volatile bool m_tainted; 92 private volatile bool m_tainted;
@@ -90,6 +94,85 @@ namespace OpenSim.Region.CoreModules.World.Terrain
90 94
91 private String m_InitialTerrain = "pinhead-island"; 95 private String m_InitialTerrain = "pinhead-island";
92 96
97 // If true, send terrain patch updates to clients based on their view distance
98 private bool m_sendTerrainUpdatesByViewDistance = true;
99
100 // Class to keep the per client collection of terrain patches that must be sent.
101 // A patch is set to 'true' meaning it should be sent to the client. Once the
102 // patch packet is queued to the client, the bit for that patch is set to 'false'.
103 private class PatchUpdates
104 {
105 private bool[,] updated; // for each patch, whether it needs to be sent to this client
106 private int updateCount; // number of patches that need to be sent
107 public ScenePresence Presence; // a reference to the client to send to
108 public PatchUpdates(TerrainData terrData, ScenePresence pPresence)
109 {
110 updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize];
111 updateCount = 0;
112 Presence = pPresence;
113 // Initially, send all patches to the client
114 SetAll(true);
115 }
116 // Returns 'true' if there are any patches marked for sending
117 public bool HasUpdates()
118 {
119 return (updateCount > 0);
120 }
121 public void SetByXY(int x, int y, bool state)
122 {
123 this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
124 }
125 public bool GetByPatch(int patchX, int patchY)
126 {
127 return updated[patchX, patchY];
128 }
129 public void SetByPatch(int patchX, int patchY, bool state)
130 {
131 bool prevState = updated[patchX, patchY];
132 if (!prevState && state)
133 updateCount++;
134 if (prevState && !state)
135 updateCount--;
136 updated[patchX, patchY] = state;
137 }
138 public void SetAll(bool state)
139 {
140 updateCount = 0;
141 for (int xx = 0; xx < updated.GetLength(0); xx++)
142 for (int yy = 0; yy < updated.GetLength(1); yy++)
143 updated[xx, yy] = state;
144 if (state)
145 updateCount = updated.GetLength(0) * updated.GetLength(1);
146 }
147 // Logically OR's the terrain data's patch taint map into this client's update map.
148 public void SetAll(TerrainData terrData)
149 {
150 if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize)
151 || updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize))
152 {
153 throw new Exception(
154 String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>",
155 LogHeader, updated.GetLength(0), updated.GetLength(1),
156 terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
157 );
158 }
159 for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
160 {
161 for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
162 {
163 // Only set tainted. The patch bit may be set if the patch was to be sent later.
164 if (terrData.IsTaintedAt(xx, yy, false))
165 {
166 this.SetByXY(xx, yy, true);
167 }
168 }
169 }
170 }
171 }
172
173 // The flags of which terrain patches to send for each of the ScenePresence's
174 private Dictionary<UUID, PatchUpdates> m_perClientPatchUpdates = new Dictionary<UUID, PatchUpdates>();
175
93 /// <summary> 176 /// <summary>
94 /// Human readable list of terrain file extensions that are supported. 177 /// Human readable list of terrain file extensions that are supported.
95 /// </summary> 178 /// </summary>
@@ -118,7 +201,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
118 { 201 {
119 IConfig terrainConfig = config.Configs["Terrain"]; 202 IConfig terrainConfig = config.Configs["Terrain"];
120 if (terrainConfig != null) 203 if (terrainConfig != null)
204 {
121 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 205 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
206 m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance);
207 }
122 } 208 }
123 209
124 public void AddRegion(Scene scene) 210 public void AddRegion(Scene scene)
@@ -130,22 +216,24 @@ namespace OpenSim.Region.CoreModules.World.Terrain
130 { 216 {
131 if (m_scene.Heightmap == null) 217 if (m_scene.Heightmap == null)
132 { 218 {
133 m_channel = new TerrainChannel(m_InitialTerrain); 219 m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX,
220 (int)m_scene.RegionInfo.RegionSizeY,
221 (int)m_scene.RegionInfo.RegionSizeZ);
134 m_scene.Heightmap = m_channel; 222 m_scene.Heightmap = m_channel;
135 m_revert = new TerrainChannel();
136 UpdateRevertMap(); 223 UpdateRevertMap();
137 } 224 }
138 else 225 else
139 { 226 {
140 m_channel = m_scene.Heightmap; 227 m_channel = m_scene.Heightmap;
141 m_revert = new TerrainChannel();
142 UpdateRevertMap(); 228 UpdateRevertMap();
143 } 229 }
144 230
145 m_scene.RegisterModuleInterface<ITerrainModule>(this); 231 m_scene.RegisterModuleInterface<ITerrainModule>(this);
146 m_scene.EventManager.OnNewClient += EventManager_OnNewClient; 232 m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
233 m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed;
147 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; 234 m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
148 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; 235 m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick;
236 m_scene.EventManager.OnFrame += EventManager_OnFrame;
149 } 237 }
150 238
151 InstallDefaultEffects(); 239 InstallDefaultEffects();
@@ -184,8 +272,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
184 // remove the commands 272 // remove the commands
185 m_scene.UnregisterModuleCommander(m_commander.Name); 273 m_scene.UnregisterModuleCommander(m_commander.Name);
186 // remove the event-handlers 274 // remove the event-handlers
275 m_scene.EventManager.OnFrame -= EventManager_OnFrame;
187 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; 276 m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick;
188 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; 277 m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole;
278 m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed;
189 m_scene.EventManager.OnNewClient -= EventManager_OnNewClient; 279 m_scene.EventManager.OnNewClient -= EventManager_OnNewClient;
190 // remove the interface 280 // remove the interface
191 m_scene.UnregisterModuleInterface<ITerrainModule>(this); 281 m_scene.UnregisterModuleInterface<ITerrainModule>(this);
@@ -230,11 +320,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
230 try 320 try
231 { 321 {
232 ITerrainChannel channel = loader.Value.LoadFile(filename); 322 ITerrainChannel channel = loader.Value.LoadFile(filename);
233 if (channel.Width != Constants.RegionSize || channel.Height != Constants.RegionSize) 323 if (channel.Width != m_scene.RegionInfo.RegionSizeX || channel.Height != m_scene.RegionInfo.RegionSizeY)
234 { 324 {
235 // TerrainChannel expects a RegionSize x RegionSize map, currently 325 // TerrainChannel expects a RegionSize x RegionSize map, currently
236 throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", 326 throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}",
237 Constants.RegionSize, Constants.RegionSize)); 327 m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY));
238 } 328 }
239 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); 329 m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height);
240 m_scene.Heightmap = channel; 330 m_scene.Heightmap = channel;
@@ -261,7 +351,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
261 String.Format("Unable to load heightmap: {0}", e.Message)); 351 String.Format("Unable to load heightmap: {0}", e.Message));
262 } 352 }
263 } 353 }
264 CheckForTerrainUpdates();
265 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); 354 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
266 return; 355 return;
267 } 356 }
@@ -309,12 +398,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
309 LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); 398 LoadFromStream(filename, URIFetch(pathToTerrainHeightmap));
310 } 399 }
311 400
401 public void LoadFromStream(string filename, Stream stream)
402 {
403 LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream);
404 }
405
312 /// <summary> 406 /// <summary>
313 /// Loads a terrain file from a stream and installs it in the scene. 407 /// Loads a terrain file from a stream and installs it in the scene.
314 /// </summary> 408 /// </summary>
315 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param> 409 /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
316 /// <param name="stream"></param> 410 /// <param name="stream"></param>
317 public void LoadFromStream(string filename, Stream stream) 411 public void LoadFromStream(string filename, Vector3 displacement,
412 float radianRotation, Vector2 rotationDisplacement, Stream stream)
318 { 413 {
319 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) 414 foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
320 { 415 {
@@ -325,8 +420,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
325 try 420 try
326 { 421 {
327 ITerrainChannel channel = loader.Value.LoadStream(stream); 422 ITerrainChannel channel = loader.Value.LoadStream(stream);
328 m_scene.Heightmap = channel; 423 m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
329 m_channel = channel;
330 UpdateRevertMap(); 424 UpdateRevertMap();
331 } 425 }
332 catch (NotImplementedException) 426 catch (NotImplementedException)
@@ -337,7 +431,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
337 } 431 }
338 } 432 }
339 433
340 CheckForTerrainUpdates();
341 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); 434 m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
342 return; 435 return;
343 } 436 }
@@ -406,9 +499,46 @@ namespace OpenSim.Region.CoreModules.World.Terrain
406 } 499 }
407 } 500 }
408 501
502 // Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
503 // ITerrainModule.TaintTerrain()
409 public void TaintTerrain () 504 public void TaintTerrain ()
410 { 505 {
411 CheckForTerrainUpdates(); 506 lock (m_perClientPatchUpdates)
507 {
508 // Set the flags for all clients so the tainted patches will be sent out
509 foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
510 {
511 pups.SetAll(m_scene.Heightmap.GetTerrainData());
512 }
513 }
514 }
515
516 // ITerrainModule.PushTerrain()
517 public void PushTerrain(IClientAPI pClient)
518 {
519 if (m_sendTerrainUpdatesByViewDistance)
520 {
521 ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
522 if (presence != null)
523 {
524 lock (m_perClientPatchUpdates)
525 {
526 PatchUpdates pups;
527 if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups))
528 {
529 // There is a ScenePresence without a send patch map. Create one.
530 pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence);
531 m_perClientPatchUpdates.Add(presence.UUID, pups);
532 }
533 pups.SetAll(true);
534 }
535 }
536 }
537 else
538 {
539 // The traditional way is to call into the protocol stack to send them all.
540 pClient.SendLayerData(new float[10]);
541 }
412 } 542 }
413 543
414 #region Plugin Loading Methods 544 #region Plugin Loading Methods
@@ -532,6 +662,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
532 /// </summary> 662 /// </summary>
533 public void UpdateRevertMap() 663 public void UpdateRevertMap()
534 { 664 {
665 /*
535 int x; 666 int x;
536 for (x = 0; x < m_channel.Width; x++) 667 for (x = 0; x < m_channel.Width; x++)
537 { 668 {
@@ -541,6 +672,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
541 m_revert[x, y] = m_channel[x, y]; 672 m_revert[x, y] = m_channel[x, y];
542 } 673 }
543 } 674 }
675 */
676 m_revert = m_channel.MakeCopy();
544 } 677 }
545 678
546 /// <summary> 679 /// <summary>
@@ -567,8 +700,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
567 { 700 {
568 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, 701 ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
569 fileWidth, fileHeight, 702 fileWidth, fileHeight,
570 (int) Constants.RegionSize, 703 (int) m_scene.RegionInfo.RegionSizeX,
571 (int) Constants.RegionSize); 704 (int) m_scene.RegionInfo.RegionSizeY);
572 m_scene.Heightmap = channel; 705 m_scene.Heightmap = channel;
573 m_channel = channel; 706 m_channel = channel;
574 UpdateRevertMap(); 707 UpdateRevertMap();
@@ -615,8 +748,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
615 { 748 {
616 loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, 749 loader.Value.SaveFile(m_channel, filename, offsetX, offsetY,
617 fileWidth, fileHeight, 750 fileWidth, fileHeight,
618 (int)Constants.RegionSize, 751 (int)m_scene.RegionInfo.RegionSizeX,
619 (int)Constants.RegionSize); 752 (int)m_scene.RegionInfo.RegionSizeY);
620 753
621 MainConsole.Instance.OutputFormat( 754 MainConsole.Instance.OutputFormat(
622 "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", 755 "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}",
@@ -634,7 +767,44 @@ namespace OpenSim.Region.CoreModules.World.Terrain
634 } 767 }
635 768
636 /// <summary> 769 /// <summary>
770 /// Called before processing of every simulation frame.
771 /// This is used to check to see of any of the terrain is tainted and, if so, schedule
772 /// updates for all the presences.
773 /// This also checks to see if there are updates that need to be sent for each presence.
774 /// This is where the logic is to send terrain updates to clients.
775 /// </summary>
776 private void EventManager_OnFrame()
777 {
778 TerrainData terrData = m_channel.GetTerrainData();
779
780 bool shouldTaint = false;
781 for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
782 {
783 for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
784 {
785 if (terrData.IsTaintedAt(x, y))
786 {
787 // Found a patch that was modified. Push this flag into the clients.
788 SendToClients(terrData, x, y);
789 shouldTaint = true;
790 }
791 }
792 }
793
794 // This event also causes changes to be sent to the clients
795 CheckSendingPatchesToClients();
796
797 // If things changes, generate some events
798 if (shouldTaint)
799 {
800 m_scene.EventManager.TriggerTerrainTainted();
801 m_tainted = true;
802 }
803 }
804
805 /// <summary>
637 /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections 806 /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections
807 /// Called infrequently (like every 5 seconds or so). Best used for storing terrain.
638 /// </summary> 808 /// </summary>
639 private void EventManager_OnTerrainTick() 809 private void EventManager_OnTerrainTick()
640 { 810 {
@@ -644,8 +814,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
644 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); 814 m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
645 m_scene.SaveTerrain(); 815 m_scene.SaveTerrain();
646 816
647 m_scene.EventManager.TriggerTerrainUpdate();
648
649 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out. 817 // Clients who look at the map will never see changes after they looked at the map, so i've commented this out.
650 //m_scene.CreateTerrainTexture(true); 818 //m_scene.CreateTerrainTexture(true);
651 } 819 }
@@ -687,54 +855,48 @@ namespace OpenSim.Region.CoreModules.World.Terrain
687 } 855 }
688 856
689 /// <summary> 857 /// <summary>
690 /// Checks to see if the terrain has been modified since last check 858 /// Installs terrain brush hook to IClientAPI
691 /// but won't attempt to limit those changes to the limits specified in the estate settings
692 /// currently invoked by the command line operations in the region server only
693 /// </summary> 859 /// </summary>
694 private void CheckForTerrainUpdates() 860 /// <param name="client"></param>
861 private void EventManager_OnClientClosed(UUID client, Scene scene)
695 { 862 {
696 CheckForTerrainUpdates(false); 863 ScenePresence presence = scene.GetScenePresence(client);
697 } 864 if (presence != null)
865 {
866 presence.ControllingClient.OnModifyTerrain -= client_OnModifyTerrain;
867 presence.ControllingClient.OnBakeTerrain -= client_OnBakeTerrain;
868 presence.ControllingClient.OnLandUndo -= client_OnLandUndo;
869 presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
870 }
698 871
872 lock (m_perClientPatchUpdates)
873 m_perClientPatchUpdates.Remove(client);
874 }
875
699 /// <summary> 876 /// <summary>
700 /// Checks to see if the terrain has been modified since last check. 877 /// Scan over changes in the terrain and limit height changes. This enforces the
701 /// If it has been modified, every all the terrain patches are sent to the client. 878 /// non-estate owner limits on rate of terrain editting.
702 /// If the call is asked to respect the estate settings for terrain_raise_limit and 879 /// Returns 'true' if any heights were limited.
703 /// terrain_lower_limit, it will clamp terrain updates between these values
704 /// currently invoked by client_OnModifyTerrain only and not the Commander interfaces
705 /// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param>
706 /// </summary> 880 /// </summary>
707 private void CheckForTerrainUpdates(bool respectEstateSettings) 881 private bool EnforceEstateLimits()
708 { 882 {
709 bool shouldTaint = false; 883 TerrainData terrData = m_channel.GetTerrainData();
710 float[] serialised = m_channel.GetFloatsSerialised(); 884
711 int x; 885 bool wasLimited = false;
712 for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) 886 for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
713 { 887 {
714 int y; 888 for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
715 for (y = 0; y < m_channel.Height; y += Constants.TerrainPatchSize)
716 { 889 {
717 if (m_channel.Tainted(x, y)) 890 if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
718 { 891 {
719 // if we should respect the estate settings then 892 // If we should respect the estate settings then
720 // fixup and height deltas that don't respect them 893 // fixup and height deltas that don't respect them.
721 if (respectEstateSettings && LimitChannelChanges(x, y)) 894 // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
722 { 895 wasLimited |= LimitChannelChanges(terrData, x, y);
723 // this has been vetoed, so update
724 // what we are going to send to the client
725 serialised = m_channel.GetFloatsSerialised();
726 }
727
728 SendToClients(serialised, x, y);
729 shouldTaint = true;
730 } 896 }
731 } 897 }
732 } 898 }
733 if (shouldTaint) 899 return wasLimited;
734 {
735 m_scene.EventManager.TriggerTerrainTainted();
736 m_tainted = true;
737 }
738 } 900 }
739 901
740 /// <summary> 902 /// <summary>
@@ -742,11 +904,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
742 /// are all within the current estate limits 904 /// are all within the current estate limits
743 /// <returns>true if changes were limited, false otherwise</returns> 905 /// <returns>true if changes were limited, false otherwise</returns>
744 /// </summary> 906 /// </summary>
745 private bool LimitChannelChanges(int xStart, int yStart) 907 private bool LimitChannelChanges(TerrainData terrData, int xStart, int yStart)
746 { 908 {
747 bool changesLimited = false; 909 bool changesLimited = false;
748 double minDelta = m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; 910 float minDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit;
749 double maxDelta = m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; 911 float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit;
750 912
751 // loop through the height map for this patch and compare it against 913 // loop through the height map for this patch and compare it against
752 // the revert map 914 // the revert map
@@ -754,19 +916,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
754 { 916 {
755 for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) 917 for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
756 { 918 {
757 919 float requestedHeight = terrData[x, y];
758 double requestedHeight = m_channel[x, y]; 920 float bakedHeight = (float)m_revert[x, y];
759 double bakedHeight = m_revert[x, y]; 921 float requestedDelta = requestedHeight - bakedHeight;
760 double requestedDelta = requestedHeight - bakedHeight;
761 922
762 if (requestedDelta > maxDelta) 923 if (requestedDelta > maxDelta)
763 { 924 {
764 m_channel[x, y] = bakedHeight + maxDelta; 925 terrData[x, y] = bakedHeight + maxDelta;
765 changesLimited = true; 926 changesLimited = true;
766 } 927 }
767 else if (requestedDelta < minDelta) 928 else if (requestedDelta < minDelta)
768 { 929 {
769 m_channel[x, y] = bakedHeight + minDelta; //as lower is a -ve delta 930 terrData[x, y] = bakedHeight + minDelta; //as lower is a -ve delta
770 changesLimited = true; 931 changesLimited = true;
771 } 932 }
772 } 933 }
@@ -794,14 +955,154 @@ namespace OpenSim.Region.CoreModules.World.Terrain
794 /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> 955 /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param>
795 /// <param name="x">The patch corner to send</param> 956 /// <param name="x">The patch corner to send</param>
796 /// <param name="y">The patch corner to send</param> 957 /// <param name="y">The patch corner to send</param>
797 private void SendToClients(float[] serialised, int x, int y) 958 private void SendToClients(TerrainData terrData, int x, int y)
959 {
960 if (m_sendTerrainUpdatesByViewDistance)
961 {
962 // Add that this patch needs to be sent to the accounting for each client.
963 lock (m_perClientPatchUpdates)
964 {
965 m_scene.ForEachScenePresence(presence =>
966 {
967 PatchUpdates thisClientUpdates;
968 if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
969 {
970 // There is a ScenePresence without a send patch map. Create one.
971 thisClientUpdates = new PatchUpdates(terrData, presence);
972 m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
973 }
974 thisClientUpdates.SetByXY(x, y, true);
975 }
976 );
977 }
978 }
979 else
980 {
981 // Legacy update sending where the update is sent out as soon as noticed
982 // We know the actual terrain data passed is ignored. This kludge saves changing IClientAPI.
983 //float[] heightMap = terrData.GetFloatsSerialized();
984 float[] heightMap = new float[10];
985 m_scene.ForEachClient(
986 delegate(IClientAPI controller)
987 {
988 controller.SendLayerData(x / Constants.TerrainPatchSize,
989 y / Constants.TerrainPatchSize,
990 heightMap);
991 }
992 );
993 }
994 }
995
996 private class PatchesToSend : IComparable<PatchesToSend>
798 { 997 {
799 m_scene.ForEachClient( 998 public int PatchX;
800 delegate(IClientAPI controller) 999 public int PatchY;
801 { controller.SendLayerData( 1000 public float Dist;
802 x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); 1001 public PatchesToSend(int pX, int pY, float pDist)
1002 {
1003 PatchX = pX;
1004 PatchY = pY;
1005 Dist = pDist;
1006 }
1007 public int CompareTo(PatchesToSend other)
1008 {
1009 return Dist.CompareTo(other.Dist);
1010 }
1011 }
1012
1013 // Called each frame time to see if there are any patches to send to any of the
1014 // ScenePresences.
1015 // Loop through all the per-client info and send any patches necessary.
1016 private void CheckSendingPatchesToClients()
1017 {
1018 lock (m_perClientPatchUpdates)
1019 {
1020 foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
1021 {
1022 if (pups.HasUpdates())
1023 {
1024 // There is something that could be sent to this client.
1025 List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
1026 if (toSend.Count > 0)
1027 {
1028 // m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
1029 // LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
1030 // Sort the patches to send by the distance from the presence
1031 toSend.Sort();
1032 /*
1033 foreach (PatchesToSend pts in toSend)
1034 {
1035 pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null);
1036 // presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land);
1037 }
1038 */
1039
1040 int[] xPieces = new int[toSend.Count];
1041 int[] yPieces = new int[toSend.Count];
1042 float[] patchPieces = new float[toSend.Count * 2];
1043 int pieceIndex = 0;
1044 foreach (PatchesToSend pts in toSend)
1045 {
1046 patchPieces[pieceIndex++] = pts.PatchX;
1047 patchPieces[pieceIndex++] = pts.PatchY;
1048 }
1049 pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces);
1050 }
1051 }
1052 }
1053 }
1054 }
1055
1056 private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups)
1057 {
1058 List<PatchesToSend> ret = new List<PatchesToSend>();
1059
1060 ScenePresence presence = pups.Presence;
1061 if (presence == null)
1062 return ret;
1063
1064 // Compute the area of patches within our draw distance
1065 int startX = (((int) (presence.AbsolutePosition.X - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
1066 startX = Math.Max(startX, 0);
1067 startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
1068 int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
1069 startY = Math.Max(startY, 0);
1070 startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
1071 int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
1072 endX = Math.Max(endX, 0);
1073 endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
1074 int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
1075 endY = Math.Max(endY, 0);
1076 endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
1077 // m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>",
1078 // LogHeader, m_scene.RegionInfo.RegionName,
1079 // presence.DrawDistance, presence.AbsolutePosition,
1080 // startX, startY, endX, endY);
1081 for (int x = startX; x < endX; x++)
1082 {
1083 for (int y = startY; y < endY; y++)
1084 {
1085 //Need to make sure we don't send the same ones over and over
1086 Vector3 presencePos = presence.AbsolutePosition;
1087 Vector3 patchPos = new Vector3(x * Constants.TerrainPatchSize, y * Constants.TerrainPatchSize, presencePos.Z);
1088 if (pups.GetByPatch(x, y))
1089 {
1090 //Check which has less distance, camera or avatar position, both have to be done.
1091 //Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off
1092 if (Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50)
1093 || Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50))
1094 {
1095 //They can see it, send it to them
1096 pups.SetByPatch(x, y, false);
1097 float dist = Vector3.DistanceSquared(presencePos, patchPos);
1098 ret.Add(new PatchesToSend(x, y, dist));
1099 //Wait and send them all at once
1100 // pups.client.SendLayerData(x, y, null);
1101 }
803 } 1102 }
804 ); 1103 }
1104 }
1105 return ret;
805 } 1106 }
806 1107
807 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action, 1108 private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action,
@@ -846,7 +1147,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
846 m_painteffects[(StandardTerrainEffects) action].PaintEffect( 1147 m_painteffects[(StandardTerrainEffects) action].PaintEffect(
847 m_channel, allowMask, west, south, height, size, seconds); 1148 m_channel, allowMask, west, south, height, size, seconds);
848 1149
849 CheckForTerrainUpdates(!god); //revert changes outside estate limits 1150 //revert changes outside estate limits
1151 if (!god)
1152 EnforceEstateLimits();
850 } 1153 }
851 } 1154 }
852 else 1155 else
@@ -884,10 +1187,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
884 if (allowed) 1187 if (allowed)
885 { 1188 {
886 StoreUndoState(); 1189 StoreUndoState();
887 m_floodeffects[(StandardTerrainEffects) action].FloodEffect( 1190 m_floodeffects[(StandardTerrainEffects) action].FloodEffect(m_channel, fillArea, size);
888 m_channel, fillArea, size);
889 1191
890 CheckForTerrainUpdates(!god); //revert changes outside estate limits 1192 //revert changes outside estate limits
1193 if (!god)
1194 EnforceEstateLimits();
891 } 1195 }
892 } 1196 }
893 else 1197 else
@@ -911,7 +1215,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
911 protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) 1215 protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY)
912 { 1216 {
913 //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); 1217 //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
914 client.SendLayerData(patchX, patchY, m_scene.Heightmap.GetFloatsSerialised()); 1218 // SendLayerData does not use the heightmap parameter. This kludge is so as to not change IClientAPI.
1219 float[] heightMap = new float[10];
1220 client.SendLayerData(patchX, patchY, heightMap);
915 } 1221 }
916 1222
917 private void StoreUndoState() 1223 private void StoreUndoState()
@@ -938,7 +1244,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
938 private void InterfaceLoadFile(Object[] args) 1244 private void InterfaceLoadFile(Object[] args)
939 { 1245 {
940 LoadFromFile((string) args[0]); 1246 LoadFromFile((string) args[0]);
941 CheckForTerrainUpdates();
942 } 1247 }
943 1248
944 private void InterfaceLoadTileFile(Object[] args) 1249 private void InterfaceLoadTileFile(Object[] args)
@@ -948,7 +1253,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
948 (int) args[2], 1253 (int) args[2],
949 (int) args[3], 1254 (int) args[3],
950 (int) args[4]); 1255 (int) args[4]);
951 CheckForTerrainUpdates();
952 } 1256 }
953 1257
954 private void InterfaceSaveFile(Object[] args) 1258 private void InterfaceSaveFile(Object[] args)
@@ -977,7 +1281,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
977 for (y = 0; y < m_channel.Height; y++) 1281 for (y = 0; y < m_channel.Height; y++)
978 m_channel[x, y] = m_revert[x, y]; 1282 m_channel[x, y] = m_revert[x, y];
979 1283
980 CheckForTerrainUpdates();
981 } 1284 }
982 1285
983 private void InterfaceFlipTerrain(Object[] args) 1286 private void InterfaceFlipTerrain(Object[] args)
@@ -986,28 +1289,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
986 1289
987 if (direction.ToLower().StartsWith("y")) 1290 if (direction.ToLower().StartsWith("y"))
988 { 1291 {
989 for (int x = 0; x < Constants.RegionSize; x++) 1292 for (int x = 0; x < m_channel.Width; x++)
990 { 1293 {
991 for (int y = 0; y < Constants.RegionSize / 2; y++) 1294 for (int y = 0; y < m_channel.Height / 2; y++)
992 { 1295 {
993 double height = m_channel[x, y]; 1296 double height = m_channel[x, y];
994 double flippedHeight = m_channel[x, (int)Constants.RegionSize - 1 - y]; 1297 double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y];
995 m_channel[x, y] = flippedHeight; 1298 m_channel[x, y] = flippedHeight;
996 m_channel[x, (int)Constants.RegionSize - 1 - y] = height; 1299 m_channel[x, (int)m_channel.Height - 1 - y] = height;
997 1300
998 } 1301 }
999 } 1302 }
1000 } 1303 }
1001 else if (direction.ToLower().StartsWith("x")) 1304 else if (direction.ToLower().StartsWith("x"))
1002 { 1305 {
1003 for (int y = 0; y < Constants.RegionSize; y++) 1306 for (int y = 0; y < m_channel.Height; y++)
1004 { 1307 {
1005 for (int x = 0; x < Constants.RegionSize / 2; x++) 1308 for (int x = 0; x < m_channel.Width / 2; x++)
1006 { 1309 {
1007 double height = m_channel[x, y]; 1310 double height = m_channel[x, y];
1008 double flippedHeight = m_channel[(int)Constants.RegionSize - 1 - x, y]; 1311 double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y];
1009 m_channel[x, y] = flippedHeight; 1312 m_channel[x, y] = flippedHeight;
1010 m_channel[(int)Constants.RegionSize - 1 - x, y] = height; 1313 m_channel[(int)m_channel.Width - 1 - x, y] = height;
1011 1314
1012 } 1315 }
1013 } 1316 }
@@ -1016,9 +1319,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1016 { 1319 {
1017 m_log.Error("Unrecognised direction - need x or y"); 1320 m_log.Error("Unrecognised direction - need x or y");
1018 } 1321 }
1019
1020
1021 CheckForTerrainUpdates();
1022 } 1322 }
1023 1323
1024 private void InterfaceRescaleTerrain(Object[] args) 1324 private void InterfaceRescaleTerrain(Object[] args)
@@ -1076,7 +1376,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1076 } 1376 }
1077 } 1377 }
1078 1378
1079 CheckForTerrainUpdates();
1080 } 1379 }
1081 1380
1082 } 1381 }
@@ -1087,7 +1386,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1087 for (x = 0; x < m_channel.Width; x++) 1386 for (x = 0; x < m_channel.Width; x++)
1088 for (y = 0; y < m_channel.Height; y++) 1387 for (y = 0; y < m_channel.Height; y++)
1089 m_channel[x, y] += (double) args[0]; 1388 m_channel[x, y] += (double) args[0];
1090 CheckForTerrainUpdates();
1091 } 1389 }
1092 1390
1093 private void InterfaceMultiplyTerrain(Object[] args) 1391 private void InterfaceMultiplyTerrain(Object[] args)
@@ -1096,7 +1394,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1096 for (x = 0; x < m_channel.Width; x++) 1394 for (x = 0; x < m_channel.Width; x++)
1097 for (y = 0; y < m_channel.Height; y++) 1395 for (y = 0; y < m_channel.Height; y++)
1098 m_channel[x, y] *= (double) args[0]; 1396 m_channel[x, y] *= (double) args[0];
1099 CheckForTerrainUpdates();
1100 } 1397 }
1101 1398
1102 private void InterfaceLowerTerrain(Object[] args) 1399 private void InterfaceLowerTerrain(Object[] args)
@@ -1105,17 +1402,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1105 for (x = 0; x < m_channel.Width; x++) 1402 for (x = 0; x < m_channel.Width; x++)
1106 for (y = 0; y < m_channel.Height; y++) 1403 for (y = 0; y < m_channel.Height; y++)
1107 m_channel[x, y] -= (double) args[0]; 1404 m_channel[x, y] -= (double) args[0];
1108 CheckForTerrainUpdates();
1109 } 1405 }
1110 1406
1111 private void InterfaceFillTerrain(Object[] args) 1407 public void InterfaceFillTerrain(Object[] args)
1112 { 1408 {
1113 int x, y; 1409 int x, y;
1114 1410
1115 for (x = 0; x < m_channel.Width; x++) 1411 for (x = 0; x < m_channel.Width; x++)
1116 for (y = 0; y < m_channel.Height; y++) 1412 for (y = 0; y < m_channel.Height; y++)
1117 m_channel[x, y] = (double) args[0]; 1413 m_channel[x, y] = (double) args[0];
1118 CheckForTerrainUpdates();
1119 } 1414 }
1120 1415
1121 private void InterfaceMinTerrain(Object[] args) 1416 private void InterfaceMinTerrain(Object[] args)
@@ -1128,7 +1423,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1128 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); 1423 m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]);
1129 } 1424 }
1130 } 1425 }
1131 CheckForTerrainUpdates();
1132 } 1426 }
1133 1427
1134 private void InterfaceMaxTerrain(Object[] args) 1428 private void InterfaceMaxTerrain(Object[] args)
@@ -1141,7 +1435,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1141 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); 1435 m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]);
1142 } 1436 }
1143 } 1437 }
1144 CheckForTerrainUpdates();
1145 } 1438 }
1146 1439
1147 private void InterfaceShowDebugStats(Object[] args) 1440 private void InterfaceShowDebugStats(Object[] args)
@@ -1204,7 +1497,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
1204 if (m_plugineffects.ContainsKey(firstArg)) 1497 if (m_plugineffects.ContainsKey(firstArg))
1205 { 1498 {
1206 m_plugineffects[firstArg].RunEffect(m_channel); 1499 m_plugineffects[firstArg].RunEffect(m_channel);
1207 CheckForTerrainUpdates();
1208 } 1500 }
1209 else 1501 else
1210 { 1502 {
diff --git a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
index be719ea..062d7ff 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/Tests/TerrainTest.cs
@@ -40,10 +40,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
40 [Test] 40 [Test]
41 public void BrushTest() 41 public void BrushTest()
42 { 42 {
43 int midRegion = (int)Constants.RegionSize / 2;
44
45 // Create a mask that covers only the left half of the region
43 bool[,] allowMask = new bool[(int)Constants.RegionSize, 256]; 46 bool[,] allowMask = new bool[(int)Constants.RegionSize, 256];
44 int x; 47 int x;
45 int y; 48 int y;
46 for (x = 0; x < (int)((int)Constants.RegionSize * 0.5f); x++) 49 for (x = 0; x < midRegion; x++)
47 { 50 {
48 for (y = 0; y < (int)Constants.RegionSize; y++) 51 for (y = 0; y < (int)Constants.RegionSize; y++)
49 { 52 {
@@ -57,13 +60,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
57 TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); 60 TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize);
58 ITerrainPaintableEffect effect = new RaiseSphere(); 61 ITerrainPaintableEffect effect = new RaiseSphere();
59 62
60 effect.PaintEffect(map, allowMask, (int)Constants.RegionSize * 0.5f, (int)Constants.RegionSize * 0.5f, -1.0, 2, 0.1); 63 effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
61 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (127,128)."); 64 Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128).");
62 Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (124,128)."); 65 Assert.That(map[125, midRegion] > 0.0, "Raise brush should raising value at this point (124,128).");
63 Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (123,128)."); 66 Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128).");
64 Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (128,128)."); 67 Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128).");
65 Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (0,128)."); 68 Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128).");
66
67 // 69 //
68 // Test LowerSphere 70 // Test LowerSphere
69 // 71 //
@@ -77,13 +79,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
77 } 79 }
78 effect = new LowerSphere(); 80 effect = new LowerSphere();
79 81
80 effect.PaintEffect(map, allowMask, ((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), -1.0, 2, 6.0); 82 effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
81 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); 83 Assert.That(map[127, midRegion] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128).");
82 Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); 84 Assert.That(map[127, midRegion] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128).");
83 Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] < 1.0, "Lower brush should lowering value at this point (124,128)."); 85 Assert.That(map[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128).");
84 Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (123,128)."); 86 Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128).");
85 Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (128,128)."); 87 Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128).");
86 Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (0,128)."); 88 Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128).");
87 } 89 }
88 90
89 [Test] 91 [Test]