Merge branch 'mbworkvar2' into ubitvar

avinationmerge
UbitUmarov 2015-08-19 08:48:50 +01:00
commit 0b105da626
76 changed files with 3561 additions and 1898 deletions

View File

@ -1157,7 +1157,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
// Set home position // Set home position
GridRegion home = scene.GridService.GetRegionByPosition(scopeID, GridRegion home = scene.GridService.GetRegionByPosition(scopeID,
(int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation));
if (null == home) if (null == home)
{ {
m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", firstName, lastName); m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", firstName, lastName);
@ -1387,7 +1387,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
if ((null != regionXLocation) && (null != regionYLocation)) if ((null != regionXLocation) && (null != regionYLocation))
{ {
GridRegion home = scene.GridService.GetRegionByPosition(scopeID, GridRegion home = scene.GridService.GetRegionByPosition(scopeID,
(int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); (int)Util.RegionToWorldLoc((uint)regionXLocation), (int)Util.RegionToWorldLoc((uint)regionYLocation));
if (null == home) { if (null == home) {
m_log.WarnFormat("[RADMIN]: Unable to set home region for updated user account {0} {1}", firstName, lastName); m_log.WarnFormat("[RADMIN]: Unable to set home region for updated user account {0} {1}", firstName, lastName);
} else { } else {
@ -3118,7 +3118,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
// Set home position // Set home position
GridRegion home = scene.GridService.GetRegionByPosition(scopeID, GridRegion home = scene.GridService.GetRegionByPosition(scopeID,
(int)(regionXLocation * Constants.RegionSize), (int)(regionYLocation * Constants.RegionSize)); (int)Util.RegionToWorldLoc(regionXLocation), (int)Util.RegionToWorldLoc(regionYLocation));
if (null == home) { if (null == home) {
m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", names[0], names[1]); m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", names[0], names[1]);
} else { } else {

View File

@ -52,14 +52,14 @@ namespace OpenSim.Data
public int sizeY; public int sizeY;
/// <summary> /// <summary>
/// Return the x-coordinate of this region. /// Return the x-coordinate of this region in region units.
/// </summary> /// </summary>
public int coordX { get { return posX / (int)Constants.RegionSize; } } public int coordX { get { return (int)Util.WorldToRegionLoc((uint)posX); } }
/// <summary> /// <summary>
/// Return the y-coordinate of this region. /// Return the y-coordinate of this region in region units.
/// </summary> /// </summary>
public int coordY { get { return posY / (int)Constants.RegionSize; } } public int coordY { get { return (int)Util.WorldToRegionLoc((uint)posY); } }
public Dictionary<string, object> Data; public Dictionary<string, object> Data;
} }

View File

@ -530,43 +530,52 @@ 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]; double[,] ret = null;
terrain.Initialize(); TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
if (terrData != null)
ret = terrData.GetDoubles();
return ret;
}
// Returns 'null' if region not found
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"]); if (reader.Read())
BinaryReader br = new BinaryReader(str);
for (int x = 0; x < (int)Constants.RegionSize; x++)
{ {
for (int y = 0; y < (int)Constants.RegionSize; y++) int 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");
} }
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
public void StoreTerrain(double[,] ter, UUID regionID)
{
StoreTerrain(new HeightmapTerrainData(ter), regionID);
} }
/// <summary> /// <summary>
@ -574,10 +583,8 @@ ELSE
/// </summary> /// </summary>
/// <param name="terrain">terrain map data.</param> /// <param name="terrain">terrain map data.</param>
/// <param name="regionID">regionID.</param> /// <param name="regionID">regionID.</param>
public void StoreTerrain(double[,] terrain, UUID regionID) public void StoreTerrain(TerrainData terrData, UUID regionID)
{ {
int revision = Util.UnixTimeSinceEpoch();
//Delete old terrain map //Delete old terrain map
string sql = "delete from terrain where RegionUUID=@RegionUUID"; string sql = "delete from terrain where RegionUUID=@RegionUUID";
using (SqlConnection conn = new SqlConnection(m_connectionString)) using (SqlConnection conn = new SqlConnection(m_connectionString))
@ -590,17 +597,23 @@ ELSE
sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)"; sql = "insert into terrain(RegionUUID, Revision, Heightfield) values(@RegionUUID, @Revision, @Heightfield)";
int terrainDBRevision;
Array 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", revision)); {
cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", serializeTerrain(terrain))); 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.Info("[REGION DB]: Stored terrain revision r " + revision); _Log.Info("[REGION DB]: Stored terrain");
} }
/// <summary> /// <summary>
@ -1344,6 +1357,7 @@ VALUES
#region Private Methods #region Private Methods
/*
/// <summary> /// <summary>
/// Serializes the terrain data for storage in DB. /// Serializes the terrain data for storage in DB.
/// </summary> /// </summary>
@ -1367,6 +1381,7 @@ VALUES
return str.ToArray(); return str.ToArray();
} }
*/
/// <summary> /// <summary>
/// Stores new regionsettings. /// Stores new regionsettings.

View File

@ -48,8 +48,18 @@ namespace OpenSim.Data.MySQL
public class MySQLSimulationData : ISimulationDataStore public class MySQLSimulationData : ISimulationDataStore
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[REGION DB MYSQL]";
private string m_connectionString; private string m_connectionString;
/// <summary>
/// This lock was being used to serialize database operations when the connection was shared, but this has
/// been unnecessary for a long time after we switched to using MySQL's underlying connection pooling instead.
/// FIXME: However, the locks remain in many places since they are effectively providing a level of
/// transactionality. This should be replaced by more efficient database transactions which would not require
/// unrelated operations to block each other or unrelated operations on the same tables from blocking each
/// other.
/// </summary>
private object m_dbLock = new object(); private object m_dbLock = new object();
protected virtual Assembly Assembly protected virtual Assembly Assembly
@ -91,7 +101,7 @@ namespace OpenSim.Data.MySQL
} }
catch (Exception e) catch (Exception e)
{ {
m_log.Error("[REGION DB]: MySQL error in ExecuteReader: " + e.Message); m_log.ErrorFormat("{0} MySQL error in ExecuteReader: {1}", LogHeader, e);
throw; throw;
} }
@ -574,12 +584,16 @@ namespace OpenSim.Data.MySQL
} }
} }
public virtual void StoreTerrain(double[,] ter, UUID regionID) // Legacy entry point for when terrain was always a 256x256 hieghtmap
public void StoreTerrain(double[,] ter, UUID regionID)
{
StoreTerrain(new HeightmapTerrainData(ter), regionID);
}
public void StoreTerrain(TerrainData terrData, UUID regionID)
{ {
Util.FireAndForget(delegate(object x) Util.FireAndForget(delegate(object x)
{ {
double[,] oldTerrain = LoadTerrain(regionID);
m_log.Info("[REGION DB]: Storing terrain"); m_log.Info("[REGION DB]: Storing terrain");
lock (m_dbLock) lock (m_dbLock)
@ -601,8 +615,12 @@ namespace OpenSim.Data.MySQL
"Revision, Heightfield) values (?RegionUUID, " + "Revision, Heightfield) values (?RegionUUID, " +
"1, ?Heightfield)"; "1, ?Heightfield)";
cmd2.Parameters.AddWithValue("RegionUUID", regionID.ToString()); int terrainDBRevision;
cmd2.Parameters.AddWithValue("Heightfield", SerializeTerrain(ter, oldTerrain)); Array terrainDBblob;
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
cmd2.Parameters.AddWithValue("Revision", terrainDBRevision);
cmd2.Parameters.AddWithValue("Heightfield", terrainDBblob);
ExecuteNonQuery(cmd); ExecuteNonQuery(cmd);
ExecuteNonQuery(cmd2); ExecuteNonQuery(cmd2);
@ -618,9 +636,20 @@ namespace OpenSim.Data.MySQL
}); });
} }
// Legacy region loading
public virtual double[,] LoadTerrain(UUID regionID) public virtual double[,] LoadTerrain(UUID regionID)
{ {
double[,] terrain = null; double[,] ret = null;
TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
if (terrData != null)
ret = terrData.GetDoubles();
return ret;
}
// Returns 'null' if region not found
public TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ)
{
TerrainData terrData = null;
lock (m_dbLock) lock (m_dbLock)
{ {
@ -640,32 +669,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 virtual void RemoveLandObject(UUID globalID) public virtual void RemoveLandObject(UUID globalID)

View File

@ -132,15 +132,33 @@ 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.
// Returns 'null' if region not found
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

@ -46,6 +46,7 @@ namespace OpenSim.Data.PGSQL
public class PGSQLSimulationData : ISimulationDataStore public class PGSQLSimulationData : ISimulationDataStore
{ {
private const string _migrationStore = "RegionStore"; private const string _migrationStore = "RegionStore";
private const string LogHeader = "[REGION DB PGSQL]";
// private static FileSystemDataStore Instance = new FileSystemDataStore(); // private static FileSystemDataStore Instance = new FileSystemDataStore();
private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@ -523,8 +524,17 @@ 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]; double[,] ret = null;
terrain.Initialize(); TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
if (terrData != null)
ret = terrData.GetDoubles();
return ret;
}
// Returns 'null' if region not found
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; ";
@ -540,16 +550,9 @@ namespace OpenSim.Data.PGSQL
int rev; int rev;
if (reader.Read()) if (reader.Read())
{ {
MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]); rev = Convert.ToInt32(reader["Revision"]);
BinaryReader br = new BinaryReader(str); byte[] blob = (byte[])reader["Heightfield"];
for (int x = 0; x < (int)Constants.RegionSize; x++) terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
{
for (int y = 0; y < (int)Constants.RegionSize; y++)
{
terrain[x, y] = br.ReadDouble();
}
}
rev = (int)reader["Revision"];
} }
else else
{ {
@ -560,7 +563,13 @@ namespace OpenSim.Data.PGSQL
} }
} }
return terrain; return terrData;
}
// Legacy entry point for when terrain was always a 256x256 heightmap
public void StoreTerrain(double[,] terrain, UUID regionID)
{
StoreTerrain(new HeightmapTerrainData(terrain), regionID);
} }
/// <summary> /// <summary>
@ -568,35 +577,38 @@ namespace OpenSim.Data.PGSQL
/// </summary> /// </summary>
/// <param name="terrain">terrain map data.</param> /// <param name="terrain">terrain map data.</param>
/// <param name="regionID">regionID.</param> /// <param name="regionID">regionID.</param>
public void StoreTerrain(double[,] terrain, UUID regionID) public void StoreTerrain(TerrainData terrData, UUID regionID)
{ {
int revision = Util.UnixTimeSinceEpoch();
//Delete old terrain map //Delete old terrain map
string sql = @"delete from terrain where ""RegionUUID""=:RegionUUID"; string sql = @"delete from terrain where ""RegionUUID""=:RegionUUID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{ {
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID)); using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
conn.Open(); {
cmd.ExecuteNonQuery(); cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
conn.Open();
cmd.ExecuteNonQuery();
}
} }
int terrainDBRevision;
_Log.Info("[REGION DB]: Deleted terrain revision r " + revision); Array terrainDBblob;
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
sql = @"insert into terrain(""RegionUUID"", ""Revision"", ""Heightfield"") values(:RegionUUID, :Revision, :Heightfield)"; sql = @"insert into terrain(""RegionUUID"", ""Revision"", ""Heightfield"") values(:RegionUUID, :Revision, :Heightfield)";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString)) using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{ {
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID)); using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
cmd.Parameters.Add(_Database.CreateParameter("Revision", revision)); {
cmd.Parameters.Add(_Database.CreateParameter("Heightfield", serializeTerrain(terrain))); 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.Info("[REGION DB]: Stored terrain revision r " + revision); _Log.Info("[REGION DB]: Stored terrain revision r " + terrainDBRevision);
} }
/// <summary> /// <summary>
@ -1349,6 +1361,7 @@ namespace OpenSim.Data.PGSQL
#region Private Methods #region Private Methods
/*
/// <summary> /// <summary>
/// Serializes the terrain data for storage in DB. /// Serializes the terrain data for storage in DB.
/// </summary> /// </summary>
@ -1372,6 +1385,7 @@ namespace OpenSim.Data.PGSQL
return str.ToArray(); return str.ToArray();
} }
*/
/// <summary> /// <summary>
/// Stores new regionsettings. /// Stores new regionsettings.

View File

@ -51,6 +51,7 @@ namespace OpenSim.Data.SQLite
public class SQLiteSimulationData : ISimulationDataStore public class SQLiteSimulationData : ISimulationDataStore
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[REGION DB SQLLITE]";
private const string primSelect = "select * from prims"; private const string primSelect = "select * from prims";
private const string shapeSelect = "select * from primshapes"; private const string shapeSelect = "select * from primshapes";
@ -819,12 +820,18 @@ namespace OpenSim.Data.SQLite
prim.Inventory.RestoreInventoryItems(inventory); prim.Inventory.RestoreInventoryItems(inventory);
} }
// Legacy entry point for when terrain was always a 256x256 hieghtmap
public void StoreTerrain(double[,] ter, UUID regionID)
{
StoreTerrain(new HeightmapTerrainData(ter), regionID);
}
/// <summary> /// <summary>
/// Store a terrain revision in region storage /// Store a terrain revision in region storage
/// </summary> /// </summary>
/// <param name="ter">terrain heightfield</param> /// <param name="ter">terrain heightfield</param>
/// <param name="regionID">region UUID</param> /// <param name="regionID">region UUID</param>
public void StoreTerrain(double[,] ter, UUID regionID) public void StoreTerrain(TerrainData terrData, UUID regionID)
{ {
lock (ds) lock (ds)
{ {
@ -853,11 +860,17 @@ namespace OpenSim.Data.SQLite
String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" + String sql = "insert into terrain(RegionUUID, Revision, Heightfield)" +
" values(:RegionUUID, :Revision, :Heightfield)"; " values(:RegionUUID, :Revision, :Heightfield)";
int terrainDBRevision;
Array terrainDBblob;
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
m_log.DebugFormat("{0} Storing terrain revision r {1}", LogHeader, terrainDBRevision);
using (SqliteCommand cmd = new SqliteCommand(sql, m_conn)) using (SqliteCommand cmd = new SqliteCommand(sql, m_conn))
{ {
cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString())); cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString()));
cmd.Parameters.Add(new SqliteParameter(":Revision", revision)); cmd.Parameters.Add(new SqliteParameter(":Revision", terrainDBRevision));
cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter))); cmd.Parameters.Add(new SqliteParameter(":Heightfield", terrainDBblob));
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
} }
@ -870,11 +883,20 @@ namespace OpenSim.Data.SQLite
/// <returns>Heightfield data</returns> /// <returns>Heightfield data</returns>
public double[,] LoadTerrain(UUID regionID) public double[,] LoadTerrain(UUID regionID)
{ {
double[,] ret = null;
TerrainData terrData = LoadTerrain(regionID, (int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
if (terrData != null)
ret = terrData.GetDoubles();
return ret;
}
// Returns 'null' if region not found
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 +909,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 +922,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)
@ -2016,6 +2026,7 @@ namespace OpenSim.Data.SQLite
return entry; return entry;
} }
/*
/// <summary> /// <summary>
/// ///
/// </summary> /// </summary>
@ -2033,6 +2044,7 @@ namespace OpenSim.Data.SQLite
return str.ToArray(); return str.ToArray();
} }
*/
// private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val) // private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val)
// { // {

View File

@ -27,6 +27,7 @@
using System; using System;
using OpenMetaverse; using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenSim.Framework namespace OpenSim.Framework
{ {
@ -40,9 +41,26 @@ namespace OpenSim.Framework
public byte WaterHeight; public byte WaterHeight;
public ushort X; public ushort X;
public ushort Y; public ushort Y;
public ushort SizeX;
public ushort SizeY;
public MapBlockData() public MapBlockData()
{ {
} }
public OSDMap ToOSD()
{
OSDMap map = new OSDMap();
map["X"] = X;
map["Y"] = Y;
map["SizeX"] = SizeX;
map["SizeY"] = SizeY;
map["Name"] = Name;
map["Access"] = Access;
map["RegionFlags"] = RegionFlags;
map["WaterHeight"] = WaterHeight;
map["MapImageID"] = MapImageId;
return map;
}
} }
} }

View File

@ -149,11 +149,32 @@ namespace OpenSim.Framework
public uint WorldLocX = 0; public uint WorldLocX = 0;
public uint WorldLocY = 0; public uint WorldLocY = 0;
public uint WorldLocZ = 0; public uint WorldLocZ = 0;
/// <summary>
/// X dimension of the region.
/// </summary>
/// <remarks>
/// If this is a varregion then the default size set here will be replaced when we load the region config.
/// </remarks>
public uint RegionSizeX = Constants.RegionSize; public uint RegionSizeX = Constants.RegionSize;
/// <summary>
/// X dimension of the region.
/// </summary>
/// <remarks>
/// If this is a varregion then the default size set here will be replaced when we load the region config.
/// </remarks>
public uint RegionSizeY = Constants.RegionSize; public uint RegionSizeY = Constants.RegionSize;
/// <summary>
/// Z dimension of the region.
/// </summary>
/// <remarks>
/// XXX: Unknown if this accounts for regions with negative Z.
/// </remarks>
public uint RegionSizeZ = Constants.RegionHeight; public uint RegionSizeZ = Constants.RegionHeight;
private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>(); private Dictionary<String, String> m_extraSettings = new Dictionary<string, string>();
// Apparently, we're applying the same estatesettings regardless of whether it's local or remote. // Apparently, we're applying the same estatesettings regardless of whether it's local or remote.
@ -506,16 +527,16 @@ namespace OpenSim.Framework
{ {
string val; string val;
string keylower = key.ToLower(); string keylower = key.ToLower();
if (m_otherSettings.TryGetValue(keylower, out val)) if (m_extraSettings.TryGetValue(keylower, out val))
return val; return val;
m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key); m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key);
return null; return null;
} }
public void SetOtherSetting(string key, string value) public void SetExtraSetting(string key, string value)
{ {
string keylower = key.ToLower(); string keylower = key.ToLower();
m_otherSettings[keylower] = value; m_extraSettings[keylower] = value;
} }
private void ReadNiniConfig(IConfigSource source, string name) private void ReadNiniConfig(IConfigSource source, string name)
@ -733,7 +754,7 @@ namespace OpenSim.Framework
foreach (String s in allKeys) foreach (String s in allKeys)
{ {
SetOtherSetting(s, config.GetString(s)); SetExtraSetting(s, config.GetString(s));
} }
} }
@ -804,6 +825,7 @@ namespace OpenSim.Framework
if (DataStore != String.Empty) if (DataStore != String.Empty)
config.Set("Datastore", DataStore); config.Set("Datastore", DataStore);
if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize) if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize)
{ {
config.Set("SizeX", RegionSizeX); config.Set("SizeX", RegionSizeX);

View File

@ -0,0 +1,464 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using OpenMetaverse;
using log4net;
namespace OpenSim.Framework
{
public abstract class TerrainData
{
// Terrain always is a square
public int SizeX { get; protected set; }
public int SizeY { 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; }
// Someday terrain will have caves
public abstract float this[int x, int y, int z] { get; set; }
public abstract bool IsTaintedAt(int xx, int yy);
public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest);
public abstract void TaintAllTerrain();
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.
// Returns 'true' to say blob was stored in the 'out' locations.
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 ints
public abstract int[] GetCompressedMap();
public abstract float CompressionFactor { get; }
public abstract float[] GetFloatsSerialized();
public abstract double[,] GetDoubles();
public abstract TerrainData Clone();
}
// The terrain is stored in the database as a blob with a 'revision' field.
// Some implementations of terrain storage would fill the revision field with
// the time the terrain was stored. When real revisions were added and this
// feature removed, that left some old entries with the time in the revision
// field.
// Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
// left over and it is presumed to be 'Legacy256'.
// Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
// If a revision does not match any of these, it is assumed to be Legacy256.
public enum DBTerrainRevision
{
// Terrain is 'double[256,256]'
Legacy256 = 11,
// 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.
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
// "int compressedHeight = (int)(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'.
RevisionHigh = 1234
}
// Version of terrain that is a heightmap.
// This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
// of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
// The heighmap is kept as an array of integers. The integer values are converted to
// and from floats by TerrainCompressionFactor.
public class HeightmapTerrainData : TerrainData
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[HEIGHTMAP TERRAIN DATA]";
// TerrainData.this[x, y]
public override float this[int x, int y]
{
get { return FromCompressedHeight(m_heightmap[x, y]); }
set {
int newVal = ToCompressedHeight(value);
if (m_heightmap[x, y] != newVal)
{
m_heightmap[x, y] = newVal;
m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
}
}
}
// TerrainData.this[x, y, z]
public override float this[int x, int y, int z]
{
get { return this[x, y]; }
set { this[x, y] = value; }
}
// TerrainData.ClearTaint
public override void ClearTaint()
{
SetAllTaint(false);
}
// TerrainData.TaintAllTerrain
public override void TaintAllTerrain()
{
SetAllTaint(true);
}
private void SetAllTaint(bool setting)
{
for (int ii = 0; ii < m_taint.GetLength(0); ii++)
for (int jj = 0; jj < m_taint.GetLength(1); jj++)
m_taint[ii, jj] = setting;
}
// TerrainData.ClearLand
public override void ClearLand()
{
ClearLand(DefaultTerrainHeight);
}
// TerrainData.ClearLand(float)
public override void ClearLand(float pHeight)
{
int flatHeight = ToCompressedHeight(pHeight);
for (int xx = 0; xx < SizeX; xx++)
for (int yy = 0; yy < SizeY; yy++)
m_heightmap[xx, yy] = flatHeight;
}
// Return 'true' of the patch that contains these region coordinates has been modified.
// Note that checking the taint clears it.
// There is existing code that relies on this feature.
public override bool IsTaintedAt(int xx, int yy, bool clearOnTest)
{
int tx = xx / Constants.TerrainPatchSize;
int ty = yy / Constants.TerrainPatchSize;
bool ret = m_taint[tx, ty];
if (ret && clearOnTest)
m_taint[tx, ty] = false;
return ret;
}
// Old form that clears the taint flag when we check it.
public override bool IsTaintedAt(int xx, int yy)
{
return IsTaintedAt(xx, yy, true /* clearOnTest */);
}
// TerrainData.GetDatabaseBlob
// The user wants something to store in the database.
public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
{
bool ret = false;
if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize)
{
DBRevisionCode = (int)DBTerrainRevision.Legacy256;
blob = ToLegacyTerrainSerialization();
ret = true;
}
else
{
DBRevisionCode = (int)DBTerrainRevision.Compressed2D;
blob = ToCompressedTerrainSerialization();
ret = true;
}
return ret;
}
// TerrainData.CompressionFactor
private float m_compressionFactor = 100.0f;
public override float CompressionFactor { get { return m_compressionFactor; } }
// TerrainData.GetCompressedMap
public override int[] GetCompressedMap()
{
int[] newMap = new int[SizeX * SizeY];
int ind = 0;
for (int xx = 0; xx < SizeX; xx++)
for (int yy = 0; yy < SizeY; yy++)
newMap[ind++] = m_heightmap[xx, yy];
return newMap;
}
// TerrainData.Clone
public override TerrainData Clone()
{
HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ);
ret.m_heightmap = (int[,])this.m_heightmap.Clone();
return ret;
}
// TerrainData.GetFloatsSerialized
// This one dimensional version is ordered so height = map[y*sizeX+x];
// DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
// and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
public override float[] GetFloatsSerialized()
{
int points = SizeX * SizeY;
float[] heights = new float[points];
int idx = 0;
for (int jj = 0; jj < SizeY; jj++)
for (int ii = 0; ii < SizeX; ii++)
{
heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]);
}
return heights;
}
// 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 int[,] m_heightmap;
// Remember subregions of the heightmap that has changed.
private bool[,] m_taint;
// To save space (especially for large regions), keep the height as a short integer
// that is coded as the float height times the compression factor (usually '100'
// to make for two decimal points).
public int ToCompressedHeight(double pHeight)
{
return (int)(pHeight * CompressionFactor);
}
public float FromCompressedHeight(int pHeight)
{
return ((float)pHeight) / CompressionFactor;
}
// To keep with the legacy theme, create an instance of this class based on the
// way terrain used to be passed around.
public HeightmapTerrainData(double[,] pTerrain)
{
SizeX = pTerrain.GetLength(0);
SizeY = pTerrain.GetLength(1);
SizeZ = (int)Constants.RegionHeight;
m_compressionFactor = 100.0f;
m_heightmap = new int[SizeX, SizeY];
for (int ii = 0; ii < SizeX; ii++)
{
for (int jj = 0; jj < SizeY; jj++)
{
m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]);
}
}
// m_log.DebugFormat("{0} new by doubles. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
ClearTaint();
}
// Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
public HeightmapTerrainData(int pX, int pY, int pZ)
{
SizeX = pX;
SizeY = pY;
SizeZ = pZ;
m_compressionFactor = 100.0f;
m_heightmap = new int[SizeX, SizeY];
m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
// m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
ClearTaint();
ClearLand(0f);
}
public HeightmapTerrainData(int[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ)
{
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++];
// m_log.DebugFormat("{0} new by compressed map. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
}
// 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);
m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
break;
default:
FromLegacyTerrainSerialization(pBlob);
m_log.DebugFormat("{0} HeightmapTerrainData create from legacy serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
break;
}
}
// Just create an array of doubles. Presumes the caller implicitly knows the size.
public Array ToLegacyTerrainSerialization()
{
Array ret = null;
using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double)))
{
using (BinaryWriter bw = new BinaryWriter(str))
{
for (int xx = 0; xx < Constants.RegionSize; xx++)
{
for (int yy = 0; yy < Constants.RegionSize; yy++)
{
double height = this[xx, yy];
if (height == 0.0)
height = double.Epsilon;
bw.Write(height);
}
}
}
ret = str.ToArray();
}
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();
}
}
// 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] = 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

@ -161,14 +161,18 @@ namespace OpenSim.Framework
{ {
get get
{ {
return Utils.UIntsToLong( return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY));
m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize);
} }
set set
{ {
m_homeRegionX = (uint) (value >> 40); uint regionWorldLocX, regionWorldLocY;
m_homeRegionY = (((uint) (value)) >> 8); Util.RegionHandleToWorldLoc(value, out regionWorldLocX, out regionWorldLocY);
m_homeRegionX = Util.WorldToRegionLoc(regionWorldLocX);
m_homeRegionY = Util.WorldToRegionLoc(regionWorldLocY);
// m_homeRegionX = (uint) (value >> 40);
// m_homeRegionY = (((uint) (value)) >> 8);
} }
} }

View File

