aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Data/MSSQL/MSSQLSimulationData.cs45
-rw-r--r--OpenSim/Data/MySQL/MySQLSimulationData.cs47
-rw-r--r--OpenSim/Data/SQLite/SQLiteSimulationData.cs40
-rw-r--r--OpenSim/Framework/Constants.cs2
-rw-r--r--OpenSim/Framework/TerrainData.cs113
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs69
-rw-r--r--OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs29
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs20
-rw-r--r--OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs12
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs2
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs145
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainCompressor.cs59
-rw-r--r--OpenSim/Services/Interfaces/IGridService.cs4
13 files changed, 279 insertions, 308 deletions
diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
index 8adddc9..dbfd16c 100644
--- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
@@ -49,6 +49,7 @@ namespace OpenSim.Data.MSSQL
49 49
50 // private static FileSystemDataStore Instance = new FileSystemDataStore(); 50 // private static FileSystemDataStore Instance = new FileSystemDataStore();
51 private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 private static string LogHeader = "[REGION DB MSSQL]";
52 53
53 /// <summary> 54 /// <summary>
54 /// The database manager 55 /// The database manager
@@ -569,15 +570,19 @@ ELSE
569 return terrain; 570 return terrain;
570 } 571 }
571 572
573 // Legacy entry point for when terrain was always a 256x256 hieghtmap
574 public void StoreTerrain(double[,] ter, UUID regionID)
575 {
576 StoreTerrain(new HeightmapTerrainData(ter), regionID);
577 }
578
572 /// <summary> 579 /// <summary>
573 /// Stores the terrain map to DB. 580 /// Stores the terrain map to DB.
574 /// </summary> 581 /// </summary>
575 /// <param name="terrain">terrain map data.</param> 582 /// <param name="terrain">terrain map data.</param>
576 /// <param name="regionID">regionID.</param> 583 /// <param name="regionID">regionID.</param>
577 public void StoreTerrain(double[,] terrain, UUID regionID) 584 public void StoreTerrain(TerrainData terrData, UUID regionID)
578 { 585 {
579 int revision = (int)DBTerrainRevision.Legacy256;
580
581 //Delete old terrain map 586 //Delete old terrain map
582 string sql = "delete from terrain where RegionUUID=@RegionUUID"; 587 string sql = "delete from terrain where RegionUUID=@RegionUUID";
583 using (SqlConnection conn = new SqlConnection(m_connectionString)) 588 using (SqlConnection conn = new SqlConnection(m_connectionString))
@@ -590,17 +595,21 @@ ELSE
590 595
591 sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)"; 596 sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)";
592 597
598 int terrainDBRevision;
599 Array terrainDBblob;
600 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
601
593 using (SqlConnection conn = new SqlConnection(m_connectionString)) 602 using (SqlConnection conn = new SqlConnection(m_connectionString))
594 using (SqlCommand cmd = new SqlCommand(sql, conn)) 603 using (SqlCommand cmd = new SqlCommand(sql, conn))
595 { 604 {
596 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID)); 605 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
597 cmd.Parameters.Add(_Database.CreateParameter("@Revision", revision)); 606 cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision));
598 cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", serializeTerrain(terrain))); 607 cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob));
599 conn.Open(); 608 conn.Open();
600 cmd.ExecuteNonQuery(); 609 cmd.ExecuteNonQuery();
601 } 610 }
602 611
603 _Log.Info("[REGION DB]: Stored terrain revision r " + revision); 612 _Log.InfoFormat("{0} Stored terrain revision r={1}", LogHeader, terrainDBRevision);
604 } 613 }
605 614
606 /// <summary> 615 /// <summary>
@@ -1345,30 +1354,6 @@ VALUES
1345 #region Private Methods 1354 #region Private Methods
1346 1355
1347 /// <summary> 1356 /// <summary>
1348 /// Serializes the terrain data for storage in DB.
1349 /// </summary>
1350 /// <param name="val">terrain data</param>
1351 /// <returns></returns>
1352 private static Array serializeTerrain(double[,] val)
1353 {
1354 MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double));
1355 BinaryWriter bw = new BinaryWriter(str);
1356
1357 // TODO: COMPATIBILITY - Add byte-order conversions
1358 for (int x = 0; x < (int)Constants.RegionSize; x++)
1359 for (int y = 0; y < (int)Constants.RegionSize; y++)
1360 {
1361 double height = val[x, y];
1362 if (height == 0.0)
1363 height = double.Epsilon;
1364
1365 bw.Write(height);
1366 }
1367
1368 return str.ToArray();
1369 }
1370
1371 /// <summary>
1372 /// Stores new regionsettings. 1357 /// Stores new regionsettings.
1373 /// </summary> 1358 /// </summary>
1374 /// <param name="regionSettings">The region settings.</param> 1359 /// <param name="regionSettings">The region settings.</param>
diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index 5751dc8..4bd8617 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -48,6 +48,7 @@ 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;
53 private object m_dbLock = new object(); 54 private object m_dbLock = new object();
@@ -91,7 +92,7 @@ namespace OpenSim.Data.MySQL
91 } 92 }
92 catch (Exception e) 93 catch (Exception e)
93 { 94 {
94 m_log.Error("[REGION DB]: MySQL error in ExecuteReader: " + e.Message); 95 m_log.ErrorFormat("{0} MySQL error in ExecuteReader: {1}", LogHeader, e);
95 throw; 96 throw;
96 } 97 }
97 98
@@ -572,11 +573,14 @@ namespace OpenSim.Data.MySQL
572 } 573 }
573 } 574 }
574 575
576 // Legacy entry point for when terrain was always a 256x256 hieghtmap
575 public void StoreTerrain(double[,] ter, UUID regionID) 577 public void StoreTerrain(double[,] ter, UUID regionID)
576 { 578 {
577 m_log.Info("[REGION DB]: Storing terrain"); 579 StoreTerrain(new HeightmapTerrainData(ter), regionID);
578 int revision = (int)DBTerrainRevision.Legacy256; 580 }
579 581
582 public void StoreTerrain(TerrainData terrData, UUID regionID)
583 {
580 lock (m_dbLock) 584 lock (m_dbLock)
581 { 585 {
582 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString)) 586 using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
@@ -590,11 +594,18 @@ namespace OpenSim.Data.MySQL
590 594
591 ExecuteNonQuery(cmd); 595 ExecuteNonQuery(cmd);
592 596
597 int terrainDBRevision;
598 Array terrainDBblob;
599 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
600
601 m_log.InfoFormat("{0} Storing terrain. X={1}, Y={2}, rev={3}",
602 LogHeader, terrData.SizeX, terrData.SizeY, terrainDBRevision);
603
593 cmd.CommandText = "insert into terrain (RegionUUID, Revision, Heightfield)" 604 cmd.CommandText = "insert into terrain (RegionUUID, Revision, Heightfield)"
594 + "values (?RegionUUID, ?Revision, ?Heightfield)"; 605 + "values (?RegionUUID, ?Revision, ?Heightfield)";
595 606
596 cmd.Parameters.AddWithValue("Revision", revision); 607 cmd.Parameters.AddWithValue("Revision", terrainDBRevision);
597 cmd.Parameters.AddWithValue("Heightfield", SerializeTerrain(ter)); 608 cmd.Parameters.AddWithValue("Heightfield", terrainDBblob);
598 609
599 ExecuteNonQuery(cmd); 610 ExecuteNonQuery(cmd);
600 } 611 }
@@ -1526,30 +1537,6 @@ namespace OpenSim.Data.MySQL
1526 } 1537 }
1527 1538
1528 /// <summary> 1539 /// <summary>
1529 ///
1530 /// </summary>
1531 /// <param name="val"></param>
1532 /// <returns></returns>
1533 private static Array SerializeTerrain(double[,] val)
1534 {
1535 MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) *sizeof (double));
1536 BinaryWriter bw = new BinaryWriter(str);
1537
1538 // TODO: COMPATIBILITY - Add byte-order conversions
1539 for (int x = 0; x < (int)Constants.RegionSize; x++)
1540 for (int y = 0; y < (int)Constants.RegionSize; y++)
1541 {
1542 double height = val[x, y];
1543 if (height == 0.0)
1544 height = double.Epsilon;
1545
1546 bw.Write(height);
1547 }
1548
1549 return str.ToArray();
1550 }
1551
1552 /// <summary>
1553 /// Fill the prim command with prim values 1540 /// Fill the prim command with prim values
1554 /// </summary> 1541 /// </summary>
1555 /// <param name="row"></param> 1542 /// <param name="row"></param>
diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
index b70af6b..cce59c1 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,17 +820,21 @@ 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 {
831 int revision = (int)DBTerrainRevision.Legacy256;
832
833 using ( 838 using (
834 SqliteCommand cmd = new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID", m_conn)) 839 SqliteCommand cmd = new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID", m_conn))
835 { 840 {
@@ -839,15 +844,20 @@ namespace OpenSim.Data.SQLite
839 844
840 // the following is an work around for .NET. The perf 845 // the following is an work around for .NET. The perf
841 // issues associated with it aren't as bad as you think. 846 // issues associated with it aren't as bad as you think.
842 m_log.Debug("[SQLITE REGION DB]: Storing terrain revision r" + revision.ToString());
843 String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" + 847 String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" +
844 " values(:RegionUUID, :Revision, :Heightfield)"; 848 " values(:RegionUUID, :Revision, :Heightfield)";
845 849
850 int terrainDBRevision;
851 Array terrainDBblob;
852 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
853
854 m_log.DebugFormat("{0} Storing terrain revision r {1}", LogHeader, terrainDBRevision);
855
846 using (SqliteCommand cmd = new SqliteCommand(sql, m_conn)) 856 using (SqliteCommand cmd = new SqliteCommand(sql, m_conn))
847 { 857 {
848 cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString())); 858 cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString()));
849 cmd.Parameters.Add(new SqliteParameter(":Revision", revision)); 859 cmd.Parameters.Add(new SqliteParameter(":Revision", terrainDBRevision));
850 cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter))); 860 cmd.Parameters.Add(new SqliteParameter(":Heightfield", terrainDBblob));
851 cmd.ExecuteNonQuery(); 861 cmd.ExecuteNonQuery();
852 } 862 }
853 } 863 }
@@ -2006,24 +2016,6 @@ namespace OpenSim.Data.SQLite
2006 return entry; 2016 return entry;
2007 } 2017 }
2008 2018
2009 /// <summary>
2010 ///
2011 /// </summary>
2012 /// <param name="val"></param>
2013 /// <returns></returns>
2014 private static Array serializeTerrain(double[,] val)
2015 {
2016 MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double));
2017 BinaryWriter bw = new BinaryWriter(str);
2018
2019 // TODO: COMPATIBILITY - Add byte-order conversions
2020 for (int x = 0; x < (int)Constants.RegionSize; x++)
2021 for (int y = 0; y < (int)Constants.RegionSize; y++)
2022 bw.Write(val[x, y]);
2023
2024 return str.ToArray();
2025 }
2026
2027 // private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val) 2019 // private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val)
2028 // { 2020 // {
2029 // row["RegionUUID"] = regionUUID; 2021 // row["RegionUUID"] = regionUUID;
diff --git a/OpenSim/Framework/Constants.cs b/OpenSim/Framework/Constants.cs
index 7979132..9ddb34b 100644
--- a/OpenSim/Framework/Constants.cs
+++ b/OpenSim/Framework/Constants.cs
@@ -40,7 +40,7 @@ namespace OpenSim.Framework
40 public const float TerrainCompression = 100.0f; 40 public const float TerrainCompression = 100.0f;
41 // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum 41 // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum
42 public const int MinRegionSize = 16; 42 public const int MinRegionSize = 16;
43 public const byte TerrainPatchSize = 16; 43 public const int TerrainPatchSize = 16;
44 44
45 public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; 45 public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";
46 46
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs
index 8cb1aef..bee6814 100644
--- a/OpenSim/Framework/TerrainData.cs
+++ b/OpenSim/Framework/TerrainData.cs
@@ -44,9 +44,19 @@ namespace OpenSim.Framework
44 // Someday terrain will have caves 44 // Someday terrain will have caves
45 public abstract float this[int x, int y, int z] { get; set; } 45 public abstract float this[int x, int y, int z] { get; set; }
46 46
47 public bool IsTainted { get; protected set; }
48 public abstract bool IsTaintedAt(int xx, int yy);
49 public abstract void ClearTaint();
50
47 // Return a representation of this terrain for storing as a blob in the database. 51 // Return a representation of this terrain for storing as a blob in the database.
48 // Returns 'true' to say blob was stored in the 'out' locations. 52 // Returns 'true' to say blob was stored in the 'out' locations.
49 public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob); 53 public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
54
55 // return a special compressed representation of the heightmap in shorts
56 public abstract short[] GetCompressedMap();
57 public abstract void SetCompressedMap(short[] cmap);
58
59 public abstract TerrainData Clone();
50 } 60 }
51 61
52 // The terrain is stored as a blob in the database with a 'revision' field. 62 // The terrain is stored as a blob in the database with a 'revision' field.
@@ -72,13 +82,23 @@ namespace OpenSim.Framework
72 // Version of terrain that is a heightmap. 82 // Version of terrain that is a heightmap.
73 // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge 83 // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
74 // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer. 84 // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
85 // The heighmap is kept as an array of short integers. The integer values are converted to
86 // and from floats by TerrainCompressionFactor.
75 public class HeightmapTerrainData : TerrainData 87 public class HeightmapTerrainData : TerrainData
76 { 88 {
77 // TerrainData.this[x, y] 89 // TerrainData.this[x, y]
78 public override float this[int x, int y] 90 public override float this[int x, int y]
79 { 91 {
80 get { return m_heightmap[x * SizeX + y]; } 92 get { return FromCompressedHeight(m_heightmap[x, y]); }
81 set { m_heightmap[x * SizeX + y] = value; } 93 set {
94 short newVal = ToCompressedHeight(value);
95 if (m_heightmap[x, y] != newVal)
96 {
97 m_heightmap[x, y] = newVal;
98 m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
99
100 }
101 }
82 } 102 }
83 103
84 // TerrainData.this[x, y, z] 104 // TerrainData.this[x, y, z]
@@ -88,6 +108,20 @@ namespace OpenSim.Framework
88 set { this[x, y] = value; } 108 set { this[x, y] = value; }
89 } 109 }
90 110
111 // TerrainData.ClearTaint
112 public override void ClearTaint()
113 {
114 IsTainted = false;
115 for (int ii = 0; ii < m_taint.GetLength(0); ii++)
116 for (int jj = 0; jj < m_taint.GetLength(1); jj++)
117 m_taint[ii, jj] = false;
118 }
119
120 public override bool IsTaintedAt(int xx, int yy)
121 {
122 return m_taint[xx / Constants.TerrainPatchSize, yy / Constants.TerrainPatchSize];
123 }
124
91 // TerrainData.GetDatabaseBlob 125 // TerrainData.GetDatabaseBlob
92 // The user wants something to store in the database. 126 // The user wants something to store in the database.
93 public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) 127 public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
@@ -96,7 +130,53 @@ namespace OpenSim.Framework
96 blob = LegacyTerrainSerialization(); 130 blob = LegacyTerrainSerialization();
97 return false; 131 return false;
98 } 132 }
99 private float[] m_heightmap; 133
134 public override short[] GetCompressedMap()
135 {
136 short[] newMap = new short[SizeX * SizeY];
137
138 int ind = 0;
139 for (int xx = 0; xx < SizeX; xx++)
140 for (int yy = 0; yy < SizeY; yy++)
141 newMap[ind++] = m_heightmap[xx, yy];
142
143 return newMap;
144
145 }
146 public override void SetCompressedMap(short[] cmap)
147 {
148 int ind = 0;
149 for (int xx = 0; xx < SizeX; xx++)
150 for (int yy = 0; yy < SizeY; yy++)
151 m_heightmap[xx, yy] = cmap[ind++];
152 }
153
154 // TerrainData.Clone
155 public override TerrainData Clone()
156 {
157 HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ);
158 ret.m_heightmap = (short[,])this.m_heightmap.Clone();
159 return ret;
160 }
161
162 // =============================================================
163
164 private short[,] m_heightmap;
165 // Remember subregions of the heightmap that has changed.
166 private bool[,] m_taint;
167
168 // To save space (especially for large regions), keep the height as a short integer
169 // that is coded as the float height times the compression factor (usually '100'
170 // to make for two decimal points).
171 public static short ToCompressedHeight(double pHeight)
172 {
173 return (short)(pHeight * Constants.TerrainCompression);
174 }
175
176 public static float FromCompressedHeight(short pHeight)
177 {
178 return ((float)pHeight) / Constants.TerrainCompression;
179 }
100 180
101 // To keep with the legacy theme, this can be created with the way terrain 181 // To keep with the legacy theme, this can be created with the way terrain
102 // used to passed around as. 182 // used to passed around as.
@@ -106,26 +186,37 @@ namespace OpenSim.Framework
106 SizeY = pTerrain.GetLength(1); 186 SizeY = pTerrain.GetLength(1);
107 SizeZ = (int)Constants.RegionHeight; 187 SizeZ = (int)Constants.RegionHeight;
108 188
109 int idx = 0; 189 m_heightmap = new short[SizeX, SizeY];
110 m_heightmap = new float[SizeX * SizeY];
111 for (int ii = 0; ii < SizeX; ii++) 190 for (int ii = 0; ii < SizeX; ii++)
112 { 191 {
113 for (int jj = 0; jj < SizeY; jj++) 192 for (int jj = 0; jj < SizeY; jj++)
114 { 193 {
115 m_heightmap[idx++] = (float)pTerrain[ii, jj]; 194 m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]);
116 195
117 } 196 }
118 } 197 }
198
199 m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
200 ClearTaint();
119 } 201 }
120 202
121 public HeightmapTerrainData(float[] pHeightmap, int pX, int pY, int pZ) 203 // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
204 public HeightmapTerrainData(int pX, int pY, int pZ)
122 { 205 {
123 m_heightmap = pHeightmap;
124 SizeX = pX; 206 SizeX = pX;
125 SizeY = pY; 207 SizeY = pY;
126 SizeZ = pZ; 208 SizeZ = pZ;
209 m_heightmap = new short[SizeX, SizeY];
210 m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
211 ClearTaint();
127 } 212 }
128 213
214 public HeightmapTerrainData(short[] cmap, int pX, int pY, int pZ) : this(pX, pY, pZ)
215 {
216 SetCompressedMap(cmap);
217 }
218
219
129 // Just create an array of doubles. Presumes the caller implicitly knows the size. 220 // Just create an array of doubles. Presumes the caller implicitly knows the size.
130 public Array LegacyTerrainSerialization() 221 public Array LegacyTerrainSerialization()
131 { 222 {
@@ -135,12 +226,12 @@ namespace OpenSim.Framework
135 using (BinaryWriter bw = new BinaryWriter(str)) 226 using (BinaryWriter bw = new BinaryWriter(str))
136 { 227 {
137 // TODO: COMPATIBILITY - Add byte-order conversions 228 // TODO: COMPATIBILITY - Add byte-order conversions
138 for (int ii = 0; ii < m_heightmap.Length; ii++) 229 for (int ii = 0; ii < SizeX; ii++)
230 for (int jj = 0; jj < SizeY; jj++)
139 { 231 {
140 double height = (double)m_heightmap[ii]; 232 double height = this[ii, jj];
141 if (height == 0.0) 233 if (height == 0.0)
142 height = double.Epsilon; 234 height = double.Epsilon;
143
144 bw.Write(height); 235 bw.Write(height);
145 } 236 }
146 } 237 }
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index fea9ddf..7984acc 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -34,11 +34,13 @@ using System.Text;
34using System.Threading; 34using System.Threading;
35using System.Timers; 35using System.Timers;
36using System.Xml; 36using System.Xml;
37
37using log4net; 38using log4net;
38using OpenMetaverse; 39using OpenMetaverse;
39using OpenMetaverse.Packets; 40using OpenMetaverse.Packets;
40using OpenMetaverse.Messages.Linden; 41using OpenMetaverse.Messages.Linden;
41using OpenMetaverse.StructuredData; 42using OpenMetaverse.StructuredData;
43
42using OpenSim.Framework; 44using OpenSim.Framework;
43using OpenSim.Framework.Client; 45using OpenSim.Framework.Client;
44using OpenSim.Framework.Monitoring; 46using OpenSim.Framework.Monitoring;
@@ -48,7 +50,6 @@ using OpenSim.Services.Interfaces;
48using Timer = System.Timers.Timer; 50using Timer = System.Timers.Timer;
49using AssetLandmark = OpenSim.Framework.AssetLandmark; 51using AssetLandmark = OpenSim.Framework.AssetLandmark;
50using RegionFlags = OpenMetaverse.RegionFlags; 52using RegionFlags = OpenMetaverse.RegionFlags;
51using Nini.Config;
52 53
53using System.IO; 54using System.IO;
54using PermissionMask = OpenSim.Framework.PermissionMask; 55using PermissionMask = OpenSim.Framework.PermissionMask;
@@ -307,6 +308,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
307 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; 308 private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
308 309
309 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 310 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
311 private static string LogHeader = "[LLCLIENTVIEW]";
310 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients 312 protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
311 313
312 /// <summary> 314 /// <summary>
@@ -447,7 +449,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 449
448// ~LLClientView() 450// ~LLClientView()
449// { 451// {
450// m_log.DebugFormat("[LLCLIENTVIEW]: Destructor called for {0}, circuit code {1}", Name, CircuitCode); 452// m_log.DebugFormat("{0} Destructor called for {1}, circuit code {2}", LogHeader, Name, CircuitCode);
451// } 453// }
452 454
453 /// <summary> 455 /// <summary>
@@ -513,9 +515,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
513 // there is some unidentified connection problem, not where we have issues due to deadlock 515 // there is some unidentified connection problem, not where we have issues due to deadlock
514 if (!IsActive && !force) 516 if (!IsActive && !force)
515 { 517 {
516 m_log.DebugFormat( 518 m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set",
517 "[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set", 519 LogHeader, Name, m_scene.Name);
518 Name, m_scene.Name);
519 520
520 return; 521 return;
521 } 522 }
@@ -1162,10 +1163,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1162 /// <param name="o"></param> 1163 /// <param name="o"></param>
1163 private void DoSendLayerData(object o) 1164 private void DoSendLayerData(object o)
1164 { 1165 {
1165 float[] map = LLHeightFieldMoronize((float[])o); 1166 float[] map = (float[])o;
1166 1167
1167 try 1168 try
1168 { 1169 {
1170 // Send LayerData in typerwriter pattern
1169 //for (int y = 0; y < 16; y++) 1171 //for (int y = 0; y < 16; y++)
1170 //{ 1172 //{
1171 // for (int x = 0; x < 16; x++) 1173 // for (int x = 0; x < 16; x++)
@@ -1230,7 +1232,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1230 // } 1232 // }
1231 1233
1232 /// <summary> 1234 /// <summary>
1233 /// Sends a specified patch to a client 1235 /// Sends a terrain packet for the point specified.
1236 /// This is a legacy call that has refarbed the terrain into a flat map of floats.
1237 /// We just use the terrain from the region we know about.
1234 /// </summary> 1238 /// </summary>
1235 /// <param name="px">Patch coordinate (x) 0..15</param> 1239 /// <param name="px">Patch coordinate (x) 0..15</param>
1236 /// <param name="py">Patch coordinate (y) 0..15</param> 1240 /// <param name="py">Patch coordinate (y) 0..15</param>
@@ -1239,10 +1243,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1239 { 1243 {
1240 try 1244 try
1241 { 1245 {
1242 int[] patches = new int[] { py * 16 + px }; 1246 // For unknown reasons, after this point, patch numbers are swapped X for y.
1243 float[] heightmap = (map.Length == 65536) ? map : LLHeightFieldMoronize(map); 1247 // That means, that for <patchNumX, patchNumY, the array location is computed as map[patchNumY * 16 + patchNumX].
1244 1248 // TODO: someday straighten the below implementation to keep the X row order for patch numbers.
1245 LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); 1249 // Since this is passing only one patch, we just swap the patch numbers.
1250 LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(m_scene.Heightmap.GetTerrainData(), px, py);
1246 1251
1247 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. 1252 // When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
1248 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. 1253 // To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
@@ -1260,14 +1265,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1260 if (m_justEditedTerrain) 1265 if (m_justEditedTerrain)
1261 { 1266 {
1262 layerpack.Header.Reliable = false; 1267 layerpack.Header.Reliable = false;
1263 OutPacket(layerpack, 1268 OutPacket(layerpack, ThrottleOutPacketType.Unknown );
1264 ThrottleOutPacketType.Unknown );
1265 } 1269 }
1266 else 1270 else
1267 { 1271 {
1268 layerpack.Header.Reliable = true; 1272 layerpack.Header.Reliable = true;
1269 OutPacket(layerpack, 1273 OutPacket(layerpack, ThrottleOutPacketType.Land);
1270 ThrottleOutPacketType.Land);
1271 } 1274 }
1272 } 1275 }
1273 catch (Exception e) 1276 catch (Exception e)
@@ -1277,38 +1280,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1277 } 1280 }
1278 1281
1279 /// <summary> 1282 /// <summary>
1280 /// Munges heightfield into the LLUDP backed in restricted heightfield.
1281 /// </summary>
1282 /// <param name="map">float array in the base; Constants.RegionSize</param>
1283 /// <returns>float array in the base 256</returns>
1284 internal float[] LLHeightFieldMoronize(float[] map)
1285 {
1286 if (map.Length == 65536)
1287 return map;
1288 else
1289 {
1290 float[] returnmap = new float[65536];
1291
1292 if (map.Length < 65535)
1293 {
1294 // rebase the vector stride to 256
1295 for (int i = 0; i < Constants.RegionSize; i++)
1296 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, (int)Constants.RegionSize);
1297 }
1298 else
1299 {
1300 for (int i = 0; i < 256; i++)
1301 Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256);
1302 }
1303
1304 //Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536);
1305
1306 return returnmap;
1307 }
1308
1309 }
1310
1311 /// <summary>
1312 /// Send the wind matrix to the client 1283 /// Send the wind matrix to the client
1313 /// </summary> 1284 /// </summary>
1314 /// <param name="windSpeeds">16x16 array of wind speeds</param> 1285 /// <param name="windSpeeds">16x16 array of wind speeds</param>
@@ -2780,8 +2751,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2780 { 2751 {
2781 if (req.AssetInf.Data == null) 2752 if (req.AssetInf.Data == null)
2782 { 2753 {
2783 m_log.ErrorFormat("Cannot send asset {0} ({1}), asset data is null", 2754 m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null",
2784 req.AssetInf.ID, req.AssetInf.Metadata.ContentType); 2755 LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
2785 return; 2756 return;
2786 } 2757 }
2787 2758
diff --git a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
index 2fff4c1..eb6187b 100644
--- a/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
+++ b/OpenSim/Region/CoreModules/World/Terrain/TerrainModule.cs
@@ -30,10 +30,14 @@ using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.Reflection; 31using System.Reflection;
32using System.Net; 32using System.Net;
33
33using log4net; 34using log4net;
34using Nini.Config; 35using Nini.Config;
36
35using OpenMetaverse; 37using OpenMetaverse;
36using Mono.Addins; 38using Mono.Addins;
39
40using OpenSim.Data;
37using OpenSim.Framework; 41using OpenSim.Framework;
38using OpenSim.Region.CoreModules.Framework.InterfaceCommander; 42using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
39using OpenSim.Region.CoreModules.World.Terrain.FileLoaders; 43using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
@@ -130,8 +134,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
130 { 134 {
131 if (m_scene.Heightmap == null) 135 if (m_scene.Heightmap == null)
132 { 136 {
133 m_channel = new TerrainChannel(m_InitialTerrain, 137 m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX,
134 m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY, m_scene.RegionInfo.RegionSizeZ); 138 (int)m_scene.RegionInfo.RegionSizeY,
139 (int)m_scene.RegionInfo.RegionSizeZ);
135 m_scene.Heightmap = m_channel; 140 m_scene.Heightmap = m_channel;
136 UpdateRevertMap(); 141 UpdateRevertMap();
137 } 142 }
@@ -707,7 +712,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
707 private void CheckForTerrainUpdates(bool respectEstateSettings) 712 private void CheckForTerrainUpdates(bool respectEstateSettings)
708 { 713 {
709 bool shouldTaint = false; 714 bool shouldTaint = false;
710 float[] serialised = m_channel.GetFloatsSerialised(); 715 float[] terrData = m_channel.GetFloatsSerialised();
711 int x; 716 int x;
712 for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize) 717 for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize)
713 { 718 {
@@ -716,16 +721,16 @@ namespace OpenSim.Region.CoreModules.World.Terrain
716 { 721 {
717 if (m_channel.Tainted(x, y)) 722 if (m_channel.Tainted(x, y))
718 { 723 {
719 // if we should respect the estate settings then 724 // If we should respect the estate settings then
720 // fixup and height deltas that don't respect them 725 // fixup and height deltas that don't respect them.
726 // Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
721 if (respectEstateSettings && LimitChannelChanges(x, y)) 727 if (respectEstateSettings && LimitChannelChanges(x, y))
722 { 728 {
723 // this has been vetoed, so update 729 // Terrain heights were modified. Refetch the terrain info.
724 // what we are going to send to the client 730 terrData = m_channel.GetFloatsSerialised();
725 serialised = m_channel.GetFloatsSerialised();
726 } 731 }
727 732
728 SendToClients(serialised, x, y); 733 SendToClients(terrData, x, y);
729 shouldTaint = true; 734 shouldTaint = true;
730 } 735 }
731 } 736 }
@@ -794,13 +799,11 @@ 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> 799 /// <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> 800 /// <param name="x">The patch corner to send</param>
796 /// <param name="y">The patch corner to send</param> 801 /// <param name="y">The patch corner to send</param>
797 private void SendToClients(float[] serialised, int x, int y) 802 private void SendToClients(float[] heightMap, int x, int y)
798 { 803 {
799 m_scene.ForEachClient( 804 m_scene.ForEachClient(
800 delegate(IClientAPI controller) 805 delegate(IClientAPI controller)
801 { controller.SendLayerData( 806 { controller.SendLayerData( x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, heightMap); }
802 x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised);
803 }
804 ); 807 );
805 } 808 }
806 809
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
index 847d245..5ba5b31 100644
--- a/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
+++ b/OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs
@@ -136,24 +136,4 @@ namespace OpenSim.Region.Framework.Interfaces
136 void Shutdown(); 136 void Shutdown();
137 } 137 }
138 138
139 // The terrain is stored as a blob in the database with a 'revision' field.
140 // Some implementations of terrain storage would fill the revision field with
141 // the time the terrain was stored. When real revisions were added and this
142 // feature removed, that left some old entries with the time in the revision
143 // field.
144 // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
145 // left over and it is presumed to be 'Legacy256'.
146 // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
147 // If a revision does not match any of these, it is assumed to be Legacy256.
148 public enum DBTerrainRevision
149 {
150 // Terrain is 'double[256,256]'
151 Legacy256 = 11,
152 // Terrain is 'int32, int32, float[,]' where the shorts are X and Y dimensions
153 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
154 Variable2D = 22,
155 // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
156 RevisionHigh = 1234
157 }
158
159} 139}
diff --git a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
index 3c060a4..cc8a236 100644
--- a/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
+++ b/OpenSim/Region/Framework/Interfaces/ITerrainChannel.cs
@@ -25,6 +25,8 @@
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;
29
28namespace OpenSim.Region.Framework.Interfaces 30namespace OpenSim.Region.Framework.Interfaces
29{ 31{
30 public interface ITerrainChannel 32 public interface ITerrainChannel
@@ -35,18 +37,20 @@ namespace OpenSim.Region.Framework.Interfaces
35 37
36 double this[int x, int y] { get; set; } 38 double this[int x, int y] { get; set; }
37 39
40 // Return the packaged terrain data for passing into lower levels of communication
41 TerrainData GetTerrainData();
42
38 /// <summary> 43 /// <summary>
39 /// Squash the entire heightmap into a single dimensioned array 44 /// Squash the entire heightmap into a single dimensioned array
40 /// </summary> 45 /// </summary>
41 /// <returns></returns> 46 /// <returns></returns>
42 float[] GetFloatsSerialised(); 47 float[] GetFloatsSerialised();
43 // Get version of map as a single dimensioned array and each value compressed
44 // into an int (compressedHeight = (int)(floatHeight * Constants.TerrainCompression);)
45 // This is done to make the map smaller as it can get pretty larger for variable sized regions.
46 short[] GetCompressedMap();
47 48
48 double[,] GetDoubles(); 49 double[,] GetDoubles();
50
51 // Check if a location has been updated. Clears the taint flag as a side effect.
49 bool Tainted(int x, int y); 52 bool Tainted(int x, int y);
53
50 ITerrainChannel MakeCopy(); 54 ITerrainChannel MakeCopy();
51 string SaveToXmlString(); 55 string SaveToXmlString();
52 void LoadFromXmlString(string data); 56 void LoadFromXmlString(string data);
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 49e32c6..e2880e3 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1905,7 +1905,7 @@ namespace OpenSim.Region.Framework.Scenes
1905 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); 1905 m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
1906 1906
1907 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); 1907 m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
1908 Heightmap = new TerrainChannel(m_InitialTerrain, RegionInfo.RegionSizeX, RegionInfo.RegionSizeY, RegionInfo.RegionSizeZ); 1908 Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1909 1909
1910 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); 1910 SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
1911 } 1911 }
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index fef93bf..65e890f 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -25,14 +25,19 @@
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 log4net;
40
36namespace OpenSim.Region.Framework.Scenes 41namespace OpenSim.Region.Framework.Scenes
37{ 42{
38 /// <summary> 43 /// <summary>
@@ -40,18 +45,20 @@ namespace OpenSim.Region.Framework.Scenes
40 /// </summary> 45 /// </summary>
41 public class TerrainChannel : ITerrainChannel 46 public class TerrainChannel : ITerrainChannel
42 { 47 {
43 protected bool[,] m_taint; 48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 protected short[] m_map; 49 private static string LogHeader = "[TERRAIN CHANNEL]";
45 50
46 public int Width { get; private set; } // X dimension 51 protected TerrainData m_terrainData;
52
53 public int Width { get { return m_terrainData.SizeX; } } // X dimension
47 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y 54 // Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
48 public int Height { get; private set; } // Y dimension 55 public int Height { get { return m_terrainData.SizeY; } } // Y dimension
49 public int Altitude { get; private set; } // Y dimension 56 public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
50 57
51 // Default, not-often-used builder 58 // Default, not-often-used builder
52 public TerrainChannel() 59 public TerrainChannel()
53 { 60 {
54 InitializeStructures(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight, false); 61 m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
55 FlatLand(); 62 FlatLand();
56 // PinHeadIsland(); 63 // PinHeadIsland();
57 } 64 }
@@ -59,27 +66,23 @@ namespace OpenSim.Region.Framework.Scenes
59 // Create terrain of given size 66 // Create terrain of given size
60 public TerrainChannel(int pX, int pY) 67 public TerrainChannel(int pX, int pY)
61 { 68 {
62 InitializeStructures((uint)pX, (uint)pY, Constants.RegionHeight, true); 69 m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
63 } 70 }
64 71
65 // Create terrain of specified size and initialize with specified terrain. 72 // Create terrain of specified size and initialize with specified terrain.
66 // TODO: join this with the terrain initializers. 73 // TODO: join this with the terrain initializers.
67 public TerrainChannel(String type, uint pX, uint pY, uint pZ) 74 public TerrainChannel(String type, int pX, int pY, int pZ)
68 { 75 {
69 InitializeStructures(pX, pY, pZ, false); 76 m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
70 if (type.Equals("flat")) 77 if (type.Equals("flat"))
71 FlatLand(); 78 FlatLand();
72 else 79 else
73 PinHeadIsland(); 80 PinHeadIsland();
74 } 81 }
75 82
76 public TerrainChannel(double[,] pM, uint pH) 83 public TerrainChannel(double[,] pM, uint pAltitude)
77 { 84 {
78 InitializeStructures((uint)pM.GetLength(0), (uint)pM.GetLength(1), pH, false); 85 m_terrainData = new HeightmapTerrainData(pM);
79 int idx = 0;
80 for (int ii = 0; ii < Height; ii++)
81 for (int jj = 0; jj < Width; jj++)
82 m_map[idx++] = ToCompressedHeight(pM[ii, jj]);
83 } 86 }
84 87
85 #region ITerrainChannel Members 88 #region ITerrainChannel Members
@@ -90,20 +93,23 @@ namespace OpenSim.Region.Framework.Scenes
90 return this.Copy(); 93 return this.Copy();
91 } 94 }
92 95
93 // ITerrainChannel.GetCompressedMap() 96 // ITerrainChannel.GetTerrainData()
94 public short[] GetCompressedMap() 97 public TerrainData GetTerrainData()
95 { 98 {
96 return m_map; 99 return m_terrainData;
97 } 100 }
98 101
99 // ITerrainChannel.GetFloatsSerialized() 102 // ITerrainChannel.GetFloatsSerialized()
103 // NOTICE that the one dimensional form is ordered by Y!!
100 public float[] GetFloatsSerialised() 104 public float[] GetFloatsSerialised()
101 { 105 {
102 int points = Width * Height; 106 int points = Width * Height;
103 float[] heights = new float[points]; 107 float[] heights = new float[points];
104 108
105 for (int ii = 0; ii < points; ii++) 109 int idx = 0;
106 heights[ii] = FromCompressedHeight(m_map[ii]); 110 for (int ii = 0; ii < Height; ii++)
111 for (int jj = 0; jj < Width; jj++)
112 heights[idx++] = m_terrainData[jj, ii];
107 113
108 return heights; 114 return heights;
109 } 115 }
@@ -116,11 +122,11 @@ namespace OpenSim.Region.Framework.Scenes
116 double[,] heights = new double[w, l]; 122 double[,] heights = new double[w, l];
117 123
118 int idx = 0; // index into serialized array 124 int idx = 0; // index into serialized array
119 for (int ii = 0; ii < l; ii++) 125 for (int ii = 0; ii < w; ii++)
120 { 126 {
121 for (int jj = 0; jj < w; jj++) 127 for (int jj = 0; jj < l; jj++)
122 { 128 {
123 heights[ii, jj] = (double)FromCompressedHeight(m_map[idx]); 129 heights[ii, jj] = (double)m_terrainData[ii, jj];
124 idx++; 130 idx++;
125 } 131 }
126 } 132 }
@@ -131,31 +137,20 @@ namespace OpenSim.Region.Framework.Scenes
131 // ITerrainChannel.this[x,y] 137 // ITerrainChannel.this[x,y]
132 public double this[int x, int y] 138 public double this[int x, int y]
133 { 139 {
134 get { return m_map[x * Width + y]; } 140 get { return (double)m_terrainData[x, y]; }
135 set 141 set
136 { 142 {
137 // Will "fix" terrain hole problems. Although not fantastically.
138 if (Double.IsNaN(value) || Double.IsInfinity(value)) 143 if (Double.IsNaN(value) || Double.IsInfinity(value))
139 return; 144 return;
140 145
141 int idx = x * Width + y; 146 m_terrainData[x, y] = (float)value;
142 if (m_map[idx] != value)
143 {
144 m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
145 m_map[idx] = ToCompressedHeight(value);
146 }
147 } 147 }
148 } 148 }
149 149
150 // ITerrainChannel.Tainted() 150 // ITerrainChannel.Tainted()
151 public bool Tainted(int x, int y) 151 public bool Tainted(int x, int y)
152 { 152 {
153 if (m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize]) 153 return m_terrainData.IsTaintedAt(x, y);
154 {
155 m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = false;
156 return true;
157 }
158 return false;
159 } 154 }
160 155
161 // ITerrainChannel.SaveToXmlString() 156 // ITerrainChannel.SaveToXmlString()
@@ -188,49 +183,25 @@ namespace OpenSim.Region.Framework.Scenes
188 183
189 #endregion 184 #endregion
190 185
191 private void InitializeStructures(uint pX, uint pY, uint pZ, bool shouldInitializeHeightmap) 186 /*
192 {
193 Width = (int)pX;
194 Height = (int)pY;
195 Altitude = (int)pZ;
196 m_map = new short[Width * Height];
197 m_taint = new bool[Width / Constants.TerrainPatchSize, Height / Constants.TerrainPatchSize];
198 ClearTaint();
199 if (shouldInitializeHeightmap)
200 {
201 FlatLand();
202 }
203 }
204
205 public void ClearTaint()
206 {
207 for (int ii = 0; ii < Width / Constants.TerrainPatchSize; ii++)
208 for (int jj = 0; jj < Height / Constants.TerrainPatchSize; jj++)
209 m_taint[ii, jj] = false;
210 }
211
212 // To save space (especially for large regions), keep the height as a short integer 187 // To save space (especially for large regions), keep the height as a short integer
213 // that is coded as the float height times the compression factor (usually '100' 188 // that is coded as the float height times the compression factor (usually '100'
214 // to make for two decimal points). 189 // to make for two decimal points).
215 public short ToCompressedHeight(double pHeight) 190 public static short ToCompressedHeight(double pHeight)
216 { 191 {
217 return (short)(pHeight * Constants.TerrainCompression); 192 return (short)(pHeight * Constants.TerrainCompression);
218 } 193 }
219 194
220 public float FromCompressedHeight(short pHeight) 195 public static float FromCompressedHeight(short pHeight)
221 { 196 {
222 return ((float)pHeight) / Constants.TerrainCompression; 197 return ((float)pHeight) / Constants.TerrainCompression;
223 } 198 }
199 */
224 200
225 public TerrainChannel Copy() 201 public TerrainChannel Copy()
226 { 202 {
227 TerrainChannel copy = new TerrainChannel(); 203 TerrainChannel copy = new TerrainChannel();
228 copy.m_map = (short[])m_map.Clone(); 204 copy.m_terrainData = m_terrainData.Clone();
229 copy.m_taint = (bool[,])m_taint.Clone();
230 copy.Width = Width;
231 copy.Height = Height;
232 copy.Altitude = Altitude;
233
234 return copy; 205 return copy;
235 } 206 }
236 207
@@ -289,6 +260,8 @@ namespace OpenSim.Region.Framework.Scenes
289 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); 260 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
290 int index = 0; 261 int index = 0;
291 262
263 m_terrainData = new HeightmapTerrainData(Width, Height, Altitude);
264
292 for (int y = 0; y < Height; y++) 265 for (int y = 0; y < Height; y++)
293 { 266 {
294 for (int x = 0; x < Width; x++) 267 for (int x = 0; x < Width; x++)
@@ -321,7 +294,7 @@ namespace OpenSim.Region.Framework.Scenes
321 // New terrain serialization format that includes the width and length. 294 // New terrain serialization format that includes the width and length.
322 private void ToXml2(XmlWriter xmlWriter) 295 private void ToXml2(XmlWriter xmlWriter)
323 { 296 {
324 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_map); 297 TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.GetCompressedMap());
325 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage)); 298 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
326 serializer.Serialize(xmlWriter, package); 299 serializer.Serialize(xmlWriter, package);
327 } 300 }
@@ -331,38 +304,32 @@ namespace OpenSim.Region.Framework.Scenes
331 { 304 {
332 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage)); 305 XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
333 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader); 306 TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
334 Width = package.SizeX; 307 m_terrainData = new HeightmapTerrainData(package.Map, package.SizeX, package.SizeY, package.SizeZ);
335 Height = package.SizeY;
336 Altitude = package.SizeZ;
337 m_map = package.Map;
338 } 308 }
339 309
340 // Fill the heightmap with the center bump terrain 310 // Fill the heightmap with the center bump terrain
341 private void PinHeadIsland() 311 private void PinHeadIsland()
342 { 312 {
343 int x; 313 for (int x = 0; x < Width; x++)
344 for (x = 0; x < Width; x++)
345 { 314 {
346 int y; 315 for (int y = 0; y < Height; y++)
347 for (y = 0; y < Height; y++)
348 { 316 {
349 int idx = x * (int)Width + y; 317 m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
350 m_map[idx] = ToCompressedHeight(TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10); 318 float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
351 short spherFacA = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01); 319 float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
352 short spherFacB = ToCompressedHeight(TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001); 320 if (m_terrainData[x, y]< spherFacA)
353 if (m_map[idx] < spherFacA) 321 m_terrainData[x, y]= spherFacA;
354 m_map[idx] = spherFacA; 322 if (m_terrainData[x, y]< spherFacB)
355 if (m_map[idx] < spherFacB) 323 m_terrainData[x, y] = spherFacB;
356 m_map[idx] = spherFacB;
357 } 324 }
358 } 325 }
359 } 326 }
360 327
361 private void FlatLand() 328 private void FlatLand()
362 { 329 {
363 short flatHeight = ToCompressedHeight(21); 330 for (int xx = 0; xx < Width; xx++)
364 for (int ii = 0; ii < m_map.Length; ii++) 331 for (int yy = 0; yy < Height; yy++)
365 m_map[ii] = flatHeight; 332 m_terrainData[xx, yy] = 21;
366 } 333 }
367 } 334 }
368} 335}
diff --git a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
index 2e856bc..511745d 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
@@ -113,22 +113,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
113 // routines (like IClientAPI) only pass the float array of heights around. This entry 113 // routines (like IClientAPI) only pass the float array of heights around. This entry
114 // converts that legacy representation into the more compact represenation used in 114 // converts that legacy representation into the more compact represenation used in
115 // TerrainChannel. Someday fix the plumbing between here and the scene. 115 // TerrainChannel. Someday fix the plumbing between here and the scene.
116 public static LayerDataPacket CreateLandPacket(float[] heightmap, int patchX, int patchY, uint sizeX, uint sizeY) 116 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
117 { 117 {
118 int[] xPieces = new int[1]; 118 int[] xPieces = new int[1];
119 int[] yPieces = new int[1]; 119 int[] yPieces = new int[1];
120
121 short[] newmap = new short[heightmap.Length];
122 for (int ii = 0; ii < heightmap.Length; ii++)
123 newmap[ii] = TerrainChannel.ToCompressedHeight(heightmap[ii]);
124
125 xPieces[0] = patchX; // patch X dimension 120 xPieces[0] = patchX; // patch X dimension
126 yPieces[0] = patchY; 121 yPieces[0] = patchY;
127 122
128 m_log.DebugFormat("{0} CreateLandPacket. patchX={1}, patchY={2}, sizeX={3}, sizeY={4}", 123 m_log.DebugFormat("{0} CreateLandPacket. patchX={1}, patchY={2}, sizeX={3}, sizeY={4}",
129 LogHeader, patchX, patchY, sizeX, sizeY); 124 LogHeader, patchX, patchY, terrData.SizeX, terrData.SizeY);
130 125
131 return CreateLandPacket(newmap, xPieces, yPieces, (int)TerrainPatch.LayerType.Land, sizeX, sizeY); 126 return CreateLandPacket(terrData, xPieces, yPieces, (int)TerrainPatch.LayerType.Land);
132 } 127 }
133 128
134 /// <summary> 129 /// <summary>
@@ -153,8 +148,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
153 /// <param name="pRegionSizeX"></param> 148 /// <param name="pRegionSizeX"></param>
154 /// <param name="pRegionSizeY"></param> 149 /// <param name="pRegionSizeY"></param>
155 /// <returns></returns> 150 /// <returns></returns>
156 public static LayerDataPacket CreateLandPacket(short[] heightmap, int[] x, int[] y, byte type, 151 public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
157 uint pRegionSizeX, uint pRegionSizeY)
158 { 152 {
159 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}}; 153 LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
160 154
@@ -168,7 +162,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
168 bitpack.PackBits(type, 8); 162 bitpack.PackBits(type, 8);
169 163
170 for (int i = 0; i < x.Length; i++) 164 for (int i = 0; i < x.Length; i++)
171 CreatePatchFromHeightmap(bitpack, heightmap, x[i], y[i], pRegionSizeX, pRegionSizeY); 165 CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
172 166
173 bitpack.PackBits(END_OF_PATCHES, 8); 167 bitpack.PackBits(END_OF_PATCHES, 8);
174 168
@@ -217,14 +211,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
217 /// </param> 211 /// </param>
218 /// <param name="pRegionSizeX"></param> 212 /// <param name="pRegionSizeX"></param>
219 /// <param name="pRegionSizeY"></param> 213 /// <param name="pRegionSizeY"></param>
220 public static void CreatePatchFromHeightmap(BitPack output, short[] heightmap, int patchX, int patchY, 214 public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
221 uint pRegionSizeX, uint pRegionSizeY)
222 { 215 {
223 TerrainPatch.Header header = PrescanPatch(heightmap, patchX, patchY, pRegionSizeX, pRegionSizeY); 216 TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
224 header.QuantWBits = 136; 217 header.QuantWBits = 136;
225 218
226 // If larger than legacy region size, pack patch X and Y info differently. 219 // If larger than legacy region size, pack patch X and Y info differently.
227 if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize) 220 if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
228 { 221 {
229 header.PatchIDs = (patchY & 0xFFFF); 222 header.PatchIDs = (patchY & 0xFFFF);
230 header.PatchIDs += (patchX << 16); 223 header.PatchIDs += (patchX << 16);
@@ -237,8 +230,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
237 230
238 // NOTE: No idea what prequant and postquant should be or what they do 231 // NOTE: No idea what prequant and postquant should be or what they do
239 int wbits; 232 int wbits;
240 int[] patch = CompressPatch(heightmap, patchX, patchY, header, 10, pRegionSizeX, pRegionSizeY, out wbits); 233 int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
241 wbits = EncodePatchHeader(output, header, patch, pRegionSizeX, pRegionSizeY, wbits); 234 wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
242 EncodePatch(output, patch, 0, wbits); 235 EncodePatch(output, patch, 0, wbits);
243 } 236 }
244 237
@@ -262,19 +255,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
262 } 255 }
263 256
264 // Scan the height info we're returning and return a patch packet header for this patch. 257 // Scan the height info we're returning and return a patch packet header for this patch.
265 // TODO. Why are patches ordered Y,X rather than X,Y? 258 private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
266 private static TerrainPatch.Header PrescanPatch(short[] heightmap, int patchX, int patchY,
267 uint pRegionSizeX, uint pRegionSizeY)
268 { 259 {
269 TerrainPatch.Header header = new TerrainPatch.Header(); 260 TerrainPatch.Header header = new TerrainPatch.Header();
270 short zmax = -32767; 261 float zmax = -99999999.0f;
271 short zmin = 32767; 262 float zmin = 99999999.0f;
272 263
273 for (int j = patchY*16; j < (patchY + 1)*16; j++) 264 for (int j = patchY*16; j < (patchY + 1)*16; j++)
274 { 265 {
275 for (int i = patchX*16; i < (patchX + 1)*16; i++) 266 for (int i = patchX*16; i < (patchX + 1)*16; i++)
276 { 267 {
277 short val = heightmap[j*pRegionSizeX + i]; 268 // short val = heightmap[j*pRegionSizeX + i];
269 float val = terrData[j, i];
278 if (val > zmax) zmax = val; 270 if (val > zmax) zmax = val;
279 if (val < zmin) zmin = val; 271 if (val < zmin) zmin = val;
280 } 272 }
@@ -282,8 +274,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
282 274
283 // Since the the min and max values are the shorts, rescale to be real values. 275 // Since the the min and max values are the shorts, rescale to be real values.
284 // TODO: all this logic should go into the class wrapping the short values. 276 // TODO: all this logic should go into the class wrapping the short values.
285 header.DCOffset = TerrainChannel.FromCompressedHeight(zmin); 277 header.DCOffset = zmin;
286 header.Range = (int)(TerrainChannel.FromCompressedHeight(zmax) - TerrainChannel.FromCompressedHeight(zmin) + 1.0f); 278 header.Range = (int)(zmax - zmin + 1.0f);
287 279
288 return header; 280 return header;
289 } 281 }
@@ -812,8 +804,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
812 return itemp; 804 return itemp;
813 } 805 }
814 806
815 private static int[] CompressPatch(short[] heightmap, int patchX, int patchY, TerrainPatch.Header header, 807 private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
816 int prequant, uint pRegionSizeX, uint pRegionSizeY, out int wbits) 808 int prequant, out int wbits)
817 { 809 {
818 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize]; 810 float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
819 int wordsize = prequant; 811 int wordsize = prequant;
@@ -827,19 +819,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
827 819
828 int k = 0; 820 int k = 0;
829 821
830 premult /= Constants.TerrainCompression; // put here short to float factor
831
832 int jPatchLimit = patchY; 822 int jPatchLimit = patchY;
833 if (patchY >= (pRegionSizeY / Constants.TerrainPatchSize)) 823 if (patchY >= (terrData.SizeY / Constants.TerrainPatchSize))
834 { 824 {
835 jPatchLimit = (int)(pRegionSizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize; 825 jPatchLimit = (int)(terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
836 } 826 }
837 jPatchLimit = (jPatchLimit + 1) * Constants.TerrainPatchSize; 827 jPatchLimit = (jPatchLimit + 1) * Constants.TerrainPatchSize;
838 828
839 int iPatchLimit = patchX; 829 int iPatchLimit = patchX;
840 if (patchX >= (pRegionSizeX / Constants.TerrainPatchSize)) 830 if (patchX >= (terrData.SizeX / Constants.TerrainPatchSize))
841 { 831 {
842 iPatchLimit = (int)(pRegionSizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize; 832 iPatchLimit = (int)(terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize;
843 } 833 }
844 iPatchLimit = (iPatchLimit + 1) * Constants.TerrainPatchSize; 834 iPatchLimit = (iPatchLimit + 1) * Constants.TerrainPatchSize;
845 835
@@ -847,7 +837,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
847 { 837 {
848 for (int i = patchX * Constants.TerrainPatchSize; i < iPatchLimit; i++) 838 for (int i = patchX * Constants.TerrainPatchSize; i < iPatchLimit; i++)
849 { 839 {
850 block[k++] = (heightmap[j*pRegionSizeX + i])*premult - sub; 840 // block[k++] = (heightmap[j*pRegionSizeX + i])*premult - sub;
841 block[k++] = terrData[j, i] - sub;
851 } 842 }
852 } 843 }
853 844
diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs
index 14b6d1a..56171b1 100644
--- a/OpenSim/Services/Interfaces/IGridService.cs
+++ b/OpenSim/Services/Interfaces/IGridService.cs
@@ -246,8 +246,8 @@ namespace OpenSim.Services.Interfaces
246 public GridRegion(RegionInfo ConvertFrom) 246 public GridRegion(RegionInfo ConvertFrom)
247 { 247 {
248 m_regionName = ConvertFrom.RegionName; 248 m_regionName = ConvertFrom.RegionName;
249 m_regionLocX = (int)(ConvertFrom.LegacyRegionLocX * Constants.RegionSize); 249 m_regionLocX = (int)(ConvertFrom.RegionWorldLocX);
250 m_regionLocY = (int)(ConvertFrom.LegacyRegionLocY * Constants.RegionSize); 250 m_regionLocY = (int)(ConvertFrom.RegionWorldLocY);
251 m_internalEndPoint = ConvertFrom.InternalEndPoint; 251 m_internalEndPoint = ConvertFrom.InternalEndPoint;
252 m_externalHostName = ConvertFrom.ExternalHostName; 252 m_externalHostName = ConvertFrom.ExternalHostName;
253 m_httpPort = ConvertFrom.HttpPort; 253 m_httpPort = ConvertFrom.HttpPort;