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.
varregion
Robert Adams 2013-11-01 11:35:31 -07:00
parent 39777db8ef
commit ff5885ab23
12 changed files with 343 additions and 130 deletions

View File

@ -531,43 +531,43 @@ ELSE
/// <returns></returns> /// <returns></returns>
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{ {
double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
terrain.Initialize(); return terrData.GetDoubles();
}
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
TerrainData terrData = null;
string sql = "select top 1 RegionUUID, Revision, Heightfield from terrain where RegionUUID = @RegionUUID order by Revision desc"; string sql = "select top 1 RegionUUID, Revision, Heightfield from terrain where RegionUUID = @RegionUUID order by Revision desc";
using (SqlConnection conn = new SqlConnection(m_connectionString)) using (SqlConnection conn = new SqlConnection(m_connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn))
{ {
// MySqlParameter param = new MySqlParameter(); using (SqlCommand cmd = new SqlCommand(sql, conn))
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{ {
int rev; // MySqlParameter param = new MySqlParameter();
if (reader.Read()) cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
conn.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{ {
MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); int rev;
BinaryReader br = new BinaryReader(str); if (reader.Read())
for (int x = 0; x < (int)Constants.RegionSize; x++)
{ {
for (int y = 0; y < (int)Constants.RegionSize; y++) rev = (int)reader["Revision"];
{ byte[] blob = (byte[])reader["Heightfield"];
terrain[x, y] = br.ReadDouble(); terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
}
} }
rev = (int)reader["Revision"]; else
{
_Log.Info("[REGION DB]: No terrain found for region");
return null;
}
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
} }
else
{
_Log.Info("[REGION DB]: No terrain found for region");
return null;
}
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
} }
} }
return terrain; return terrData;
} }
// Legacy entry point for when terrain was always a 256x256 hieghtmap // Legacy entry point for when terrain was always a 256x256 hieghtmap
@ -600,13 +600,15 @@ ELSE
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob); terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
using (SqlConnection conn = new SqlConnection(m_connectionString)) using (SqlConnection conn = new SqlConnection(m_connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn))
{ {
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID)); using (SqlCommand cmd = new SqlCommand(sql, conn))
cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision)); {
cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob)); cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
conn.Open(); cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision));
cmd.ExecuteNonQuery(); cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob));
conn.Open();
cmd.ExecuteNonQuery();
}
} }
_Log.InfoFormat("{0} Stored terrain revision r={1}", LogHeader, terrainDBRevision); _Log.InfoFormat("{0} Stored terrain revision r={1}", LogHeader, terrainDBRevision);

View File

@ -613,9 +613,16 @@ namespace OpenSim.Data.MySQL
} }
} }
// Legacy region loading
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{ {
double[,] terrain = null; TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
return terrData.GetDoubles();
}
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
TerrainData terrData = null;
lock (m_dbLock) lock (m_dbLock)
{ {
@ -635,32 +642,15 @@ namespace OpenSim.Data.MySQL
while (reader.Read()) while (reader.Read())
{ {
int rev = Convert.ToInt32(reader["Revision"]); int rev = Convert.ToInt32(reader["Revision"]);
byte[] blob = (byte[])reader["Heightfield"];
terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
terrain.Initialize();
using (MemoryStream mstr = new MemoryStream((byte[])reader["Heightfield"]))
{
using (BinaryReader br = new BinaryReader(mstr))
{
for (int x = 0; x < (int)Constants.RegionSize; x++)
{
for (int y = 0; y < (int)Constants.RegionSize; y++)
{
terrain[x, y] = br.ReadDouble();
}
}
}
m_log.InfoFormat("[REGION DB]: Loaded terrain revision r{0}", rev);
}
} }
} }
} }
} }
} }
return terrain; return terrData;
} }
public void RemoveLandObject(UUID globalID) public void RemoveLandObject(UUID globalID)

View File