@ -59,6 +59,7 @@ namespace OpenSim.Region.ClientStack.Linden
public class EventQueueGetModule : IEventQueue, INonSharedRegionModule public class EventQueueGetModule : IEventQueue, INonSharedRegionModule
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[EVENT QUEUE GET MODULE]";
/// <value> /// <value>
/// Debug level. /// Debug level.
@ -479,7 +480,7 @@ namespace OpenSim.Region.ClientStack.Linden
public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY) public virtual void EnableSimulator(ulong handle, IPEndPoint endPoint, UUID avatarID, int regionSizeX, int regionSizeY)
{ {
m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>", m_log.DebugFormat("{0} EnableSimulator. handle={1}, avatarID={2}, regionSize={3},{4}>",
"[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); LogHeader, handle, avatarID, regionSizeX, regionSizeY);
OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY); OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
Enqueue(item, avatarID); Enqueue(item, avatarID);
@ -489,7 +490,7 @@ namespace OpenSim.Region.ClientStack.Linden
ulong regionHandle, int regionSizeX, int regionSizeY) ulong regionHandle, int regionSizeX, int regionSizeY)
{ {
m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>", m_log.DebugFormat("{0} EstablishAgentCommunication. handle={1}, avatarID={2}, regionSize={3},{4}>",
"[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); LogHeader, regionHandle, avatarID, regionSizeX, regionSizeY);
OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY); OSD item = EventQueueHelper.EstablishAgentCommunication(avatarID, endPoint.ToString(), capsPath, regionHandle, regionSizeX, regionSizeY);
Enqueue(item, avatarID); Enqueue(item, avatarID);
} }
@ -500,7 +501,7 @@ namespace OpenSim.Region.ClientStack.Linden
UUID avatarID, int regionSizeX, int regionSizeY) UUID avatarID, int regionSizeX, int regionSizeY)
{ {
m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>", m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>",
"[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY); LogHeader, regionHandle, avatarID, regionSizeX, regionSizeY);
OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint, OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY); locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
@ -512,7 +513,7 @@ namespace OpenSim.Region.ClientStack.Linden
string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY) string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
{ {
m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>", m_log.DebugFormat("{0} CrossRegion. handle={1}, avatarID={2}, regionSize={3},{4}>",
"[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY); LogHeader, handle, avatarID, regionSizeX, regionSizeY);
OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint, OSD item = EventQueueHelper.CrossRegion(handle, pos, lookAt, newRegionExternalEndPoint,
capsURL, avatarID, sessionID, regionSizeX, regionSizeY); capsURL, avatarID, sessionID, regionSizeX, regionSizeY);

View File

@ -312,6 +312,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f; private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[LLCLIENTVIEW]";
protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients protected static Dictionary<PacketType, PacketMethod> PacketHandlers = new Dictionary<PacketType, PacketMethod>(); //Global/static handlers for all clients
/// <summary> /// <summary>
@ -691,13 +692,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// </param> /// </param>
/// <returns>true if the handler was added. This is currently always the case.</returns> /// <returns>true if the handler was added. This is currently always the case.</returns>
public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync) public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync)
{
return AddLocalPacketHandler(packetType, handler, doAsync, false);
}
/// <summary>
/// Add a handler for the given packet type.
/// </summary>
/// <param name="packetType"></param>
/// <param name="handler"></param>
/// <param name="doAsync">
/// If true, when the packet is received handle it on a different thread. Whether this is given direct to
/// a threadpool thread or placed in a queue depends on the inEngine parameter.
/// </param>
/// <param name="inEngine">
/// If async is false then this parameter is ignored.
/// If async is true and inEngine is false, then the packet is sent directly to a
/// threadpool thread.
/// If async is true and inEngine is true, then the packet is sent to the IncomingPacketAsyncHandlingEngine.
/// This may result in slower handling but reduces the risk of overloading the simulator when there are many
/// simultaneous async requests.
/// </param>
/// <returns>true if the handler was added. This is currently always the case.</returns>
public bool AddLocalPacketHandler(PacketType packetType, PacketMethod handler, bool doAsync, bool inEngine)
{ {
bool result = false; bool result = false;
lock (m_packetHandlers) lock (m_packetHandlers)
{ {
if (!m_packetHandlers.ContainsKey(packetType)) if (!m_packetHandlers.ContainsKey(packetType))
{ {
m_packetHandlers.Add(packetType, new PacketProcessor() { method = handler, Async = doAsync }); m_packetHandlers.Add(
packetType, new PacketProcessor() { method = handler, Async = doAsync });
result = true; result = true;
} }
} }
@ -1176,11 +1201,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <summary> /// <summary>
/// Send the region heightmap to the client /// Send the region heightmap to the client
/// This method is only called when not doing intellegent terrain patch sending and
/// is only called when the scene presence is initially created and sends all of the
/// region's patches to the client.
/// </summary> /// </summary>
/// <param name="map">heightmap</param> /// <param name="map">heightmap</param>
public virtual void SendLayerData(float[] map) public virtual void SendLayerData(float[] map)
{ {
Util.FireAndForget(DoSendLayerData, map); Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData());
// Send it sync, and async. It's not that much data // Send it sync, and async. It's not that much data
// and it improves user experience just so much! // and it improves user experience just so much!
@ -1193,15 +1221,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
/// <param name="o"></param> /// <param name="o"></param>
private void DoSendLayerData(object o) private void DoSendLayerData(object o)
{ {
float[] map = LLHeightFieldMoronize((float[])o); TerrainData map = (TerrainData)o;
try try
{ {
// Send LayerData in typerwriter pattern
for (int y = 0; y < 16; y++) for (int y = 0; y < 16; y++)
{ {
for (int x = 0; x < 16; x+=4) for (int x = 0; x < 16; x++)
{ {
SendLayerPacket(x, y, map); SendLayerData(x, y, map);
} }
} }
} }
@ -1211,77 +1240,95 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
} }
/// <summary> // Legacy form of invocation that passes around a bare data array.
/// Sends a set of four patches (x, x+1, ..., x+3) to the client // Just ignore what was passed and use the real terrain info that is part of the scene.
/// </summary> // As a HORRIBLE kludge in an attempt to not change the definition of IClientAPI,
/// <param name="map">heightmap</param> // there is a special form for specifying multiple terrain patches to send.
/// <param name="px">X coordinate for patches 0..12</param> // The form is to pass 'px' as negative the number of patches to send and to
/// <param name="py">Y coordinate for patches 0..15</param> // pass the float array as pairs of patch X and Y coordinates. So, passing 'px'
private void SendLayerPacket(int x, int y, float[] map) // as -2 and map= [3, 5, 8, 4] would mean to send two terrain heightmap patches
// and the patches to send are <3,5> and <8,4>.
public void SendLayerData(int px, int py, float[] map)
{ {
int[] patches = new int[4]; if (px >= 0)
patches[0] = x + 0 + y * 16;
patches[1] = x + 1 + y * 16;
patches[2] = x + 2 + y * 16;
patches[3] = x + 3 + y * 16;
float[] heightmap = (map.Length == 65536) ?
map :
LLHeightFieldMoronize(map);
try
{ {
Packet layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); SendLayerData(px, py, m_scene.Heightmap.GetTerrainData());
OutPacket(layerpack, ThrottleOutPacketType.Land);
} }
catch else
{ {
for (int px = x ; px < x + 4 ; px++) int numPatches = -px;
SendLayerData(px, y, map); int[] xPatches = new int[numPatches];
int[] yPatches = new int[numPatches];
for (int pp = 0; pp < numPatches; pp++)
{
xPatches[pp] = (int)map[pp * 2];
yPatches[pp] = (int)map[pp * 2 + 1];
}
// DebugSendingPatches("SendLayerData", xPatches, yPatches);
SendLayerData(xPatches, yPatches, m_scene.Heightmap.GetTerrainData());
}
}
private void DebugSendingPatches(string pWho, int[] pX, int[] pY)
{
if (m_log.IsDebugEnabled)
{
int numPatches = pX.Length;
string Xs = "";
string Ys = "";
for (int pp = 0; pp < numPatches; pp++)
{
Xs += String.Format("{0}", (int)pX[pp]) + ",";
Ys += String.Format("{0}", (int)pY[pp]) + ",";
}
m_log.DebugFormat("{0} {1}: numPatches={2}, X={3}, Y={4}", LogHeader, pWho, numPatches, Xs, Ys);
} }
} }
/// <summary> /// <summary>
/// Sends a specified patch to a client /// Sends a terrain packet for the point specified.
/// This is a legacy call that has refarbed the terrain into a flat map of floats.
/// We just use the terrain from the region we know about.
/// </summary> /// </summary>
/// <param name="px">Patch coordinate (x) 0..15</param> /// <param name="px">Patch coordinate (x) 0..15</param>
/// <param name="py">Patch coordinate (y) 0..15</param> /// <param name="py">Patch coordinate (y) 0..15</param>
/// <param name="map">heightmap</param> /// <param name="map">heightmap</param>
public void SendLayerData(int px, int py, float[] map) public void SendLayerData(int px, int py, TerrainData terrData)
{
int[] xPatches = new[] { px };
int[] yPatches = new[] { py };
SendLayerData(xPatches, yPatches, terrData);
}
private void SendLayerData(int[] px, int[] py, TerrainData terrData)
{ {
try try
{ {
int[] patches = new int[] { py * 16 + px }; /* test code using the terrain compressor in libOpenMetaverse
float[] heightmap = (map.Length == 65536) ? int[] patchInd = new int[1];
map : patchInd[0] = px + (py * Constants.TerrainPatchSize);
LLHeightFieldMoronize(map); LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(terrData.GetFloatsSerialized(), patchInd);
*/
LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches); // Many, many patches could have been passed to us. Since the patches will be compressed
// into variable sized blocks, we cannot pre-compute how many will fit into one
// When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience. // packet. While some fancy packing algorithm is possible, 4 seems to always fit.
// To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain. int PatchesAssumedToFit = 4;
// We also make them unreliable because it's extremely likely that multiple packets will be sent for a terrain patch area for (int pcnt = 0; pcnt < px.Length; pcnt += PatchesAssumedToFit)
// invalidating previous packets for that area.
// It's possible for an editing user to flood themselves with edited packets but the majority of use cases are such that only a
// tiny percentage of users will be editing the terrain. Other, non-editing users will see the edits much slower.
// One last note on this topic, by the time users are going to be editing the terrain, it's extremely likely that the sim will
// have rezzed already and therefore this is not likely going to cause any additional issues with lost packets, objects or terrain
// patches.
// m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we only have one cache miss.
if (m_justEditedTerrain)
{ {
layerpack.Header.Reliable = false; int remaining = Math.Min(px.Length - pcnt, PatchesAssumedToFit);
OutPacket(layerpack, int[] xPatches = new int[remaining];
ThrottleOutPacketType.Unknown ); int[] yPatches = new int[remaining];
} for (int ii = 0; ii < remaining; ii++)
else {
{ xPatches[ii] = px[pcnt + ii];
layerpack.Header.Reliable = true; yPatches[ii] = py[pcnt + ii];
OutPacket(layerpack, }
ThrottleOutPacketType.Task); LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, xPatches, yPatches);
// DebugSendingPatches("SendLayerDataInternal", xPatches, yPatches);
SendTheLayerPacket(layerpack);
} }
} }
catch (Exception e) catch (Exception e)
@ -1290,36 +1337,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
} }
/// <summary> // When a user edits the terrain, so much data is sent, the data queues up fast and presents a
/// Munges heightfield into the LLUDP backed in restricted heightfield. // sub optimal editing experience. To alleviate this issue, when the user edits the terrain, we
/// </summary> // start skipping the queues until they're done editing the terrain. We also make them
/// <param name="map">float array in the base; Constants.RegionSize</param> // unreliable because it's extremely likely that multiple packets will be sent for a terrain patch
/// <returns>float array in the base 256</returns> // area invalidating previous packets for that area.
internal float[] LLHeightFieldMoronize(float[] map)
// It's possible for an editing user to flood themselves with edited packets but the majority
// of use cases are such that only a tiny percentage of users will be editing the terrain.
// Other, non-editing users will see the edits much slower.
// One last note on this topic, by the time users are going to be editing the terrain, it's
// extremely likely that the sim will have rezzed already and therefore this is not likely going
// to cause any additional issues with lost packets, objects or terrain patches.
// m_justEditedTerrain is volatile, so test once and duplicate two affected statements so we
// only have one cache miss.
private void SendTheLayerPacket(LayerDataPacket layerpack)
{ {
if (map.Length == 65536) if (m_justEditedTerrain)
return map; {
layerpack.Header.Reliable = false;
OutPacket(layerpack, ThrottleOutPacketType.Unknown );
}
else else
{ {
float[] returnmap = new float[65536]; layerpack.Header.Reliable = true;
OutPacket(layerpack, ThrottleOutPacketType.Land);
if (map.Length < 65535)
{
// rebase the vector stride to 256
for (int i = 0; i < Constants.RegionSize; i++)
Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, (int)Constants.RegionSize);
}
else
{
for (int i = 0; i < 256; i++)
Array.Copy(map, i * (int)Constants.RegionSize, returnmap, i * 256, 256);
}
//Array.Copy(map,0,returnmap,0,(map.Length < 65536)? map.Length : 65536);
return returnmap;
} }
} }
/// <summary> /// <summary>
@ -1348,21 +1393,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
Vector2[] windSpeeds = (Vector2[])o; Vector2[] windSpeeds = (Vector2[])o;
TerrainPatch[] patches = new TerrainPatch[2]; TerrainPatch[] patches = new TerrainPatch[2];
patches[0] = new TerrainPatch(); patches[0] = new TerrainPatch { Data = new float[16 * 16] };
patches[0].Data = new float[16 * 16]; patches[1] = new TerrainPatch { Data = new float[16 * 16] };
patches[1] = new TerrainPatch();
patches[1].Data = new float[16 * 16];
for (int y = 0; y < 16; y++) for (int x = 0; x < 16 * 16; x++)
{ {
for (int x = 0; x < 16; x++) patches[0].Data[x] = windSpeeds[x].X;
{ patches[1].Data[x] = windSpeeds[x].Y;
patches[0].Data[y * 16 + x] = windSpeeds[y * 16 + x].X;
patches[1].Data[y * 16 + x] = windSpeeds[y * 16 + x].Y;
}
} }
LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Wind); byte layerType = (byte)TerrainPatch.LayerType.Wind;
if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
layerType = (byte)TerrainPatch.LayerType.WindExtended;
// LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
(int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
layerpack.Header.Zerocoded = true; layerpack.Header.Zerocoded = true;
OutPacket(layerpack, ThrottleOutPacketType.Wind); OutPacket(layerpack, ThrottleOutPacketType.Wind);
} }
@ -1386,7 +1432,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
} }
} }
LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, TerrainPatch.LayerType.Cloud); byte layerType = (byte)TerrainPatch.LayerType.Cloud;
if (m_scene.RegionInfo.RegionSizeX > Constants.RegionSize || m_scene.RegionInfo.RegionSizeY > Constants.RegionSize)
layerType = (byte)TerrainPatch.LayerType.CloudExtended;
// LayerDataPacket layerpack = TerrainCompressor.CreateLayerDataPacket(patches, (TerrainPatch.LayerType)layerType);
LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
(int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
layerpack.Header.Zerocoded = true; layerpack.Header.Zerocoded = true;
OutPacket(layerpack, ThrottleOutPacketType.Cloud); OutPacket(layerpack, ThrottleOutPacketType.Cloud);
} }
@ -1491,10 +1543,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
mapReply.Data[i].Access = mapBlocks2[i].Access; mapReply.Data[i].Access = mapBlocks2[i].Access;
mapReply.Data[i].Agents = mapBlocks2[i].Agents; mapReply.Data[i].Agents = mapBlocks2[i].Agents;
// TODO: hookup varregion sim size here
mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock(); mapReply.Size[i] = new MapBlockReplyPacket.SizeBlock();
mapReply.Size[i].SizeX = 256; mapReply.Size[i].SizeX = mapBlocks2[i].SizeX;
mapReply.Size[i].SizeY = 256; mapReply.Size[i].SizeY = mapBlocks2[i].SizeY;
} }
OutPacket(mapReply, ThrottleOutPacketType.Land); OutPacket(mapReply, ThrottleOutPacketType.Land);
} }
@ -1659,15 +1710,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
public void SendKillObject(List<uint> localIDs) public void SendKillObject(List<uint> localIDs)
{ {
// foreach (uint id in localIDs)
// m_log.DebugFormat("[CLIENT]: Sending KillObjectPacket to {0} for {1} in {2}", Name, id, regionHandle);
// remove pending entities
lock (m_entityProps.SyncRoot)
m_entityProps.Remove(localIDs);
lock (m_entityUpdates.SyncRoot)
m_entityUpdates.Remove(localIDs);
KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject); KillObjectPacket kill = (KillObjectPacket)PacketPool.Instance.GetPacket(PacketType.KillObject);
// TODO: don't create new blocks if recycling an old packet // TODO: don't create new blocks if recycling an old packet
kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count]; kill.ObjectData = new KillObjectPacket.ObjectDataBlock[localIDs.Count];
@ -9093,6 +9135,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest; TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest;
if (handlerTeleportLocationRequest != null) if (handlerTeleportLocationRequest != null)
{ {
// Adjust teleport location to base of a larger region if requested to teleport to a sub-region
uint locX, locY;
Util.RegionHandleToWorldLoc(tpLocReq.Info.RegionHandle, out locX, out locY);
if ((locX >= m_scene.RegionInfo.WorldLocX)
&& (locX < (m_scene.RegionInfo.WorldLocX + m_scene.RegionInfo.RegionSizeX))
&& (locY >= m_scene.RegionInfo.WorldLocY)
&& (locY < (m_scene.RegionInfo.WorldLocY + m_scene.RegionInfo.RegionSizeY)) )
{
tpLocReq.Info.RegionHandle = m_scene.RegionInfo.RegionHandle;
tpLocReq.Info.Position.X += locX - m_scene.RegionInfo.WorldLocX;
tpLocReq.Info.Position.Y += locY - m_scene.RegionInfo.WorldLocY;
}
handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position, handlerTeleportLocationRequest(this, tpLocReq.Info.RegionHandle, tpLocReq.Info.Position,
tpLocReq.Info.LookAt, 16); tpLocReq.Info.LookAt, 16);
} }

View File

@ -213,8 +213,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
IScene scene = c.Scene; IScene scene = c.Scene;
UUID destination = c.Destination; UUID destination = c.Destination;
Vector3 fromPos = c.Position; Vector3 fromPos = c.Position;
Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize, Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0);
scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
bool checkParcelHide = false; bool checkParcelHide = false;
UUID sourceParcelID = UUID.Zero; UUID sourceParcelID = UUID.Zero;
@ -424,8 +423,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
{ {
Vector3 fromRegionPos = fromPos + regionPos; Vector3 fromRegionPos = fromPos + regionPos;
Vector3 toRegionPos = presence.AbsolutePosition + Vector3 toRegionPos = presence.AbsolutePosition +
new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize, new Vector3(presence.Scene.RegionInfo.WorldLocX, presence.Scene.RegionInfo.WorldLocY, 0);
presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos); int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);

View File

@ -663,8 +663,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
Vector3 avaPos = p.AbsolutePosition; Vector3 avaPos = p.AbsolutePosition;
// Getting the global position for the Avatar // Getting the global position for the Avatar
Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X, Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.WorldLocX + avaPos.X,
remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y, remoteClient.Scene.RegionInfo.WorldLocY + avaPos.Y,
avaPos.Z); avaPos.Z);
string landOwnerName = string.Empty; string landOwnerName = string.Empty;
@ -1353,4 +1353,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
} }
#endregion Web Util #endregion Web Util
} }
} }

View File

@ -317,9 +317,7 @@ namespace OpenSim.Region.CoreModules.Framework
foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID]) foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID])
{ {
uint x, y; uint x, y;
Utils.LongToUInts(kvp.Key, out x, out y); Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
x = x / Constants.RegionSize;
y = y / Constants.RegionSize;
m_log.Info(" >> "+x+", "+y+": "+kvp.Value); m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
} }
} }

View File

@ -213,8 +213,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules
if (part != null) if (part != null)
{ {
ObjectRegionName = s.RegionInfo.RegionName; ObjectRegionName = s.RegionInfo.RegionName;
uint localX = (s.RegionInfo.RegionLocX * (int)Constants.RegionSize); uint localX = s.RegionInfo.WorldLocX;
uint localY = (s.RegionInfo.RegionLocY * (int)Constants.RegionSize); uint localY = s.RegionInfo.WorldLocY;
ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")"; ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")";
return part; return part;
} }

View File

@ -268,11 +268,11 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key); caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key);
List<GridRegion> regions = kvp.Value.GetNeighbours(); List<GridRegion> regions = kvp.Value.GetNeighbours();
foreach (GridRegion r in regions) foreach (GridRegion r in regions)
caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, r.RegionLocX / Constants.RegionSize, r.RegionLocY / Constants.RegionSize); caps.AppendFormat(" {0} @ {1}-{2}\n", r.RegionName, Util.WorldToRegionLoc((uint)r.RegionLocX), Util.WorldToRegionLoc((uint)r.RegionLocY));
} }
} }
MainConsole.Instance.Output(caps.ToString()); MainConsole.Instance.Output(caps.ToString());
} }
} }
} }

View File

@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
return; return;
m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}", m_log.DebugFormat("[REGION CACHE]: (on region {0}) Region {1} is up @ {2}-{3}",
m_scene.RegionInfo.RegionName, otherRegion.RegionName, otherRegion.RegionLocX / Constants.RegionSize, otherRegion.RegionLocY / Constants.RegionSize); m_scene.RegionInfo.RegionName, otherRegion.RegionName, Util.WorldToRegionLoc((uint)otherRegion.RegionLocX), Util.WorldToRegionLoc((uint)otherRegion.RegionLocY));
m_neighbours[otherRegion.RegionHandle] = otherRegion; m_neighbours[otherRegion.RegionHandle] = otherRegion;
} }
@ -82,11 +82,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
return new List<GridRegion>(m_neighbours.Values); return new List<GridRegion>(m_neighbours.Values);
} }
// Get a region given its base coordinates (in meters).
// NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
// be the base coordinate of the region.
// The snapping is technically unnecessary but is harmless because regions are always
// multiples of the legacy region size (256).
public GridRegion GetRegionByPosition(int x, int y) public GridRegion GetRegionByPosition(int x, int y)
{ {
uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize; uint xsnap = (uint)(x / Constants.RegionSize) * Constants.RegionSize;
uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize; uint ysnap = (uint)(y / Constants.RegionSize) * Constants.RegionSize;
ulong handle = Utils.UIntsToLong(xsnap, ysnap); ulong handle = Util.RegionWorldLocToHandle(xsnap, ysnap);
if (m_neighbours.ContainsKey(handle)) if (m_neighbours.ContainsKey(handle))
return m_neighbours[handle]; return m_neighbours[handle];

View File

@ -141,7 +141,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null"); Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null");
Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match"); Assert.That(result.RegionID, Is.EqualTo(new UUID(1)), "Retrieved region's UUID does not match");
result = m_LocalConnector.GetRegionByPosition(UUID.Zero, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); result = m_LocalConnector.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000));
Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null"); Assert.IsNotNull(result, "Retrieved GetRegionByPosition is null");
Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match"); Assert.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match");
@ -197,4 +197,4 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected"); Assert.That(results.Count, Is.EqualTo(0), "Retrieved linked regions collection is not the number expected");
} }
} }
} }

View File

@ -57,6 +57,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
{ {
private static readonly ILog m_log = private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[MAP IMAGE SERVICE MODULE]";
private bool m_enabled = false; private bool m_enabled = false;
private IMapImageService m_MapService; private IMapImageService m_MapService;
@ -192,47 +193,94 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
m_lastrefresh = Util.EnvironmentTickCount(); m_lastrefresh = Util.EnvironmentTickCount();
} }
public void UploadMapTile(IScene scene, Bitmap mapTile)
{
m_log.DebugFormat("{0} Upload maptile for {1}", LogHeader, scene.Name);
// mapTile.Save( // DEBUG DEBUG
// String.Format("maptiles/raw-{0}-{1}-{2}.jpg", regionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY),
// ImageFormat.Jpeg);
// If the region/maptile is legacy sized, just upload the one tile like it has always been done
if (mapTile.Width == Constants.RegionSize && mapTile.Height == Constants.RegionSize)
{
ConvertAndUploadMaptile(mapTile, scene,
scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY);
}
else
{
// For larger regions (varregion) we must cut the region image into legacy sized
// pieces since that is how the maptile system works.
// Note the assumption that varregions are always a multiple of legacy size.
for (uint xx = 0; xx < mapTile.Width; xx += Constants.RegionSize)
{
for (uint yy = 0; yy < mapTile.Height; yy += Constants.RegionSize)
{
// Images are addressed from the upper left corner so have to do funny
// math to pick out the sub-tile since regions are numbered from
// the lower left.
Rectangle rect = new Rectangle(
(int)xx,
mapTile.Height - (int)yy - (int)Constants.RegionSize,
(int)Constants.RegionSize, (int)Constants.RegionSize);
using (Bitmap subMapTile = mapTile.Clone(rect, mapTile.PixelFormat))
{
ConvertAndUploadMaptile(subMapTile, scene,
scene.RegionInfo.RegionLocX + (xx / Constants.RegionSize),
scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize)
);
}
}
}
}
}
///<summary> ///<summary>
/// ///
///</summary> ///</summary>
public void UploadMapTile(IScene scene) public void UploadMapTile(IScene scene)
{ {
m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: upload maptile for {0}", scene.RegionInfo.RegionName); m_log.DebugFormat("{0}: upload maptile for {1}", LogHeader, scene.RegionInfo.RegionName);
// Create a JPG map tile and upload it to the AddMapTile API // Create a JPG map tile and upload it to the AddMapTile API
byte[] jpgData = Utils.EmptyBytes;
IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>(); IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
if (tileGenerator == null) if (tileGenerator == null)
{ {
m_log.Warn("[MAP IMAGE SERVICE MODULE]: Cannot upload PNG map tile without an ImageGenerator"); m_log.WarnFormat("{0} Cannot upload map tile without an ImageGenerator", LogHeader);
return; return;
} }
using (Image mapTile = tileGenerator.CreateMapTile()) using (Bitmap mapTile = tileGenerator.CreateMapTile())
{ {
// XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there // XXX: The MapImageModule will return a null if the user has chosen not to create map tiles and there
// is no static map tile. // is no static map tile.
if (mapTile == null) if (mapTile == null)
return; return;
using (MemoryStream stream = new MemoryStream()) UploadMapTile(scene, mapTile);
}
}
private void ConvertAndUploadMaptile(Image tileImage, IScene scene, uint locX, uint locY)
{
byte[] jpgData = Utils.EmptyBytes;
using (MemoryStream stream = new MemoryStream())
{
tileImage.Save(stream, ImageFormat.Jpeg);
jpgData = stream.ToArray();
}
if (jpgData != Utils.EmptyBytes)
{
string reason = string.Empty;
if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, scene.RegionInfo.ScopeID, out reason))
{ {
mapTile.Save(stream, ImageFormat.Jpeg); m_log.DebugFormat("{0} Unable to upload tile image for {1} at {2}-{3}: {4}", LogHeader,
jpgData = stream.ToArray(); scene.RegionInfo.RegionName, locX, locY, reason);
} }
} }
else
if (jpgData == Utils.EmptyBytes)
{ {
m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Tile image generation failed"); m_log.WarnFormat("{0} Tile image generation failed for region {1}", LogHeader, scene.RegionInfo.RegionName);
return;
}
string reason = string.Empty;
if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, scene.RegionInfo.ScopeID, out reason))
{
m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: Unable to upload tile image for {0} at {1}-{2}: {3}",
scene.RegionInfo.RegionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, reason);
} }
} }
} }

View File

@ -125,14 +125,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour
public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion) public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion)
{ {
uint x, y; uint x, y;
Utils.LongToUInts(regionHandle, out x, out y); Util.RegionHandleToRegionLoc(regionHandle, out x, out y);
foreach (Scene s in m_Scenes) foreach (Scene s in m_Scenes)
{ {
if (s.RegionInfo.RegionHandle == regionHandle) if (s.RegionInfo.RegionHandle == regionHandle)
{ {
m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}", m_log.DebugFormat("[LOCAL NEIGHBOUR SERVICE CONNECTOR]: HelloNeighbour from region {0} to neighbour {1} at {2}-{3}",
thisRegion.RegionName, s.Name, x / Constants.RegionSize, y / Constants.RegionSize); thisRegion.RegionName, s.Name, x, y );
//m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour"); //m_log.Debug("[NEIGHBOUR CONNECTOR]: Found region to SendHelloNeighbour");
return s.IncomingHelloNeighbour(thisRegion); return s.IncomingHelloNeighbour(thisRegion);

View File

@ -533,7 +533,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
if (isMegaregion) if (isMegaregion)
size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID); size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
else else
size = new Vector2((float)Constants.RegionSize, (float)Constants.RegionSize); size = new Vector2((float)scene.RegionInfo.RegionSizeX, (float)scene.RegionInfo.RegionSizeY);
xtw.WriteElementString("is_megaregion", isMegaregion.ToString()); xtw.WriteElementString("is_megaregion", isMegaregion.ToString());
xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y)); xtw.WriteElementString("size_in_meters", string.Format("{0},{1}", size.X, size.Y));

View File

