aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorUbitUmarov2015-08-19 08:48:50 +0100
committerUbitUmarov2015-08-19 08:48:50 +0100
commit0b105da626ae8c2fb519a817b827f90534ed7d08 (patch)
tree509e6d091fb12f38fd09528335e51aeedbe59c08
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
-rw-r--r--OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs6
-rw-r--r--OpenSim/Data/IRegionData.cs8
-rw-r--r--OpenSim/Data/MSSQL/MSSQLSimulationData.cs83
-rw-r--r--OpenSim/Data/MySQL/MySQLSimulationData.cs66
-rw-r--r--OpenSim/Data/Null/NullSimulationData.cs22
-rw-r--r--OpenSim/Data/PGSQL/PGSQLSimulationData.cs72
-rw-r--r--OpenSim/Data/SQLite/SQLiteSimulationData.cs54
-rw-r--r--OpenSim/Framework/MapBlockData.cs18
-rw-r--r--OpenSim/Framework/RegionInfo.cs32
-rw-r--r--OpenSim/Framework/TerrainData.cs464
-rw-r--r--OpenSim/Framework/UserProfileData.cs12
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs9
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs273
-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
-rw-r--r--OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs5
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs9
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs10
-rw-r--r--OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs19
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.Inventory.cs11
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs362
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs12
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs5
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs79
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs352
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainCompressor.cs948
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs2
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs2
-rw-r--r--OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs5
-rw-r--r--OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs33
-rw-r--r--OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs4
-rw-r--r--OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs17
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs14
-rw-r--r--OpenSim/Region/Physics/Manager/PhysicsScene.cs9
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs320
-rw-r--r--OpenSim/Region/RegionCombinerModule/RegionConnections.cs6
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs17
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs10
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs10
-rw-r--r--OpenSim/Server/Handlers/Map/MapAddServerConnector.cs2
-rw-r--r--OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs2
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs8
-rw-r--r--OpenSim/Services/Connectors/Simulation/SimulationDataService.cs10
-rw-r--r--OpenSim/Services/GridService/GridService.cs3
-rw-r--r--OpenSim/Services/GridService/HypergridLinker.cs55
-rw-r--r--OpenSim/Services/Interfaces/IGridService.cs16
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginResponse.cs24
-rw-r--r--OpenSim/Services/LLLoginService/LLLoginService.cs2
-rw-r--r--OpenSim/Tests/Clients/Grid/GridClient.cs8
-rw-r--r--OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs10
-rw-r--r--OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs29
76 files changed, 3541 insertions, 1878 deletions
diff --git a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
index e71e81c..2e128a7 100644
--- a/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
+++ b/OpenSim/ApplicationPlugins/RemoteController/RemoteAdminPlugin.cs
@@ -1157,7 +1157,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1157 // Set home position 1157 // Set home position
1158 1158
1159 GridRegion home = scene.GridService.GetRegionByPosition(scopeID, 1159 GridRegion home = scene.GridService.GetRegionByPosition(scopeID,
1160 (int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); 1160 (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation));
1161 if (null == home) 1161 if (null == home)
1162 { 1162 {
1163 m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", firstName, lastName); 1163 m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", firstName, lastName);
@@ -1387,7 +1387,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
1387 if ((null != regionXLocation) && (null != regionYLocation)) 1387 if ((null != regionXLocation) && (null != regionYLocation))
1388 { 1388 {
1389 GridRegion home = scene.GridService.GetRegionByPosition(scopeID, 1389 GridRegion home = scene.GridService.GetRegionByPosition(scopeID,
1390 (int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); 1390 (int)Util.RegionToWorldLoc((uint)regionXLocation), (int)Util.RegionToWorldLoc((uint)regionYLocation));
1391 if (null == home) { 1391 if (null == home) {
1392 m_log.WarnFormat("[RADMIN]: Unable to set home region for updated user account {0} {1}", firstName, lastName); 1392 m_log.WarnFormat("[RADMIN]: Unable to set home region for updated user account {0} {1}", firstName, lastName);
1393 } else { 1393 } else {
@@ -3118,7 +3118,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
3118 // Set home position 3118 // Set home position
3119 3119
3120 GridRegion home = scene.GridService.GetRegionByPosition(scopeID, 3120 GridRegion home = scene.GridService.GetRegionByPosition(scopeID,
3121 (int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); 3121 (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation));
3122 if (null == home) { 3122 if (null == home) {
3123 m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", names[0], names[1]); 3123 m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", names[0], names[1]);
3124 } else { 3124 } else {
diff --git a/OpenSim/Data/IRegionData.cs b/OpenSim/Data/IRegionData.cs
index 463c621..ca9b327 100644
--- a/OpenSim/Data/IRegionData.cs
+++ b/OpenSim/Data/IRegionData.cs
@@ -52,14 +52,14 @@ namespace OpenSim.Data
52 public int sizeY; 52 public int sizeY;
53 53
54 /// <summary> 54 /// <summary>
55 /// Return the x-coordinate of this region. 55 /// Return the x-coordinate of this region in region units.
56 /// </summary> 56 /// </summary>
57 public int coordX { get { return posX / (int)Constants.RegionSize; } } 57 public int coordX { get { return (int)Util.WorldToRegionLoc((uint)posX); } }
58 58
59 /// <summary> 59 /// <summary>
60 /// Return the y-coordinate of this region. 60 /// Return the y-coordinate of this region in region units.
61 /// </summary> 61 /// </summary>
62 public int coordY { get { return posY / (int)Constants.RegionSize; } } 62 public int coordY { get { return (int)Util.WorldToRegionLoc((uint)posY); } }
63 63
64 public Dictionary<string, object> Data; 64 public Dictionary<string, object> Data;
65 } 65 }
diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
index 0d09be6..145b9c0 100644
--- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
@@ -530,43 +530,52 @@ ELSE
530 /// <returns></returns> 530 /// <returns></returns>
531 public double[,] LoadTerrain(UUID regionID) 531 public double[,] LoadTerrain(UUID regionID)
532 { 532 {
533 double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; 533 double[,] ret = null;
534 terrain.Initialize(); 534 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
535 if (terrData != null)
536 ret = terrData.GetDoubles();
537 return ret;
538 }
539
540 // Returns 'null' if region not found
541 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
542 {
543 TerrainData terrData = null;
535 544
536 string sql = "select top 1 RegionUUID, Revision, Heightfield from terrain where RegionUUID = @RegionUUID order by Revision desc"; 545 string sql = "select top 1 RegionUUID, Revision, Heightfield from terrain where RegionUUID = @RegionUUID order by Revision desc";
537 546
538 using (SqlConnection conn = new SqlConnection(m_connectionString)) 547 using (SqlConnection conn = new SqlConnection(m_connectionString))
539 using (SqlCommand cmd = new SqlCommand(sql, conn))
540 { 548 {
541 // MySqlParameter param = new MySqlParameter(); 549 using (SqlCommand cmd = new SqlCommand(sql, conn))
542 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
543 conn.Open();
544 using (SqlDataReader reader = cmd.ExecuteReader())
545 { 550 {
546 int rev; 551 // MySqlParameter param = new MySqlParameter();
547 if (reader.Read()) 552 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
553 conn.Open();
554 using (SqlDataReader reader = cmd.ExecuteReader())
548 { 555 {
549 MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); 556 if (reader.Read())
550 BinaryReader br = new BinaryReader(str);
551 for (int x = 0; x < (int)Constants.RegionSize; x++)
552 { 557 {
553 for (int y = 0; y < (int)Constants.RegionSize; y++) 558 int rev = (int)reader["Revision"];
554 { 559 byte[] blob = (byte[])reader["Heightfield"];
555 terrain[x, y] = br.ReadDouble(); 560 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
556 }
557 } 561 }
558 rev = (int)reader["Revision"]; 562 else
559 } 563 {
560 else 564 _Log.Info("[REGION DB]: No terrain found for region");
561 { 565 return null;
562 _Log.Info("[REGION DB]: No terrain found for region"); 566 }
563 return null; 567 _Log.Info("[REGION DB]: Loaded terrain");
564 } 568 }
565 _Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
566 } 569 }
567 } 570 }
568 571
569 return terrain; 572 return terrData;
573 }
574
575 // Legacy entry point for when terrain was always a 256x256 hieghtmap
576 public void StoreTerrain(double[,] ter, UUID regionID)
577 {
578 StoreTerrain(new HeightmapTerrainData(ter), regionID);
570 } 579 }
571 580
572 /// <summary> 581 /// <summary>
@@ -574,10 +583,8 @@ ELSE
574 /// </summary> 583 /// </summary>
575 /// <param name="terrain">terrain map data.</param> 584 /// <param name="terrain">terrain map data.</param>
576 /// <param name="regionID">regionID.</param> 585 /// <param name="regionID">regionID.</param>
577 public void StoreTerrain(double[,] terrain, UUID regionID) 586 public void StoreTerrain(TerrainData terrData, UUID regionID)
578 { 587 {
579 int revision = Util.UnixTimeSinceEpoch();
580
581 //Delete old terrain map 588 //Delete old terrain map
582 string sql = "delete from terrain where RegionUUID=@RegionUUID"; 589 string sql = "delete from terrain where RegionUUID=@RegionUUID";
583 using (SqlConnection conn = new SqlConnection(m_connectionString)) 590 using (SqlConnection conn = new SqlConnection(m_connectionString))
@@ -590,17 +597,23 @@ ELSE
590 597
591 sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)"; 598 sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)";
592 599
600 int terrainDBRevision;
601 Array terrainDBblob;
602 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
603
593 using (SqlConnection conn = new SqlConnection(m_connectionString)) 604 using (SqlConnection conn = new SqlConnection(m_connectionString))
594 using (SqlCommand cmd = new SqlCommand(sql, conn))
595 { 605 {
596 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID)); 606 using (SqlCommand cmd = new SqlCommand(sql, conn))
597 cmd.Parameters.Add(_Database.CreateParameter("@Revision", revision)); 607 {
598 cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", serializeTerrain(terrain))); 608 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
599 conn.Open(); 609 cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision));
600 cmd.ExecuteNonQuery(); 610 cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob));
611 conn.Open();
612 cmd.ExecuteNonQuery();
613 }
601 } 614 }
602 615
603 _Log.Info("[REGION DB]: Stored terrain revision r " + revision); 616 _Log.Info("[REGION DB]: Stored terrain");
604 } 617 }
605 618
606 /// <summary> 619 /// <summary>
@@ -1344,6 +1357,7 @@ VALUES
1344 1357
1345 #region Private Methods 1358 #region Private Methods
1346 1359
1360 /*
1347 /// <summary> 1361 /// <summary>
1348 /// Serializes the terrain data for storage in DB. 1362 /// Serializes the terrain data for storage in DB.
1349 /// </summary> 1363 /// </summary>
@@ -1367,6 +1381,7 @@ VALUES
1367 1381
1368 return str.ToArray(); 1382 return str.ToArray();
1369 } 1383 }
1384 */
1370 1385
1371 /// <summary> 1386 /// <summary>
1372 /// Stores new regionsettings. 1387 /// Stores new regionsettings.
diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index cc844ae..f910e44 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -48,8 +48,18 @@ namespace OpenSim.Data.MySQL
48 public class MySQLSimulationData : ISimulationDataStore 48 public class MySQLSimulationData : ISimulationDataStore
49 { 49 {
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 private static string LogHeader = "[REGION DB MYSQL]";
51 52
52 private string m_connectionString; 53 private string m_connectionString;
54
55 /// <summary>
56 /// This lock was being used to serialize database operations when the connection was shared, but this has
57 /// been unnecessary for a long time after we switched to using MySQL's underlying connection pooling instead.
58 /// FIXME: However, the locks remain in many places since they are effectively providing a level of
59 /// transactionality. This should be replaced by more efficient database transactions which would not require
60 /// unrelated operations to block each other or unrelated operations on the same tables from blocking each
61 /// other.
62 /// </summary>
53 private object m_dbLock = new object(); 63 private object m_dbLock = new object();
54 64
55 protected virtual Assembly Assembly 65 protected virtual Assembly Assembly
@@ -91,7 +101,7 @@ namespace OpenSim.Data.MySQL
91 } 101 }
92 catch (Exception e) 102 catch (Exception e)
93 { 103 {
94 m_log.Error("[REGION DB]: MySQL error in ExecuteReader: " + e.Message); 104 m_log.ErrorFormat("{0} MySQL error in ExecuteReader: {1}", LogHeader, e);
95 throw; 105 throw;
96 } 106 }
97 107
@@ -574,12 +584,16 @@ namespace OpenSim.Data.MySQL
574 } 584 }
575 } 585 }
576 586
577 public virtual void StoreTerrain(double[,] ter, UUID regionID) 587 // Legacy entry point for when terrain was always a 256x256 hieghtmap
588 public void StoreTerrain(double[,] ter, UUID regionID)
589 {
590 StoreTerrain(new HeightmapTerrainData(ter), regionID);
591 }
592
593 public void StoreTerrain(TerrainData terrData, UUID regionID)
578 { 594 {
579 Util.FireAndForget(delegate(object x) 595 Util.FireAndForget(delegate(object x)
580 { 596 {
581 double[,] oldTerrain = LoadTerrain(regionID);
582
583 m_log.Info("[REGION DB]: Storing terrain"); 597 m_log.Info("[REGION DB]: Storing terrain");
584 598
585 lock (m_dbLock) 599 lock (m_dbLock)
@@ -601,8 +615,12 @@ namespace OpenSim.Data.MySQL
601 "Revision, Heightfield) values (?RegionUUID, " + 615 "Revision, Heightfield) values (?RegionUUID, " +
602 "1, ?Heightfield)"; 616 "1, ?Heightfield)";
603 617
604 cmd2.Parameters.AddWithValue("RegionUUID", regionID.ToString()); 618 int terrainDBRevision;
605 cmd2.Parameters.AddWithValue("Heightfield", SerializeTerrain(ter, oldTerrain)); 619 Array terrainDBblob;
620 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
621
622 cmd2.Parameters.AddWithValue("Revision", terrainDBRevision);
623 cmd2.Parameters.AddWithValue("Heightfield", terrainDBblob);
606 624
607 ExecuteNonQuery(cmd); 625 ExecuteNonQuery(cmd);
608 ExecuteNonQuery(cmd2); 626 ExecuteNonQuery(cmd2);
@@ -618,9 +636,20 @@ namespace OpenSim.Data.MySQL
618 }); 636 });
619 } 637 }
620 638
639 // Legacy region loading
621 public virtual double[,] LoadTerrain(UUID regionID) 640 public virtual double[,] LoadTerrain(UUID regionID)
622 { 641 {
623 double[,] terrain = null; 642 double[,] ret = null;
643 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
644 if (terrData != null)
645 ret = terrData.GetDoubles();
646 return ret;
647 }
648
649 // Returns 'null' if region not found
650 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
651 {
652 TerrainData terrData = null;
624 653
625 lock (m_dbLock) 654 lock (m_dbLock)
626 { 655 {
@@ -640,32 +669,15 @@ namespace OpenSim.Data.MySQL
640 while (reader.Read()) 669 while (reader.Read())
641 { 670 {
642 int rev = Convert.ToInt32(reader["Revision"]); 671 int rev = Convert.ToInt32(reader["Revision"]);
643 672 byte[] blob = (byte[])reader["Heightfield"];
644 terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; 673 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
645 terrain.Initialize();
646
647 using (MemoryStream mstr = new MemoryStream((byte[])reader["Heightfield"]))
648 {
649 using (BinaryReader br = new BinaryReader(mstr))
650 {
651 for (int x = 0; x < (int)Constants.RegionSize; x++)
652 {
653 for (int y = 0; y < (int)Constants.RegionSize; y++)
654 {
655 terrain[x, y] = br.ReadDouble();
656 }
657 }
658 }
659
660 m_log.InfoFormat("[REGION DB]: Loaded terrain revision r{0}", rev);
661 }
662 } 674 }
663 } 675 }
664 } 676 }
665 } 677 }
666 } 678 }
667 679
668 return terrain; 680 return terrData;
669 } 681 }
670 682
671 public virtual void RemoveLandObject(UUID globalID) 683 public virtual void RemoveLandObject(UUID globalID)
diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs
index 15824a9..339e7f4 100644
--- a/OpenSim/Data/Null/NullSimulationData.cs
+++ b/OpenSim/Data/Null/NullSimulationData.cs
@@ -132,18 +132,36 @@ namespace OpenSim.Data.Null
132 return new List<SceneObjectGroup>(); 132 return new List<SceneObjectGroup>();
133 } 133 }
134 134
135 Dictionary<UUID, double[,]> m_terrains = new Dictionary<UUID, double[,]>(); 135 Dictionary<UUID, TerrainData> m_terrains = new Dictionary<UUID, TerrainData>();
136 public void StoreTerrain(double[,] ter, UUID regionID) 136 public void StoreTerrain(TerrainData ter, UUID regionID)
137 { 137 {
138 if (m_terrains.ContainsKey(regionID)) 138 if (m_terrains.ContainsKey(regionID))
139 m_terrains.Remove(regionID); 139 m_terrains.Remove(regionID);
140 m_terrains.Add(regionID, ter); 140 m_terrains.Add(regionID, ter);
141 } 141 }
142 142
143 // Legacy. Just don't do this.
144 public void StoreTerrain(double[,] ter, UUID regionID)
145 {
146 TerrainData terrData = new HeightmapTerrainData(ter);
147 StoreTerrain(terrData, regionID);
148 }
149
150 // Legacy. Just don't do this.
151 // Returns 'null' if region not found
143 public double[,] LoadTerrain(UUID regionID) 152 public double[,] LoadTerrain(UUID regionID)
144 { 153 {
145 if (m_terrains.ContainsKey(regionID)) 154 if (m_terrains.ContainsKey(regionID))
146 { 155 {
156 return m_terrains[regionID].GetDoubles();
157 }
158 return null;
159 }
160
161 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
162 {
163 if (m_terrains.ContainsKey(regionID))
164 {
147 return m_terrains[regionID]; 165 return m_terrains[regionID];
148 } 166 }
149 return null; 167 return null;
diff --git a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs
index 3243635..cd02e05 100644
--- a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs
+++ b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs
@@ -46,6 +46,7 @@ namespace OpenSim.Data.PGSQL
46 public class PGSQLSimulationData : ISimulationDataStore 46 public class PGSQLSimulationData : ISimulationDataStore
47 { 47 {
48 private const string _migrationStore = "RegionStore"; 48 private const string _migrationStore = "RegionStore";
49 private const string LogHeader = "[REGION DB PGSQL]";
49 50
50 // private static FileSystemDataStore Instance = new FileSystemDataStore(); 51 // private static FileSystemDataStore Instance = new FileSystemDataStore();
51 private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 52 private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -523,8 +524,17 @@ namespace OpenSim.Data.PGSQL
523 /// <returns></returns> 524 /// <returns></returns>
524 public double[,] LoadTerrain(UUID regionID) 525 public double[,] LoadTerrain(UUID regionID)
525 { 526 {
526 double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; 527 double[,] ret = null;
527 terrain.Initialize(); 528 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
529 if (terrData != null)
530 ret = terrData.GetDoubles();
531 return ret;
532 }
533
534 // Returns 'null' if region not found
535 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
536 {
537 TerrainData terrData = null;
528 538
529 string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain 539 string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain
530 where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; "; 540 where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; ";
@@ -540,16 +550,9 @@ namespace OpenSim.Data.PGSQL
540 int rev; 550 int rev;
541 if (reader.Read()) 551 if (reader.Read())
542 { 552 {
543 MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); 553 rev = Convert.ToInt32(reader["Revision"]);
544 BinaryReader br = new BinaryReader(str); 554 byte[] blob = (byte[])reader["Heightfield"];
545 for (int x = 0; x < (int)Constants.RegionSize; x++) 555 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
546 {
547 for (int y = 0; y < (int)Constants.RegionSize; y++)
548 {
549 terrain[x, y] = br.ReadDouble();
550 }
551 }
552 rev = (int)reader["Revision"];
553 } 556 }
554 else 557 else
555 { 558 {
@@ -560,7 +563,13 @@ namespace OpenSim.Data.PGSQL
560 } 563 }
561 } 564 }
562 565
563 return terrain; 566 return terrData;
567 }
568
569 // Legacy entry point for when terrain was always a 256x256 heightmap
570 public void StoreTerrain(double[,] terrain, UUID regionID)
571 {
572 StoreTerrain(new HeightmapTerrainData(terrain), regionID);
564 } 573 }
565 574
566 /// <summary> 575 /// <summary>
@@ -568,35 +577,38 @@ namespace OpenSim.Data.PGSQL
568 /// </summary> 577 /// </summary>
569 /// <param name="terrain">terrain map data.</param> 578 /// <param name="terrain">terrain map data.</param>
570 /// <param name="regionID">regionID.</param> 579 /// <param name="regionID">regionID.</param>
571 public void StoreTerrain(double[,] terrain, UUID regionID) 580 public void StoreTerrain(TerrainData terrData, UUID regionID)
572 { 581 {
573 int revision = Util.UnixTimeSinceEpoch();
574
575 //Delete old terrain map 582 //Delete old terrain map
576 string sql = @"delete from terrain where ""RegionUUID""=:RegionUUID"; 583 string sql = @"delete from terrain where ""RegionUUID""=:RegionUUID";
577 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) 584 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
578 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
579 { 585 {
580 cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID)); 586 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
581 conn.Open(); 587 {
582 cmd.ExecuteNonQuery(); 588 cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
589 conn.Open();
590 cmd.ExecuteNonQuery();
591 }
583 } 592 }
584 593 int terrainDBRevision;
585 _Log.Info("[REGION DB]: Deleted terrain revision r " + revision); 594 Array terrainDBblob;
595 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
586 596
587 sql = @"insert into terrain(""RegionUUID"", ""Revision"", ""Heightfield"") values(:RegionUUID, :Revision, :Heightfield)"; 597 sql = @"insert into terrain(""RegionUUID"", ""Revision"", ""Heightfield"") values(:RegionUUID, :Revision, :Heightfield)";
588 598
589 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) 599 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
590 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
591 { 600 {
592 cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID)); 601 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
593 cmd.Parameters.Add(_Database.CreateParameter("Revision", revision)); 602 {
594 cmd.Parameters.Add(_Database.CreateParameter("Heightfield", serializeTerrain(terrain))); 603 cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
595 conn.Open(); 604 cmd.Parameters.Add(_Database.CreateParameter("Revision", terrainDBRevision));
596 cmd.ExecuteNonQuery(); 605 cmd.Parameters.Add(_Database.CreateParameter("Heightfield", terrainDBblob));
606 conn.Open();
607 cmd.ExecuteNonQuery();
608 }
597 } 609 }
598 610
599 _Log.Info("[REGION DB]: Stored terrain revision r " + revision); 611 _Log.Info("[REGION DB]: Stored terrain revision r " + terrainDBRevision);
600 } 612 }
601 613
602 /// <summary> 614 /// <summary>
@@ -1349,6 +1361,7 @@ namespace OpenSim.Data.PGSQL
1349 1361
1350 #region Private Methods 1362 #region Private Methods
1351 1363
1364 /*
1352 /// <summary> 1365 /// <summary>
1353 /// Serializes the terrain data for storage in DB. 1366 /// Serializes the terrain data for storage in DB.
1354 /// </summary> 1367 /// </summary>
@@ -1372,6 +1385,7 @@ namespace OpenSim.Data.PGSQL
1372 1385
1373 return str.ToArray(); 1386 return str.ToArray();
1374 } 1387 }
1388 */
1375 1389
1376 /// <summary> 1390 /// <summary>
1377 /// Stores new regionsettings. 1391 /// Stores new regionsettings.
diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
index 4d6a80a..d28c227 100644
--- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs
+++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
@@ -51,6 +51,7 @@ namespace OpenSim.Data.SQLite
51 public class SQLiteSimulationData : ISimulationDataStore 51 public class SQLiteSimulationData : ISimulationDataStore
52 { 52 {
53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 53 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 private static readonly string LogHeader = "[REGION DB SQLLITE]";
54 55
55 private const string primSelect = "select * from prims"; 56 private const string primSelect = "select * from prims";
56 private const string shapeSelect = "select * from primshapes"; 57 private const string shapeSelect = "select * from primshapes";
@@ -819,12 +820,18 @@ namespace OpenSim.Data.SQLite
819 prim.Inventory.RestoreInventoryItems(inventory); 820 prim.Inventory.RestoreInventoryItems(inventory);
820 } 821 }
821 822
823 // Legacy entry point for when terrain was always a 256x256 hieghtmap
824 public void StoreTerrain(double[,] ter, UUID regionID)
825 {
826 StoreTerrain(new HeightmapTerrainData(ter), regionID);
827 }
828
822 /// <summary> 829 /// <summary>
823 /// Store a terrain revision in region storage 830 /// Store a terrain revision in region storage
824 /// </summary> 831 /// </summary>
825 /// <param name="ter">terrain heightfield</param> 832 /// <param name="ter">terrain heightfield</param>
826 /// <param name="regionID">region UUID</param> 833 /// <param name="regionID">region UUID</param>
827 public void StoreTerrain(double[,] ter, UUID regionID) 834 public void StoreTerrain(TerrainData terrData, UUID regionID)
828 { 835 {
829 lock (ds) 836 lock (ds)
830 { 837 {
@@ -853,11 +860,17 @@ namespace OpenSim.Data.SQLite
853 String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" + 860 String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" +
854 " values(:RegionUUID, :Revision, :Heightfield)"; 861 " values(:RegionUUID, :Revision, :Heightfield)";
855 862
863 int terrainDBRevision;
864 Array terrainDBblob;
865 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
866
867 m_log.DebugFormat("{0} Storing terrain revision r {1}", LogHeader, terrainDBRevision);
868
856 using (SqliteCommand cmd = new SqliteCommand(sql, m_conn)) 869 using (SqliteCommand cmd = new SqliteCommand(sql, m_conn))
857 { 870 {
858 cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString())); 871 cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString()));
859 cmd.Parameters.Add(new SqliteParameter(":Revision", revision)); 872 cmd.Parameters.Add(new SqliteParameter(":Revision", terrainDBRevision));
860 cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter))); 873 cmd.Parameters.Add(new SqliteParameter(":Heightfield", terrainDBblob));
861 cmd.ExecuteNonQuery(); 874 cmd.ExecuteNonQuery();
862 } 875 }
863 } 876 }
@@ -870,11 +883,20 @@ namespace OpenSim.Data.SQLite
870 /// <returns>Heightfield data</returns> 883 /// <returns>Heightfield data</returns>
871 public double[,] LoadTerrain(UUID regionID) 884 public double[,] LoadTerrain(UUID regionID)
872 { 885 {
886 double[,] ret = null;
887 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
888 if (terrData != null)
889 ret = terrData.GetDoubles();
890 return ret;
891 }
892
893 // Returns 'null' if region not found
894 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
895 {
896 TerrainData terrData = null;
897
873 lock (ds) 898 lock (ds)
874 { 899 {
875 double[,] terret = new double[(int)Constants.RegionSize, (int)Constants.RegionSize];
876 terret.Initialize();
877
878 String sql = "select RegionUUID, Revision, Heightfield from terrain" + 900 String sql = "select RegionUUID, Revision, Heightfield from terrain" +
879 " where RegionUUID=:RegionUUID order by Revision desc"; 901 " where RegionUUID=:RegionUUID order by Revision desc";
880 902
@@ -887,21 +909,9 @@ namespace OpenSim.Data.SQLite
887 int rev = 0; 909 int rev = 0;
888 if (row.Read()) 910 if (row.Read())
889 { 911 {
890 // TODO: put this into a function
891 using (MemoryStream str = new MemoryStream((byte[])row["Heightfield"]))
892 {
893 using (BinaryReader br = new BinaryReader(str))
894 {
895 for (int x = 0; x < (int)Constants.RegionSize; x++)
896 {
897 for (int y = 0; y < (int)Constants.RegionSize; y++)
898 {
899 terret[x, y] = br.ReadDouble();
900 }
901 }
902 }
903 }
904 rev = Convert.ToInt32(row["Revision"]); 912 rev = Convert.ToInt32(row["Revision"]);
913 byte[] blob = (byte[])row["Heightfield"];
914 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
905 } 915 }
906 else 916 else
907 { 917 {
@@ -912,8 +922,8 @@ namespace OpenSim.Data.SQLite
912 m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString()); 922 m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString());
913 } 923 }
914 } 924 }
915 return terret;
916 } 925 }
926 return terrData;
917 } 927 }
918 928
919 public void RemoveLandObject(UUID globalID) 929 public void RemoveLandObject(UUID globalID)
@@ -2016,6 +2026,7 @@ namespace OpenSim.Data.SQLite
2016 return entry; 2026 return entry;
2017 } 2027 }
2018 2028
2029 /*
2019 /// <summary> 2030 /// <summary>
2020 /// 2031 ///
2021 /// </summary> 2032 /// </summary>
@@ -2033,6 +2044,7 @@ namespace OpenSim.Data.SQLite
2033 2044
2034 return str.ToArray(); 2045 return str.ToArray();
2035 } 2046 }
2047 */
2036 2048
2037 // private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val) 2049 // private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val)
2038 // { 2050 // {
diff --git a/OpenSim/Framework/MapBlockData.cs b/OpenSim/Framework/MapBlockData.cs
index 2298ac5..4bee499 100644
--- a/OpenSim/Framework/MapBlockData.cs
+++ b/OpenSim/Framework/MapBlockData.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using OpenMetaverse; 29using OpenMetaverse;
30using OpenMetaverse.StructuredData;
30 31
31namespace OpenSim.Framework 32namespace OpenSim.Framework
32{ 33{
@@ -40,9 +41,26 @@ namespace OpenSim.Framework
40 public byte WaterHeight; 41 public byte WaterHeight;
41 public ushort X; 42 public ushort X;
42 public ushort Y; 43 public ushort Y;
44 public ushort SizeX;
45 public ushort SizeY;
43 46
44 public MapBlockData() 47 public MapBlockData()
45 { 48 {
46 } 49 }
50
51 public OSDMap ToOSD()
52 {
53 OSDMap map = new OSDMap();
54 map["X"] = X;
55 map["Y"] = Y;
56 map["SizeX"] = SizeX;
57 map["SizeY"] = SizeY;
58 map["Name"] = Name;
59 map["Access"] = Access;
60 map["RegionFlags"] = RegionFlags;
61 map["WaterHeight"] = WaterHeight;
62 map["MapImageID"] = MapImageId;
63 return map;
64 }
47 } 65 }
48} 66}
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs
index ae2ff63..019fffc 100644
--- a/OpenSim/Framework/RegionInfo.cs
+++ b/OpenSim/Framework/RegionInfo.cs
@@ -149,11 +149,32 @@ namespace OpenSim.Framework
149 public uint WorldLocX = 0; 149 public uint WorldLocX = 0;
150 public uint WorldLocY = 0; 150 public uint WorldLocY = 0;
151 public uint WorldLocZ = 0; 151 public uint WorldLocZ = 0;
152
153 /// <summary>
154 /// X dimension of the region.
155 /// </summary>
156 /// <remarks>
157 /// If this is a varregion then the default size set here will be replaced when we load the region config.
158 /// </remarks>
152 public uint RegionSizeX = Constants.RegionSize; 159 public uint RegionSizeX = Constants.RegionSize;
160
161 /// <summary>
162 /// X dimension of the region.
163 /// </summary>
164 /// <remarks>
165 /// If this is a varregion then the default size set here will be replaced when we load the region config.
166 /// </remarks>
153 public uint RegionSizeY = Constants.RegionSize; 167 public uint RegionSizeY = Constants.RegionSize;
168
169 /// <summary>
170 /// Z dimension of the region.
171 /// </summary>
172 /// <remarks>
173 /// XXX: Unknown if this accounts for regions with negative Z.
174 /// </remarks>
154 public uint RegionSizeZ = Constants.RegionHeight; 175 public uint RegionSizeZ = Constants.RegionHeight;
155 176
156 private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>(); 177 private Dictionary<String, String> m_extraSettings = new Dictionary<string, string>();
157 178
158 // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. 179 // Apparently, we're applying the same estatesettings regardless of whether it's local or remote.
159 180
@@ -506,16 +527,16 @@ namespace OpenSim.Framework
506 { 527 {
507 string val; 528 string val;
508 string keylower = key.ToLower(); 529 string keylower = key.ToLower();
509 if (m_otherSettings.TryGetValue(keylower, out val)) 530 if (m_extraSettings.TryGetValue(keylower, out val))
510 return val; 531 return val;
511 m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key); 532 m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key);
512 return null; 533 return null;
513 } 534 }
514 535
515 public void SetOtherSetting(string key, string value) 536 public void SetExtraSetting(string key, string value)
516 { 537 {
517 string keylower = key.ToLower(); 538 string keylower = key.ToLower();
518 m_otherSettings[keylower] = value; 539 m_extraSettings[keylower] = value;
519 } 540 }
520 541
521 private void ReadNiniConfig(IConfigSource source, string name) 542 private void ReadNiniConfig(IConfigSource source, string name)
@@ -733,7 +754,7 @@ namespace OpenSim.Framework
733 754
734 foreach (String s in allKeys) 755 foreach (String s in allKeys)
735 { 756 {
736 SetOtherSetting(s, config.GetString(s)); 757 SetExtraSetting(s, config.GetString(s));
737 } 758 }
738 } 759 }
739 760
@@ -804,6 +825,7 @@ namespace OpenSim.Framework
804 825
805 if (DataStore != String.Empty) 826 if (DataStore != String.Empty)
806 config.Set("Datastore", DataStore); 827 config.Set("Datastore", DataStore);
828
807 if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize) 829 if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize)
808 { 830 {
809 config.Set("SizeX", RegionSizeX); 831 config.Set("SizeX", RegionSizeX);
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs
new file mode 100644
index 0000000..6b1be4e
--- /dev/null
+++ b/OpenSim/Framework/TerrainData.cs
@@ -0,0 +1,464 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32
33using OpenMetaverse;
34
35using log4net;
36
37namespace OpenSim.Framework
38{
39 public abstract class TerrainData
40 {
41 // Terrain always is a square
42 public int SizeX { get; protected set; }
43 public int SizeY { get; protected set; }
44 public int SizeZ { get; protected set; }
45
46 // A height used when the user doesn't specify anything
47 public const float DefaultTerrainHeight = 21f;
48
49 public abstract float this[int x, int y] { get; set; }
50 // Someday terrain will have caves
51 public abstract float this[int x, int y, int z] { get; set; }
52
53 public abstract bool IsTaintedAt(int xx, int yy);
54 public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest);
55 public abstract void TaintAllTerrain();
56 public abstract void ClearTaint();
57
58 public abstract void ClearLand();
59 public abstract void ClearLand(float height);
60
61 // Return a representation of this terrain for storing as a blob in the database.
62 // Returns 'true' to say blob was stored in the 'out' locations.
63 public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
64
65 // Given a revision code and a blob from the database, create and return the right type of TerrainData.
66 // The sizes passed are the expected size of the region. The database info will be used to
67 // initialize the heightmap of that sized region with as much data is in the blob.
68 // Return created TerrainData or 'null' if unsuccessful.
69 public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
70 {
71 // For the moment, there is only one implementation class
72 return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob);
73 }
74
75 // return a special compressed representation of the heightmap in ints
76 public abstract int[] GetCompressedMap();
77 public abstract float CompressionFactor { get; }
78
79 public abstract float[] GetFloatsSerialized();
80 public abstract double[,] GetDoubles();
81 public abstract TerrainData Clone();
82 }
83
84 // The terrain is stored in the database as a blob with a 'revision' field.
85 // Some implementations of terrain storage would fill the revision field with
86 // the time the terrain was stored. When real revisions were added and this
87 // feature removed, that left some old entries with the time in the revision
88 // field.
89 // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
90 // left over and it is presumed to be 'Legacy256'.
91 // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
92 // If a revision does not match any of these, it is assumed to be Legacy256.
93 public enum DBTerrainRevision
94 {
95 // Terrain is 'double[256,256]'
96 Legacy256 = 11,
97 // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions
98 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
99 Variable2D = 22,
100 // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions
101 // and third int is the 'compression factor'. The heights are compressed as
102 // "int compressedHeight = (int)(height * compressionFactor);"
103 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
104 Compressed2D = 27,
105 // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
106 RevisionHigh = 1234
107 }
108
109 // Version of terrain that is a heightmap.
110 // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
111 // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
112 // The heighmap is kept as an array of integers. The integer values are converted to
113 // and from floats by TerrainCompressionFactor.
114 public class HeightmapTerrainData : TerrainData
115 {
116 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
117 private static string LogHeader = "[HEIGHTMAP TERRAIN DATA]";
118
119 // TerrainData.this[x, y]
120 public override float this[int x, int y]
121 {
122 get { return FromCompressedHeight(m_heightmap[x, y]); }
123 set {
124 int newVal = ToCompressedHeight(value);
125 if (m_heightmap[x, y] != newVal)
126 {
127 m_heightmap[x, y] = newVal;
128 m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
129 }
130 }
131 }
132
133 // TerrainData.this[x, y, z]
134 public override float this[int x, int y, int z]
135 {
136 get { return this[x, y]; }
137 set { this[x, y] = value; }
138 }
139
140 // TerrainData.ClearTaint
141 public override void ClearTaint()
142 {
143 SetAllTaint(false);
144 }
145
146 // TerrainData.TaintAllTerrain
147 public override void TaintAllTerrain()
148 {
149 SetAllTaint(true);
150 }
151
152 private void SetAllTaint(bool setting)
153 {
154 for (int ii = 0; ii < m_taint.GetLength(0); ii++)
155 for (int jj = 0; jj < m_taint.GetLength(1); jj++)
156 m_taint[ii, jj] = setting;
157 }
158
159 // TerrainData.ClearLand
160 public override void ClearLand()
161 {
162 ClearLand(DefaultTerrainHeight);
163 }
164 // TerrainData.ClearLand(float)
165 public override void ClearLand(float pHeight)
166 {
167 int flatHeight = ToCompressedHeight(pHeight);
168 for (int xx = 0; xx < SizeX; xx++)
169 for (int yy = 0; yy < SizeY; yy++)
170 m_heightmap[xx, yy] = flatHeight;
171 }
172
173 // Return 'true' of the patch that contains these region coordinates has been modified.
174 // Note that checking the taint clears it.
175 // There is existing code that relies on this feature.
176 public override bool IsTaintedAt(int xx, int yy, bool clearOnTest)
177 {
178 int tx = xx / Constants.TerrainPatchSize;
179 int ty = yy / Constants.TerrainPatchSize;
180 bool ret = m_taint[tx, ty];
181 if (ret && clearOnTest)
182 m_taint[tx, ty] = false;
183 return ret;
184 }
185
186 // Old form that clears the taint flag when we check it.
187 public override bool IsTaintedAt(int xx, int yy)
188 {
189 return IsTaintedAt(xx, yy, true /* clearOnTest */);
190 }
191
192 // TerrainData.GetDatabaseBlob
193 // The user wants something to store in the database.
194 public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
195 {
196 bool ret = false;
197 if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize)
198 {
199 DBRevisionCode = (int)DBTerrainRevision.Legacy256;
200 blob = ToLegacyTerrainSerialization();
201 ret = true;
202 }
203 else
204 {
205 DBRevisionCode = (int)DBTerrainRevision.Compressed2D;
206 blob = ToCompressedTerrainSerialization();
207 ret = true;
208 }
209 return ret;
210 }
211
212 // TerrainData.CompressionFactor
213 private float m_compressionFactor = 100.0f;
214 public override float CompressionFactor { get { return m_compressionFactor; } }
215
216 // TerrainData.GetCompressedMap
217 public override int[] GetCompressedMap()
218 {
219 int[] newMap = new int[SizeX * SizeY];
220
221 int ind = 0;
222 for (int xx = 0; xx < SizeX; xx++)
223 for (int yy = 0; yy < SizeY; yy++)
224 newMap[ind++] = m_heightmap[xx, yy];
225
226 return newMap;
227
228 }
229 // TerrainData.Clone
230 public override TerrainData Clone()
231 {
232 HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ);
233 ret.m_heightmap = (int[,])this.m_heightmap.Clone();
234 return ret;
235 }
236
237 // TerrainData.GetFloatsSerialized
238 // This one dimensional version is ordered so height = map[y*sizeX+x];
239 // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
240 // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
241 public override float[] GetFloatsSerialized()
242 {
243 int points = SizeX * SizeY;
244 float[] heights = new float[points];
245
246 int idx = 0;
247 for (int jj = 0; jj < SizeY; jj++)
248 for (int ii = 0; ii < SizeX; ii++)
249 {
250 heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]);
251 }
252
253 return heights;
254 }
255
256 // TerrainData.GetDoubles
257 public override double[,] GetDoubles()
258 {
259 double[,] ret = new double[SizeX, SizeY];
260 for (int xx = 0; xx < SizeX; xx++)
261 for (int yy = 0; yy < SizeY; yy++)
262 ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]);
263
264 return ret;
265 }
266
267
268 // =============================================================
269
270 private int[,] m_heightmap;
271 // Remember subregions of the heightmap that has changed.
272 private bool[,] m_taint;
273
274 // To save space (especially for large regions), keep the height as a short integer
275 // that is coded as the float height times the compression factor (usually '100'
276 // to make for two decimal points).
277 public int ToCompressedHeight(double pHeight)
278 {
279 return (int)(pHeight * CompressionFactor);
280 }
281
282 public float FromCompressedHeight(int pHeight)
283 {
284 return ((float)pHeight) / CompressionFactor;
285 }
286
287 // To keep with the legacy theme, create an instance of this class based on the
288 // way terrain used to be passed around.
289 public HeightmapTerrainData(double[,] pTerrain)
290 {
291 SizeX = pTerrain.GetLength(0);
292 SizeY = pTerrain.GetLength(1);
293 SizeZ = (int)Constants.RegionHeight;
294 m_compressionFactor = 100.0f;
295
296 m_heightmap = new int[SizeX, SizeY];
297 for (int ii = 0; ii < SizeX; ii++)
298 {
299 for (int jj = 0; jj < SizeY; jj++)
300 {
301 m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]);
302
303 }
304 }
305 // m_log.DebugFormat("{0} new by doubles. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
306
307 m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
308 ClearTaint();
309 }
310
311 // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
312 public HeightmapTerrainData(int pX, int pY, int pZ)
313 {
314 SizeX = pX;
315 SizeY = pY;
316 SizeZ = pZ;
317 m_compressionFactor = 100.0f;
318 m_heightmap = new int[SizeX, SizeY];
319 m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
320 // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
321 ClearTaint();
322 ClearLand(0f);
323 }
324
325 public HeightmapTerrainData(int[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ)
326 {
327 m_compressionFactor = pCompressionFactor;
328 int ind = 0;
329 for (int xx = 0; xx < SizeX; xx++)
330 for (int yy = 0; yy < SizeY; yy++)
331 m_heightmap[xx, yy] = cmap[ind++];
332 // m_log.DebugFormat("{0} new by compressed map. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
333 }
334
335 // Create a heighmap from a database blob
336 public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ)
337 {
338 switch ((DBTerrainRevision)pFormatCode)
339 {
340 case DBTerrainRevision.Compressed2D:
341 FromCompressedTerrainSerialization(pBlob);
342 m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
343 break;
344 default:
345 FromLegacyTerrainSerialization(pBlob);
346 m_log.DebugFormat("{0} HeightmapTerrainData create from legacy serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
347 break;
348 }
349 }
350
351 // Just create an array of doubles. Presumes the caller implicitly knows the size.
352 public Array ToLegacyTerrainSerialization()
353 {
354 Array ret = null;
355
356 using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double)))
357 {
358 using (BinaryWriter bw = new BinaryWriter(str))
359 {
360 for (int xx = 0; xx < Constants.RegionSize; xx++)
361 {
362 for (int yy = 0; yy < Constants.RegionSize; yy++)
363 {
364 double height = this[xx, yy];
365 if (height == 0.0)
366 height = double.Epsilon;
367 bw.Write(height);
368 }
369 }
370 }
371 ret = str.ToArray();
372 }
373 return ret;
374 }
375
376 // Just create an array of doubles. Presumes the caller implicitly knows the size.
377 public void FromLegacyTerrainSerialization(byte[] pBlob)
378 {
379 // In case database info doesn't match real terrain size, initialize the whole terrain.
380 ClearLand();
381
382 using (MemoryStream mstr = new MemoryStream(pBlob))
383 {
384 using (BinaryReader br = new BinaryReader(mstr))
385 {
386 for (int xx = 0; xx < (int)Constants.RegionSize; xx++)
387 {
388 for (int yy = 0; yy < (int)Constants.RegionSize; yy++)
389 {
390 float val = (float)br.ReadDouble();
391 if (xx < SizeX && yy < SizeY)
392 m_heightmap[xx, yy] = ToCompressedHeight(val);
393 }
394 }
395 }
396 ClearTaint();
397 }
398 }
399
400 // See the reader below.
401 public Array ToCompressedTerrainSerialization()
402 {
403 Array ret = null;
404 using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16))))
405 {
406 using (BinaryWriter bw = new BinaryWriter(str))
407 {
408 bw.Write((Int32)DBTerrainRevision.Compressed2D);
409 bw.Write((Int32)SizeX);
410 bw.Write((Int32)SizeY);
411 bw.Write((Int32)CompressionFactor);
412 for (int yy = 0; yy < SizeY; yy++)
413 for (int xx = 0; xx < SizeX; xx++)
414 {
415 bw.Write((Int16)m_heightmap[xx, yy]);
416 }
417 }
418 ret = str.ToArray();
419 }
420 return ret;
421 }
422
423 // Initialize heightmap from blob consisting of:
424 // int32, int32, int32, int32, int16[]
425 // where the first int32 is format code, next two int32s are the X and y of heightmap data and
426 // the forth int is the compression factor for the following int16s
427 // This is just sets heightmap info. The actual size of the region was set on this instance's
428 // creation and any heights not initialized by theis blob are set to the default height.
429 public void FromCompressedTerrainSerialization(byte[] pBlob)
430 {
431 Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor;
432
433 using (MemoryStream mstr = new MemoryStream(pBlob))
434 {
435 using (BinaryReader br = new BinaryReader(mstr))
436 {
437 hmFormatCode = br.ReadInt32();
438 hmSizeX = br.ReadInt32();
439 hmSizeY = br.ReadInt32();
440 hmCompressionFactor = br.ReadInt32();
441
442 m_compressionFactor = hmCompressionFactor;
443
444 // In case database info doesn't match real terrain size, initialize the whole terrain.
445 ClearLand();
446
447 for (int yy = 0; yy < hmSizeY; yy++)
448 {
449 for (int xx = 0; xx < hmSizeX; xx++)
450 {
451 Int16 val = br.ReadInt16();
452 if (xx < SizeX && yy < SizeY)
453 m_heightmap[xx, yy] = val;
454 }
455 }
456 }
457 ClearTaint();
458
459 m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}",
460 LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor);
461 }
462 }
463 }
464}
diff --git a/OpenSim/Framework/UserProfileData.cs b/OpenSim/Framework/UserProfileData.cs
index 9bac739..f7069a5 100644
--- a/OpenSim/Framework/UserProfileData.cs
+++ b/OpenSim/Framework/UserProfileData.cs
@@ -161,14 +161,18 @@ namespace OpenSim.Framework
161 { 161 {
162 get 162 get
163 { 163 {
164 return Utils.UIntsToLong( 164 return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY));
165 m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); 165 // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize);
166 } 166 }
167 167
168 set 168 set
169 { 169 {
170 m_homeRegionX = (uint) (value >> 40); 170 uint regionWorldLocX, regionWorldLocY;
171 m_homeRegionY = (((uint) (value)) >> 8); 171 Util.RegionHandleToWorldLoc(value, out regionWorldLocX, out regionWorldLocY);
172 m_homeRegionX = Util.WorldToRegionLoc(regionWorldLocX);
173 m_homeRegionY = Util.WorldToRegionLoc(regionWorldLocY);
174 // m_homeRegionX = (uint) (value >> 40);
175 // m_homeRegionY = (((uint) (value)) >> 8);
172 } 176 }
173 } 177 }
174 178
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
index ca6c3ca..51535a6 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs
@@ -59,6 +59,7 @@ namespace OpenSim.Region.ClientStack.Linden
59 public class EventQueueGetModule : IEventQueue, INonSharedRegionModule 59 public class EventQueueGetModule : IEventQueue, INonSharedRegionModule
60 { 60 {
61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
62 private static string LogHeader = "[EVENT QUEUE GET MODULE]";
62 63
63 /// <value> 64 /// <value>
64 /// Debug level. 65 /// Debug level.
@@ -479,7 +480,7 @@ namespace OpenSim.Region.ClientStack.Linden
479 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) 480 public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
480 { 481 {
481 m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>", 482 m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>",
482 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); 483 LogHeader, handle, avatarID, regionSizeX, regionSizeY);
483 484
484 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY); 485 OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
485 Enqueue(item, avatarID); 486 Enqueue(item, avatarID);
@@ -489,7 +490,7 @@ namespace OpenSim.Region.ClientStack.Linden
489 ulong regionHandle, int regionSizeX, int regionSizeY) 490 ulong regionHandle, int regionSizeX, int regionSizeY)
490 { 491 {
491 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>", 492 m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>",
492 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); 493 LogHeader, regionHandle, avatarID, regionSizeX, regionSizeY);
493 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY); 494 OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
494 Enqueue(item, avatarID); 495 Enqueue(item, avatarID);
495 } 496 }
@@ -500,7 +501,7 @@ namespace OpenSim.Region.ClientStack.Linden
500 UUID avatarID, int regionSizeX, int regionSizeY) 501 UUID avatarID, int regionSizeX, int regionSizeY)
501 { 502 {
502 m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>", 503 m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>",
503 "[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); 504 LogHeader, regionHandle, avatarID, regionSizeX, regionSizeY);
504 505
505 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, 506 OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
506 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY); 507 locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
@@ -512,7 +513,7 @@ namespace OpenSim.Region.ClientStack.Linden
512 string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) 513 string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
513 { 514 {
514 m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>", 515 m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
515 "[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); 516 LogHeader, handle, avatarID, regionSizeX, regionSizeY);
516 517
517 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, 518 OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
518 capsURL, avatarID, sessionID, regionSizeX, regionSizeY); 519 capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index 7b6889a..226f2a1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -312,6 +312,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
312 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; 312 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
313 313
314 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 314 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
315 private static string LogHeader = "[LLCLIENTVIEW]";
315 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients 316 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
316 317
317 /// <summary> 318 /// <summary>
@@ -692,12 +693,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
692 /// <returns>true if the handler was added. This is currently always the case.</returns> 693 /// <returns>true if the handler was added. This is currently always the case.</returns>
693 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) 694 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
694 { 695 {
696 return AddLocalPacketHandler(packetType, handler, doAsync, false);
697 }
698
699 /// <summary>
700 /// Add a handler for the given packet type.
701 /// </summary>
702 /// <param name="packetType"></param>
703 /// <param name="handler"></param>
704 /// <param name="doAsync">
705 /// If true, when the packet is received handle it on a different thread. Whether this is given direct to
706 /// a threadpool thread or placed in a queue depends on the inEngine parameter.
707 /// </param>
708 /// <param name="inEngine">
709 /// If async is false then this parameter is ignored.
710 /// If async is true and inEngine is false, then the packet is sent directly to a
711 /// threadpool thread.
712 /// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine.
713 /// This may result in slower handling but reduces the risk of overloading the simulator when there are many
714 /// simultaneous async requests.
715 /// </param>
716 /// <returns>true if the handler was added. This is currently always the case.</returns>
717 public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine)
718 {
695 bool result = false; 719 bool result = false;
696 lock (m_packetHandlers) 720 lock (m_packetHandlers)
697 { 721 {
698 if (!m_packetHandlers.ContainsKey(packetType)) 722 if (!m_packetHandlers.ContainsKey(packetType))
699 { 723 {
700 m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = doAsync }); 724 m_packetHandlers.Add(
725 packetType, new PacketProcessor() { method = handler, Async = doAsync });
701 result = true; 726 result = true;
702 } 727 }
703 } 728 }
@@ -1176,11 +1201,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1176 1201
1177 /// <summary> 1202 /// <summary>
1178 /// Send the region heightmap to the client 1203 /// Send the region heightmap to the client
1204 /// This method is only called when not doing intellegent terrain patch sending and
1205 /// is only called when the scene presence is initially created and sends all of the
1206 /// region's patches to the client.
1179 /// </summary> 1207 /// </summary>
1180 /// <param name="map">heightmap</param> 1208 /// <param name="map">heightmap</param>
1181 public virtual void SendLayerData(float[] map) 1209 public virtual void SendLayerData(float[] map)
1182 { 1210 {
1183 Util.FireAndForget(DoSendLayerData, map); 1211 Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData());
1184 1212
1185 // Send it sync, and async. It's not that much data 1213 // Send it sync, and async. It's not that much data
1186 // and it improves user experience just so much! 1214 // and it improves user experience just so much!
@@ -1193,15 +1221,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1193 /// <param name="o"></param> 1221 /// <param name="o"></param>
1194 private void DoSendLayerData(object o) 1222 private void DoSendLayerData(object o)
1195 { 1223 {
1196 float[] map = LLHeightFieldMoronize((float[])o); 1224 TerrainData map = (TerrainData)o;
1197 1225
1198 try 1226 try
1199 { 1227 {
1228 // Send LayerData in typerwriter pattern
1200 for (int y = 0; y < 16; y++) 1229 for (int y = 0; y < 16; y++)
1201 { 1230 {
1202 for (int x = 0; x < 16; x+=4) 1231 for (int x = 0; x < 16; x++)
1203 { 1232 {
1204 SendLayerPacket(x, y, map); 1233 SendLayerData(x, y, map);
1205 } 1234 }
1206 } 1235 }
1207 } 1236 }
@@ -1211,77 +1240,95 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1211 } 1240 }
1212 } 1241 }
1213 1242
1214 /// <summary> 1243 // Legacy form of invocation that passes around a bare data array.
1215 /// Sends a set of four patches (x, x+1, ..., x+3) to the client 1244 // Just ignore what was passed and use the real terrain info that is part of the scene.
1216 /// </summary> 1245 // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
1217 /// <param name="map">heightmap</param> 1246 // there is a special form for specifying multiple terrain patches to send.
1218 /// <param name="px">X coordinate for patches 0..12</param> 1247 // The form is to pass 'px' as negative the number of patches to send and to
1219 /// <param name="py">Y coordinate for patches 0..15</param> 1248 // pass the float array as pairs of patch X and Y coordinates. So, passing 'px'
1220 private void SendLayerPacket(int x, int y, float[] map) 1249 // as -2 and map= [3, 5, 8, 4] would mean to send two terrain heightmap patches
1250 // and the patches to send are <3,5> and <8,4>.
1251 public void SendLayerData(int px, int py, float[] map)
1221 { 1252 {
1222 int[] patches = new int[4]; 1253 if (px >= 0)
1223 patches[0] = x + 0 + y * 16; 1254 {
1224 patches[1] = x + 1 + y * 16; 1255 SendLayerData(px, py, m_scene.Heightmap.GetTerrainData());
1225 patches[2] = x + 2 + y * 16; 1256 }
1226 patches[3] = x + 3 + y * 16; 1257 else
1258 {
1259 int numPatches = -px;
1260 int[] xPatches = new int[numPatches];
1261 int[] yPatches = new int[numPatches];
1262 for (int pp = 0; pp < numPatches; pp++)
1263 {
1264 xPatches[pp] = (int)map[pp * 2];
1265 yPatches[pp] = (int)map[pp * 2 + 1];
1266 }
1227 1267
1228 float[] heightmap = (map.Length == 65536) ? 1268 // DebugSendingPatches("SendLayerData", xPatches, yPatches);
1229 map :
1230 LLHeightFieldMoronize(map);
1231 1269
1232 try 1270 SendLayerData(xPatches, yPatches, m_scene.Heightmap.GetTerrainData());
1233 {
1234 Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
1235 OutPacket(layerpack, ThrottleOutPacketType.Land);
1236 } 1271 }
1237 catch 1272 }
1273
1274 private void DebugSendingPatches(string pWho, int[] pX, int[] pY)
1275 {
1276 if (m_log.IsDebugEnabled)
1238 { 1277 {
1239 for (int px = x ; px < x + 4 ; px++) 1278 int numPatches = pX.Length;
1240 SendLayerData(px, y, map); 1279 string Xs = "";
1280 string Ys = "";
1281 for (int pp = 0; pp < numPatches; pp++)
1282 {
1283 Xs += String.Format("{0}", (int)pX[pp]) + ",";
1284 Ys += String.Format("{0}", (int)pY[pp]) + ",";
1285 }
1286 m_log.DebugFormat("{0} {1}: numPatches={2}, X={3}, Y={4}", LogHeader, pWho, numPatches, Xs, Ys);
1241 } 1287 }
1242 } 1288 }
1243 1289
1244 /// <summary> 1290 /// <summary>
1245 /// Sends a specified patch to a client 1291 /// Sends a terrain packet for the point specified.
1292 /// This is a legacy call that has refarbed the terrain into a flat map of floats.
1293 /// We just use the terrain from the region we know about.
1246 /// </summary> 1294 /// </summary>
1247 /// <param name="px">Patch coordinate (x) 0..15</param> 1295 /// <param name="px">Patch coordinate (x) 0..15</param>
1248 /// <param name="py">Patch coordinate (y) 0..15</param> 1296 /// <param name="py">Patch coordinate (y) 0..15</param>
1249 /// <param name="map">heightmap</param> 1297 /// <param name="map">heightmap</param>
1250 public void SendLayerData(int px, int py, float[] map) 1298 public void SendLayerData(int px, int py, TerrainData terrData)
1299 {
1300 int[] xPatches = new[] { px };
1301 int[] yPatches = new[] { py };
1302 SendLayerData(xPatches, yPatches, terrData);
1303 }
1304
1305 private void SendLayerData(int[] px, int[] py, TerrainData terrData)
1251 { 1306 {
1252 try 1307 try
1253 { 1308 {
1254 int[] patches = new int[] { py * 16 + px }; 1309 /* test code using the terrain compressor in libOpenMetaverse
1255 float[] heightmap = (map.Length == 65536) ? 1310 int[] patchInd = new int[1];
1256 map : 1311 patchInd[0] = px + (py * Constants.TerrainPatchSize);
1257 LLHeightFieldMoronize(map); 1312 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd);
1258 1313 */
1259 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1314 // Many, many patches could have been passed to us. Since the patches will be compressed
1260 1315 // into variable sized blocks, we cannot pre-compute how many will fit into one
1261 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. 1316 // packet. While some fancy packing algorithm is possible, 4 seems to always fit.
1262 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. 1317 int PatchesAssumedToFit = 4;
1263 // We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area 1318 for (int pcnt = 0; pcnt < px.Length; pcnt += PatchesAssumedToFit)
1264 // invalidating previous packets for that area. 1319 {
1265 1320 int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit);
1266 // It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a 1321 int[] xPatches = new int[remaining];
1267 // tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower. 1322 int[] yPatches = new int[remaining];
1268 1323 for (int ii = 0; ii < remaining; ii++)
1269 // One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will 1324 {
1270 // have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain 1325 xPatches[ii] = px[pcnt + ii];
1271 // patches. 1326 yPatches[ii] = py[pcnt + ii];
1327 }
1328 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches);
1329 // DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches);
1272 1330
1273 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss. 1331 SendTheLayerPacket(layerpack);
1274 if (m_justEditedTerrain)
1275 {
1276 layerpack.Header.Reliable = false;
1277 OutPacket(layerpack,
1278 ThrottleOutPacketType.Unknown );
1279 }
1280 else
1281 {
1282 layerpack.Header.Reliable = true;
1283 OutPacket(layerpack,
1284 ThrottleOutPacketType.Task);
1285 } 1332 }
1286 } 1333 }
1287 catch (Exception e) 1334 catch (Exception e)
@@ -1290,36 +1337,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1290 } 1337 }
1291 } 1338 }
1292 1339
1293 /// <summary> 1340 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a
1294 /// Munges heightfield into the LLUDP backed in restricted heightfield. 1341 // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we
1295 /// </summary> 1342 // start skipping the queues until they're done editing the terrain. We also make them
1296 /// <param name="map">float array in the base; Constants.RegionSize</param> 1343 // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch
1297 /// <returns>float array in the base 256</returns> 1344 // area invalidating previous packets for that area.
1298 internal float[] LLHeightFieldMoronize(float[] map) 1345
1346 // It's possible for an editing user to flood themselves with edited packets but the majority
1347 // of use cases are such that only a tiny percentage of users will be editing the terrain.
1348 // Other, non-editing users will see the edits much slower.
1349
1350 // One last note on this topic, by the time users are going to be editing the terrain, it's
1351 // extremely likely that the sim will have rezzed already and therefore this is not likely going
1352 // to cause any additional issues with lost packets, objects or terrain patches.
1353
1354 // m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we
1355 // only have one cache miss.
1356 private void SendTheLayerPacket(LayerDataPacket layerpack)
1299 { 1357 {
1300 if (map.Length == 65536) 1358 if (m_justEditedTerrain)
1301 return map; 1359 {
1360 layerpack.Header.Reliable = false;
1361 OutPacket(layerpack, ThrottleOutPacketType.Unknown );
1362 }
1302 else 1363 else
1303 { 1364 {
1304 float[] returnmap = new float[65536]; 1365 layerpack.Header.Reliable = true;
1305 1366 OutPacket(layerpack, ThrottleOutPacketType.Land);
1306 if (map.Length < 65535)
1307 {
1308 // rebase the vector stride to 256
1309 for (int i = 0; i < Constants.RegionSize; i++)
1310 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, (int)Constants.RegionSize);
1311 }
1312 else
1313 {
1314 for (int i = 0; i < 256; i++)
1315 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256);
1316 }
1317
1318 //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536);
1319
1320 return returnmap;
1321 } 1367 }
1322
1323 } 1368 }
1324 1369
1325 /// <summary> 1370 /// <summary>
@@ -1348,21 +1393,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1348 { 1393 {
1349 Vector2[] windSpeeds = (Vector2[])o; 1394 Vector2[] windSpeeds = (Vector2[])o;
1350 TerrainPatch[] patches = new TerrainPatch[2]; 1395 TerrainPatch[] patches = new TerrainPatch[2];
1351 patches[0] = new TerrainPatch(); 1396 patches[0] = new TerrainPatch { Data = new float[16 * 16] };
1352 patches[0].Data = new float[16 * 16]; 1397 patches[1] = new TerrainPatch { Data = new float[16 * 16] };
1353 patches[1] = new TerrainPatch();
1354 patches[1].Data = new float[16 * 16];
1355 1398
1356 for (int y = 0; y < 16; y++) 1399 for (int x = 0; x < 16 * 16; x++)
1357 { 1400 {
1358 for (int x = 0; x < 16; x++) 1401 patches[0].Data[x] = windSpeeds[x].X;
1359 { 1402 patches[1].Data[x] = windSpeeds[x].Y;
1360 patches[0].Data[y * 16 + x] = windSpeeds[y * 16 + x].X;
1361 patches[1].Data[y * 16 + x] = windSpeeds[y * 16 + x].Y;
1362 }
1363 } 1403 }
1364 1404
1365 LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Wind); 1405 byte layerType = (byte)TerrainPatch.LayerType.Wind;
1406 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1407 layerType = (byte)TerrainPatch.LayerType.WindExtended;
1408
1409 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1410 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1411 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1366 layerpack.Header.Zerocoded = true; 1412 layerpack.Header.Zerocoded = true;
1367 OutPacket(layerpack, ThrottleOutPacketType.Wind); 1413 OutPacket(layerpack, ThrottleOutPacketType.Wind);
1368 } 1414 }
@@ -1386,7 +1432,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1386 } 1432 }
1387 } 1433 }
1388 1434
1389 LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Cloud); 1435 byte layerType = (byte)TerrainPatch.LayerType.Cloud;
1436 if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
1437 layerType = (byte)TerrainPatch.LayerType.CloudExtended;
1438
1439 // LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
1440 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
1441 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
1390 layerpack.Header.Zerocoded = true; 1442 layerpack.Header.Zerocoded = true;
1391 OutPacket(layerpack, ThrottleOutPacketType.Cloud); 1443 OutPacket(layerpack, ThrottleOutPacketType.Cloud);
1392 } 1444 }
@@ -1491,10 +1543,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1491 mapReply.Data[i].Access = mapBlocks2[i].Access; 1543 mapReply.Data[i].Access = mapBlocks2[i].Access;
1492 mapReply.Data[i].Agents = mapBlocks2[i].Agents; 1544 mapReply.Data[i].Agents = mapBlocks2[i].Agents;
1493 1545
1494 // TODO: hookup varregion sim size here
1495 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock(); 1546 mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
1496 mapReply.Size[i].SizeX = 256; 1547 mapReply.Size[i].SizeX = mapBlocks2[i].SizeX;
1497 mapReply.Size[i].SizeY = 256; 1548 mapReply.Size[i].SizeY = mapBlocks2[i].SizeY;
1498 } 1549 }
1499 OutPacket(mapReply, ThrottleOutPacketType.Land); 1550 OutPacket(mapReply, ThrottleOutPacketType.Land);
1500 } 1551 }
@@ -1659,15 +1710,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1659 1710
1660 public void SendKillObject(List<uint> localIDs) 1711 public void SendKillObject(List<uint> localIDs)
1661 { 1712 {
1662// foreach (uint id in localIDs)
1663// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
1664
1665 // remove pending entities
1666 lock (m_entityProps.SyncRoot)
1667 m_entityProps.Remove(localIDs);
1668 lock (m_entityUpdates.SyncRoot)
1669 m_entityUpdates.Remove(localIDs);
1670
1671 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); 1713 KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
1672 // TODO: don't create new blocks if recycling an old packet 1714 // TODO: don't create new blocks if recycling an old packet
1673 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; 1715 kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
@@ -9093,6 +9135,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
9093 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest; 9135 TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest;
9094 if (handlerTeleportLocationRequest != null) 9136 if (handlerTeleportLocationRequest != null)
9095 { 9137 {
9138 // Adjust teleport location to base of a larger region if requested to teleport to a sub-region
9139 uint locX, locY;
9140 Util.RegionHandleToWorldLoc(tpLocReq.Info.RegionHandle, out locX, out locY);
9141 if ((locX >= m_scene.RegionInfo.WorldLocX)
9142 && (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
9143 && (locY >= m_scene.RegionInfo.WorldLocY)
9144 && (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) )
9145 {
9146 tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
9147 tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
9148 tpLocReq.Info.Position.Y += locY - m_scene.RegionInfo.WorldLocY;
9149 }
9150
9096 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position, 9151 handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position,
9097 tpLocReq.Info.LookAt, 16); 9152 tpLocReq.Info.LookAt, 16);
9098 } 9153 }
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]
diff --git a/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs
index e03ac5a..c6f531e 100644
--- a/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs
+++ b/OpenSim/Region/Framework/Interfaces/IRegionCombinerModule.cs
@@ -55,5 +55,10 @@ namespace OpenSim.Region.Framework.Interfaces
55 /// Currently, will throw an exception if this does not match a root region. 55 /// Currently, will throw an exception if this does not match a root region.
56 /// </param> 56 /// </param>
57 Vector2 GetSizeOfMegaregion(UUID regionId); 57 Vector2 GetSizeOfMegaregion(UUID regionId);
58
59 /// <summary>
60 /// Tests to see of position (relative to the region) is within the megaregion
61 /// </summary>
62 bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy);
58 } 63 }
59} \ No newline at end of file 64} \ No newline at end of file
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs
index 3e97a7a..13358cb 100644
--- a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs
@@ -68,13 +68,22 @@ namespace OpenSim.Region.Framework.Interfaces
68 /// </summary> 68 /// </summary>
69 /// <param name="ter">HeightField data</param> 69 /// <param name="ter">HeightField data</param>
70 /// <param name="regionID">region UUID</param> 70 /// <param name="regionID">region UUID</param>
71 void StoreTerrain(TerrainData terrain, UUID regionID);
72
73 // Legacy version kept for downward compabibility
71 void StoreTerrain(double[,] terrain, UUID regionID); 74 void StoreTerrain(double[,] terrain, UUID regionID);
72 75
73 /// <summary> 76 /// <summary>
74 /// Load the latest terrain revision from region storage 77 /// Load the latest terrain revision from region storage
75 /// </summary> 78 /// </summary>
76 /// <param name="regionID">the region UUID</param> 79 /// <param name="regionID">the region UUID</param>
80 /// <param name="sizeX">the X dimension of the region being filled</param>
81 /// <param name="sizeY">the Y dimension of the region being filled</param>
82 /// <param name="sizeZ">the Z dimension of the region being filled</param>
77 /// <returns>Heightfield data</returns> 83 /// <returns>Heightfield data</returns>
84 TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ);
85
86 // Legacy version kept for downward compabibility
78 double[,] LoadTerrain(UUID regionID); 87 double[,] LoadTerrain(UUID regionID);
79 88
80 void StoreLandObject(ILandObject Parcel); 89 void StoreLandObject(ILandObject Parcel);
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
index 17bd48b..e09f775 100644
--- a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
@@ -79,13 +79,22 @@ namespace OpenSim.Region.Framework.Interfaces
79 /// </summary> 79 /// </summary>
80 /// <param name="ter">HeightField data</param> 80 /// <param name="ter">HeightField data</param>
81 /// <param name="regionID">region UUID</param> 81 /// <param name="regionID">region UUID</param>
82 void StoreTerrain(TerrainData terrain, UUID regionID);
83
84 // Legacy version kept for downward compabibility
82 void StoreTerrain(double[,] terrain, UUID regionID); 85 void StoreTerrain(double[,] terrain, UUID regionID);
83 86
84 /// <summary> 87 /// <summary>
85 /// Load the latest terrain revision from region storage 88 /// Load the latest terrain revision from region storage
86 /// </summary> 89 /// </summary>
87 /// <param name="regionID">the region UUID</param> 90 /// <param name="regionID">the region UUID</param>
91 /// <param name="pSizeX">the X dimension of the terrain being filled</param>
92 /// <param name="pSizeY">the Y dimension of the terrain being filled</param>
93 /// <param name="pSizeZ">the Z dimension of the terrain being filled</param>
88 /// <returns>Heightfield data</returns> 94 /// <returns>Heightfield data</returns>
95 TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ);
96
97 // Legacy version kept for downward compabibility
89 double[,] LoadTerrain(UUID regionID); 98 double[,] LoadTerrain(UUID regionID);
90 99
91 void StoreLandObject(ILandObject Parcel); 100 void StoreLandObject(ILandObject Parcel);
@@ -136,4 +145,5 @@ namespace OpenSim.Region.Framework.Interfaces
136 145
137 void Shutdown(); 146 void Shutdown();
138 } 147 }
148
139} 149}
diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
index e467701..f660b8d 100644
--- a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
+++ b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
@@ -25,13 +25,23 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenSim.Framework;
29using OpenMetaverse;
30
28namespace OpenSim.Region.Framework.Interfaces 31namespace OpenSim.Region.Framework.Interfaces
29{ 32{
30 public interface ITerrainChannel 33 public interface ITerrainChannel
31 { 34 {
32 int Height { get; } 35 int Width { get;} // X dimension
36 int Height { get;} // Y dimension
37 int Altitude { get;} // Z dimension
38
33 double this[int x, int y] { get; set; } 39 double this[int x, int y] { get; set; }
34 int Width { get; } 40
41 float GetHeightAtXYZ(float x, float y, float z);
42
43 // Return the packaged terrain data for passing into lower levels of communication
44 TerrainData GetTerrainData();
35 45
36 /// <summary> 46 /// <summary>
37 /// Squash the entire heightmap into a single dimensioned array 47 /// Squash the entire heightmap into a single dimensioned array
@@ -40,9 +50,14 @@ namespace OpenSim.Region.Framework.Interfaces
40 float[] GetFloatsSerialised(); 50 float[] GetFloatsSerialised();
41 51
42 double[,] GetDoubles(); 52 double[,] GetDoubles();
53
54 // Check if a location has been updated. Clears the taint flag as a side effect.
43 bool Tainted(int x, int y); 55 bool Tainted(int x, int y);
56
44 ITerrainChannel MakeCopy(); 57 ITerrainChannel MakeCopy();
45 string SaveToXmlString(); 58 string SaveToXmlString();
46 void LoadFromXmlString(string data); 59 void LoadFromXmlString(string data);
60 // Merge some terrain into this channel
61 void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement);
47 } 62 }
48} 63}
diff --git a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
index b45cc4d..4ab5a4a 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.Inventory.cs
@@ -2221,14 +2221,9 @@ namespace OpenSim.Region.Framework.Scenes
2221 itemID = UUID.Zero; 2221 itemID = UUID.Zero;
2222 if (grp != null) 2222 if (grp != null)
2223 { 2223 {
2224 Vector3 inventoryStoredPosition = new Vector3 2224 Vector3 inventoryStoredPosition = new Vector3(
2225 (((grp.AbsolutePosition.X > (int)Constants.RegionSize) 2225 Math.Min(grp.AbsolutePosition.X, RegionInfo.RegionSizeX - 6),
2226 ? 250 2226 Math.Min(grp.AbsolutePosition.Y, RegionInfo.RegionSizeY - 6),
2227 : grp.AbsolutePosition.X)
2228 ,
2229 (grp.AbsolutePosition.X > (int)Constants.RegionSize)
2230 ? 250
2231 : grp.AbsolutePosition.X,
2232 grp.AbsolutePosition.Z); 2227 grp.AbsolutePosition.Z);
2233 2228
2234 Vector3 originalPosition = grp.AbsolutePosition; 2229 Vector3 originalPosition = grp.AbsolutePosition;
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index eb34f55..46c9048 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -6,7 +6,7 @@
6 * modification, are permitted provided that the following conditions are met: 6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright 7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD 9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution. 11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the 12 * * Neither the name of the OpenSimulator Project nor the
@@ -103,7 +103,29 @@ namespace OpenSim.Region.Framework.Scenes
103 /// <summary> 103 /// <summary>
104 /// If false then physical objects are disabled, though collisions will continue as normal. 104 /// If false then physical objects are disabled, though collisions will continue as normal.
105 /// </summary> 105 /// </summary>
106 public bool PhysicsEnabled { get; set; } 106 public bool PhysicsEnabled
107 {
108 get
109 {
110 return m_physicsEnabled;
111 }
112
113 set
114 {
115 m_physicsEnabled = value;
116
117 if (PhysicsScene != null)
118 {
119 IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
120
121 if (physScene != null)
122 physScene.SetPhysicsParameter(
123 "Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
124 }
125 }
126 }
127
128 private bool m_physicsEnabled;
107 129
108 /// <summary> 130 /// <summary>
109 /// If false then scripts are not enabled on the smiulator 131 /// If false then scripts are not enabled on the smiulator
@@ -160,11 +182,6 @@ namespace OpenSim.Region.Framework.Scenes
160 /// </summary> 182 /// </summary>
161 public SimStatsReporter StatsReporter { get; private set; } 183 public SimStatsReporter StatsReporter { get; private set; }
162 184
163 public List<Border> NorthBorders = new List<Border>();
164 public List<Border> EastBorders = new List<Border>();
165 public List<Border> SouthBorders = new List<Border>();
166 public List<Border> WestBorders = new List<Border>();
167
168 /// <summary> 185 /// <summary>
169 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a 186 /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
170 /// PhysicsScene in order to perform collision detection 187 /// PhysicsScene in order to perform collision detection
@@ -204,15 +221,16 @@ namespace OpenSim.Region.Framework.Scenes
204 /// </summary> 221 /// </summary>
205 public int m_linksetCapacity = 0; 222 public int m_linksetCapacity = 0;
206 223
224 public bool m_clampPrimSize;
225 public bool m_trustBinaries;
226 public bool m_allowScriptCrossings = true;
227
207 /// <summary> 228 /// <summary>
208 /// Max prims an Physical object will hold 229 /// Max prims an Physical object will hold
209 /// </summary> 230 /// </summary>
210 /// 231 ///
211 public int m_linksetPhysCapacity = 0; 232 public int m_linksetPhysCapacity = 0;
212 233
213 public bool m_clampPrimSize;
214 public bool m_trustBinaries;
215 public bool m_allowScriptCrossings;
216 public bool m_useFlySlow; 234 public bool m_useFlySlow;
217 public bool m_useTrashOnDelete = true; 235 public bool m_useTrashOnDelete = true;
218 236
@@ -364,7 +382,6 @@ namespace OpenSim.Region.Framework.Scenes
364 382
365 // TODO: Possibly stop other classes being able to manipulate this directly. 383 // TODO: Possibly stop other classes being able to manipulate this directly.
366 private SceneGraph m_sceneGraph; 384 private SceneGraph m_sceneGraph;
367 private volatile int m_bordersLocked;
368 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing 385 private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
369 private volatile bool m_backingup; 386 private volatile bool m_backingup;
370 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); 387 private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
@@ -446,18 +463,6 @@ namespace OpenSim.Region.Framework.Scenes
446 set { m_splitRegionID = value; } 463 set { m_splitRegionID = value; }
447 } 464 }
448 465
449 public bool BordersLocked
450 {
451 get { return m_bordersLocked == 1; }
452 set
453 {
454 if (value == true)
455 m_bordersLocked = 1;
456 else
457 m_bordersLocked = 0;
458 }
459 }
460
461 public new float TimeDilation 466 public new float TimeDilation
462 { 467 {
463 get { return m_sceneGraph.PhysicsScene.TimeDilation; } 468 get { return m_sceneGraph.PhysicsScene.TimeDilation; }
@@ -1075,28 +1080,6 @@ namespace OpenSim.Region.Framework.Scenes
1075 PeriodicBackup = true; 1080 PeriodicBackup = true;
1076 UseBackup = true; 1081 UseBackup = true;
1077 1082
1078 BordersLocked = true;
1079 Border northBorder = new Border();
1080 northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeY); //<---
1081 northBorder.CrossDirection = Cardinals.N;
1082 NorthBorders.Add(northBorder);
1083
1084 Border southBorder = new Border();
1085 southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
1086 southBorder.CrossDirection = Cardinals.S;
1087 SouthBorders.Add(southBorder);
1088
1089 Border eastBorder = new Border();
1090 eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeX); //<---
1091 eastBorder.CrossDirection = Cardinals.E;
1092 EastBorders.Add(eastBorder);
1093
1094 Border westBorder = new Border();
1095 westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
1096 westBorder.CrossDirection = Cardinals.W;
1097 WestBorders.Add(westBorder);
1098 BordersLocked = false;
1099
1100 m_eventManager = new EventManager(); 1083 m_eventManager = new EventManager();
1101 1084
1102 m_permissions = new ScenePermissions(this); 1085 m_permissions = new ScenePermissions(this);
@@ -1975,7 +1958,7 @@ namespace OpenSim.Region.Framework.Scenes
1975 { 1958 {
1976 try 1959 try
1977 { 1960 {
1978 double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID); 1961 TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1979 if (map == null) 1962 if (map == null)
1980 { 1963 {
1981 // This should be in the Terrain module, but it isn't because 1964 // This should be in the Terrain module, but it isn't because
@@ -1986,7 +1969,7 @@ namespace OpenSim.Region.Framework.Scenes
1986 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 1969 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
1987 1970
1988 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); 1971 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
1989 Heightmap = new TerrainChannel(m_InitialTerrain); 1972 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1990 1973
1991 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 1974 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1992 } 1975 }
@@ -2611,185 +2594,35 @@ namespace OpenSim.Region.Framework.Scenes
2611 EntityTransferModule.Cross(grp, attemptedPosition, silent); 2594 EntityTransferModule.Cross(grp, attemptedPosition, silent);
2612 } 2595 }
2613 2596
2614 public Border GetCrossedBorder(Vector3 position, Cardinals gridline) 2597 // Simple test to see if a position is in the current region.
2598 // This test is mostly used to see if a region crossing is necessary.
2599 // Assuming the position is relative to the region so anything outside its bounds.
2600 // Return 'true' if position inside region.
2601 public bool PositionIsInCurrentRegion(Vector3 pos)
2615 { 2602 {
2616 if (BordersLocked) 2603 bool ret = false;
2617 { 2604 int xx = (int)Math.Floor(pos.X);
2618 switch (gridline) 2605 int yy = (int)Math.Floor(pos.Y);
2619 { 2606 if (xx < 0 || yy < 0)
2620 case Cardinals.N: 2607 return false;
2621 lock (NorthBorders)
2622 {
2623 foreach (Border b in NorthBorders)
2624 {
2625 if (b.TestCross(position))
2626 return b;
2627 }
2628 }
2629 break;
2630 case Cardinals.S:
2631 lock (SouthBorders)
2632 {
2633 foreach (Border b in SouthBorders)
2634 {
2635 if (b.TestCross(position))
2636 return b;
2637 }
2638 }
2639
2640 break;
2641 case Cardinals.E:
2642 lock (EastBorders)
2643 {
2644 foreach (Border b in EastBorders)
2645 {
2646 if (b.TestCross(position))
2647 return b;
2648 }
2649 }
2650
2651 break;
2652 case Cardinals.W:
2653
2654 lock (WestBorders)
2655 {
2656 foreach (Border b in WestBorders)
2657 {
2658 if (b.TestCross(position))
2659 return b;
2660 }
2661 }
2662 break;
2663 2608
2664 } 2609 IRegionCombinerModule regionCombinerModule = RequestModuleInterface<IRegionCombinerModule>();
2610 if (regionCombinerModule == null)
2611 {
2612 // Regular region. Just check for region size
2613 if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY )
2614 ret = true;
2665 } 2615 }
2666 else 2616 else
2667 { 2617 {
2668 switch (gridline) 2618 // We're in a mega-region so see if we are still in that larger region
2669 { 2619 ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
2670 case Cardinals.N:
2671 foreach (Border b in NorthBorders)
2672 {
2673 if (b.TestCross(position))
2674 return b;
2675 }
2676
2677 break;
2678 case Cardinals.S:
2679 foreach (Border b in SouthBorders)
2680 {
2681 if (b.TestCross(position))
2682 return b;
2683 }
2684 break;
2685 case Cardinals.E:
2686 foreach (Border b in EastBorders)
2687 {
2688 if (b.TestCross(position))
2689 return b;
2690 }
2691
2692 break;
2693 case Cardinals.W:
2694 foreach (Border b in WestBorders)
2695 {
2696 if (b.TestCross(position))
2697 return b;
2698 }
2699 break;
2700
2701 }
2702 } 2620 }
2703 2621
2704 return null; 2622 return ret;
2705 }
2706 2623
2707 public bool TestBorderCross(Vector3 position, Cardinals border)
2708 {
2709 if (BordersLocked)
2710 {
2711 switch (border)
2712 {
2713 case Cardinals.N:
2714 lock (NorthBorders)
2715 {
2716 foreach (Border b in NorthBorders)
2717 {
2718 if (b.TestCross(position))
2719 return true;
2720 }
2721 }
2722 break;
2723 case Cardinals.E:
2724 lock (EastBorders)
2725 {
2726 foreach (Border b in EastBorders)
2727 {
2728 if (b.TestCross(position))
2729 return true;
2730 }
2731 }
2732 break;
2733 case Cardinals.S:
2734 lock (SouthBorders)
2735 {
2736 foreach (Border b in SouthBorders)
2737 {
2738 if (b.TestCross(position))
2739 return true;
2740 }
2741 }
2742 break;
2743 case Cardinals.W:
2744 lock (WestBorders)
2745 {
2746 foreach (Border b in WestBorders)
2747 {
2748 if (b.TestCross(position))
2749 return true;
2750 }
2751 }
2752 break;
2753 }
2754 }
2755 else
2756 {
2757 switch (border)
2758 {
2759 case Cardinals.N:
2760 foreach (Border b in NorthBorders)
2761 {
2762 if (b.TestCross(position))
2763 return true;
2764 }
2765 break;
2766 case Cardinals.E:
2767 foreach (Border b in EastBorders)
2768 {
2769 if (b.TestCross(position))
2770 return true;
2771 }
2772 break;
2773 case Cardinals.S:
2774 foreach (Border b in SouthBorders)
2775 {
2776 if (b.TestCross(position))
2777 return true;
2778 }
2779 break;
2780 case Cardinals.W:
2781 foreach (Border b in WestBorders)
2782 {
2783 if (b.TestCross(position))
2784 return true;
2785 }
2786 break;
2787 }
2788 }
2789 return false;
2790 } 2624 }
2791 2625
2792
2793 /// <summary> 2626 /// <summary>
2794 /// Called when objects or attachments cross the border, or teleport, between regions. 2627 /// Called when objects or attachments cross the border, or teleport, between regions.
2795 /// </summary> 2628 /// </summary>
@@ -4116,60 +3949,11 @@ namespace OpenSim.Region.Framework.Scenes
4116 { 3949 {
4117// CleanDroppedAttachments(); 3950// CleanDroppedAttachments();
4118 3951
4119 if (TestBorderCross(acd.startpos, Cardinals.E)) 3952 // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking)
4120 { 3953 if (acd.startpos.X < 0) acd.startpos.X = 1f;
4121 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E); 3954 if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
4122 acd.startpos.X = crossedBorder.BorderLine.Z - 1; 3955 if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
4123 } 3956 if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
4124
4125 if (TestBorderCross(acd.startpos, Cardinals.N))
4126 {
4127 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
4128 acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
4129 }
4130
4131 //Mitigate http://opensimulator.org/mantis/view.php?id=3522
4132 // Check if start position is outside of region
4133 // If it is, check the Z start position also.. if not, leave it alone.
4134 if (BordersLocked)
4135 {
4136 lock (EastBorders)
4137 {
4138 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
4139 {
4140 m_log.Warn("FIX AGENT POSITION");
4141 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
4142 if (acd.startpos.Z > 720)
4143 acd.startpos.Z = 720;
4144 }
4145 }
4146 lock (NorthBorders)
4147 {
4148 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
4149 {
4150 m_log.Warn("FIX Agent POSITION");
4151 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
4152 if (acd.startpos.Z > 720)
4153 acd.startpos.Z = 720;
4154 }
4155 }
4156 } else
4157 {
4158 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
4159 {
4160 m_log.Warn("FIX AGENT POSITION");
4161 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
4162 if (acd.startpos.Z > 720)
4163 acd.startpos.Z = 720;
4164 }
4165 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
4166 {
4167 m_log.Warn("FIX Agent POSITION");
4168 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
4169 if (acd.startpos.Z > 720)
4170 acd.startpos.Z = 720;
4171 }
4172 }
4173 3957
4174// m_log.DebugFormat( 3958// m_log.DebugFormat(
4175// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}", 3959// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
@@ -4883,44 +4667,6 @@ namespace OpenSim.Region.Framework.Scenes
4883 ScenePresence sp = GetScenePresence(remoteClient.AgentId); 4667 ScenePresence sp = GetScenePresence(remoteClient.AgentId);
4884 if (sp != null) 4668 if (sp != null)
4885 { 4669 {
4886 uint regionX = RegionInfo.RegionLocX;
4887 uint regionY = RegionInfo.RegionLocY;
4888
4889 Utils.LongToUInts(regionHandle, out regionX, out regionY);
4890
4891 int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize;
4892 int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize;
4893
4894 position.X += shiftx;
4895 position.Y += shifty;
4896
4897 bool result = false;
4898
4899 if (TestBorderCross(position,Cardinals.N))
4900 result = true;
4901
4902 if (TestBorderCross(position, Cardinals.S))
4903 result = true;
4904
4905 if (TestBorderCross(position, Cardinals.E))
4906 result = true;
4907
4908 if (TestBorderCross(position, Cardinals.W))
4909 result = true;
4910
4911 // bordercross if position is outside of region
4912
4913 if (!result)
4914 {
4915 regionHandle = RegionInfo.RegionHandle;
4916 }
4917 else
4918 {
4919 // not in this region, undo the shift!
4920 position.X -= shiftx;
4921 position.Y -= shifty;
4922 }
4923
4924 if (EntityTransferModule != null) 4670 if (EntityTransferModule != null)
4925 { 4671 {
4926 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); 4672 EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
diff --git a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
index 52f46f2..a2625c4 100644
--- a/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneCommunicationService.cs
@@ -52,6 +52,7 @@ namespace OpenSim.Region.Framework.Scenes
52 public class SceneCommunicationService //one instance per region 52 public class SceneCommunicationService //one instance per region
53 { 53 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private static string LogHeader = "[SCENE COMMUNICATION SERVICE]";
55 56
56 protected RegionInfo m_regionInfo; 57 protected RegionInfo m_regionInfo;
57 protected Scene m_scene; 58 protected Scene m_scene;
@@ -100,7 +101,7 @@ namespace OpenSim.Region.Framework.Scenes
100 { 101 {
101 m_log.WarnFormat( 102 m_log.WarnFormat(
102 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.", 103 "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.",
103 m_scene.Name, x / Constants.RegionSize, y / Constants.RegionSize); 104 m_scene.Name, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
104 } 105 }
105 } 106 }
106 107
@@ -166,7 +167,7 @@ namespace OpenSim.Region.Framework.Scenes
166 // we only want to send one update to each simulator; the simulator will 167 // we only want to send one update to each simulator; the simulator will
167 // hand it off to the regions where a child agent exists, this does assume 168 // hand it off to the regions where a child agent exists, this does assume
168 // that the region position is cached or performance will degrade 169 // that the region position is cached or performance will degrade
169 Utils.LongToUInts(regionHandle, out x, out y); 170 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
170 GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y); 171 GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y);
171 if (dest == null) 172 if (dest == null)
172 continue; 173 continue;
@@ -206,7 +207,7 @@ namespace OpenSim.Region.Framework.Scenes
206 207
207 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID); 208 //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
208 uint x = 0, y = 0; 209 uint x = 0, y = 0;
209 Utils.LongToUInts(regionHandle, out x, out y); 210 Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
210 211
211 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); 212 GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
212 213
@@ -226,6 +227,8 @@ namespace OpenSim.Region.Framework.Scenes
226 { 227 {
227 foreach (ulong handle in regionslst) 228 foreach (ulong handle in regionslst)
228 { 229 {
230 // We must take a copy here since handle acts like a reference when used in an iterator.
231 // This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region.
229 ulong handleCopy = handle; 232 ulong handleCopy = handle;
230 Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); }); 233 Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); });
231 } 234 }
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 89c7a1a..cb2f377 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -412,7 +412,7 @@ namespace OpenSim.Region.Framework.Scenes
412 { 412 {
413 get 413 get
414 { 414 {
415 Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); 415 Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
416 Vector3 maxScale = Vector3.Zero; 416 Vector3 maxScale = Vector3.Zero;
417 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 417 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
418 418
@@ -529,12 +529,10 @@ namespace OpenSim.Region.Framework.Scenes
529 set 529 set
530 { 530 {
531 Vector3 val = value; 531 Vector3 val = value;
532 if (Scene != null && !IsAttachmentCheckFull() 532 if (Scene != null
533 && !Scene.LoadingPrims && 533 && Scene.PositionIsInCurrentRegion(val)
534 (Scene.TestBorderCross(val, Cardinals.E) || 534 && !IsAttachmentCheckFull()
535 Scene.TestBorderCross(val, Cardinals.W) || 535 && !Scene.LoadingPrims
536 Scene.TestBorderCross(val, Cardinals.N) ||
537 Scene.TestBorderCross(val, Cardinals.S))
538 ) 536 )
539 { 537 {
540 if (!inTransit) 538 if (!inTransit)
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
index 91293c4..8979659 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
@@ -2979,10 +2979,7 @@ namespace OpenSim.Region.Framework.Scenes
2979 { 2979 {
2980 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0); 2980 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0);
2981 2981
2982 if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N) 2982 if (!ParentGroup.Scene.PositionIsInCurrentRegion(newpos))
2983 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
2984 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
2985 || ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
2986 { 2983 {
2987 ParentGroup.AbsolutePosition = newpos; 2984 ParentGroup.AbsolutePosition = newpos;
2988 return; 2985 return;
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index dff582b..3e278a9 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -842,9 +842,8 @@ namespace OpenSim.Region.Framework.Scenes
842 foreach (ulong handle in seeds.Keys) 842 foreach (ulong handle in seeds.Keys)
843 { 843 {
844 uint x, y; 844 uint x, y;
845 Utils.LongToUInts(handle, out x, out y); 845 Util.RegionHandleToRegionLoc(handle, out x, out y);
846 x = x / Constants.RegionSize; 846
847 y = y / Constants.RegionSize;
848 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) 847 if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
849 { 848 {
850 old.Add(handle); 849 old.Add(handle);
@@ -866,9 +865,7 @@ namespace OpenSim.Region.Framework.Scenes
866 foreach (KeyValuePair<ulong, string> kvp in KnownRegions) 865 foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
867 { 866 {
868 uint x, y; 867 uint x, y;
869 Utils.LongToUInts(kvp.Key, out x, out y); 868 Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
870 x = x / Constants.RegionSize;
871 y = y / Constants.RegionSize;
872 m_log.Info(" >> "+x+", "+y+": "+kvp.Value); 869 m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
873 } 870 }
874 } 871 }
@@ -1170,18 +1167,6 @@ namespace OpenSim.Region.Framework.Scenes
1170 1167
1171 if (ParentID == 0) 1168 if (ParentID == 0)
1172 { 1169 {
1173 if (m_scene.TestBorderCross(pos, Cardinals.E))
1174 {
1175 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
1176 pos.X = crossedBorder.BorderLine.Z - 1;
1177 }
1178
1179 if (m_scene.TestBorderCross(pos, Cardinals.N))
1180 {
1181 Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
1182 pos.Y = crossedBorder.BorderLine.Z - 1;
1183 }
1184
1185 CheckAndAdjustLandingPoint(ref pos); 1170 CheckAndAdjustLandingPoint(ref pos);
1186 1171
1187 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) 1172 if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
@@ -1201,7 +1186,7 @@ namespace OpenSim.Region.Framework.Scenes
1201 1186
1202 float posZLimit = 0; 1187 float posZLimit = 0;
1203 1188
1204 if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize) 1189 if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY)
1205 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; 1190 posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
1206 1191
1207 float newPosZ = posZLimit + localAVHeight / 2; 1192 float newPosZ = posZLimit + localAVHeight / 2;
@@ -2612,7 +2597,7 @@ namespace OpenSim.Region.Framework.Scenes
2612 if (regionCombinerModule != null) 2597 if (regionCombinerModule != null)
2613 regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); 2598 regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
2614 else 2599 else
2615 regionSize = new Vector2(Constants.RegionSize); 2600 regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY);
2616 2601
2617 if (pos.X < 0 || pos.X >= regionSize.X 2602 if (pos.X < 0 || pos.X >= regionSize.X
2618 || pos.Y < 0 || pos.Y >= regionSize.Y 2603 || pos.Y < 0 || pos.Y >= regionSize.Y
@@ -2630,8 +2615,8 @@ namespace OpenSim.Region.Framework.Scenes
2630// } 2615// }
2631 2616
2632 // Get terrain height for sub-region in a megaregion if necessary 2617 // Get terrain height for sub-region in a megaregion if necessary
2633 int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); 2618 int X = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
2634 int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); 2619 int Y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y);
2635 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y); 2620 GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y);
2636 // If X and Y is NaN, target_region will be null 2621 // If X and Y is NaN, target_region will be null
2637 if (target_region == null) 2622 if (target_region == null)
@@ -2642,7 +2627,7 @@ namespace OpenSim.Region.Framework.Scenes
2642 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) 2627 if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
2643 targetScene = m_scene; 2628 targetScene = m_scene;
2644 2629
2645 float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)]; 2630 float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)];
2646 // dont try to land underground 2631 // dont try to land underground
2647 terrainHeight += Appearance.AvatarHeight / 2; 2632 terrainHeight += Appearance.AvatarHeight / 2;
2648 pos.Z = Math.Max(terrainHeight, pos.Z); 2633 pos.Z = Math.Max(terrainHeight, pos.Z);
@@ -3872,32 +3857,28 @@ namespace OpenSim.Region.Framework.Scenes
3872// m_log.DebugFormat( 3857// m_log.DebugFormat(
3873// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}", 3858// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
3874// pos2, Name, Scene.Name); 3859// pos2, Name, Scene.Name);
3875 3860
3876 if( Scene.TestBorderCross(pos2, Cardinals.E) || 3861 if (Scene.PositionIsInCurrentRegion(pos2))
3877 Scene.TestBorderCross(pos2, Cardinals.W) || 3862 return;
3878 Scene.TestBorderCross(pos2, Cardinals.N) || 3863
3879 Scene.TestBorderCross(pos2, Cardinals.S) 3864 if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero)
3880 )
3881 { 3865 {
3882 if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero) 3866 // we don't have entity transfer module
3883 { 3867 Vector3 pos = AbsolutePosition;
3884 // we don't have entity transfer module 3868 float px = pos.X;
3885 Vector3 pos = AbsolutePosition; 3869 if (px < 0)
3886 float px = pos.X; 3870 pos.X += Velocity.X * 2;
3887 if (px < 0) 3871 else if (px > m_scene.RegionInfo.RegionSizeX)
3888 pos.X += Velocity.X * 2; 3872 pos.X -= Velocity.X * 2;
3889 else if (px > m_scene.RegionInfo.RegionSizeX)
3890 pos.X -= Velocity.X * 2;
3891 3873
3892 float py = pos.Y; 3874 float py = pos.Y;
3893 if (py < 0) 3875 if (py < 0)
3894 pos.Y += Velocity.Y * 2; 3876 pos.Y += Velocity.Y * 2;
3895 else if (py > m_scene.RegionInfo.RegionSizeY) 3877 else if (py > m_scene.RegionInfo.RegionSizeY)
3896 pos.Y -= Velocity.Y * 2; 3878 pos.Y -= Velocity.Y * 2;
3897 3879
3898 Velocity = Vector3.Zero; 3880 Velocity = Vector3.Zero;
3899 AbsolutePosition = pos; 3881 AbsolutePosition = pos;
3900 }
3901 } 3882 }
3902 } 3883 }
3903 3884
@@ -3962,7 +3943,7 @@ namespace OpenSim.Region.Framework.Scenes
3962 3943
3963 // Put the child agent back at the center 3944 // Put the child agent back at the center
3964 AbsolutePosition 3945 AbsolutePosition
3965 = new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 70); 3946 = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70);
3966 3947
3967 Animator.ResetAnimations(); 3948 Animator.ResetAnimations();
3968 } 3949 }
@@ -3989,9 +3970,7 @@ namespace OpenSim.Region.Framework.Scenes
3989 if (handle != Scene.RegionInfo.RegionHandle) 3970 if (handle != Scene.RegionInfo.RegionHandle)
3990 { 3971 {
3991 uint x, y; 3972 uint x, y;
3992 Utils.LongToUInts(handle, out x, out y); 3973 Util.RegionHandleToRegionLoc(handle, out x, out y);
3993 x = x / Constants.RegionSize;
3994 y = y / Constants.RegionSize;
3995 3974
3996// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); 3975// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
3997// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); 3976// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index b6e0a97..3d563a6 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -25,14 +25,21 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenSim.Framework;
29using OpenSim.Region.Framework.Interfaces;
30using System; 28using System;
29using System.IO;
31using System.Text; 30using System.Text;
31using System.Reflection;
32using System.Xml; 32using System.Xml;
33using System.IO;
34using System.Xml.Serialization; 33using System.Xml.Serialization;
35 34
35using OpenSim.Data;
36using OpenSim.Framework;
37using OpenSim.Region.Framework.Interfaces;
38
39using OpenMetaverse;
40
41using log4net;
42
36namespace OpenSim.Region.Framework.Scenes 43namespace OpenSim.Region.Framework.Scenes
37{ 44{
38 /// <summary> 45 /// <summary>
@@ -40,140 +47,136 @@ namespace OpenSim.Region.Framework.Scenes
40 /// </summary> 47 /// </summary>
41 public class TerrainChannel : ITerrainChannel 48 public class TerrainChannel : ITerrainChannel
42 { 49 {
43 private readonly bool[,] taint; 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 private double[,] map; 51 private static string LogHeader = "[TERRAIN CHANNEL]";
45 52
53 protected TerrainData m_terrainData;
54
55 public int Width { get { return m_terrainData.SizeX; } } // X dimension
56 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
57 public int Height { get { return m_terrainData.SizeY; } } // Y dimension
58 public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
59
60 // Default, not-often-used builder
46 public TerrainChannel() 61 public TerrainChannel()
47 { 62 {
48 map = new double[Constants.RegionSize, Constants.RegionSize]; 63 m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
49 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 64 FlatLand();
50 65 // PinHeadIsland();
51 PinHeadIsland();
52 } 66 }
53 67
54 public TerrainChannel(String type) 68 // Create terrain of given size
69 public TerrainChannel(int pX, int pY)
55 { 70 {
56 map = new double[Constants.RegionSize, Constants.RegionSize]; 71 m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
57 taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; 72 }
58 73
74 // Create terrain of specified size and initialize with specified terrain.
75 // TODO: join this with the terrain initializers.
76 public TerrainChannel(String type, int pX, int pY, int pZ)
77 {
78 m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
59 if (type.Equals("flat")) 79 if (type.Equals("flat"))
60 FlatLand(); 80 FlatLand();
61 else 81 else
62 PinHeadIsland(); 82 PinHeadIsland();
63 } 83 }
64 84
65 public TerrainChannel(double[,] import) 85 // Create channel passed a heightmap and expected dimensions of the region.
86 // The heightmap might not fit the passed size so accomodations must be made.
87 public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude)
66 { 88 {
67 map = import; 89 int hmSizeX = pM.GetLength(0);
68 taint = new bool[import.GetLength(0),import.GetLength(1)]; 90 int hmSizeY = pM.GetLength(1);
69 }
70 91
71 public TerrainChannel(bool createMap) 92 m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
72 { 93
73 if (createMap) 94 for (int xx = 0; xx < pSizeX; xx++)
74 { 95 for (int yy = 0; yy < pSizeY; yy++)
75 map = new double[Constants.RegionSize,Constants.RegionSize]; 96 if (xx > hmSizeX || yy > hmSizeY)
76 taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16]; 97 m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
77 } 98 else
99 m_terrainData[xx, yy] = (float)pM[xx, yy];
78 } 100 }
79 101
80 public TerrainChannel(int w, int h) 102 public TerrainChannel(TerrainData pTerrData)
81 { 103 {
82 map = new double[w,h]; 104 m_terrainData = pTerrData;
83 taint = new bool[w / 16,h / 16];
84 } 105 }
85 106
86 #region ITerrainChannel Members 107 #region ITerrainChannel Members
87 108
88 public int Width 109 // ITerrainChannel.MakeCopy()
110 public ITerrainChannel MakeCopy()
89 { 111 {
90 get { return map.GetLength(0); } 112 return this.Copy();
91 } 113 }
92 114
93 public int Height 115 // ITerrainChannel.GetTerrainData()
116 public TerrainData GetTerrainData()
94 { 117 {
95 get { return map.GetLength(1); } 118 return m_terrainData;
96 } 119 }
97 120
98 public ITerrainChannel MakeCopy() 121 // ITerrainChannel.GetFloatsSerialized()
122 // This one dimensional version is ordered so height = map[y*sizeX+x];
123 // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
124 // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
125 public float[] GetFloatsSerialised()
99 { 126 {
100 TerrainChannel copy = new TerrainChannel(false); 127 return m_terrainData.GetFloatsSerialized();
101 copy.map = (double[,]) map.Clone();
102
103 return copy;
104 } 128 }
105 129
106 public float[] GetFloatsSerialised() 130 // ITerrainChannel.GetDoubles()
131 public double[,] GetDoubles()
107 { 132 {
108 // Move the member variables into local variables, calling 133 double[,] heights = new double[Width, Height];
109 // member variables 256*256 times gets expensive
110 int w = Width;
111 int h = Height;
112 float[] heights = new float[w * h];
113 134
114 int i, j; // map coordinates
115 int idx = 0; // index into serialized array 135 int idx = 0; // index into serialized array
116 for (i = 0; i < h; i++) 136 for (int ii = 0; ii < Width; ii++)
117 { 137 {
118 for (j = 0; j < w; j++) 138 for (int jj = 0; jj < Height; jj++)
119 { 139 {
120 heights[idx++] = (float)map[j, i]; 140 heights[ii, jj] = (double)m_terrainData[ii, jj];
141 idx++;
121 } 142 }
122 } 143 }
123 144
124 return heights; 145 return heights;
125 } 146 }
126 147
127 public double[,] GetDoubles() 148 // ITerrainChannel.this[x,y]
128 {
129 return map;
130 }
131
132 public double this[int x, int y] 149 public double this[int x, int y]
133 { 150 {
134 get 151 get {
135 { 152 if (x < 0 || x >= Width || y < 0 || y >= Height)
136 if (x < 0) x = 0; 153 return 0;
137 if (y < 0) y = 0; 154 return (double)m_terrainData[x, y];
138 if (x >= (int)Constants.RegionSize) x = (int)Constants.RegionSize - 1;
139 if (y >= (int)Constants.RegionSize) y = (int)Constants.RegionSize - 1;
140
141 return map[x, y];
142 } 155 }
143 set 156 set
144 { 157 {
145 // Will "fix" terrain hole problems. Although not fantastically.
146 if (Double.IsNaN(value) || Double.IsInfinity(value)) 158 if (Double.IsNaN(value) || Double.IsInfinity(value))
147 return; 159 return;
148 160
149 if (map[x, y] != value) 161 m_terrainData[x, y] = (float)value;
150 {
151 taint[x / 16, y / 16] = true;
152 map[x, y] = value;
153 }
154 } 162 }
155 } 163 }
156 164
157 public bool Tainted(int x, int y) 165 // ITerrainChannel.GetHieghtAtXYZ(x, y, z)
166 public float GetHeightAtXYZ(float x, float y, float z)
158 { 167 {
159 if (taint[x / 16, y / 16]) 168 if (x < 0 || x >= Width || y < 0 || y >= Height)
160 { 169 return 0;
161 taint[x / 16, y / 16] = false; 170 return m_terrainData[(int)x, (int)y];
162 return true;
163 }
164 return false;
165 } 171 }
166 172
167 #endregion 173 // ITerrainChannel.Tainted()
168 174 public bool Tainted(int x, int y)
169 public TerrainChannel Copy()
170 { 175 {
171 TerrainChannel copy = new TerrainChannel(false); 176 return m_terrainData.IsTaintedAt(x, y);
172 copy.map = (double[,]) map.Clone();
173
174 return copy;
175 } 177 }
176 178
179 // ITerrainChannel.SaveToXmlString()
177 public string SaveToXmlString() 180 public string SaveToXmlString()
178 { 181 {
179 XmlWriterSettings settings = new XmlWriterSettings(); 182 XmlWriterSettings settings = new XmlWriterSettings();
@@ -189,13 +192,7 @@ namespace OpenSim.Region.Framework.Scenes
189 } 192 }
190 } 193 }
191 194
192 private void WriteXml(XmlWriter writer) 195 // ITerrainChannel.LoadFromXmlString()
193 {
194 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
195 ToXml(writer);
196 writer.WriteEndElement();
197 }
198
199 public void LoadFromXmlString(string data) 196 public void LoadFromXmlString(string data)
200 { 197 {
201 StringReader sr = new StringReader(data); 198 StringReader sr = new StringReader(data);
@@ -207,12 +204,124 @@ namespace OpenSim.Region.Framework.Scenes
207 sr.Close(); 204 sr.Close();
208 } 205 }
209 206
207 // ITerrainChannel.Merge
208 public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement)
209 {
210 m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader,
211 newTerrain.Width, newTerrain.Height,
212 displacement, radianRotation, rotationDisplacement,
213 m_terrainData.SizeX, m_terrainData.SizeY);
214 for (int xx = 0; xx < newTerrain.Width; xx++)
215 {
216 for (int yy = 0; yy < newTerrain.Height; yy++)
217 {
218 int dispX = (int)displacement.X;
219 int dispY = (int)displacement.Y;
220 float newHeight = (float)newTerrain[xx, yy] + displacement.Z;
221 if (radianRotation == 0)
222 {
223 // If no rotation, place the new height in the specified location
224 dispX += xx;
225 dispY += yy;
226 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
227 {
228 m_terrainData[dispX, dispY] = newHeight;
229 }
230 }
231 else
232 {
233 // If rotating, we have to smooth the result because the conversion
234 // to ints will mean heightmap entries will not get changed
235 // First compute the rotation location for the new height.
236 dispX += (int)(rotationDisplacement.X
237 + ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation)
238 - ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) );
239
240 dispY += (int)(rotationDisplacement.Y
241 + ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation)
242 + ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) );
243
244 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
245 {
246 float oldHeight = m_terrainData[dispX, dispY];
247 // Smooth the heights around this location if the old height is far from this one
248 for (int sxx = dispX - 2; sxx < dispX + 2; sxx++)
249 {
250 for (int syy = dispY - 2; syy < dispY + 2; syy++)
251 {
252 if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY)
253 {
254 if (sxx == dispX && syy == dispY)
255 {
256 // Set height for the exact rotated point
257 m_terrainData[dispX, dispY] = newHeight;
258 }
259 else
260 {
261 if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f)
262 {
263 // If the adjacent height is far off, force it to this height
264 m_terrainData[sxx, syy] = newHeight;
265 }
266 }
267 }
268 }
269 }
270 }
271
272 if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
273 {
274 m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy];
275 }
276 }
277 }
278 }
279 }
280
281 #endregion
282
283 public TerrainChannel Copy()
284 {
285 TerrainChannel copy = new TerrainChannel();
286 copy.m_terrainData = m_terrainData.Clone();
287 return copy;
288 }
289
290 private void WriteXml(XmlWriter writer)
291 {
292 if (Width == Constants.RegionSize && Height == Constants.RegionSize)
293 {
294 // Downward compatibility for legacy region terrain maps.
295 // If region is exactly legacy size, return the old format XML.
296 writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
297 ToXml(writer);
298 writer.WriteEndElement();
299 }
300 else
301 {
302 // New format XML that includes width and length.
303 writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
304 ToXml2(writer);
305 writer.WriteEndElement();
306 }
307 }
308
210 private void ReadXml(XmlReader reader) 309 private void ReadXml(XmlReader reader)
211 { 310 {
212 reader.ReadStartElement("TerrainMap"); 311 // Check the first element. If legacy element, use the legacy reader.
213 FromXml(reader); 312 if (reader.IsStartElement("TerrainMap"))
313 {
314 reader.ReadStartElement("TerrainMap");
315 FromXml(reader);
316 }
317 else
318 {
319 reader.ReadStartElement("TerrainMap2");
320 FromXml2(reader);
321 }
214 } 322 }
215 323
324 // Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
216 private void ToXml(XmlWriter xmlWriter) 325 private void ToXml(XmlWriter xmlWriter)
217 { 326 {
218 float[] mapData = GetFloatsSerialised(); 327 float[] mapData = GetFloatsSerialised();
@@ -226,12 +335,15 @@ namespace OpenSim.Region.Framework.Scenes
226 serializer.Serialize(xmlWriter, buffer); 335 serializer.Serialize(xmlWriter, buffer);
227 } 336 }
228 337
338 // Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
229 private void FromXml(XmlReader xmlReader) 339 private void FromXml(XmlReader xmlReader)
230 { 340 {
231 XmlSerializer serializer = new XmlSerializer(typeof(byte[])); 341 XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
232 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); 342 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
233 int index = 0; 343 int index = 0;
234 344
345 m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight);
346
235 for (int y = 0; y < Height; y++) 347 for (int y = 0; y < Height; y++)
236 { 348 {
237 for (int x = 0; x < Width; x++) 349 for (int x = 0; x < Width; x++)
@@ -244,35 +356,63 @@ namespace OpenSim.Region.Framework.Scenes
244 } 356 }
245 } 357 }
246 358
359 private class TerrainChannelXMLPackage
360 {
361 public int Version;
362 public int SizeX;
363 public int SizeY;
364 public int SizeZ;
365 public float CompressionFactor;
366 public int[] Map;
367 public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap)
368 {
369 Version = 1;
370 SizeX = pX;
371 SizeY = pY;
372 SizeZ = pZ;
373 CompressionFactor = pCompressionFactor;
374 Map = pMap;
375 }
376 }
377
378 // New terrain serialization format that includes the width and length.
379 private void ToXml2(XmlWriter xmlWriter)
380 {
381 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.CompressionFactor,
382 m_terrainData.GetCompressedMap());
383 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
384 serializer.Serialize(xmlWriter, package);
385 }
386
387 // New terrain serialization format that includes the width and length.
388 private void FromXml2(XmlReader xmlReader)
389 {
390 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
391 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
392 m_terrainData = new HeightmapTerrainData(package.Map, package.CompressionFactor, package.SizeX, package.SizeY, package.SizeZ);
393 }
394
395 // Fill the heightmap with the center bump terrain
247 private void PinHeadIsland() 396 private void PinHeadIsland()
248 { 397 {
249 int x; 398 for (int x = 0; x < Width; x++)
250 for (x = 0; x < Constants.RegionSize; x++)
251 { 399 {
252 int y; 400 for (int y = 0; y < Height; y++)
253 for (y = 0; y < Constants.RegionSize; y++)
254 { 401 {
255 map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; 402 m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
256 double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; 403 float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
257 double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; 404 float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
258 if (map[x, y] < spherFacA) 405 if (m_terrainData[x, y]< spherFacA)
259 map[x, y] = spherFacA; 406 m_terrainData[x, y]= spherFacA;
260 if (map[x, y] < spherFacB) 407 if (m_terrainData[x, y]< spherFacB)
261 map[x, y] = spherFacB; 408 m_terrainData[x, y] = spherFacB;
262 } 409 }
263 } 410 }
264 } 411 }
265 412
266 private void FlatLand() 413 private void FlatLand()
267 { 414 {
268 int x; 415 m_terrainData.ClearLand();
269 for (x = 0; x < Constants.RegionSize; x++)
270 {
271 int y;
272 for (y = 0; y < Constants.RegionSize; y++)
273 map[x, y] = 21;
274 }
275 } 416 }
276
277 } 417 }
278} 418}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
new file mode 100644
index 0000000..fc8f8cd
--- /dev/null
+++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
@@ -0,0 +1,948 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/* Freely adapted from the Aurora version of the terrain compressor.
29 * Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
30 */
31
32using System;
33using System.Reflection;
34
35using log4net;
36
37using OpenSim.Framework;
38using OpenSim.Region.Framework;
39using OpenSim.Region.Framework.Scenes;
40
41using OpenMetaverse;
42using OpenMetaverse.Packets;
43
44namespace OpenSim.Region.ClientStack.LindenUDP
45{
46 public static class OpenSimTerrainCompressor
47 {
48// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50#pragma warning disable 414
51 private static string LogHeader = "[TERRAIN COMPRESSOR]";
52#pragma warning restore 414
53
54 public const int END_OF_PATCHES = 97;
55
56 private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
57 private const int STRIDE = 264;
58
59 private const int ZERO_CODE = 0x0;
60 private const int ZERO_EOB = 0x2;
61 private const int POSITIVE_VALUE = 0x6;
62 private const int NEGATIVE_VALUE = 0x7;
63
64 private static readonly float[] DequantizeTable16 =
65 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
66
67 private static readonly float[] DequantizeTable32 =
68 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
69
70 private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
71 //private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize];
72 private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
73 private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
74
75 private static readonly float[] QuantizeTable16 =
76 new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
77
78 static OpenSimTerrainCompressor()
79 {
80 // Initialize the decompression tables
81 BuildDequantizeTable16();
82 SetupCosines16();
83 BuildCopyMatrix16();
84 BuildQuantizeTable16();
85 }
86
87 // Used to send cloud and wind patches
88 public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX,
89 int pRegionSizeY)
90 {
91 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
92
93 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
94 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
95
96 // Should be enough to fit even the most poorly packed data
97 byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2];
98 BitPack bitpack = new BitPack(data, 0);
99 bitpack.PackBits(header.Stride, 16);
100 bitpack.PackBits(header.PatchSize, 8);
101 bitpack.PackBits(type, 8);
102
103 foreach (TerrainPatch t in patches)
104 CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY);
105
106 bitpack.PackBits(END_OF_PATCHES, 8);
107
108 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
109 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
110
111 return layer;
112 }
113
114 // Create a land packet for a single patch.
115 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
116 {
117 int[] xPieces = new int[1];
118 int[] yPieces = new int[1];
119 xPieces[0] = patchX; // patch X dimension
120 yPieces[0] = patchY;
121
122 return CreateLandPacket(terrData, xPieces, yPieces);
123 }
124
125 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces)
126 {
127 byte landPacketType = (byte)TerrainPatch.LayerType.Land;
128 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
129 {
130 landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
131 }
132
133 return CreateLandPacket(terrData, xPieces, yPieces, landPacketType);
134 }
135
136 /// <summary>
137 /// Creates a LayerData packet for compressed land data given a full
138 /// simulator heightmap and an array of indices of patches to compress
139 /// </summary>
140 /// <param name="terrData">
141 /// Terrain data that can result in a meter square heightmap.
142 /// </param>
143 /// <param name="x">
144 /// Array of indexes in the grid of patches
145 /// for this simulator.
146 /// If creating a packet for multiple patches, there will be entries in
147 /// both the X and Y arrays for each of the patches.
148 /// For example if patches 1 and 17 are to be sent,
149 /// x[] = {1,1} and y[] = {0,1} which specifies the patches at
150 /// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches).
151 /// </param>
152 /// <param name="y">
153 /// Array of indexes in the grid of patches.
154 /// </param>
155 /// <param name="type"></param>
156 /// <returns></returns>
157 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
158 {
159 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
160
161 TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
162 {Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
163
164 byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
165 BitPack bitpack = new BitPack(data, 0);
166 bitpack.PackBits(header.Stride, 16);
167 bitpack.PackBits(header.PatchSize, 8);
168 bitpack.PackBits(type, 8);
169
170 for (int i = 0; i < x.Length; i++)
171 CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
172
173 bitpack.PackBits(END_OF_PATCHES, 8);
174
175 layer.LayerData.Data = new byte[bitpack.BytePos + 1];
176 Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
177
178 return layer;
179 }
180
181 // Unused: left for historical reference.
182 public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
183 {
184 TerrainPatch.Header header = PrescanPatch(patchData);
185 header.QuantWBits = 136;
186 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
187 {
188 header.PatchIDs = (y & 0xFFFF);
189 header.PatchIDs += (x << 16);
190 }
191 else
192 {
193 header.PatchIDs = (y & 0x1F);
194 header.PatchIDs += (x << 5);
195 }
196
197 // NOTE: No idea what prequant and postquant should be or what they do
198
199 int wbits;
200 int[] patch = CompressPatch(patchData, header, 10, out wbits);
201 wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits);
202 EncodePatch(output, patch, 0, wbits);
203 }
204
205 /// <summary>
206 /// Add a patch of terrain to a BitPacker
207 /// </summary>
208 /// <param name="output">BitPacker to write the patch to</param>
209 /// <param name="heightmap">
210 /// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
211 /// </param>
212 /// <param name="patchX">
213 /// X offset of the patch to create.
214 /// </param>
215 /// <param name="patchY">
216 /// Y offset of the patch to create.
217 /// </param>
218 /// <param name="pRegionSizeX"></param>
219 /// <param name="pRegionSizeY"></param>
220 public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
221 {
222 TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
223 header.QuantWBits = 136;
224
225 // If larger than legacy region size, pack patch X and Y info differently.
226 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
227 {
228 header.PatchIDs = (patchY & 0xFFFF);
229 header.PatchIDs += (patchX << 16);
230 }
231 else
232 {
233 header.PatchIDs = (patchY & 0x1F);
234 header.PatchIDs += (patchX << 5);
235 }
236
237 // m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}",
238 // LogHeader, patchX, patchY, header.DCOffset, header.Range);
239
240 // NOTE: No idea what prequant and postquant should be or what they do
241 int wbits;
242 int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
243 wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
244 EncodePatch(output, patch, 0, wbits);
245 }
246
247 private static TerrainPatch.Header PrescanPatch(float[] patch)
248 {
249 TerrainPatch.Header header = new TerrainPatch.Header();
250 float zmax = -99999999.0f;
251 float zmin = 99999999.0f;
252
253 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
254 {
255 float val = patch[i];
256 if (val > zmax) zmax = val;
257 if (val < zmin) zmin = val;
258 }
259
260 header.DCOffset = zmin;
261 header.Range = (int) ((zmax - zmin) + 1.0f);
262
263 return header;
264 }
265
266 // Scan the height info we're returning and return a patch packet header for this patch.
267 private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
268 {
269 TerrainPatch.Header header = new TerrainPatch.Header();
270 float zmax = -99999999.0f;
271 float zmin = 99999999.0f;
272
273 for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++)
274 {
275 for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++)
276 {
277 float val = terrData[i, j];
278 if (val > zmax) zmax = val;
279 if (val < zmin) zmin = val;
280 }
281 }
282
283 header.DCOffset = zmin;
284 header.Range = (int)((zmax - zmin) + 1.0f);
285
286 return header;
287 }
288
289 public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
290 {
291 TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
292
293 // Quantized word bits
294 if (header.QuantWBits == END_OF_PATCHES)
295 return header;
296
297 // DC offset
298 header.DCOffset = bitpack.UnpackFloat();
299
300 // Range
301 header.Range = bitpack.UnpackBits(16);
302
303 // Patch IDs (10 bits)
304 header.PatchIDs = bitpack.UnpackBits(10);
305
306 // Word bits
307 header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
308
309 return header;
310 }
311
312 private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
313 uint pRegionSizeY, int wbits)
314 {
315 /*
316 int temp;
317 int wbits = (header.QuantWBits & 0x0f) + 2;
318 uint maxWbits = (uint)wbits + 5;
319 uint minWbits = ((uint)wbits >> 1);
320 int wbitsMaxValue;
321 */
322 // goal is to determ minimum number of bits to use so all data fits
323 /*
324 wbits = (int)minWbits;
325 wbitsMaxValue = (1 << wbits);
326
327 for (int i = 0; i < patch.Length; i++)
328 {
329 temp = patch[i];
330 if (temp != 0)
331 {
332 // Get the absolute value
333 if (temp < 0) temp *= -1;
334
335 no coments..
336
337 for (int j = (int)maxWbits; j > (int)minWbits; j--)
338 {
339 if ((temp & (1 << j)) != 0)
340 {
341 if (j > wbits) wbits = j;
342 break;
343 }
344 }
345
346 while (temp > wbitsMaxValue)
347 {
348 wbits++;
349 if (wbits == maxWbits)
350 goto Done;
351 wbitsMaxValue = 1 << wbits;
352 }
353 }
354 }
355
356 Done:
357
358 // wbits += 1;
359 */
360 // better check
361 if (wbits > 17)
362 wbits = 16;
363 else if (wbits < 3)
364 wbits = 3;
365
366 header.QuantWBits &= 0xf0;
367
368 header.QuantWBits |= (wbits - 2);
369
370 output.PackBits(header.QuantWBits, 8);
371 output.PackFloat(header.DCOffset);
372 output.PackBits(header.Range, 16);
373 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
374 output.PackBits(header.PatchIDs, 32);
375 else
376 output.PackBits(header.PatchIDs, 10);
377
378 return wbits;
379 }
380
381 private static void IDCTColumn16(float[] linein, float[] lineout, int column)
382 {
383 for (int n = 0; n < Constants.TerrainPatchSize; n++)
384 {
385 float total = OO_SQRT2*linein[column];
386
387 for (int u = 1; u < Constants.TerrainPatchSize; u++)
388 {
389 int usize = u*Constants.TerrainPatchSize;
390 total += linein[usize + column]*CosineTable16[usize + n];
391 }
392
393 lineout[Constants.TerrainPatchSize*n + column] = total;
394 }
395 }
396
397 private static void IDCTLine16(float[] linein, float[] lineout, int line)
398 {
399 const float oosob = 2.0f/Constants.TerrainPatchSize;
400 int lineSize = line*Constants.TerrainPatchSize;
401
402 for (int n = 0; n < Constants.TerrainPatchSize; n++)
403 {
404 float total = OO_SQRT2*linein[lineSize];
405
406 for (int u = 1; u < Constants.TerrainPatchSize; u++)
407 {
408 total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
409 }
410
411 lineout[lineSize + n] = total*oosob;
412 }
413 }
414
415/*
416 private static void DCTLine16(float[] linein, float[] lineout, int line)
417 {
418 float total = 0.0f;
419 int lineSize = line * Constants.TerrainPatchSize;
420
421 for (int n = 0; n < Constants.TerrainPatchSize; n++)
422 {
423 total += linein[lineSize + n];
424 }
425
426 lineout[lineSize] = OO_SQRT2 * total;
427
428 int uptr = 0;
429 for (int u = 1; u < Constants.TerrainPatchSize; u++)
430 {
431 total = 0.0f;
432 uptr += Constants.TerrainPatchSize;
433
434 for (int n = 0; n < Constants.TerrainPatchSize; n++)
435 {
436 total += linein[lineSize + n] * CosineTable16[uptr + n];
437 }
438
439 lineout[lineSize + u] = total;
440 }
441 }
442*/
443
444 private static void DCTLine16(float[] linein, float[] lineout, int line)
445 {
446 // outputs transpose data (lines exchanged with coluns )
447 // so to save a bit of cpu when doing coluns
448 float total = 0.0f;
449 int lineSize = line*Constants.TerrainPatchSize;
450
451 for (int n = 0; n < Constants.TerrainPatchSize; n++)
452 {
453 total += linein[lineSize + n];
454 }
455
456 lineout[line] = OO_SQRT2*total;
457
458 for (int u = Constants.TerrainPatchSize;
459 u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
460 u += Constants.TerrainPatchSize)
461 {
462 total = 0.0f;
463 for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
464 {
465 total += linein[ptrn]*CosineTable16[ptru];
466 }
467
468 lineout[line + u] = total;
469 }
470 }
471
472
473 /*
474 private static void DCTColumn16(float[] linein, int[] lineout, int column)
475 {
476 float total = 0.0f;
477 // const float oosob = 2.0f / Constants.TerrainPatchSize;
478
479 for (int n = 0; n < Constants.TerrainPatchSize; n++)
480 {
481 total += linein[Constants.TerrainPatchSize * n + column];
482 }
483
484 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
485 lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
486
487 for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
488 {
489 total = 0.0f;
490
491 for (int n = 0; n < Constants.TerrainPatchSize; n++)
492 {
493 total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
494 }
495
496 // lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
497 lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
498 }
499 }
500
501 private static void DCTColumn16(float[] linein, int[] lineout, int column)
502 {
503 // input columns are in fact stored in lines now
504
505 float total = 0.0f;
506// const float oosob = 2.0f / Constants.TerrainPatchSize;
507 int inlinesptr = Constants.TerrainPatchSize*column;
508
509 for (int n = 0; n < Constants.TerrainPatchSize; n++)
510 {
511 total += linein[inlinesptr + n];
512 }
513
514 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
515 lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
516
517 for (int uptr = Constants.TerrainPatchSize;
518 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
519 uptr += Constants.TerrainPatchSize)
520 {
521 total = 0.0f;
522
523 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
524 {
525 total += linein[n]*CosineTable16[ptru];
526 }
527
528// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
529 lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
530 }
531 }
532 */
533
534 private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
535 {
536 // input columns are in fact stored in lines now
537
538 bool dowbits = wbits != maxwbits;
539 int wbitsMaxValue = 1 << wbits;
540
541 float total = 0.0f;
542 // const float oosob = 2.0f / Constants.TerrainPatchSize;
543 int inlinesptr = Constants.TerrainPatchSize*column;
544
545 for (int n = 0; n < Constants.TerrainPatchSize; n++)
546 {
547 total += linein[inlinesptr + n];
548 }
549
550 // lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
551 int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
552 lineout[CopyMatrix16[column]] = tmp;
553
554 if (dowbits)
555 {
556 if (tmp < 0) tmp *= -1;
557 while (tmp > wbitsMaxValue)
558 {
559 wbits++;
560 wbitsMaxValue = 1 << wbits;
561 if (wbits == maxwbits)
562 {
563 dowbits = false;
564 break;
565 }
566 }
567 }
568
569 for (int uptr = Constants.TerrainPatchSize;
570 uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
571 uptr += Constants.TerrainPatchSize)
572 {
573 total = 0.0f;
574
575 for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
576 {
577 total += linein[n]*CosineTable16[ptru];
578 }
579
580 tmp = (int) (total*QuantizeTable16[uptr + column]);
581 lineout[CopyMatrix16[uptr + column]] = tmp;
582
583 if (dowbits)
584 {
585 if (tmp < 0) tmp *= -1;
586 while (tmp > wbitsMaxValue)
587 {
588 wbits++;
589 wbitsMaxValue = 1 << wbits;
590 if (wbits == maxwbits)
591 {
592 dowbits = false;
593 break;
594 }
595 }
596 }
597 }
598 return wbits;
599 }
600
601 public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
602 {
603 for (int n = 0; n < size*size; n++)
604 {
605 // ?
606 int temp = bitpack.UnpackBits(1);
607 if (temp != 0)
608 {
609 // Value or EOB
610 temp = bitpack.UnpackBits(1);
611 if (temp != 0)
612 {
613 // Value
614 temp = bitpack.UnpackBits(1);
615 if (temp != 0)
616 {
617 // Negative
618 temp = bitpack.UnpackBits((int) header.WordBits);
619 patches[n] = temp*-1;
620 }
621 else
622 {
623 // Positive
624 temp = bitpack.UnpackBits((int) header.WordBits);
625 patches[n] = temp;
626 }
627 }
628 else
629 {
630 // Set the rest to zero
631 // TODO: This might not be necessary
632 for (int o = n; o < size*size; o++)
633 {
634 patches[o] = 0;
635 }
636 break;
637 }
638 }
639 else
640 {
641 patches[n] = 0;
642 }
643 }
644 }
645
646 private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
647 {
648 int maxwbitssize = (1 << wbits) - 1;
649
650 if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
651 {
652 Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
653 return;
654 }
655
656 if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
657
658 for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
659 {
660 int temp = patch[i];
661
662 if (temp == 0)
663 {
664 bool eob = true;
665
666 for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
667 {
668 if (patch[j] != 0)
669 {
670 eob = false;
671 break;
672 }
673 }
674
675 if (eob)
676 {
677 output.PackBits(ZERO_EOB, 2);
678 return;
679 }
680 output.PackBits(ZERO_CODE, 1);
681 }
682 else
683 {
684 if (temp < 0)
685 {
686 temp *= -1;
687
688 if (temp > maxwbitssize) temp = maxwbitssize;
689
690 output.PackBits(NEGATIVE_VALUE, 3);
691 output.PackBits(temp, wbits);
692 }
693 else
694 {
695 if (temp > maxwbitssize) temp = maxwbitssize;
696
697 output.PackBits(POSITIVE_VALUE, 3);
698 output.PackBits(temp, wbits);
699 }
700 }
701 }
702 }
703
704 public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
705 {
706 float[] block = new float[group.PatchSize*group.PatchSize];
707 float[] output = new float[group.PatchSize*group.PatchSize];
708 int prequant = (header.QuantWBits >> 4) + 2;
709 int quantize = 1 << prequant;
710 float ooq = 1.0f/quantize;
711 float mult = ooq*header.Range;
712 float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
713
714 if (group.PatchSize == Constants.TerrainPatchSize)
715 {
716 for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
717 {
718 block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
719 }
720
721 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
722
723 for (int o = 0; o < Constants.TerrainPatchSize; o++)
724 IDCTColumn16(block, ftemp, o);
725 for (int o = 0; o < Constants.TerrainPatchSize; o++)
726 IDCTLine16(ftemp, block, o);
727 }
728 else
729 {
730 for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
731 {
732 block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
733 }
734
735 Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
736 }
737
738 for (int j = 0; j < block.Length; j++)
739 {
740 output[j] = block[j]*mult + addval;
741 }
742
743 return output;
744 }
745
746 private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
747 {
748 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
749 int wordsize = (prequant - 2) & 0x0f;
750 float oozrange = 1.0f/header.Range;
751 float range = (1 << prequant);
752 float premult = oozrange*range;
753 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
754
755 header.QuantWBits = wordsize;
756 header.QuantWBits |= wordsize << 4;
757
758 int k = 0;
759 for (int j = 0; j < Constants.TerrainPatchSize; j++)
760 {
761 for (int i = 0; i < Constants.TerrainPatchSize; i++)
762 block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
763 }
764
765 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
766 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
767
768
769 int maxWbits = prequant + 5;
770 wbits = (prequant >> 1);
771
772 for (int o = 0; o < Constants.TerrainPatchSize; o++)
773 DCTLine16(block, ftemp, o);
774 for (int o = 0; o < Constants.TerrainPatchSize; o++)
775 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
776
777 return itemp;
778 }
779
780 private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
781 {
782 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
783 float oozrange = 1.0f/header.Range;
784 float range = (1 << prequant);
785 float premult = oozrange*range;
786 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
787 int wordsize = (prequant - 2) & 0x0f;
788
789 header.QuantWBits = wordsize;
790 header.QuantWBits |= wordsize << 4;
791
792 int k = 0;
793 for (int j = 0; j < Constants.TerrainPatchSize; j++)
794 {
795 for (int i = 0; i < Constants.TerrainPatchSize; i++)
796 block[k++] = patchData[j, i]*premult - sub;
797 }
798
799 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
800 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
801
802 int maxWbits = prequant + 5;
803 wbits = (prequant >> 1);
804
805 for (int o = 0; o < Constants.TerrainPatchSize; o++)
806 DCTLine16(block, ftemp, o);
807 for (int o = 0; o < Constants.TerrainPatchSize; o++)
808 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
809
810 return itemp;
811 }
812
813 private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
814 int prequant, out int wbits)
815 {
816 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
817 int wordsize = prequant;
818 float oozrange = 1.0f/header.Range;
819 float range = (1 << prequant);
820 float premult = oozrange*range;
821 float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
822
823 header.QuantWBits = wordsize - 2;
824 header.QuantWBits |= (prequant - 2) << 4;
825
826 int k = 0;
827
828 int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ?
829 (terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY;
830 yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize;
831
832 int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ?
833 (terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX;
834 xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize;
835
836 for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++)
837 {
838 for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++)
839 {
840 block[k++] = terrData[xx, yy] * premult - sub;
841 }
842 }
843
844 float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
845 int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
846
847 int maxWbits = prequant + 5;
848 wbits = (prequant >> 1);
849
850 for (int o = 0; o < Constants.TerrainPatchSize; o++)
851 DCTLine16(block, ftemp, o);
852 for (int o = 0; o < Constants.TerrainPatchSize; o++)
853 wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
854
855 return itemp;
856 }
857
858 #region Initialization
859
860 private static void BuildDequantizeTable16()
861 {
862 for (int j = 0; j < Constants.TerrainPatchSize; j++)
863 {
864 for (int i = 0; i < Constants.TerrainPatchSize; i++)
865 {
866 DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
867 }
868 }
869 }
870
871 private static void BuildQuantizeTable16()
872 {
873 const float oosob = 2.0f/Constants.TerrainPatchSize;
874 for (int j = 0; j < Constants.TerrainPatchSize; j++)
875 {
876 for (int i = 0; i < Constants.TerrainPatchSize; i++)
877 {
878// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
879 QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
880 }
881 }
882 }
883
884 private static void SetupCosines16()
885 {
886 const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
887
888 for (int u = 0; u < Constants.TerrainPatchSize; u++)
889 {
890 for (int n = 0; n < Constants.TerrainPatchSize; n++)
891 {
892 CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
893 }
894 }
895 }
896
897 private static void BuildCopyMatrix16()
898 {
899 bool diag = false;
900 bool right = true;
901 int i = 0;
902 int j = 0;
903 int count = 0;
904
905 while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
906 {
907 CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
908
909 if (!diag)
910 {
911 if (right)
912 {
913 if (i < Constants.TerrainPatchSize - 1) i++;
914 else j++;
915
916 right = false;
917 diag = true;
918 }
919 else
920 {
921 if (j < Constants.TerrainPatchSize - 1) j++;
922 else i++;
923
924 right = true;
925 diag = true;
926 }
927 }
928 else
929 {
930 if (right)
931 {
932 i++;
933 j--;
934 if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
935 }
936 else
937 {
938 i--;
939 j++;
940 if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
941 }
942 }
943 }
944 }
945
946 #endregion Initialization
947 }
948}
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 8c0ad75..51ecc8d 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -520,7 +520,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
520 520
521 public Vector3 StartPos 521 public Vector3 StartPos
522 { 522 {
523 get { return new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 50); } 523 get { return new Vector3(m_scene.RegionInfo.RegionSizeX * 0.5f, m_scene.RegionInfo.RegionSizeY * 0.5f, 50f); }
524 set { } 524 set { }
525 } 525 }
526 526
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
index c5cba8e..f5bd44d 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/IRCConnector.cs
@@ -52,6 +52,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
52 52
53 // Local constants 53 // Local constants
54 54
55 // This computation is not the real region center if the region is larger than 256.
56 // This computation isn't fixed because there is not a handle back to the region.
55 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 57 private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
56 private static readonly char[] CS_SPACE = { ' ' }; 58 private static readonly char[] CS_SPACE = { ' ' };
57 59
diff --git a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
index d4fe5e0..5505001 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Chat/RegionState.cs
@@ -44,6 +44,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
44 private static readonly ILog m_log = 44 private static readonly ILog m_log =
45 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 // This computation is not the real region center if the region is larger than 256.
48 // This computation isn't fixed because there is not a handle back to the region.
47 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); 49 private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
48 private const int DEBUG_CHANNEL = 2147483647; 50 private const int DEBUG_CHANNEL = 2147483647;
49 51
diff --git a/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs b/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
index a375da9..0bf23f1 100644
--- a/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
+++ b/OpenSim/Region/OptionalModules/PrimLimitsModule/PrimLimitsModule.cs
@@ -122,8 +122,8 @@ namespace OpenSim.Region.OptionalModules
122 122
123 private bool CanObjectEnter(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene) 123 private bool CanObjectEnter(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene)
124 { 124 {
125 if (newPoint.X < -1f || newPoint.X > (float)(Constants.RegionSize + 1) || 125 if (newPoint.X < -1f || newPoint.X > (scene.RegionInfo.RegionSizeX + 1) ||
126 newPoint.Y < -1f || newPoint.Y > (float)(Constants.RegionSize + 1)) 126 newPoint.Y < -1f || newPoint.Y > (scene.RegionInfo.RegionSizeY) )
127 return true; 127 return true;
128 128
129 SceneObjectPart obj = scene.GetSceneObjectPart(objectID); 129 SceneObjectPart obj = scene.GetSceneObjectPart(objectID);
diff --git a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
index eb386fe..296ab87 100644
--- a/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
+++ b/OpenSim/Region/OptionalModules/Scripting/RegionReadyModule/RegionReadyModule.cs
@@ -170,7 +170,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
170 c.Channel = m_channelNotify; 170 c.Channel = m_channelNotify;
171 c.Message += numScriptsFailed.ToString() + "," + message; 171 c.Message += numScriptsFailed.ToString() + "," + message;
172 c.Type = ChatTypeEnum.Region; 172 c.Type = ChatTypeEnum.Region;
173 c.Position = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30); 173 if (m_scene != null)
174 c.Position = new Vector3((m_scene.RegionInfo.RegionSizeX * 0.5f), (m_scene.RegionInfo.RegionSizeY * 0.5f), 30);
175 else
176 c.Position = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30);
174 c.Sender = null; 177 c.Sender = null;
175 c.SenderUUID = UUID.Zero; 178 c.SenderUUID = UUID.Zero;
176 c.Scene = m_scene; 179 c.Scene = m_scene;
diff --git a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
index 29b39e0..6cbccc0 100644
--- a/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
+++ b/OpenSim/Region/OptionalModules/World/SceneCommands/SceneCommandsModule.cs
@@ -116,37 +116,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
116 + "If teleport is true then some extra teleport debug information is logged.\n" 116 + "If teleport is true then some extra teleport debug information is logged.\n"
117 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", 117 + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
118 HandleDebugSceneSetCommand); 118 HandleDebugSceneSetCommand);
119
120 scene.AddCommand(
121 "Regions",
122 this, "show borders", "show borders", "Show border information for regions", HandleShowBordersCommand);
123 }
124
125 private void HandleShowBordersCommand(string module, string[] args)
126 {
127 StringBuilder sb = new StringBuilder();
128 sb.AppendFormat("Borders for {0}:\n", m_scene.Name);
129
130 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
131 cdt.AddColumn("Cross Direction", 15);
132 cdt.AddColumn("Line", 34);
133 cdt.AddColumn("Trigger Region", 14);
134
135 foreach (Border b in m_scene.NorthBorders)
136 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
137
138 foreach (Border b in m_scene.EastBorders)
139 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
140
141 foreach (Border b in m_scene.SouthBorders)
142 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
143
144 foreach (Border b in m_scene.WestBorders)
145 cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
146
147 cdt.AddToStringBuilder(sb);
148
149 MainConsole.Instance.Output(sb.ToString());
150 } 119 }
151 120
152 private void HandleDebugSceneGetCommand(string module, string[] args) 121 private void HandleDebugSceneGetCommand(string module, string[] args)
@@ -263,4 +232,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
263 } 232 }
264 } 233 }
265 } 234 }
266} \ No newline at end of file 235}
diff --git a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
index 8144870..e4a3382 100644
--- a/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
+++ b/OpenSim/Region/OptionalModules/World/TreePopulator/TreePopulatorModule.cs
@@ -748,8 +748,8 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
748 position.X = s_tree.AbsolutePosition.X + (float)randX; 748 position.X = s_tree.AbsolutePosition.X + (float)randX;
749 position.Y = s_tree.AbsolutePosition.Y + (float)randY; 749 position.Y = s_tree.AbsolutePosition.Y + (float)randY;
750 750
751 if (position.X <= ((int)Constants.RegionSize - 1) && position.X >= 0 && 751 if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 &&
752 position.Y <= ((int)Constants.RegionSize - 1) && position.Y >= 0 && 752 position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 &&
753 Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range) 753 Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range)
754 { 754 {
755 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; 755 UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
diff --git a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
index 0816b7b..8e40561 100644
--- a/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
+++ b/OpenSim/Region/Physics/BasicPhysicsPlugin/BasicPhysicsScene.cs
@@ -46,6 +46,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
46 private List<BasicActor> _actors = new List<BasicActor>(); 46 private List<BasicActor> _actors = new List<BasicActor>();
47 private List<BasicPhysicsPrim> _prims = new List<BasicPhysicsPrim>(); 47 private List<BasicPhysicsPrim> _prims = new List<BasicPhysicsPrim>();
48 private float[] _heightMap; 48 private float[] _heightMap;
49 private Vector3 m_regionExtent;
49 50
50 //protected internal string sceneIdentifier; 51 //protected internal string sceneIdentifier;
51 52
@@ -58,6 +59,12 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
58 59
59 public override void Initialise(IMesher meshmerizer, IConfigSource config) 60 public override void Initialise(IMesher meshmerizer, IConfigSource config)
60 { 61 {
62 throw new Exception("Should not be called.");
63 }
64
65 public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
66 {
67 m_regionExtent = regionExtent;
61 } 68 }
62 69
63 public override void Dispose() {} 70 public override void Dispose() {}
@@ -121,23 +128,23 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
121 { 128 {
122 actorPosition.Y = 0.1F; 129 actorPosition.Y = 0.1F;
123 } 130 }
124 else if (actor.Position.Y >= Constants.RegionSize) 131 else if (actor.Position.Y >= m_regionExtent.Y)
125 { 132 {
126 actorPosition.Y = ((int)Constants.RegionSize - 0.1f); 133 actorPosition.Y = (m_regionExtent.Y - 0.1f);
127 } 134 }
128 135
129 if (actor.Position.X < 0) 136 if (actor.Position.X < 0)
130 { 137 {
131 actorPosition.X = 0.1F; 138 actorPosition.X = 0.1F;
132 } 139 }
133 else if (actor.Position.X >= Constants.RegionSize) 140 else if (actor.Position.X >= m_regionExtent.X)
134 { 141 {
135 actorPosition.X = ((int)Constants.RegionSize - 0.1f); 142 actorPosition.X = (m_regionExtent.X - 0.1f);
136 } 143 }
137 144
138 float terrainHeight = 0; 145 float terrainHeight = 0;
139 if (_heightMap != null) 146 if (_heightMap != null)
140 terrainHeight = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X]; 147 terrainHeight = _heightMap[(int)actor.Position.Y * (int)m_regionExtent.Y + (int)actor.Position.X];
141 148
142 float height = terrainHeight + actor.Size.Z; 149 float height = terrainHeight + actor.Size.Z;
143 150
diff --git a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
index 8ccfda5..d14edfd 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsPluginManager.cs
@@ -32,6 +32,7 @@ using System.Reflection;
32using Nini.Config; 32using Nini.Config;
33using log4net; 33using log4net;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenMetaverse;
35 36
36namespace OpenSim.Region.Physics.Manager 37namespace OpenSim.Region.Physics.Manager
37{ 38{
@@ -59,6 +60,14 @@ namespace OpenSim.Region.Physics.Manager
59 m_log.Info("[PHYSICS]: Added meshing engine: " + plugHard.GetName()); 60 m_log.Info("[PHYSICS]: Added meshing engine: " + plugHard.GetName());
60 } 61 }
61 62
63 // Legacy method for simulators before extent was passed
64 public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName,
65 IConfigSource config, string regionName)
66 {
67 Vector3 extent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
68 return GetPhysicsScene(physEngineName, meshEngineName, config, regionName, extent);
69 }
70
62 /// <summary> 71 /// <summary>
63 /// Get a physics scene for the given physics engine and mesher. 72 /// Get a physics scene for the given physics engine and mesher.
64 /// </summary> 73 /// </summary>
@@ -66,7 +75,8 @@ namespace OpenSim.Region.Physics.Manager
66 /// <param name="meshEngineName"></param> 75 /// <param name="meshEngineName"></param>
67 /// <param name="config"></param> 76 /// <param name="config"></param>
68 /// <returns></returns> 77 /// <returns></returns>
69 public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName, IConfigSource config, string regionName) 78 public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName,
79 IConfigSource config, string regionName, Vector3 regionExtent)
70 { 80 {
71 if (String.IsNullOrEmpty(physEngineName)) 81 if (String.IsNullOrEmpty(physEngineName))
72 { 82 {
@@ -94,7 +104,7 @@ namespace OpenSim.Region.Physics.Manager
94 { 104 {
95 m_log.Info("[PHYSICS]: creating " + physEngineName); 105 m_log.Info("[PHYSICS]: creating " + physEngineName);
96 PhysicsScene result = _PhysPlugins[physEngineName].GetScene(regionName); 106 PhysicsScene result = _PhysPlugins[physEngineName].GetScene(regionName);
97 result.Initialise(meshEngine, config); 107 result.Initialise(meshEngine, config, regionExtent);
98 return result; 108 return result;
99 } 109 }
100 else 110 else
diff --git a/OpenSim/Region/Physics/Manager/PhysicsScene.cs b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
index dd9bbc1..4f4ff07 100644
--- a/OpenSim/Region/Physics/Manager/PhysicsScene.cs
+++ b/OpenSim/Region/Physics/Manager/PhysicsScene.cs
@@ -132,8 +132,17 @@ namespace OpenSim.Region.Physics.Manager
132 } 132 }
133 } 133 }
134 134
135 // Deprecated. Do not use this for new physics engines.
135 public abstract void Initialise(IMesher meshmerizer, IConfigSource config); 136 public abstract void Initialise(IMesher meshmerizer, IConfigSource config);
136 137
138 // For older physics engines that do not implement non-legacy region sizes.
139 // If the physics engine handles the region extent feature, it overrides this function.
140 public virtual void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
141 {
142 // If not overridden, call the old initialization entry.
143 Initialise(meshmerizer, config);
144 }
145
137 /// <summary> 146 /// <summary>
138 /// Add an avatar 147 /// Add an avatar
139 /// </summary> 148 /// </summary>
diff --git a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
index 7127c73..341c8f8 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionCombinerModule.cs
@@ -134,6 +134,49 @@ namespace OpenSim.Region.RegionCombinerModule
134 throw new Exception(string.Format("Region with id {0} not found", regionId)); 134 throw new Exception(string.Format("Region with id {0} not found", regionId));
135 } 135 }
136 136
137 // Test to see if this postiion (relative to the region) is within the area covered
138 // by this megaregion.
139 public bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy)
140 {
141 bool ret = false;
142 if (xx < 0 || yy < 0)
143 return ret;
144
145 foreach (RegionConnections rootRegion in m_regions.Values)
146 {
147 if (currentRegion == rootRegion.RegionId)
148 {
149 // The caller is in the root region so this is an easy test
150 if (xx < rootRegion.XEnd && yy < rootRegion.YEnd)
151 {
152 ret = true;
153 }
154 break;
155 }
156 else
157 {
158 // Maybe the caller is in one of the sub-regions
159 foreach (RegionData childRegion in rootRegion.ConnectedRegions)
160 {
161 if (currentRegion == childRegion.RegionId)
162 {
163 // This is a child. Diddle the offsets and check if in
164 Vector3 positionInMegaregion = childRegion.Offset;
165 positionInMegaregion.X += xx;
166 positionInMegaregion.Y += yy;
167 if (positionInMegaregion.X < rootRegion.XEnd && positionInMegaregion.Y < rootRegion.YEnd)
168 {
169 ret = true;
170 }
171 break;
172 }
173 }
174 }
175 }
176
177 return ret;
178 }
179
137 private void NewPresence(ScenePresence presence) 180 private void NewPresence(ScenePresence presence)
138 { 181 {
139 if (presence.IsChildAgent) 182 if (presence.IsChildAgent)
@@ -220,27 +263,6 @@ namespace OpenSim.Region.RegionCombinerModule
220 // 263 //
221*/ 264*/
222 265
223 // Give each region a standard set of non-infinite borders
224 Border northBorder = new Border();
225 northBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize); //<---
226 northBorder.CrossDirection = Cardinals.N;
227 scene.NorthBorders[0] = northBorder;
228
229 Border southBorder = new Border();
230 southBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0); //--->
231 southBorder.CrossDirection = Cardinals.S;
232 scene.SouthBorders[0] = southBorder;
233
234 Border eastBorder = new Border();
235 eastBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize); //<---
236 eastBorder.CrossDirection = Cardinals.E;
237 scene.EastBorders[0] = eastBorder;
238
239 Border westBorder = new Border();
240 westBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0); //--->
241 westBorder.CrossDirection = Cardinals.W;
242 scene.WestBorders[0] = westBorder;
243
244 RegionConnections newConn = new RegionConnections(); 266 RegionConnections newConn = new RegionConnections();
245 newConn.ConnectedRegions = new List<RegionData>(); 267 newConn.ConnectedRegions = new List<RegionData>();
246 newConn.RegionScene = scene; 268 newConn.RegionScene = scene;
@@ -248,8 +270,8 @@ namespace OpenSim.Region.RegionCombinerModule
248 newConn.RegionId = scene.RegionInfo.originRegionID; 270 newConn.RegionId = scene.RegionInfo.originRegionID;
249 newConn.X = scene.RegionInfo.RegionLocX; 271 newConn.X = scene.RegionInfo.RegionLocX;
250 newConn.Y = scene.RegionInfo.RegionLocY; 272 newConn.Y = scene.RegionInfo.RegionLocY;
251 newConn.XEnd = (int)Constants.RegionSize; 273 newConn.XEnd = scene.RegionInfo.RegionSizeX;
252 newConn.YEnd = (int)Constants.RegionSize; 274 newConn.YEnd = scene.RegionInfo.RegionSizeX;
253 275
254 lock (m_regions) 276 lock (m_regions)
255 { 277 {
@@ -415,6 +437,11 @@ namespace OpenSim.Region.RegionCombinerModule
415 */ 437 */
416 #endregion 438 #endregion
417 439
440
441 // Check to see if this new region is adjacent to the root region.
442 // Note that we expect the regions to be combined from the root region outward
443 // thus the requirement for the ordering in the configuration files.
444
418 // If we're one region over +x y (i.e. root region is to the west) 445 // If we're one region over +x y (i.e. root region is to the west)
419 //xxx 446 //xxx
420 //xxy 447 //xxy
@@ -431,7 +458,7 @@ namespace OpenSim.Region.RegionCombinerModule
431 //xxx 458 //xxx
432 if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) 459 if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
433 { 460 {
434 connectedYN = DoWorkForOneRegionOverXPlusY(rootConn, newConn, scene); 461 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
435 break; 462 break;
436 } 463 }
437 464
@@ -441,9 +468,8 @@ namespace OpenSim.Region.RegionCombinerModule
441 //xxx 468 //xxx
442 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) 469 if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
443 { 470 {
444 connectedYN = DoWorkForOneRegionOverPlusXPlusY(rootConn, newConn, scene); 471 connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
445 break; 472 break;
446
447 } 473 }
448 } 474 }
449 475
@@ -453,20 +479,20 @@ namespace OpenSim.Region.RegionCombinerModule
453 DoWorkForRootRegion(newConn, scene); 479 DoWorkForRootRegion(newConn, scene);
454 } 480 }
455 } 481 }
456
457 // Set up infinite borders around the entire AABB of the combined ConnectedRegions
458 AdjustLargeRegionBounds();
459 } 482 }
460 483
461 private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene) 484 private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
462 { 485 {
486 // Offset (in meters) from the base of this region to the base of the root region.
463 Vector3 offset = Vector3.Zero; 487 Vector3 offset = Vector3.Zero;
464 offset.X = newConn.PosX - rootConn.PosX; 488 offset.X = newConn.PosX - rootConn.PosX;
465 offset.Y = newConn.PosY - rootConn.PosY; 489 offset.Y = newConn.PosY - rootConn.PosY;
466 490
491 // The new total size of the region (in meters)
492 // We just extend the X and Y dimensions so the extent might temporarily include areas without regions.
467 Vector3 extents = Vector3.Zero; 493 Vector3 extents = Vector3.Zero;
468 extents.Y = rootConn.YEnd; 494 extents.X = Math.Max(rootConn.XEnd, offset.X + newConn.RegionScene.RegionInfo.RegionSizeX);
469 extents.X = rootConn.XEnd + newConn.XEnd; 495 extents.Y = Math.Max(rootConn.YEnd, offset.Y + newConn.RegionScene.RegionInfo.RegionSizeY);
470 496
471 rootConn.UpdateExtents(extents); 497 rootConn.UpdateExtents(extents);
472 498
@@ -475,9 +501,6 @@ namespace OpenSim.Region.RegionCombinerModule
475 rootConn.RegionScene.RegionInfo.RegionName, 501 rootConn.RegionScene.RegionInfo.RegionName,
476 newConn.RegionScene.RegionInfo.RegionName, offset, extents); 502 newConn.RegionScene.RegionInfo.RegionName, offset, extents);
477 503
478 scene.BordersLocked = true;
479 rootConn.RegionScene.BordersLocked = true;
480
481 RegionData ConnectedRegion = new RegionData(); 504 RegionData ConnectedRegion = new RegionData();
482 ConnectedRegion.Offset = offset; 505 ConnectedRegion.Offset = offset;
483 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; 506 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
@@ -490,34 +513,10 @@ namespace OpenSim.Region.RegionCombinerModule
490 // Inform Child region that it needs to forward it's terrain to the root region 513 // Inform Child region that it needs to forward it's terrain to the root region
491 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); 514 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
492 515
493 // Extend the borders as appropriate
494 lock (rootConn.RegionScene.EastBorders)
495 rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;
496
497 lock (rootConn.RegionScene.NorthBorders)
498 rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
499
500 lock (rootConn.RegionScene.SouthBorders)
501 rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
502
503 lock (scene.WestBorders)
504 {
505 scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
506
507 // Trigger auto teleport to root region
508 scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
509 scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
510 }
511
512 // Reset Terrain.. since terrain loads before we get here, we need to load 516 // Reset Terrain.. since terrain loads before we get here, we need to load
513 // it again so it loads in the root region 517 // it again so it loads in the root region
514
515 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); 518 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
516 519
517 // Unlock borders
518 rootConn.RegionScene.BordersLocked = false;
519 scene.BordersLocked = false;
520
521 // Create a client event forwarder and add this region's events to the root region. 520 // Create a client event forwarder and add this region's events to the root region.
522 if (rootConn.ClientEventForwarder != null) 521 if (rootConn.ClientEventForwarder != null)
523 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); 522 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
@@ -525,6 +524,9 @@ namespace OpenSim.Region.RegionCombinerModule
525 return true; 524 return true;
526 } 525 }
527 526
527 /*
528 * 20140215 radams1: The border stuff was removed and the addition of regions to the mega-regions
529 * was generalized. These functions are not needed for the generalized solution but left for reference.
528 private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) 530 private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
529 { 531 {
530 Vector3 offset = Vector3.Zero; 532 Vector3 offset = Vector3.Zero;
@@ -536,9 +538,6 @@ namespace OpenSim.Region.RegionCombinerModule
536 extents.X = rootConn.XEnd; 538 extents.X = rootConn.XEnd;
537 rootConn.UpdateExtents(extents); 539 rootConn.UpdateExtents(extents);
538 540
539 scene.BordersLocked = true;
540 rootConn.RegionScene.BordersLocked = true;
541
542 RegionData ConnectedRegion = new RegionData(); 541 RegionData ConnectedRegion = new RegionData();
543 ConnectedRegion.Offset = offset; 542 ConnectedRegion.Offset = offset;
544 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; 543 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
@@ -553,30 +552,11 @@ namespace OpenSim.Region.RegionCombinerModule
553 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); 552 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
554 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); 553 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
555 554
556 lock (rootConn.RegionScene.NorthBorders)
557 rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
558
559 lock (rootConn.RegionScene.EastBorders)
560 rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
561
562 lock (rootConn.RegionScene.WestBorders)
563 rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
564
565 lock (scene.SouthBorders)
566 {
567 scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
568 scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
569 scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
570 }
571
572 // Reset Terrain.. since terrain normally loads first. 555 // Reset Terrain.. since terrain normally loads first.
573 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); 556 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
574 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); 557 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
575 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); 558 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
576 559
577 scene.BordersLocked = false;
578 rootConn.RegionScene.BordersLocked = false;
579
580 if (rootConn.ClientEventForwarder != null) 560 if (rootConn.ClientEventForwarder != null)
581 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); 561 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
582 562
@@ -600,9 +580,6 @@ namespace OpenSim.Region.RegionCombinerModule
600 extents.Y = rootConn.YEnd; 580 extents.Y = rootConn.YEnd;
601 extents.X = rootConn.XEnd; 581 extents.X = rootConn.XEnd;
602 582
603 scene.BordersLocked = true;
604 rootConn.RegionScene.BordersLocked = true;
605
606 RegionData ConnectedRegion = new RegionData(); 583 RegionData ConnectedRegion = new RegionData();
607 ConnectedRegion.Offset = offset; 584 ConnectedRegion.Offset = offset;
608 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; 585 ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
@@ -618,67 +595,10 @@ namespace OpenSim.Region.RegionCombinerModule
618 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); 595 rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
619 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); 596 scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
620 597
621 lock (rootConn.RegionScene.NorthBorders)
622 {
623 if (rootConn.RegionScene.NorthBorders.Count == 1)// && 2)
624 {
625 //compound border
626 // already locked above
627 rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
628
629 lock (rootConn.RegionScene.EastBorders)
630 rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
631
632 lock (rootConn.RegionScene.WestBorders)
633 rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
634 }
635 }
636
637 lock (scene.SouthBorders)
638 {
639 scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
640 scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
641 scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
642 }
643
644 lock (rootConn.RegionScene.EastBorders)
645 {
646 if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2)
647 {
648 rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;
649
650 lock (rootConn.RegionScene.NorthBorders)
651 rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
652
653 lock (rootConn.RegionScene.SouthBorders)
654 rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
655 }
656 }
657
658 lock (scene.WestBorders)
659 {
660 scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
661 scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
662 scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
663 }
664
665 /*
666 else
667 {
668 conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
669 conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
670 conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
671 scene.SouthBorders[0].BorderLine.Z += (int)Constants.RegionSize; //auto teleport south
672 }
673 */
674
675
676 // Reset Terrain.. since terrain normally loads first. 598 // Reset Terrain.. since terrain normally loads first.
677 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); 599 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
678 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); 600 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
679 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); 601 //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
680 scene.BordersLocked = false;
681 rootConn.RegionScene.BordersLocked = false;
682 602
683 if (rootConn.ClientEventForwarder != null) 603 if (rootConn.ClientEventForwarder != null)
684 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); 604 rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
@@ -687,6 +607,7 @@ namespace OpenSim.Region.RegionCombinerModule
687 607
688 //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents); 608 //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents);
689 } 609 }
610 */
690 611
691 private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene) 612 private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene)
692 { 613 {
@@ -885,125 +806,6 @@ namespace OpenSim.Region.RegionCombinerModule
885// } 806// }
886// } 807// }
887 808
888 // Create a set of infinite borders around the whole aabb of the combined island.
889 private void AdjustLargeRegionBounds()
890 {
891 lock (m_regions)
892 {
893 foreach (RegionConnections rconn in m_regions.Values)
894 {
895 Vector3 offset = Vector3.Zero;
896 rconn.RegionScene.BordersLocked = true;
897 foreach (RegionData rdata in rconn.ConnectedRegions)
898 {
899 if (rdata.Offset.X > offset.X) offset.X = rdata.Offset.X;
900 if (rdata.Offset.Y > offset.Y) offset.Y = rdata.Offset.Y;
901 }
902
903 lock (rconn.RegionScene.NorthBorders)
904 {
905 Border northBorder = null;
906 // If we don't already have an infinite border, create one.
907 if (!TryGetInfiniteBorder(rconn.RegionScene.NorthBorders, out northBorder))
908 {
909 northBorder = new Border();
910 rconn.RegionScene.NorthBorders.Add(northBorder);
911 }
912
913 northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,
914 offset.Y + (int) Constants.RegionSize); //<---
915 northBorder.CrossDirection = Cardinals.N;
916 }
917
918 lock (rconn.RegionScene.SouthBorders)
919 {
920 Border southBorder = null;
921 // If we don't already have an infinite border, create one.
922 if (!TryGetInfiniteBorder(rconn.RegionScene.SouthBorders, out southBorder))
923 {
924 southBorder = new Border();
925 rconn.RegionScene.SouthBorders.Add(southBorder);
926 }
927 southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, 0); //--->
928 southBorder.CrossDirection = Cardinals.S;
929 }
930
931 lock (rconn.RegionScene.EastBorders)
932 {
933 Border eastBorder = null;
934 // If we don't already have an infinite border, create one.
935 if (!TryGetInfiniteBorder(rconn.RegionScene.EastBorders, out eastBorder))
936 {
937 eastBorder = new Border();
938 rconn.RegionScene.EastBorders.Add(eastBorder);
939 }
940 eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, offset.X + (int)Constants.RegionSize);
941 //<---
942 eastBorder.CrossDirection = Cardinals.E;
943 }
944
945 lock (rconn.RegionScene.WestBorders)
946 {
947 Border westBorder = null;
948 // If we don't already have an infinite border, create one.
949 if (!TryGetInfiniteBorder(rconn.RegionScene.WestBorders, out westBorder))
950 {
951 westBorder = new Border();
952 rconn.RegionScene.WestBorders.Add(westBorder);
953
954 }
955 westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, 0); //--->
956 westBorder.CrossDirection = Cardinals.W;
957 }
958
959 rconn.RegionScene.BordersLocked = false;
960 }
961 }
962 }
963
964 /// <summary>
965 /// Try and get an Infinite border out of a listT of borders
966 /// </summary>
967 /// <param name="borders"></param>
968 /// <param name="oborder"></param>
969 /// <returns></returns>
970 public static bool TryGetInfiniteBorder(List<Border> borders, out Border oborder)
971 {
972 // Warning! Should be locked before getting here!
973 foreach (Border b in borders)
974 {
975 if (b.BorderLine.X == float.MinValue && b.BorderLine.Y == float.MaxValue)
976 {
977 oborder = b;
978 return true;
979 }
980 }
981
982 oborder = null;
983 return false;
984 }
985
986 public RegionData GetRegionFromPosition(Vector3 pPosition)
987 {
988 pPosition = pPosition/(int) Constants.RegionSize;
989 int OffsetX = (int) pPosition.X;
990 int OffsetY = (int) pPosition.Y;
991
992 lock (m_regions)
993 {
994 foreach (RegionConnections regConn in m_regions.Values)
995 {
996 foreach (RegionData reg in regConn.ConnectedRegions)
997 {
998 if (reg.Offset.X == OffsetX && reg.Offset.Y == OffsetY)
999 return reg;
1000 }
1001 }
1002 }
1003
1004 return new RegionData();
1005 }
1006
1007 public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion) 809 public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion)
1008 { 810 {
1009 if (BigRegion.PermissionModule == null) 811 if (BigRegion.PermissionModule == null)
diff --git a/OpenSim/Region/RegionCombinerModule/RegionConnections.cs b/OpenSim/Region/RegionCombinerModule/RegionConnections.cs
index fba51d2..6bf1c4a 100644
--- a/OpenSim/Region/RegionCombinerModule/RegionConnections.cs
+++ b/OpenSim/Region/RegionCombinerModule/RegionConnections.cs
@@ -64,12 +64,12 @@ namespace OpenSim.Region.RegionCombinerModule
64 /// <summary> 64 /// <summary>
65 /// The X meters position of this connection. 65 /// The X meters position of this connection.
66 /// </summary> 66 /// </summary>
67 public uint PosX { get { return X * Constants.RegionSize; } } 67 public uint PosX { get { return Util.RegionToWorldLoc(X); } }
68 68
69 /// <summary> 69 /// <summary>
70 /// The Y meters co-ordinate of this connection. 70 /// The Y meters co-ordinate of this connection.
71 /// </summary> 71 /// </summary>
72 public uint PosY { get { return Y * Constants.RegionSize; } } 72 public uint PosY { get { return Util.RegionToWorldLoc(Y); } }
73 73
74 /// <summary> 74 /// <summary>
75 /// The size of the megaregion in meters. 75 /// The size of the megaregion in meters.
@@ -91,4 +91,4 @@ namespace OpenSim.Region.RegionCombinerModule
91 YEnd = (uint)extents.Y; 91 YEnd = (uint)extents.Y;
92 } 92 }
93 } 93 }
94} \ No newline at end of file 94}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 3c8f54f..b5ba4a0 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -2352,7 +2352,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2352 // 2352 //
2353 // This workaround is to prevent silent failure of this function. 2353 // This workaround is to prevent silent failure of this function.
2354 // According to the specification on the SL Wiki, providing a position outside of the 2354 // According to the specification on the SL Wiki, providing a position outside of the
2355 if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) 2355 if (pos.x < 0 || pos.x > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY)
2356 { 2356 {
2357 return 0; 2357 return 0;
2358 } 2358 }
@@ -2362,9 +2362,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
2362 m_host.ParentGroup.IsAttachment || // return FALSE if attachment 2362 m_host.ParentGroup.IsAttachment || // return FALSE if attachment
2363 ( 2363 (
2364 pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region. 2364 pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region.
2365 pos.x > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a east-adjacent region. 2365 pos.x > (World.RegionInfo.RegionSizeX + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
2366 pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region. 2366 pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
2367 pos.y > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a north-adjacent region. 2367 pos.y > (World.RegionInfo.RegionSizeY + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
2368 pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m 2368 pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
2369 ) 2369 )
2370 ) 2370 )
@@ -4655,10 +4655,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
4655 DataserverPlugin.RegisterRequest(m_host.LocalId, 4655 DataserverPlugin.RegisterRequest(m_host.LocalId,
4656 m_item.ItemID, item.AssetID.ToString()); 4656 m_item.ItemID, item.AssetID.ToString());
4657 4657
4658 Vector3 region = new Vector3( 4658 Vector3 region = new Vector3(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
4659 World.RegionInfo.RegionLocX * Constants.RegionSize,
4660 World.RegionInfo.RegionLocY * Constants.RegionSize,
4661 0);
4662 4659
4663 World.AssetService.Get(item.AssetID.ToString(), this, 4660 World.AssetService.Get(item.AssetID.ToString(), this,
4664 delegate(string i, object sender, AssetBase a) 4661 delegate(string i, object sender, AssetBase a)
@@ -5949,7 +5946,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
5949 public LSL_Vector llGetRegionCorner() 5946 public LSL_Vector llGetRegionCorner()
5950 { 5947 {
5951 m_host.AddScriptLPS(1); 5948 m_host.AddScriptLPS(1);
5952 return new LSL_Vector(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0); 5949 return new LSL_Vector(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
5953 } 5950 }
5954 5951
5955 /// <summary> 5952 /// <summary>
@@ -6104,7 +6101,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6104 LSL_Float mag; 6101 LSL_Float mag;
6105 if (dir.x > 0) 6102 if (dir.x > 0)
6106 { 6103 {
6107 mag = (Constants.RegionSize - pos.x) / dir.x; 6104 mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x;
6108 } 6105 }
6109 else 6106 else
6110 { 6107 {
@@ -6115,7 +6112,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
6115 6112
6116 edge.y = pos.y + (dir.y * mag); 6113 edge.y = pos.y + (dir.y * mag);
6117 6114
6118 if (edge.y > Constants.RegionSize || edge.y < 0) 6115 if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0)
6119 { 6116 {
6120 // Y goes out of bounds first 6117 // Y goes out of bounds first
6121 edge.y = dir.y / Math.Abs(dir.y); 6118 edge.y = dir.y / Math.Abs(dir.y);
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
index d2a5980..01d90e7 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs
@@ -459,7 +459,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
459 { 459 {
460 m_host.AddScriptLPS(1); 460 m_host.AddScriptLPS(1);
461 461
462 if (x > ((int)Constants.RegionSize - 1) || x < 0 || y > ((int)Constants.RegionSize - 1) || y < 0) 462 if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0)
463 OSSLError("osSetTerrainHeight: Coordinate out of bounds"); 463 OSSLError("osSetTerrainHeight: Coordinate out of bounds");
464 464
465 if (World.Permissions.CanTerraformLand(m_host.OwnerID, new Vector3(x, y, 0))) 465 if (World.Permissions.CanTerraformLand(m_host.OwnerID, new Vector3(x, y, 0)))
@@ -489,7 +489,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
489 private LSL_Float GetTerrainHeight(int x, int y) 489 private LSL_Float GetTerrainHeight(int x, int y)
490 { 490 {
491 m_host.AddScriptLPS(1); 491 m_host.AddScriptLPS(1);
492 if (x > ((int)Constants.RegionSize - 1) || x < 0 || y > ((int)Constants.RegionSize - 1) || y < 0) 492 if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0)
493 OSSLError("osGetTerrainHeight: Coordinate out of bounds"); 493 OSSLError("osGetTerrainHeight: Coordinate out of bounds");
494 494
495 return World.Heightmap[x, y]; 495 return World.Heightmap[x, y];
@@ -823,7 +823,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
823 private void TeleportAgent(string agent, int regionX, int regionY, 823 private void TeleportAgent(string agent, int regionX, int regionY,
824 LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions) 824 LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions)
825 { 825 {
826 ulong regionHandle = Util.UIntsToLong(((uint)regionX * (uint)Constants.RegionSize), ((uint)regionY * (uint)Constants.RegionSize)); 826 ulong regionHandle = Util.RegionLocToHandle((uint)regionX, (uint)regionY);
827 827
828 m_host.AddScriptLPS(1); 828 m_host.AddScriptLPS(1);
829 UUID agentId = new UUID(); 829 UUID agentId = new UUID();
@@ -3024,7 +3024,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
3024 } 3024 }
3025 else 3025 else
3026 { 3026 {
3027 return new LSL_Vector((float)Constants.RegionSize, (float)Constants.RegionSize, Constants.RegionHeight); 3027 return new LSL_Vector((float)World.RegionInfo.RegionSizeX,
3028 (float)World.RegionInfo.RegionSizeY,
3029 (float)World.RegionInfo.RegionSizeZ );
3028 } 3030 }
3029 } 3031 }
3030 3032
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
index 9cf7b35..8666421 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Runtime/OSSL_Stub.cs
@@ -708,18 +708,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
708 } 708 }
709 private void Save() 709 private void Save()
710 { 710 {
711 /* Remove temporarily until we have a handle to the region size
711 if (Position.x > ((int)Constants.RegionSize - 1)) 712 if (Position.x > ((int)Constants.RegionSize - 1))
712 Position.x = ((int)Constants.RegionSize - 1); 713 Position.x = ((int)Constants.RegionSize - 1);
713 if (Position.x < 0)
714 Position.x = 0;
715 if (Position.y > ((int)Constants.RegionSize - 1)) 714 if (Position.y > ((int)Constants.RegionSize - 1))
716 Position.y = ((int)Constants.RegionSize - 1); 715 Position.y = ((int)Constants.RegionSize - 1);
716 */
717 if (Position.x < 0)
718 Position.x = 0;
717 if (Position.y < 0) 719 if (Position.y < 0)
718 Position.y = 0; 720 Position.y = 0;
719 if (Position.z > 768)
720 Position.z = 768;
721 if (Position.z < 0) 721 if (Position.z < 0)
722 Position.z = 0; 722 Position.z = 0;
723 if (Position.z > Constants.RegionHeight)
724 Position.z = Constants.RegionHeight;
723 prim.OSSL.llSetPos(Position); 725 prim.OSSL.llSetPos(Position);
724 } 726 }
725 727
diff --git a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs
index 7ee347c..d2fbfa6 100644
--- a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs
+++ b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs
@@ -133,7 +133,7 @@ namespace OpenSim.Server.Handlers.MapImage
133 if (m_GridService != null) 133 if (m_GridService != null)
134 { 134 {
135 System.Net.IPAddress ipAddr = GetCallerIP(httpRequest); 135 System.Net.IPAddress ipAddr = GetCallerIP(httpRequest);
136 GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, x * (int)Constants.RegionSize, y * (int)Constants.RegionSize); 136 GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc((uint)x), (int)Util.RegionToWorldLoc((uint)y));
137 if (r != null) 137 if (r != null)
138 { 138 {
139 if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString()) 139 if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString())
diff --git a/OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs b/OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs
index 8a31579..88d774a 100644
--- a/OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs
+++ b/OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs
@@ -128,7 +128,7 @@ namespace OpenSim.Server.Handlers.MapImage
128 if (m_GridService != null) 128 if (m_GridService != null)
129 { 129 {
130 System.Net.IPAddress ipAddr = GetCallerIP(httpRequest); 130 System.Net.IPAddress ipAddr = GetCallerIP(httpRequest);
131 GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, x * (int)Constants.RegionSize, y * (int)Constants.RegionSize); 131 GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc((uint)x), (int)Util.RegionToWorldLoc((uint)y));
132 if (r != null) 132 if (r != null)
133 { 133 {
134 if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString()) 134 if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString())
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
index 3cf3416..312832f 100644
--- a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs
@@ -112,7 +112,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
112// m_log.Warn("Registering region " + regionInfo.RegionName + " (" + regionInfo.RegionID + ") that we are not tracking"); 112// m_log.Warn("Registering region " + regionInfo.RegionName + " (" + regionInfo.RegionID + ") that we are not tracking");
113 113
114 Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0); 114 Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0);
115 Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 115 Vector3d maxPosition = minPosition + new Vector3d(regionInfo.RegionSizeX, regionInfo.RegionSizeY, Constants.RegionHeight);
116 116
117 OSDMap extraData = new OSDMap 117 OSDMap extraData = new OSDMap
118 { 118 {
@@ -174,8 +174,8 @@ namespace OpenSim.Services.Connectors.SimianGrid
174 if (region != null) 174 if (region != null)
175 { 175 {
176 List<GridRegion> regions = GetRegionRange(scopeID, 176 List<GridRegion> regions = GetRegionRange(scopeID,
177 region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + (int)Constants.RegionSize + NEIGHBOR_RADIUS, 177 region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + region.RegionSizeX + NEIGHBOR_RADIUS,
178 region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + (int)Constants.RegionSize + NEIGHBOR_RADIUS); 178 region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + region.RegionSizeY + NEIGHBOR_RADIUS);
179 179
180 for (int i = 0; i < regions.Count; i++) 180 for (int i = 0; i < regions.Count; i++)
181 { 181 {
@@ -240,7 +240,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
240 else 240 else
241 { 241 {
242 // m_log.InfoFormat("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}", 242 // m_log.InfoFormat("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}",
243 // x / Constants.RegionSize, y / Constants.RegionSize); 243 // Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
244 return null; 244 return null;
245 } 245 }
246 } 246 }
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs
index 96c02d9..4759838 100644
--- a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs
+++ b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs
@@ -100,6 +100,11 @@ namespace OpenSim.Services.Connectors
100 return m_database.LoadObjects(regionUUID); 100 return m_database.LoadObjects(regionUUID);
101 } 101 }
102 102
103 public void StoreTerrain(TerrainData terrain, UUID regionID)
104 {
105 m_database.StoreTerrain(terrain, regionID);
106 }
107
103 public void StoreTerrain(double[,] terrain, UUID regionID) 108 public void StoreTerrain(double[,] terrain, UUID regionID)
104 { 109 {
105 m_database.StoreTerrain(terrain, regionID); 110 m_database.StoreTerrain(terrain, regionID);
@@ -110,6 +115,11 @@ namespace OpenSim.Services.Connectors
110 return m_database.LoadTerrain(regionID); 115 return m_database.LoadTerrain(regionID);
111 } 116 }
112 117
118 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
119 {
120 return m_database.LoadTerrain(regionID, pSizeX, pSizeY, pSizeZ);
121 }
122
113 public void StoreLandObject(ILandObject Parcel) 123 public void StoreLandObject(ILandObject Parcel)
114 { 124 {
115 m_database.StoreLandObject(Parcel); 125 m_database.StoreLandObject(Parcel);
diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs
index 76415ce..eb44dcb 100644
--- a/OpenSim/Services/GridService/GridService.cs
+++ b/OpenSim/Services/GridService/GridService.cs
@@ -655,7 +655,7 @@ namespace OpenSim.Services.GridService
655 return; 655 return;
656 } 656 }
657 657
658 RegionData region = m_Database.Get(x * (int)Constants.RegionSize, y * (int)Constants.RegionSize, UUID.Zero); 658 RegionData region = m_Database.Get((int)Util.RegionToWorldLoc((uint)x), (int)Util.RegionToWorldLoc((uint)y), UUID.Zero);
659 if (region == null) 659 if (region == null)
660 { 660 {
661 MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y); 661 MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y);
@@ -673,6 +673,7 @@ namespace OpenSim.Services.GridService
673 dispList.AddRow("Region Name", r.RegionName); 673 dispList.AddRow("Region Name", r.RegionName);
674 dispList.AddRow("Region ID", r.RegionID); 674 dispList.AddRow("Region ID", r.RegionID);
675 dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY)); 675 dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY));
676 dispList.AddRow("Size", string.Format("{0}x{1}", r.sizeX, r.sizeY));
676 dispList.AddRow("URI", r.Data["serverURI"]); 677 dispList.AddRow("URI", r.Data["serverURI"]);
677 dispList.AddRow("Owner ID", r.Data["owner_uuid"]); 678 dispList.AddRow("Owner ID", r.Data["owner_uuid"]);
678 dispList.AddRow("Flags", flags); 679 dispList.AddRow("Flags", flags);
diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs
index 4024295..0448b54 100644
--- a/OpenSim/Services/GridService/HypergridLinker.cs
+++ b/OpenSim/Services/GridService/HypergridLinker.cs
@@ -183,8 +183,8 @@ namespace OpenSim.Services.GridService
183 public GridRegion LinkRegion(UUID scopeID, string regionDescriptor) 183 public GridRegion LinkRegion(UUID scopeID, string regionDescriptor)
184 { 184 {
185 string reason = string.Empty; 185 string reason = string.Empty;
186 int xloc = random.Next(0, Int16.MaxValue) * (int)Constants.RegionSize; 186 uint xloc = Util.RegionToWorldLoc((uint)random.Next(0, Int16.MaxValue));
187 return TryLinkRegionToCoords(scopeID, regionDescriptor, xloc, 0, out reason); 187 return TryLinkRegionToCoords(scopeID, regionDescriptor, (int)xloc, 0, out reason);
188 } 188 }
189 189
190 private static Random random = new Random(); 190 private static Random random = new Random();
@@ -260,7 +260,7 @@ namespace OpenSim.Services.GridService
260 { 260 {
261 m_log.DebugFormat("[HYPERGRID LINKER]: Link to {0} {1}, in {2}-{3}", 261 m_log.DebugFormat("[HYPERGRID LINKER]: Link to {0} {1}, in {2}-{3}",
262 ((serverURI == null) ? (externalHostName + ":" + externalPort) : serverURI), 262 ((serverURI == null) ? (externalHostName + ":" + externalPort) : serverURI),
263 remoteRegionName, xloc / Constants.RegionSize, yloc / Constants.RegionSize); 263 remoteRegionName, Util.WorldToRegionLoc((uint)xloc), Util.WorldToRegionLoc((uint)yloc));
264 264
265 reason = string.Empty; 265 reason = string.Empty;
266 Uri uri = null; 266 Uri uri = null;
@@ -311,7 +311,7 @@ namespace OpenSim.Services.GridService
311 if (region != null) 311 if (region != null)
312 { 312 {
313 m_log.WarnFormat("[HYPERGRID LINKER]: Coordinates {0}-{1} are already occupied by region {2} with uuid {3}", 313 m_log.WarnFormat("[HYPERGRID LINKER]: Coordinates {0}-{1} are already occupied by region {2} with uuid {3}",
314 regInfo.RegionLocX / Constants.RegionSize, regInfo.RegionLocY / Constants.RegionSize, 314 Util.WorldToRegionLoc((uint)regInfo.RegionLocX), Util.WorldToRegionLoc((uint)regInfo.RegionLocY),
315 region.RegionName, region.RegionID); 315 region.RegionName, region.RegionID);
316 reason = "Coordinates are already in use"; 316 reason = "Coordinates are already in use";
317 return false; 317 return false;
@@ -347,7 +347,7 @@ namespace OpenSim.Services.GridService
347 if (region != null) 347 if (region != null)
348 { 348 {
349 m_log.DebugFormat("[HYPERGRID LINKER]: Region already exists in coordinates {0} {1}", 349 m_log.DebugFormat("[HYPERGRID LINKER]: Region already exists in coordinates {0} {1}",
350 region.RegionLocX / Constants.RegionSize, region.RegionLocY / Constants.RegionSize); 350 Util.WorldToRegionLoc((uint)regInfo.RegionLocX), Util.WorldToRegionLoc((uint)regInfo.RegionLocY));
351 regInfo = region; 351 regInfo = region;
352 return true; 352 return true;
353 } 353 }
@@ -424,10 +424,10 @@ namespace OpenSim.Services.GridService
424// { 424// {
425// uint ux = 0, uy = 0; 425// uint ux = 0, uy = 0;
426// Utils.LongToUInts(realHandle, out ux, out uy); 426// Utils.LongToUInts(realHandle, out ux, out uy);
427// x = ux / Constants.RegionSize; 427// x = Util.WorldToRegionLoc(ux);
428// y = uy / Constants.RegionSize; 428// y = Util.WorldToRegionLoc(uy);
429// 429//
430// const uint limit = (4096 - 1) * Constants.RegionSize; 430// const uint limit = Util.RegionToWorldLoc(4096 - 1);
431// uint xmin = ux - limit; 431// uint xmin = ux - limit;
432// uint xmax = ux + limit; 432// uint xmax = ux + limit;
433// uint ymin = uy - limit; 433// uint ymin = uy - limit;
@@ -503,8 +503,9 @@ namespace OpenSim.Services.GridService
503 foreach (RegionData r in regions) 503 foreach (RegionData r in regions)
504 { 504 {
505 MainConsole.Instance.Output(String.Format("{0}\n{2,-32} {1}\n", 505 MainConsole.Instance.Output(String.Format("{0}\n{2,-32} {1}\n",
506 r.RegionName, r.RegionID, String.Format("{0},{1} ({2},{3})", r.posX, r.posY, 506 r.RegionName, r.RegionID,
507 r.posX / Constants.RegionSize, r.posY / Constants.RegionSize))); 507 String.Format("{0},{1} ({2},{3})", r.posX, r.posY,
508 Util.WorldToRegionLoc((uint)r.posX), Util.WorldToRegionLoc((uint)r.posY))) );
508 } 509 }
509 return; 510 return;
510 } 511 }
@@ -529,8 +530,8 @@ namespace OpenSim.Services.GridService
529 int xloc, yloc; 530 int xloc, yloc;
530 string serverURI; 531 string serverURI;
531 string remoteName = null; 532 string remoteName = null;
532 xloc = Convert.ToInt32(cmdparams[0]) * (int)Constants.RegionSize; 533 xloc = (int)Util.RegionToWorldLoc((uint)Convert.ToInt32(cmdparams[0]));
533 yloc = Convert.ToInt32(cmdparams[1]) * (int)Constants.RegionSize; 534 yloc = (int)Util.RegionToWorldLoc((uint)Convert.ToInt32(cmdparams[1]));
534 serverURI = cmdparams[2]; 535 serverURI = cmdparams[2];
535 if (cmdparams.Length > 3) 536 if (cmdparams.Length > 3)
536 remoteName = string.Join(" ", cmdparams, 3, cmdparams.Length - 3); 537 remoteName = string.Join(" ", cmdparams, 3, cmdparams.Length - 3);
@@ -601,13 +602,13 @@ namespace OpenSim.Services.GridService
601 { 602 {
602 // old format 603 // old format
603 GridRegion regInfo; 604 GridRegion regInfo;
604 int xloc, yloc; 605 uint xloc, yloc;
605 uint externalPort; 606 uint externalPort;
606 string externalHostName; 607 string externalHostName;
607 try 608 try
608 { 609 {
609 xloc = Convert.ToInt32(cmdparams[0]); 610 xloc = (uint)Convert.ToInt32(cmdparams[0]);
610 yloc = Convert.ToInt32(cmdparams[1]); 611 yloc = (uint)Convert.ToInt32(cmdparams[1]);
611 externalPort = Convert.ToUInt32(cmdparams[3]); 612 externalPort = Convert.ToUInt32(cmdparams[3]);
612 externalHostName = cmdparams[2]; 613 externalHostName = cmdparams[2];
613 //internalPort = Convert.ToUInt32(cmdparams[4]); 614 //internalPort = Convert.ToUInt32(cmdparams[4]);
@@ -621,10 +622,11 @@ namespace OpenSim.Services.GridService
621 } 622 }
622 623
623 // Convert cell coordinates given by the user to meters 624 // Convert cell coordinates given by the user to meters
624 xloc = xloc * (int)Constants.RegionSize; 625 xloc = Util.RegionToWorldLoc(xloc);
625 yloc = yloc * (int)Constants.RegionSize; 626 yloc = Util.RegionToWorldLoc(yloc);
626 string reason = string.Empty; 627 string reason = string.Empty;
627 if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) 628 if (TryCreateLink(UUID.Zero, (int)xloc, (int)yloc,
629 string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason))
628 { 630 {
629 // What is this? The GridRegion instance will be discarded anyway, 631 // What is this? The GridRegion instance will be discarded anyway,
630 // which effectively ignores any local name given with the command. 632 // which effectively ignores any local name given with the command.
@@ -704,13 +706,13 @@ namespace OpenSim.Services.GridService
704 private void ReadLinkFromConfig(IConfig config) 706 private void ReadLinkFromConfig(IConfig config)
705 { 707 {
706 GridRegion regInfo; 708 GridRegion regInfo;
707 int xloc, yloc; 709 uint xloc, yloc;
708 uint externalPort; 710 uint externalPort;
709 string externalHostName; 711 string externalHostName;
710 uint realXLoc, realYLoc; 712 uint realXLoc, realYLoc;
711 713
712 xloc = Convert.ToInt32(config.GetString("xloc", "0")); 714 xloc = (uint)Convert.ToInt32(config.GetString("xloc", "0"));
713 yloc = Convert.ToInt32(config.GetString("yloc", "0")); 715 yloc = (uint)Convert.ToInt32(config.GetString("yloc", "0"));
714 externalPort = Convert.ToUInt32(config.GetString("externalPort", "0")); 716 externalPort = Convert.ToUInt32(config.GetString("externalPort", "0"));
715 externalHostName = config.GetString("externalHostName", ""); 717 externalHostName = config.GetString("externalHostName", "");
716 realXLoc = Convert.ToUInt32(config.GetString("real-xloc", "0")); 718 realXLoc = Convert.ToUInt32(config.GetString("real-xloc", "0"));
@@ -718,18 +720,19 @@ namespace OpenSim.Services.GridService
718 720
719 if (m_enableAutoMapping) 721 if (m_enableAutoMapping)
720 { 722 {
721 xloc = (int)((xloc % 100) + m_autoMappingX); 723 xloc = (uint)((xloc % 100) + m_autoMappingX);
722 yloc = (int)((yloc % 100) + m_autoMappingY); 724 yloc = (uint)((yloc % 100) + m_autoMappingY);
723 } 725 }
724 726
725 if (((realXLoc == 0) && (realYLoc == 0)) || 727 if (((realXLoc == 0) && (realYLoc == 0)) ||
726 (((realXLoc - xloc < 3896) || (xloc - realXLoc < 3896)) && 728 (((realXLoc - xloc < 3896) || (xloc - realXLoc < 3896)) &&
727 ((realYLoc - yloc < 3896) || (yloc - realYLoc < 3896)))) 729 ((realYLoc - yloc < 3896) || (yloc - realYLoc < 3896))))
728 { 730 {
729 xloc = xloc * (int)Constants.RegionSize; 731 xloc = Util.RegionToWorldLoc(xloc);
730 yloc = yloc * (int)Constants.RegionSize; 732 yloc = Util.RegionToWorldLoc(yloc);
731 string reason = string.Empty; 733 string reason = string.Empty;
732 if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) 734 if (TryCreateLink(UUID.Zero, (int)xloc, (int)yloc,
735 string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason))
733 { 736 {
734 regInfo.RegionName = config.GetString("localName", ""); 737 regInfo.RegionName = config.GetString("localName", "");
735 } 738 }
diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs
index 19ea0fe..1119e48 100644
--- a/OpenSim/Services/Interfaces/IGridService.cs
+++ b/OpenSim/Services/Interfaces/IGridService.cs
@@ -179,14 +179,14 @@ namespace OpenSim.Services.Interfaces
179 protected IPEndPoint m_internalEndPoint; 179 protected IPEndPoint m_internalEndPoint;
180 180
181 /// <summary> 181 /// <summary>
182 /// The co-ordinate of this region. 182 /// The co-ordinate of this region in region units.
183 /// </summary> 183 /// </summary>
184 public int RegionCoordX { get { return RegionLocX / (int)Constants.RegionSize; } } 184 public int RegionCoordX { get { return (int)Util.WorldToRegionLoc((uint)RegionLocX); } }
185 185
186 /// <summary> 186 /// <summary>
187 /// The co-ordinate of this region 187 /// The co-ordinate of this region in region units
188 /// </summary> 188 /// </summary>
189 public int RegionCoordY { get { return RegionLocY / (int)Constants.RegionSize; } } 189 public int RegionCoordY { get { return (int)Util.WorldToRegionLoc((uint)RegionLocY); } }
190 190
191 /// <summary> 191 /// <summary>
192 /// The location of this region in meters. 192 /// The location of this region in meters.
@@ -265,8 +265,8 @@ namespace OpenSim.Services.Interfaces
265 265
266 public GridRegion(uint xcell, uint ycell) 266 public GridRegion(uint xcell, uint ycell)
267 { 267 {
268 m_regionLocX = (int)(xcell * Constants.RegionSize); 268 m_regionLocX = (int)Util.RegionToWorldLoc(xcell);
269 m_regionLocY = (int)(ycell * Constants.RegionSize); 269 m_regionLocY = (int)Util.RegionToWorldLoc(ycell);
270 RegionSizeX = (int)Constants.RegionSize; 270 RegionSizeX = (int)Constants.RegionSize;
271 RegionSizeY = (int)Constants.RegionSize; 271 RegionSizeY = (int)Constants.RegionSize;
272 } 272 }
@@ -274,8 +274,8 @@ namespace OpenSim.Services.Interfaces
274 public GridRegion(RegionInfo ConvertFrom) 274 public GridRegion(RegionInfo ConvertFrom)
275 { 275 {
276 m_regionName = ConvertFrom.RegionName; 276 m_regionName = ConvertFrom.RegionName;
277 m_regionLocX = (int)(ConvertFrom.RegionLocX * Constants.RegionSize); 277 m_regionLocX = (int)(ConvertFrom.WorldLocX);
278 m_regionLocY = (int)(ConvertFrom.RegionLocY * Constants.RegionSize); 278 m_regionLocY = (int)(ConvertFrom.WorldLocY);
279 RegionSizeX = (int)ConvertFrom.RegionSizeX; 279 RegionSizeX = (int)ConvertFrom.RegionSizeX;
280 RegionSizeY = (int)ConvertFrom.RegionSizeY; 280 RegionSizeY = (int)ConvertFrom.RegionSizeY;
281 m_internalEndPoint = ConvertFrom.InternalEndPoint; 281 m_internalEndPoint = ConvertFrom.InternalEndPoint;
diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
index f641955..da351b9 100644
--- a/OpenSim/Services/LLLoginService/LLLoginResponse.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs
@@ -368,7 +368,8 @@ namespace OpenSim.Services.LLLoginService
368 368
369 private void FillOutHomeData(GridUserInfo pinfo, GridRegion home) 369 private void FillOutHomeData(GridUserInfo pinfo, GridRegion home)
370 { 370 {
371 int x = 1000 * (int)Constants.RegionSize, y = 1000 * (int)Constants.RegionSize; 371 int x = (int)Util.RegionToWorldLoc(1000);
372 int y = (int)Util.RegionToWorldLoc(1000);
372 if (home != null) 373 if (home != null)
373 { 374 {
374 x = home.RegionLocX; 375 x = home.RegionLocX;
@@ -443,10 +444,23 @@ namespace OpenSim.Services.LLLoginService
443 ErrorReason = "key"; 444 ErrorReason = "key";
444 welcomeMessage = "Welcome to OpenSim!"; 445 welcomeMessage = "Welcome to OpenSim!";
445 seedCapability = String.Empty; 446 seedCapability = String.Empty;
446 home = "{'region_handle':[r" + (1000*Constants.RegionSize).ToString() + ",r" + (1000*Constants.RegionSize).ToString() + "], 'position':[r" + 447 home = "{'region_handle':["
447 userProfile.homepos.X.ToString() + ",r" + userProfile.homepos.Y.ToString() + ",r" + 448 + "r" + Util.RegionToWorldLoc(1000).ToString()
448 userProfile.homepos.Z.ToString() + "], 'look_at':[r" + userProfile.homelookat.X.ToString() + ",r" + 449 + ","
449 userProfile.homelookat.Y.ToString() + ",r" + userProfile.homelookat.Z.ToString() + "]}"; 450 + "r" + Util.RegionToWorldLoc(1000).ToString()
451 + "], 'position':["
452 + "r" + userProfile.homepos.X.ToString()
453 + ","
454 + "r" + userProfile.homepos.Y.ToString()
455 + ","
456 + "r" + userProfile.homepos.Z.ToString()
457 + "], 'look_at':["
458 + "r" + userProfile.homelookat.X.ToString()
459 + ","
460 + "r" + userProfile.homelookat.Y.ToString()
461 + ","
462 + "r" + userProfile.homelookat.Z.ToString()
463 + "]}";
450 lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]"; 464 lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]";
451 RegionX = (uint) 255232; 465 RegionX = (uint) 255232;
452 RegionY = (uint) 254976; 466 RegionY = (uint) 254976;
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs
index 1c1c9b0..c833131 100644
--- a/OpenSim/Services/LLLoginService/LLLoginService.cs
+++ b/OpenSim/Services/LLLoginService/LLLoginService.cs
@@ -695,7 +695,7 @@ namespace OpenSim.Services.LLLoginService
695 private GridRegion FindAlternativeRegion(UUID scopeID) 695 private GridRegion FindAlternativeRegion(UUID scopeID)
696 { 696 {
697 List<GridRegion> hyperlinks = null; 697 List<GridRegion> hyperlinks = null;
698 List<GridRegion> regions = m_GridService.GetFallbackRegions(scopeID, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); 698 List<GridRegion> regions = m_GridService.GetFallbackRegions(scopeID, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000));
699 if (regions != null && regions.Count > 0) 699 if (regions != null && regions.Count > 0)
700 { 700 {
701 hyperlinks = m_GridService.GetHyperlinks(scopeID); 701 hyperlinks = m_GridService.GetHyperlinks(scopeID);
diff --git a/OpenSim/Tests/Clients/Grid/GridClient.cs b/OpenSim/Tests/Clients/Grid/GridClient.cs
index 8e33373..fed7a16 100644
--- a/OpenSim/Tests/Clients/Grid/GridClient.cs
+++ b/OpenSim/Tests/Clients/Grid/GridClient.cs
@@ -150,16 +150,16 @@ namespace OpenSim.Tests.Clients.GridClient
150 150
151 Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 2 regions)"); 151 Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 2 regions)");
152 regions = m_Connector.GetRegionRange(UUID.Zero, 152 regions = m_Connector.GetRegionRange(UUID.Zero,
153 900 * (int)Constants.RegionSize, 1002 * (int) Constants.RegionSize, 153 (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002),
154 900 * (int)Constants.RegionSize, 1002 * (int) Constants.RegionSize); 154 (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002) );
155 if (regions == null) 155 if (regions == null)
156 Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); 156 Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null");
157 else 157 else
158 Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions"); 158 Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions");
159 Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 0 regions)"); 159 Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 0 regions)");
160 regions = m_Connector.GetRegionRange(UUID.Zero, 160 regions = m_Connector.GetRegionRange(UUID.Zero,
161 900 * (int)Constants.RegionSize, 950 * (int)Constants.RegionSize, 161 (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950),
162 900 * (int)Constants.RegionSize, 950 * (int)Constants.RegionSize); 162 (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950) );
163 if (regions == null) 163 if (regions == null)
164 Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); 164 Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null");
165 else 165 else
diff --git a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
index 52a17e7..84de47f 100644
--- a/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
+++ b/OpenSim/Tests/Common/Helpers/EntityTransferHelpers.cs
@@ -69,9 +69,7 @@ namespace OpenSim.Tests.Common
69 tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) => 69 tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) =>
70 { 70 {
71 uint x, y; 71 uint x, y;
72 Utils.LongToUInts(neighbourHandle, out x, out y); 72 Util.RegionHandleToRegionLoc(neighbourHandle, out x, out y);
73 x /= Constants.RegionSize;
74 y /= Constants.RegionSize;
75 73
76 m_log.DebugFormat( 74 m_log.DebugFormat(
77 "[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}", 75 "[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}",
@@ -104,9 +102,7 @@ namespace OpenSim.Tests.Common
104 += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => 102 += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) =>
105 { 103 {
106 uint x, y; 104 uint x, y;
107 Utils.LongToUInts(regionHandle, out x, out y); 105 Util.RegionHandleToRegionLoc(regionHandle, out x, out y);
108 x /= Constants.RegionSize;
109 y /= Constants.RegionSize;
110 106
111 m_log.DebugFormat( 107 m_log.DebugFormat(
112 "[TEST CLIENT]: Processing send region teleport for destination at {0},{1} at {2}", 108 "[TEST CLIENT]: Processing send region teleport for destination at {0},{1} at {2}",
@@ -125,4 +121,4 @@ namespace OpenSim.Tests.Common
125 }; 121 };
126 } 122 }
127 } 123 }
128} \ No newline at end of file 124}
diff --git a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs
index 5c1ec0b..3ab9020 100644
--- a/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs
+++ b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs
@@ -69,11 +69,21 @@ namespace OpenSim.Data.Null
69 m_store.StoreTerrain(terrain, regionID); 69 m_store.StoreTerrain(terrain, regionID);
70 } 70 }
71 71
72 public void StoreTerrain(TerrainData terrain, UUID regionID)
73 {
74 m_store.StoreTerrain(terrain, regionID);
75 }
76
72 public double[,] LoadTerrain(UUID regionID) 77 public double[,] LoadTerrain(UUID regionID)
73 { 78 {
74 return m_store.LoadTerrain(regionID); 79 return m_store.LoadTerrain(regionID);
75 } 80 }
76 81
82 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
83 {
84 return m_store.LoadTerrain(regionID, pSizeX, pSizeY, pSizeZ);
85 }
86
77 public void StoreLandObject(ILandObject Parcel) 87 public void StoreLandObject(ILandObject Parcel)
78 { 88 {
79 m_store.StoreLandObject(Parcel); 89 m_store.StoreLandObject(Parcel);
@@ -159,7 +169,7 @@ namespace OpenSim.Data.Null
159 protected Dictionary<UUID, SceneObjectPart> m_sceneObjectParts = new Dictionary<UUID, SceneObjectPart>(); 169 protected Dictionary<UUID, SceneObjectPart> m_sceneObjectParts = new Dictionary<UUID, SceneObjectPart>();
160 protected Dictionary<UUID, ICollection<TaskInventoryItem>> m_primItems 170 protected Dictionary<UUID, ICollection<TaskInventoryItem>> m_primItems
161 = new Dictionary<UUID, ICollection<TaskInventoryItem>>(); 171 = new Dictionary<UUID, ICollection<TaskInventoryItem>>();
162 protected Dictionary<UUID, double[,]> m_terrains = new Dictionary<UUID, double[,]>(); 172 protected Dictionary<UUID, TerrainData> m_terrains = new Dictionary<UUID, TerrainData>();
163 protected Dictionary<UUID, LandData> m_landData = new Dictionary<UUID, LandData>(); 173 protected Dictionary<UUID, LandData> m_landData = new Dictionary<UUID, LandData>();
164 174
165 public void Initialise(string dbfile) 175 public void Initialise(string dbfile)
@@ -304,12 +314,17 @@ namespace OpenSim.Data.Null
304 return new List<SceneObjectGroup>(objects.Values); 314 return new List<SceneObjectGroup>(objects.Values);
305 } 315 }
306 316
307 public void StoreTerrain(double[,] ter, UUID regionID) 317 public void StoreTerrain(TerrainData ter, UUID regionID)
308 { 318 {
309 m_terrains[regionID] = ter; 319 m_terrains[regionID] = ter;
310 } 320 }
311 321
312 public double[,] LoadTerrain(UUID regionID) 322 public void StoreTerrain(double[,] ter, UUID regionID)
323 {
324 m_terrains[regionID] = new HeightmapTerrainData(ter);
325 }
326
327 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
313 { 328 {
314 if (m_terrains.ContainsKey(regionID)) 329 if (m_terrains.ContainsKey(regionID))
315 return m_terrains[regionID]; 330 return m_terrains[regionID];
@@ -317,6 +332,14 @@ namespace OpenSim.Data.Null
317 return null; 332 return null;
318 } 333 }
319 334
335 public double[,] LoadTerrain(UUID regionID)
336 {
337 if (m_terrains.ContainsKey(regionID))
338 return m_terrains[regionID].GetDoubles();
339 else
340 return null;
341 }
342
320 public void RemoveLandObject(UUID globalID) 343 public void RemoveLandObject(UUID globalID)
321 { 344 {
322 if (m_landData.ContainsKey(globalID)) 345 if (m_landData.ContainsKey(globalID))