@ -132,15 +132,32 @@ namespace OpenSim.Data.Null
return new List<SceneObjectGroup>(); return new List<SceneObjectGroup>();
} }
Dictionary<UUID, double[,]> m_terrains = new Dictionary<UUID, double[,]>(); Dictionary<UUID, TerrainData> m_terrains = new Dictionary<UUID, TerrainData>();
public void StoreTerrain(double[,] ter, UUID regionID) public void StoreTerrain(TerrainData ter, UUID regionID)
{ {
if (m_terrains.ContainsKey(regionID)) if (m_terrains.ContainsKey(regionID))
m_terrains.Remove(regionID); m_terrains.Remove(regionID);
m_terrains.Add(regionID, ter); m_terrains.Add(regionID, ter);
} }
// Legacy. Just don't do this.
public void StoreTerrain(double[,] ter, UUID regionID)
{
TerrainData terrData = new HeightmapTerrainData(ter);
StoreTerrain(terrData, regionID);
}
// Legacy. Just don't do this.
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{
if (m_terrains.ContainsKey(regionID))
{
return m_terrains[regionID].GetDoubles();
}
return null;
}
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{ {
if (m_terrains.ContainsKey(regionID)) if (m_terrains.ContainsKey(regionID))
{ {

View File

@ -524,44 +524,44 @@ namespace OpenSim.Data.PGSQL
/// <returns></returns> /// <returns></returns>
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{ {
double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize]; TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
terrain.Initialize(); return terrData.GetDoubles();
}
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
TerrainData terrData = null;
string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain
where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; "; where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; ";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{ {
// PGSqlParameter param = new PGSqlParameter(); using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{ {
int rev; // PGSqlParameter param = new PGSqlParameter();
if (reader.Read()) cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{ {
MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); int rev;
BinaryReader br = new BinaryReader(str); if (reader.Read())
for (int x = 0; x < (int)Constants.RegionSize; x++)
{ {
for (int y = 0; y < (int)Constants.RegionSize; y++) rev = Convert.ToInt32(reader["Revision"]);
{ byte[] blob = (byte[])reader["Heightfield"];
terrain[x, y] = br.ReadDouble(); terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
}
} }
rev = (int)reader["Revision"]; else
{
_Log.Info("[REGION DB]: No terrain found for region");
return null;
}
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
} }
else
{
_Log.Info("[REGION DB]: No terrain found for region");
return null;
}
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
} }
} }
return terrain; return terrData;
} }
// Legacy entry point for when terrain was always a 256x256 heightmap // Legacy entry point for when terrain was always a 256x256 heightmap

View File

@ -870,11 +870,16 @@ namespace OpenSim.Data.SQLite
/// <returns>Heightfield data</returns> /// <returns>Heightfield data</returns>
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{ {
TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
return terrData.GetDoubles();
}
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
TerrainData terrData = null;
lock (ds) lock (ds)
{ {
double[,] terret = new double[(int)Constants.RegionSize, (int)Constants.RegionSize];
terret.Initialize();
String sql = "select RegionUUID, Revision, Heightfield from terrain" + String sql = "select RegionUUID, Revision, Heightfield from terrain" +
" where RegionUUID=:RegionUUID order by Revision desc"; " where RegionUUID=:RegionUUID order by Revision desc";
@ -887,21 +892,9 @@ namespace OpenSim.Data.SQLite
int rev = 0; int rev = 0;
if (row.Read()) if (row.Read())
{ {
// TODO: put this into a function
using (MemoryStream str = new MemoryStream((byte[])row["Heightfield"]))
{
using (BinaryReader br = new BinaryReader(str))
{
for (int x = 0; x < (int)Constants.RegionSize; x++)
{
for (int y = 0; y < (int)Constants.RegionSize; y++)
{
terret[x, y] = br.ReadDouble();
}
}
}
}
rev = Convert.ToInt32(row["Revision"]); rev = Convert.ToInt32(row["Revision"]);
byte[] blob = (byte[])row["Heightfield"];
terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
} }
else else
{ {
@ -912,8 +905,8 @@ namespace OpenSim.Data.SQLite
m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString()); m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString());
} }
} }
return terret;
} }
return terrData;
} }
public void RemoveLandObject(UUID globalID) public void RemoveLandObject(UUID globalID)

View File