@ -64,6 +64,12 @@ namespace OpenSim.Region.CoreModules.World.Land
public class LandManagementModule : INonSharedRegionModule public class LandManagementModule : INonSharedRegionModule
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
/// <summary>
/// Minimum land unit size in region co-ordinates.
/// </summary>
public const int landUnit = 4;
private static readonly string remoteParcelRequestPath = "0009/"; private static readonly string remoteParcelRequestPath = "0009/";
@ -74,15 +80,10 @@ namespace OpenSim.Region.CoreModules.World.Land
protected IPrimCountModule m_primCountModule; protected IPrimCountModule m_primCountModule;
protected IDialogModule m_Dialog; protected IDialogModule m_Dialog;
// Minimum for parcels to work is 64m even if we don't actually use them.
#pragma warning disable 0429
private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
#pragma warning restore 0429
/// <value> /// <value>
/// Local land ids at specified region co-ordinates (region size / 4) /// Local land ids at specified region co-ordinates (region size / 4)
/// </value> /// </value>
private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; private int[,] m_landIDList;
/// <value> /// <value>
/// Land objects keyed by local id /// Land objects keyed by local id
@ -123,7 +124,7 @@ namespace OpenSim.Region.CoreModules.World.Land
public void AddRegion(Scene scene) public void AddRegion(Scene scene)
{ {
m_scene = scene; m_scene = scene;
m_landIDList.Initialize(); m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
landChannel = new LandChannel(scene, this); landChannel = new LandChannel(scene, this);
parcelInfoCache = new Cache(); parcelInfoCache = new Cache();
@ -235,7 +236,7 @@ namespace OpenSim.Region.CoreModules.World.Land
public void UpdateLandObject(int local_id, LandData data) public void UpdateLandObject(int local_id, LandData data)
{ {
LandData newData = data.Copy(); LandData newData = data.Copy();
newData.LocalID = local_id; newData.LocalID = local_id;
ILandObject land; ILandObject land;
lock (m_landList) lock (m_landList)
@ -264,7 +265,7 @@ namespace OpenSim.Region.CoreModules.World.Land
{ {
m_landList.Clear(); m_landList.Clear();
m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
m_landIDList.Initialize(); m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
} }
} }
@ -274,11 +275,11 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns>The parcel created.</returns> /// <returns>The parcel created.</returns>
protected ILandObject CreateDefaultParcel() protected ILandObject CreateDefaultParcel()
{ {
m_log.DebugFormat( m_log.DebugFormat("{0} Creating default parcel for region {1}", LogHeader, m_scene.RegionInfo.RegionName);
"[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0,
(int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY));
fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
@ -569,9 +570,9 @@ namespace OpenSim.Region.CoreModules.World.Land
new_land.LandData.LocalID = newLandLocalID; new_land.LandData.LocalID = newLandLocalID;
bool[,] landBitmap = new_land.GetLandBitmap(); bool[,] landBitmap = new_land.GetLandBitmap();
for (int x = 0; x < landArrayMax; x++) for (int x = 0; x < landBitmap.GetLength(0); x++)
{ {
for (int y = 0; y < landArrayMax; y++) for (int y = 0; y < landBitmap.GetLength(1); y++)
{ {
if (landBitmap[x, y]) if (landBitmap[x, y])
{ {
@ -601,9 +602,9 @@ namespace OpenSim.Region.CoreModules.World.Land
ILandObject land; ILandObject land;
lock (m_landList) lock (m_landList)
{ {
for (int x = 0; x < 64; x++) for (int x = 0; x < m_landIDList.GetLength(0); x++)
{ {
for (int y = 0; y < 64; y++) for (int y = 0; y < m_landIDList.GetLength(1); y++)
{ {
if (m_landIDList[x, y] == local_id) if (m_landIDList[x, y] == local_id)
{ {
@ -656,9 +657,9 @@ namespace OpenSim.Region.CoreModules.World.Land
bool[,] landBitmapSlave = slave.GetLandBitmap(); bool[,] landBitmapSlave = slave.GetLandBitmap();
lock (m_landList) lock (m_landList)
{ {
for (int x = 0; x < 64; x++) for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
{ {
for (int y = 0; y < 64; y++) for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
{ {
if (landBitmapSlave[x, y]) if (landBitmapSlave[x, y])
{ {
@ -695,20 +696,23 @@ namespace OpenSim.Region.CoreModules.World.Land
int x; int x;
int y; int y;
if (x_float > Constants.RegionSize || x_float < 0 || y_float > Constants.RegionSize || y_float < 0) if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0)
return null; return null;
try try
{ {
x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit));
y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit));
} }
catch (OverflowException) catch (OverflowException)
{ {
return null; return null;
} }
if (x >= 64 || y >= 64 || x < 0 || y < 0) if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit)
|| y >= (m_scene.RegionInfo.RegionSizeY / landUnit)
|| x < 0
|| y < 0)
{ {
return null; return null;
} }
@ -740,20 +744,20 @@ namespace OpenSim.Region.CoreModules.World.Land
int avx = (int)x; int avx = (int)x;
if (avx < 0) if (avx < 0)
avx = 0; avx = 0;
else if (avx >= (int)Constants.RegionSize) else if (avx >= m_scene.RegionInfo.RegionSizeX)
avx = (int)Constants.RegionSize - 1; avx = (int)Constants.RegionSize - 1;
int avy = (int)y; int avy = (int)y;
if (avy < 0) if (avy < 0)
avy = 0; avy = 0;
else if (avy >= (int)Constants.RegionSize) else if (avy >= m_scene.RegionInfo.RegionSizeY)
avy = (int)Constants.RegionSize - 1; avy = (int)Constants.RegionSize - 1;
lock (m_landIDList) lock (m_landIDList)
{ {
try try
{ {
return m_landList[m_landIDList[avx / 4, avy / 4]]; return m_landList[m_landIDList[avx / landUnit, avy / landUnit]];
} }
catch (IndexOutOfRangeException) catch (IndexOutOfRangeException)
{ {
@ -764,7 +768,7 @@ namespace OpenSim.Region.CoreModules.World.Land
public ILandObject GetLandObject(int x, int y) public ILandObject GetLandObject(int x, int y)
{ {
if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0)
{ {
// These exceptions here will cause a lot of complaints from the users specifically because // These exceptions here will cause a lot of complaints from the users specifically because
// they happen every time at border crossings // they happen every time at border crossings
@ -1057,9 +1061,10 @@ namespace OpenSim.Region.CoreModules.World.Land
int byteArrayCount = 0; int byteArrayCount = 0;
int sequenceID = 0; int sequenceID = 0;
for (int y = 0; y < Constants.RegionSize; y += 4) // Layer data is in landUnit (4m) chunks
for (int y = 0; y < m_scene.RegionInfo.RegionSizeY; y += landUnit)
{ {
for (int x = 0; x < Constants.RegionSize; x += 4) for (int x = 0; x < m_scene.RegionInfo.RegionSizeX; x += landUnit)
{ {
byte tempByte = 0; //This represents the byte for the current 4x4 byte tempByte = 0; //This represents the byte for the current 4x4
@ -1769,7 +1774,7 @@ namespace OpenSim.Region.CoreModules.World.Land
{ {
// most likely still cached from building the extLandData entry // most likely still cached from building the extLandData entry
uint x = 0, y = 0; uint x = 0, y = 0;
Utils.LongToUInts(data.RegionHandle, out x, out y); Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y);
info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
} }
// we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.

View File

@ -45,15 +45,13 @@ namespace OpenSim.Region.CoreModules.World.Land
#region Member Variables #region Member Variables
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#pragma warning disable 0429 private static readonly string LogHeader = "[LAND OBJECT]";
private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
#pragma warning restore 0429 private readonly int landUnit = 4;
private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax];
private int m_lastSeqId = 0; private int m_lastSeqId = 0;
private int m_expiryCounter = 0; private int m_expiryCounter = 0;
protected LandData m_landData = new LandData();
protected Scene m_scene; protected Scene m_scene;
protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>(); protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>();
@ -61,6 +59,7 @@ namespace OpenSim.Region.CoreModules.World.Land
protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>(); protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>();
protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds
private bool[,] m_landBitmap;
public bool[,] LandBitmap public bool[,] LandBitmap
{ {
get { return m_landBitmap; } get { return m_landBitmap; }
@ -76,6 +75,7 @@ namespace OpenSim.Region.CoreModules.World.Land
return free; return free;
} }
protected LandData m_landData;
public LandData LandData public LandData LandData
{ {
get { return m_landData; } get { return m_landData; }
@ -94,12 +94,12 @@ namespace OpenSim.Region.CoreModules.World.Land
{ {
get get
{ {
for (int y = 0; y < landArrayMax; y++) for (int y = 0; y < LandBitmap.GetLength(1); y++)
{ {
for (int x = 0; x < landArrayMax; x++) for (int x = 0; x < LandBitmap.GetLength(0); x++)
{ {
if (LandBitmap[x, y]) if (LandBitmap[x, y])
return new Vector3(x * 4, y * 4, 0); return new Vector3(x * landUnit, y * landUnit, 0);
} }
} }
@ -111,13 +111,13 @@ namespace OpenSim.Region.CoreModules.World.Land
{ {
get get
{ {
for (int y = landArrayMax - 1; y >= 0; y--) for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--)
{ {
for (int x = landArrayMax - 1; x >= 0; x--) for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--)
{ {
if (LandBitmap[x, y]) if (LandBitmap[x, y])
{ {
return new Vector3(x * 4 + 4, y * 4 + 4, 0); return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
} }
} }
} }
@ -128,9 +128,21 @@ namespace OpenSim.Region.CoreModules.World.Land
#region Constructors #region Constructors
public LandObject(LandData landData, Scene scene)
{
LandData = landData.Copy();
m_scene = scene;
}
public LandObject(UUID owner_id, bool is_group_owned, Scene scene) public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
{ {
m_scene = scene; m_scene = scene;
if (m_scene == null)
LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
else
LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
LandData = new LandData();
LandData.OwnerID = owner_id; LandData.OwnerID = owner_id;
if (is_group_owned) if (is_group_owned)
LandData.GroupID = owner_id; LandData.GroupID = owner_id;
@ -155,9 +167,9 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns>Returns true if the piece of land contains the specified point</returns> /// <returns>Returns true if the piece of land contains the specified point</returns>
public bool ContainsPoint(int x, int y) public bool ContainsPoint(int x, int y)
{ {
if (x >= 0 && y >= 0 && x < Constants.RegionSize && y < Constants.RegionSize) if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
{ {
return (LandBitmap[x / 4, y / 4] == true); return LandBitmap[x / landUnit, y / landUnit];
} }
else else
{ {
@ -197,10 +209,10 @@ namespace OpenSim.Region.CoreModules.World.Land
else else
{ {
// Normal Calculations // Normal Calculations
int parcelMax = (int)((long)LandData.Area int parcelMax = (int)( (long)LandData.Area
* (long)m_scene.RegionInfo.ObjectCapacity * (long)m_scene.RegionInfo.ObjectCapacity
* (long)m_scene.RegionInfo.RegionSettings.ObjectBonus * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus
/ 65536L); / (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) );
//m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax); //m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax);
return parcelMax; return parcelMax;
} }
@ -231,8 +243,9 @@ namespace OpenSim.Region.CoreModules.World.Land
else else
{ {
//Normal Calculations //Normal Calculations
int simMax = (int)((long)LandData.SimwideArea int simMax = (int)( (long)LandData.SimwideArea
* (long)m_scene.RegionInfo.ObjectCapacity / 65536L); * (long)m_scene.RegionInfo.ObjectCapacity
/ (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) );
// m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}", LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax); // m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}", LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax);
return simMax; return simMax;
} }
@ -597,8 +610,8 @@ namespace OpenSim.Region.CoreModules.World.Land
try try
{ {
over = over =
m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
} }
catch (Exception) catch (Exception)
{ {
@ -752,9 +765,9 @@ namespace OpenSim.Region.CoreModules.World.Land
int max_y = Int32.MinValue; int max_y = Int32.MinValue;
int tempArea = 0; int tempArea = 0;
int x, y; int x, y;
for (x = 0; x < 64; x++) for (x = 0; x < LandBitmap.GetLength(0); x++)
{ {
for (y = 0; y < 64; y++) for (y = 0; y < LandBitmap.GetLength(1); y++)
{ {
if (LandBitmap[x, y] == true) if (LandBitmap[x, y] == true)
{ {
@ -766,23 +779,25 @@ namespace OpenSim.Region.CoreModules.World.Land
max_x = x; max_x = x;
if (max_y < y) if (max_y < y)
max_y = y; max_y = y;
tempArea += 16; //16sqm peice of land tempArea += landUnit * landUnit; //16sqm peice of land
} }
} }
} }
int tx = min_x * landUnit;
if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
int tx = min_x * 4;
int htx; int htx;
if (tx == ((int)Constants.RegionSize)) if (tx >= ((int)m_scene.RegionInfo.RegionSizeX))
htx = tx - 1; htx = (int)m_scene.RegionInfo.RegionSizeX - 1;
else else
htx = tx; htx = tx;
int ty = min_y * 4; int ty = min_y * landUnit;
int hty; int hty;
if (ty == ((int)Constants.RegionSize)) if (ty >= ((int)m_scene.RegionInfo.RegionSizeY))
hty = ty - 1; hty = (int)m_scene.RegionInfo.RegionSizeY - 1;
else else
hty = ty; hty = ty;
@ -791,17 +806,17 @@ namespace OpenSim.Region.CoreModules.World.Land
(float)(tx), (float)(ty), m_scene != null ? (float)m_scene.Heightmap[htx, hty] : 0); (float)(tx), (float)(ty), m_scene != null ? (float)m_scene.Heightmap[htx, hty] : 0);
max_x++; max_x++;
tx = max_x * 4; tx = max_x * landUnit;
if (tx == ((int)Constants.RegionSize)) if (tx >= ((int)m_scene.RegionInfo.RegionSizeX))
htx = tx - 1; htx = (int)m_scene.RegionInfo.RegionSizeX - 1;
else else
htx = tx; htx = tx;
max_y++; max_y++;
ty = max_y * 4; ty = max_y * 4;
if (ty == ((int)Constants.RegionSize)) if (ty >= ((int)m_scene.RegionInfo.RegionSizeY))
hty = ty - 1; hty = (int)m_scene.RegionInfo.RegionSizeY - 1;
else else
hty = ty; hty = ty;
@ -819,20 +834,11 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <summary> /// <summary>
/// Sets the land's bitmap manually /// Sets the land's bitmap manually
/// </summary> /// </summary>
/// <param name="bitmap">64x64 block representing where this land is on a map</param> /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
public void SetLandBitmap(bool[,] bitmap) public void SetLandBitmap(bool[,] bitmap)
{ {
if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) LandBitmap = bitmap;
{ ForceUpdateLandInfo();
//Throw an exception - The bitmap is not 64x64
//throw new Exception("Error: Invalid Parcel Bitmap");
}
else
{
//Valid: Lets set it
LandBitmap = bitmap;
ForceUpdateLandInfo();
}
} }
/// <summary> /// <summary>
@ -846,14 +852,16 @@ namespace OpenSim.Region.CoreModules.World.Land
public bool[,] BasicFullRegionLandBitmap() public bool[,] BasicFullRegionLandBitmap()
{ {
return GetSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize); return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY);
} }
public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
{ {
bool[,] tempBitmap = new bool[64,64]; // Empty bitmap for the whole region
bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
tempBitmap.Initialize(); tempBitmap.Initialize();
// Fill the bitmap square area specified by state and end
tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
return tempBitmap; return tempBitmap;
} }
@ -871,19 +879,13 @@ namespace OpenSim.Region.CoreModules.World.Land
public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
bool set_value) bool set_value)
{ {
if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
{
//Throw an exception - The bitmap is not 64x64
//throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
}
int x, y; int x, y;
for (y = 0; y < 64; y++) for (y = 0; y < land_bitmap.GetLength(1); y++)
{ {
for (x = 0; x < 64; x++) for (x = 0; x < land_bitmap.GetLength(0); x++)
{ {
if (x >= start_x / 4 && x < end_x / 4 if (x >= start_x / landUnit && x < end_x / landUnit
&& y >= start_y / 4 && y < end_y / 4) && y >= start_y / landUnit && y < end_y / landUnit)
{ {
land_bitmap[x, y] = set_value; land_bitmap[x, y] = set_value;
} }
@ -900,21 +902,21 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns></returns> /// <returns></returns>
public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
{ {
if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
|| bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
|| bitmap_add.Rank != 2
|| bitmap_base.Rank != 2)
{ {
//Throw an exception - The bitmap is not 64x64 throw new Exception(
throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
} LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2) );
{
//Throw an exception - The bitmap is not 64x64
throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
} }
int x, y; int x, y;
for (y = 0; y < 64; y++) for (y = 0; y < bitmap_base.GetLength(1); y++)
{ {
for (x = 0; x < 64; x++) for (x = 0; x < bitmap_add.GetLength(0); x++)
{ {
if (bitmap_add[x, y]) if (bitmap_add[x, y])
{ {
@ -931,14 +933,14 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns></returns> /// <returns></returns>
private byte[] ConvertLandBitmapToBytes() private byte[] ConvertLandBitmapToBytes()
{ {
byte[] tempConvertArr = new byte[512]; byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
int tempByte = 0; int tempByte = 0;
int x, y, i, byteNum = 0; int i, byteNum = 0;
int mask = 1; int mask = 1;
i = 0; i = 0;
for (y = 0; y < 64; y++) for (int y = 0; y < LandBitmap.GetLength(1); y++)
{ {
for (x = 0; x < 64; x++) for (int x = 0; x < LandBitmap.GetLength(0); x++)
{ {
if (LandBitmap[x, y]) if (LandBitmap[x, y])
tempByte |= mask; tempByte |= mask;
@ -971,25 +973,45 @@ namespace OpenSim.Region.CoreModules.World.Land
private bool[,] ConvertBytesToLandBitmap() private bool[,] ConvertBytesToLandBitmap()
{ {
bool[,] tempConvertMap = new bool[landArrayMax, landArrayMax]; bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
tempConvertMap.Initialize(); tempConvertMap.Initialize();
byte tempByte = 0; byte tempByte = 0;
int x = 0, y = 0, i = 0, bitNum = 0; // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
for (i = 0; i < 512; i++) int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
if (bitmapLen == 512)
{
// Legacy bitmap being passed in. Use the legacy region size
// and only set the lower area of the larger region.
xLen = (int)(Constants.RegionSize / landUnit);
}
// m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
int x = 0, y = 0;
for (int i = 0; i < bitmapLen; i++)
{ {
tempByte = LandData.Bitmap[i]; tempByte = LandData.Bitmap[i];
for (bitNum = 0; bitNum < 8; bitNum++) for (int bitNum = 0; bitNum < 8; bitNum++)
{ {
bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
tempConvertMap[x, y] = bit; try
{
tempConvertMap[x, y] = bit;
}
catch (Exception)
{
m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
}
x++; x++;
if (x > 63) if (x >= xLen)
{ {
x = 0; x = 0;
y++; y++;
} }
} }
} }
return tempConvertMap; return tempConvertMap;
} }

View File

@ -102,7 +102,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
terrainRenderer.Initialise(m_scene, m_config); terrainRenderer.Initialise(m_scene, m_config);
mapbmp = new Bitmap((int)Constants.RegionSize, (int)Constants.RegionSize, System.Drawing.Imaging.PixelFormat.Format24bppRgb); mapbmp = new Bitmap((int)m_scene.Heightmap.Width, (int)m_scene.Heightmap.Height,
System.Drawing.Imaging.PixelFormat.Format24bppRgb);
//long t = System.Environment.TickCount; //long t = System.Environment.TickCount;
//for (int i = 0; i < 10; ++i) { //for (int i = 0; i < 10; ++i) {
terrainRenderer.TerrainToBitmap(mapbmp); terrainRenderer.TerrainToBitmap(mapbmp);
@ -277,7 +278,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp) private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
{ {
int tc = 0; int tc = 0;
double[,] hm = whichScene.Heightmap.GetDoubles(); ITerrainChannel hm = whichScene.Heightmap;
tc = Environment.TickCount; tc = Environment.TickCount;
m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile"); m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
EntityBase[] objs = whichScene.GetEntities(); EntityBase[] objs = whichScene.GetEntities();
@ -363,7 +364,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
Vector3 pos = part.GetWorldPosition(); Vector3 pos = part.GetWorldPosition();
// skip prim outside of retion // skip prim outside of retion
if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f) if (!m_scene.PositionIsInCurrentRegion(pos))
continue; continue;
// skip prim in non-finite position // skip prim in non-finite position
@ -388,7 +389,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z); Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
Vector3 scale = new Vector3(); Vector3 scale = new Vector3();
Vector3 tScale = new Vector3(); Vector3 tScale = new Vector3();
Vector3 axPos = new Vector3(pos.X,pos.Y,pos.Z); Vector3 axPos = new Vector3(pos.X, pos.Y, pos.Z);
Quaternion llrot = part.GetWorldRotation(); Quaternion llrot = part.GetWorldRotation();
Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z); Quaternion rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
@ -406,9 +407,14 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
int mapdrawendY = (int)(pos.Y + scale.Y); int mapdrawendY = (int)(pos.Y + scale.Y);
// If object is beyond the edge of the map, don't draw it to avoid errors // If object is beyond the edge of the map, don't draw it to avoid errors
if (mapdrawstartX < 0 || mapdrawstartX > ((int)Constants.RegionSize - 1) || mapdrawendX < 0 || mapdrawendX > ((int)Constants.RegionSize - 1) if (mapdrawstartX < 0
|| mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0 || mapdrawstartX > (hm.Width - 1)
|| mapdrawendY > ((int)Constants.RegionSize - 1)) || mapdrawendX < 0
|| mapdrawendX > (hm.Width - 1)
|| mapdrawstartY < 0
|| mapdrawstartY > (hm.Height - 1)
|| mapdrawendY < 0
|| mapdrawendY > (hm.Height - 1))
continue; continue;
#region obb face reconstruction part duex #region obb face reconstruction part duex
@ -530,11 +536,11 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
for (int i = 0; i < FaceA.Length; i++) for (int i = 0; i < FaceA.Length; i++)
{ {
Point[] working = new Point[5]; Point[] working = new Point[5];
working[0] = project(FaceA[i], axPos); working[0] = project(hm, FaceA[i], axPos);
working[1] = project(FaceB[i], axPos); working[1] = project(hm, FaceB[i], axPos);
working[2] = project(FaceD[i], axPos); working[2] = project(hm, FaceD[i], axPos);
working[3] = project(FaceC[i], axPos); working[3] = project(hm, FaceC[i], axPos);
working[4] = project(FaceA[i], axPos); working[4] = project(hm, FaceA[i], axPos);
face workingface = new face(); face workingface = new face();
workingface.pts = working; workingface.pts = working;
@ -609,17 +615,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
return mapbmp; return mapbmp;
} }
private Point project(Vector3 point3d, Vector3 originpos) private Point project(ITerrainChannel hm, Vector3 point3d, Vector3 originpos)
{ {
Point returnpt = new Point(); Point returnpt = new Point();
//originpos = point3d; //originpos = point3d;
//int d = (int)(256f / 1.5f); //int d = (int)(256f / 1.5f);
//Vector3 topos = new Vector3(0, 0, 0); //Vector3 topos = new Vector3(0, 0, 0);
// float z = -point3d.z - topos.z; // float z = -point3d.z - topos.z;
returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d); returnpt.X = (int)point3d.X;//(int)((topos.x - point3d.x) / z * d);
returnpt.Y = (int)(((int)Constants.RegionSize - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d))); returnpt.Y = (int)((hm.Width - 1) - point3d.Y);//(int)(255 - (((topos.y - point3d.y) / z * d)));
return returnpt; return returnpt;
} }

View File

@ -31,6 +31,7 @@ using System.Reflection;
using log4net; using log4net;
using Nini.Config; using Nini.Config;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes; using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.CoreModules.World.LegacyMap namespace OpenSim.Region.CoreModules.World.LegacyMap
@ -39,8 +40,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
{ {
private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95); private static readonly Color WATER_COLOR = Color.FromArgb(29, 71, 95);
private static readonly ILog m_log = private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]";
private Scene m_scene; private Scene m_scene;
//private IConfigSource m_config; // not used currently //private IConfigSource m_config; // not used currently
@ -53,19 +54,26 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
public void TerrainToBitmap(Bitmap mapbmp) public void TerrainToBitmap(Bitmap mapbmp)
{ {
m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
int tc = Environment.TickCount; int tc = Environment.TickCount;
m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Terrain");
double[,] hm = m_scene.Heightmap.GetDoubles(); ITerrainChannel hm = m_scene.Heightmap;
if (mapbmp.Width != hm.Width || mapbmp.Height != hm.Height)
{
m_log.ErrorFormat("{0} TerrainToBitmap. Passed bitmap wrong dimensions. passed=<{1},{2}>, size=<{3},{4}>",
LogHeader, mapbmp.Width, mapbmp.Height, hm.Width, hm.Height);
}
bool ShadowDebugContinue = true; bool ShadowDebugContinue = true;
bool terraincorruptedwarningsaid = false; bool terraincorruptedwarningsaid = false;
float low = 255; float low = 255;
float high = 0; float high = 0;
for (int x = 0; x < (int)Constants.RegionSize; x++) for (int x = 0; x < hm.Width; x++)
{ {
for (int y = 0; y < (int)Constants.RegionSize; y++) for (int y = 0; y < hm.Height; y++)
{ {
float hmval = (float)hm[x, y]; float hmval = (float)hm[x, y];
if (hmval < low) if (hmval < low)
@ -77,12 +85,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight; float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
for (int x = 0; x < (int)Constants.RegionSize; x++) for (int x = 0; x < hm.Width; x++)
{ {
for (int y = 0; y < (int)Constants.RegionSize; y++) for (int y = 0; y < hm.Height; y++)
{ {
// Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left // Y flip the cordinates for the bitmap: hf origin is lower left, bm origin is upper left
int yr = ((int)Constants.RegionSize - 1) - y; int yr = ((int)hm.Height - 1) - y;
float heightvalue = (float)hm[x, y]; float heightvalue = (float)hm[x, y];
@ -109,12 +117,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
// . // .
// //
// Shade the terrain for shadows // Shade the terrain for shadows
if (x < ((int)Constants.RegionSize - 1) && yr < ((int)Constants.RegionSize - 1)) if (x < (hm.Width - 1) && yr < (hm.Height - 1))
{ {
float hfvalue = (float)hm[x, y]; float hfvalue = (float)hm[x, y];
float hfvaluecompare = 0f; float hfvaluecompare = 0f;
if ((x + 1 < (int)Constants.RegionSize) && (y + 1 < (int)Constants.RegionSize)) if ((x + 1 < hm.Width) && (y + 1 < hm.Height))
{ {
hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there hfvaluecompare = (float)hm[x + 1, y + 1]; // light from north-east => look at land height there
} }
@ -179,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
if (ShadowDebugContinue) if (ShadowDebugContinue)
{ {
if ((x - 1 > 0) && (yr + 1 < (int)Constants.RegionSize)) if ((x - 1 > 0) && (yr + 1 < hm.Height))
{ {
color = mapbmp.GetPixel(x - 1, yr + 1); color = mapbmp.GetPixel(x - 1, yr + 1);
int r = color.R; int r = color.R;
@ -233,7 +241,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
terraincorruptedwarningsaid = true; terraincorruptedwarningsaid = true;
} }
Color black = Color.Black; Color black = Color.Black;
mapbmp.SetPixel(x, ((int)Constants.RegionSize - y) - 1, black); mapbmp.SetPixel(x, (hm.Width - y) - 1, black);
} }
} }
} }
@ -242,4 +250,4 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms"); m_log.Debug("[SHADED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
} }
} }
} }

View File

@ -151,14 +151,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
break; break;
case 2: // Sell a copy case 2: // Sell a copy
Vector3 inventoryStoredPosition = new Vector3 Vector3 inventoryStoredPosition = new Vector3(
(((group.AbsolutePosition.X > (int)Constants.RegionSize) Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6),
? 250 Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6),
: group.AbsolutePosition.X)
,
(group.AbsolutePosition.X > (int)Constants.RegionSize)
? 250
: group.AbsolutePosition.X,
group.AbsolutePosition.Z); group.AbsolutePosition.Z);
Vector3 originalPosition = group.AbsolutePosition; Vector3 originalPosition = group.AbsolutePosition;

View File

@ -1571,10 +1571,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
float X = position.X; float X = position.X;
float Y = position.Y; float Y = position.Y;
if (X > ((int)Constants.RegionSize - 1)) if (X > ((int)m_scene.RegionInfo.RegionSizeX - 1))
X = ((int)Constants.RegionSize - 1); X = ((int)m_scene.RegionInfo.RegionSizeX - 1);
if (Y > ((int)Constants.RegionSize - 1)) if (Y > ((int)m_scene.RegionInfo.RegionSizeY - 1))
Y = ((int)Constants.RegionSize - 1); Y = ((int)m_scene.RegionInfo.RegionSizeY - 1);
if (X < 0) if (X < 0)
X = 0; X = 0;
if (Y < 0) if (Y < 0)

View File

@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects
for (y = 0; y < map.Height; y++) for (y = 0; y < map.Height; y++)
{ {
map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10; map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 3, 0.25) * 10;
double spherFac = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2, Constants.RegionSize / 2, 50) * 0.01; double spherFac = TerrainUtil.SphericalFactor(x, y, map.Width / 2, map.Height / 2, 50) * 0.01;
if (map[x, y] < spherFac) if (map[x, y] < spherFac)
{ {
map[x, y] = spherFac; map[x, y] = spherFac;
@ -53,4 +53,4 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects
#endregion #endregion
} }
} }

View File

@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
{ {
using (Bitmap bitmap = new Bitmap(filename)) using (Bitmap bitmap = new Bitmap(filename))
{ {
ITerrainChannel retval = new TerrainChannel(true); ITerrainChannel retval = new TerrainChannel(w, h);
for (int x = 0; x < retval.Width; x++) for (int x = 0; x < retval.Width; x++)
{ {

View File

@ -154,10 +154,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
public ITerrainChannel LoadStream(Stream s) public ITerrainChannel LoadStream(Stream s)
{ {
// Set to default size
int w = (int)Constants.RegionSize; int w = (int)Constants.RegionSize;
int h = (int)Constants.RegionSize; int h = (int)Constants.RegionSize;
// create a dummy channel (in case data is bad)
TerrainChannel retval = new TerrainChannel(w, h); TerrainChannel retval = new TerrainChannel(w, h);
BinaryReader bs = new BinaryReader(s); BinaryReader bs = new BinaryReader(s);
@ -165,8 +166,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
bool eof = false; bool eof = false;
if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ") if (Encoding.ASCII.GetString(bs.ReadBytes(16)) == "TERRAGENTERRAIN ")
{ {
// int fileWidth = w;
// int fileHeight = h;
// Terragen file // Terragen file
while (eof == false) while (eof == false)
@ -175,31 +174,29 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
switch (tmp) switch (tmp)
{ {
case "SIZE": case "SIZE":
// int sztmp = bs.ReadInt16() + 1; w = bs.ReadInt16() + 1;
// fileWidth = sztmp; h = w;
// fileHeight = sztmp;
bs.ReadInt16();
bs.ReadInt16(); bs.ReadInt16();
break; break;
case "XPTS": case "XPTS":
// fileWidth = bs.ReadInt16(); w = bs.ReadInt16();
bs.ReadInt16();
bs.ReadInt16(); bs.ReadInt16();
break; break;
case "YPTS": case "YPTS":
// fileHeight = bs.ReadInt16(); h = bs.ReadInt16();
bs.ReadInt16();
bs.ReadInt16(); bs.ReadInt16();
break; break;
case "ALTW": case "ALTW":
eof = true; eof = true;
Int16 heightScale = bs.ReadInt16(); // create new channel of proper size (now that we know it)
Int16 baseHeight = bs.ReadInt16(); retval = new TerrainChannel(w, h);
double heightScale = (double)bs.ReadInt16() / 65536.0;
double baseHeight = (double)bs.ReadInt16();
for (int y = 0; y < h; y++) for (int y = 0; y < h; y++)
{ {
for (int x = 0; x < w; x++) for (int x = 0; x < w; x++)
{ {
retval[x, y] = baseHeight + bs.ReadInt16() * (double)heightScale / 65536.0; retval[x, y] = baseHeight + (double)bs.ReadInt16() * heightScale;
} }
} }
break; break;
@ -257,17 +254,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
bs.Write(enc.GetBytes("TERRAGENTERRAIN ")); bs.Write(enc.GetBytes("TERRAGENTERRAIN "));
bs.Write(enc.GetBytes("SIZE")); bs.Write(enc.GetBytes("SIZE"));
bs.Write(Convert.ToInt16(Constants.RegionSize)); bs.Write(Convert.ToInt16(map.Width));
bs.Write(Convert.ToInt16(0)); // necessary padding bs.Write(Convert.ToInt16(0)); // necessary padding
//The XPTS and YPTS chunks are not needed for square regions //The XPTS and YPTS chunks are not needed for square regions
//but L3DT won't load the terrain file properly without them. //but L3DT won't load the terrain file properly without them.
bs.Write(enc.GetBytes("XPTS")); bs.Write(enc.GetBytes("XPTS"));
bs.Write(Convert.ToInt16(Constants.RegionSize)); bs.Write(Convert.ToInt16(map.Width));
bs.Write(Convert.ToInt16(0)); // necessary padding bs.Write(Convert.ToInt16(0)); // necessary padding
bs.Write(enc.GetBytes("YPTS")); bs.Write(enc.GetBytes("YPTS"));
bs.Write(Convert.ToInt16(Constants.RegionSize)); bs.Write(Convert.ToInt16(map.Height));
bs.Write(Convert.ToInt16(0)); // necessary padding bs.Write(Convert.ToInt16(0)); // necessary padding
bs.Write(enc.GetBytes("SCAL")); bs.Write(enc.GetBytes("SCAL"));
@ -283,11 +280,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min bs.Write(Convert.ToInt16(horizontalScale)); // range between max and min
bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point bs.Write(Convert.ToInt16(baseHeight)); // base height or mid point
double factor = 65536.0 / horizontalScale; // avoid computing this on each iteration
for (int y = 0; y < map.Height; y++) for (int y = 0; y < map.Height; y++)
{ {
for (int x = 0; x < map.Width; x++) for (int x = 0; x < map.Width; x++)
{ {
float elevation = (float)((map[x,y] - baseHeight) * 65536 ) / (float)horizontalScale; // see LoadStream for inverse float elevation = (float)((map[x,y] - baseHeight) * factor); // see LoadStream for inverse
// clamp rounding issues // clamp rounding issues
if (elevation > Int16.MaxValue) if (elevation > Int16.MaxValue)

View File

@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
{ {
if (fillArea[x, y]) if (fillArea[x, y])
{ {
double noise = TerrainUtil.PerlinNoise2D((double) x / Constants.RegionSize, (double) y / Constants.RegionSize, 8, 1.0); double noise = TerrainUtil.PerlinNoise2D((double) x / map.Width, (double) y / map.Height, 8, 1.0);
map[x, y] += noise * strength; map[x, y] += noise * strength;
} }
@ -55,4 +55,4 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
#endregion #endregion
} }
} }

View File

@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
z *= z; z *= z;
z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry)); z -= ((x - rx) * (x - rx)) + ((y - ry) * (y - ry));
double noise = TerrainUtil.PerlinNoise2D(x / (double) Constants.RegionSize, y / (double) Constants.RegionSize, 8, 1.0); double noise = TerrainUtil.PerlinNoise2D(x / (double) map.Width, y / (double) map.Height, 8, 1.0);
if (z > 0.0) if (z > 0.0)
map[x, y] += noise * z * duration; map[x, y] += noise * z * duration;

View File

@ -71,6 +71,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#pragma warning disable 414
private static readonly string LogHeader = "[TERRAIN MODULE]";
#pragma warning restore 414
private readonly Commander m_commander = new Commander("terrain"); private readonly Commander m_commander = new Commander("terrain");
private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects = private readonly Dictionary<StandardTerrainEffects, ITerrainFloodEffect> m_floodeffects =
@ -81,8 +85,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects = private readonly Dictionary<StandardTerrainEffects, ITerrainPaintableEffect> m_painteffects =
new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>(); new Dictionary<StandardTerrainEffects, ITerrainPaintableEffect>();
private ITerrainChannel m_channel;
private Dictionary<string, ITerrainEffect> m_plugineffects; private Dictionary<string, ITerrainEffect> m_plugineffects;
private ITerrainChannel m_channel;
private ITerrainChannel m_revert; private ITerrainChannel m_revert;
private Scene m_scene; private Scene m_scene;
private volatile bool m_tainted; private volatile bool m_tainted;
@ -90,6 +94,85 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private String m_InitialTerrain = "pinhead-island"; private String m_InitialTerrain = "pinhead-island";
// If true, send terrain patch updates to clients based on their view distance
private bool m_sendTerrainUpdatesByViewDistance = true;
// Class to keep the per client collection of terrain patches that must be sent.
// A patch is set to 'true' meaning it should be sent to the client. Once the
// patch packet is queued to the client, the bit for that patch is set to 'false'.
private class PatchUpdates
{
private bool[,] updated; // for each patch, whether it needs to be sent to this client
private int updateCount; // number of patches that need to be sent
public ScenePresence Presence; // a reference to the client to send to
public PatchUpdates(TerrainData terrData, ScenePresence pPresence)
{
updated = new bool[terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize];
updateCount = 0;
Presence = pPresence;
// Initially, send all patches to the client
SetAll(true);
}
// Returns 'true' if there are any patches marked for sending
public bool HasUpdates()
{
return (updateCount > 0);
}
public void SetByXY(int x, int y, bool state)
{
this.SetByPatch(x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, state);
}
public bool GetByPatch(int patchX, int patchY)
{
return updated[patchX, patchY];
}
public void SetByPatch(int patchX, int patchY, bool state)
{
bool prevState = updated[patchX, patchY];
if (!prevState && state)
updateCount++;
if (prevState && !state)
updateCount--;
updated[patchX, patchY] = state;
}
public void SetAll(bool state)
{
updateCount = 0;
for (int xx = 0; xx < updated.GetLength(0); xx++)
for (int yy = 0; yy < updated.GetLength(1); yy++)
updated[xx, yy] = state;
if (state)
updateCount = updated.GetLength(0) * updated.GetLength(1);
}
// Logically OR's the terrain data's patch taint map into this client's update map.
public void SetAll(TerrainData terrData)
{
if (updated.GetLength(0) != (terrData.SizeX / Constants.TerrainPatchSize)
|| updated.GetLength(1) != (terrData.SizeY / Constants.TerrainPatchSize))
{
throw new Exception(
String.Format("{0} PatchUpdates.SetAll: patch array not same size as terrain. arr=<{1},{2}>, terr=<{3},{4}>",
LogHeader, updated.GetLength(0), updated.GetLength(1),
terrData.SizeX / Constants.TerrainPatchSize, terrData.SizeY / Constants.TerrainPatchSize)
);
}
for (int xx = 0; xx < terrData.SizeX; xx += Constants.TerrainPatchSize)
{
for (int yy = 0; yy < terrData.SizeY; yy += Constants.TerrainPatchSize)
{
// Only set tainted. The patch bit may be set if the patch was to be sent later.
if (terrData.IsTaintedAt(xx, yy, false))
{
this.SetByXY(xx, yy, true);
}
}
}
}
}
// The flags of which terrain patches to send for each of the ScenePresence's
private Dictionary<UUID, PatchUpdates> m_perClientPatchUpdates = new Dictionary<UUID, PatchUpdates>();
/// <summary> /// <summary>
/// Human readable list of terrain file extensions that are supported. /// Human readable list of terrain file extensions that are supported.
/// </summary> /// </summary>
@ -118,7 +201,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
IConfig terrainConfig = config.Configs["Terrain"]; IConfig terrainConfig = config.Configs["Terrain"];
if (terrainConfig != null) if (terrainConfig != null)
{
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
m_sendTerrainUpdatesByViewDistance = terrainConfig.GetBoolean("SendTerrainUpdatesByViewDistance", m_sendTerrainUpdatesByViewDistance);
}
} }
public void AddRegion(Scene scene) public void AddRegion(Scene scene)
@ -130,22 +216,24 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
if (m_scene.Heightmap == null) if (m_scene.Heightmap == null)
{ {
m_channel = new TerrainChannel(m_InitialTerrain); m_channel = new TerrainChannel(m_InitialTerrain, (int)m_scene.RegionInfo.RegionSizeX,
(int)m_scene.RegionInfo.RegionSizeY,
(int)m_scene.RegionInfo.RegionSizeZ);
m_scene.Heightmap = m_channel; m_scene.Heightmap = m_channel;
m_revert = new TerrainChannel();
UpdateRevertMap(); UpdateRevertMap();
} }
else else
{ {
m_channel = m_scene.Heightmap; m_channel = m_scene.Heightmap;
m_revert = new TerrainChannel();
UpdateRevertMap(); UpdateRevertMap();
} }
m_scene.RegisterModuleInterface<ITerrainModule>(this); m_scene.RegisterModuleInterface<ITerrainModule>(this);
m_scene.EventManager.OnNewClient += EventManager_OnNewClient; m_scene.EventManager.OnNewClient += EventManager_OnNewClient;
m_scene.EventManager.OnClientClosed += EventManager_OnClientClosed;
m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole; m_scene.EventManager.OnPluginConsole += EventManager_OnPluginConsole;
m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick; m_scene.EventManager.OnTerrainTick += EventManager_OnTerrainTick;
m_scene.EventManager.OnFrame += EventManager_OnFrame;
} }
InstallDefaultEffects(); InstallDefaultEffects();
@ -184,8 +272,10 @@ namespace OpenSim.Region.CoreModules.World.Terrain
// remove the commands // remove the commands
m_scene.UnregisterModuleCommander(m_commander.Name); m_scene.UnregisterModuleCommander(m_commander.Name);
// remove the event-handlers // remove the event-handlers
m_scene.EventManager.OnFrame -= EventManager_OnFrame;
m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick; m_scene.EventManager.OnTerrainTick -= EventManager_OnTerrainTick;
m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole; m_scene.EventManager.OnPluginConsole -= EventManager_OnPluginConsole;
m_scene.EventManager.OnClientClosed -= EventManager_OnClientClosed;
m_scene.EventManager.OnNewClient -= EventManager_OnNewClient; m_scene.EventManager.OnNewClient -= EventManager_OnNewClient;
// remove the interface // remove the interface
m_scene.UnregisterModuleInterface<ITerrainModule>(this); m_scene.UnregisterModuleInterface<ITerrainModule>(this);
@ -230,11 +320,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
try try
{ {
ITerrainChannel channel = loader.Value.LoadFile(filename); ITerrainChannel channel = loader.Value.LoadFile(filename);
if (channel.Width != Constants.RegionSize || channel.Height != Constants.RegionSize) if (channel.Width != m_scene.RegionInfo.RegionSizeX || channel.Height != m_scene.RegionInfo.RegionSizeY)
{ {
// TerrainChannel expects a RegionSize x RegionSize map, currently // TerrainChannel expects a RegionSize x RegionSize map, currently
throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}", throw new ArgumentException(String.Format("wrong size, use a file with size {0} x {1}",
Constants.RegionSize, Constants.RegionSize)); m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY));
} }
m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height); m_log.DebugFormat("[TERRAIN]: Loaded terrain, wd/ht: {0}/{1}", channel.Width, channel.Height);
m_scene.Heightmap = channel; m_scene.Heightmap = channel;
@ -261,7 +351,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
String.Format("Unable to load heightmap: {0}", e.Message)); String.Format("Unable to load heightmap: {0}", e.Message));
} }
} }
CheckForTerrainUpdates();
m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
return; return;
} }
@ -309,12 +398,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
LoadFromStream(filename, URIFetch(pathToTerrainHeightmap)); LoadFromStream(filename, URIFetch(pathToTerrainHeightmap));
} }
public void LoadFromStream(string filename, Stream stream)
{
LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream);
}
/// <summary> /// <summary>
/// Loads a terrain file from a stream and installs it in the scene. /// Loads a terrain file from a stream and installs it in the scene.
/// </summary> /// </summary>
/// <param name="filename">Filename to terrain file. Type is determined by extension.</param> /// <param name="filename">Filename to terrain file. Type is determined by extension.</param>
/// <param name="stream"></param> /// <param name="stream"></param>
public void LoadFromStream(string filename, Stream stream) public void LoadFromStream(string filename, Vector3 displacement,
float radianRotation, Vector2 rotationDisplacement, Stream stream)
{ {
foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders) foreach (KeyValuePair<string, ITerrainLoader> loader in m_loaders)
{ {
@ -325,8 +420,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
try try
{ {
ITerrainChannel channel = loader.Value.LoadStream(stream); ITerrainChannel channel = loader.Value.LoadStream(stream);
m_scene.Heightmap = channel; m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
m_channel = channel;
UpdateRevertMap(); UpdateRevertMap();
} }
catch (NotImplementedException) catch (NotImplementedException)
@ -337,7 +431,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
} }
} }
CheckForTerrainUpdates();
m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully"); m_log.Info("[TERRAIN]: File (" + filename + ") loaded successfully");
return; return;
} }
@ -406,9 +499,46 @@ namespace OpenSim.Region.CoreModules.World.Terrain
} }
} }
// Someone diddled terrain outside the normal code paths. Set the taintedness for all clients.
// ITerrainModule.TaintTerrain()
public void TaintTerrain () public void TaintTerrain ()
{ {
CheckForTerrainUpdates(); lock (m_perClientPatchUpdates)
{
// Set the flags for all clients so the tainted patches will be sent out
foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
{
pups.SetAll(m_scene.Heightmap.GetTerrainData());
}
}
}
// ITerrainModule.PushTerrain()
public void PushTerrain(IClientAPI pClient)
{
if (m_sendTerrainUpdatesByViewDistance)
{
ScenePresence presence = m_scene.GetScenePresence(pClient.AgentId);
if (presence != null)
{
lock (m_perClientPatchUpdates)
{
PatchUpdates pups;
if (!m_perClientPatchUpdates.TryGetValue(pClient.AgentId, out pups))
{
// There is a ScenePresence without a send patch map. Create one.
pups = new PatchUpdates(m_scene.Heightmap.GetTerrainData(), presence);
m_perClientPatchUpdates.Add(presence.UUID, pups);
}
pups.SetAll(true);
}
}
}
else
{
// The traditional way is to call into the protocol stack to send them all.
pClient.SendLayerData(new float[10]);
}
} }
#region Plugin Loading Methods #region Plugin Loading Methods
@ -532,6 +662,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// </summary> /// </summary>
public void UpdateRevertMap() public void UpdateRevertMap()
{ {
/*
int x; int x;
for (x = 0; x < m_channel.Width; x++) for (x = 0; x < m_channel.Width; x++)
{ {
@ -541,6 +672,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_revert[x, y] = m_channel[x, y]; m_revert[x, y] = m_channel[x, y];
} }
} }
*/
m_revert = m_channel.MakeCopy();
} }
/// <summary> /// <summary>
@ -567,8 +700,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY, ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
fileWidth, fileHeight, fileWidth, fileHeight,
(int) Constants.RegionSize, (int) m_scene.RegionInfo.RegionSizeX,
(int) Constants.RegionSize); (int) m_scene.RegionInfo.RegionSizeY);
m_scene.Heightmap = channel; m_scene.Heightmap = channel;
m_channel = channel; m_channel = channel;
UpdateRevertMap(); UpdateRevertMap();
@ -615,8 +748,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
loader.Value.SaveFile(m_channel, filename, offsetX, offsetY, loader.Value.SaveFile(m_channel, filename, offsetX, offsetY,
fileWidth, fileHeight, fileWidth, fileHeight,
(int)Constants.RegionSize, (int)m_scene.RegionInfo.RegionSizeX,
(int)Constants.RegionSize); (int)m_scene.RegionInfo.RegionSizeY);
MainConsole.Instance.OutputFormat( MainConsole.Instance.OutputFormat(
"Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}", "Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}",
@ -633,8 +766,45 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_scene.RegionInfo.RegionName, filename, m_supportFileExtensionsForTileSave); m_scene.RegionInfo.RegionName, filename, m_supportFileExtensionsForTileSave);
} }
/// <summary>
/// Called before processing of every simulation frame.
/// This is used to check to see of any of the terrain is tainted and, if so, schedule
/// updates for all the presences.
/// This also checks to see if there are updates that need to be sent for each presence.
/// This is where the logic is to send terrain updates to clients.
/// </summary>
private void EventManager_OnFrame()
{
TerrainData terrData = m_channel.GetTerrainData();
bool shouldTaint = false;
for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
{
for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
{
if (terrData.IsTaintedAt(x, y))
{
// Found a patch that was modified. Push this flag into the clients.
SendToClients(terrData, x, y);
shouldTaint = true;
}
}
}
// This event also causes changes to be sent to the clients
CheckSendingPatchesToClients();
// If things changes, generate some events
if (shouldTaint)
{
m_scene.EventManager.TriggerTerrainTainted();
m_tainted = true;
}
}
/// <summary> /// <summary>
/// Performs updates to the region periodically, synchronising physics and other heightmap aware sections /// Performs updates to the region periodically, synchronising physics and other heightmap aware sections
/// Called infrequently (like every 5 seconds or so). Best used for storing terrain.
/// </summary> /// </summary>
private void EventManager_OnTerrainTick() private void EventManager_OnTerrainTick()
{ {
@ -644,8 +814,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised()); m_scene.PhysicsScene.SetTerrain(m_channel.GetFloatsSerialised());
m_scene.SaveTerrain(); m_scene.SaveTerrain();
m_scene.EventManager.TriggerTerrainUpdate();
// Clients who look at the map will never see changes after they looked at the map, so i've commented this out. // Clients who look at the map will never see changes after they looked at the map, so i've commented this out.
//m_scene.CreateTerrainTexture(true); //m_scene.CreateTerrainTexture(true);
} }
@ -687,54 +855,48 @@ namespace OpenSim.Region.CoreModules.World.Terrain
} }
/// <summary> /// <summary>
/// Checks to see if the terrain has been modified since last check /// Installs terrain brush hook to IClientAPI
/// but won't attempt to limit those changes to the limits specified in the estate settings
/// currently invoked by the command line operations in the region server only
/// </summary> /// </summary>
private void CheckForTerrainUpdates() /// <param name="client"></param>
private void EventManager_OnClientClosed(UUID client, Scene scene)
{ {
CheckForTerrainUpdates(false); ScenePresence presence = scene.GetScenePresence(client);
} if (presence != null)
/// <summary>
/// Checks to see if the terrain has been modified since last check.
/// If it has been modified, every all the terrain patches are sent to the client.
/// If the call is asked to respect the estate settings for terrain_raise_limit and
/// terrain_lower_limit, it will clamp terrain updates between these values
/// currently invoked by client_OnModifyTerrain only and not the Commander interfaces
/// <param name="respectEstateSettings">should height map deltas be limited to the estate settings limits</param>
/// </summary>
private void CheckForTerrainUpdates(bool respectEstateSettings)
{
bool shouldTaint = false;
float[] serialised = m_channel.GetFloatsSerialised();
int x;
for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize)
{ {
int y; presence.ControllingClient.OnModifyTerrain -= client_OnModifyTerrain;
for (y = 0; y < m_channel.Height; y += Constants.TerrainPatchSize) presence.ControllingClient.OnBakeTerrain -= client_OnBakeTerrain;
{ presence.ControllingClient.OnLandUndo -= client_OnLandUndo;
if (m_channel.Tainted(x, y)) presence.ControllingClient.OnUnackedTerrain -= client_OnUnackedTerrain;
{ }
// if we should respect the estate settings then
// fixup and height deltas that don't respect them
if (respectEstateSettings && LimitChannelChanges(x, y))
{
// this has been vetoed, so update
// what we are going to send to the client
serialised = m_channel.GetFloatsSerialised();
}
SendToClients(serialised, x, y); lock (m_perClientPatchUpdates)
shouldTaint = true; m_perClientPatchUpdates.Remove(client);
}
/// <summary>
/// Scan over changes in the terrain and limit height changes. This enforces the
/// non-estate owner limits on rate of terrain editting.
/// Returns 'true' if any heights were limited.
/// </summary>
private bool EnforceEstateLimits()
{
TerrainData terrData = m_channel.GetTerrainData();
bool wasLimited = false;
for (int x = 0; x < terrData.SizeX; x += Constants.TerrainPatchSize)
{
for (int y = 0; y < terrData.SizeY; y += Constants.TerrainPatchSize)
{
if (terrData.IsTaintedAt(x, y, false /* clearOnTest */))
{
// If we should respect the estate settings then
// fixup and height deltas that don't respect them.
// Note that LimitChannelChanges() modifies the TerrainChannel with the limited height values.
wasLimited |= LimitChannelChanges(terrData, x, y);
} }
} }
} }
if (shouldTaint) return wasLimited;
{
m_scene.EventManager.TriggerTerrainTainted();
m_tainted = true;
}
} }
/// <summary> /// <summary>
@ -742,11 +904,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// are all within the current estate limits /// are all within the current estate limits
/// <returns>true if changes were limited, false otherwise</returns> /// <returns>true if changes were limited, false otherwise</returns>
/// </summary> /// </summary>
private bool LimitChannelChanges(int xStart, int yStart) private bool LimitChannelChanges(TerrainData terrData, int xStart, int yStart)
{ {
bool changesLimited = false; bool changesLimited = false;
double minDelta = m_scene.RegionInfo.RegionSettings.TerrainLowerLimit; float minDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainLowerLimit;
double maxDelta = m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit; float maxDelta = (float)m_scene.RegionInfo.RegionSettings.TerrainRaiseLimit;
// loop through the height map for this patch and compare it against // loop through the height map for this patch and compare it against
// the revert map // the revert map
@ -754,19 +916,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++) for (int y = yStart; y < yStart + Constants.TerrainPatchSize; y++)
{ {
float requestedHeight = terrData[x, y];
double requestedHeight = m_channel[x, y]; float bakedHeight = (float)m_revert[x, y];
double bakedHeight = m_revert[x, y]; float requestedDelta = requestedHeight - bakedHeight;
double requestedDelta = requestedHeight - bakedHeight;
if (requestedDelta > maxDelta) if (requestedDelta > maxDelta)
{ {
m_channel[x, y] = bakedHeight + maxDelta; terrData[x, y] = bakedHeight + maxDelta;
changesLimited = true; changesLimited = true;
} }
else if (requestedDelta < minDelta) else if (requestedDelta < minDelta)
{ {
m_channel[x, y] = bakedHeight + minDelta; //as lower is a -ve delta terrData[x, y] = bakedHeight + minDelta; //as lower is a -ve delta
changesLimited = true; changesLimited = true;
} }
} }
@ -794,14 +955,154 @@ namespace OpenSim.Region.CoreModules.World.Terrain
/// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param> /// <param name="serialised">A copy of the terrain as a 1D float array of size w*h</param>
/// <param name="x">The patch corner to send</param> /// <param name="x">The patch corner to send</param>
/// <param name="y">The patch corner to send</param> /// <param name="y">The patch corner to send</param>
private void SendToClients(float[] serialised, int x, int y) private void SendToClients(TerrainData terrData, int x, int y)
{ {
m_scene.ForEachClient( if (m_sendTerrainUpdatesByViewDistance)
delegate(IClientAPI controller) {
{ controller.SendLayerData( // Add that this patch needs to be sent to the accounting for each client.
x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised); lock (m_perClientPatchUpdates)
{
m_scene.ForEachScenePresence(presence =>
{
PatchUpdates thisClientUpdates;
if (!m_perClientPatchUpdates.TryGetValue(presence.UUID, out thisClientUpdates))
{
// There is a ScenePresence without a send patch map. Create one.
thisClientUpdates = new PatchUpdates(terrData, presence);
m_perClientPatchUpdates.Add(presence.UUID, thisClientUpdates);
}
thisClientUpdates.SetByXY(x, y, true);
}
);
}
}
else
{
// Legacy update sending where the update is sent out as soon as noticed
// We know the actual terrain data passed is ignored. This kludge saves changing IClientAPI.
//float[] heightMap = terrData.GetFloatsSerialized();
float[] heightMap = new float[10];
m_scene.ForEachClient(
delegate(IClientAPI controller)
{
controller.SendLayerData(x / Constants.TerrainPatchSize,
y / Constants.TerrainPatchSize,
heightMap);
} }
); );
}
}
private class PatchesToSend : IComparable<PatchesToSend>
{
public int PatchX;
public int PatchY;
public float Dist;
public PatchesToSend(int pX, int pY, float pDist)
{
PatchX = pX;
PatchY = pY;
Dist = pDist;
}
public int CompareTo(PatchesToSend other)
{
return Dist.CompareTo(other.Dist);
}
}
// Called each frame time to see if there are any patches to send to any of the
// ScenePresences.
// Loop through all the per-client info and send any patches necessary.
private void CheckSendingPatchesToClients()
{
lock (m_perClientPatchUpdates)
{
foreach (PatchUpdates pups in m_perClientPatchUpdates.Values)
{
if (pups.HasUpdates())
{
// There is something that could be sent to this client.
List<PatchesToSend> toSend = GetModifiedPatchesInViewDistance(pups);
if (toSend.Count > 0)
{
// m_log.DebugFormat("{0} CheckSendingPatchesToClient: sending {1} patches to {2} in region {3}",
// LogHeader, toSend.Count, pups.Presence.Name, m_scene.RegionInfo.RegionName);
// Sort the patches to send by the distance from the presence
toSend.Sort();
/*
foreach (PatchesToSend pts in toSend)
{
pups.Presence.ControllingClient.SendLayerData(pts.PatchX, pts.PatchY, null);
// presence.ControllingClient.SendLayerData(xs.ToArray(), ys.ToArray(), null, TerrainPatch.LayerType.Land);
}
*/
int[] xPieces = new int[toSend.Count];
int[] yPieces = new int[toSend.Count];
float[] patchPieces = new float[toSend.Count * 2];
int pieceIndex = 0;
foreach (PatchesToSend pts in toSend)
{
patchPieces[pieceIndex++] = pts.PatchX;
patchPieces[pieceIndex++] = pts.PatchY;
}
pups.Presence.ControllingClient.SendLayerData(-toSend.Count, 0, patchPieces);
}
}
}
}
}
private List<PatchesToSend> GetModifiedPatchesInViewDistance(PatchUpdates pups)
{
List<PatchesToSend> ret = new List<PatchesToSend>();
ScenePresence presence = pups.Presence;
if (presence == null)
return ret;
// Compute the area of patches within our draw distance
int startX = (((int) (presence.AbsolutePosition.X - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
startX = Math.Max(startX, 0);
startX = Math.Min(startX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
int startY = (((int) (presence.AbsolutePosition.Y - presence.DrawDistance))/Constants.TerrainPatchSize) - 2;
startY = Math.Max(startY, 0);
startY = Math.Min(startY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
int endX = (((int) (presence.AbsolutePosition.X + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
endX = Math.Max(endX, 0);
endX = Math.Min(endX, (int)m_scene.RegionInfo.RegionSizeX/Constants.TerrainPatchSize);
int endY = (((int) (presence.AbsolutePosition.Y + presence.DrawDistance))/Constants.TerrainPatchSize) + 2;
endY = Math.Max(endY, 0);
endY = Math.Min(endY, (int)m_scene.RegionInfo.RegionSizeY/Constants.TerrainPatchSize);
// m_log.DebugFormat("{0} GetModifiedPatchesInViewDistance. rName={1}, ddist={2}, apos={3}, start=<{4},{5}>, end=<{6},{7}>",
// LogHeader, m_scene.RegionInfo.RegionName,
// presence.DrawDistance, presence.AbsolutePosition,
// startX, startY, endX, endY);
for (int x = startX; x < endX; x++)
{
for (int y = startY; y < endY; y++)
{
//Need to make sure we don't send the same ones over and over
Vector3 presencePos = presence.AbsolutePosition;
Vector3 patchPos = new Vector3(x * Constants.TerrainPatchSize, y * Constants.TerrainPatchSize, presencePos.Z);
if (pups.GetByPatch(x, y))
{
//Check which has less distance, camera or avatar position, both have to be done.
//Its not a radius, its a diameter and we add 50 so that it doesn't look like it cuts off
if (Util.DistanceLessThan(presencePos, patchPos, presence.DrawDistance + 50)
|| Util.DistanceLessThan(presence.CameraPosition, patchPos, presence.DrawDistance + 50))
{
//They can see it, send it to them
pups.SetByPatch(x, y, false);
float dist = Vector3.DistanceSquared(presencePos, patchPos);
ret.Add(new PatchesToSend(x, y, dist));
//Wait and send them all at once
// pups.client.SendLayerData(x, y, null);
}
}
}
}
return ret;
} }
private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action, private void client_OnModifyTerrain(UUID user, float height, float seconds, byte size, byte action,
@ -846,7 +1147,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_painteffects[(StandardTerrainEffects) action].PaintEffect( m_painteffects[(StandardTerrainEffects) action].PaintEffect(
m_channel, allowMask, west, south, height, size, seconds); m_channel, allowMask, west, south, height, size, seconds);
CheckForTerrainUpdates(!god); //revert changes outside estate limits //revert changes outside estate limits
if (!god)
EnforceEstateLimits();
} }
} }
else else
@ -884,10 +1187,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (allowed) if (allowed)
{ {
StoreUndoState(); StoreUndoState();
m_floodeffects[(StandardTerrainEffects) action].FloodEffect( m_floodeffects[(StandardTerrainEffects) action].FloodEffect(m_channel, fillArea, size);
m_channel, fillArea, size);
CheckForTerrainUpdates(!god); //revert changes outside estate limits //revert changes outside estate limits
if (!god)
EnforceEstateLimits();
} }
} }
else else
@ -911,7 +1215,9 @@ namespace OpenSim.Region.CoreModules.World.Terrain
protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY) protected void client_OnUnackedTerrain(IClientAPI client, int patchX, int patchY)
{ {
//m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY); //m_log.Debug("Terrain packet unacked, resending patch: " + patchX + " , " + patchY);
client.SendLayerData(patchX, patchY, m_scene.Heightmap.GetFloatsSerialised()); // SendLayerData does not use the heightmap parameter. This kludge is so as to not change IClientAPI.
float[] heightMap = new float[10];
client.SendLayerData(patchX, patchY, heightMap);
} }
private void StoreUndoState() private void StoreUndoState()
@ -938,7 +1244,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
private void InterfaceLoadFile(Object[] args) private void InterfaceLoadFile(Object[] args)
{ {
LoadFromFile((string) args[0]); LoadFromFile((string) args[0]);
CheckForTerrainUpdates();
} }
private void InterfaceLoadTileFile(Object[] args) private void InterfaceLoadTileFile(Object[] args)
@ -948,7 +1253,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
(int) args[2], (int) args[2],
(int) args[3], (int) args[3],
(int) args[4]); (int) args[4]);
CheckForTerrainUpdates();
} }
private void InterfaceSaveFile(Object[] args) private void InterfaceSaveFile(Object[] args)
@ -977,7 +1281,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
for (y = 0; y < m_channel.Height; y++) for (y = 0; y < m_channel.Height; y++)
m_channel[x, y] = m_revert[x, y]; m_channel[x, y] = m_revert[x, y];
CheckForTerrainUpdates();
} }
private void InterfaceFlipTerrain(Object[] args) private void InterfaceFlipTerrain(Object[] args)
@ -986,28 +1289,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (direction.ToLower().StartsWith("y")) if (direction.ToLower().StartsWith("y"))
{ {
for (int x = 0; x < Constants.RegionSize; x++) for (int x = 0; x < m_channel.Width; x++)
{ {
for (int y = 0; y < Constants.RegionSize / 2; y++) for (int y = 0; y < m_channel.Height / 2; y++)
{ {
double height = m_channel[x, y]; double height = m_channel[x, y];
double flippedHeight = m_channel[x, (int)Constants.RegionSize - 1 - y]; double flippedHeight = m_channel[x, (int)m_channel.Height - 1 - y];
m_channel[x, y] = flippedHeight; m_channel[x, y] = flippedHeight;
m_channel[x, (int)Constants.RegionSize - 1 - y] = height; m_channel[x, (int)m_channel.Height - 1 - y] = height;
} }
} }
} }
else if (direction.ToLower().StartsWith("x")) else if (direction.ToLower().StartsWith("x"))
{ {
for (int y = 0; y < Constants.RegionSize; y++) for (int y = 0; y < m_channel.Height; y++)
{ {
for (int x = 0; x < Constants.RegionSize / 2; x++) for (int x = 0; x < m_channel.Width / 2; x++)
{ {
double height = m_channel[x, y]; double height = m_channel[x, y];
double flippedHeight = m_channel[(int)Constants.RegionSize - 1 - x, y]; double flippedHeight = m_channel[(int)m_channel.Width - 1 - x, y];
m_channel[x, y] = flippedHeight; m_channel[x, y] = flippedHeight;
m_channel[(int)Constants.RegionSize - 1 - x, y] = height; m_channel[(int)m_channel.Width - 1 - x, y] = height;
} }
} }
@ -1016,9 +1319,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
{ {
m_log.Error("Unrecognised direction - need x or y"); m_log.Error("Unrecognised direction - need x or y");
} }
CheckForTerrainUpdates();
} }
private void InterfaceRescaleTerrain(Object[] args) private void InterfaceRescaleTerrain(Object[] args)
@ -1076,7 +1376,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
} }
} }
CheckForTerrainUpdates();
} }
} }
@ -1087,7 +1386,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
for (x = 0; x < m_channel.Width; x++) for (x = 0; x < m_channel.Width; x++)
for (y = 0; y < m_channel.Height; y++) for (y = 0; y < m_channel.Height; y++)
m_channel[x, y] += (double) args[0]; m_channel[x, y] += (double) args[0];
CheckForTerrainUpdates();
} }
private void InterfaceMultiplyTerrain(Object[] args) private void InterfaceMultiplyTerrain(Object[] args)
@ -1096,7 +1394,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
for (x = 0; x < m_channel.Width; x++) for (x = 0; x < m_channel.Width; x++)
for (y = 0; y < m_channel.Height; y++) for (y = 0; y < m_channel.Height; y++)
m_channel[x, y] *= (double) args[0]; m_channel[x, y] *= (double) args[0];
CheckForTerrainUpdates();
} }
private void InterfaceLowerTerrain(Object[] args) private void InterfaceLowerTerrain(Object[] args)
@ -1105,17 +1402,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
for (x = 0; x < m_channel.Width; x++) for (x = 0; x < m_channel.Width; x++)
for (y = 0; y < m_channel.Height; y++) for (y = 0; y < m_channel.Height; y++)
m_channel[x, y] -= (double) args[0]; m_channel[x, y] -= (double) args[0];
CheckForTerrainUpdates();
} }
private void InterfaceFillTerrain(Object[] args) public void InterfaceFillTerrain(Object[] args)
{ {
int x, y; int x, y;
for (x = 0; x < m_channel.Width; x++) for (x = 0; x < m_channel.Width; x++)
for (y = 0; y < m_channel.Height; y++) for (y = 0; y < m_channel.Height; y++)
m_channel[x, y] = (double) args[0]; m_channel[x, y] = (double) args[0];
CheckForTerrainUpdates();
} }
private void InterfaceMinTerrain(Object[] args) private void InterfaceMinTerrain(Object[] args)
@ -1128,7 +1423,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]); m_channel[x, y] = Math.Max((double)args[0], m_channel[x, y]);
} }
} }
CheckForTerrainUpdates();
} }
private void InterfaceMaxTerrain(Object[] args) private void InterfaceMaxTerrain(Object[] args)
@ -1141,7 +1435,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]); m_channel[x, y] = Math.Min((double)args[0], m_channel[x, y]);
} }
} }
CheckForTerrainUpdates();
} }
private void InterfaceShowDebugStats(Object[] args) private void InterfaceShowDebugStats(Object[] args)
@ -1204,7 +1497,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain
if (m_plugineffects.ContainsKey(firstArg)) if (m_plugineffects.ContainsKey(firstArg))
{ {
m_plugineffects[firstArg].RunEffect(m_channel); m_plugineffects[firstArg].RunEffect(m_channel);
CheckForTerrainUpdates();
} }
else else
{ {

View File

@ -40,10 +40,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
[Test] [Test]
public void BrushTest() public void BrushTest()
{ {
int midRegion = (int)Constants.RegionSize / 2;
// Create a mask that covers only the left half of the region
bool[,] allowMask = new bool[(int)Constants.RegionSize, 256]; bool[,] allowMask = new bool[(int)Constants.RegionSize, 256];
int x; int x;
int y; int y;
for (x = 0; x < (int)((int)Constants.RegionSize * 0.5f); x++) for (x = 0; x < midRegion; x++)
{ {
for (y = 0; y < (int)Constants.RegionSize; y++) for (y = 0; y < (int)Constants.RegionSize; y++)
{ {
@ -57,13 +60,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize); TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize);
ITerrainPaintableEffect effect = new RaiseSphere(); ITerrainPaintableEffect effect = new RaiseSphere();
effect.PaintEffect(map, allowMask, (int)Constants.RegionSize * 0.5f, (int)Constants.RegionSize * 0.5f, -1.0, 2, 0.1); effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (127,128)."); Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128).");
Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] > 0.0, "Raise brush should raising value at this point (124,128)."); Assert.That(map[125, midRegion] > 0.0, "Raise brush should raising value at this point (124,128).");
Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (123,128)."); Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128).");
Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (128,128)."); Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128).");
Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Raise brush should not change value at this point (0,128)."); Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128).");
// //
// Test LowerSphere // Test LowerSphere
// //
@ -77,13 +79,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
} }
effect = new LowerSphere(); effect = new LowerSphere();
effect.PaintEffect(map, allowMask, ((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), -1.0, 2, 6.0); effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128)."); Assert.That(map[127, midRegion] >= 0.0, "Lower should not lowering value below 0.0 at this point (127,128).");
Assert.That(map[127, (int)((int)Constants.RegionSize * 0.5f)] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128)."); Assert.That(map[127, midRegion] == 0.0, "Lower brush should lowering value to 0.0 at this point (127,128).");
Assert.That(map[124, (int)((int)Constants.RegionSize * 0.5f)] < 1.0, "Lower brush should lowering value at this point (124,128)."); Assert.That(map[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128).");
Assert.That(map[123, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (123,128)."); Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128).");
Assert.That(map[128, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (128,128)."); Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128).");
Assert.That(map[0, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (0,128)."); Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128).");
} }
[Test] [Test]

View File

@ -55,5 +55,10 @@ namespace OpenSim.Region.Framework.Interfaces
/// Currently, will throw an exception if this does not match a root region. /// Currently, will throw an exception if this does not match a root region.
/// </param> /// </param>
Vector2 GetSizeOfMegaregion(UUID regionId); Vector2 GetSizeOfMegaregion(UUID regionId);
/// <summary>
/// Tests to see of position (relative to the region) is within the megaregion
/// </summary>
bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy);
} }
} }

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);
@ -136,4 +145,5 @@ namespace OpenSim.Region.Framework.Interfaces
void Shutdown(); void Shutdown();
} }
} }

