aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorRobert Adams2013-11-01 11:35:31 -0700
committerRobert Adams2013-11-01 11:35:31 -0700
commitff5885ab234bc9a7efda49eea0e2200711c4933c (patch)
tree21ef180072b30891700f139792d34ca9b2c7e0d6 /OpenSim
parentvarregion: fix problem of X/Y dimensions swapped and incorrect terrain (diff)
downloadopensim-SC-ff5885ab234bc9a7efda49eea0e2200711c4933c.zip
opensim-SC-ff5885ab234bc9a7efda49eea0e2200711c4933c.tar.gz
opensim-SC-ff5885ab234bc9a7efda49eea0e2200711c4933c.tar.bz2
opensim-SC-ff5885ab234bc9a7efda49eea0e2200711c4933c.tar.xz
varregion: push TerrainData implementation up and down the database storage stack.
Implement both LoadTerrain and StoreTerrain for all DBs. Move all database blob serialization/deserialization into TerrainData.
Diffstat (limited to 'OpenSim')
-rw-r--r--OpenSim/Data/MSSQL/MSSQLSimulationData.cs62
-rw-r--r--OpenSim/Data/MySQL/MySQLSimulationData.cs32
-rw-r--r--OpenSim/Data/Null/NullSimulationData.cs21
-rw-r--r--OpenSim/Data/PGSQL/PGSQLSimulationData.cs48
-rw-r--r--OpenSim/Data/SQLite/SQLiteSimulationData.cs29
-rw-r--r--OpenSim/Framework/TerrainData.cs193
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs9
-rw-r--r--OpenSim/Region/Framework/Interfaces/ISimulationDataStore.cs9
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs4
-rw-r--r--OpenSim/Region/Framework/Scenes/TerrainChannel.cs27
-rw-r--r--OpenSim/Services/Connectors/Simulation/SimulationDataService.cs10
-rw-r--r--OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs29
12 files changed, 343 insertions, 130 deletions
diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
index dbfd16c..9f5991b 100644
--- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
@@ -531,43 +531,43 @@ ELSE
531 /// <returns></returns> 531 /// <returns></returns>
532 public double[,] LoadTerrain(UUID regionID) 532 public double[,] LoadTerrain(UUID regionID)
533 { 533 {
534 double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; 534 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
535 terrain.Initialize(); 535 return terrData.GetDoubles();
536 }
537
538 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
539 {
540 TerrainData terrData = null;
536 541
537 string sql = "select top 1 RegionUUID, Revision, Heightfield from terrain where RegionUUID = @RegionUUID order by Revision desc"; 542 string sql = "select top 1 RegionUUID, Revision, Heightfield from terrain where RegionUUID = @RegionUUID order by Revision desc";
538 543
539 using (SqlConnection conn = new SqlConnection(m_connectionString)) 544 using (SqlConnection conn = new SqlConnection(m_connectionString))
540 using (SqlCommand cmd = new SqlCommand(sql, conn))
541 { 545 {
542 // MySqlParameter param = new MySqlParameter(); 546 using (SqlCommand cmd = new SqlCommand(sql, conn))
543 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
544 conn.Open();
545 using (SqlDataReader reader = cmd.ExecuteReader())
546 { 547 {
547 int rev; 548 // MySqlParameter param = new MySqlParameter();
548 if (reader.Read()) 549 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
550 conn.Open();
551 using (SqlDataReader reader = cmd.ExecuteReader())
549 { 552 {
550 MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); 553 int rev;
551 BinaryReader br = new BinaryReader(str); 554 if (reader.Read())
552 for (int x = 0; x < (int)Constants.RegionSize; x++)
553 { 555 {
554 for (int y = 0; y < (int)Constants.RegionSize; y++) 556 rev = (int)reader["Revision"];
555 { 557 byte[] blob = (byte[])reader["Heightfield"];
556 terrain[x, y] = br.ReadDouble(); 558 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
557 }
558 } 559 }
559 rev = (int)reader["Revision"]; 560 else
560 } 561 {
561 else 562 _Log.Info("[REGION DB]: No terrain found for region");
562 { 563 return null;
563 _Log.Info("[REGION DB]: No terrain found for region"); 564 }
564 return null; 565 _Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
565 } 566 }
566 _Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
567 } 567 }
568 } 568 }
569 569
570 return terrain; 570 return terrData;
571 } 571 }
572 572
573 // Legacy entry point for when terrain was always a 256x256 hieghtmap 573 // Legacy entry point for when terrain was always a 256x256 hieghtmap
@@ -600,13 +600,15 @@ ELSE
600 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob); 600 terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
601 601
602 using (SqlConnection conn = new SqlConnection(m_connectionString)) 602 using (SqlConnection conn = new SqlConnection(m_connectionString))
603 using (SqlCommand cmd = new SqlCommand(sql, conn))
604 { 603 {
605 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID)); 604 using (SqlCommand cmd = new SqlCommand(sql, conn))
606 cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision)); 605 {
607 cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob)); 606 cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
608 conn.Open(); 607 cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision));
609 cmd.ExecuteNonQuery(); 608 cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob));
609 conn.Open();
610 cmd.ExecuteNonQuery();
611 }
610 } 612 }
611 613
612 _Log.InfoFormat("{0} Stored terrain revision r={1}", LogHeader, terrainDBRevision); 614 _Log.InfoFormat("{0} Stored terrain revision r={1}", LogHeader, terrainDBRevision);
diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index 4bd8617..42f2ebb 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -613,9 +613,16 @@ namespace OpenSim.Data.MySQL
613 } 613 }
614 } 614 }
615 615
616 // Legacy region loading
616 public double[,] LoadTerrain(UUID regionID) 617 public double[,] LoadTerrain(UUID regionID)
617 { 618 {
618 double[,] terrain = null; 619 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
620 return terrData.GetDoubles();
621 }
622
623 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
624 {
625 TerrainData terrData = null;
619 626
620 lock (m_dbLock) 627 lock (m_dbLock)
621 { 628 {
@@ -635,32 +642,15 @@ namespace OpenSim.Data.MySQL
635 while (reader.Read()) 642 while (reader.Read())
636 { 643 {
637 int rev = Convert.ToInt32(reader["Revision"]); 644 int rev = Convert.ToInt32(reader["Revision"]);
638 645 byte[] blob = (byte[])reader["Heightfield"];
639 terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; 646 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
640 terrain.Initialize();
641
642 using (MemoryStream mstr = new MemoryStream((byte[])reader["Heightfield"]))
643 {
644 using (BinaryReader br = new BinaryReader(mstr))
645 {
646 for (int x = 0; x < (int)Constants.RegionSize; x++)
647 {
648 for (int y = 0; y < (int)Constants.RegionSize; y++)
649 {
650 terrain[x, y] = br.ReadDouble();
651 }
652 }
653 }
654
655 m_log.InfoFormat("[REGION DB]: Loaded terrain revision r{0}", rev);
656 }
657 } 647 }
658 } 648 }
659 } 649 }
660 } 650 }
661 } 651 }
662 652
663 return terrain; 653 return terrData;
664 } 654 }
665 655
666 public void RemoveLandObject(UUID globalID) 656 public void RemoveLandObject(UUID globalID)
diff --git a/OpenSim/Data/Null/NullSimulationData.cs b/OpenSim/Data/Null/NullSimulationData.cs
index d11ad72..acde1a1 100644
--- a/OpenSim/Data/Null/NullSimulationData.cs
+++ b/OpenSim/Data/Null/NullSimulationData.cs
@@ -132,18 +132,35 @@ 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.
143 public double[,] LoadTerrain(UUID regionID) 151 public double[,] LoadTerrain(UUID regionID)
144 { 152 {
145 if (m_terrains.ContainsKey(regionID)) 153 if (m_terrains.ContainsKey(regionID))
146 { 154 {
155 return m_terrains[regionID].GetDoubles();
156 }
157 return null;
158 }
159
160 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
161 {
162 if (m_terrains.ContainsKey(regionID))
163 {
147 return m_terrains[regionID]; 164 return m_terrains[regionID];
148 } 165 }
149 return null; 166 return null;
diff --git a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs
index 433ffe9..34eb038 100644
--- a/OpenSim/Data/PGSQL/PGSQLSimulationData.cs
+++ b/OpenSim/Data/PGSQL/PGSQLSimulationData.cs
@@ -524,44 +524,44 @@ namespace OpenSim.Data.PGSQL
524 /// <returns></returns> 524 /// <returns></returns>
525 public double[,] LoadTerrain(UUID regionID) 525 public double[,] LoadTerrain(UUID regionID)
526 { 526 {
527 double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; 527 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
528 terrain.Initialize(); 528 return terrData.GetDoubles();
529 }
530
531 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
532 {
533 TerrainData terrData = null;
529 534
530 string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain 535 string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain
531 where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; "; 536 where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; ";
532 537
533 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) 538 using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
534 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
535 { 539 {
536 // PGSqlParameter param = new PGSqlParameter(); 540 using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
537 cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
538 conn.Open();
539 using (NpgsqlDataReader reader = cmd.ExecuteReader())
540 { 541 {
541 int rev; 542 // PGSqlParameter param = new PGSqlParameter();
542 if (reader.Read()) 543 cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
544 conn.Open();
545 using (NpgsqlDataReader reader = cmd.ExecuteReader())
543 { 546 {
544 MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); 547 int rev;
545 BinaryReader br = new BinaryReader(str); 548 if (reader.Read())
546 for (int x = 0; x < (int)Constants.RegionSize; x++)
547 { 549 {
548 for (int y = 0; y < (int)Constants.RegionSize; y++) 550 rev = Convert.ToInt32(reader["Revision"]);
549 { 551 byte[] blob = (byte[])reader["Heightfield"];
550 terrain[x, y] = br.ReadDouble(); 552 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
551 }
552 } 553 }
553 rev = (int)reader["Revision"]; 554 else
554 } 555 {
555 else 556 _Log.Info("[REGION DB]: No terrain found for region");
556 { 557 return null;
557 _Log.Info("[REGION DB]: No terrain found for region"); 558 }
558 return null; 559 _Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
559 } 560 }
560 _Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
561 } 561 }
562 } 562 }
563 563
564 return terrain; 564 return terrData;
565 } 565 }
566 566
567 // Legacy entry point for when terrain was always a 256x256 heightmap 567 // Legacy entry point for when terrain was always a 256x256 heightmap
diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
index cce59c1..dac4450 100644
--- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs
+++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
@@ -870,11 +870,16 @@ namespace OpenSim.Data.SQLite
870 /// <returns>Heightfield data</returns> 870 /// <returns>Heightfield data</returns>
871 public double[,] LoadTerrain(UUID regionID) 871 public double[,] LoadTerrain(UUID regionID)
872 { 872 {
873 TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
874 return terrData.GetDoubles();
875 }
876
877 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
878 {
879 TerrainData terrData = null;
880
873 lock (ds) 881 lock (ds)
874 { 882 {
875 double[,] terret = new double[(int)Constants.RegionSize, (int)Constants.RegionSize];
876 terret.Initialize();
877
878 String sql = "select RegionUUID, Revision, Heightfield from terrain" + 883 String sql = "select RegionUUID, Revision, Heightfield from terrain" +
879 " where RegionUUID=:RegionUUID order by Revision desc"; 884 " where RegionUUID=:RegionUUID order by Revision desc";
880 885
@@ -887,21 +892,9 @@ namespace OpenSim.Data.SQLite
887 int rev = 0; 892 int rev = 0;
888 if (row.Read()) 893 if (row.Read())
889 { 894 {
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"]); 895 rev = Convert.ToInt32(row["Revision"]);
896 byte[] blob = (byte[])row["Heightfield"];
897 terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
905 } 898 }
906 else 899 else
907 { 900 {
@@ -912,8 +905,8 @@ namespace OpenSim.Data.SQLite
912 m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString()); 905 m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString());
913 } 906 }
914 } 907 }
915 return terret;
916 } 908 }
909 return terrData;
917 } 910 }
918 911
919 public void RemoveLandObject(UUID globalID) 912 public void RemoveLandObject(UUID globalID)
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs
index d7f1655..58b203f 100644
--- a/OpenSim/Framework/TerrainData.cs
+++ b/OpenSim/Framework/TerrainData.cs
@@ -43,6 +43,9 @@ namespace OpenSim.Framework
43 public int SizeY { get; protected set; } 43 public int SizeY { get; protected set; }
44 public int SizeZ { get; protected set; } 44 public int SizeZ { get; protected set; }
45 45
46 // A height used when the user doesn't specify anything
47 public const float DefaultTerrainHeight = 21f;
48
46 public abstract float this[int x, int y] { get; set; } 49 public abstract float this[int x, int y] { get; set; }
47 // Someday terrain will have caves 50 // Someday terrain will have caves
48 public abstract float this[int x, int y, int z] { get; set; } 51 public abstract float this[int x, int y, int z] { get; set; }
@@ -51,15 +54,28 @@ namespace OpenSim.Framework
51 public abstract bool IsTaintedAt(int xx, int yy); 54 public abstract bool IsTaintedAt(int xx, int yy);
52 public abstract void ClearTaint(); 55 public abstract void ClearTaint();
53 56
57 public abstract void ClearLand();
58 public abstract void ClearLand(float height);
59
54 // Return a representation of this terrain for storing as a blob in the database. 60 // Return a representation of this terrain for storing as a blob in the database.
55 // Returns 'true' to say blob was stored in the 'out' locations. 61 // Returns 'true' to say blob was stored in the 'out' locations.
56 public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob); 62 public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
57 63
64 // Given a revision code and a blob from the database, create and return the right type of TerrainData.
65 // The sizes passed are the expected size of the region. The database info will be used to
66 // initialize the heightmap of that sized region with as much data is in the blob.
67 // Return created TerrainData or 'null' if unsuccessful.
68 public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
69 {
70 // For the moment, there is only one implementation class
71 return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob);
72 }
73
58 // return a special compressed representation of the heightmap in shorts 74 // return a special compressed representation of the heightmap in shorts
59 public abstract short[] GetCompressedMap(); 75 public abstract short[] GetCompressedMap();
60 public abstract float CompressionFactor { get; } 76 public abstract float CompressionFactor { get; }
61 public abstract void SetCompressedMap(short[] cmap, float pCompressionFactor);
62 77
78 public abstract double[,] GetDoubles();
63 public abstract TerrainData Clone(); 79 public abstract TerrainData Clone();
64 } 80 }
65 81
@@ -76,9 +92,14 @@ namespace OpenSim.Framework
76 { 92 {
77 // Terrain is 'double[256,256]' 93 // Terrain is 'double[256,256]'
78 Legacy256 = 11, 94 Legacy256 = 11,
79 // Terrain is 'int32, int32, float[,]' where the shorts are X and Y dimensions 95 // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions
80 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. 96 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
81 Variable2D = 22, 97 Variable2D = 22,
98 // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions
99 // and third int is the 'compression factor'. The heights are compressed as
100 // "short compressedHeight = (short)(height * compressionFactor);"
101 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
102 Compressed2D = 27,
82 // A revision that is not listed above or any revision greater than this value is 'Legacy256'. 103 // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
83 RevisionHigh = 1234 104 RevisionHigh = 1234
84 } 105 }
@@ -124,6 +145,20 @@ namespace OpenSim.Framework
124 m_taint[ii, jj] = false; 145 m_taint[ii, jj] = false;
125 } 146 }
126 147
148 // TerrainData.ClearLand
149 public override void ClearLand()
150 {
151 ClearLand(DefaultTerrainHeight);
152 }
153 // TerrainData.ClearLand(float)
154 public override void ClearLand(float pHeight)
155 {
156 short flatHeight = ToCompressedHeight(pHeight);
157 for (int xx = 0; xx < SizeX; xx++)
158 for (int yy = 0; yy < SizeY; yy++)
159 m_heightmap[xx, yy] = flatHeight;
160 }
161
127 public override bool IsTaintedAt(int xx, int yy) 162 public override bool IsTaintedAt(int xx, int yy)
128 { 163 {
129 return m_taint[xx / Constants.TerrainPatchSize, yy / Constants.TerrainPatchSize]; 164 return m_taint[xx / Constants.TerrainPatchSize, yy / Constants.TerrainPatchSize];
@@ -134,7 +169,7 @@ namespace OpenSim.Framework
134 public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) 169 public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
135 { 170 {
136 DBRevisionCode = (int)DBTerrainRevision.Legacy256; 171 DBRevisionCode = (int)DBTerrainRevision.Legacy256;
137 blob = LegacyTerrainSerialization(); 172 blob = ToLegacyTerrainSerialization();
138 return false; 173 return false;
139 } 174 }
140 175
@@ -155,17 +190,6 @@ namespace OpenSim.Framework
155 return newMap; 190 return newMap;
156 191
157 } 192 }
158 // TerrainData.SetCompressedMap
159 public override void SetCompressedMap(short[] cmap, float pCompressionFactor)
160 {
161 m_compressionFactor = pCompressionFactor;
162
163 int ind = 0;
164 for (int xx = 0; xx < SizeX; xx++)
165 for (int yy = 0; yy < SizeY; yy++)
166 m_heightmap[xx, yy] = cmap[ind++];
167 }
168
169 // TerrainData.Clone 193 // TerrainData.Clone
170 public override TerrainData Clone() 194 public override TerrainData Clone()
171 { 195 {
@@ -174,6 +198,18 @@ namespace OpenSim.Framework
174 return ret; 198 return ret;
175 } 199 }
176 200
201 // TerrainData.GetDoubles
202 public override double[,] GetDoubles()
203 {
204 double[,] ret = new double[SizeX, SizeY];
205 for (int xx = 0; xx < SizeX; xx++)
206 for (int yy = 0; yy < SizeY; yy++)
207 ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]);
208
209 return ret;
210 }
211
212
177 // ============================================================= 213 // =============================================================
178 214
179 private short[,] m_heightmap; 215 private short[,] m_heightmap;
@@ -230,31 +266,140 @@ namespace OpenSim.Framework
230 266
231 public HeightmapTerrainData(short[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ) 267 public HeightmapTerrainData(short[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ)
232 { 268 {
233 SetCompressedMap(cmap, pCompressionFactor); 269 m_compressionFactor = pCompressionFactor;
270 int ind = 0;
271 for (int xx = 0; xx < SizeX; xx++)
272 for (int yy = 0; yy < SizeY; yy++)
273 m_heightmap[xx, yy] = cmap[ind++];
234 } 274 }
235 275
276 // Create a heighmap from a database blob
277 public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ)
278 {
279 switch ((DBTerrainRevision)pFormatCode)
280 {
281 case DBTerrainRevision.Compressed2D:
282 FromCompressedTerrainSerialization(pBlob);
283 break;
284 default:
285 FromLegacyTerrainSerialization(pBlob);
286 break;
287 }
288 }
236 289
237 // Just create an array of doubles. Presumes the caller implicitly knows the size. 290 // Just create an array of doubles. Presumes the caller implicitly knows the size.
238 public Array LegacyTerrainSerialization() 291 public Array ToLegacyTerrainSerialization()
239 { 292 {
240 Array ret = null; 293 Array ret = null;
241 using (MemoryStream str = new MemoryStream(SizeX * SizeY * sizeof(double))) 294
295 using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double)))
242 { 296 {
243 using (BinaryWriter bw = new BinaryWriter(str)) 297 using (BinaryWriter bw = new BinaryWriter(str))
244 { 298 {
245 // TODO: COMPATIBILITY - Add byte-order conversions 299 for (int xx = 0; xx < Constants.RegionSize; xx++)
246 for (int ii = 0; ii < SizeX; ii++)
247 for (int jj = 0; jj < SizeY; jj++)
248 { 300 {
249 double height = this[ii, jj]; 301 for (int yy = 0; yy < Constants.RegionSize; yy++)
250 if (height == 0.0) 302 {
251 height = double.Epsilon; 303 double height = this[xx, yy];
252 bw.Write(height); 304 if (height == 0.0)
305 height = double.Epsilon;
306 bw.Write(height);
307 }
253 } 308 }
254 } 309 }
255 ret = str.ToArray(); 310 ret = str.ToArray();
256 } 311 }
257 return ret; 312 return ret;
258 } 313 }
314
315 // Just create an array of doubles. Presumes the caller implicitly knows the size.
316 public void FromLegacyTerrainSerialization(byte[] pBlob)
317 {
318 // In case database info doesn't match real terrain size, initialize the whole terrain.
319 ClearLand();
320
321 using (MemoryStream mstr = new MemoryStream(pBlob))
322 {
323 using (BinaryReader br = new BinaryReader(mstr))
324 {
325 for (int xx = 0; xx < (int)Constants.RegionSize; xx++)
326 {
327 for (int yy = 0; yy < (int)Constants.RegionSize; yy++)
328 {
329 float val = (float)br.ReadDouble();
330 if (xx < SizeX && yy < SizeY)
331 m_heightmap[xx, yy] = ToCompressedHeight(val);
332 }
333 }
334 }
335 ClearTaint();
336
337 m_log.InfoFormat("{0} Loaded legacy heightmap. SizeX={1}, SizeY={2}", LogHeader, SizeX, SizeY);
338 }
339 }
340
341 // See the reader below.
342 public Array ToCompressedTerrainSerialization()
343 {
344 Array ret = null;
345 using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16))))
346 {
347 using (BinaryWriter bw = new BinaryWriter(str))
348 {
349 bw.Write((Int32)DBTerrainRevision.Compressed2D);
350 bw.Write((Int32)SizeX);
351 bw.Write((Int32)SizeY);
352 bw.Write((Int32)CompressionFactor);
353 for (int yy = 0; yy < SizeY; yy++)
354 for (int xx = 0; xx < SizeX; xx++)
355 {
356 bw.Write((Int16)m_heightmap[xx, yy]);
357 }
358 }
359 ret = str.ToArray();
360 }
361 return ret;
362 }
363
364 // Initialize heightmap from blob consisting of:
365 // int32, int32, int32, int32, int16[]
366 // where the first int32 is format code, next two int32s are the X and y of heightmap data and
367 // the forth int is the compression factor for the following int16s
368 // This is just sets heightmap info. The actual size of the region was set on this instance's
369 // creation and any heights not initialized by theis blob are set to the default height.
370 public void FromCompressedTerrainSerialization(byte[] pBlob)
371 {
372 Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor;
373
374 using (MemoryStream mstr = new MemoryStream(pBlob))
375 {
376 using (BinaryReader br = new BinaryReader(mstr))
377 {
378 hmFormatCode = br.ReadInt32();
379 hmSizeX = br.ReadInt32();
380 hmSizeY = br.ReadInt32();
381 hmCompressionFactor = br.ReadInt32();
382
383 m_compressionFactor = hmCompressionFactor;
384
385 // In case database info doesn't match real terrain size, initialize the whole terrain.
386 ClearLand();
387
388 for (int yy = 0; yy < hmSizeY; yy++)
389 {
390 for (int xx = 0; xx < hmSizeX; xx++)
391 {
392 Int16 val = br.ReadInt16();
393 if (xx < SizeX && yy < SizeY)
394 m_heightmap[xx, yy] = ToCompressedHeight(val);
395 }
396 }
397 }
398 ClearTaint();
399
400 m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size={<{3},{4}>. CompFact={5}", LogHeader,
401 hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor);
402 }
403 }
259 } 404 }
260} 405}
diff --git a/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs b/OpenSim/Region/Framework/Interfaces/ISimulationDataService.cs
index 085b5ca..8948f04 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 5ba5b31..917b5d1 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);
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index e2880e3..a19f31f 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -1894,7 +1894,7 @@ namespace OpenSim.Region.Framework.Scenes
1894 { 1894 {
1895 try 1895 try
1896 { 1896 {
1897 double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID); 1897 TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
1898 if (map == null) 1898 if (map == null)
1899 { 1899 {
1900 // This should be in the Terrain module, but it isn't because 1900 // This should be in the Terrain module, but it isn't because
@@ -1911,7 +1911,7 @@ namespace OpenSim.Region.Framework.Scenes
1911 } 1911 }
1912 else 1912 else
1913 { 1913 {
1914 Heightmap = new TerrainChannel(map, RegionInfo.RegionSizeZ); 1914 Heightmap = new TerrainChannel(map);
1915 } 1915 }
1916 } 1916 }
1917 catch (IOException e) 1917 catch (IOException e)
diff --git a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
index d641c87..03499e8 100644
--- a/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
+++ b/OpenSim/Region/Framework/Scenes/TerrainChannel.cs
@@ -80,9 +80,26 @@ namespace OpenSim.Region.Framework.Scenes
80 PinHeadIsland(); 80 PinHeadIsland();
81 } 81 }
82 82
83 public TerrainChannel(double[,] pM, uint pAltitude) 83 // Create channel passed a heightmap and expected dimensions of the region.
84 // The heightmap might not fit the passed size so accomodations must be made.
85 public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude)
84 { 86 {
85 m_terrainData = new HeightmapTerrainData(pM); 87 int hmSizeX = pM.GetLength(0);
88 int hmSizeY = pM.GetLength(1);
89
90 m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
91
92 for (int xx = 0; xx < pSizeX; xx++)
93 for (int yy = 0; yy < pSizeY; yy++)
94 if (xx > hmSizeX || yy > hmSizeY)
95 m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
96 else
97 m_terrainData[xx, yy] = (float)pM[xx, yy];
98 }
99
100 public TerrainChannel(TerrainData pTerrData)
101 {
102 m_terrainData = pTerrData;
86 } 103 }
87 104
88 #region ITerrainChannel Members 105 #region ITerrainChannel Members
@@ -247,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes
247 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); 264 byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
248 int index = 0; 265 int index = 0;
249 266
250 m_terrainData = new HeightmapTerrainData(Width, Height, Altitude); 267 m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
251 268
252 for (int y = 0; y < Height; y++) 269 for (int y = 0; y < Height; y++)
253 { 270 {
@@ -317,9 +334,7 @@ namespace OpenSim.Region.Framework.Scenes
317 334
318 private void FlatLand() 335 private void FlatLand()
319 { 336 {
320 for (int xx = 0; xx < Width; xx++) 337 m_terrainData.ClearLand();
321 for (int yy = 0; yy < Height; yy++)
322 m_terrainData[xx, yy] = 21;
323 } 338 }
324 } 339 }
325} 340}
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs
index 504fcaf..2cbf967 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/Tests/Common/Mock/MockRegionDataPlugin.cs b/OpenSim/Tests/Common/Mock/MockRegionDataPlugin.cs
index ed29c39..5df8e04 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);
@@ -154,7 +164,7 @@ namespace OpenSim.Data.Null
154 protected Dictionary<UUID, SceneObjectPart> m_sceneObjectParts = new Dictionary<UUID, SceneObjectPart>(); 164 protected Dictionary<UUID, SceneObjectPart> m_sceneObjectParts = new Dictionary<UUID, SceneObjectPart>();
155 protected Dictionary<UUID, ICollection<TaskInventoryItem>> m_primItems 165 protected Dictionary<UUID, ICollection<TaskInventoryItem>> m_primItems
156 = new Dictionary<UUID, ICollection<TaskInventoryItem>>(); 166 = new Dictionary<UUID, ICollection<TaskInventoryItem>>();
157 protected Dictionary<UUID, double[,]> m_terrains = new Dictionary<UUID, double[,]>(); 167 protected Dictionary<UUID, TerrainData> m_terrains = new Dictionary<UUID, TerrainData>();
158 protected Dictionary<UUID, LandData> m_landData = new Dictionary<UUID, LandData>(); 168 protected Dictionary<UUID, LandData> m_landData = new Dictionary<UUID, LandData>();
159 169
160 public void Initialise(string dbfile) 170 public void Initialise(string dbfile)
@@ -299,12 +309,17 @@ namespace OpenSim.Data.Null
299 return new List<SceneObjectGroup>(objects.Values); 309 return new List<SceneObjectGroup>(objects.Values);
300 } 310 }
301 311
302 public void StoreTerrain(double[,] ter, UUID regionID) 312 public void StoreTerrain(TerrainData ter, UUID regionID)
303 { 313 {
304 m_terrains[regionID] = ter; 314 m_terrains[regionID] = ter;
305 } 315 }
306 316
307 public double[,] LoadTerrain(UUID regionID) 317 public void StoreTerrain(double[,] ter, UUID regionID)
318 {
319 m_terrains[regionID] = new HeightmapTerrainData(ter);
320 }
321
322 public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
308 { 323 {
309 if (m_terrains.ContainsKey(regionID)) 324 if (m_terrains.ContainsKey(regionID))
310 return m_terrains[regionID]; 325 return m_terrains[regionID];
@@ -312,6 +327,14 @@ namespace OpenSim.Data.Null
312 return null; 327 return null;
313 } 328 }
314 329
330 public double[,] LoadTerrain(UUID regionID)
331 {
332 if (m_terrains.ContainsKey(regionID))
333 return m_terrains[regionID].GetDoubles();
334 else
335 return null;
336 }
337
315 public void RemoveLandObject(UUID globalID) 338 public void RemoveLandObject(UUID globalID)
316 { 339 {
317 if (m_landData.ContainsKey(globalID)) 340 if (m_landData.ContainsKey(globalID))