@ -43,6 +43,9 @@ namespace OpenSim.Framework
public int SizeY { get; protected set; } public int SizeY { get; protected set; }
public int SizeZ { get; protected set; } public int SizeZ { get; protected set; }
// A height used when the user doesn't specify anything
public const float DefaultTerrainHeight = 21f;
public abstract float this[int x, int y] { get; set; } public abstract float this[int x, int y] { get; set; }
// Someday terrain will have caves // Someday terrain will have caves
public abstract float this[int x, int y, int z] { get; set; } public abstract float this[int x, int y, int z] { get; set; }
@ -51,15 +54,28 @@ namespace OpenSim.Framework
public abstract bool IsTaintedAt(int xx, int yy); public abstract bool IsTaintedAt(int xx, int yy);
public abstract void ClearTaint(); public abstract void ClearTaint();
public abstract void ClearLand();
public abstract void ClearLand(float height);
// Return a representation of this terrain for storing as a blob in the database. // Return a representation of this terrain for storing as a blob in the database.
// Returns 'true' to say blob was stored in the 'out' locations. // Returns 'true' to say blob was stored in the 'out' locations.
public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob); public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
// Given a revision code and a blob from the database, create and return the right type of TerrainData.
// The sizes passed are the expected size of the region. The database info will be used to
// initialize the heightmap of that sized region with as much data is in the blob.
// Return created TerrainData or 'null' if unsuccessful.
public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
{
// For the moment, there is only one implementation class
return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob);
}
// return a special compressed representation of the heightmap in shorts // return a special compressed representation of the heightmap in shorts
public abstract short[] GetCompressedMap(); public abstract short[] GetCompressedMap();
public abstract float CompressionFactor { get; } public abstract float CompressionFactor { get; }
public abstract void SetCompressedMap(short[] cmap, float pCompressionFactor);
public abstract double[,] GetDoubles();
public abstract TerrainData Clone(); public abstract TerrainData Clone();
} }
@ -76,9 +92,14 @@ namespace OpenSim.Framework
{ {
// Terrain is 'double[256,256]' // Terrain is 'double[256,256]'
Legacy256 = 11, Legacy256 = 11,
// Terrain is 'int32, int32, float[,]' where the shorts are X and Y dimensions // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions
// The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256. // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
Variable2D = 22, Variable2D = 22,
// Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions
// and third int is the 'compression factor'. The heights are compressed as
// "short compressedHeight = (short)(height * compressionFactor);"
// The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
Compressed2D = 27,
// A revision that is not listed above or any revision greater than this value is 'Legacy256'. // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
RevisionHigh = 1234 RevisionHigh = 1234
} }
@ -124,6 +145,20 @@ namespace OpenSim.Framework
m_taint[ii, jj] = false; m_taint[ii, jj] = false;
} }
// TerrainData.ClearLand
public override void ClearLand()
{
ClearLand(DefaultTerrainHeight);
}
// TerrainData.ClearLand(float)
public override void ClearLand(float pHeight)
{
short flatHeight = ToCompressedHeight(pHeight);
for (int xx = 0; xx < SizeX; xx++)
for (int yy = 0; yy < SizeY; yy++)
m_heightmap[xx, yy] = flatHeight;
}
public override bool IsTaintedAt(int xx, int yy) public override bool IsTaintedAt(int xx, int yy)
{ {
return m_taint[xx / Constants.TerrainPatchSize, yy / Constants.TerrainPatchSize]; return m_taint[xx / Constants.TerrainPatchSize, yy / Constants.TerrainPatchSize];
@ -134,7 +169,7 @@ namespace OpenSim.Framework
public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob) public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
{ {
DBRevisionCode = (int)DBTerrainRevision.Legacy256; DBRevisionCode = (int)DBTerrainRevision.Legacy256;
blob = LegacyTerrainSerialization(); blob = ToLegacyTerrainSerialization();
return false; return false;
} }
@ -155,17 +190,6 @@ namespace OpenSim.Framework
return newMap; return newMap;
} }
// TerrainData.SetCompressedMap
public override void SetCompressedMap(short[] cmap, float pCompressionFactor)
{
m_compressionFactor = pCompressionFactor;
int ind = 0;
for (int xx = 0; xx < SizeX; xx++)
for (int yy = 0; yy < SizeY; yy++)
m_heightmap[xx, yy] = cmap[ind++];
}
// TerrainData.Clone // TerrainData.Clone
public override TerrainData Clone() public override TerrainData Clone()
{ {
@ -174,6 +198,18 @@ namespace OpenSim.Framework
return ret; return ret;
} }
// TerrainData.GetDoubles
public override double[,] GetDoubles()
{
double[,] ret = new double[SizeX, SizeY];
for (int xx = 0; xx < SizeX; xx++)
for (int yy = 0; yy < SizeY; yy++)
ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]);
return ret;
}
// ============================================================= // =============================================================
private short[,] m_heightmap; private short[,] m_heightmap;
@ -230,31 +266,140 @@ namespace OpenSim.Framework
public HeightmapTerrainData(short[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ) public HeightmapTerrainData(short[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ)
{ {
SetCompressedMap(cmap, pCompressionFactor); m_compressionFactor = pCompressionFactor;
int ind = 0;
for (int xx = 0; xx < SizeX; xx++)
for (int yy = 0; yy < SizeY; yy++)
m_heightmap[xx, yy] = cmap[ind++];
} }
// Create a heighmap from a database blob
public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ)
{
switch ((DBTerrainRevision)pFormatCode)
{
case DBTerrainRevision.Compressed2D:
FromCompressedTerrainSerialization(pBlob);
break;
default:
FromLegacyTerrainSerialization(pBlob);
break;
}
}
// Just create an array of doubles. Presumes the caller implicitly knows the size. // Just create an array of doubles. Presumes the caller implicitly knows the size.
public Array LegacyTerrainSerialization() public Array ToLegacyTerrainSerialization()
{ {
Array ret = null; Array ret = null;
using (MemoryStream str = new MemoryStream(SizeX * SizeY * sizeof(double)))
using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double)))
{ {
using (BinaryWriter bw = new BinaryWriter(str)) using (BinaryWriter bw = new BinaryWriter(str))
{ {
// TODO: COMPATIBILITY - Add byte-order conversions for (int xx = 0; xx < Constants.RegionSize; xx++)
for (int ii = 0; ii < SizeX; ii++)
for (int jj = 0; jj < SizeY; jj++)
{ {
double height = this[ii, jj]; for (int yy = 0; yy < Constants.RegionSize; yy++)
if (height == 0.0) {
height = double.Epsilon; double height = this[xx, yy];
bw.Write(height); if (height == 0.0)
height = double.Epsilon;
bw.Write(height);
}
} }
} }
ret = str.ToArray(); ret = str.ToArray();
} }
return ret; return ret;
} }
// Just create an array of doubles. Presumes the caller implicitly knows the size.
public void FromLegacyTerrainSerialization(byte[] pBlob)
{
// In case database info doesn't match real terrain size, initialize the whole terrain.
ClearLand();
using (MemoryStream mstr = new MemoryStream(pBlob))
{
using (BinaryReader br = new BinaryReader(mstr))
{
for (int xx = 0; xx < (int)Constants.RegionSize; xx++)
{
for (int yy = 0; yy < (int)Constants.RegionSize; yy++)
{
float val = (float)br.ReadDouble();
if (xx < SizeX && yy < SizeY)
m_heightmap[xx, yy] = ToCompressedHeight(val);
}
}
}
ClearTaint();
m_log.InfoFormat("{0} Loaded legacy heightmap. SizeX={1}, SizeY={2}", LogHeader, SizeX, SizeY);
}
}
// See the reader below.
public Array ToCompressedTerrainSerialization()
{
Array ret = null;
using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16))))
{
using (BinaryWriter bw = new BinaryWriter(str))
{
bw.Write((Int32)DBTerrainRevision.Compressed2D);
bw.Write((Int32)SizeX);
bw.Write((Int32)SizeY);
bw.Write((Int32)CompressionFactor);
for (int yy = 0; yy < SizeY; yy++)
for (int xx = 0; xx < SizeX; xx++)
{
bw.Write((Int16)m_heightmap[xx, yy]);
}
}
ret = str.ToArray();
}
return ret;
}
// Initialize heightmap from blob consisting of:
// int32, int32, int32, int32, int16[]
// where the first int32 is format code, next two int32s are the X and y of heightmap data and
// the forth int is the compression factor for the following int16s
// This is just sets heightmap info. The actual size of the region was set on this instance's
// creation and any heights not initialized by theis blob are set to the default height.
public void FromCompressedTerrainSerialization(byte[] pBlob)
{
Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor;
using (MemoryStream mstr = new MemoryStream(pBlob))
{
using (BinaryReader br = new BinaryReader(mstr))
{
hmFormatCode = br.ReadInt32();
hmSizeX = br.ReadInt32();
hmSizeY = br.ReadInt32();
hmCompressionFactor = br.ReadInt32();
m_compressionFactor = hmCompressionFactor;
// In case database info doesn't match real terrain size, initialize the whole terrain.
ClearLand();
for (int yy = 0; yy < hmSizeY; yy++)
{
for (int xx = 0; xx < hmSizeX; xx++)
{
Int16 val = br.ReadInt16();
if (xx < SizeX && yy < SizeY)
m_heightmap[xx, yy] = ToCompressedHeight(val);
}
}
}
ClearTaint();
m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size={<{3},{4}>. CompFact={5}", LogHeader,
hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor);
}
}
} }
} }