View File

@ -25,13 +25,23 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using OpenSim.Framework;
using OpenMetaverse;
namespace OpenSim.Region.Framework.Interfaces namespace OpenSim.Region.Framework.Interfaces
{ {
public interface ITerrainChannel public interface ITerrainChannel
{ {
int Height { get; } int Width { get;} // X dimension
int Height { get;} // Y dimension
int Altitude { get;} // Z dimension
double this[int x, int y] { get; set; } double this[int x, int y] { get; set; }
int Width { get; }
float GetHeightAtXYZ(float x, float y, float z);
// Return the packaged terrain data for passing into lower levels of communication
TerrainData GetTerrainData();
/// <summary> /// <summary>
/// Squash the entire heightmap into a single dimensioned array /// Squash the entire heightmap into a single dimensioned array
@ -40,9 +50,14 @@ namespace OpenSim.Region.Framework.Interfaces
float[] GetFloatsSerialised(); float[] GetFloatsSerialised();
double[,] GetDoubles(); double[,] GetDoubles();
// Check if a location has been updated. Clears the taint flag as a side effect.
bool Tainted(int x, int y); bool Tainted(int x, int y);
ITerrainChannel MakeCopy(); ITerrainChannel MakeCopy();
string SaveToXmlString(); string SaveToXmlString();
void LoadFromXmlString(string data); void LoadFromXmlString(string data);
// Merge some terrain into this channel
void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement);
} }
} }

View File

@ -2221,14 +2221,9 @@ namespace OpenSim.Region.Framework.Scenes
itemID = UUID.Zero; itemID = UUID.Zero;
if (grp != null) if (grp != null)
{ {
Vector3 inventoryStoredPosition = new Vector3 Vector3 inventoryStoredPosition = new Vector3(
(((grp.AbsolutePosition.X > (int)Constants.RegionSize) Math.Min(grp.AbsolutePosition.X, RegionInfo.RegionSizeX - 6),
? 250 Math.Min(grp.AbsolutePosition.Y, RegionInfo.RegionSizeY - 6),
: grp.AbsolutePosition.X)
,
(grp.AbsolutePosition.X > (int)Constants.RegionSize)
? 250
: grp.AbsolutePosition.X,
grp.AbsolutePosition.Z); grp.AbsolutePosition.Z);
Vector3 originalPosition = grp.AbsolutePosition; Vector3 originalPosition = grp.AbsolutePosition;

View File

@ -6,7 +6,7 @@
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright * * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer. * notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyrightD * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the * * Neither the name of the OpenSimulator Project nor the
@ -103,7 +103,29 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// If false then physical objects are disabled, though collisions will continue as normal. /// If false then physical objects are disabled, though collisions will continue as normal.
/// </summary> /// </summary>
public bool PhysicsEnabled { get; set; } public bool PhysicsEnabled
{
get
{
return m_physicsEnabled;
}
set
{
m_physicsEnabled = value;
if (PhysicsScene != null)
{
IPhysicsParameters physScene = PhysicsScene as IPhysicsParameters;
if (physScene != null)
physScene.SetPhysicsParameter(
"Active", m_physicsEnabled.ToString(), PhysParameterEntry.APPLY_TO_NONE);
}
}
}
private bool m_physicsEnabled;
/// <summary> /// <summary>
/// If false then scripts are not enabled on the smiulator /// If false then scripts are not enabled on the smiulator
@ -160,11 +182,6 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
public SimStatsReporter StatsReporter { get; private set; } public SimStatsReporter StatsReporter { get; private set; }
public List<Border> NorthBorders = new List<Border>();
public List<Border> EastBorders = new List<Border>();
public List<Border> SouthBorders = new List<Border>();
public List<Border> WestBorders = new List<Border>();
/// <summary> /// <summary>
/// Controls whether physics can be applied to prims. Even if false, prims still have entries in a /// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
/// PhysicsScene in order to perform collision detection /// PhysicsScene in order to perform collision detection
@ -204,15 +221,16 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
public int m_linksetCapacity = 0; public int m_linksetCapacity = 0;
public bool m_clampPrimSize;
public bool m_trustBinaries;
public bool m_allowScriptCrossings = true;
/// <summary> /// <summary>
/// Max prims an Physical object will hold /// Max prims an Physical object will hold
/// </summary> /// </summary>
/// ///
public int m_linksetPhysCapacity = 0; public int m_linksetPhysCapacity = 0;
public bool m_clampPrimSize;
public bool m_trustBinaries;
public bool m_allowScriptCrossings;
public bool m_useFlySlow; public bool m_useFlySlow;
public bool m_useTrashOnDelete = true; public bool m_useTrashOnDelete = true;
@ -364,7 +382,6 @@ namespace OpenSim.Region.Framework.Scenes
// TODO: Possibly stop other classes being able to manipulate this directly. // TODO: Possibly stop other classes being able to manipulate this directly.
private SceneGraph m_sceneGraph; private SceneGraph m_sceneGraph;
private volatile int m_bordersLocked;
private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
private volatile bool m_backingup; private volatile bool m_backingup;
private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>(); private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
@ -446,18 +463,6 @@ namespace OpenSim.Region.Framework.Scenes
set { m_splitRegionID = value; } set { m_splitRegionID = value; }
} }
public bool BordersLocked
{
get { return m_bordersLocked == 1; }
set
{
if (value == true)
m_bordersLocked = 1;
else
m_bordersLocked = 0;
}
}
public new float TimeDilation public new float TimeDilation
{ {
get { return m_sceneGraph.PhysicsScene.TimeDilation; } get { return m_sceneGraph.PhysicsScene.TimeDilation; }
@ -1075,28 +1080,6 @@ namespace OpenSim.Region.Framework.Scenes
PeriodicBackup = true; PeriodicBackup = true;
UseBackup = true; UseBackup = true;
BordersLocked = true;
Border northBorder = new Border();
northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeY); //<---
northBorder.CrossDirection = Cardinals.N;
NorthBorders.Add(northBorder);
Border southBorder = new Border();
southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
southBorder.CrossDirection = Cardinals.S;
SouthBorders.Add(southBorder);
Border eastBorder = new Border();
eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, RegionInfo.RegionSizeX); //<---
eastBorder.CrossDirection = Cardinals.E;
EastBorders.Add(eastBorder);
Border westBorder = new Border();
westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,0); //--->
westBorder.CrossDirection = Cardinals.W;
WestBorders.Add(westBorder);
BordersLocked = false;
m_eventManager = new EventManager(); m_eventManager = new EventManager();
m_permissions = new ScenePermissions(this); m_permissions = new ScenePermissions(this);
@ -1975,7 +1958,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
@ -1986,7 +1969,7 @@ namespace OpenSim.Region.Framework.Scenes
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain); m_InitialTerrain = terrainConfig.GetString("InitialTerrain", m_InitialTerrain);
m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain); m_log.InfoFormat("[TERRAIN]: No default terrain. Generating a new terrain {0}.", m_InitialTerrain);
Heightmap = new TerrainChannel(m_InitialTerrain); Heightmap = new TerrainChannel(m_InitialTerrain, (int)RegionInfo.RegionSizeX, (int)RegionInfo.RegionSizeY, (int)RegionInfo.RegionSizeZ);
SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID); SimulationDataService.StoreTerrain(Heightmap.GetDoubles(), RegionInfo.RegionID);
} }
@ -2611,185 +2594,35 @@ namespace OpenSim.Region.Framework.Scenes
EntityTransferModule.Cross(grp, attemptedPosition, silent); EntityTransferModule.Cross(grp, attemptedPosition, silent);
} }
public Border GetCrossedBorder(Vector3 position, Cardinals gridline) // Simple test to see if a position is in the current region.
// This test is mostly used to see if a region crossing is necessary.
// Assuming the position is relative to the region so anything outside its bounds.
// Return 'true' if position inside region.
public bool PositionIsInCurrentRegion(Vector3 pos)
{ {
if (BordersLocked) bool ret = false;
int xx = (int)Math.Floor(pos.X);
int yy = (int)Math.Floor(pos.Y);
if (xx < 0 || yy < 0)
return false;
IRegionCombinerModule regionCombinerModule = RequestModuleInterface<IRegionCombinerModule>();
if (regionCombinerModule == null)
{ {
switch (gridline) // Regular region. Just check for region size
{ if (xx < RegionInfo.RegionSizeX && yy < RegionInfo.RegionSizeY )
case Cardinals.N: ret = true;
lock (NorthBorders)
{
foreach (Border b in NorthBorders)
{
if (b.TestCross(position))
return b;
}
}
break;
case Cardinals.S:
lock (SouthBorders)
{
foreach (Border b in SouthBorders)
{
if (b.TestCross(position))
return b;
}
}
break;
case Cardinals.E:
lock (EastBorders)
{
foreach (Border b in EastBorders)
{
if (b.TestCross(position))
return b;
}
}
break;
case Cardinals.W:
lock (WestBorders)
{
foreach (Border b in WestBorders)
{
if (b.TestCross(position))
return b;
}
}
break;
}
} }
else else
{ {
switch (gridline) // We're in a mega-region so see if we are still in that larger region
{ ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
case Cardinals.N:
foreach (Border b in NorthBorders)
{
if (b.TestCross(position))
return b;
}
break;
case Cardinals.S:
foreach (Border b in SouthBorders)
{
if (b.TestCross(position))
return b;
}
break;
case Cardinals.E:
foreach (Border b in EastBorders)
{
if (b.TestCross(position))
return b;
}
break;
case Cardinals.W:
foreach (Border b in WestBorders)
{
if (b.TestCross(position))
return b;
}
break;
}
} }
return null; return ret;
} }
public bool TestBorderCross(Vector3 position, Cardinals border)
{
if (BordersLocked)
{
switch (border)
{
case Cardinals.N:
lock (NorthBorders)
{
foreach (Border b in NorthBorders)
{
if (b.TestCross(position))
return true;
}
}
break;
case Cardinals.E:
lock (EastBorders)
{
foreach (Border b in EastBorders)
{
if (b.TestCross(position))
return true;
}
}
break;
case Cardinals.S:
lock (SouthBorders)
{
foreach (Border b in SouthBorders)
{
if (b.TestCross(position))
return true;
}
}
break;
case Cardinals.W:
lock (WestBorders)
{
foreach (Border b in WestBorders)
{
if (b.TestCross(position))
return true;
}
}
break;
}
}
else
{
switch (border)
{
case Cardinals.N:
foreach (Border b in NorthBorders)
{
if (b.TestCross(position))
return true;
}
break;
case Cardinals.E:
foreach (Border b in EastBorders)
{
if (b.TestCross(position))
return true;
}
break;
case Cardinals.S:
foreach (Border b in SouthBorders)
{
if (b.TestCross(position))
return true;
}
break;
case Cardinals.W:
foreach (Border b in WestBorders)
{
if (b.TestCross(position))
return true;
}
break;
}
}
return false;
}
/// <summary> /// <summary>
/// Called when objects or attachments cross the border, or teleport, between regions. /// Called when objects or attachments cross the border, or teleport, between regions.
/// </summary> /// </summary>
@ -4116,60 +3949,11 @@ namespace OpenSim.Region.Framework.Scenes
{ {
// CleanDroppedAttachments(); // CleanDroppedAttachments();
if (TestBorderCross(acd.startpos, Cardinals.E)) // Make sure avatar position is in the region (why it wouldn't be is a mystery but do sanity checking)
{ if (acd.startpos.X < 0) acd.startpos.X = 1f;
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E); if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
acd.startpos.X = crossedBorder.BorderLine.Z - 1; if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
} if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
if (TestBorderCross(acd.startpos, Cardinals.N))
{
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
}
//Mitigate http://opensimulator.org/mantis/view.php?id=3522
// Check if start position is outside of region
// If it is, check the Z start position also.. if not, leave it alone.
if (BordersLocked)
{
lock (EastBorders)
{
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
{
m_log.Warn("FIX AGENT POSITION");
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (acd.startpos.Z > 720)
acd.startpos.Z = 720;
}
}
lock (NorthBorders)
{
if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
{
m_log.Warn("FIX Agent POSITION");
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (acd.startpos.Z > 720)
acd.startpos.Z = 720;
}
}
} else
{
if (acd.startpos.X > EastBorders[0].BorderLine.Z)
{
m_log.Warn("FIX AGENT POSITION");
acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
if (acd.startpos.Z > 720)
acd.startpos.Z = 720;
}
if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
{
m_log.Warn("FIX Agent POSITION");
acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
if (acd.startpos.Z > 720)
acd.startpos.Z = 720;
}
}
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}", // "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
@ -4883,44 +4667,6 @@ namespace OpenSim.Region.Framework.Scenes
ScenePresence sp = GetScenePresence(remoteClient.AgentId); ScenePresence sp = GetScenePresence(remoteClient.AgentId);
if (sp != null) if (sp != null)
{ {
uint regionX = RegionInfo.RegionLocX;
uint regionY = RegionInfo.RegionLocY;
Utils.LongToUInts(regionHandle, out regionX, out regionY);
int shiftx = (int) regionX - (int) RegionInfo.RegionLocX * (int)Constants.RegionSize;
int shifty = (int) regionY - (int) RegionInfo.RegionLocY * (int)Constants.RegionSize;
position.X += shiftx;
position.Y += shifty;
bool result = false;
if (TestBorderCross(position,Cardinals.N))
result = true;
if (TestBorderCross(position, Cardinals.S))
result = true;
if (TestBorderCross(position, Cardinals.E))
result = true;
if (TestBorderCross(position, Cardinals.W))
result = true;
// bordercross if position is outside of region
if (!result)
{
regionHandle = RegionInfo.RegionHandle;
}
else
{
// not in this region, undo the shift!
position.X -= shiftx;
position.Y -= shifty;
}
if (EntityTransferModule != null) if (EntityTransferModule != null)
{ {
EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags); EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);

View File

@ -52,6 +52,7 @@ namespace OpenSim.Region.Framework.Scenes
public class SceneCommunicationService //one instance per region public class SceneCommunicationService //one instance per region
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static string LogHeader = "[SCENE COMMUNICATION SERVICE]";
protected RegionInfo m_regionInfo; protected RegionInfo m_regionInfo;
protected Scene m_scene; protected Scene m_scene;
@ -100,7 +101,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
m_log.WarnFormat( m_log.WarnFormat(
"[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.", "[SCENE COMMUNICATION SERVICE]: Region {0} failed to inform neighbour at {1}-{2} that it is up.",
m_scene.Name, x / Constants.RegionSize, y / Constants.RegionSize); m_scene.Name, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
} }
} }
@ -166,7 +167,7 @@ namespace OpenSim.Region.Framework.Scenes
// we only want to send one update to each simulator; the simulator will // we only want to send one update to each simulator; the simulator will
// hand it off to the regions where a child agent exists, this does assume // hand it off to the regions where a child agent exists, this does assume
// that the region position is cached or performance will degrade // that the region position is cached or performance will degrade
Utils.LongToUInts(regionHandle, out x, out y); Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y); GridRegion dest = m_scene.GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y);
if (dest == null) if (dest == null)
continue; continue;
@ -206,7 +207,7 @@ namespace OpenSim.Region.Framework.Scenes
//m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID); //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
uint x = 0, y = 0; uint x = 0, y = 0;
Utils.LongToUInts(regionHandle, out x, out y); Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y); GridRegion destination = m_scene.GridService.GetRegionByPosition(m_regionInfo.ScopeID, (int)x, (int)y);
@ -226,6 +227,8 @@ namespace OpenSim.Region.Framework.Scenes
{ {
foreach (ulong handle in regionslst) foreach (ulong handle in regionslst)
{ {
// We must take a copy here since handle acts like a reference when used in an iterator.
// This leads to race conditions if directly passed to SendCloseChildAgent with more than one neighbour region.
ulong handleCopy = handle; ulong handleCopy = handle;
Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); }); Util.FireAndForget((o) => { SendCloseChildAgent(agentID, handleCopy, auth_code); });
} }

View File