View File

@ -68,13 +68,22 @@ namespace OpenSim.Region.Framework.Interfaces
/// </summary> /// </summary>
/// <param name="ter">HeightField data</param> /// <param name="ter">HeightField data</param>
/// <param name="regionID">region UUID</param> /// <param name="regionID">region UUID</param>
void StoreTerrain(TerrainData terrain, UUID regionID);
// Legacy version kept for downward compabibility
void StoreTerrain(double[,] terrain, UUID regionID); void StoreTerrain(double[,] terrain, UUID regionID);
/// <summary> /// <summary>
/// Load the latest terrain revision from region storage /// Load the latest terrain revision from region storage
/// </summary> /// </summary>
/// <param name="regionID">the region UUID</param> /// <param name="regionID">the region UUID</param>
/// <param name="sizeX">the X dimension of the region being filled</param>
/// <param name="sizeY">the Y dimension of the region being filled</param>
/// <param name="sizeZ">the Z dimension of the region being filled</param>
/// <returns>Heightfield data</returns> /// <returns>Heightfield data</returns>
TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ);
// Legacy version kept for downward compabibility
double[,] LoadTerrain(UUID regionID); double[,] LoadTerrain(UUID regionID);
void StoreLandObject(ILandObject Parcel); void StoreLandObject(ILandObject Parcel);