@ -412,7 +412,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
get get
{ {
Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
Vector3 maxScale = Vector3.Zero; Vector3 maxScale = Vector3.Zero;
Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
@ -529,12 +529,10 @@ namespace OpenSim.Region.Framework.Scenes
set set
{ {
Vector3 val = value; Vector3 val = value;
if (Scene != null && !IsAttachmentCheckFull() if (Scene != null
&& !Scene.LoadingPrims && && Scene.PositionIsInCurrentRegion(val)
(Scene.TestBorderCross(val, Cardinals.E) || && !IsAttachmentCheckFull()
Scene.TestBorderCross(val, Cardinals.W) || && !Scene.LoadingPrims
Scene.TestBorderCross(val, Cardinals.N) ||
Scene.TestBorderCross(val, Cardinals.S))
) )
{ {
if (!inTransit) if (!inTransit)

View File

@ -2979,10 +2979,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0); Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0);
if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N) if (!ParentGroup.Scene.PositionIsInCurrentRegion(newpos))
|| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
|| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
|| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
{ {
ParentGroup.AbsolutePosition = newpos; ParentGroup.AbsolutePosition = newpos;
return; return;

View File

@ -842,9 +842,8 @@ namespace OpenSim.Region.Framework.Scenes
foreach (ulong handle in seeds.Keys) foreach (ulong handle in seeds.Keys)
{ {
uint x, y; uint x, y;
Utils.LongToUInts(handle, out x, out y); Util.RegionHandleToRegionLoc(handle, out x, out y);
x = x / Constants.RegionSize;
y = y / Constants.RegionSize;
if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY)) if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
{ {
old.Add(handle); old.Add(handle);
@ -866,9 +865,7 @@ namespace OpenSim.Region.Framework.Scenes
foreach (KeyValuePair<ulong, string> kvp in KnownRegions) foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
{ {
uint x, y; uint x, y;
Utils.LongToUInts(kvp.Key, out x, out y); Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
x = x / Constants.RegionSize;
y = y / Constants.RegionSize;
m_log.Info(" >> "+x+", "+y+": "+kvp.Value); m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
} }
} }
@ -1170,18 +1167,6 @@ namespace OpenSim.Region.Framework.Scenes
if (ParentID == 0) if (ParentID == 0)
{ {
if (m_scene.TestBorderCross(pos, Cardinals.E))
{
Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
pos.X = crossedBorder.BorderLine.Z - 1;
}
if (m_scene.TestBorderCross(pos, Cardinals.N))
{
Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
pos.Y = crossedBorder.BorderLine.Z - 1;
}
CheckAndAdjustLandingPoint(ref pos); CheckAndAdjustLandingPoint(ref pos);
if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f) if (pos.X < 0f || pos.Y < 0f || pos.Z < 0f)
@ -1201,7 +1186,7 @@ namespace OpenSim.Region.Framework.Scenes
float posZLimit = 0; float posZLimit = 0;
if (pos.X < Constants.RegionSize && pos.Y < Constants.RegionSize) if (pos.X < m_scene.RegionInfo.RegionSizeX && pos.Y < m_scene.RegionInfo.RegionSizeY)
posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y]; posZLimit = (float)m_scene.Heightmap[(int)pos.X, (int)pos.Y];
float newPosZ = posZLimit + localAVHeight / 2; float newPosZ = posZLimit + localAVHeight / 2;
@ -2612,7 +2597,7 @@ namespace OpenSim.Region.Framework.Scenes
if (regionCombinerModule != null) if (regionCombinerModule != null)
regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID); regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
else else
regionSize = new Vector2(Constants.RegionSize); regionSize = new Vector2(m_scene.RegionInfo.RegionSizeX, m_scene.RegionInfo.RegionSizeY);
if (pos.X < 0 || pos.X >= regionSize.X if (pos.X < 0 || pos.X >= regionSize.X
|| pos.Y < 0 || pos.Y >= regionSize.Y || pos.Y < 0 || pos.Y >= regionSize.Y
@ -2630,8 +2615,8 @@ namespace OpenSim.Region.Framework.Scenes
// } // }
// Get terrain height for sub-region in a megaregion if necessary // Get terrain height for sub-region in a megaregion if necessary
int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X); int X = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y); int Y = (int)((m_scene.RegionInfo.WorldLocY) + pos.Y);
GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y); GridRegion target_region = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, X, Y);
// If X and Y is NaN, target_region will be null // If X and Y is NaN, target_region will be null
if (target_region == null) if (target_region == null)
@ -2642,7 +2627,7 @@ namespace OpenSim.Region.Framework.Scenes
if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene)) if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
targetScene = m_scene; targetScene = m_scene;
float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % Constants.RegionSize), (int)(pos.Y % Constants.RegionSize)]; float terrainHeight = (float)targetScene.Heightmap[(int)(pos.X % regionSize.X), (int)(pos.Y % regionSize.Y)];
// dont try to land underground // dont try to land underground
terrainHeight += Appearance.AvatarHeight / 2; terrainHeight += Appearance.AvatarHeight / 2;
pos.Z = Math.Max(terrainHeight, pos.Z); pos.Z = Math.Max(terrainHeight, pos.Z);
@ -3872,32 +3857,28 @@ namespace OpenSim.Region.Framework.Scenes
// m_log.DebugFormat( // m_log.DebugFormat(
// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}", // "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
// pos2, Name, Scene.Name); // pos2, Name, Scene.Name);
if( Scene.TestBorderCross(pos2, Cardinals.E) || if (Scene.PositionIsInCurrentRegion(pos2))
Scene.TestBorderCross(pos2, Cardinals.W) || return;
Scene.TestBorderCross(pos2, Cardinals.N) ||
Scene.TestBorderCross(pos2, Cardinals.S) if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero)
)
{ {
if (!CrossToNewRegion() && m_requestedSitTargetUUID == UUID.Zero) // we don't have entity transfer module
{ Vector3 pos = AbsolutePosition;
// we don't have entity transfer module float px = pos.X;
Vector3 pos = AbsolutePosition; if (px < 0)
float px = pos.X; pos.X += Velocity.X * 2;
if (px < 0) else if (px > m_scene.RegionInfo.RegionSizeX)
pos.X += Velocity.X * 2; pos.X -= Velocity.X * 2;
else if (px > m_scene.RegionInfo.RegionSizeX)
pos.X -= Velocity.X * 2;
float py = pos.Y; float py = pos.Y;
if (py < 0) if (py < 0)
pos.Y += Velocity.Y * 2; pos.Y += Velocity.Y * 2;
else if (py > m_scene.RegionInfo.RegionSizeY) else if (py > m_scene.RegionInfo.RegionSizeY)
pos.Y -= Velocity.Y * 2; pos.Y -= Velocity.Y * 2;
Velocity = Vector3.Zero; Velocity = Vector3.Zero;
AbsolutePosition = pos; AbsolutePosition = pos;
}
} }
} }
@ -3962,7 +3943,7 @@ namespace OpenSim.Region.Framework.Scenes
// Put the child agent back at the center // Put the child agent back at the center
AbsolutePosition AbsolutePosition
= new Vector3(((float)Constants.RegionSize * 0.5f), ((float)Constants.RegionSize * 0.5f), 70); = new Vector3(((float)m_scene.RegionInfo.RegionSizeX * 0.5f), ((float)m_scene.RegionInfo.RegionSizeY * 0.5f), 70);
Animator.ResetAnimations(); Animator.ResetAnimations();
} }
@ -3989,9 +3970,7 @@ namespace OpenSim.Region.Framework.Scenes
if (handle != Scene.RegionInfo.RegionHandle) if (handle != Scene.RegionInfo.RegionHandle)
{ {
uint x, y; uint x, y;
Utils.LongToUInts(handle, out x, out y); Util.RegionHandleToRegionLoc(handle, out x, out y);
x = x / Constants.RegionSize;
y = y / Constants.RegionSize;
// m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX))); // m_log.Debug("---> x: " + x + "; newx:" + newRegionX + "; Abs:" + (int)Math.Abs((int)(x - newRegionX)));
// m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY))); // m_log.Debug("---> y: " + y + "; newy:" + newRegionY + "; Abs:" + (int)Math.Abs((int)(y - newRegionY)));

View File

@ -25,13 +25,20 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.IO;
using System.Text;
using System.Reflection;
using System.Xml;
using System.Xml.Serialization;
using OpenSim.Data;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Interfaces;
using System;
using System.Text; using OpenMetaverse;
using System.Xml;
using System.IO; using log4net;
using System.Xml.Serialization;
namespace OpenSim.Region.Framework.Scenes namespace OpenSim.Region.Framework.Scenes
{ {
@ -40,140 +47,136 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary> /// </summary>
public class TerrainChannel : ITerrainChannel public class TerrainChannel : ITerrainChannel
{ {
private readonly bool[,] taint; private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private double[,] map; private static string LogHeader = "[TERRAIN CHANNEL]";
protected TerrainData m_terrainData;
public int Width { get { return m_terrainData.SizeX; } } // X dimension
// Unfortunately, for historical reasons, in this module 'Width' is X and 'Height' is Y
public int Height { get { return m_terrainData.SizeY; } } // Y dimension
public int Altitude { get { return m_terrainData.SizeZ; } } // Y dimension
// Default, not-often-used builder
public TerrainChannel() public TerrainChannel()
{ {
map = new double[Constants.RegionSize, Constants.RegionSize]; m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; FlatLand();
// PinHeadIsland();
PinHeadIsland();
} }
public TerrainChannel(String type) // Create terrain of given size
public TerrainChannel(int pX, int pY)
{ {
map = new double[Constants.RegionSize, Constants.RegionSize]; m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16]; }
// Create terrain of specified size and initialize with specified terrain.
// TODO: join this with the terrain initializers.
public TerrainChannel(String type, int pX, int pY, int pZ)
{
m_terrainData = new HeightmapTerrainData(pX, pY, pZ);
if (type.Equals("flat")) if (type.Equals("flat"))
FlatLand(); FlatLand();
else else
PinHeadIsland(); PinHeadIsland();
} }
public TerrainChannel(double[,] import) // 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)
{ {
map = import; int hmSizeX = pM.GetLength(0);
taint = new bool[import.GetLength(0),import.GetLength(1)]; 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(bool createMap) public TerrainChannel(TerrainData pTerrData)
{ {
if (createMap) m_terrainData = pTerrData;
{
map = new double[Constants.RegionSize,Constants.RegionSize];
taint = new bool[Constants.RegionSize / 16,Constants.RegionSize / 16];
}
}
public TerrainChannel(int w, int h)
{
map = new double[w,h];
taint = new bool[w / 16,h / 16];
} }
#region ITerrainChannel Members #region ITerrainChannel Members
public int Width // ITerrainChannel.MakeCopy()
{
get { return map.GetLength(0); }
}
public int Height
{
get { return map.GetLength(1); }
}
public ITerrainChannel MakeCopy() public ITerrainChannel MakeCopy()
{ {
TerrainChannel copy = new TerrainChannel(false); return this.Copy();
copy.map = (double[,]) map.Clone();
return copy;
} }
// ITerrainChannel.GetTerrainData()
public TerrainData GetTerrainData()
{
return m_terrainData;
}
// ITerrainChannel.GetFloatsSerialized()
// This one dimensional version is ordered so height = map[y*sizeX+x];
// DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
// and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
public float[] GetFloatsSerialised() public float[] GetFloatsSerialised()
{ {
// Move the member variables into local variables, calling return m_terrainData.GetFloatsSerialized();
// member variables 256*256 times gets expensive }
int w = Width;
int h = Height; // ITerrainChannel.GetDoubles()
float[] heights = new float[w * h]; public double[,] GetDoubles()
{
double[,] heights = new double[Width, Height];
int i, j; // map coordinates
int idx = 0; // index into serialized array int idx = 0; // index into serialized array
for (i = 0; i < h; i++) for (int ii = 0; ii < Width; ii++)
{ {
for (j = 0; j < w; j++) for (int jj = 0; jj < Height; jj++)
{ {
heights[idx++] = (float)map[j, i]; heights[ii, jj] = (double)m_terrainData[ii, jj];
idx++;
} }
} }
return heights; return heights;
} }
public double[,] GetDoubles() // ITerrainChannel.this[x,y]
{
return map;
}
public double this[int x, int y] public double this[int x, int y]
{ {
get get {
{ if (x < 0 || x >= Width || y < 0 || y >= Height)
if (x < 0) x = 0; return 0;
if (y < 0) y = 0; return (double)m_terrainData[x, y];
if (x >= (int)Constants.RegionSize) x = (int)Constants.RegionSize - 1;
if (y >= (int)Constants.RegionSize) y = (int)Constants.RegionSize - 1;
return map[x, y];
} }
set set
{ {
// Will "fix" terrain hole problems. Although not fantastically.
if (Double.IsNaN(value) || Double.IsInfinity(value)) if (Double.IsNaN(value) || Double.IsInfinity(value))
return; return;
if (map[x, y] != value) m_terrainData[x, y] = (float)value;
{
taint[x / 16, y / 16] = true;
map[x, y] = value;
}
} }
} }
// ITerrainChannel.GetHieghtAtXYZ(x, y, z)
public float GetHeightAtXYZ(float x, float y, float z)
{
if (x < 0 || x >= Width || y < 0 || y >= Height)
return 0;
return m_terrainData[(int)x, (int)y];
}
// ITerrainChannel.Tainted()
public bool Tainted(int x, int y) public bool Tainted(int x, int y)
{ {
if (taint[x / 16, y / 16]) return m_terrainData.IsTaintedAt(x, y);
{
taint[x / 16, y / 16] = false;
return true;
}
return false;
}
#endregion
public TerrainChannel Copy()
{
TerrainChannel copy = new TerrainChannel(false);
copy.map = (double[,]) map.Clone();
return copy;
} }
// ITerrainChannel.SaveToXmlString()
public string SaveToXmlString() public string SaveToXmlString()
{ {
XmlWriterSettings settings = new XmlWriterSettings(); XmlWriterSettings settings = new XmlWriterSettings();
@ -189,13 +192,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
private void WriteXml(XmlWriter writer) // ITerrainChannel.LoadFromXmlString()
{
writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
ToXml(writer);
writer.WriteEndElement();
}
public void LoadFromXmlString(string data) public void LoadFromXmlString(string data)
{ {
StringReader sr = new StringReader(data); StringReader sr = new StringReader(data);
@ -207,12 +204,124 @@ namespace OpenSim.Region.Framework.Scenes
sr.Close(); sr.Close();
} }
private void ReadXml(XmlReader reader) // ITerrainChannel.Merge
public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement)
{ {
reader.ReadStartElement("TerrainMap"); m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader,
FromXml(reader); newTerrain.Width, newTerrain.Height,
displacement, radianRotation, rotationDisplacement,
m_terrainData.SizeX, m_terrainData.SizeY);
for (int xx = 0; xx < newTerrain.Width; xx++)
{
for (int yy = 0; yy < newTerrain.Height; yy++)
{
int dispX = (int)displacement.X;
int dispY = (int)displacement.Y;
float newHeight = (float)newTerrain[xx, yy] + displacement.Z;
if (radianRotation == 0)
{
// If no rotation, place the new height in the specified location
dispX += xx;
dispY += yy;
if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
{
m_terrainData[dispX, dispY] = newHeight;
}
}
else
{
// If rotating, we have to smooth the result because the conversion
// to ints will mean heightmap entries will not get changed
// First compute the rotation location for the new height.
dispX += (int)(rotationDisplacement.X
+ ((float)xx - rotationDisplacement.X) * Math.Cos(radianRotation)
- ((float)yy - rotationDisplacement.Y) * Math.Sin(radianRotation) );
dispY += (int)(rotationDisplacement.Y
+ ((float)xx - rotationDisplacement.X) * Math.Sin(radianRotation)
+ ((float)yy - rotationDisplacement.Y) * Math.Cos(radianRotation) );
if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
{
float oldHeight = m_terrainData[dispX, dispY];
// Smooth the heights around this location if the old height is far from this one
for (int sxx = dispX - 2; sxx < dispX + 2; sxx++)
{
for (int syy = dispY - 2; syy < dispY + 2; syy++)
{
if (sxx >= 0 && sxx < m_terrainData.SizeX && syy >= 0 && syy < m_terrainData.SizeY)
{
if (sxx == dispX && syy == dispY)
{
// Set height for the exact rotated point
m_terrainData[dispX, dispY] = newHeight;
}
else
{
if (Math.Abs(m_terrainData[sxx, syy] - newHeight) > 1f)
{
// If the adjacent height is far off, force it to this height
m_terrainData[sxx, syy] = newHeight;
}
}
}
}
}
}
if (dispX >= 0 && dispX < m_terrainData.SizeX && dispY >= 0 && dispY < m_terrainData.SizeY)
{
m_terrainData[dispX, dispY] = (float)newTerrain[xx, yy];
}
}
}
}
} }
#endregion
public TerrainChannel Copy()
{
TerrainChannel copy = new TerrainChannel();
copy.m_terrainData = m_terrainData.Clone();
return copy;
}
private void WriteXml(XmlWriter writer)
{
if (Width == Constants.RegionSize && Height == Constants.RegionSize)
{
// Downward compatibility for legacy region terrain maps.
// If region is exactly legacy size, return the old format XML.
writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
ToXml(writer);
writer.WriteEndElement();
}
else
{
// New format XML that includes width and length.
writer.WriteStartElement(String.Empty, "TerrainMap2", String.Empty);
ToXml2(writer);
writer.WriteEndElement();
}
}
private void ReadXml(XmlReader reader)
{
// Check the first element. If legacy element, use the legacy reader.
if (reader.IsStartElement("TerrainMap"))
{
reader.ReadStartElement("TerrainMap");
FromXml(reader);
}
else
{
reader.ReadStartElement("TerrainMap2");
FromXml2(reader);
}
}
// Write legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
private void ToXml(XmlWriter xmlWriter) private void ToXml(XmlWriter xmlWriter)
{ {
float[] mapData = GetFloatsSerialised(); float[] mapData = GetFloatsSerialised();
@ -226,12 +335,15 @@ namespace OpenSim.Region.Framework.Scenes
serializer.Serialize(xmlWriter, buffer); serializer.Serialize(xmlWriter, buffer);
} }
// Read legacy terrain map. Presumed to be 256x256 of data encoded as floats in a byte array.
private void FromXml(XmlReader xmlReader) private void FromXml(XmlReader xmlReader)
{ {
XmlSerializer serializer = new XmlSerializer(typeof(byte[])); XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
byte[] dataArray = (byte[])serializer.Deserialize(xmlReader); byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
int index = 0; int index = 0;
m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight);
for (int y = 0; y < Height; y++) for (int y = 0; y < Height; y++)
{ {
for (int x = 0; x < Width; x++) for (int x = 0; x < Width; x++)
@ -244,35 +356,63 @@ namespace OpenSim.Region.Framework.Scenes
} }
} }
private class TerrainChannelXMLPackage
{
public int Version;
public int SizeX;
public int SizeY;
public int SizeZ;
public float CompressionFactor;
public int[] Map;
public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, int[] pMap)
{
Version = 1;
SizeX = pX;
SizeY = pY;
SizeZ = pZ;
CompressionFactor = pCompressionFactor;
Map = pMap;
}
}
// New terrain serialization format that includes the width and length.
private void ToXml2(XmlWriter xmlWriter)
{
TerrainChannelXMLPackage package = new TerrainChannelXMLPackage(Width, Height, Altitude, m_terrainData.CompressionFactor,
m_terrainData.GetCompressedMap());
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
serializer.Serialize(xmlWriter, package);
}
// New terrain serialization format that includes the width and length.
private void FromXml2(XmlReader xmlReader)
{
XmlSerializer serializer = new XmlSerializer(typeof(TerrainChannelXMLPackage));
TerrainChannelXMLPackage package = (TerrainChannelXMLPackage)serializer.Deserialize(xmlReader);
m_terrainData = new HeightmapTerrainData(package.Map, package.CompressionFactor, package.SizeX, package.SizeY, package.SizeZ);
}
// Fill the heightmap with the center bump terrain
private void PinHeadIsland() private void PinHeadIsland()
{ {
int x; for (int x = 0; x < Width; x++)
for (x = 0; x < Constants.RegionSize; x++)
{ {
int y; for (int y = 0; y < Height; y++)
for (y = 0; y < Constants.RegionSize; y++)
{ {
map[x, y] = TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10; m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
double spherFacA = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 50) * 0.01; float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001; float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
if (map[x, y] < spherFacA) if (m_terrainData[x, y]< spherFacA)
map[x, y] = spherFacA; m_terrainData[x, y]= spherFacA;
if (map[x, y] < spherFacB) if (m_terrainData[x, y]< spherFacB)
map[x, y] = spherFacB; m_terrainData[x, y] = spherFacB;
} }
} }
} }
private void FlatLand() private void FlatLand()
{ {
int x; m_terrainData.ClearLand();
for (x = 0; x < Constants.RegionSize; x++)
{
int y;
for (y = 0; y < Constants.RegionSize; y++)
map[x, y] = 21;
}
} }
} }
} }

View File

@ -0,0 +1,948 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* Freely adapted from the Aurora version of the terrain compressor.
* Copyright (c) Contributors, http://aurora-sim.org/, http://opensimulator.org/
*/
using System;
using System.Reflection;
using log4net;
using OpenSim.Framework;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenMetaverse;
using OpenMetaverse.Packets;
namespace OpenSim.Region.ClientStack.LindenUDP
{
public static class OpenSimTerrainCompressor
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#pragma warning disable 414
private static string LogHeader = "[TERRAIN COMPRESSOR]";
#pragma warning restore 414
public const int END_OF_PATCHES = 97;
private const float OO_SQRT2 = 0.7071067811865475244008443621049f;
private const int STRIDE = 264;
private const int ZERO_CODE = 0x0;
private const int ZERO_EOB = 0x2;
private const int POSITIVE_VALUE = 0x6;
private const int NEGATIVE_VALUE = 0x7;
private static readonly float[] DequantizeTable16 =
new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
private static readonly float[] DequantizeTable32 =
new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
private static readonly float[] CosineTable16 = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
//private static readonly float[] CosineTable32 = new float[Constants.TerrainPatchSize * Constants.TerrainPatchSize];
private static readonly int[] CopyMatrix16 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
private static readonly int[] CopyMatrix32 = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
private static readonly float[] QuantizeTable16 =
new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
static OpenSimTerrainCompressor()
{
// Initialize the decompression tables
BuildDequantizeTable16();
SetupCosines16();
BuildCopyMatrix16();
BuildQuantizeTable16();
}
// Used to send cloud and wind patches
public static LayerDataPacket CreateLayerDataPacket(TerrainPatch[] patches, byte type, int pRegionSizeX,
int pRegionSizeY)
{
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
{Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
// Should be enough to fit even the most poorly packed data
byte[] data = new byte[patches.Length*Constants.TerrainPatchSize*Constants.TerrainPatchSize*2];
BitPack bitpack = new BitPack(data, 0);
bitpack.PackBits(header.Stride, 16);
bitpack.PackBits(header.PatchSize, 8);
bitpack.PackBits(type, 8);
foreach (TerrainPatch t in patches)
CreatePatch(bitpack, t.Data, t.X, t.Y, pRegionSizeX, pRegionSizeY);
bitpack.PackBits(END_OF_PATCHES, 8);
layer.LayerData.Data = new byte[bitpack.BytePos + 1];
Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
return layer;
}
// Create a land packet for a single patch.
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int patchX, int patchY)
{
int[] xPieces = new int[1];
int[] yPieces = new int[1];
xPieces[0] = patchX; // patch X dimension
yPieces[0] = patchY;
return CreateLandPacket(terrData, xPieces, yPieces);
}
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] xPieces, int[] yPieces)
{
byte landPacketType = (byte)TerrainPatch.LayerType.Land;
if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
{
landPacketType = (byte)TerrainPatch.LayerType.LandExtended;
}
return CreateLandPacket(terrData, xPieces, yPieces, landPacketType);
}
/// <summary>
/// Creates a LayerData packet for compressed land data given a full
/// simulator heightmap and an array of indices of patches to compress
/// </summary>
/// <param name="terrData">
/// Terrain data that can result in a meter square heightmap.
/// </param>
/// <param name="x">
/// Array of indexes in the grid of patches
/// for this simulator.
/// If creating a packet for multiple patches, there will be entries in
/// both the X and Y arrays for each of the patches.
/// For example if patches 1 and 17 are to be sent,
/// x[] = {1,1} and y[] = {0,1} which specifies the patches at
/// indexes <1,0> and <1,1> (presuming the terrain size is 16x16 patches).
/// </param>
/// <param name="y">
/// Array of indexes in the grid of patches.
/// </param>
/// <param name="type"></param>
/// <returns></returns>
public static LayerDataPacket CreateLandPacket(TerrainData terrData, int[] x, int[] y, byte type)
{
LayerDataPacket layer = new LayerDataPacket {LayerID = {Type = type}};
TerrainPatch.GroupHeader header = new TerrainPatch.GroupHeader
{Stride = STRIDE, PatchSize = Constants.TerrainPatchSize};
byte[] data = new byte[x.Length * Constants.TerrainPatchSize * Constants.TerrainPatchSize * 2];
BitPack bitpack = new BitPack(data, 0);
bitpack.PackBits(header.Stride, 16);
bitpack.PackBits(header.PatchSize, 8);
bitpack.PackBits(type, 8);
for (int i = 0; i < x.Length; i++)
CreatePatchFromHeightmap(bitpack, terrData, x[i], y[i]);
bitpack.PackBits(END_OF_PATCHES, 8);
layer.LayerData.Data = new byte[bitpack.BytePos + 1];
Buffer.BlockCopy(bitpack.Data, 0, layer.LayerData.Data, 0, bitpack.BytePos + 1);
return layer;
}
// Unused: left for historical reference.
public static void CreatePatch(BitPack output, float[] patchData, int x, int y, int pRegionSizeX, int pRegionSizeY)
{
TerrainPatch.Header header = PrescanPatch(patchData);
header.QuantWBits = 136;
if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
{
header.PatchIDs = (y & 0xFFFF);
header.PatchIDs += (x << 16);
}
else
{
header.PatchIDs = (y & 0x1F);
header.PatchIDs += (x << 5);
}
// NOTE: No idea what prequant and postquant should be or what they do
int wbits;
int[] patch = CompressPatch(patchData, header, 10, out wbits);
wbits = EncodePatchHeader(output, header, patch, Constants.RegionSize, Constants.RegionSize, wbits);
EncodePatch(output, patch, 0, wbits);
}
/// <summary>
/// Add a patch of terrain to a BitPacker
/// </summary>
/// <param name="output">BitPacker to write the patch to</param>
/// <param name="heightmap">
/// Heightmap of the simulator. Presumed to be an sizeX*sizeY array.
/// </param>
/// <param name="patchX">
/// X offset of the patch to create.
/// </param>
/// <param name="patchY">
/// Y offset of the patch to create.
/// </param>
/// <param name="pRegionSizeX"></param>
/// <param name="pRegionSizeY"></param>
public static void CreatePatchFromHeightmap(BitPack output, TerrainData terrData, int patchX, int patchY)
{
TerrainPatch.Header header = PrescanPatch(terrData, patchX, patchY);
header.QuantWBits = 136;
// If larger than legacy region size, pack patch X and Y info differently.
if (terrData.SizeX > Constants.RegionSize || terrData.SizeY > Constants.RegionSize)
{
header.PatchIDs = (patchY & 0xFFFF);
header.PatchIDs += (patchX << 16);
}
else
{
header.PatchIDs = (patchY & 0x1F);
header.PatchIDs += (patchX << 5);
}
// m_log.DebugFormat("{0} CreatePatchFromHeightmap. patchX={1}, patchY={2}, DCOffset={3}, range={4}",
// LogHeader, patchX, patchY, header.DCOffset, header.Range);
// NOTE: No idea what prequant and postquant should be or what they do
int wbits;
int[] patch = CompressPatch(terrData, patchX, patchY, header, 10, out wbits);
wbits = EncodePatchHeader(output, header, patch, (uint)terrData.SizeX, (uint)terrData.SizeY, wbits);
EncodePatch(output, patch, 0, wbits);
}
private static TerrainPatch.Header PrescanPatch(float[] patch)
{
TerrainPatch.Header header = new TerrainPatch.Header();
float zmax = -99999999.0f;
float zmin = 99999999.0f;
for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
{
float val = patch[i];
if (val > zmax) zmax = val;
if (val < zmin) zmin = val;
}
header.DCOffset = zmin;
header.Range = (int) ((zmax - zmin) + 1.0f);
return header;
}
// Scan the height info we're returning and return a patch packet header for this patch.
private static TerrainPatch.Header PrescanPatch(TerrainData terrData, int patchX, int patchY)
{
TerrainPatch.Header header = new TerrainPatch.Header();
float zmax = -99999999.0f;
float zmin = 99999999.0f;
for (int j = patchY*Constants.TerrainPatchSize; j < (patchY + 1)*Constants.TerrainPatchSize; j++)
{
for (int i = patchX*Constants.TerrainPatchSize; i < (patchX + 1)*Constants.TerrainPatchSize; i++)
{
float val = terrData[i, j];
if (val > zmax) zmax = val;
if (val < zmin) zmin = val;
}
}
header.DCOffset = zmin;
header.Range = (int)((zmax - zmin) + 1.0f);
return header;
}
public static TerrainPatch.Header DecodePatchHeader(BitPack bitpack)
{
TerrainPatch.Header header = new TerrainPatch.Header {QuantWBits = bitpack.UnpackBits(8)};
// Quantized word bits
if (header.QuantWBits == END_OF_PATCHES)
return header;
// DC offset
header.DCOffset = bitpack.UnpackFloat();
// Range
header.Range = bitpack.UnpackBits(16);
// Patch IDs (10 bits)
header.PatchIDs = bitpack.UnpackBits(10);
// Word bits
header.WordBits = (uint) ((header.QuantWBits & 0x0f) + 2);
return header;
}
private static int EncodePatchHeader(BitPack output, TerrainPatch.Header header, int[] patch, uint pRegionSizeX,
uint pRegionSizeY, int wbits)
{
/*
int temp;
int wbits = (header.QuantWBits & 0x0f) + 2;
uint maxWbits = (uint)wbits + 5;
uint minWbits = ((uint)wbits >> 1);
int wbitsMaxValue;
*/
// goal is to determ minimum number of bits to use so all data fits
/*
wbits = (int)minWbits;
wbitsMaxValue = (1 << wbits);
for (int i = 0; i < patch.Length; i++)
{
temp = patch[i];
if (temp != 0)
{
// Get the absolute value
if (temp < 0) temp *= -1;
no coments..
for (int j = (int)maxWbits; j > (int)minWbits; j--)
{
if ((temp & (1 << j)) != 0)
{
if (j > wbits) wbits = j;
break;
}
}
while (temp > wbitsMaxValue)
{
wbits++;
if (wbits == maxWbits)
goto Done;
wbitsMaxValue = 1 << wbits;
}
}
}
Done:
// wbits += 1;
*/
// better check
if (wbits > 17)
wbits = 16;
else if (wbits < 3)
wbits = 3;
header.QuantWBits &= 0xf0;
header.QuantWBits |= (wbits - 2);
output.PackBits(header.QuantWBits, 8);
output.PackFloat(header.DCOffset);
output.PackBits(header.Range, 16);
if (pRegionSizeX > Constants.RegionSize || pRegionSizeY > Constants.RegionSize)
output.PackBits(header.PatchIDs, 32);
else
output.PackBits(header.PatchIDs, 10);
return wbits;
}
private static void IDCTColumn16(float[] linein, float[] lineout, int column)
{
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
float total = OO_SQRT2*linein[column];
for (int u = 1; u < Constants.TerrainPatchSize; u++)
{
int usize = u*Constants.TerrainPatchSize;
total += linein[usize + column]*CosineTable16[usize + n];
}
lineout[Constants.TerrainPatchSize*n + column] = total;
}
}
private static void IDCTLine16(float[] linein, float[] lineout, int line)
{
const float oosob = 2.0f/Constants.TerrainPatchSize;
int lineSize = line*Constants.TerrainPatchSize;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
float total = OO_SQRT2*linein[lineSize];
for (int u = 1; u < Constants.TerrainPatchSize; u++)
{
total += linein[lineSize + u]*CosineTable16[u*Constants.TerrainPatchSize + n];
}
lineout[lineSize + n] = total*oosob;
}
}
/*
private static void DCTLine16(float[] linein, float[] lineout, int line)
{
float total = 0.0f;
int lineSize = line * Constants.TerrainPatchSize;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
total += linein[lineSize + n];
}
lineout[lineSize] = OO_SQRT2 * total;
int uptr = 0;
for (int u = 1; u < Constants.TerrainPatchSize; u++)
{
total = 0.0f;
uptr += Constants.TerrainPatchSize;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
total += linein[lineSize + n] * CosineTable16[uptr + n];
}
lineout[lineSize + u] = total;
}
}
*/
private static void DCTLine16(float[] linein, float[] lineout, int line)
{
// outputs transpose data (lines exchanged with coluns )
// so to save a bit of cpu when doing coluns
float total = 0.0f;
int lineSize = line*Constants.TerrainPatchSize;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
total += linein[lineSize + n];
}
lineout[line] = OO_SQRT2*total;
for (int u = Constants.TerrainPatchSize;
u < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
u += Constants.TerrainPatchSize)
{
total = 0.0f;
for (int ptrn = lineSize, ptru = u; ptrn < lineSize + Constants.TerrainPatchSize; ptrn++,ptru++)
{
total += linein[ptrn]*CosineTable16[ptru];
}
lineout[line + u] = total;
}
}
/*
private static void DCTColumn16(float[] linein, int[] lineout, int column)
{
float total = 0.0f;
// const float oosob = 2.0f / Constants.TerrainPatchSize;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
total += linein[Constants.TerrainPatchSize * n + column];
}
// lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * QuantizeTable16[column]);
for (int uptr = Constants.TerrainPatchSize; uptr < Constants.TerrainPatchSize * Constants.TerrainPatchSize; uptr += Constants.TerrainPatchSize)
{
total = 0.0f;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
total += linein[Constants.TerrainPatchSize * n + column] * CosineTable16[uptr + n];
}
// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
lineout[CopyMatrix16[uptr + column]] = (int)(total * QuantizeTable16[uptr + column]);
}
}
private static void DCTColumn16(float[] linein, int[] lineout, int column)
{
// input columns are in fact stored in lines now
float total = 0.0f;
// const float oosob = 2.0f / Constants.TerrainPatchSize;
int inlinesptr = Constants.TerrainPatchSize*column;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
total += linein[inlinesptr + n];
}
// lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
lineout[CopyMatrix16[column]] = (int) (OO_SQRT2*total*QuantizeTable16[column]);
for (int uptr = Constants.TerrainPatchSize;
uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
uptr += Constants.TerrainPatchSize)
{
total = 0.0f;
for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
{
total += linein[n]*CosineTable16[ptru];
}
// lineout[CopyMatrix16[Constants.TerrainPatchSize * u + column]] = (int)(total * oosob * QuantizeTable16[Constants.TerrainPatchSize * u + column]);
lineout[CopyMatrix16[uptr + column]] = (int) (total*QuantizeTable16[uptr + column]);
}
}
*/
private static int DCTColumn16Wbits(float[] linein, int[] lineout, int column, int wbits, int maxwbits)
{
// input columns are in fact stored in lines now
bool dowbits = wbits != maxwbits;
int wbitsMaxValue = 1 << wbits;
float total = 0.0f;
// const float oosob = 2.0f / Constants.TerrainPatchSize;
int inlinesptr = Constants.TerrainPatchSize*column;
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
total += linein[inlinesptr + n];
}
// lineout[CopyMatrix16[column]] = (int)(OO_SQRT2 * total * oosob * QuantizeTable16[column]);
int tmp = (int) (OO_SQRT2*total*QuantizeTable16[column]);
lineout[CopyMatrix16[column]] = tmp;
if (dowbits)
{
if (tmp < 0) tmp *= -1;
while (tmp > wbitsMaxValue)
{
wbits++;
wbitsMaxValue = 1 << wbits;
if (wbits == maxwbits)
{
dowbits = false;
break;
}
}
}
for (int uptr = Constants.TerrainPatchSize;
uptr < Constants.TerrainPatchSize*Constants.TerrainPatchSize;
uptr += Constants.TerrainPatchSize)
{
total = 0.0f;
for (int n = inlinesptr, ptru = uptr; n < inlinesptr + Constants.TerrainPatchSize; n++, ptru++)
{
total += linein[n]*CosineTable16[ptru];
}
tmp = (int) (total*QuantizeTable16[uptr + column]);
lineout[CopyMatrix16[uptr + column]] = tmp;
if (dowbits)
{
if (tmp < 0) tmp *= -1;
while (tmp > wbitsMaxValue)
{
wbits++;
wbitsMaxValue = 1 << wbits;
if (wbits == maxwbits)
{
dowbits = false;
break;
}
}
}
}
return wbits;
}
public static void DecodePatch(int[] patches, BitPack bitpack, TerrainPatch.Header header, int size)
{
for (int n = 0; n < size*size; n++)
{
// ?
int temp = bitpack.UnpackBits(1);
if (temp != 0)
{
// Value or EOB
temp = bitpack.UnpackBits(1);
if (temp != 0)
{
// Value
temp = bitpack.UnpackBits(1);
if (temp != 0)
{
// Negative
temp = bitpack.UnpackBits((int) header.WordBits);
patches[n] = temp*-1;
}
else
{
// Positive
temp = bitpack.UnpackBits((int) header.WordBits);
patches[n] = temp;
}
}
else
{
// Set the rest to zero
// TODO: This might not be necessary
for (int o = n; o < size*size; o++)
{
patches[o] = 0;
}
break;
}
}
else
{
patches[n] = 0;
}
}
}
private static void EncodePatch(BitPack output, int[] patch, int postquant, int wbits)
{
int maxwbitssize = (1 << wbits) - 1;
if (postquant > Constants.TerrainPatchSize*Constants.TerrainPatchSize || postquant < 0)
{
Logger.Log("Postquant is outside the range of allowed values in EncodePatch()", Helpers.LogLevel.Error);
return;
}
if (postquant != 0) patch[Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant] = 0;
for (int i = 0; i < Constants.TerrainPatchSize*Constants.TerrainPatchSize; i++)
{
int temp = patch[i];
if (temp == 0)
{
bool eob = true;
for (int j = i; j < Constants.TerrainPatchSize*Constants.TerrainPatchSize - postquant; j++)
{
if (patch[j] != 0)
{
eob = false;
break;
}
}
if (eob)
{
output.PackBits(ZERO_EOB, 2);
return;
}
output.PackBits(ZERO_CODE, 1);
}
else
{
if (temp < 0)
{
temp *= -1;
if (temp > maxwbitssize) temp = maxwbitssize;
output.PackBits(NEGATIVE_VALUE, 3);
output.PackBits(temp, wbits);
}
else
{
if (temp > maxwbitssize) temp = maxwbitssize;
output.PackBits(POSITIVE_VALUE, 3);
output.PackBits(temp, wbits);
}
}
}
}
public static float[] DecompressPatch(int[] patches, TerrainPatch.Header header, TerrainPatch.GroupHeader group)
{
float[] block = new float[group.PatchSize*group.PatchSize];
float[] output = new float[group.PatchSize*group.PatchSize];
int prequant = (header.QuantWBits >> 4) + 2;
int quantize = 1 << prequant;
float ooq = 1.0f/quantize;
float mult = ooq*header.Range;
float addval = mult*(1 << (prequant - 1)) + header.DCOffset;
if (group.PatchSize == Constants.TerrainPatchSize)
{
for (int n = 0; n < Constants.TerrainPatchSize*Constants.TerrainPatchSize; n++)
{
block[n] = patches[CopyMatrix16[n]]*DequantizeTable16[n];
}
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
for (int o = 0; o < Constants.TerrainPatchSize; o++)
IDCTColumn16(block, ftemp, o);
for (int o = 0; o < Constants.TerrainPatchSize; o++)
IDCTLine16(ftemp, block, o);
}
else
{
for (int n = 0; n < Constants.TerrainPatchSize*2*Constants.TerrainPatchSize*2; n++)
{
block[n] = patches[CopyMatrix32[n]]*DequantizeTable32[n];
}
Logger.Log("Implement IDCTPatchLarge", Helpers.LogLevel.Error);
}
for (int j = 0; j < block.Length; j++)
{
output[j] = block[j]*mult + addval;
}
return output;
}
private static int[] CompressPatch(float[] patchData, TerrainPatch.Header header, int prequant, out int wbits)
{
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int wordsize = (prequant - 2) & 0x0f;
float oozrange = 1.0f/header.Range;
float range = (1 << prequant);
float premult = oozrange*range;
float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
header.QuantWBits = wordsize;
header.QuantWBits |= wordsize << 4;
int k = 0;
for (int j = 0; j < Constants.TerrainPatchSize; j++)
{
for (int i = 0; i < Constants.TerrainPatchSize; i++)
block[k++] = patchData[j*Constants.TerrainPatchSize + i]*premult - sub;
}
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int maxWbits = prequant + 5;
wbits = (prequant >> 1);
for (int o = 0; o < Constants.TerrainPatchSize; o++)
DCTLine16(block, ftemp, o);
for (int o = 0; o < Constants.TerrainPatchSize; o++)
wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
return itemp;
}
private static int[] CompressPatch(float[,] patchData, TerrainPatch.Header header, int prequant, out int wbits)
{
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
float oozrange = 1.0f/header.Range;
float range = (1 << prequant);
float premult = oozrange*range;
float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
int wordsize = (prequant - 2) & 0x0f;
header.QuantWBits = wordsize;
header.QuantWBits |= wordsize << 4;
int k = 0;
for (int j = 0; j < Constants.TerrainPatchSize; j++)
{
for (int i = 0; i < Constants.TerrainPatchSize; i++)
block[k++] = patchData[j, i]*premult - sub;
}
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int maxWbits = prequant + 5;
wbits = (prequant >> 1);
for (int o = 0; o < Constants.TerrainPatchSize; o++)
DCTLine16(block, ftemp, o);
for (int o = 0; o < Constants.TerrainPatchSize; o++)
wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
return itemp;
}
private static int[] CompressPatch(TerrainData terrData, int patchX, int patchY, TerrainPatch.Header header,
int prequant, out int wbits)
{
float[] block = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int wordsize = prequant;
float oozrange = 1.0f/header.Range;
float range = (1 << prequant);
float premult = oozrange*range;
float sub = (1 << (prequant - 1)) + header.DCOffset*premult;
header.QuantWBits = wordsize - 2;
header.QuantWBits |= (prequant - 2) << 4;
int k = 0;
int yPatchLimit = patchY >= (terrData.SizeY / Constants.TerrainPatchSize) ?
(terrData.SizeY - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchY;
yPatchLimit = (yPatchLimit + 1) * Constants.TerrainPatchSize;
int xPatchLimit = patchX >= (terrData.SizeX / Constants.TerrainPatchSize) ?
(terrData.SizeX - Constants.TerrainPatchSize) / Constants.TerrainPatchSize : patchX;
xPatchLimit = (xPatchLimit + 1) * Constants.TerrainPatchSize;
for (int yy = patchY * Constants.TerrainPatchSize; yy < yPatchLimit; yy++)
{
for (int xx = patchX * Constants.TerrainPatchSize; xx < xPatchLimit; xx++)
{
block[k++] = terrData[xx, yy] * premult - sub;
}
}
float[] ftemp = new float[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int[] itemp = new int[Constants.TerrainPatchSize*Constants.TerrainPatchSize];
int maxWbits = prequant + 5;
wbits = (prequant >> 1);
for (int o = 0; o < Constants.TerrainPatchSize; o++)
DCTLine16(block, ftemp, o);
for (int o = 0; o < Constants.TerrainPatchSize; o++)
wbits = DCTColumn16Wbits(ftemp, itemp, o, wbits, maxWbits);
return itemp;
}
#region Initialization
private static void BuildDequantizeTable16()
{
for (int j = 0; j < Constants.TerrainPatchSize; j++)
{
for (int i = 0; i < Constants.TerrainPatchSize; i++)
{
DequantizeTable16[j*Constants.TerrainPatchSize + i] = 1.0f + 2.0f*(i + j);
}
}
}
private static void BuildQuantizeTable16()
{
const float oosob = 2.0f/Constants.TerrainPatchSize;
for (int j = 0; j < Constants.TerrainPatchSize; j++)
{
for (int i = 0; i < Constants.TerrainPatchSize; i++)
{
// QuantizeTable16[j * Constants.TerrainPatchSize + i] = 1.0f / (1.0f + 2.0f * ((float)i + (float)j));
QuantizeTable16[j*Constants.TerrainPatchSize + i] = oosob/(1.0f + 2.0f*(i + (float) j));
}
}
}
private static void SetupCosines16()
{
const float hposz = (float) Math.PI*0.5f/Constants.TerrainPatchSize;
for (int u = 0; u < Constants.TerrainPatchSize; u++)
{
for (int n = 0; n < Constants.TerrainPatchSize; n++)
{
CosineTable16[u*Constants.TerrainPatchSize + n] = (float) Math.Cos((2.0f*n + 1.0f)*u*hposz);
}
}
}
private static void BuildCopyMatrix16()
{
bool diag = false;
bool right = true;
int i = 0;
int j = 0;
int count = 0;
while (i < Constants.TerrainPatchSize && j < Constants.TerrainPatchSize)
{
CopyMatrix16[j*Constants.TerrainPatchSize + i] = count++;
if (!diag)
{
if (right)
{
if (i < Constants.TerrainPatchSize - 1) i++;
else j++;
right = false;
diag = true;
}
else
{
if (j < Constants.TerrainPatchSize - 1) j++;
else i++;
right = true;
diag = true;
}
}
else
{
if (right)
{
i++;
j--;
if (i == Constants.TerrainPatchSize - 1 || j == 0) diag = false;
}
else
{
i--;
j++;
if (j == Constants.TerrainPatchSize - 1 || i == 0) diag = false;
}
}
}
}
#endregion Initialization
}
}