View File

@ -79,13 +79,22 @@ namespace OpenSim.Region.Framework.Interfaces
/// </summary> /// </summary>
/// <param name="ter">HeightField data</param> /// <param name="ter">HeightField data</param>
/// <param name="regionID">region UUID</param> /// <param name="regionID">region UUID</param>
void StoreTerrain(TerrainData terrain, UUID regionID);
// Legacy version kept for downward compabibility
void StoreTerrain(double[,] terrain, UUID regionID); void StoreTerrain(double[,] terrain, UUID regionID);
/// <summary> /// <summary>
/// Load the latest terrain revision from region storage /// Load the latest terrain revision from region storage
/// </summary> /// </summary>
/// <param name="regionID">the region UUID</param> /// <param name="regionID">the region UUID</param>
/// <param name="pSizeX">the X dimension of the terrain being filled</param>
/// <param name="pSizeY">the Y dimension of the terrain being filled</param>
/// <param name="pSizeZ">the Z dimension of the terrain being filled</param>
/// <returns>Heightfield data</returns> /// <returns>Heightfield data</returns>
TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ);
// Legacy version kept for downward compabibility
double[,] LoadTerrain(UUID regionID); double[,] LoadTerrain(UUID regionID);
void StoreLandObject(ILandObject Parcel); void StoreLandObject(ILandObject Parcel);

View File

@ -1894,7 +1894,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
try try
{ {
double[,] map = SimulationDataService.LoadTerrain(RegionInfo.RegionID); TerrainData map = SimulationDataService.LoadTerrain(RegionInfo.RegionID, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
if (map == null) if (map == null)
{ {
// This should be in the Terrain module, but it isn't because // This should be in the Terrain module, but it isn't because
@ -1911,7 +1911,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
else else
{ {
Heightmap = new TerrainChannel(map, RegionInfo.RegionSizeZ); Heightmap = new TerrainChannel(map);
} }
} }
catch (IOException e) catch (IOException e)

View File

@ -80,9 +80,26 @@ namespace OpenSim.Region.Framework.Scenes
PinHeadIsland(); PinHeadIsland();
} }
public TerrainChannel(double[,] pM, uint pAltitude) // Create channel passed a heightmap and expected dimensions of the region.
// The heightmap might not fit the passed size so accomodations must be made.
public TerrainChannel(double[,] pM, int pSizeX, int pSizeY, int pAltitude)
{ {
m_terrainData = new HeightmapTerrainData(pM); int hmSizeX = pM.GetLength(0);
int hmSizeY = pM.GetLength(1);
m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
for (int xx = 0; xx < pSizeX; xx++)
for (int yy = 0; yy < pSizeY; yy++)
if (xx > hmSizeX || yy > hmSizeY)
m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
else
m_terrainData[xx, yy] = (float)pM[xx, yy];
}
public TerrainChannel(TerrainData pTerrData)
{
m_terrainData = pTerrData;
} }
#region ITerrainChannel Members #region ITerrainChannel Members
@ -247,7 +264,7 @@ namespace OpenSim.Region.Framework.Scenes
byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
int index = 0; int index = 0;
m_terrainData = new HeightmapTerrainData(Width, Height, Altitude); m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
for (int y = 0; y < Height; y++) for (int y = 0; y < Height; y++)
{ {
@ -317,9 +334,7 @@ namespace OpenSim.Region.Framework.Scenes
private void FlatLand() private void FlatLand()
{ {
for (int xx = 0; xx < Width; xx++) m_terrainData.ClearLand();
for (int yy = 0; yy < Height; yy++)
m_terrainData[xx, yy] = 21;
} }
} }
} }