View File

@ -520,7 +520,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
public Vector3 StartPos public Vector3 StartPos
{ {
get { return new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 50); } get { return new Vector3(m_scene.RegionInfo.RegionSizeX * 0.5f, m_scene.RegionInfo.RegionSizeY * 0.5f, 50f); }
set { } set { }
} }

View File

@ -52,6 +52,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
// Local constants // Local constants
// This computation is not the real region center if the region is larger than 256.
// This computation isn't fixed because there is not a handle back to the region.
private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); private static readonly Vector3 CenterOfRegion = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
private static readonly char[] CS_SPACE = { ' ' }; private static readonly char[] CS_SPACE = { ' ' };

View File

@ -44,6 +44,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
private static readonly ILog m_log = private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// This computation is not the real region center if the region is larger than 256.
// This computation isn't fixed because there is not a handle back to the region.
private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20); private static readonly OpenMetaverse.Vector3 CenterOfRegion = new OpenMetaverse.Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 20);
private const int DEBUG_CHANNEL = 2147483647; private const int DEBUG_CHANNEL = 2147483647;

View File

@ -122,8 +122,8 @@ namespace OpenSim.Region.OptionalModules
private bool CanObjectEnter(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene) private bool CanObjectEnter(UUID objectID, bool enteringRegion, Vector3 newPoint, Scene scene)
{ {
if (newPoint.X < -1f || newPoint.X > (float)(Constants.RegionSize + 1) || if (newPoint.X < -1f || newPoint.X > (scene.RegionInfo.RegionSizeX + 1) ||
newPoint.Y < -1f || newPoint.Y > (float)(Constants.RegionSize + 1)) newPoint.Y < -1f || newPoint.Y > (scene.RegionInfo.RegionSizeY) )
return true; return true;
SceneObjectPart obj = scene.GetSceneObjectPart(objectID); SceneObjectPart obj = scene.GetSceneObjectPart(objectID);

View File

@ -170,7 +170,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
c.Channel = m_channelNotify; c.Channel = m_channelNotify;
c.Message += numScriptsFailed.ToString() + "," + message; c.Message += numScriptsFailed.ToString() + "," + message;
c.Type = ChatTypeEnum.Region; c.Type = ChatTypeEnum.Region;
c.Position = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30); if (m_scene != null)
c.Position = new Vector3((m_scene.RegionInfo.RegionSizeX * 0.5f), (m_scene.RegionInfo.RegionSizeY * 0.5f), 30);
else
c.Position = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30);
c.Sender = null; c.Sender = null;
c.SenderUUID = UUID.Zero; c.SenderUUID = UUID.Zero;
c.Scene = m_scene; c.Scene = m_scene;

View File

@ -116,37 +116,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
+ "If teleport is true then some extra teleport debug information is logged.\n" + "If teleport is true then some extra teleport debug information is logged.\n"
+ "If updates is true then any frame which exceeds double the maximum desired frame time is logged.", + "If updates is true then any frame which exceeds double the maximum desired frame time is logged.",
HandleDebugSceneSetCommand); HandleDebugSceneSetCommand);
scene.AddCommand(
"Regions",
this, "show borders", "show borders", "Show border information for regions", HandleShowBordersCommand);
}
private void HandleShowBordersCommand(string module, string[] args)
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Borders for {0}:\n", m_scene.Name);
ConsoleDisplayTable cdt = new ConsoleDisplayTable();
cdt.AddColumn("Cross Direction", 15);
cdt.AddColumn("Line", 34);
cdt.AddColumn("Trigger Region", 14);
foreach (Border b in m_scene.NorthBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
foreach (Border b in m_scene.EastBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
foreach (Border b in m_scene.SouthBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
foreach (Border b in m_scene.WestBorders)
cdt.AddRow(b.CrossDirection, b.BorderLine, string.Format("{0}, {1}", b.TriggerRegionX, b.TriggerRegionY));
cdt.AddToStringBuilder(sb);
MainConsole.Instance.Output(sb.ToString());
} }
private void HandleDebugSceneGetCommand(string module, string[] args) private void HandleDebugSceneGetCommand(string module, string[] args)
@ -263,4 +232,4 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
} }
} }
} }
} }

View File

@ -748,8 +748,8 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
position.X = s_tree.AbsolutePosition.X + (float)randX; position.X = s_tree.AbsolutePosition.X + (float)randX;
position.Y = s_tree.AbsolutePosition.Y + (float)randY; position.Y = s_tree.AbsolutePosition.Y + (float)randY;
if (position.X <= ((int)Constants.RegionSize - 1) && position.X >= 0 && if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 &&
position.Y <= ((int)Constants.RegionSize - 1) && position.Y >= 0 && position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 &&
Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range) Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range)
{ {
UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner; UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;

View File

@ -46,6 +46,7 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
private List<BasicActor> _actors = new List<BasicActor>(); private List<BasicActor> _actors = new List<BasicActor>();
private List<BasicPhysicsPrim> _prims = new List<BasicPhysicsPrim>(); private List<BasicPhysicsPrim> _prims = new List<BasicPhysicsPrim>();
private float[] _heightMap; private float[] _heightMap;
private Vector3 m_regionExtent;
//protected internal string sceneIdentifier; //protected internal string sceneIdentifier;
@ -58,6 +59,12 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
public override void Initialise(IMesher meshmerizer, IConfigSource config) public override void Initialise(IMesher meshmerizer, IConfigSource config)
{ {
throw new Exception("Should not be called.");
}
public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
{
m_regionExtent = regionExtent;
} }
public override void Dispose() {} public override void Dispose() {}
@ -121,23 +128,23 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
{ {
actorPosition.Y = 0.1F; actorPosition.Y = 0.1F;
} }
else if (actor.Position.Y >= Constants.RegionSize) else if (actor.Position.Y >= m_regionExtent.Y)
{ {
actorPosition.Y = ((int)Constants.RegionSize - 0.1f); actorPosition.Y = (m_regionExtent.Y - 0.1f);
} }
if (actor.Position.X < 0) if (actor.Position.X < 0)
{ {
actorPosition.X = 0.1F; actorPosition.X = 0.1F;
} }
else if (actor.Position.X >= Constants.RegionSize) else if (actor.Position.X >= m_regionExtent.X)
{ {
actorPosition.X = ((int)Constants.RegionSize - 0.1f); actorPosition.X = (m_regionExtent.X - 0.1f);
} }
float terrainHeight = 0; float terrainHeight = 0;
if (_heightMap != null) if (_heightMap != null)
terrainHeight = _heightMap[(int)actor.Position.Y * Constants.RegionSize + (int)actor.Position.X]; terrainHeight = _heightMap[(int)actor.Position.Y * (int)m_regionExtent.Y + (int)actor.Position.X];
float height = terrainHeight + actor.Size.Z; float height = terrainHeight + actor.Size.Z;

View File

@ -32,6 +32,7 @@ using System.Reflection;
using Nini.Config; using Nini.Config;
using log4net; using log4net;
using OpenSim.Framework; using OpenSim.Framework;
using OpenMetaverse;
namespace OpenSim.Region.Physics.Manager namespace OpenSim.Region.Physics.Manager
{ {
@ -59,6 +60,14 @@ namespace OpenSim.Region.Physics.Manager
m_log.Info("[PHYSICS]: Added meshing engine: " + plugHard.GetName()); m_log.Info("[PHYSICS]: Added meshing engine: " + plugHard.GetName());
} }
// Legacy method for simulators before extent was passed
public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName,
IConfigSource config, string regionName)
{
Vector3 extent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
return GetPhysicsScene(physEngineName, meshEngineName, config, regionName, extent);
}
/// <summary> /// <summary>
/// Get a physics scene for the given physics engine and mesher. /// Get a physics scene for the given physics engine and mesher.
/// </summary> /// </summary>
@ -66,7 +75,8 @@ namespace OpenSim.Region.Physics.Manager
/// <param name="meshEngineName"></param> /// <param name="meshEngineName"></param>
/// <param name="config"></param> /// <param name="config"></param>
/// <returns></returns> /// <returns></returns>
public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName, IConfigSource config, string regionName) public PhysicsScene GetPhysicsScene(string physEngineName, string meshEngineName,
IConfigSource config, string regionName, Vector3 regionExtent)
{ {
if (String.IsNullOrEmpty(physEngineName)) if (String.IsNullOrEmpty(physEngineName))
{ {
@ -94,7 +104,7 @@ namespace OpenSim.Region.Physics.Manager
{ {
m_log.Info("[PHYSICS]: creating " + physEngineName); m_log.Info("[PHYSICS]: creating " + physEngineName);
PhysicsScene result = _PhysPlugins[physEngineName].GetScene(regionName); PhysicsScene result = _PhysPlugins[physEngineName].GetScene(regionName);
result.Initialise(meshEngine, config); result.Initialise(meshEngine, config, regionExtent);
return result; return result;
} }
else else

View File

@ -132,8 +132,17 @@ namespace OpenSim.Region.Physics.Manager
} }
} }
// Deprecated. Do not use this for new physics engines.
public abstract void Initialise(IMesher meshmerizer, IConfigSource config); public abstract void Initialise(IMesher meshmerizer, IConfigSource config);
// For older physics engines that do not implement non-legacy region sizes.
// If the physics engine handles the region extent feature, it overrides this function.
public virtual void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
{
// If not overridden, call the old initialization entry.
Initialise(meshmerizer, config);
}
/// <summary> /// <summary>
/// Add an avatar /// Add an avatar
/// </summary> /// </summary>

View File

@ -134,6 +134,49 @@ namespace OpenSim.Region.RegionCombinerModule
throw new Exception(string.Format("Region with id {0} not found", regionId)); throw new Exception(string.Format("Region with id {0} not found", regionId));
} }
// Test to see if this postiion (relative to the region) is within the area covered
// by this megaregion.
public bool PositionIsInMegaregion(UUID currentRegion, int xx, int yy)
{
bool ret = false;
if (xx < 0 || yy < 0)
return ret;
foreach (RegionConnections rootRegion in m_regions.Values)
{
if (currentRegion == rootRegion.RegionId)
{
// The caller is in the root region so this is an easy test
if (xx < rootRegion.XEnd && yy < rootRegion.YEnd)
{
ret = true;
}
break;
}
else
{
// Maybe the caller is in one of the sub-regions
foreach (RegionData childRegion in rootRegion.ConnectedRegions)
{
if (currentRegion == childRegion.RegionId)
{
// This is a child. Diddle the offsets and check if in
Vector3 positionInMegaregion = childRegion.Offset;
positionInMegaregion.X += xx;
positionInMegaregion.Y += yy;
if (positionInMegaregion.X < rootRegion.XEnd && positionInMegaregion.Y < rootRegion.YEnd)
{
ret = true;
}
break;
}
}
}
}
return ret;
}
private void NewPresence(ScenePresence presence) private void NewPresence(ScenePresence presence)
{ {
if (presence.IsChildAgent) if (presence.IsChildAgent)
@ -220,27 +263,6 @@ namespace OpenSim.Region.RegionCombinerModule
// //
*/ */
// Give each region a standard set of non-infinite borders
Border northBorder = new Border();
northBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize); //<---
northBorder.CrossDirection = Cardinals.N;
scene.NorthBorders[0] = northBorder;
Border southBorder = new Border();
southBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0); //--->
southBorder.CrossDirection = Cardinals.S;
scene.SouthBorders[0] = southBorder;
Border eastBorder = new Border();
eastBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, (int)Constants.RegionSize); //<---
eastBorder.CrossDirection = Cardinals.E;
scene.EastBorders[0] = eastBorder;
Border westBorder = new Border();
westBorder.BorderLine = new Vector3(0, (int)Constants.RegionSize, 0); //--->
westBorder.CrossDirection = Cardinals.W;
scene.WestBorders[0] = westBorder;
RegionConnections newConn = new RegionConnections(); RegionConnections newConn = new RegionConnections();
newConn.ConnectedRegions = new List<RegionData>(); newConn.ConnectedRegions = new List<RegionData>();
newConn.RegionScene = scene; newConn.RegionScene = scene;
@ -248,8 +270,8 @@ namespace OpenSim.Region.RegionCombinerModule
newConn.RegionId = scene.RegionInfo.originRegionID; newConn.RegionId = scene.RegionInfo.originRegionID;
newConn.X = scene.RegionInfo.RegionLocX; newConn.X = scene.RegionInfo.RegionLocX;
newConn.Y = scene.RegionInfo.RegionLocY; newConn.Y = scene.RegionInfo.RegionLocY;
newConn.XEnd = (int)Constants.RegionSize; newConn.XEnd = scene.RegionInfo.RegionSizeX;
newConn.YEnd = (int)Constants.RegionSize; newConn.YEnd = scene.RegionInfo.RegionSizeX;
lock (m_regions) lock (m_regions)
{ {
@ -415,6 +437,11 @@ namespace OpenSim.Region.RegionCombinerModule
*/ */
#endregion #endregion
// Check to see if this new region is adjacent to the root region.
// Note that we expect the regions to be combined from the root region outward
// thus the requirement for the ordering in the configuration files.
// If we're one region over +x y (i.e. root region is to the west) // If we're one region over +x y (i.e. root region is to the west)
//xxx //xxx
//xxy //xxy
@ -431,7 +458,7 @@ namespace OpenSim.Region.RegionCombinerModule
//xxx //xxx
if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) if (rootConn.PosX >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
{ {
connectedYN = DoWorkForOneRegionOverXPlusY(rootConn, newConn, scene); connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
break; break;
} }
@ -441,9 +468,8 @@ namespace OpenSim.Region.RegionCombinerModule
//xxx //xxx
if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY) if (rootConn.PosX + rootConn.XEnd >= newConn.PosX && rootConn.PosY + rootConn.YEnd >= newConn.PosY)
{ {
connectedYN = DoWorkForOneRegionOverPlusXPlusY(rootConn, newConn, scene); connectedYN = DoWorkForOneRegionOverPlusXY(rootConn, newConn, scene);
break; break;
} }
} }
@ -453,20 +479,20 @@ namespace OpenSim.Region.RegionCombinerModule
DoWorkForRootRegion(newConn, scene); DoWorkForRootRegion(newConn, scene);
} }
} }
// Set up infinite borders around the entire AABB of the combined ConnectedRegions
AdjustLargeRegionBounds();
} }
private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene) private bool DoWorkForOneRegionOverPlusXY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
{ {
// Offset (in meters) from the base of this region to the base of the root region.
Vector3 offset = Vector3.Zero; Vector3 offset = Vector3.Zero;
offset.X = newConn.PosX - rootConn.PosX; offset.X = newConn.PosX - rootConn.PosX;
offset.Y = newConn.PosY - rootConn.PosY; offset.Y = newConn.PosY - rootConn.PosY;
// The new total size of the region (in meters)
// We just extend the X and Y dimensions so the extent might temporarily include areas without regions.
Vector3 extents = Vector3.Zero; Vector3 extents = Vector3.Zero;
extents.Y = rootConn.YEnd; extents.X = Math.Max(rootConn.XEnd, offset.X + newConn.RegionScene.RegionInfo.RegionSizeX);
extents.X = rootConn.XEnd + newConn.XEnd; extents.Y = Math.Max(rootConn.YEnd, offset.Y + newConn.RegionScene.RegionInfo.RegionSizeY);
rootConn.UpdateExtents(extents); rootConn.UpdateExtents(extents);
@ -475,9 +501,6 @@ namespace OpenSim.Region.RegionCombinerModule
rootConn.RegionScene.RegionInfo.RegionName, rootConn.RegionScene.RegionInfo.RegionName,
newConn.RegionScene.RegionInfo.RegionName, offset, extents); newConn.RegionScene.RegionInfo.RegionName, offset, extents);
scene.BordersLocked = true;
rootConn.RegionScene.BordersLocked = true;
RegionData ConnectedRegion = new RegionData(); RegionData ConnectedRegion = new RegionData();
ConnectedRegion.Offset = offset; ConnectedRegion.Offset = offset;
ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
@ -490,34 +513,10 @@ namespace OpenSim.Region.RegionCombinerModule
// Inform Child region that it needs to forward it's terrain to the root region // Inform Child region that it needs to forward it's terrain to the root region
scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
// Extend the borders as appropriate
lock (rootConn.RegionScene.EastBorders)
rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;
lock (rootConn.RegionScene.NorthBorders)
rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
lock (rootConn.RegionScene.SouthBorders)
rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
lock (scene.WestBorders)
{
scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
// Trigger auto teleport to root region
scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
}
// Reset Terrain.. since terrain loads before we get here, we need to load // Reset Terrain.. since terrain loads before we get here, we need to load
// it again so it loads in the root region // it again so it loads in the root region
scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
// Unlock borders
rootConn.RegionScene.BordersLocked = false;
scene.BordersLocked = false;
// Create a client event forwarder and add this region's events to the root region. // Create a client event forwarder and add this region's events to the root region.
if (rootConn.ClientEventForwarder != null) if (rootConn.ClientEventForwarder != null)
rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
@ -525,6 +524,9 @@ namespace OpenSim.Region.RegionCombinerModule
return true; return true;
} }
/*
* 20140215 radams1: The border stuff was removed and the addition of regions to the mega-regions
* was generalized. These functions are not needed for the generalized solution but left for reference.
private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene) private bool DoWorkForOneRegionOverXPlusY(RegionConnections rootConn, RegionConnections newConn, Scene scene)
{ {
Vector3 offset = Vector3.Zero; Vector3 offset = Vector3.Zero;
@ -536,9 +538,6 @@ namespace OpenSim.Region.RegionCombinerModule
extents.X = rootConn.XEnd; extents.X = rootConn.XEnd;
rootConn.UpdateExtents(extents); rootConn.UpdateExtents(extents);
scene.BordersLocked = true;
rootConn.RegionScene.BordersLocked = true;
RegionData ConnectedRegion = new RegionData(); RegionData ConnectedRegion = new RegionData();
ConnectedRegion.Offset = offset; ConnectedRegion.Offset = offset;
ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
@ -553,30 +552,11 @@ namespace OpenSim.Region.RegionCombinerModule
rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
lock (rootConn.RegionScene.NorthBorders)
rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
lock (rootConn.RegionScene.EastBorders)
rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
lock (rootConn.RegionScene.WestBorders)
rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
lock (scene.SouthBorders)
{
scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
}
// Reset Terrain.. since terrain normally loads first. // Reset Terrain.. since terrain normally loads first.
//conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
//conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
scene.BordersLocked = false;
rootConn.RegionScene.BordersLocked = false;
if (rootConn.ClientEventForwarder != null) if (rootConn.ClientEventForwarder != null)
rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
@ -600,9 +580,6 @@ namespace OpenSim.Region.RegionCombinerModule
extents.Y = rootConn.YEnd; extents.Y = rootConn.YEnd;
extents.X = rootConn.XEnd; extents.X = rootConn.XEnd;
scene.BordersLocked = true;
rootConn.RegionScene.BordersLocked = true;
RegionData ConnectedRegion = new RegionData(); RegionData ConnectedRegion = new RegionData();
ConnectedRegion.Offset = offset; ConnectedRegion.Offset = offset;
ConnectedRegion.RegionId = scene.RegionInfo.originRegionID; ConnectedRegion.RegionId = scene.RegionInfo.originRegionID;
@ -618,67 +595,10 @@ namespace OpenSim.Region.RegionCombinerModule
rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents); rootConn.RegionScene.PhysicsScene.Combine(null, Vector3.Zero, extents);
scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero); scene.PhysicsScene.Combine(rootConn.RegionScene.PhysicsScene, offset, Vector3.Zero);
lock (rootConn.RegionScene.NorthBorders)
{
if (rootConn.RegionScene.NorthBorders.Count == 1)// && 2)
{
//compound border
// already locked above
rootConn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
lock (rootConn.RegionScene.EastBorders)
rootConn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
lock (rootConn.RegionScene.WestBorders)
rootConn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
}
}
lock (scene.SouthBorders)
{
scene.SouthBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocY - rootConn.RegionScene.RegionInfo.RegionLocY) * (int)Constants.RegionSize); //auto teleport south
scene.SouthBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
scene.SouthBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
}
lock (rootConn.RegionScene.EastBorders)
{
if (rootConn.RegionScene.EastBorders.Count == 1)// && conn.RegionScene.EastBorders.Count == 2)
{
rootConn.RegionScene.EastBorders[0].BorderLine.Z += (int)Constants.RegionSize;
lock (rootConn.RegionScene.NorthBorders)
rootConn.RegionScene.NorthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
lock (rootConn.RegionScene.SouthBorders)
rootConn.RegionScene.SouthBorders[0].BorderLine.Y += (int)Constants.RegionSize;
}
}
lock (scene.WestBorders)
{
scene.WestBorders[0].BorderLine.Z = (int)((scene.RegionInfo.RegionLocX - rootConn.RegionScene.RegionInfo.RegionLocX) * (int)Constants.RegionSize); //auto teleport West
scene.WestBorders[0].TriggerRegionX = rootConn.RegionScene.RegionInfo.RegionLocX;
scene.WestBorders[0].TriggerRegionY = rootConn.RegionScene.RegionInfo.RegionLocY;
}
/*
else
{
conn.RegionScene.NorthBorders[0].BorderLine.Z += (int)Constants.RegionSize;
conn.RegionScene.EastBorders[0].BorderLine.Y += (int)Constants.RegionSize;
conn.RegionScene.WestBorders[0].BorderLine.Y += (int)Constants.RegionSize;
scene.SouthBorders[0].BorderLine.Z += (int)Constants.RegionSize; //auto teleport south
}
*/
// Reset Terrain.. since terrain normally loads first. // Reset Terrain.. since terrain normally loads first.
//conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised()); scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
//conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised()); //conn.RegionScene.PhysicsScene.SetTerrain(conn.RegionScene.Heightmap.GetFloatsSerialised());
scene.BordersLocked = false;
rootConn.RegionScene.BordersLocked = false;
if (rootConn.ClientEventForwarder != null) if (rootConn.ClientEventForwarder != null)
rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene); rootConn.ClientEventForwarder.AddSceneToEventForwarding(scene);
@ -687,6 +607,7 @@ namespace OpenSim.Region.RegionCombinerModule
//scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents); //scene.PhysicsScene.Combine(conn.RegionScene.PhysicsScene, offset,extents);
} }
*/
private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene) private void DoWorkForRootRegion(RegionConnections rootConn, Scene scene)
{ {
@ -885,125 +806,6 @@ namespace OpenSim.Region.RegionCombinerModule
// } // }
// } // }
// Create a set of infinite borders around the whole aabb of the combined island.
private void AdjustLargeRegionBounds()
{
lock (m_regions)
{
foreach (RegionConnections rconn in m_regions.Values)
{
Vector3 offset = Vector3.Zero;
rconn.RegionScene.BordersLocked = true;
foreach (RegionData rdata in rconn.ConnectedRegions)
{
if (rdata.Offset.X > offset.X) offset.X = rdata.Offset.X;
if (rdata.Offset.Y > offset.Y) offset.Y = rdata.Offset.Y;
}
lock (rconn.RegionScene.NorthBorders)
{
Border northBorder = null;
// If we don't already have an infinite border, create one.
if (!TryGetInfiniteBorder(rconn.RegionScene.NorthBorders, out northBorder))
{
northBorder = new Border();
rconn.RegionScene.NorthBorders.Add(northBorder);
}
northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue,
offset.Y + (int) Constants.RegionSize); //<---
northBorder.CrossDirection = Cardinals.N;
}
lock (rconn.RegionScene.SouthBorders)
{
Border southBorder = null;
// If we don't already have an infinite border, create one.
if (!TryGetInfiniteBorder(rconn.RegionScene.SouthBorders, out southBorder))
{
southBorder = new Border();
rconn.RegionScene.SouthBorders.Add(southBorder);
}
southBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, 0); //--->
southBorder.CrossDirection = Cardinals.S;
}
lock (rconn.RegionScene.EastBorders)
{
Border eastBorder = null;
// If we don't already have an infinite border, create one.
if (!TryGetInfiniteBorder(rconn.RegionScene.EastBorders, out eastBorder))
{
eastBorder = new Border();
rconn.RegionScene.EastBorders.Add(eastBorder);
}
eastBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, offset.X + (int)Constants.RegionSize);
//<---
eastBorder.CrossDirection = Cardinals.E;
}
lock (rconn.RegionScene.WestBorders)
{
Border westBorder = null;
// If we don't already have an infinite border, create one.
if (!TryGetInfiniteBorder(rconn.RegionScene.WestBorders, out westBorder))
{
westBorder = new Border();
rconn.RegionScene.WestBorders.Add(westBorder);
}
westBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, 0); //--->
westBorder.CrossDirection = Cardinals.W;
}
rconn.RegionScene.BordersLocked = false;
}
}
}
/// <summary>
/// Try and get an Infinite border out of a listT of borders
/// </summary>
/// <param name="borders"></param>
/// <param name="oborder"></param>
/// <returns></returns>
public static bool TryGetInfiniteBorder(List<Border> borders, out Border oborder)
{
// Warning! Should be locked before getting here!
foreach (Border b in borders)
{
if (b.BorderLine.X == float.MinValue && b.BorderLine.Y == float.MaxValue)
{
oborder = b;
return true;
}
}
oborder = null;
return false;
}
public RegionData GetRegionFromPosition(Vector3 pPosition)
{
pPosition = pPosition/(int) Constants.RegionSize;
int OffsetX = (int) pPosition.X;
int OffsetY = (int) pPosition.Y;
lock (m_regions)
{
foreach (RegionConnections regConn in m_regions.Values)
{
foreach (RegionData reg in regConn.ConnectedRegions)
{
if (reg.Offset.X == OffsetX && reg.Offset.Y == OffsetY)
return reg;
}
}
}
return new RegionData();
}
public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion) public void ForwardPermissionRequests(RegionConnections BigRegion, Scene VirtualRegion)
{ {
if (BigRegion.PermissionModule == null) if (BigRegion.PermissionModule == null)

View File

@ -64,12 +64,12 @@ namespace OpenSim.Region.RegionCombinerModule
/// <summary> /// <summary>
/// The X meters position of this connection. /// The X meters position of this connection.
/// </summary> /// </summary>
public uint PosX { get { return X * Constants.RegionSize; } } public uint PosX { get { return Util.RegionToWorldLoc(X); } }
/// <summary> /// <summary>
/// The Y meters co-ordinate of this connection. /// The Y meters co-ordinate of this connection.
/// </summary> /// </summary>
public uint PosY { get { return Y * Constants.RegionSize; } } public uint PosY { get { return Util.RegionToWorldLoc(Y); } }
/// <summary> /// <summary>
/// The size of the megaregion in meters. /// The size of the megaregion in meters.
@ -91,4 +91,4 @@ namespace OpenSim.Region.RegionCombinerModule
YEnd = (uint)extents.Y; YEnd = (uint)extents.Y;
} }
} }
} }

View File

@ -2352,7 +2352,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// //
// This workaround is to prevent silent failure of this function. // This workaround is to prevent silent failure of this function.
// According to the specification on the SL Wiki, providing a position outside of the // According to the specification on the SL Wiki, providing a position outside of the
if (pos.x < 0 || pos.x > Constants.RegionSize || pos.y < 0 || pos.y > Constants.RegionSize) if (pos.x < 0 || pos.x > World.RegionInfo.RegionSizeX || pos.y < 0 || pos.y > World.RegionInfo.RegionSizeY)
{ {
return 0; return 0;
} }
@ -2362,9 +2362,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
m_host.ParentGroup.IsAttachment || // return FALSE if attachment m_host.ParentGroup.IsAttachment || // return FALSE if attachment
( (
pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region. pos.x < -10.0 || // return FALSE if more than 10 meters into a west-adjacent region.
pos.x > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a east-adjacent region. pos.x > (World.RegionInfo.RegionSizeX + 10) || // return FALSE if more than 10 meters into a east-adjacent region.
pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region. pos.y < -10.0 || // return FALSE if more than 10 meters into a south-adjacent region.
pos.y > (Constants.RegionSize + 10) || // return FALSE if more than 10 meters into a north-adjacent region. pos.y > (World.RegionInfo.RegionSizeY + 10) || // return FALSE if more than 10 meters into a north-adjacent region.
pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m pos.z > Constants.RegionHeight // return FALSE if altitude than 4096m
) )
) )
@ -4655,10 +4655,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
DataserverPlugin.RegisterRequest(m_host.LocalId, DataserverPlugin.RegisterRequest(m_host.LocalId,
m_item.ItemID, item.AssetID.ToString()); m_item.ItemID, item.AssetID.ToString());
Vector3 region = new Vector3( Vector3 region = new Vector3(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
World.RegionInfo.RegionLocX * Constants.RegionSize,
World.RegionInfo.RegionLocY * Constants.RegionSize,
0);
World.AssetService.Get(item.AssetID.ToString(), this, World.AssetService.Get(item.AssetID.ToString(), this,
delegate(string i, object sender, AssetBase a) delegate(string i, object sender, AssetBase a)
@ -5949,7 +5946,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public LSL_Vector llGetRegionCorner() public LSL_Vector llGetRegionCorner()
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
return new LSL_Vector(World.RegionInfo.RegionLocX * Constants.RegionSize, World.RegionInfo.RegionLocY * Constants.RegionSize, 0); return new LSL_Vector(World.RegionInfo.WorldLocX, World.RegionInfo.WorldLocY, 0);
} }
/// <summary> /// <summary>
@ -6104,7 +6101,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
LSL_Float mag; LSL_Float mag;
if (dir.x > 0) if (dir.x > 0)
{ {
mag = (Constants.RegionSize - pos.x) / dir.x; mag = (World.RegionInfo.RegionSizeX - pos.x) / dir.x;
} }
else else
{ {
@ -6115,7 +6112,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
edge.y = pos.y + (dir.y * mag); edge.y = pos.y + (dir.y * mag);
if (edge.y > Constants.RegionSize || edge.y < 0) if (edge.y > World.RegionInfo.RegionSizeY || edge.y < 0)
{ {
// Y goes out of bounds first // Y goes out of bounds first
edge.y = dir.y / Math.Abs(dir.y); edge.y = dir.y / Math.Abs(dir.y);

View File

@ -459,7 +459,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
if (x > ((int)Constants.RegionSize - 1) || x < 0 || y > ((int)Constants.RegionSize - 1) || y < 0) if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0)
OSSLError("osSetTerrainHeight: Coordinate out of bounds"); OSSLError("osSetTerrainHeight: Coordinate out of bounds");
if (World.Permissions.CanTerraformLand(m_host.OwnerID, new Vector3(x, y, 0))) if (World.Permissions.CanTerraformLand(m_host.OwnerID, new Vector3(x, y, 0)))
@ -489,7 +489,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
private LSL_Float GetTerrainHeight(int x, int y) private LSL_Float GetTerrainHeight(int x, int y)
{ {
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
if (x > ((int)Constants.RegionSize - 1) || x < 0 || y > ((int)Constants.RegionSize - 1) || y < 0) if (x > (World.RegionInfo.RegionSizeX - 1) || x < 0 || y > (World.RegionInfo.RegionSizeY - 1) || y < 0)
OSSLError("osGetTerrainHeight: Coordinate out of bounds"); OSSLError("osGetTerrainHeight: Coordinate out of bounds");
return World.Heightmap[x, y]; return World.Heightmap[x, y];
@ -823,7 +823,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
private void TeleportAgent(string agent, int regionX, int regionY, private void TeleportAgent(string agent, int regionX, int regionY,
LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions) LSL_Types.Vector3 position, LSL_Types.Vector3 lookat, bool relaxRestrictions)
{ {
ulong regionHandle = Util.UIntsToLong(((uint)regionX * (uint)Constants.RegionSize), ((uint)regionY * (uint)Constants.RegionSize)); ulong regionHandle = Util.RegionLocToHandle((uint)regionX, (uint)regionY);
m_host.AddScriptLPS(1); m_host.AddScriptLPS(1);
UUID agentId = new UUID(); UUID agentId = new UUID();
@ -3024,7 +3024,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
} }
else else
{ {
return new LSL_Vector((float)Constants.RegionSize, (float)Constants.RegionSize, Constants.RegionHeight); return new LSL_Vector((float)World.RegionInfo.RegionSizeX,
(float)World.RegionInfo.RegionSizeY,
(float)World.RegionInfo.RegionSizeZ );
} }
} }

View File

@ -708,18 +708,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
} }
private void Save() private void Save()
{ {
/* Remove temporarily until we have a handle to the region size
if (Position.x > ((int)Constants.RegionSize - 1)) if (Position.x > ((int)Constants.RegionSize - 1))
Position.x = ((int)Constants.RegionSize - 1); Position.x = ((int)Constants.RegionSize - 1);
if (Position.x < 0)
Position.x = 0;
if (Position.y > ((int)Constants.RegionSize - 1)) if (Position.y > ((int)Constants.RegionSize - 1))
Position.y = ((int)Constants.RegionSize - 1); Position.y = ((int)Constants.RegionSize - 1);
*/
if (Position.x < 0)
Position.x = 0;
if (Position.y < 0) if (Position.y < 0)
Position.y = 0; Position.y = 0;
if (Position.z > 768)
Position.z = 768;
if (Position.z < 0) if (Position.z < 0)
Position.z = 0; Position.z = 0;
if (Position.z > Constants.RegionHeight)
Position.z = Constants.RegionHeight;
prim.OSSL.llSetPos(Position); prim.OSSL.llSetPos(Position);
} }

View File

@ -133,7 +133,7 @@ namespace OpenSim.Server.Handlers.MapImage
if (m_GridService != null) if (m_GridService != null)
{ {
System.Net.IPAddress ipAddr = GetCallerIP(httpRequest); System.Net.IPAddress ipAddr = GetCallerIP(httpRequest);
GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, x * (int)Constants.RegionSize, y * (int)Constants.RegionSize); GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc((uint)x), (int)Util.RegionToWorldLoc((uint)y));
if (r != null) if (r != null)
{ {
if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString()) if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString())

View File

@ -128,7 +128,7 @@ namespace OpenSim.Server.Handlers.MapImage
if (m_GridService != null) if (m_GridService != null)
{ {
System.Net.IPAddress ipAddr = GetCallerIP(httpRequest); System.Net.IPAddress ipAddr = GetCallerIP(httpRequest);
GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, x * (int)Constants.RegionSize, y * (int)Constants.RegionSize); GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, (int)Util.RegionToWorldLoc((uint)x), (int)Util.RegionToWorldLoc((uint)y));
if (r != null) if (r != null)
{ {
if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString()) if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString())

View File

@ -112,7 +112,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
// m_log.Warn("Registering region " + regionInfo.RegionName + " (" + regionInfo.RegionID + ") that we are not tracking"); // m_log.Warn("Registering region " + regionInfo.RegionName + " (" + regionInfo.RegionID + ") that we are not tracking");
Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0); Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0);
Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); Vector3d maxPosition = minPosition + new Vector3d(regionInfo.RegionSizeX, regionInfo.RegionSizeY, Constants.RegionHeight);
OSDMap extraData = new OSDMap OSDMap extraData = new OSDMap
{ {
@ -174,8 +174,8 @@ namespace OpenSim.Services.Connectors.SimianGrid
if (region != null) if (region != null)
{ {
List<GridRegion> regions = GetRegionRange(scopeID, List<GridRegion> regions = GetRegionRange(scopeID,
region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + (int)Constants.RegionSize + NEIGHBOR_RADIUS, region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + region.RegionSizeX + NEIGHBOR_RADIUS,
region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + (int)Constants.RegionSize + NEIGHBOR_RADIUS); region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + region.RegionSizeY + NEIGHBOR_RADIUS);
for (int i = 0; i < regions.Count; i++) for (int i = 0; i < regions.Count; i++)
{ {
@ -240,7 +240,7 @@ namespace OpenSim.Services.Connectors.SimianGrid
else else
{ {
// m_log.InfoFormat("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}", // m_log.InfoFormat("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}",
// x / Constants.RegionSize, y / Constants.RegionSize); // Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
return null; return null;
} }
} }

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

@ -655,7 +655,7 @@ namespace OpenSim.Services.GridService
return; return;
} }
RegionData region = m_Database.Get(x * (int)Constants.RegionSize, y * (int)Constants.RegionSize, UUID.Zero); RegionData region = m_Database.Get((int)Util.RegionToWorldLoc((uint)x), (int)Util.RegionToWorldLoc((uint)y), UUID.Zero);
if (region == null) if (region == null)
{ {
MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y); MainConsole.Instance.OutputFormat("No region found at {0},{1}", x, y);
@ -673,6 +673,7 @@ namespace OpenSim.Services.GridService
dispList.AddRow("Region Name", r.RegionName); dispList.AddRow("Region Name", r.RegionName);
dispList.AddRow("Region ID", r.RegionID); dispList.AddRow("Region ID", r.RegionID);
dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY)); dispList.AddRow("Location", string.Format("{0},{1}", r.coordX, r.coordY));
dispList.AddRow("Size", string.Format("{0}x{1}", r.sizeX, r.sizeY));
dispList.AddRow("URI", r.Data["serverURI"]); dispList.AddRow("URI", r.Data["serverURI"]);
dispList.AddRow("Owner ID", r.Data["owner_uuid"]); dispList.AddRow("Owner ID", r.Data["owner_uuid"]);
dispList.AddRow("Flags", flags); dispList.AddRow("Flags", flags);

View File

@ -183,8 +183,8 @@ namespace OpenSim.Services.GridService
public GridRegion LinkRegion(UUID scopeID, string regionDescriptor) public GridRegion LinkRegion(UUID scopeID, string regionDescriptor)
{ {
string reason = string.Empty; string reason = string.Empty;
int xloc = random.Next(0, Int16.MaxValue) * (int)Constants.RegionSize; uint xloc = Util.RegionToWorldLoc((uint)random.Next(0, Int16.MaxValue));
return TryLinkRegionToCoords(scopeID, regionDescriptor, xloc, 0, out reason); return TryLinkRegionToCoords(scopeID, regionDescriptor, (int)xloc, 0, out reason);
} }
private static Random random = new Random(); private static Random random = new Random();
@ -260,7 +260,7 @@ namespace OpenSim.Services.GridService
{ {
m_log.DebugFormat("[HYPERGRID LINKER]: Link to {0} {1}, in {2}-{3}", m_log.DebugFormat("[HYPERGRID LINKER]: Link to {0} {1}, in {2}-{3}",
((serverURI == null) ? (externalHostName + ":" + externalPort) : serverURI), ((serverURI == null) ? (externalHostName + ":" + externalPort) : serverURI),
remoteRegionName, xloc / Constants.RegionSize, yloc / Constants.RegionSize); remoteRegionName, Util.WorldToRegionLoc((uint)xloc), Util.WorldToRegionLoc((uint)yloc));
reason = string.Empty; reason = string.Empty;
Uri uri = null; Uri uri = null;
@ -311,7 +311,7 @@ namespace OpenSim.Services.GridService
if (region != null) if (region != null)
{ {
m_log.WarnFormat("[HYPERGRID LINKER]: Coordinates {0}-{1} are already occupied by region {2} with uuid {3}", m_log.WarnFormat("[HYPERGRID LINKER]: Coordinates {0}-{1} are already occupied by region {2} with uuid {3}",
regInfo.RegionLocX / Constants.RegionSize, regInfo.RegionLocY / Constants.RegionSize, Util.WorldToRegionLoc((uint)regInfo.RegionLocX), Util.WorldToRegionLoc((uint)regInfo.RegionLocY),
region.RegionName, region.RegionID); region.RegionName, region.RegionID);
reason = "Coordinates are already in use"; reason = "Coordinates are already in use";
return false; return false;
@ -347,7 +347,7 @@ namespace OpenSim.Services.GridService
if (region != null) if (region != null)
{ {
m_log.DebugFormat("[HYPERGRID LINKER]: Region already exists in coordinates {0} {1}", m_log.DebugFormat("[HYPERGRID LINKER]: Region already exists in coordinates {0} {1}",
region.RegionLocX / Constants.RegionSize, region.RegionLocY / Constants.RegionSize); Util.WorldToRegionLoc((uint)regInfo.RegionLocX), Util.WorldToRegionLoc((uint)regInfo.RegionLocY));
regInfo = region; regInfo = region;
return true; return true;
} }
@ -424,10 +424,10 @@ namespace OpenSim.Services.GridService
// { // {
// uint ux = 0, uy = 0; // uint ux = 0, uy = 0;
// Utils.LongToUInts(realHandle, out ux, out uy); // Utils.LongToUInts(realHandle, out ux, out uy);
// x = ux / Constants.RegionSize; // x = Util.WorldToRegionLoc(ux);
// y = uy / Constants.RegionSize; // y = Util.WorldToRegionLoc(uy);
// //
// const uint limit = (4096 - 1) * Constants.RegionSize; // const uint limit = Util.RegionToWorldLoc(4096 - 1);
// uint xmin = ux - limit; // uint xmin = ux - limit;
// uint xmax = ux + limit; // uint xmax = ux + limit;
// uint ymin = uy - limit; // uint ymin = uy - limit;
@ -503,8 +503,9 @@ namespace OpenSim.Services.GridService
foreach (RegionData r in regions) foreach (RegionData r in regions)
{ {
MainConsole.Instance.Output(String.Format("{0}\n{2,-32} {1}\n", MainConsole.Instance.Output(String.Format("{0}\n{2,-32} {1}\n",
r.RegionName, r.RegionID, String.Format("{0},{1} ({2},{3})", r.posX, r.posY, r.RegionName, r.RegionID,
r.posX / Constants.RegionSize, r.posY / Constants.RegionSize))); String.Format("{0},{1} ({2},{3})", r.posX, r.posY,
Util.WorldToRegionLoc((uint)r.posX), Util.WorldToRegionLoc((uint)r.posY))) );
} }
return; return;
} }
@ -529,8 +530,8 @@ namespace OpenSim.Services.GridService
int xloc, yloc; int xloc, yloc;
string serverURI; string serverURI;
string remoteName = null; string remoteName = null;
xloc = Convert.ToInt32(cmdparams[0]) * (int)Constants.RegionSize; xloc = (int)Util.RegionToWorldLoc((uint)Convert.ToInt32(cmdparams[0]));
yloc = Convert.ToInt32(cmdparams[1]) * (int)Constants.RegionSize; yloc = (int)Util.RegionToWorldLoc((uint)Convert.ToInt32(cmdparams[1]));
serverURI = cmdparams[2]; serverURI = cmdparams[2];
if (cmdparams.Length > 3) if (cmdparams.Length > 3)
remoteName = string.Join(" ", cmdparams, 3, cmdparams.Length - 3); remoteName = string.Join(" ", cmdparams, 3, cmdparams.Length - 3);
@ -601,13 +602,13 @@ namespace OpenSim.Services.GridService
{ {
// old format // old format
GridRegion regInfo; GridRegion regInfo;
int xloc, yloc; uint xloc, yloc;
uint externalPort; uint externalPort;
string externalHostName; string externalHostName;
try try
{ {
xloc = Convert.ToInt32(cmdparams[0]); xloc = (uint)Convert.ToInt32(cmdparams[0]);
yloc = Convert.ToInt32(cmdparams[1]); yloc = (uint)Convert.ToInt32(cmdparams[1]);
externalPort = Convert.ToUInt32(cmdparams[3]); externalPort = Convert.ToUInt32(cmdparams[3]);
externalHostName = cmdparams[2]; externalHostName = cmdparams[2];
//internalPort = Convert.ToUInt32(cmdparams[4]); //internalPort = Convert.ToUInt32(cmdparams[4]);
@ -621,10 +622,11 @@ namespace OpenSim.Services.GridService
} }
// Convert cell coordinates given by the user to meters // Convert cell coordinates given by the user to meters
xloc = xloc * (int)Constants.RegionSize; xloc = Util.RegionToWorldLoc(xloc);
yloc = yloc * (int)Constants.RegionSize; yloc = Util.RegionToWorldLoc(yloc);
string reason = string.Empty; string reason = string.Empty;
if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) if (TryCreateLink(UUID.Zero, (int)xloc, (int)yloc,
string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason))
{ {
// What is this? The GridRegion instance will be discarded anyway, // What is this? The GridRegion instance will be discarded anyway,
// which effectively ignores any local name given with the command. // which effectively ignores any local name given with the command.
@ -704,13 +706,13 @@ namespace OpenSim.Services.GridService
private void ReadLinkFromConfig(IConfig config) private void ReadLinkFromConfig(IConfig config)
{ {
GridRegion regInfo; GridRegion regInfo;
int xloc, yloc; uint xloc, yloc;
uint externalPort; uint externalPort;
string externalHostName; string externalHostName;
uint realXLoc, realYLoc; uint realXLoc, realYLoc;
xloc = Convert.ToInt32(config.GetString("xloc", "0")); xloc = (uint)Convert.ToInt32(config.GetString("xloc", "0"));
yloc = Convert.ToInt32(config.GetString("yloc", "0")); yloc = (uint)Convert.ToInt32(config.GetString("yloc", "0"));
externalPort = Convert.ToUInt32(config.GetString("externalPort", "0")); externalPort = Convert.ToUInt32(config.GetString("externalPort", "0"));
externalHostName = config.GetString("externalHostName", ""); externalHostName = config.GetString("externalHostName", "");
realXLoc = Convert.ToUInt32(config.GetString("real-xloc", "0")); realXLoc = Convert.ToUInt32(config.GetString("real-xloc", "0"));
@ -718,18 +720,19 @@ namespace OpenSim.Services.GridService
if (m_enableAutoMapping) if (m_enableAutoMapping)
{ {
xloc = (int)((xloc % 100) + m_autoMappingX); xloc = (uint)((xloc % 100) + m_autoMappingX);
yloc = (int)((yloc % 100) + m_autoMappingY); yloc = (uint)((yloc % 100) + m_autoMappingY);
} }
if (((realXLoc == 0) && (realYLoc == 0)) || if (((realXLoc == 0) && (realYLoc == 0)) ||
(((realXLoc - xloc < 3896) || (xloc - realXLoc < 3896)) && (((realXLoc - xloc < 3896) || (xloc - realXLoc < 3896)) &&
((realYLoc - yloc < 3896) || (yloc - realYLoc < 3896)))) ((realYLoc - yloc < 3896) || (yloc - realYLoc < 3896))))
{ {
xloc = xloc * (int)Constants.RegionSize; xloc = Util.RegionToWorldLoc(xloc);
yloc = yloc * (int)Constants.RegionSize; yloc = Util.RegionToWorldLoc(yloc);
string reason = string.Empty; string reason = string.Empty;
if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) if (TryCreateLink(UUID.Zero, (int)xloc, (int)yloc,
string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason))
{ {
regInfo.RegionName = config.GetString("localName", ""); regInfo.RegionName = config.GetString("localName", "");
} }

View File

@ -179,14 +179,14 @@ namespace OpenSim.Services.Interfaces
protected IPEndPoint m_internalEndPoint; protected IPEndPoint m_internalEndPoint;
/// <summary> /// <summary>
/// The co-ordinate of this region. /// The co-ordinate of this region in region units.
/// </summary> /// </summary>
public int RegionCoordX { get { return RegionLocX / (int)Constants.RegionSize; } } public int RegionCoordX { get { return (int)Util.WorldToRegionLoc((uint)RegionLocX); } }
/// <summary> /// <summary>
/// The co-ordinate of this region /// The co-ordinate of this region in region units
/// </summary> /// </summary>
public int RegionCoordY { get { return RegionLocY / (int)Constants.RegionSize; } } public int RegionCoordY { get { return (int)Util.WorldToRegionLoc((uint)RegionLocY); } }
/// <summary> /// <summary>
/// The location of this region in meters. /// The location of this region in meters.
@ -265,8 +265,8 @@ namespace OpenSim.Services.Interfaces
public GridRegion(uint xcell, uint ycell) public GridRegion(uint xcell, uint ycell)
{ {
m_regionLocX = (int)(xcell * Constants.RegionSize); m_regionLocX = (int)Util.RegionToWorldLoc(xcell);
m_regionLocY = (int)(ycell * Constants.RegionSize); m_regionLocY = (int)Util.RegionToWorldLoc(ycell);
RegionSizeX = (int)Constants.RegionSize; RegionSizeX = (int)Constants.RegionSize;
RegionSizeY = (int)Constants.RegionSize; RegionSizeY = (int)Constants.RegionSize;
} }
@ -274,8 +274,8 @@ namespace OpenSim.Services.Interfaces
public GridRegion(RegionInfo ConvertFrom) public GridRegion(RegionInfo ConvertFrom)
{ {
m_regionName = ConvertFrom.RegionName; m_regionName = ConvertFrom.RegionName;
m_regionLocX = (int)(ConvertFrom.RegionLocX * Constants.RegionSize); m_regionLocX = (int)(ConvertFrom.WorldLocX);
m_regionLocY = (int)(ConvertFrom.RegionLocY * Constants.RegionSize); m_regionLocY = (int)(ConvertFrom.WorldLocY);
RegionSizeX = (int)ConvertFrom.RegionSizeX; RegionSizeX = (int)ConvertFrom.RegionSizeX;
RegionSizeY = (int)ConvertFrom.RegionSizeY; RegionSizeY = (int)ConvertFrom.RegionSizeY;
m_internalEndPoint = ConvertFrom.InternalEndPoint; m_internalEndPoint = ConvertFrom.InternalEndPoint;

View File

@ -368,7 +368,8 @@ namespace OpenSim.Services.LLLoginService
private void FillOutHomeData(GridUserInfo pinfo, GridRegion home) private void FillOutHomeData(GridUserInfo pinfo, GridRegion home)
{ {
int x = 1000 * (int)Constants.RegionSize, y = 1000 * (int)Constants.RegionSize; int x = (int)Util.RegionToWorldLoc(1000);
int y = (int)Util.RegionToWorldLoc(1000);
if (home != null) if (home != null)
{ {
x = home.RegionLocX; x = home.RegionLocX;
@ -443,10 +444,23 @@ namespace OpenSim.Services.LLLoginService
ErrorReason = "key"; ErrorReason = "key";
welcomeMessage = "Welcome to OpenSim!"; welcomeMessage = "Welcome to OpenSim!";
seedCapability = String.Empty; seedCapability = String.Empty;
home = "{'region_handle':[r" + (1000*Constants.RegionSize).ToString() + ",r" + (1000*Constants.RegionSize).ToString() + "], 'position':[r" + home = "{'region_handle':["
userProfile.homepos.X.ToString() + ",r" + userProfile.homepos.Y.ToString() + ",r" + + "r" + Util.RegionToWorldLoc(1000).ToString()
userProfile.homepos.Z.ToString() + "], 'look_at':[r" + userProfile.homelookat.X.ToString() + ",r" + + ","
userProfile.homelookat.Y.ToString() + ",r" + userProfile.homelookat.Z.ToString() + "]}"; + "r" + Util.RegionToWorldLoc(1000).ToString()
+ "], 'position':["
+ "r" + userProfile.homepos.X.ToString()
+ ","
+ "r" + userProfile.homepos.Y.ToString()
+ ","
+ "r" + userProfile.homepos.Z.ToString()
+ "], 'look_at':["
+ "r" + userProfile.homelookat.X.ToString()
+ ","
+ "r" + userProfile.homelookat.Y.ToString()
+ ","
+ "r" + userProfile.homelookat.Z.ToString()
+ "]}";
lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]"; lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]";
RegionX = (uint) 255232; RegionX = (uint) 255232;
RegionY = (uint) 254976; RegionY = (uint) 254976;

View File

@ -695,7 +695,7 @@ namespace OpenSim.Services.LLLoginService
private GridRegion FindAlternativeRegion(UUID scopeID) private GridRegion FindAlternativeRegion(UUID scopeID)
{ {
List<GridRegion> hyperlinks = null; List<GridRegion> hyperlinks = null;
List<GridRegion> regions = m_GridService.GetFallbackRegions(scopeID, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); List<GridRegion> regions = m_GridService.GetFallbackRegions(scopeID, (int)Util.RegionToWorldLoc(1000), (int)Util.RegionToWorldLoc(1000));
if (regions != null && regions.Count > 0) if (regions != null && regions.Count > 0)
{ {
hyperlinks = m_GridService.GetHyperlinks(scopeID); hyperlinks = m_GridService.GetHyperlinks(scopeID);

View File

@ -150,16 +150,16 @@ namespace OpenSim.Tests.Clients.GridClient
Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 2 regions)"); Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 2 regions)");
regions = m_Connector.GetRegionRange(UUID.Zero, regions = m_Connector.GetRegionRange(UUID.Zero,
900 * (int)Constants.RegionSize, 1002 * (int) Constants.RegionSize, (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002),
900 * (int)Constants.RegionSize, 1002 * (int) Constants.RegionSize); (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(1002) );
if (regions == null) if (regions == null)
Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null");
else else
Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions"); Console.WriteLine("[GRID CLIENT]: GetRegionRange returned " + regions.Count + " regions");
Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 0 regions)"); Console.WriteLine("[GRID CLIENT]: *** GetRegionRange (this should return 0 regions)");
regions = m_Connector.GetRegionRange(UUID.Zero, regions = m_Connector.GetRegionRange(UUID.Zero,
900 * (int)Constants.RegionSize, 950 * (int)Constants.RegionSize, (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950),
900 * (int)Constants.RegionSize, 950 * (int)Constants.RegionSize); (int)Util.RegionToWorldLoc(900), (int)Util.RegionToWorldLoc(950) );
if (regions == null) if (regions == null)
Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null"); Console.WriteLine("[GRID CLIENT]: GetRegionRange returned null");
else else

View File

@ -69,9 +69,7 @@ namespace OpenSim.Tests.Common
tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) => tc.OnTestClientInformClientOfNeighbour += (neighbourHandle, neighbourExternalEndPoint) =>
{ {
uint x, y; uint x, y;
Utils.LongToUInts(neighbourHandle, out x, out y); Util.RegionHandleToRegionLoc(neighbourHandle, out x, out y);
x /= Constants.RegionSize;
y /= Constants.RegionSize;
m_log.DebugFormat( m_log.DebugFormat(
"[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}", "[TEST CLIENT]: Processing inform client of neighbour located at {0},{1} at {2}",
@ -104,9 +102,7 @@ namespace OpenSim.Tests.Common
+= (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) => += (regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL) =>
{ {
uint x, y; uint x, y;
Utils.LongToUInts(regionHandle, out x, out y); Util.RegionHandleToRegionLoc(regionHandle, out x, out y);
x /= Constants.RegionSize;
y /= Constants.RegionSize;
m_log.DebugFormat( m_log.DebugFormat(
"[TEST CLIENT]: Processing send region teleport for destination at {0},{1} at {2}", "[TEST CLIENT]: Processing send region teleport for destination at {0},{1} at {2}",
@ -125,4 +121,4 @@ namespace OpenSim.Tests.Common
}; };
} }
} }
} }

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);
@ -159,7 +169,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)
@ -304,15 +314,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;
} }