View File

@ -100,6 +100,11 @@ namespace OpenSim.Services.Connectors
return m_database.LoadObjects(regionUUID); return m_database.LoadObjects(regionUUID);
} }
public void StoreTerrain(TerrainData terrain, UUID regionID)
{
m_database.StoreTerrain(terrain, regionID);
}
public void StoreTerrain(double[,] terrain, UUID regionID) public void StoreTerrain(double[,] terrain, UUID regionID)
{ {
m_database.StoreTerrain(terrain, regionID); m_database.StoreTerrain(terrain, regionID);
@ -110,6 +115,11 @@ namespace OpenSim.Services.Connectors
return m_database.LoadTerrain(regionID); return m_database.LoadTerrain(regionID);
} }
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
return m_database.LoadTerrain(regionID, pSizeX, pSizeY, pSizeZ);
}
public void StoreLandObject(ILandObject Parcel) public void StoreLandObject(ILandObject Parcel)
{ {
m_database.StoreLandObject(Parcel); m_database.StoreLandObject(Parcel);

View File

@ -69,11 +69,21 @@ namespace OpenSim.Data.Null
m_store.StoreTerrain(terrain, regionID); m_store.StoreTerrain(terrain, regionID);
} }
public void StoreTerrain(TerrainData terrain, UUID regionID)
{
m_store.StoreTerrain(terrain, regionID);
}
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{ {
return m_store.LoadTerrain(regionID); return m_store.LoadTerrain(regionID);
} }
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
return m_store.LoadTerrain(regionID, pSizeX, pSizeY, pSizeZ);
}
public void StoreLandObject(ILandObject Parcel) public void StoreLandObject(ILandObject Parcel)
{ {
m_store.StoreLandObject(Parcel); m_store.StoreLandObject(Parcel);
@ -154,7 +164,7 @@ namespace OpenSim.Data.Null
protected Dictionary<UUID, SceneObjectPart> m_sceneObjectParts = new Dictionary<UUID, SceneObjectPart>(); protected Dictionary<UUID, SceneObjectPart> m_sceneObjectParts = new Dictionary<UUID, SceneObjectPart>();
protected Dictionary<UUID, ICollection<TaskInventoryItem>> m_primItems protected Dictionary<UUID, ICollection<TaskInventoryItem>> m_primItems
= new Dictionary<UUID, ICollection<TaskInventoryItem>>(); = new Dictionary<UUID, ICollection<TaskInventoryItem>>();
protected Dictionary<UUID, double[,]> m_terrains = new Dictionary<UUID, double[,]>(); protected Dictionary<UUID, TerrainData> m_terrains = new Dictionary<UUID, TerrainData>();
protected Dictionary<UUID, LandData> m_landData = new Dictionary<UUID, LandData>(); protected Dictionary<UUID, LandData> m_landData = new Dictionary<UUID, LandData>();
public void Initialise(string dbfile) public void Initialise(string dbfile)
@ -299,15 +309,28 @@ namespace OpenSim.Data.Null
return new List<SceneObjectGroup>(objects.Values); return new List<SceneObjectGroup>(objects.Values);
} }
public void StoreTerrain(double[,] ter, UUID regionID) public void StoreTerrain(TerrainData ter, UUID regionID)
{ {
m_terrains[regionID] = ter; m_terrains[regionID] = ter;
} }
public void StoreTerrain(double[,] ter, UUID regionID)
{
m_terrains[regionID] = new HeightmapTerrainData(ter);
}
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
if (m_terrains.ContainsKey(regionID))
return m_terrains[regionID];
else
return null;
}
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{ {
if (m_terrains.ContainsKey(regionID)) if (m_terrains.ContainsKey(regionID))
return m_terrains[regionID]; return m_terrains[regionID].GetDoubles();
else else
return null; return null;
} }