Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fc289c039 | ||
|
|
877bdcdce1 | ||
|
|
bdbbeaa494 | ||
|
|
f6913e911e | ||
|
|
f74aafaf63 | ||
|
|
4fed301e65 | ||
|
|
733e067958 | ||
|
|
ffd0da23fb | ||
|
|
f49d513089 | ||
|
|
fc35b45e21 | ||
|
|
bc7fda39b4 | ||
|
|
e10012a7a6 | ||
|
|
3a7c8d1f32 | ||
|
|
c0cc5e0fa4 | ||
|
|
b83a224147 | ||
|
|
4a1c1fc009 | ||
|
|
cf61cdf58c | ||
|
|
1913ab5ad5 | ||
|
|
29c8461631 | ||
|
|
8f372b8ac8 | ||
|
|
342be228c6 | ||
|
|
87abf06956 | ||
|
|
f81841a2c5 | ||
|
|
1b41ec0a85 | ||
|
|
31cba5aa66 | ||
|
|
1aed6567a8 | ||
|
|
f0f852b27f | ||
|
|
1197658233 | ||
|
|
e1d1c27965 | ||
|
|
49c2213a01 | ||
|
|
41b6602a77 | ||
|
|
8c6a0cb44a | ||
|
|
2a4dd34616 | ||
|
|
9c97fb8e12 | ||
|
|
a8e64cd59a | ||
|
|
abb193ec94 | ||
|
|
b2878eb773 | ||
|
|
b8e22f02e7 | ||
|
|
1380b37d71 | ||
|
|
3d62f4369d | ||
|
|
d405254971 | ||
|
|
9db4090c07 | ||
|
|
c9550e473d | ||
|
|
257f9cec40 | ||
|
|
13bb9ea682 | ||
|
|
67ec95bde8 | ||
|
|
c467dfcd81 | ||
|
|
b73baeb4a4 | ||
|
|
b50e5704b8 | ||
|
|
7807b19a89 | ||
|
|
bdab05df0e | ||
|
|
0842e2e15b | ||
|
|
fbf33ef1de | ||
|
|
3f5c6c897f | ||
|
|
1900254e77 | ||
|
|
678c107915 | ||
|
|
dde0e547a7 | ||
|
|
226b5e4d75 | ||
|
|
cfe1bced7d | ||
|
|
2877c7d94d | ||
|
|
0c3493f619 | ||
|
|
d25265ae82 | ||
|
|
1d533b0f01 | ||
|
|
bfb0011cd3 | ||
|
|
e5d59dc696 | ||
|
|
8eec717f5f | ||
|
|
4faf11e001 | ||
|
|
49af6b53e7 | ||
|
|
13a9d5409c | ||
|
|
6831e58616 | ||
|
|
afb2e07111 | ||
|
|
674a3a5639 | ||
|
|
4c362a83f9 | ||
|
|
90fa3202c6 | ||
|
|
5e6a47f13f | ||
|
|
6fbfb47b92 | ||
|
|
dd6db72939 | ||
|
|
f127e4b4ee | ||
|
|
54a4b9eab4 | ||
|
|
813f0da00b | ||
|
|
08fa0a6a8a | ||
|
|
60de0bc3c2 | ||
|
|
cc5cffc212 | ||
|
|
1eea6fd452 | ||
|
|
3760d10cd0 | ||
|
|
1cf17a3cf7 | ||
|
|
fd045d520e | ||
|
|
9984ecf862 | ||
|
|
01c0bbf181 | ||
|
|
2d2bea4aa7 | ||
|
|
e5f7c8b6e8 | ||
|
|
b40b57776b | ||
|
|
5c9fa15f30 | ||
|
|
a01862509e | ||
|
|
6937eec258 | ||
|
|
13a9a4b653 | ||
|
|
4eb52eb19e | ||
|
|
31bacfbb63 | ||
|
|
6cd0d7a62b | ||
|
|
109136c074 | ||
|
|
7aa00632b9 | ||
|
|
3193bcaae1 | ||
|
|
604b39cea9 | ||
|
|
d67236c09d | ||
|
|
e2a1fa806d | ||
|
|
c12e68e34d | ||
|
|
7061784cc6 | ||
|
|
beeec1c467 | ||
|
|
a7a837550e | ||
|
|
f7bd0da026 | ||
|
|
a75ce7423c | ||
|
|
d0854e4ace | ||
|
|
c931b16c1f | ||
|
|
f2810bf03a | ||
|
|
cd1a23fc14 | ||
|
|
ac94dc8a14 | ||
|
|
9bf363e9be | ||
|
|
79b031bd0c | ||
|
|
6df7d4219d | ||
|
|
f66737fe56 | ||
|
|
92c06a5d0b | ||
|
|
976530569a | ||
|
|
ff5885ab23 | ||
|
|
39777db8ef | ||
|
|
2be0347f50 | ||
|
|
c581506058 | ||
|
|
8937a2244d | ||
|
|
97bc5263de | ||
|
|
86bf79aa2b | ||
|
|
7416809077 | ||
|
|
25ae59b9eb | ||
|
|
9b150194f6 | ||
|
|
8c432c7c9b | ||
|
|
8c1d80fdfd | ||
|
|
aea5d3a842 | ||
|
|
fa1c688342 | ||
|
|
139639d25e | ||
|
|
317c04fe17 | ||
|
|
fbc9072a5c | ||
|
|
7fa64cce7d | ||
|
|
ab1474b5de | ||
|
|
0765a83a8c | ||
|
|
96abbbb6fb |
@@ -145,6 +145,7 @@ what it is today.
|
||||
* Richard Alimi (IBM)
|
||||
* Rick Alther (IBM)
|
||||
* Rob Smart (IBM)
|
||||
* Roger Kirkman (zadark)
|
||||
* rtomita
|
||||
* Ruud Lathorp
|
||||
* SachaMagne
|
||||
|
||||
@@ -1022,7 +1022,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
// Set home position
|
||||
|
||||
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)
|
||||
{
|
||||
m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", firstName, lastName);
|
||||
@@ -1252,7 +1252,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
if ((null != regionXLocation) && (null != regionYLocation))
|
||||
{
|
||||
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) {
|
||||
m_log.WarnFormat("[RADMIN]: Unable to set home region for updated user account {0} {1}", firstName, lastName);
|
||||
} else {
|
||||
@@ -1484,8 +1484,11 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
}
|
||||
|
||||
IRegionArchiverModule archiver = scene.RequestModuleInterface<IRegionArchiverModule>();
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string,object>();
|
||||
if (mergeOar) archiveOptions.Add("merge", null);
|
||||
if (skipAssets) archiveOptions.Add("skipAssets", null);
|
||||
if (archiver != null)
|
||||
archiver.DearchiveRegion(filename, mergeOar, skipAssets, Guid.Empty);
|
||||
archiver.DearchiveRegion(filename, Guid.Empty, archiveOptions);
|
||||
else
|
||||
throw new Exception("Archiver module not present for scene");
|
||||
|
||||
@@ -2881,7 +2884,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
// Set home position
|
||||
|
||||
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) {
|
||||
m_log.WarnFormat("[RADMIN]: Unable to set home region for newly created user account {0} {1}", names[0], names[1]);
|
||||
} else {
|
||||
|
||||
@@ -54,12 +54,12 @@ namespace OpenSim.Data
|
||||
/// <summary>
|
||||
/// Return the x-coordinate of this region.
|
||||
/// </summary>
|
||||
public int coordX { get { return posX / (int)Constants.RegionSize; } }
|
||||
public int coordX { get { return (int)Util.WorldToRegionLoc((uint)posX); } }
|
||||
|
||||
/// <summary>
|
||||
/// Return the y-coordinate of this region.
|
||||
/// </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;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace OpenSim.Data.MSSQL
|
||||
|
||||
// private static FileSystemDataStore Instance = new FileSystemDataStore();
|
||||
private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[REGION DB MSSQL]";
|
||||
|
||||
/// <summary>
|
||||
/// The database manager
|
||||
@@ -530,43 +531,53 @@ ELSE
|
||||
/// <returns></returns>
|
||||
public double[,] LoadTerrain(UUID regionID)
|
||||
{
|
||||
double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize];
|
||||
terrain.Initialize();
|
||||
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;
|
||||
|
||||
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 (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
// MySqlParameter param = new MySqlParameter();
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
|
||||
conn.Open();
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
int rev;
|
||||
if (reader.Read())
|
||||
// MySqlParameter param = new MySqlParameter();
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
|
||||
conn.Open();
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]);
|
||||
BinaryReader br = new BinaryReader(str);
|
||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
int rev;
|
||||
if (reader.Read())
|
||||
{
|
||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
{
|
||||
terrain[x, y] = br.ReadDouble();
|
||||
}
|
||||
rev = (int)reader["Revision"];
|
||||
byte[] blob = (byte[])reader["Heightfield"];
|
||||
terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
|
||||
}
|
||||
rev = (int)reader["Revision"];
|
||||
else
|
||||
{
|
||||
_Log.Info("[REGION DB]: No terrain found for region");
|
||||
return null;
|
||||
}
|
||||
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Log.Info("[REGION DB]: No terrain found for region");
|
||||
return null;
|
||||
}
|
||||
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
|
||||
}
|
||||
}
|
||||
|
||||
return terrain;
|
||||
return terrData;
|
||||
}
|
||||
|
||||
// Legacy entry point for when terrain was always a 256x256 hieghtmap
|
||||
public void StoreTerrain(double[,] ter, UUID regionID)
|
||||
{
|
||||
StoreTerrain(new HeightmapTerrainData(ter), regionID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -574,10 +585,8 @@ ELSE
|
||||
/// </summary>
|
||||
/// <param name="terrain">terrain map data.</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
|
||||
string sql = "delete from terrain where RegionUUID=@RegionUUID";
|
||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||
@@ -590,17 +599,23 @@ ELSE
|
||||
|
||||
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 (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@Revision", revision));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", serializeTerrain(terrain)));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", regionID));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@Revision", terrainDBRevision));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@Heightfield", terrainDBblob));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
||||
_Log.Info("[REGION DB]: Stored terrain revision r " + revision);
|
||||
_Log.InfoFormat("{0} Stored terrain revision r={1}", LogHeader, terrainDBRevision);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1344,30 +1359,6 @@ VALUES
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the terrain data for storage in DB.
|
||||
/// </summary>
|
||||
/// <param name="val">terrain data</param>
|
||||
/// <returns></returns>
|
||||
private static Array serializeTerrain(double[,] val)
|
||||
{
|
||||
MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double));
|
||||
BinaryWriter bw = new BinaryWriter(str);
|
||||
|
||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
{
|
||||
double height = val[x, y];
|
||||
if (height == 0.0)
|
||||
height = double.Epsilon;
|
||||
|
||||
bw.Write(height);
|
||||
}
|
||||
|
||||
return str.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores new regionsettings.
|
||||
/// </summary>
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace OpenSim.Data.MySQL
|
||||
public class MySQLSimulationData : ISimulationDataStore
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[REGION DB MYSQL]";
|
||||
|
||||
private string m_connectionString;
|
||||
private object m_dbLock = new object();
|
||||
@@ -91,7 +92,7 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -572,10 +573,14 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy entry point for when terrain was always a 256x256 hieghtmap
|
||||
public void StoreTerrain(double[,] ter, UUID regionID)
|
||||
{
|
||||
m_log.Info("[REGION DB]: Storing terrain");
|
||||
StoreTerrain(new HeightmapTerrainData(ter), regionID);
|
||||
}
|
||||
|
||||
public void StoreTerrain(TerrainData terrData, UUID regionID)
|
||||
{
|
||||
lock (m_dbLock)
|
||||
{
|
||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
@@ -589,11 +594,18 @@ namespace OpenSim.Data.MySQL
|
||||
|
||||
ExecuteNonQuery(cmd);
|
||||
|
||||
cmd.CommandText = "insert into terrain (RegionUUID, " +
|
||||
"Revision, Heightfield) values (?RegionUUID, " +
|
||||
"1, ?Heightfield)";
|
||||
|
||||
cmd.Parameters.AddWithValue("Heightfield", SerializeTerrain(ter));
|
||||
int terrainDBRevision;
|
||||
Array terrainDBblob;
|
||||
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
|
||||
|
||||
m_log.InfoFormat("{0} Storing terrain. X={1}, Y={2}, rev={3}",
|
||||
LogHeader, terrData.SizeX, terrData.SizeY, terrainDBRevision);
|
||||
|
||||
cmd.CommandText = "insert into terrain (RegionUUID, Revision, Heightfield)"
|
||||
+ "values (?RegionUUID, ?Revision, ?Heightfield)";
|
||||
|
||||
cmd.Parameters.AddWithValue("Revision", terrainDBRevision);
|
||||
cmd.Parameters.AddWithValue("Heightfield", terrainDBblob);
|
||||
|
||||
ExecuteNonQuery(cmd);
|
||||
}
|
||||
@@ -601,9 +613,20 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
}
|
||||
|
||||
// Legacy region loading
|
||||
public 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)
|
||||
{
|
||||
@@ -623,32 +646,15 @@ namespace OpenSim.Data.MySQL
|
||||
while (reader.Read())
|
||||
{
|
||||
int rev = Convert.ToInt32(reader["Revision"]);
|
||||
|
||||
terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize];
|
||||
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);
|
||||
}
|
||||
byte[] blob = (byte[])reader["Heightfield"];
|
||||
terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return terrain;
|
||||
return terrData;
|
||||
}
|
||||
|
||||
public void RemoveLandObject(UUID globalID)
|
||||
@@ -1524,30 +1530,6 @@ namespace OpenSim.Data.MySQL
|
||||
return entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="val"></param>
|
||||
/// <returns></returns>
|
||||
private static Array SerializeTerrain(double[,] val)
|
||||
{
|
||||
MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) *sizeof (double));
|
||||
BinaryWriter bw = new BinaryWriter(str);
|
||||
|
||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
{
|
||||
double height = val[x, y];
|
||||
if (height == 0.0)
|
||||
height = double.Epsilon;
|
||||
|
||||
bw.Write(height);
|
||||
}
|
||||
|
||||
return str.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fill the prim command with prim values
|
||||
/// </summary>
|
||||
|
||||
@@ -132,15 +132,33 @@ namespace OpenSim.Data.Null
|
||||
return new List<SceneObjectGroup>();
|
||||
}
|
||||
|
||||
Dictionary<UUID, double[,]> m_terrains = new Dictionary<UUID, double[,]>();
|
||||
public void StoreTerrain(double[,] ter, UUID regionID)
|
||||
Dictionary<UUID, TerrainData> m_terrains = new Dictionary<UUID, TerrainData>();
|
||||
public void StoreTerrain(TerrainData ter, UUID regionID)
|
||||
{
|
||||
if (m_terrains.ContainsKey(regionID))
|
||||
m_terrains.Remove(regionID);
|
||||
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)
|
||||
{
|
||||
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))
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ namespace OpenSim.Data.PGSQL
|
||||
public class PGSQLSimulationData : ISimulationDataStore
|
||||
{
|
||||
private const string _migrationStore = "RegionStore";
|
||||
private const string LogHeader = "[REGION DB PGSQL]";
|
||||
|
||||
// private static FileSystemDataStore Instance = new FileSystemDataStore();
|
||||
private static readonly ILog _Log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
@@ -523,44 +524,54 @@ namespace OpenSim.Data.PGSQL
|
||||
/// <returns></returns>
|
||||
public double[,] LoadTerrain(UUID regionID)
|
||||
{
|
||||
double[,] terrain = new double[(int)Constants.RegionSize, (int)Constants.RegionSize];
|
||||
terrain.Initialize();
|
||||
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;
|
||||
|
||||
string sql = @"select ""RegionUUID"", ""Revision"", ""Heightfield"" from terrain
|
||||
where ""RegionUUID"" = :RegionUUID order by ""Revision"" desc limit 1; ";
|
||||
|
||||
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
|
||||
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
|
||||
{
|
||||
// PGSqlParameter param = new PGSqlParameter();
|
||||
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
|
||||
conn.Open();
|
||||
using (NpgsqlDataReader reader = cmd.ExecuteReader())
|
||||
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
|
||||
{
|
||||
int rev;
|
||||
if (reader.Read())
|
||||
// PGSqlParameter param = new PGSqlParameter();
|
||||
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
|
||||
conn.Open();
|
||||
using (NpgsqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
MemoryStream str = new MemoryStream((byte[])reader["Heightfield"]);
|
||||
BinaryReader br = new BinaryReader(str);
|
||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
int rev;
|
||||
if (reader.Read())
|
||||
{
|
||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
{
|
||||
terrain[x, y] = br.ReadDouble();
|
||||
}
|
||||
rev = Convert.ToInt32(reader["Revision"]);
|
||||
byte[] blob = (byte[])reader["Heightfield"];
|
||||
terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
|
||||
}
|
||||
rev = (int)reader["Revision"];
|
||||
else
|
||||
{
|
||||
_Log.Info("[REGION DB]: No terrain found for region");
|
||||
return null;
|
||||
}
|
||||
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Log.Info("[REGION DB]: No terrain found for region");
|
||||
return null;
|
||||
}
|
||||
_Log.Info("[REGION DB]: Loaded terrain revision r" + rev);
|
||||
}
|
||||
}
|
||||
|
||||
return terrain;
|
||||
return terrData;
|
||||
}
|
||||
|
||||
// Legacy entry point for when terrain was always a 256x256 heightmap
|
||||
public void StoreTerrain(double[,] terrain, UUID regionID)
|
||||
{
|
||||
StoreTerrain(new HeightmapTerrainData(terrain), regionID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -568,35 +579,43 @@ namespace OpenSim.Data.PGSQL
|
||||
/// </summary>
|
||||
/// <param name="terrain">terrain map data.</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
|
||||
string sql = @"delete from terrain where ""RegionUUID""=:RegionUUID";
|
||||
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
|
||||
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
_Log.InfoFormat("{0} Deleted terrain revision id = {1}", LogHeader, regionID);
|
||||
}
|
||||
}
|
||||
|
||||
_Log.Info("[REGION DB]: Deleted terrain revision r " + revision);
|
||||
int terrainDBRevision;
|
||||
Array terrainDBblob;
|
||||
terrData.GetDatabaseBlob(out terrainDBRevision, out terrainDBblob);
|
||||
|
||||
sql = @"insert into terrain(""RegionUUID"", ""Revision"", ""Heightfield"") values(:RegionUUID, :Revision, :Heightfield)";
|
||||
|
||||
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
|
||||
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("Revision", revision));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("Heightfield", serializeTerrain(terrain)));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("RegionUUID", regionID));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("Revision", terrainDBRevision));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("Heightfield", terrainDBblob));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
|
||||
_Log.InfoFormat("{0} Stored terrain id = {1}, terrainSize = <{2},{3}>",
|
||||
LogHeader, regionID, terrData.SizeX, terrData.SizeY);
|
||||
}
|
||||
}
|
||||
|
||||
_Log.Info("[REGION DB]: Stored terrain revision r " + revision);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1349,30 +1368,6 @@ namespace OpenSim.Data.PGSQL
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Serializes the terrain data for storage in DB.
|
||||
/// </summary>
|
||||
/// <param name="val">terrain data</param>
|
||||
/// <returns></returns>
|
||||
private static Array serializeTerrain(double[,] val)
|
||||
{
|
||||
MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double));
|
||||
BinaryWriter bw = new BinaryWriter(str);
|
||||
|
||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
{
|
||||
double height = val[x, y];
|
||||
if (height == 0.0)
|
||||
height = double.Epsilon;
|
||||
|
||||
bw.Write(height);
|
||||
}
|
||||
|
||||
return str.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stores new regionsettings.
|
||||
/// </summary>
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace OpenSim.Data.SQLite
|
||||
public class SQLiteSimulationData : ISimulationDataStore
|
||||
{
|
||||
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 shapeSelect = "select * from primshapes";
|
||||
@@ -819,45 +820,44 @@ namespace OpenSim.Data.SQLite
|
||||
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>
|
||||
/// Store a terrain revision in region storage
|
||||
/// </summary>
|
||||
/// <param name="ter">terrain heightfield</param>
|
||||
/// <param name="regionID">region UUID</param>
|
||||
public void StoreTerrain(double[,] ter, UUID regionID)
|
||||
public void StoreTerrain(TerrainData terrData, UUID regionID)
|
||||
{
|
||||
lock (ds)
|
||||
{
|
||||
int revision = Util.UnixTimeSinceEpoch();
|
||||
|
||||
// This is added to get rid of the infinitely growing
|
||||
// terrain databases which negatively impact on SQLite
|
||||
// over time. Before reenabling this feature there
|
||||
// needs to be a limitter put on the number of
|
||||
// revisions in the database, as this old
|
||||
// implementation is a DOS attack waiting to happen.
|
||||
|
||||
using (
|
||||
SqliteCommand cmd =
|
||||
new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID and Revision <= :Revision",
|
||||
m_conn))
|
||||
SqliteCommand cmd = new SqliteCommand("delete from terrain where RegionUUID=:RegionUUID", m_conn))
|
||||
{
|
||||
cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString()));
|
||||
cmd.Parameters.Add(new SqliteParameter(":Revision", revision));
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
// the following is an work around for .NET. The perf
|
||||
// issues associated with it aren't as bad as you think.
|
||||
m_log.Debug("[SQLITE REGION DB]: Storing terrain revision r" + revision.ToString());
|
||||
String sql = "insert into terrain(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))
|
||||
{
|
||||
cmd.Parameters.Add(new SqliteParameter(":RegionUUID", regionID.ToString()));
|
||||
cmd.Parameters.Add(new SqliteParameter(":Revision", revision));
|
||||
cmd.Parameters.Add(new SqliteParameter(":Heightfield", serializeTerrain(ter)));
|
||||
cmd.Parameters.Add(new SqliteParameter(":Revision", terrainDBRevision));
|
||||
cmd.Parameters.Add(new SqliteParameter(":Heightfield", terrainDBblob));
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
@@ -870,11 +870,20 @@ namespace OpenSim.Data.SQLite
|
||||
/// <returns>Heightfield data</returns>
|
||||
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)
|
||||
{
|
||||
double[,] terret = new double[(int)Constants.RegionSize, (int)Constants.RegionSize];
|
||||
terret.Initialize();
|
||||
|
||||
String sql = "select RegionUUID, Revision, Heightfield from terrain" +
|
||||
" where RegionUUID=:RegionUUID order by Revision desc";
|
||||
|
||||
@@ -887,21 +896,9 @@ namespace OpenSim.Data.SQLite
|
||||
int rev = 0;
|
||||
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"]);
|
||||
byte[] blob = (byte[])row["Heightfield"];
|
||||
terrData = TerrainData.CreateFromDatabaseBlobFactory(pSizeX, pSizeY, pSizeZ, rev, blob);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -912,8 +909,8 @@ namespace OpenSim.Data.SQLite
|
||||
m_log.Debug("[SQLITE REGION DB]: Loaded terrain revision r" + rev.ToString());
|
||||
}
|
||||
}
|
||||
return terret;
|
||||
}
|
||||
return terrData;
|
||||
}
|
||||
|
||||
public void RemoveLandObject(UUID globalID)
|
||||
@@ -2016,40 +2013,6 @@ namespace OpenSim.Data.SQLite
|
||||
return entry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="val"></param>
|
||||
/// <returns></returns>
|
||||
private static Array serializeTerrain(double[,] val)
|
||||
{
|
||||
MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize) * sizeof(double));
|
||||
BinaryWriter bw = new BinaryWriter(str);
|
||||
|
||||
// TODO: COMPATIBILITY - Add byte-order conversions
|
||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
bw.Write(val[x, y]);
|
||||
|
||||
return str.ToArray();
|
||||
}
|
||||
|
||||
// private void fillTerrainRow(DataRow row, UUID regionUUID, int rev, double[,] val)
|
||||
// {
|
||||
// row["RegionUUID"] = regionUUID;
|
||||
// row["Revision"] = rev;
|
||||
|
||||
// MemoryStream str = new MemoryStream(((int)Constants.RegionSize * (int)Constants.RegionSize)*sizeof (double));
|
||||
// BinaryWriter bw = new BinaryWriter(str);
|
||||
|
||||
// // TODO: COMPATIBILITY - Add byte-order conversions
|
||||
// for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
// for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
// bw.Write(val[x, y]);
|
||||
|
||||
// row["Heightfield"] = str.ToArray();
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
using System;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
@@ -40,9 +41,26 @@ namespace OpenSim.Framework
|
||||
public byte WaterHeight;
|
||||
public ushort X;
|
||||
public ushort Y;
|
||||
public ushort SizeX;
|
||||
public ushort SizeY;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
@@ -37,5 +38,37 @@ namespace OpenSim.Framework
|
||||
public int Extra;
|
||||
public int Extra2;
|
||||
public string name;
|
||||
|
||||
public mapItemReply(uint pX, uint pY, UUID pId, string pName, int pExt1, int pExt2)
|
||||
{
|
||||
x = pX;
|
||||
y = pY;
|
||||
id = pId;
|
||||
name = pName;
|
||||
Extra = pExt1;
|
||||
Extra2 = pExt2;
|
||||
}
|
||||
|
||||
public OSDMap ToOSD()
|
||||
{
|
||||
OSDMap map = new OSDMap();
|
||||
map["X"] = OSD.FromInteger((int)x);
|
||||
map["Y"] = OSD.FromInteger((int)y);
|
||||
map["ID"] = OSD.FromUUID(id);
|
||||
map["Name"] = OSD.FromString(name);
|
||||
map["Extra"] = OSD.FromInteger(Extra);
|
||||
map["Extra2"] = OSD.FromInteger(Extra2);
|
||||
return map;
|
||||
}
|
||||
|
||||
public void FromOSD(OSDMap map)
|
||||
{
|
||||
x = (uint) map["X"].AsInteger();
|
||||
y = (uint) map["Y"].AsInteger();
|
||||
id = map["ID"].AsUUID();
|
||||
Extra = map["Extra"].AsInteger();
|
||||
Extra2 = map["Extra2"].AsInteger();
|
||||
name = map["Name"].AsString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
423
OpenSim/Framework/TerrainData.cs
Normal file
423
OpenSim/Framework/TerrainData.cs
Normal file
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
* 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 bool IsTainted { get; protected set; }
|
||||
public abstract bool IsTaintedAt(int xx, int yy);
|
||||
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 shorts
|
||||
public abstract short[] GetCompressedMap();
|
||||
public abstract float CompressionFactor { get; }
|
||||
|
||||
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
|
||||
// "short compressedHeight = (short)(height * compressionFactor);"
|
||||
// The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
|
||||
Compressed2D = 27,
|
||||
// A revision that is not listed above or any revision greater than this value is 'Legacy256'.
|
||||
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 short integers. The integer values are converted to
|
||||
// and from floats by TerrainCompressionFactor. Shorts are used to limit storage used.
|
||||
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 {
|
||||
short 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()
|
||||
{
|
||||
IsTainted = false;
|
||||
for (int ii = 0; ii < m_taint.GetLength(0); ii++)
|
||||
for (int jj = 0; jj < m_taint.GetLength(1); jj++)
|
||||
m_taint[ii, jj] = false;
|
||||
}
|
||||
|
||||
// TerrainData.ClearLand
|
||||
public override void ClearLand()
|
||||
{
|
||||
ClearLand(DefaultTerrainHeight);
|
||||
}
|
||||
// TerrainData.ClearLand(float)
|
||||
public override void ClearLand(float pHeight)
|
||||
{
|
||||
short flatHeight = ToCompressedHeight(pHeight);
|
||||
for (int xx = 0; xx < SizeX; xx++)
|
||||
for (int yy = 0; yy < SizeY; yy++)
|
||||
m_heightmap[xx, yy] = flatHeight;
|
||||
}
|
||||
|
||||
public override bool IsTaintedAt(int xx, int yy)
|
||||
{
|
||||
int tx = xx / Constants.TerrainPatchSize;
|
||||
int ty = yy / Constants.TerrainPatchSize;
|
||||
bool ret = m_taint[tx, ty];
|
||||
m_taint[tx, ty] = false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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 short[] GetCompressedMap()
|
||||
{
|
||||
short[] newMap = new short[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 = (short[,])this.m_heightmap.Clone();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TerrainData.GetDoubles
|
||||
public override double[,] GetDoubles()
|
||||
{
|
||||
double[,] ret = new double[SizeX, SizeY];
|
||||
for (int xx = 0; xx < SizeX; xx++)
|
||||
for (int yy = 0; yy < SizeY; yy++)
|
||||
ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
// =============================================================
|
||||
|
||||
private short[,] m_heightmap;
|
||||
// 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 short ToCompressedHeight(double pHeight)
|
||||
{
|
||||
return (short)(pHeight * CompressionFactor);
|
||||
}
|
||||
|
||||
public float FromCompressedHeight(short 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 short[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 short[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(short[] 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,15 +160,19 @@ namespace OpenSim.Framework
|
||||
public virtual ulong HomeRegion
|
||||
{
|
||||
get
|
||||
{
|
||||
return Utils.UIntsToLong(
|
||||
m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize);
|
||||
{
|
||||
return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY));
|
||||
// return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
m_homeRegionX = (uint) (value >> 40);
|
||||
m_homeRegionY = (((uint) (value)) >> 8);
|
||||
uint regionWorldLocX, regionWorldLocY;
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1745,6 +1745,30 @@ namespace OpenSim.Framework
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pretty format the hashtable contents to a single line.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used for debugging output.
|
||||
/// </remarks>
|
||||
/// <param name='ht'></param>
|
||||
public static string PrettyFormatToSingleLine(Hashtable ht)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int i = 0;
|
||||
|
||||
foreach (string key in ht.Keys)
|
||||
{
|
||||
sb.AppendFormat("{0}:{1}", key, ht[key]);
|
||||
|
||||
if (++i < ht.Count)
|
||||
sb.AppendFormat(", ");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to trigger an early library load on Windows systems.
|
||||
/// </summary>
|
||||
|
||||
@@ -1030,7 +1030,7 @@ namespace OpenSim.Framework
|
||||
finally
|
||||
{
|
||||
if (requestStream != null)
|
||||
requestStream.Close();
|
||||
requestStream.Dispose();
|
||||
|
||||
// capture how much time was spent writing
|
||||
tickdata = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
@@ -1183,7 +1183,7 @@ namespace OpenSim.Framework
|
||||
finally
|
||||
{
|
||||
if (requestStream != null)
|
||||
requestStream.Close();
|
||||
requestStream.Dispose();
|
||||
|
||||
// capture how much time was spent writing
|
||||
tickdata = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
@@ -1268,4 +1268,4 @@ namespace OpenSim.Framework
|
||||
return deserial;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,10 +266,21 @@ namespace OpenSim
|
||||
SavePrimsXml2);
|
||||
|
||||
m_console.Commands.AddCommand("Archiving", false, "load oar",
|
||||
"load oar [--merge] [--skip-assets] [<OAR path>]",
|
||||
"load oar [--merge] [--skip-assets]"
|
||||
+ " [--force-terrain] [--force-parcels]"
|
||||
+ " [--no-objects]"
|
||||
+ " [--rotation degrees] [--rotation-center \"<x,y,z>\"]"
|
||||
+ " [--displacement \"<x,y,z>\"]"
|
||||
+ " [<OAR path>]",
|
||||
"Load a region's data from an OAR archive.",
|
||||
"--merge will merge the OAR with the existing scene." + Environment.NewLine
|
||||
"--merge will merge the OAR with the existing scene (suppresses terrain and parcel info loading)." + Environment.NewLine
|
||||
+ "--skip-assets will load the OAR but ignore the assets it contains." + Environment.NewLine
|
||||
+ "--displacement will add this value to the position of every object loaded" + Environment.NewLine
|
||||
+ "--force-terrain forces the loading of terrain from the oar (undoes suppression done by --merge)" + Environment.NewLine
|
||||
+ "--force-parcels forces the loading of parcels from the oar (undoes suppression done by --merge)" + Environment.NewLine
|
||||
+ "--rotation specified rotation to be applied to the oar. Specified in degrees." + Environment.NewLine
|
||||
+ "--rotation-center Location (relative to original OAR) to apply rotation. Default is <128,128,0>" + Environment.NewLine
|
||||
+ "--no-objects suppresses the addition of any objects (good for loading only the terrain)" + Environment.NewLine
|
||||
+ "The path can be either a filesystem location or a URI."
|
||||
+ " If this is not given then the command looks for an OAR named region.oar in the current directory.",
|
||||
LoadOar);
|
||||
|
||||
@@ -690,7 +690,8 @@ namespace OpenSim
|
||||
clientServer = clientNetworkServers;
|
||||
scene.LoadWorldMap();
|
||||
|
||||
scene.PhysicsScene = GetPhysicsScene(scene.RegionInfo.RegionName);
|
||||
Vector3 regionExtent = new Vector3(regionInfo.RegionSizeX, regionInfo.RegionSizeY, regionInfo.RegionSizeZ);
|
||||
scene.PhysicsScene = GetPhysicsScene(scene.RegionInfo.RegionName, regionExtent);
|
||||
scene.PhysicsScene.RequestAssetMethod = scene.PhysicsRequestAsset;
|
||||
scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
|
||||
scene.PhysicsScene.SetWaterLevel((float) regionInfo.RegionSettings.WaterHeight);
|
||||
@@ -752,10 +753,10 @@ namespace OpenSim
|
||||
|
||||
# region Setup methods
|
||||
|
||||
protected override PhysicsScene GetPhysicsScene(string osSceneIdentifier)
|
||||
protected override PhysicsScene GetPhysicsScene(string osSceneIdentifier, Vector3 regionExtent)
|
||||
{
|
||||
return GetPhysicsScene(
|
||||
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, Config, osSceneIdentifier);
|
||||
m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, Config, osSceneIdentifier, regionExtent);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
public class EventQueueGetModule : IEventQueue, INonSharedRegionModule
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[EVENT QUEUE GET MODULE]";
|
||||
|
||||
/// <value>
|
||||
/// Debug level.
|
||||
@@ -228,12 +229,18 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
lock (queue)
|
||||
queue.Enqueue(ev);
|
||||
}
|
||||
else
|
||||
else if (DebugLevel > 0)
|
||||
{
|
||||
OSDMap evMap = (OSDMap)ev;
|
||||
m_log.WarnFormat(
|
||||
"[EVENTQUEUE]: (Enqueue) No queue found for agent {0} when placing message {1} in region {2}",
|
||||
avatarID, evMap["message"], m_scene.Name);
|
||||
ScenePresence sp = m_scene.GetScenePresence(avatarID);
|
||||
|
||||
// This assumes that an NPC should never have a queue.
|
||||
if (sp != null && sp.PresenceType != PresenceType.Npc)
|
||||
{
|
||||
OSDMap evMap = (OSDMap)ev;
|
||||
m_log.WarnFormat(
|
||||
"[EVENTQUEUE]: (Enqueue) No queue found for agent {0} {1} when placing message {2} in region {3}",
|
||||
sp.Name, sp.UUID, evMap["message"], m_scene.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NullReferenceException e)
|
||||
@@ -714,7 +721,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
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}>",
|
||||
"[EVENT QUEUE GET MODULE]", handle, avatarID, regionSizeX, regionSizeY);
|
||||
LogHeader, handle, avatarID, regionSizeX, regionSizeY);
|
||||
|
||||
OSD item = EventQueueHelper.EnableSimulator(handle, endPoint, regionSizeX, regionSizeY);
|
||||
Enqueue(item, avatarID);
|
||||
@@ -724,7 +731,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
ulong regionHandle, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
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);
|
||||
Enqueue(item, avatarID);
|
||||
}
|
||||
@@ -734,8 +741,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
uint locationID, uint flags, string capsURL,
|
||||
UUID avatarID, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize={3},{4}>",
|
||||
"[EVENT QUEUE GET MODULE]", regionHandle, avatarID, regionSizeX, regionSizeY);
|
||||
m_log.DebugFormat("{0} TeleportFinishEvent. handle={1}, avatarID={2}, regionSize=<{3},{4}>",
|
||||
LogHeader, regionHandle, avatarID, regionSizeX, regionSizeY);
|
||||
|
||||
OSD item = EventQueueHelper.TeleportFinishEvent(regionHandle, simAccess, regionExternalEndPoint,
|
||||
locationID, flags, capsURL, avatarID, regionSizeX, regionSizeY);
|
||||
@@ -747,7 +754,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
string capsURL, UUID avatarID, UUID sessionID, int regionSizeX, int regionSizeY)
|
||||
{
|
||||
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,
|
||||
capsURL, avatarID, sessionID, regionSizeX, regionSizeY);
|
||||
|
||||
@@ -77,8 +77,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
llsdSimInfo.Add("Handle", new OSDBinary(ulongToByteArray(handle)));
|
||||
llsdSimInfo.Add("IP", new OSDBinary(endPoint.Address.GetAddressBytes()));
|
||||
llsdSimInfo.Add("Port", new OSDInteger(endPoint.Port));
|
||||
llsdSimInfo.Add("RegionSizeX", new OSDInteger(regionSizeX));
|
||||
llsdSimInfo.Add("RegionSizeY", new OSDInteger(regionSizeY));
|
||||
llsdSimInfo.Add("RegionSizeX", OSD.FromUInteger((uint) regionSizeX));
|
||||
llsdSimInfo.Add("RegionSizeY", OSD.FromUInteger((uint) regionSizeY));
|
||||
|
||||
OSDArray arr = new OSDArray(1);
|
||||
arr.Add(llsdSimInfo);
|
||||
@@ -138,8 +138,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
regionDataMap.Add("SeedCapability", OSD.FromString(capsURL));
|
||||
regionDataMap.Add("SimIP", OSD.FromBinary(newRegionExternalEndPoint.Address.GetAddressBytes()));
|
||||
regionDataMap.Add("SimPort", OSD.FromInteger(newRegionExternalEndPoint.Port));
|
||||
regionDataMap.Add("RegionSizeX", new OSDInteger(regionSizeX));
|
||||
regionDataMap.Add("RegionSizeY", new OSDInteger(regionSizeY));
|
||||
regionDataMap.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
|
||||
regionDataMap.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
|
||||
|
||||
OSDArray regionDataArr = new OSDArray(1);
|
||||
regionDataArr.Add(regionDataMap);
|
||||
@@ -166,8 +166,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
info.Add("SimIP", OSD.FromBinary(regionExternalEndPoint.Address.GetAddressBytes()));
|
||||
info.Add("SimPort", OSD.FromInteger(regionExternalEndPoint.Port));
|
||||
info.Add("TeleportFlags", OSD.FromULong(1L << 4)); // AgentManager.TeleportFlags.ViaLocation
|
||||
info.Add("RegionSizeX", new OSDInteger(regionSizeX));
|
||||
info.Add("RegionSizeY", new OSDInteger(regionSizeY));
|
||||
info.Add("RegionSizeX", OSD.FromUInteger((uint)regionSizeX));
|
||||
info.Add("RegionSizeY", OSD.FromUInteger((uint)regionSizeY));
|
||||
|
||||
OSDArray infoArr = new OSDArray();
|
||||
infoArr.Add(info);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
using log4net.Config;
|
||||
@@ -33,11 +34,14 @@ using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Packets;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Region.ClientStack.Linden;
|
||||
using OpenSim.Region.CoreModules.Framework;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.OptionalModules.World.NPC;
|
||||
using OpenSim.Tests.Common;
|
||||
using OpenSim.Tests.Common.Mock;
|
||||
|
||||
@@ -47,6 +51,8 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||
public class EventQueueTests : OpenSimTestCase
|
||||
{
|
||||
private TestScene m_scene;
|
||||
private EventQueueGetModule m_eqgMod;
|
||||
private NPCModule m_npcMod;
|
||||
|
||||
[SetUp]
|
||||
public override void SetUp()
|
||||
@@ -69,10 +75,15 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||
config.Configs["Startup"].Set("EventQueue", "true");
|
||||
|
||||
CapabilitiesModule capsModule = new CapabilitiesModule();
|
||||
EventQueueGetModule eqgModule = new EventQueueGetModule();
|
||||
m_eqgMod = new EventQueueGetModule();
|
||||
|
||||
// For NPC test support
|
||||
config.AddConfig("NPC");
|
||||
config.Configs["NPC"].Set("Enabled", "true");
|
||||
m_npcMod = new NPCModule();
|
||||
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(m_scene, config, capsModule, eqgModule);
|
||||
SceneHelpers.SetupSceneModules(m_scene, config, capsModule, m_eqgMod, m_npcMod);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -101,5 +112,80 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||
// TODO: Add more assertions for the other aspects of event queues
|
||||
Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestEnqueueMessage()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(m_scene, TestHelpers.ParseTail(0x1));
|
||||
|
||||
string messageName = "TestMessage";
|
||||
|
||||
m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), sp.UUID);
|
||||
|
||||
Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, sp.UUID);
|
||||
|
||||
Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.OK));
|
||||
|
||||
// Console.WriteLine("Response [{0}]", (string)eventsResponse["str_response_string"]);
|
||||
|
||||
OSDMap rawOsd = (OSDMap)OSDParser.DeserializeLLSDXml((string)eventsResponse["str_response_string"]);
|
||||
OSDArray eventsOsd = (OSDArray)rawOsd["events"];
|
||||
|
||||
bool foundUpdate = false;
|
||||
foreach (OSD osd in eventsOsd)
|
||||
{
|
||||
OSDMap eventOsd = (OSDMap)osd;
|
||||
|
||||
if (eventOsd["message"] == messageName)
|
||||
foundUpdate = true;
|
||||
}
|
||||
|
||||
Assert.That(foundUpdate, Is.True, string.Format("Did not find {0} in response", messageName));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test an attempt to put a message on the queue of a user that is not in the region.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestEnqueueMessageNoUser()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
TestHelpers.EnableLogging();
|
||||
|
||||
string messageName = "TestMessage";
|
||||
|
||||
m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), TestHelpers.ParseTail(0x1));
|
||||
|
||||
Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, TestHelpers.ParseTail(0x1));
|
||||
|
||||
Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// NPCs do not currently have an event queue but a caller may try to send a message anyway, so check behaviour.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestEnqueueMessageToNpc()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
UUID npcId
|
||||
= m_npcMod.CreateNPC(
|
||||
"John", "Smith", new Vector3(128, 128, 30), UUID.Zero, true, m_scene, new AvatarAppearance());
|
||||
|
||||
ScenePresence npc = m_scene.GetScenePresence(npcId);
|
||||
|
||||
string messageName = "TestMessage";
|
||||
|
||||
m_eqgMod.Enqueue(m_eqgMod.BuildEvent(messageName, new OSDMap()), npc.UUID);
|
||||
|
||||
Hashtable eventsResponse = m_eqgMod.GetEvents(UUID.Zero, npc.UUID);
|
||||
|
||||
Assert.That((int)eventsResponse["int_response_code"], Is.EqualTo((int)HttpStatusCode.BadGateway));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
@@ -53,8 +54,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UploadBakedTextureModule")]
|
||||
public class UploadBakedTextureModule : INonSharedRegionModule
|
||||
{
|
||||
// private static readonly ILog m_log =
|
||||
// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// For historical reasons this is fixed, but there
|
||||
@@ -63,39 +64,211 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
private Scene m_scene;
|
||||
private bool m_persistBakedTextures;
|
||||
private string m_URL;
|
||||
|
||||
private IBakedTextureModule m_BakedTextureModule;
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
IConfig config = source.Configs["ClientStack.LindenCaps"];
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
m_URL = config.GetString("Cap_UploadBakedTexture", string.Empty);
|
||||
|
||||
IConfig appearanceConfig = source.Configs["Appearance"];
|
||||
if (appearanceConfig != null)
|
||||
m_persistBakedTextures = appearanceConfig.GetBoolean("PersistBakedTextures", m_persistBakedTextures);
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void AddRegion(Scene s)
|
||||
{
|
||||
m_scene = s;
|
||||
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene s)
|
||||
{
|
||||
s.EventManager.OnRegisterCaps -= RegisterCaps;
|
||||
s.EventManager.OnNewPresence -= RegisterNewPresence;
|
||||
s.EventManager.OnRemovePresence -= DeRegisterPresence;
|
||||
m_BakedTextureModule = null;
|
||||
m_scene = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void RegionLoaded(Scene s)
|
||||
{
|
||||
m_scene.EventManager.OnRegisterCaps += RegisterCaps;
|
||||
m_scene.EventManager.OnNewPresence += RegisterNewPresence;
|
||||
m_scene.EventManager.OnRemovePresence += DeRegisterPresence;
|
||||
|
||||
}
|
||||
|
||||
private void DeRegisterPresence(UUID agentId)
|
||||
{
|
||||
ScenePresence presence = null;
|
||||
if (m_scene.TryGetScenePresence(agentId, out presence))
|
||||
{
|
||||
presence.ControllingClient.OnSetAppearance -= CaptureAppearanceSettings;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void RegisterNewPresence(ScenePresence presence)
|
||||
{
|
||||
presence.ControllingClient.OnSetAppearance += CaptureAppearanceSettings;
|
||||
|
||||
}
|
||||
|
||||
private void CaptureAppearanceSettings(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 avSize, WearableCacheItem[] cacheItems)
|
||||
{
|
||||
int maxCacheitemsLoop = cacheItems.Length;
|
||||
if (maxCacheitemsLoop > AvatarWearable.MAX_WEARABLES)
|
||||
{
|
||||
maxCacheitemsLoop = AvatarWearable.MAX_WEARABLES;
|
||||
m_log.WarnFormat("[CACHEDBAKES]: Too Many Cache items Provided {0}, the max is {1}. Truncating!", cacheItems.Length, AvatarWearable.MAX_WEARABLES);
|
||||
}
|
||||
|
||||
m_BakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
|
||||
if (cacheItems.Length > 0)
|
||||
{
|
||||
m_log.Debug("[Cacheitems]: " + cacheItems.Length);
|
||||
for (int iter = 0; iter < maxCacheitemsLoop; iter++)
|
||||
{
|
||||
m_log.Debug("[Cacheitems] {" + iter + "/" + cacheItems[iter].TextureIndex + "}: c-" + cacheItems[iter].CacheId + ", t-" +
|
||||
cacheItems[iter].TextureID);
|
||||
}
|
||||
|
||||
ScenePresence p = null;
|
||||
if (m_scene.TryGetScenePresence(remoteClient.AgentId, out p))
|
||||
{
|
||||
|
||||
WearableCacheItem[] existingitems = p.Appearance.WearableCacheItems;
|
||||
if (existingitems == null)
|
||||
{
|
||||
if (m_BakedTextureModule != null)
|
||||
{
|
||||
WearableCacheItem[] savedcache = null;
|
||||
try
|
||||
{
|
||||
if (p.Appearance.WearableCacheItemsDirty)
|
||||
{
|
||||
savedcache = m_BakedTextureModule.Get(p.UUID);
|
||||
p.Appearance.WearableCacheItems = savedcache;
|
||||
p.Appearance.WearableCacheItemsDirty = false;
|
||||
}
|
||||
|
||||
}
|
||||
/*
|
||||
* The following Catch types DO NOT WORK with m_BakedTextureModule.Get
|
||||
* it jumps to the General Packet Exception Handler if you don't catch Exception!
|
||||
*
|
||||
catch (System.Net.Sockets.SocketException)
|
||||
{
|
||||
cacheItems = null;
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
cacheItems = null;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
cacheItems = null;
|
||||
} */
|
||||
catch (Exception)
|
||||
{
|
||||
// The service logs a sufficient error message.
|
||||
}
|
||||
|
||||
|
||||
if (savedcache != null)
|
||||
existingitems = savedcache;
|
||||
}
|
||||
}
|
||||
// Existing items null means it's a fully new appearance
|
||||
if (existingitems == null)
|
||||
{
|
||||
|
||||
for (int i = 0; i < maxCacheitemsLoop; i++)
|
||||
{
|
||||
if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
|
||||
{
|
||||
Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
|
||||
if (face == null)
|
||||
{
|
||||
textureEntry.CreateFace(cacheItems[i].TextureIndex);
|
||||
textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
|
||||
AppearanceManager.DEFAULT_AVATAR_TEXTURE;
|
||||
continue;
|
||||
}
|
||||
cacheItems[i].TextureID =face.TextureID;
|
||||
if (m_scene.AssetService != null)
|
||||
cacheItems[i].TextureAsset =
|
||||
m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
|
||||
{
|
||||
// for each uploaded baked texture
|
||||
for (int i = 0; i < maxCacheitemsLoop; i++)
|
||||
{
|
||||
if (textureEntry.FaceTextures.Length > cacheItems[i].TextureIndex)
|
||||
{
|
||||
Primitive.TextureEntryFace face = textureEntry.FaceTextures[cacheItems[i].TextureIndex];
|
||||
if (face == null)
|
||||
{
|
||||
textureEntry.CreateFace(cacheItems[i].TextureIndex);
|
||||
textureEntry.FaceTextures[cacheItems[i].TextureIndex].TextureID =
|
||||
AppearanceManager.DEFAULT_AVATAR_TEXTURE;
|
||||
continue;
|
||||
}
|
||||
cacheItems[i].TextureID =
|
||||
face.TextureID;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("[CACHEDBAKES]: Invalid Texture Index Provided, Texture doesn't exist or hasn't been uploaded yet {0}, the max is {1}. Skipping!", cacheItems[i].TextureIndex, textureEntry.FaceTextures.Length);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxCacheitemsLoop; i++)
|
||||
{
|
||||
if (cacheItems[i].TextureAsset == null)
|
||||
{
|
||||
cacheItems[i].TextureAsset =
|
||||
m_scene.AssetService.GetCached(cacheItems[i].TextureID.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
p.Appearance.WearableCacheItems = cacheItems;
|
||||
|
||||
|
||||
|
||||
if (m_BakedTextureModule != null)
|
||||
{
|
||||
m_BakedTextureModule.Store(remoteClient.AgentId, cacheItems);
|
||||
p.Appearance.WearableCacheItemsDirty = true;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void PostInitialise()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void Close() { }
|
||||
|
||||
public string Name { get { return "UploadBakedTextureModule"; } }
|
||||
@@ -107,26 +280,23 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
public void RegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
// UUID capID = UUID.Random();
|
||||
UploadBakedTextureHandler avatarhandler = new UploadBakedTextureHandler(
|
||||
caps, m_scene.AssetService, m_persistBakedTextures);
|
||||
|
||||
//caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
|
||||
if (m_URL == "localhost")
|
||||
{
|
||||
caps.RegisterHandler(
|
||||
|
||||
|
||||
caps.RegisterHandler(
|
||||
"UploadBakedTexture",
|
||||
new RestStreamHandler(
|
||||
"POST",
|
||||
"/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
|
||||
avatarhandler.UploadBakedTexture,
|
||||
"UploadBakedTexture",
|
||||
new RestStreamHandler(
|
||||
"POST",
|
||||
"/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
|
||||
new UploadBakedTextureHandler(
|
||||
caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
|
||||
"UploadBakedTexture",
|
||||
agentID.ToString()));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
caps.RegisterHandler("UploadBakedTexture", m_URL);
|
||||
}
|
||||
agentID.ToString()));
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,11 +34,13 @@ using System.Text;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using System.Xml;
|
||||
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Packets;
|
||||
using OpenMetaverse.Messages.Linden;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Client;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
@@ -48,7 +50,6 @@ using OpenSim.Services.Interfaces;
|
||||
using Timer = System.Timers.Timer;
|
||||
using AssetLandmark = OpenSim.Framework.AssetLandmark;
|
||||
using RegionFlags = OpenMetaverse.RegionFlags;
|
||||
using Nini.Config;
|
||||
|
||||
using System.IO;
|
||||
using PermissionMask = OpenSim.Framework.PermissionMask;
|
||||
@@ -307,6 +308,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
private const float m_sunPainDaHalfOrbitalCutoff = 4.712388980384689858f;
|
||||
|
||||
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
|
||||
|
||||
/// <summary>
|
||||
@@ -323,6 +325,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
private readonly byte[] m_channelVersion = Utils.EmptyBytes;
|
||||
private readonly IGroupsModule m_GroupsModule;
|
||||
|
||||
private int m_cachedTextureSerial;
|
||||
private PriorityQueue m_entityUpdates;
|
||||
private PriorityQueue m_entityProps;
|
||||
private Prioritizer m_prioritizer;
|
||||
@@ -447,7 +450,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
// ~LLClientView()
|
||||
// {
|
||||
// m_log.DebugFormat("[LLCLIENTVIEW]: Destructor called for {0}, circuit code {1}", Name, CircuitCode);
|
||||
// m_log.DebugFormat("{0} Destructor called for {1}, circuit code {2}", LogHeader, Name, CircuitCode);
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
@@ -513,9 +516,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// there is some unidentified connection problem, not where we have issues due to deadlock
|
||||
if (!IsActive && !force)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[CLIENT]: Not attempting to close inactive client {0} in {1} since force flag is not set",
|
||||
Name, m_scene.Name);
|
||||
m_log.DebugFormat( "{0} Not attempting to close inactive client {1} in {2} since force flag is not set",
|
||||
LogHeader, Name, m_scene.Name);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -1153,7 +1155,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <param name="map">heightmap</param>
|
||||
public virtual void SendLayerData(float[] map)
|
||||
{
|
||||
Util.FireAndForget(DoSendLayerData, map);
|
||||
Util.FireAndForget(DoSendLayerData, m_scene.Heightmap.GetTerrainData());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1162,10 +1164,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <param name="o"></param>
|
||||
private void DoSendLayerData(object o)
|
||||
{
|
||||
float[] map = LLHeightFieldMoronize((float[])o);
|
||||
TerrainData map = (TerrainData)o;
|
||||
|
||||
try
|
||||
{
|
||||
// Send LayerData in typerwriter pattern
|
||||
//for (int y = 0; y < 16; y++)
|
||||
//{
|
||||
// for (int x = 0; x < 16; x++)
|
||||
@@ -1175,7 +1178,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
//}
|
||||
|
||||
// Send LayerData in a spiral pattern. Fun!
|
||||
SendLayerTopRight(map, 0, 0, 15, 15);
|
||||
SendLayerTopRight(map, 0, 0, map.SizeX/Constants.TerrainPatchSize-1, map.SizeY/Constants.TerrainPatchSize-1);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -1183,7 +1186,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
private void SendLayerTopRight(float[] map, int x1, int y1, int x2, int y2)
|
||||
private void SendLayerTopRight(TerrainData map, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
// Row
|
||||
for (int i = x1; i <= x2; i++)
|
||||
@@ -1193,11 +1196,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
for (int j = y1 + 1; j <= y2; j++)
|
||||
SendLayerData(x2, j, map);
|
||||
|
||||
if (x2 - x1 > 0)
|
||||
if (x2 - x1 > 0 && y2 - y1 > 0)
|
||||
SendLayerBottomLeft(map, x1, y1 + 1, x2 - 1, y2);
|
||||
}
|
||||
|
||||
void SendLayerBottomLeft(float[] map, int x1, int y1, int x2, int y2)
|
||||
void SendLayerBottomLeft(TerrainData map, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
// Row in reverse
|
||||
for (int i = x2; i >= x1; i--)
|
||||
@@ -1207,7 +1210,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
for (int j = y2 - 1; j >= y1; j--)
|
||||
SendLayerData(x1, j, map);
|
||||
|
||||
if (x2 - x1 > 0)
|
||||
if (x2 - x1 > 0 && y2 - y1 > 0)
|
||||
SendLayerTopRight(map, x1 + 1, y1, x2, y2 - 1);
|
||||
}
|
||||
|
||||
@@ -1229,22 +1232,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// OutPacket(layerpack, ThrottleOutPacketType.Land);
|
||||
// }
|
||||
|
||||
// Legacy form of invocation that passes around a bare data array.
|
||||
// Just ignore what was passed and use the real terrain info that is part of the scene.
|
||||
public void SendLayerData(int px, int py, float[] map)
|
||||
{
|
||||
SendLayerData(px, py, m_scene.Heightmap.GetTerrainData());
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// <param name="px">Patch coordinate (x) 0..15</param>
|
||||
/// <param name="py">Patch coordinate (y) 0..15</param>
|
||||
/// <param name="map">heightmap</param>
|
||||
public void SendLayerData(int px, int py, float[] map)
|
||||
public void SendLayerData(int px, int py, TerrainData terrData)
|
||||
{
|
||||
try
|
||||
{
|
||||
int[] patches = new int[] { py * 16 + px };
|
||||
float[] heightmap = (map.Length == 65536) ?
|
||||
map :
|
||||
LLHeightFieldMoronize(map);
|
||||
|
||||
LayerDataPacket layerpack = TerrainCompressor.CreateLandPacket(heightmap, patches);
|
||||
LayerDataPacket layerpack = OpenSimTerrainCompressor.CreateLandPacket(terrData, px, py);
|
||||
|
||||
// When a user edits the terrain, so much data is sent, the data queues up fast and presents a sub optimal editing experience.
|
||||
// To alleviate this issue, when the user edits the terrain, we start skipping the queues until they're done editing the terrain.
|
||||
@@ -1262,14 +1269,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (m_justEditedTerrain)
|
||||
{
|
||||
layerpack.Header.Reliable = false;
|
||||
OutPacket(layerpack,
|
||||
ThrottleOutPacketType.Unknown );
|
||||
OutPacket(layerpack, ThrottleOutPacketType.Unknown );
|
||||
}
|
||||
else
|
||||
{
|
||||
layerpack.Header.Reliable = true;
|
||||
OutPacket(layerpack,
|
||||
ThrottleOutPacketType.Land);
|
||||
OutPacket(layerpack, ThrottleOutPacketType.Land);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -1278,38 +1283,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Munges heightfield into the LLUDP backed in restricted heightfield.
|
||||
/// </summary>
|
||||
/// <param name="map">float array in the base; Constants.RegionSize</param>
|
||||
/// <returns>float array in the base 256</returns>
|
||||
internal float[] LLHeightFieldMoronize(float[] map)
|
||||
{
|
||||
if (map.Length == 65536)
|
||||
return map;
|
||||
else
|
||||
{
|
||||
float[] returnmap = new float[65536];
|
||||
|
||||
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>
|
||||
/// Send the wind matrix to the client
|
||||
/// </summary>
|
||||
@@ -1350,7 +1323,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
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 = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
|
||||
(int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
|
||||
layerpack.Header.Zerocoded = true;
|
||||
OutPacket(layerpack, ThrottleOutPacketType.Wind);
|
||||
}
|
||||
@@ -1374,7 +1352,12 @@ 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 = OpenSimTerrainCompressor.CreateLayerDataPacket(patches, layerType,
|
||||
(int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY);
|
||||
layerpack.Header.Zerocoded = true;
|
||||
OutPacket(layerpack, ThrottleOutPacketType.Cloud);
|
||||
}
|
||||
@@ -2785,8 +2768,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
if (req.AssetInf.Data == null)
|
||||
{
|
||||
m_log.ErrorFormat("Cannot send asset {0} ({1}), asset data is null",
|
||||
req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
|
||||
m_log.ErrorFormat("{0} Cannot send asset {1} ({2}), asset data is null",
|
||||
LogHeader, req.AssetInf.ID, req.AssetInf.Metadata.ContentType);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -8970,6 +8953,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
TeleportLocationRequest handlerTeleportLocationRequest = OnTeleportLocationRequest;
|
||||
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,
|
||||
tpLocReq.Info.LookAt, 16);
|
||||
}
|
||||
@@ -11757,36 +11753,158 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <returns></returns>
|
||||
protected bool HandleAgentTextureCached(IClientAPI simclient, Packet packet)
|
||||
{
|
||||
//m_log.Debug("texture cached: " + packet.ToString());
|
||||
AgentCachedTexturePacket cachedtex = (AgentCachedTexturePacket)packet;
|
||||
AgentCachedTextureResponsePacket cachedresp = (AgentCachedTextureResponsePacket)PacketPool.Instance.GetPacket(PacketType.AgentCachedTextureResponse);
|
||||
|
||||
if (cachedtex.AgentData.SessionID != SessionId)
|
||||
return false;
|
||||
|
||||
List<CachedTextureRequestArg> requestArgs = new List<CachedTextureRequestArg>();
|
||||
|
||||
for (int i = 0; i < cachedtex.WearableData.Length; i++)
|
||||
{
|
||||
CachedTextureRequestArg arg = new CachedTextureRequestArg();
|
||||
arg.BakedTextureIndex = cachedtex.WearableData[i].TextureIndex;
|
||||
arg.WearableHashID = cachedtex.WearableData[i].ID;
|
||||
|
||||
requestArgs.Add(arg);
|
||||
}
|
||||
// TODO: don't create new blocks if recycling an old packet
|
||||
cachedresp.AgentData.AgentID = AgentId;
|
||||
cachedresp.AgentData.SessionID = m_sessionId;
|
||||
cachedresp.AgentData.SerialNum = m_cachedTextureSerial;
|
||||
m_cachedTextureSerial++;
|
||||
cachedresp.WearableData =
|
||||
new AgentCachedTextureResponsePacket.WearableDataBlock[cachedtex.WearableData.Length];
|
||||
|
||||
try
|
||||
//IAvatarFactoryModule fac = m_scene.RequestModuleInterface<IAvatarFactoryModule>();
|
||||
// var item = fac.GetBakedTextureFaces(AgentId);
|
||||
//WearableCacheItem[] items = fac.GetCachedItems(AgentId);
|
||||
|
||||
IAssetService cache = m_scene.AssetService;
|
||||
IBakedTextureModule bakedTextureModule = m_scene.RequestModuleInterface<IBakedTextureModule>();
|
||||
//bakedTextureModule = null;
|
||||
int maxWearablesLoop = cachedtex.WearableData.Length;
|
||||
if (maxWearablesLoop > AvatarWearable.MAX_WEARABLES)
|
||||
maxWearablesLoop = AvatarWearable.MAX_WEARABLES;
|
||||
|
||||
if (bakedTextureModule != null && cache != null)
|
||||
{
|
||||
CachedTextureRequest handlerCachedTextureRequest = OnCachedTextureRequest;
|
||||
if (handlerCachedTextureRequest != null)
|
||||
// We need to make sure the asset stored in the bake is available on this server also by it's assetid before we map it to a Cacheid
|
||||
|
||||
WearableCacheItem[] cacheItems = null;
|
||||
ScenePresence p = m_scene.GetScenePresence(AgentId);
|
||||
if (p.Appearance != null)
|
||||
if (p.Appearance.WearableCacheItems == null || p.Appearance.WearableCacheItemsDirty)
|
||||
{
|
||||
try
|
||||
{
|
||||
cacheItems = bakedTextureModule.Get(AgentId);
|
||||
p.Appearance.WearableCacheItems = cacheItems;
|
||||
p.Appearance.WearableCacheItemsDirty = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* The following Catch types DO NOT WORK, it jumps to the General Packet Exception Handler if you don't catch Exception!
|
||||
*
|
||||
catch (System.Net.Sockets.SocketException)
|
||||
{
|
||||
cacheItems = null;
|
||||
}
|
||||
catch (WebException)
|
||||
{
|
||||
cacheItems = null;
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
cacheItems = null;
|
||||
} */
|
||||
catch (Exception)
|
||||
{
|
||||
cacheItems = null;
|
||||
}
|
||||
|
||||
}
|
||||
else if (p.Appearance.WearableCacheItems != null)
|
||||
{
|
||||
cacheItems = p.Appearance.WearableCacheItems;
|
||||
}
|
||||
|
||||
if (cache != null && cacheItems != null)
|
||||
{
|
||||
handlerCachedTextureRequest(simclient,cachedtex.AgentData.SerialNum,requestArgs);
|
||||
foreach (WearableCacheItem item in cacheItems)
|
||||
{
|
||||
|
||||
if (cache.GetCached(item.TextureID.ToString()) == null)
|
||||
{
|
||||
item.TextureAsset.Temporary = true;
|
||||
cache.Store(item.TextureAsset);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if (cacheItems != null)
|
||||
{
|
||||
|
||||
for (int i = 0; i < maxWearablesLoop; i++)
|
||||
{
|
||||
WearableCacheItem item =
|
||||
WearableCacheItem.SearchTextureIndex(cachedtex.WearableData[i].TextureIndex,cacheItems);
|
||||
|
||||
cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
|
||||
cachedresp.WearableData[i].TextureIndex= cachedtex.WearableData[i].TextureIndex;
|
||||
cachedresp.WearableData[i].HostName = new byte[0];
|
||||
if (item != null && cachedtex.WearableData[i].ID == item.CacheId)
|
||||
{
|
||||
|
||||
cachedresp.WearableData[i].TextureID = item.TextureID;
|
||||
}
|
||||
else
|
||||
{
|
||||
cachedresp.WearableData[i].TextureID = UUID.Zero;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < maxWearablesLoop; i++)
|
||||
{
|
||||
cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
|
||||
cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
|
||||
cachedresp.WearableData[i].TextureID = UUID.Zero;
|
||||
//UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
|
||||
cachedresp.WearableData[i].HostName = new byte[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat("[CLIENT VIEW]: AgentTextureCached packet handler threw an exception, {0}", e);
|
||||
return false;
|
||||
if (cache == null)
|
||||
{
|
||||
for (int i = 0; i < maxWearablesLoop; i++)
|
||||
{
|
||||
cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
|
||||
cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
|
||||
cachedresp.WearableData[i].TextureID = UUID.Zero;
|
||||
//UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
|
||||
cachedresp.WearableData[i].HostName = new byte[0];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < maxWearablesLoop; i++)
|
||||
{
|
||||
cachedresp.WearableData[i] = new AgentCachedTextureResponsePacket.WearableDataBlock();
|
||||
cachedresp.WearableData[i].TextureIndex = cachedtex.WearableData[i].TextureIndex;
|
||||
|
||||
|
||||
|
||||
if (cache.GetCached(cachedresp.WearableData[i].TextureID.ToString()) == null)
|
||||
cachedresp.WearableData[i].TextureID = UUID.Zero;
|
||||
//UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
|
||||
else
|
||||
cachedresp.WearableData[i].TextureID = UUID.Zero;
|
||||
// UUID.Parse("8334fb6e-c2f5-46ee-807d-a435f61a8d46");
|
||||
cachedresp.WearableData[i].HostName = new byte[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cachedresp.Header.Zerocoded = true;
|
||||
OutPacket(cachedresp, ThrottleOutPacketType.Task);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ namespace OpenSim.Region.ClientStack
|
||||
/// The name of the OpenSim scene this physics scene is serving. This will be used in log messages.
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
protected abstract PhysicsScene GetPhysicsScene(string osSceneIdentifier);
|
||||
protected abstract PhysicsScene GetPhysicsScene(string osSceneIdentifier, Vector3 regionExtent);
|
||||
|
||||
protected abstract ClientStackManager CreateClientStackManager();
|
||||
protected abstract Scene CreateScene(RegionInfo regionInfo, ISimulationDataService simDataService, IEstateDataService estateDataService, AgentCircuitManager circuitManager);
|
||||
@@ -123,13 +123,13 @@ namespace OpenSim.Region.ClientStack
|
||||
/// </param>
|
||||
/// <returns></returns>
|
||||
protected PhysicsScene GetPhysicsScene(
|
||||
string engine, string meshEngine, IConfigSource config, string osSceneIdentifier)
|
||||
string engine, string meshEngine, IConfigSource config, string osSceneIdentifier, Vector3 regionExtent)
|
||||
{
|
||||
PhysicsPluginManager physicsPluginManager;
|
||||
physicsPluginManager = new PhysicsPluginManager();
|
||||
physicsPluginManager.LoadPluginsFromAssemblies("Physics");
|
||||
|
||||
return physicsPluginManager.GetPhysicsScene(engine, meshEngine, config, osSceneIdentifier);
|
||||
return physicsPluginManager.GetPhysicsScene(engine, meshEngine, config, osSceneIdentifier, regionExtent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
@@ -182,6 +183,25 @@ namespace OpenSim.Region.CoreModules.Agent.TextureSender
|
||||
return DoJ2KDecode(assetID, j2kData, out layers, out components);
|
||||
}
|
||||
|
||||
public Image DecodeToImage(byte[] j2kData)
|
||||
{
|
||||
if (m_useCSJ2K)
|
||||
return J2kImage.FromBytes(j2kData);
|
||||
else
|
||||
{
|
||||
ManagedImage mimage;
|
||||
Image image;
|
||||
if (OpenJPEG.DecodeToImage(j2kData, out mimage, out image))
|
||||
{
|
||||
mimage = null;
|
||||
return image;
|
||||
}
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion IJ2KDecoder
|
||||
|
||||
/// <summary>
|
||||
|
||||
191
OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs
Normal file
191
OpenSim/Region/CoreModules/Avatar/BakedTextures/XBakesModule.cs
Normal file
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
* 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 OpenMetaverse;
|
||||
using Nini.Config;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Communications;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Mono.Addins;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Avatar.BakedTextures
|
||||
{
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XBakes.Module")]
|
||||
public class XBakesModule : INonSharedRegionModule, IBakedTextureModule
|
||||
{
|
||||
protected Scene m_Scene;
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private UTF8Encoding enc = new UTF8Encoding();
|
||||
private string m_URL = String.Empty;
|
||||
private static XmlSerializer m_serializer = new XmlSerializer(typeof(AssetBase));
|
||||
|
||||
|
||||
|
||||
public void Initialise(IConfigSource configSource)
|
||||
{
|
||||
IConfig config = configSource.Configs["XBakes"];
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
m_URL = config.GetString("URL", String.Empty);
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
{
|
||||
// m_log.InfoFormat("[XBakes]: Enabled for region {0}", scene.RegionInfo.RegionName);
|
||||
m_Scene = scene;
|
||||
|
||||
scene.RegisterModuleInterface<IBakedTextureModule>(this);
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene scene)
|
||||
{
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene scene)
|
||||
{
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "XBakes.Module"; }
|
||||
}
|
||||
|
||||
public Type ReplaceableInterface
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public WearableCacheItem[] Get(UUID id)
|
||||
{
|
||||
if (m_URL == String.Empty)
|
||||
return null;
|
||||
|
||||
int size = 0;
|
||||
RestClient rc = new RestClient(m_URL);
|
||||
List<WearableCacheItem> ret = new List<WearableCacheItem>();
|
||||
rc.AddResourcePath("bakes");
|
||||
rc.AddResourcePath(id.ToString());
|
||||
|
||||
rc.RequestMethod = "GET";
|
||||
|
||||
try
|
||||
{
|
||||
Stream s = rc.Request();
|
||||
XmlTextReader sr = new XmlTextReader(s);
|
||||
|
||||
sr.ReadStartElement("BakedAppearance");
|
||||
while (sr.LocalName == "BakedTexture")
|
||||
{
|
||||
string sTextureIndex = sr.GetAttribute("TextureIndex");
|
||||
int lTextureIndex = Convert.ToInt32(sTextureIndex);
|
||||
string sCacheId = sr.GetAttribute("CacheId");
|
||||
UUID lCacheId = UUID.Zero;
|
||||
if (!(UUID.TryParse(sCacheId, out lCacheId)))
|
||||
{
|
||||
// ?? Nothing here
|
||||
}
|
||||
|
||||
++size;
|
||||
|
||||
sr.ReadStartElement("BakedTexture");
|
||||
AssetBase a = (AssetBase)m_serializer.Deserialize(sr);
|
||||
ret.Add(new WearableCacheItem() { CacheId = lCacheId, TextureIndex = (uint)lTextureIndex, TextureAsset = a, TextureID = a.FullID });
|
||||
|
||||
sr.ReadEndElement();
|
||||
}
|
||||
m_log.DebugFormat("[XBakes]: Ended reading");
|
||||
sr.Close();
|
||||
s.Close();
|
||||
|
||||
|
||||
return ret.ToArray();
|
||||
}
|
||||
catch (XmlException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Store(UUID agentId, WearableCacheItem[] data)
|
||||
{
|
||||
if (m_URL == String.Empty)
|
||||
return;
|
||||
|
||||
MemoryStream bakeStream = new MemoryStream();
|
||||
XmlTextWriter bakeWriter = new XmlTextWriter(bakeStream, null);
|
||||
|
||||
bakeWriter.WriteStartElement(String.Empty, "BakedAppearance", String.Empty);
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (data[i] != null)
|
||||
{
|
||||
bakeWriter.WriteStartElement(String.Empty, "BakedTexture", String.Empty);
|
||||
bakeWriter.WriteAttributeString(String.Empty, "TextureIndex", String.Empty, data[i].TextureIndex.ToString());
|
||||
bakeWriter.WriteAttributeString(String.Empty, "CacheId", String.Empty, data[i].CacheId.ToString());
|
||||
if (data[i].TextureAsset != null)
|
||||
m_serializer.Serialize(bakeWriter, data[i].TextureAsset);
|
||||
|
||||
bakeWriter.WriteEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
bakeWriter.WriteEndElement();
|
||||
bakeWriter.Flush();
|
||||
|
||||
RestClient rc = new RestClient(m_URL);
|
||||
rc.AddResourcePath("bakes");
|
||||
rc.AddResourcePath(agentId.ToString());
|
||||
|
||||
rc.RequestMethod = "POST";
|
||||
|
||||
MemoryStream reqStream = new MemoryStream(bakeStream.ToArray());
|
||||
Util.FireAndForget(
|
||||
delegate
|
||||
{
|
||||
rc.Request(reqStream);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,8 +189,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||
string message = c.Message;
|
||||
Scene scene = (Scene)c.Scene;
|
||||
Vector3 fromPos = c.Position;
|
||||
Vector3 regionPos = new Vector3(scene.RegionInfo.RegionLocX * Constants.RegionSize,
|
||||
scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
|
||||
Vector3 regionPos = new Vector3(scene.RegionInfo.WorldLocX, scene.RegionInfo.WorldLocY, 0);
|
||||
|
||||
if (c.Channel == DEBUG_CHANNEL) c.Type = ChatTypeEnum.DebugChannel;
|
||||
|
||||
@@ -342,8 +341,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Chat
|
||||
{
|
||||
Vector3 fromRegionPos = fromPos + regionPos;
|
||||
Vector3 toRegionPos = presence.AbsolutePosition +
|
||||
new Vector3(presence.Scene.RegionInfo.RegionLocX * Constants.RegionSize,
|
||||
presence.Scene.RegionInfo.RegionLocY * Constants.RegionSize, 0);
|
||||
new Vector3(presence.Scene.RegionInfo.WorldLocX, presence.Scene.RegionInfo.WorldLocY, 0);
|
||||
|
||||
int dis = (int)Util.GetDistanceTo(toRegionPos, fromRegionPos);
|
||||
|
||||
|
||||
@@ -282,7 +282,17 @@ namespace OpenSim.Region.CoreModules.Avatar.InstantMessage
|
||||
string uasURL = circuit.ServiceURLs["HomeURI"].ToString();
|
||||
m_log.DebugFormat("[HG MESSAGE TRANSFER]: getting UUI of user {0} from {1}", toAgent, uasURL);
|
||||
UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uasURL);
|
||||
return uasConn.GetUUI(fromAgent, toAgent);
|
||||
|
||||
string agentUUI = string.Empty;
|
||||
try
|
||||
{
|
||||
agentUUI = uasConn.GetUUI(fromAgent, toAgent);
|
||||
}
|
||||
catch (Exception e) {
|
||||
m_log.Debug("[HG MESSAGE TRANSFER]: GetUUI call failed ", e);
|
||||
}
|
||||
|
||||
return agentUUI;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -667,8 +667,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
|
||||
|
||||
Vector3 avaPos = p.AbsolutePosition;
|
||||
// Getting the global position for the Avatar
|
||||
Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.RegionLocX*Constants.RegionSize + avaPos.X,
|
||||
remoteClient.Scene.RegionInfo.RegionLocY*Constants.RegionSize + avaPos.Y,
|
||||
Vector3 posGlobal = new Vector3(remoteClient.Scene.RegionInfo.WorldLocX + avaPos.X,
|
||||
remoteClient.Scene.RegionInfo.WorldLocY + avaPos.Y,
|
||||
avaPos.Z);
|
||||
|
||||
string landOwnerName = string.Empty;
|
||||
@@ -1164,7 +1164,16 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
|
||||
|
||||
UserAgentServiceConnector uConn = new UserAgentServiceConnector(home_url);
|
||||
|
||||
Dictionary<string, object> account = uConn.GetUserInfo(userID);
|
||||
Dictionary<string, object> account;
|
||||
try
|
||||
{
|
||||
account = uConn.GetUserInfo(userID);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[PROFILES]: GetUserInfo call failed ", e);
|
||||
account = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
if (account.Count > 0)
|
||||
{
|
||||
@@ -1290,9 +1299,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
|
||||
webRequest.ContentType = "application/json-rpc";
|
||||
webRequest.Method = "POST";
|
||||
|
||||
Stream dataStream = webRequest.GetRequestStream();
|
||||
dataStream.Write(content, 0, content.Length);
|
||||
dataStream.Close();
|
||||
using (Stream dataStream = webRequest.GetRequestStream())
|
||||
dataStream.Write(content, 0, content.Length);
|
||||
|
||||
WebResponse webResponse = null;
|
||||
try
|
||||
@@ -1306,26 +1314,18 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream rstream = webResponse.GetResponseStream();
|
||||
|
||||
OSDMap mret = new OSDMap();
|
||||
try
|
||||
using (webResponse)
|
||||
using (Stream rstream = webResponse.GetResponseStream())
|
||||
{
|
||||
mret = (OSDMap)OSDParser.DeserializeJson(rstream);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message);
|
||||
return false;
|
||||
}
|
||||
OSDMap mret = (OSDMap)OSDParser.DeserializeJson(rstream);
|
||||
|
||||
if (mret.ContainsKey("error"))
|
||||
return false;
|
||||
|
||||
if (mret.ContainsKey("error"))
|
||||
return false;
|
||||
|
||||
// get params...
|
||||
OSD.DeserializeMembers(ref parameters, (OSDMap) mret["result"]);
|
||||
return true;
|
||||
// get params...
|
||||
OSD.DeserializeMembers(ref parameters, (OSDMap)mret["result"]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1366,9 +1366,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
|
||||
webRequest.ContentType = "application/json-rpc";
|
||||
webRequest.Method = "POST";
|
||||
|
||||
Stream dataStream = webRequest.GetRequestStream();
|
||||
dataStream.Write(content, 0, content.Length);
|
||||
dataStream.Close();
|
||||
using (Stream dataStream = webRequest.GetRequestStream())
|
||||
dataStream.Write(content, 0, content.Length);
|
||||
|
||||
WebResponse webResponse = null;
|
||||
try
|
||||
@@ -1382,29 +1381,32 @@ namespace OpenSim.Region.OptionalModules.Avatar.UserProfiles
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream rstream = webResponse.GetResponseStream();
|
||||
|
||||
OSDMap response = new OSDMap();
|
||||
try
|
||||
using (webResponse)
|
||||
using (Stream rstream = webResponse.GetResponseStream())
|
||||
{
|
||||
response = (OSDMap)OSDParser.DeserializeJson(rstream);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message);
|
||||
return false;
|
||||
}
|
||||
OSDMap response = new OSDMap();
|
||||
try
|
||||
{
|
||||
response = (OSDMap)OSDParser.DeserializeJson(rstream);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES]: JsonRpcRequest Error {0} - remote user with legacy profiles?", e.Message);
|
||||
return false;
|
||||
}
|
||||
|
||||
if(response.ContainsKey("error"))
|
||||
{
|
||||
data = response["error"];
|
||||
return false;
|
||||
if (response.ContainsKey("error"))
|
||||
{
|
||||
data = response["error"];
|
||||
return false;
|
||||
}
|
||||
|
||||
data = response;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
data = response;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Web Util
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,9 +269,7 @@ namespace OpenSim.Region.CoreModules.Framework
|
||||
foreach (KeyValuePair<ulong, string> kvp in m_childrenSeeds[agentID])
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(kvp.Key, out x, out y);
|
||||
x = x / Constants.RegionSize;
|
||||
y = y / Constants.RegionSize;
|
||||
Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
|
||||
m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "EntityTransferModule")]
|
||||
public class EntityTransferModule : INonSharedRegionModule, IEntityTransferModule
|
||||
{
|
||||
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 = "[ENTITY TRANSFER MODULE]";
|
||||
|
||||
public const int DefaultMaxTransferDistance = 4095;
|
||||
@@ -121,8 +121,53 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
/// </summary>
|
||||
private EntityTransferStateMachine m_entityTransferStateMachine;
|
||||
|
||||
private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
|
||||
new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
|
||||
// For performance, we keed a cached of banned regions so we don't keep going
|
||||
// to the grid service.
|
||||
private class BannedRegionCache
|
||||
{
|
||||
private ExpiringCache<UUID, ExpiringCache<ulong, DateTime>> m_bannedRegions =
|
||||
new ExpiringCache<UUID, ExpiringCache<ulong, DateTime>>();
|
||||
ExpiringCache<ulong, DateTime> m_idCache;
|
||||
DateTime m_banUntil;
|
||||
public BannedRegionCache()
|
||||
{
|
||||
}
|
||||
// Return 'true' if there is a valid ban entry for this agent in this region
|
||||
public bool IfBanned(ulong pRegionHandle, UUID pAgentID)
|
||||
{
|
||||
bool ret = false;
|
||||
if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
|
||||
{
|
||||
if (m_idCache.TryGetValue(pRegionHandle, out m_banUntil))
|
||||
{
|
||||
if (DateTime.Now < m_banUntil)
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// Add this agent in this region as a banned person
|
||||
public void Add(ulong pRegionHandle, UUID pAgentID)
|
||||
{
|
||||
if (!m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
|
||||
{
|
||||
m_idCache = new ExpiringCache<ulong, DateTime>();
|
||||
m_bannedRegions.Add(pAgentID, m_idCache, TimeSpan.FromSeconds(45));
|
||||
}
|
||||
m_idCache.Add(pRegionHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
|
||||
}
|
||||
// Remove the agent from the region's banned list
|
||||
public void Remove(ulong pRegionHandle, UUID pAgentID)
|
||||
{
|
||||
if (m_bannedRegions.TryGetValue(pAgentID, out m_idCache))
|
||||
{
|
||||
m_idCache.Remove(pRegionHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
private BannedRegionCache m_bannedRegionCache = new BannedRegionCache();
|
||||
|
||||
private IEventQueue m_eqModule;
|
||||
private IRegionCombinerModule m_regionCombinerModule;
|
||||
@@ -337,6 +382,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
"[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
|
||||
}
|
||||
|
||||
// Attempt to teleport the ScenePresence to the specified position in the specified region (spec'ed by its handle).
|
||||
public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
|
||||
{
|
||||
if (sp.Scene.Permissions.IsGridGod(sp.UUID))
|
||||
@@ -418,7 +464,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
sp.Name, position, sp.Scene.RegionInfo.RegionName);
|
||||
|
||||
// Teleport within the same region
|
||||
if (IsOutsideRegion(sp.Scene, position) || position.Z < 0)
|
||||
if (!sp.Scene.PositionIsInCurrentRegion(position) || position.Z < 0)
|
||||
{
|
||||
Vector3 emergencyPos = new Vector3(128, 128, 128);
|
||||
|
||||
@@ -434,10 +480,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
float posZLimit = 22;
|
||||
|
||||
// TODO: Check other Scene HeightField
|
||||
if (position.X > 0 && position.X <= (int)Constants.RegionSize && position.Y > 0 && position.Y <= (int)Constants.RegionSize)
|
||||
{
|
||||
posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
|
||||
}
|
||||
posZLimit = (float)sp.Scene.Heightmap[(int)position.X, (int)position.Y];
|
||||
|
||||
float newPosZ = posZLimit + localAVHeight;
|
||||
if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ)))
|
||||
@@ -480,9 +523,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
ScenePresence sp, ulong regionHandle, Vector3 position,
|
||||
Vector3 lookAt, uint teleportFlags, out GridRegion finalDestination)
|
||||
{
|
||||
uint x = 0, y = 0;
|
||||
Utils.LongToUInts(regionHandle, out x, out y);
|
||||
GridRegion reg = Scene.GridService.GetRegionByPosition(sp.Scene.RegionInfo.ScopeID, (int)x, (int)y);
|
||||
// Get destination region taking into account that the address could be an offset
|
||||
// region inside a varregion.
|
||||
GridRegion reg = GetTeleportDestinationRegion(sp.Scene.GridService, sp.Scene.RegionInfo.ScopeID, regionHandle, ref position);
|
||||
|
||||
if (reg != null)
|
||||
{
|
||||
@@ -490,9 +533,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
|
||||
if (finalDestination == null)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Final destination is having problems. Unable to teleport {0} {1}",
|
||||
sp.Name, sp.UUID);
|
||||
m_log.WarnFormat( "{0} Final destination is having problems. Unable to teleport {1} {2}",
|
||||
LogHeader, sp.Name, sp.UUID);
|
||||
|
||||
sp.ControllingClient.SendTeleportFailed("Problem at destination");
|
||||
return;
|
||||
@@ -533,12 +575,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
|
||||
// and set the map-tile to '(Offline)'
|
||||
uint regX, regY;
|
||||
Utils.LongToUInts(regionHandle, out regX, out regY);
|
||||
Util.RegionHandleToRegionLoc(regionHandle, out regX, out regY);
|
||||
|
||||
MapBlockData block = new MapBlockData();
|
||||
block.X = (ushort)(regX / Constants.RegionSize);
|
||||
block.Y = (ushort)(regY / Constants.RegionSize);
|
||||
block.Access = 254; // == not there
|
||||
block.X = (ushort)regX;
|
||||
block.Y = (ushort)regY;
|
||||
block.Access = (byte)SimAccess.Down;
|
||||
|
||||
List<MapBlockData> blocks = new List<MapBlockData>();
|
||||
blocks.Add(block);
|
||||
@@ -546,6 +588,31 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
}
|
||||
}
|
||||
|
||||
// The teleport address could be an address in a subregion of a larger varregion.
|
||||
// Find the real base region and adjust the teleport location to account for the
|
||||
// larger region.
|
||||
private GridRegion GetTeleportDestinationRegion(IGridService gridService, UUID scope, ulong regionHandle, ref Vector3 position)
|
||||
{
|
||||
uint x = 0, y = 0;
|
||||
Util.RegionHandleToWorldLoc(regionHandle, out x, out y);
|
||||
|
||||
// Compute the world location we're teleporting to
|
||||
double worldX = (double)x + position.X;
|
||||
double worldY = (double)y + position.Y;
|
||||
|
||||
// Find the region that contains the position
|
||||
GridRegion reg = GetRegionContainingWorldLocation(gridService, scope, worldX, worldY);
|
||||
|
||||
if (reg != null)
|
||||
{
|
||||
// modify the position for the offset into the actual region returned
|
||||
position.X += x - reg.RegionLocX;
|
||||
position.Y += y - reg.RegionLocY;
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
// Nothing to validate here
|
||||
protected virtual bool ValidateGenericConditions(ScenePresence sp, GridRegion reg, GridRegion finalDestination, uint teleportFlags, out string reason)
|
||||
{
|
||||
@@ -646,10 +713,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return;
|
||||
}
|
||||
|
||||
uint newRegionX = (uint)(reg.RegionHandle >> 40);
|
||||
uint newRegionY = (((uint)(reg.RegionHandle)) >> 8);
|
||||
uint oldRegionX = (uint)(sp.Scene.RegionInfo.RegionHandle >> 40);
|
||||
uint oldRegionY = (((uint)(sp.Scene.RegionInfo.RegionHandle)) >> 8);
|
||||
uint newRegionX, newRegionY, oldRegionX, oldRegionY;
|
||||
Util.RegionHandleToRegionLoc(reg.RegionHandle, out newRegionX, out newRegionY);
|
||||
Util.RegionHandleToRegionLoc(sp.Scene.RegionInfo.RegionHandle, out oldRegionX, out oldRegionY);
|
||||
|
||||
ulong destinationHandle = finalDestination.RegionHandle;
|
||||
|
||||
@@ -1266,6 +1332,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return region;
|
||||
}
|
||||
|
||||
// This returns 'true' if the new region already has a child agent for our
|
||||
// incoming agent. The implication is that, if 'false', we have to create the
|
||||
// child and then teleport into the region.
|
||||
protected virtual bool NeedsNewAgent(float drawdist, uint oldRegionX, uint newRegionX, uint oldRegionY, uint newRegionY)
|
||||
{
|
||||
if (m_regionCombinerModule != null && m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
|
||||
@@ -1290,20 +1359,6 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return Util.IsOutsideView(drawdist, oldRegionX, newRegionX, oldRegionY, newRegionY);
|
||||
}
|
||||
|
||||
protected virtual bool IsOutsideRegion(Scene s, Vector3 pos)
|
||||
{
|
||||
if (s.TestBorderCross(pos, Cardinals.N))
|
||||
return true;
|
||||
if (s.TestBorderCross(pos, Cardinals.S))
|
||||
return true;
|
||||
if (s.TestBorderCross(pos, Cardinals.E))
|
||||
return true;
|
||||
if (s.TestBorderCross(pos, Cardinals.W))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Landmark Teleport
|
||||
@@ -1349,6 +1404,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
if (uinfo.HomeRegionID == UUID.Zero)
|
||||
{
|
||||
// can't find the Home region: Tell viewer and abort
|
||||
m_log.ErrorFormat("{0} No grid user info found for {1} {2}. Cannot send home.",
|
||||
LogHeader, client.Name, client.AgentId);
|
||||
client.SendTeleportFailed("You don't have a home position set.");
|
||||
return false;
|
||||
}
|
||||
@@ -1382,139 +1439,73 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
|
||||
#region Agent Crossings
|
||||
|
||||
public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos)
|
||||
// Given a position relative to the current region (which has previously been tested to
|
||||
// see that it is actually outside the current region), find the new region that the
|
||||
// point is actually in.
|
||||
// Returns the coordinates and information of the new region or 'null' of it doesn't exist.
|
||||
public GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos,
|
||||
out string version, out Vector3 newpos, out string failureReason)
|
||||
{
|
||||
version = String.Empty;
|
||||
newpos = pos;
|
||||
failureReason = string.Empty;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ENTITY TRANSFER MODULE]: Crossing agent {0} at pos {1} in {2}", agent.Name, pos, scene.Name);
|
||||
|
||||
uint neighbourx = scene.RegionInfo.RegionLocX;
|
||||
uint neighboury = scene.RegionInfo.RegionLocY;
|
||||
const float boundaryDistance = 1.7f;
|
||||
Vector3 northCross = new Vector3(0, boundaryDistance, 0);
|
||||
Vector3 southCross = new Vector3(0, -1 * boundaryDistance, 0);
|
||||
Vector3 eastCross = new Vector3(boundaryDistance, 0, 0);
|
||||
Vector3 westCross = new Vector3(-1 * boundaryDistance, 0, 0);
|
||||
// Compute world location of the object's position
|
||||
double presenceWorldX = (double)scene.RegionInfo.WorldLocX + pos.X;
|
||||
double presenceWorldY = (double)scene.RegionInfo.WorldLocY + pos.Y;
|
||||
|
||||
// distance into new region to place avatar
|
||||
const float enterDistance = 0.5f;
|
||||
// Call the grid service to lookup the region containing the new position.
|
||||
GridRegion neighbourRegion = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
|
||||
presenceWorldX, presenceWorldY,
|
||||
Math.Max(scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY));
|
||||
|
||||
if (scene.TestBorderCross(pos + westCross, Cardinals.W))
|
||||
if (neighbourRegion != null)
|
||||
{
|
||||
if (scene.TestBorderCross(pos + northCross, Cardinals.N))
|
||||
// Compute the entity's position relative to the new region
|
||||
newpos = new Vector3((float)(presenceWorldX - (double)neighbourRegion.RegionLocX),
|
||||
(float)(presenceWorldY - (double)neighbourRegion.RegionLocY),
|
||||
pos.Z);
|
||||
|
||||
if (m_bannedRegionCache.IfBanned(neighbourRegion.RegionHandle, agentID))
|
||||
{
|
||||
Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
|
||||
neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
|
||||
failureReason = "Cannot region cross into banned parcel";
|
||||
neighbourRegion = null;
|
||||
}
|
||||
else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
|
||||
else
|
||||
{
|
||||
neighboury--;
|
||||
newpos.Y = Constants.RegionSize - enterDistance;
|
||||
// If not banned, make sure this agent is not in the list.
|
||||
m_bannedRegionCache.Remove(neighbourRegion.RegionHandle, agentID);
|
||||
}
|
||||
|
||||
neighbourx--;
|
||||
newpos.X = Constants.RegionSize - enterDistance;
|
||||
}
|
||||
else if (scene.TestBorderCross(pos + eastCross, Cardinals.E))
|
||||
{
|
||||
Border b = scene.GetCrossedBorder(pos + eastCross, Cardinals.E);
|
||||
neighbourx += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
|
||||
newpos.X = enterDistance;
|
||||
|
||||
if (scene.TestBorderCross(pos + southCross, Cardinals.S))
|
||||
// Check to see if we have access to the target region.
|
||||
if (neighbourRegion != null
|
||||
&& !scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out failureReason))
|
||||
{
|
||||
neighboury--;
|
||||
newpos.Y = Constants.RegionSize - enterDistance;
|
||||
}
|
||||
else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
|
||||
{
|
||||
Border c = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
|
||||
neighboury += (uint)(int)(c.BorderLine.Z / (int)Constants.RegionSize);
|
||||
newpos.Y = enterDistance;
|
||||
}
|
||||
}
|
||||
else if (scene.TestBorderCross(pos + southCross, Cardinals.S))
|
||||
{
|
||||
Border b = scene.GetCrossedBorder(pos + southCross, Cardinals.S);
|
||||
neighboury--;
|
||||
newpos.Y = Constants.RegionSize - enterDistance;
|
||||
}
|
||||
else if (scene.TestBorderCross(pos + northCross, Cardinals.N))
|
||||
{
|
||||
Border b = scene.GetCrossedBorder(pos + northCross, Cardinals.N);
|
||||
neighboury += (uint)(int)(b.BorderLine.Z / (int)Constants.RegionSize);
|
||||
newpos.Y = enterDistance;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
if (pos.X < boundaryDistance) //West
|
||||
{
|
||||
neighbourx--;
|
||||
newpos.X = Constants.RegionSize - enterDistance;
|
||||
}
|
||||
else if (pos.X > Constants.RegionSize - boundaryDistance) // East
|
||||
{
|
||||
neighbourx++;
|
||||
newpos.X = enterDistance;
|
||||
}
|
||||
|
||||
if (pos.Y < boundaryDistance) // South
|
||||
{
|
||||
neighboury--;
|
||||
newpos.Y = Constants.RegionSize - enterDistance;
|
||||
}
|
||||
else if (pos.Y > Constants.RegionSize - boundaryDistance) // North
|
||||
{
|
||||
neighboury++;
|
||||
newpos.Y = enterDistance;
|
||||
}
|
||||
*/
|
||||
|
||||
xDest = neighbourx;
|
||||
yDest = neighboury;
|
||||
|
||||
int x = (int)(neighbourx * Constants.RegionSize), y = (int)(neighboury * Constants.RegionSize);
|
||||
|
||||
ulong neighbourHandle = Utils.UIntsToLong((uint)x, (uint)y);
|
||||
|
||||
ExpiringCache<ulong, DateTime> r;
|
||||
DateTime banUntil;
|
||||
|
||||
if (m_bannedRegions.TryGetValue(agentID, out r))
|
||||
{
|
||||
if (r.TryGetValue(neighbourHandle, out banUntil))
|
||||
{
|
||||
if (DateTime.Now < banUntil)
|
||||
return null;
|
||||
r.Remove(neighbourHandle);
|
||||
// remember banned
|
||||
m_bannedRegionCache.Add(neighbourRegion.RegionHandle, agentID);
|
||||
neighbourRegion = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r = null;
|
||||
// The destination region just doesn't exist
|
||||
failureReason = "Cannot cross into non-existant region";
|
||||
}
|
||||
|
||||
GridRegion neighbourRegion = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
|
||||
|
||||
string reason;
|
||||
if (!scene.SimulationService.QueryAccess(neighbourRegion, agentID, newpos, out version, out reason))
|
||||
{
|
||||
if (r == null)
|
||||
{
|
||||
r = new ExpiringCache<ulong, DateTime>();
|
||||
r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
|
||||
|
||||
m_bannedRegions.Add(agentID, r, TimeSpan.FromSeconds(45));
|
||||
}
|
||||
else
|
||||
{
|
||||
r.Add(neighbourHandle, DateTime.Now + TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
if (neighbourRegion == null)
|
||||
m_log.DebugFormat("{0} GetDestination: region not found. Old region name={1} at <{2},{3}> of size <{4},{5}>. Old pos={6}",
|
||||
LogHeader, scene.RegionInfo.RegionName,
|
||||
scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
|
||||
scene.RegionInfo.RegionSizeX, scene.RegionInfo.RegionSizeY,
|
||||
pos);
|
||||
else
|
||||
m_log.DebugFormat("{0} GetDestination: new region={1} at <{2},{3}> of size <{4},{5}>, newpos=<{6},{7}>",
|
||||
LogHeader, neighbourRegion.RegionName,
|
||||
neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, neighbourRegion.RegionSizeX, neighbourRegion.RegionSizeY,
|
||||
newpos.X, newpos.Y);
|
||||
|
||||
return neighbourRegion;
|
||||
}
|
||||
@@ -1525,11 +1516,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
uint y;
|
||||
Vector3 newpos;
|
||||
string version;
|
||||
string failureReason;
|
||||
|
||||
GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition, out x, out y, out version, out newpos);
|
||||
GridRegion neighbourRegion = GetDestination(agent.Scene, agent.UUID, agent.AbsolutePosition,
|
||||
out version, out newpos, out failureReason);
|
||||
if (neighbourRegion == null)
|
||||
{
|
||||
agent.ControllingClient.SendAlertMessage("Cannot region cross into banned parcel");
|
||||
agent.ControllingClient.SendAlertMessage(failureReason);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1568,7 +1561,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
|
||||
agent.Scene.RequestTeleportLocation(
|
||||
agent.ControllingClient,
|
||||
Utils.UIntsToLong(regionX * (uint)Constants.RegionSize, regionY * (uint)Constants.RegionSize),
|
||||
Util.RegionLocToHandle(regionX, regionY),
|
||||
position,
|
||||
agent.Lookat,
|
||||
(uint)Constants.TeleportFlags.ViaLocation);
|
||||
@@ -1578,11 +1571,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
if (im != null)
|
||||
{
|
||||
UUID gotoLocation = Util.BuildFakeParcelID(
|
||||
Util.UIntsToLong(
|
||||
(regionX *
|
||||
(uint)Constants.RegionSize),
|
||||
(regionY *
|
||||
(uint)Constants.RegionSize)),
|
||||
Util.RegionLocToHandle(regionX, regionY),
|
||||
(uint)(int)position.X,
|
||||
(uint)(int)position.Y,
|
||||
(uint)(int)position.Z);
|
||||
@@ -1635,17 +1624,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
/// Calls an asynchronous method to do so.. so it doesn't lag the sim.
|
||||
/// </summary>
|
||||
public ScenePresence CrossAgentToNewRegionAsync(
|
||||
ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
|
||||
bool isFlying, string version)
|
||||
ScenePresence agent, Vector3 pos, GridRegion neighbourRegion,
|
||||
bool isFlying, string version)
|
||||
{
|
||||
m_log.DebugFormat("{0} CrossAgentToNewRegionAsync: new region={1} at <{2},{3}>. newpos={4}",
|
||||
LogHeader, neighbourRegion.RegionName, neighbourRegion.RegionLocX, neighbourRegion.RegionLocY, pos);
|
||||
|
||||
if (!CrossAgentToNewRegionPrep(agent, neighbourRegion))
|
||||
{
|
||||
m_log.DebugFormat("{0} CrossAgentToNewRegionAsync: prep failed. Resetting transfer state", LogHeader);
|
||||
m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
|
||||
return agent;
|
||||
}
|
||||
|
||||
if (!CrossAgentIntoNewRegionMain(agent, pos, neighbourRegion, isFlying))
|
||||
{
|
||||
m_log.DebugFormat("{0} CrossAgentToNewRegionAsync: cross main failed. Resetting transfer state", LogHeader);
|
||||
m_entityTransferStateMachine.ResetFromTransit(agent.UUID);
|
||||
return agent;
|
||||
}
|
||||
@@ -2038,15 +2032,195 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
}
|
||||
}
|
||||
|
||||
// Computes the difference between two region bases.
|
||||
// Returns a vector of world coordinates (meters) from base of first region to the second.
|
||||
// The first region is the home region of the passed scene presence.
|
||||
Vector3 CalculateOffset(ScenePresence sp, GridRegion neighbour)
|
||||
{
|
||||
int rRegionX = (int)sp.Scene.RegionInfo.RegionLocX;
|
||||
int rRegionY = (int)sp.Scene.RegionInfo.RegionLocY;
|
||||
/*
|
||||
int rRegionX = (int)sp.Scene.RegionInfo.LegacyRegionLocX;
|
||||
int rRegionY = (int)sp.Scene.RegionInfo.LegacyRegionLocY;
|
||||
int tRegionX = neighbour.RegionLocX / (int)Constants.RegionSize;
|
||||
int tRegionY = neighbour.RegionLocY / (int)Constants.RegionSize;
|
||||
int shiftx = (rRegionX - tRegionX) * (int)Constants.RegionSize;
|
||||
int shifty = (rRegionY - tRegionY) * (int)Constants.RegionSize;
|
||||
return new Vector3(shiftx, shifty, 0f);
|
||||
*/
|
||||
return new Vector3( sp.Scene.RegionInfo.WorldLocX - neighbour.RegionLocX,
|
||||
sp.Scene.RegionInfo.WorldLocY - neighbour.RegionLocY,
|
||||
0f);
|
||||
}
|
||||
|
||||
public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID, double px, double py)
|
||||
{
|
||||
// Since we don't know how big the regions could be, we have to search a very large area
|
||||
// to find possible regions.
|
||||
return GetRegionContainingWorldLocation(pGridService, pScopeID, px, py, Constants.MaximumRegionSize);
|
||||
}
|
||||
|
||||
#region NotFoundLocationCache class
|
||||
// A collection of not found locations to make future lookups 'not found' lookups quick.
|
||||
// A simple expiring cache that keeps not found locations for some number of seconds.
|
||||
// A 'not found' location is presumed to be anywhere in the minimum sized region that
|
||||
// contains that point. A conservitive estimate.
|
||||
private class NotFoundLocationCache
|
||||
{
|
||||
private struct NotFoundLocation
|
||||
{
|
||||
public double minX, maxX, minY, maxY;
|
||||
public DateTime expireTime;
|
||||
}
|
||||
private List<NotFoundLocation> m_notFoundLocations = new List<NotFoundLocation>();
|
||||
public NotFoundLocationCache()
|
||||
{
|
||||
}
|
||||
// Add an area to the list of 'not found' places. The area is the snapped region
|
||||
// area around the added point.
|
||||
public void Add(double pX, double pY)
|
||||
{
|
||||
lock (m_notFoundLocations)
|
||||
{
|
||||
if (!LockedContains(pX, pY))
|
||||
{
|
||||
NotFoundLocation nfl = new NotFoundLocation();
|
||||
// A not found location is not found for at least a whole region sized area
|
||||
nfl.minX = pX - (pX % (double)Constants.RegionSize);
|
||||
nfl.minY = pY - (pY % (double)Constants.RegionSize);
|
||||
nfl.maxX = nfl.minX + (double)Constants.RegionSize;
|
||||
nfl.maxY = nfl.minY + (double)Constants.RegionSize;
|
||||
nfl.expireTime = DateTime.Now + TimeSpan.FromSeconds(30);
|
||||
m_notFoundLocations.Add(nfl);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// Test to see of this point is in any of the 'not found' areas.
|
||||
// Return 'true' if the point is found inside the 'not found' areas.
|
||||
public bool Contains(double pX, double pY)
|
||||
{
|
||||
bool ret = false;
|
||||
lock (m_notFoundLocations)
|
||||
ret = LockedContains(pX, pY);
|
||||
return ret;
|
||||
}
|
||||
private bool LockedContains(double pX, double pY)
|
||||
{
|
||||
bool ret = false;
|
||||
this.DoExpiration();
|
||||
foreach (NotFoundLocation nfl in m_notFoundLocations)
|
||||
{
|
||||
if (pX >= nfl.minX && pX < nfl.maxX && pY >= nfl.minY && pY < nfl.maxY)
|
||||
{
|
||||
ret = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
private void DoExpiration()
|
||||
{
|
||||
List<NotFoundLocation> m_toRemove = null;
|
||||
DateTime now = DateTime.Now;
|
||||
foreach (NotFoundLocation nfl in m_notFoundLocations)
|
||||
{
|
||||
if (nfl.expireTime < now)
|
||||
{
|
||||
if (m_toRemove == null)
|
||||
m_toRemove = new List<NotFoundLocation>();
|
||||
m_toRemove.Add(nfl);
|
||||
}
|
||||
}
|
||||
if (m_toRemove != null)
|
||||
{
|
||||
foreach (NotFoundLocation nfl in m_toRemove)
|
||||
m_notFoundLocations.Remove(nfl);
|
||||
m_toRemove.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion // NotFoundLocationCache class
|
||||
private NotFoundLocationCache m_notFoundLocationCache = new NotFoundLocationCache();
|
||||
|
||||
// Given a world position (fractional meter coordinate), get the GridRegion info for
|
||||
// the region containing that point.
|
||||
// Someday this should be a method on GridService.
|
||||
// 'pSizeHint' is the size of the source region but since the destination point can be anywhere
|
||||
// the size of the target region is unknown thus the search area might have to be very large.
|
||||
// Return 'null' if no such region exists.
|
||||
public GridRegion GetRegionContainingWorldLocation(IGridService pGridService, UUID pScopeID,
|
||||
double px, double py, uint pSizeHint)
|
||||
{
|
||||
m_log.DebugFormat("{0} GetRegionContainingWorldLocation: call, XY=<{1},{2}>", LogHeader, px, py);
|
||||
GridRegion ret = null;
|
||||
const double fudge = 2.0;
|
||||
|
||||
// One problem with this routine is negative results. That is, this can be called lots of times
|
||||
// for regions that don't exist. m_notFoundLocationCache remembers 'not found' results so they
|
||||
// will be quick 'not found's next time.
|
||||
// NotFoundLocationCache is an expiring cache so it will eventually forget about 'not found' and
|
||||
// thus re-ask the GridService about the location.
|
||||
if (m_notFoundLocationCache.Contains(px, py))
|
||||
{
|
||||
m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found via cache. loc=<{1},{2}>", LogHeader, px, py);
|
||||
return null;
|
||||
}
|
||||
|
||||
// As an optimization, since most regions will be legacy sized regions (256x256), first try to get
|
||||
// the region at the appropriate legacy region location.
|
||||
uint possibleX = (uint)Math.Floor(px);
|
||||
possibleX -= possibleX % Constants.RegionSize;
|
||||
uint possibleY = (uint)Math.Floor(py);
|
||||
possibleY -= possibleY % Constants.RegionSize;
|
||||
ret = pGridService.GetRegionByPosition(pScopeID, (int)possibleX, (int)possibleY);
|
||||
if (ret != null)
|
||||
{
|
||||
m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Found region using legacy size. rloc=<{1},{2}>. Rname={3}",
|
||||
LogHeader, possibleX, possibleY, ret.RegionName);
|
||||
}
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
// If the simple lookup failed, search the larger area for a region that contains this point
|
||||
double range = (double)pSizeHint + fudge;
|
||||
while (ret == null && range <= (Constants.MaximumRegionSize + Constants.RegionSize))
|
||||
{
|
||||
// Get from the grid service a list of regions that might contain this point.
|
||||
// The region origin will be in the zero direction so only subtract the range.
|
||||
List<GridRegion> possibleRegions = pGridService.GetRegionRange(pScopeID,
|
||||
(int)(px - range), (int)(px),
|
||||
(int)(py - range), (int)(py));
|
||||
m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegions cnt={1}, range={2}",
|
||||
LogHeader, possibleRegions.Count, range);
|
||||
if (possibleRegions != null && possibleRegions.Count > 0)
|
||||
{
|
||||
// If we found some regions, check to see if the point is within
|
||||
foreach (GridRegion gr in possibleRegions)
|
||||
{
|
||||
m_log.DebugFormat("{0} GetRegionContainingWorldLocation: possibleRegion nm={1}, regionLoc=<{2},{3}>, regionSize=<{4},{5}>",
|
||||
LogHeader, gr.RegionName, gr.RegionLocX, gr.RegionLocY, gr.RegionSizeX, gr.RegionSizeY);
|
||||
if (px >= (double)gr.RegionLocX && px < (double)(gr.RegionLocX + gr.RegionSizeX)
|
||||
&& py >= (double)gr.RegionLocY && py < (double)(gr.RegionLocY + gr.RegionSizeY))
|
||||
{
|
||||
// Found a region that contains the point
|
||||
ret = gr;
|
||||
m_log.DebugFormat("{0} GetRegionContainingWorldLocation: found. RegionName={1}", LogHeader, ret.RegionName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Larger search area for next time around if not found
|
||||
range *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
// remember this location was not found so we can quickly not find it next time
|
||||
m_notFoundLocationCache.Add(px, py);
|
||||
m_log.DebugFormat("{0} GetRegionContainingWorldLocation: Not found. Remembering loc=<{1},{2}>", LogHeader, px, py);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void InformClientOfNeighbourCompleted(IAsyncResult iar)
|
||||
@@ -2128,22 +2302,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
/// <param name='neCorner'></param>
|
||||
private void GetMegaregionViewRange(out Vector2 swCorner, out Vector2 neCorner)
|
||||
{
|
||||
Border[] northBorders = Scene.NorthBorders.ToArray();
|
||||
Border[] eastBorders = Scene.EastBorders.ToArray();
|
||||
|
||||
Vector2 extent = Vector2.Zero;
|
||||
for (int i = 0; i < eastBorders.Length; i++)
|
||||
{
|
||||
extent.X = (eastBorders[i].BorderLine.Z > extent.X) ? eastBorders[i].BorderLine.Z : extent.X;
|
||||
}
|
||||
for (int i = 0; i < northBorders.Length; i++)
|
||||
{
|
||||
extent.Y = (northBorders[i].BorderLine.Z > extent.Y) ? northBorders[i].BorderLine.Z : extent.Y;
|
||||
}
|
||||
|
||||
// Loss of fraction on purpose
|
||||
extent.X = ((int)extent.X / (int)Constants.RegionSize);
|
||||
extent.Y = ((int)extent.Y / (int)Constants.RegionSize);
|
||||
if (m_regionCombinerModule != null)
|
||||
{
|
||||
Vector2 megaRegionSize = m_regionCombinerModule.GetSizeOfMegaregion(Scene.RegionInfo.RegionID);
|
||||
extent.X = (float)Util.WorldToRegionLoc((uint)megaRegionSize.X);
|
||||
extent.Y = (float)Util.WorldToRegionLoc((uint)megaRegionSize.Y);
|
||||
}
|
||||
|
||||
swCorner.X = Scene.RegionInfo.RegionLocX - 1;
|
||||
swCorner.Y = Scene.RegionInfo.RegionLocY - 1;
|
||||
@@ -2168,16 +2334,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
// view to include everything in the megaregion
|
||||
if (m_regionCombinerModule == null || !m_regionCombinerModule.IsRootForMegaregion(Scene.RegionInfo.RegionID))
|
||||
{
|
||||
int dd = avatar.DrawDistance < Constants.RegionSize ? (int)Constants.RegionSize : (int)avatar.DrawDistance;
|
||||
// The area to check is as big as the current region.
|
||||
// We presume all adjacent regions are the same size as this region.
|
||||
uint dd = Math.Max((uint)avatar.DrawDistance,
|
||||
Math.Max(Scene.RegionInfo.RegionSizeX, Scene.RegionInfo.RegionSizeY));
|
||||
|
||||
int startX = (int)pRegionLocX * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2);
|
||||
int startY = (int)pRegionLocY * (int)Constants.RegionSize - dd + (int)(Constants.RegionSize/2);
|
||||
uint startX = Util.RegionToWorldLoc(pRegionLocX) - dd + Constants.RegionSize/2;
|
||||
uint startY = Util.RegionToWorldLoc(pRegionLocY) - dd + Constants.RegionSize/2;
|
||||
|
||||
int endX = (int)pRegionLocX * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2);
|
||||
int endY = (int)pRegionLocY * (int)Constants.RegionSize + dd + (int)(Constants.RegionSize/2);
|
||||
uint endX = Util.RegionToWorldLoc(pRegionLocX) + dd + Constants.RegionSize/2;
|
||||
uint endY = Util.RegionToWorldLoc(pRegionLocY) + dd + Constants.RegionSize/2;
|
||||
|
||||
List<GridRegion> neighbours =
|
||||
avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, startX, endX, startY, endY);
|
||||
avatar.Scene.GridService.GetRegionRange(m_regionInfo.ScopeID, (int)startX, (int)endX, (int)startY, (int)endY);
|
||||
|
||||
neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; });
|
||||
return neighbours;
|
||||
@@ -2190,10 +2359,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
List<GridRegion> neighbours
|
||||
= pScene.GridService.GetRegionRange(
|
||||
m_regionInfo.ScopeID,
|
||||
(int)swCorner.X * (int)Constants.RegionSize,
|
||||
(int)neCorner.X * (int)Constants.RegionSize,
|
||||
(int)swCorner.Y * (int)Constants.RegionSize,
|
||||
(int)neCorner.Y * (int)Constants.RegionSize);
|
||||
(int)Util.RegionToWorldLoc((uint)swCorner.X), (int)Util.RegionToWorldLoc((uint)neCorner.X),
|
||||
(int)Util.RegionToWorldLoc((uint)swCorner.Y), (int)Util.RegionToWorldLoc((uint)neCorner.Y) );
|
||||
|
||||
neighbours.RemoveAll(delegate(GridRegion r) { return r.RegionID == m_regionInfo.RegionID; });
|
||||
|
||||
@@ -2256,10 +2423,13 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
/// Move the given scene object into a new region depending on which region its absolute position has moved
|
||||
/// into.
|
||||
///
|
||||
/// This method locates the new region handle and offsets the prim position for the new region
|
||||
/// Using the objects new world location, ask the grid service for a the new region and adjust the prim
|
||||
/// position to be relative to the new region.
|
||||
/// </summary>
|
||||
/// <param name="attemptedPosition">the attempted out of region position of the scene object</param>
|
||||
/// <param name="grp">the scene object that we're crossing</param>
|
||||
/// <param name="attemptedPosition">the attempted out of region position of the scene object. This position is
|
||||
/// relative to the region the object currently is in.</param>
|
||||
/// <param name="silent">if 'true', the deletion of the client from the region is not broadcast to the clients</param>
|
||||
public void Cross(SceneObjectGroup grp, Vector3 attemptedPosition, bool silent)
|
||||
{
|
||||
if (grp == null)
|
||||
@@ -2285,208 +2455,49 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
return;
|
||||
}
|
||||
|
||||
int thisx = (int)scene.RegionInfo.RegionLocX;
|
||||
int thisy = (int)scene.RegionInfo.RegionLocY;
|
||||
Vector3 EastCross = new Vector3(0.1f, 0, 0);
|
||||
Vector3 WestCross = new Vector3(-0.1f, 0, 0);
|
||||
Vector3 NorthCross = new Vector3(0, 0.1f, 0);
|
||||
Vector3 SouthCross = new Vector3(0, -0.1f, 0);
|
||||
|
||||
|
||||
// use this if no borders were crossed!
|
||||
ulong newRegionHandle
|
||||
= Util.UIntsToLong((uint)((thisx) * Constants.RegionSize),
|
||||
(uint)((thisy) * Constants.RegionSize));
|
||||
|
||||
Vector3 pos = attemptedPosition;
|
||||
|
||||
int changeX = 1;
|
||||
int changeY = 1;
|
||||
|
||||
if (scene.TestBorderCross(attemptedPosition + WestCross, Cardinals.W))
|
||||
{
|
||||
if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
||||
{
|
||||
|
||||
Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
|
||||
|
||||
if (crossedBorderx.BorderLine.Z > 0)
|
||||
{
|
||||
pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
|
||||
changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
|
||||
}
|
||||
else
|
||||
pos.X = ((pos.X + Constants.RegionSize));
|
||||
|
||||
Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||
|
||||
if (crossedBordery.BorderLine.Z > 0)
|
||||
{
|
||||
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||
}
|
||||
else
|
||||
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||
|
||||
|
||||
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
|
||||
(uint)((thisy - changeY) * Constants.RegionSize));
|
||||
// x - 1
|
||||
// y - 1
|
||||
}
|
||||
else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
|
||||
{
|
||||
Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
|
||||
|
||||
if (crossedBorderx.BorderLine.Z > 0)
|
||||
{
|
||||
pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
|
||||
changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
|
||||
}
|
||||
else
|
||||
pos.X = ((pos.X + Constants.RegionSize));
|
||||
|
||||
|
||||
Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||
|
||||
if (crossedBordery.BorderLine.Z > 0)
|
||||
{
|
||||
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||
}
|
||||
else
|
||||
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
|
||||
(uint)((thisy + changeY) * Constants.RegionSize));
|
||||
// x - 1
|
||||
// y + 1
|
||||
}
|
||||
else
|
||||
{
|
||||
Border crossedBorderx = scene.GetCrossedBorder(attemptedPosition + WestCross, Cardinals.W);
|
||||
|
||||
if (crossedBorderx.BorderLine.Z > 0)
|
||||
{
|
||||
pos.X = ((pos.X + crossedBorderx.BorderLine.Z));
|
||||
changeX = (int)(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize);
|
||||
}
|
||||
else
|
||||
pos.X = ((pos.X + Constants.RegionSize));
|
||||
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)((thisx - changeX) * Constants.RegionSize),
|
||||
(uint)(thisy * Constants.RegionSize));
|
||||
// x - 1
|
||||
}
|
||||
}
|
||||
else if (scene.TestBorderCross(attemptedPosition + EastCross, Cardinals.E))
|
||||
{
|
||||
if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
||||
{
|
||||
|
||||
pos.X = ((pos.X - Constants.RegionSize));
|
||||
Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||
|
||||
if (crossedBordery.BorderLine.Z > 0)
|
||||
{
|
||||
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||
}
|
||||
else
|
||||
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||
|
||||
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
|
||||
(uint)((thisy - changeY) * Constants.RegionSize));
|
||||
// x + 1
|
||||
// y - 1
|
||||
}
|
||||
else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
|
||||
{
|
||||
pos.X = ((pos.X - Constants.RegionSize));
|
||||
pos.Y = ((pos.Y - Constants.RegionSize));
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
|
||||
(uint)((thisy + changeY) * Constants.RegionSize));
|
||||
// x + 1
|
||||
// y + 1
|
||||
}
|
||||
else
|
||||
{
|
||||
pos.X = ((pos.X - Constants.RegionSize));
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)((thisx + changeX) * Constants.RegionSize),
|
||||
(uint)(thisy * Constants.RegionSize));
|
||||
// x + 1
|
||||
}
|
||||
}
|
||||
else if (scene.TestBorderCross(attemptedPosition + SouthCross, Cardinals.S))
|
||||
{
|
||||
Border crossedBordery = scene.GetCrossedBorder(attemptedPosition + SouthCross, Cardinals.S);
|
||||
//(crossedBorderx.BorderLine.Z / (int)Constants.RegionSize)
|
||||
|
||||
if (crossedBordery.BorderLine.Z > 0)
|
||||
{
|
||||
pos.Y = ((pos.Y + crossedBordery.BorderLine.Z));
|
||||
changeY = (int)(crossedBordery.BorderLine.Z / (int)Constants.RegionSize);
|
||||
}
|
||||
else
|
||||
pos.Y = ((pos.Y + Constants.RegionSize));
|
||||
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy - changeY) * Constants.RegionSize));
|
||||
// y - 1
|
||||
}
|
||||
else if (scene.TestBorderCross(attemptedPosition + NorthCross, Cardinals.N))
|
||||
{
|
||||
|
||||
pos.Y = ((pos.Y - Constants.RegionSize));
|
||||
newRegionHandle
|
||||
= Util.UIntsToLong((uint)(thisx * Constants.RegionSize), (uint)((thisy + changeY) * Constants.RegionSize));
|
||||
// y + 1
|
||||
}
|
||||
|
||||
// Offset the positions for the new region across the border
|
||||
// Remember the old group position in case the region lookup fails so position can be restored.
|
||||
Vector3 oldGroupPosition = grp.RootPart.GroupPosition;
|
||||
|
||||
// If we fail to cross the border, then reset the position of the scene object on that border.
|
||||
uint x = 0, y = 0;
|
||||
Utils.LongToUInts(newRegionHandle, out x, out y);
|
||||
GridRegion destination = scene.GridService.GetRegionByPosition(scene.RegionInfo.ScopeID, (int)x, (int)y);
|
||||
// Compute the absolute position of the object.
|
||||
double objectWorldLocX = (double)scene.RegionInfo.WorldLocX + attemptedPosition.X;
|
||||
double objectWorldLocY = (double)scene.RegionInfo.WorldLocY + attemptedPosition.Y;
|
||||
|
||||
// Ask the grid service for the region that contains the passed address
|
||||
GridRegion destination = GetRegionContainingWorldLocation(scene.GridService, scene.RegionInfo.ScopeID,
|
||||
objectWorldLocX, objectWorldLocY);
|
||||
|
||||
Vector3 pos = Vector3.Zero;
|
||||
if (destination != null)
|
||||
{
|
||||
if (CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
|
||||
return; // we did it
|
||||
// Adjust the object's relative position from the old region (attemptedPosition)
|
||||
// to be relative to the new region (pos).
|
||||
pos = new Vector3( (float)(objectWorldLocX - (double)destination.RegionLocX),
|
||||
(float)(objectWorldLocY - (double)destination.RegionLocY),
|
||||
attemptedPosition.Z);
|
||||
}
|
||||
|
||||
// no one or failed lets go back and tell physics to go on
|
||||
oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 0.5f, (float)Constants.RegionSize - 0.5f);
|
||||
oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
|
||||
oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 0.5f, 4096.0f);
|
||||
if (destination == null || !CrossPrimGroupIntoNewRegion(destination, pos, grp, silent))
|
||||
{
|
||||
m_log.InfoFormat("[ENTITY TRANSFER MODULE] cross region transfer failed for object {0}", grp.UUID);
|
||||
|
||||
grp.AbsolutePosition = oldGroupPosition;
|
||||
grp.Velocity = Vector3.Zero;
|
||||
// We are going to move the object back to the old position so long as the old position
|
||||
// is in the region
|
||||
oldGroupPosition.X = Util.Clamp<float>(oldGroupPosition.X, 1.0f, (float)(scene.RegionInfo.RegionSizeX - 1));
|
||||
oldGroupPosition.Y = Util.Clamp<float>(oldGroupPosition.Y, 1.0f, (float)(scene.RegionInfo.RegionSizeY - 1));
|
||||
oldGroupPosition.Z = Util.Clamp<float>(oldGroupPosition.Z, 1.0f, Constants.RegionHeight);
|
||||
|
||||
if (grp.RootPart.PhysActor != null)
|
||||
grp.RootPart.PhysActor.CrossingFailure();
|
||||
grp.AbsolutePosition = oldGroupPosition;
|
||||
grp.Velocity = Vector3.Zero;
|
||||
if (grp.RootPart.PhysActor != null)
|
||||
grp.RootPart.PhysActor.CrossingFailure();
|
||||
|
||||
if (grp.RootPart.KeyframeMotion != null)
|
||||
grp.RootPart.KeyframeMotion.CrossingFailure();
|
||||
if (grp.RootPart.KeyframeMotion != null)
|
||||
grp.RootPart.KeyframeMotion.CrossingFailure();
|
||||
|
||||
grp.ScheduleGroupForFullUpdate();
|
||||
grp.ScheduleGroupForFullUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Move the given scene object into a new region
|
||||
/// </summary>
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
public class EntityTransferStateMachine
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly string LogHeader = "[ENTITY TRANSFER STATE MACHINE]";
|
||||
|
||||
/// <summary>
|
||||
/// If true then on a teleport, the source region waits for a callback from the destination region. If
|
||||
@@ -100,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
/// <returns>true if the agent was not already in transit, false if it was</returns>
|
||||
internal bool SetInTransit(UUID id)
|
||||
{
|
||||
m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id);
|
||||
lock (m_agentsInTransit)
|
||||
{
|
||||
if (!m_agentsInTransit.ContainsKey(id))
|
||||
@@ -121,6 +123,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
/// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
|
||||
internal bool UpdateInTransit(UUID id, AgentTransferState newState)
|
||||
{
|
||||
m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState);
|
||||
|
||||
bool transitionOkay = false;
|
||||
|
||||
// We don't want to throw an exception on cancel since this can come it at any time.
|
||||
@@ -193,6 +197,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
}
|
||||
else if (failIfNotOkay)
|
||||
{
|
||||
m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage);
|
||||
throw new Exception(failureMessage);
|
||||
}
|
||||
// else
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
@@ -462,7 +462,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||
|
||||
IUserAgentService userAgentService = new UserAgentServiceConnector(aCircuit.ServiceURLs["HomeURI"].ToString());
|
||||
Vector3 position = Vector3.UnitY, lookAt = Vector3.UnitY;
|
||||
GridRegion finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt);
|
||||
|
||||
GridRegion finalDestination = null;
|
||||
try
|
||||
{
|
||||
finalDestination = userAgentService.GetHomeRegion(aCircuit.AgentID, out position, out lookAt);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[HG ENTITY TRANSFER MODULE]: GetHomeRegion call failed ", e);
|
||||
}
|
||||
|
||||
if (finalDestination == null)
|
||||
{
|
||||
client.SendTeleportFailed("Your home region could not be found");
|
||||
|
||||
@@ -130,7 +130,17 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
||||
}
|
||||
|
||||
UserAgentServiceConnector uasConn = new UserAgentServiceConnector(uriStr);
|
||||
UUID userID = uasConn.GetUUID(names[0], names[1]);
|
||||
|
||||
UUID userID = UUID.Zero;
|
||||
try
|
||||
{
|
||||
userID = uasConn.GetUUID(names[0], names[1]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[USER MANAGEMENT MODULE]: GetUUID call failed ", e);
|
||||
}
|
||||
|
||||
if (!userID.Equals(UUID.Zero))
|
||||
{
|
||||
UserData ud = new UserData();
|
||||
|
||||
@@ -473,7 +473,16 @@ namespace OpenSim.Region.CoreModules.Framework.UserManagement
|
||||
// serverType, userdata.HomeURL, userID);
|
||||
|
||||
UserAgentServiceConnector uConn = new UserAgentServiceConnector(userdata.HomeURL);
|
||||
userdata.ServerURLs = uConn.GetServerURLs(userID);
|
||||
try
|
||||
{
|
||||
userdata.ServerURLs = uConn.GetServerURLs(userID);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[USER MANAGEMENT MODULE]: GetServerURLs call failed ", e);
|
||||
userdata.ServerURLs = new Dictionary<string, object>();
|
||||
}
|
||||
|
||||
if (userdata.ServerURLs != null && userdata.ServerURLs.ContainsKey(serverType) && userdata.ServerURLs[serverType] != null)
|
||||
return userdata.ServerURLs[serverType].ToString();
|
||||
}
|
||||
|
||||
@@ -126,7 +126,8 @@ namespace OpenSim.Region.CoreModules.Hypergrid
|
||||
foreach (MapBlockData b in mapBlocks)
|
||||
{
|
||||
b.Name = string.Empty;
|
||||
b.Access = 254; // means 'simulator is offline'. We need this because the viewer ignores 255's
|
||||
// Set 'simulator is offline'. We need this because the viewer ignores SimAccess.Unknown (255)
|
||||
b.Access = (byte)SimAccess.Down;
|
||||
}
|
||||
|
||||
m_log.DebugFormat("[HG MAP]: Resetting {0} blocks", mapBlocks.Count);
|
||||
|
||||
@@ -213,8 +213,8 @@ namespace OpenSim.Region.CoreModules.Scripting.EmailModules
|
||||
if (part != null)
|
||||
{
|
||||
ObjectRegionName = s.RegionInfo.RegionName;
|
||||
uint localX = (s.RegionInfo.RegionLocX * (int)Constants.RegionSize);
|
||||
uint localY = (s.RegionInfo.RegionLocY * (int)Constants.RegionSize);
|
||||
uint localX = s.RegionInfo.WorldLocX;
|
||||
uint localY = s.RegionInfo.WorldLocY;
|
||||
ObjectRegionName = ObjectRegionName + " (" + localX + ", " + localY + ")";
|
||||
return part;
|
||||
}
|
||||
|
||||
@@ -488,9 +488,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||
byte[] data = Util.UTF8.GetBytes(OutboundBody);
|
||||
|
||||
Request.ContentLength = data.Length;
|
||||
Stream bstream = Request.GetRequestStream();
|
||||
bstream.Write(data, 0, data.Length);
|
||||
bstream.Close();
|
||||
using (Stream bstream = Request.GetRequestStream())
|
||||
bstream.Write(data, 0, data.Length);
|
||||
}
|
||||
|
||||
try
|
||||
@@ -584,4 +583,4 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
|
||||
Request.Abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(
|
||||
MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[LOCAL GRID SERVICE CONNECTOR]";
|
||||
|
||||
private IGridService m_GridService;
|
||||
private Dictionary<UUID, RegionCache> m_LocalCache = new Dictionary<UUID, RegionCache>();
|
||||
@@ -56,12 +57,12 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
|
||||
public LocalGridServicesConnector()
|
||||
{
|
||||
m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector no parms.");
|
||||
m_log.DebugFormat("{0} LocalGridServicesConnector no parms.", LogHeader);
|
||||
}
|
||||
|
||||
public LocalGridServicesConnector(IConfigSource source)
|
||||
{
|
||||
m_log.Debug("[LOCAL GRID SERVICE CONNECTOR]: LocalGridServicesConnector instantiated directly.");
|
||||
m_log.DebugFormat("{0} LocalGridServicesConnector instantiated directly.", LogHeader);
|
||||
InitialiseService(source);
|
||||
}
|
||||
|
||||
@@ -192,6 +193,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
return m_GridService.GetRegionByUUID(scopeID, regionID);
|
||||
}
|
||||
|
||||
// Get a region given its base coordinates.
|
||||
// NOTE: this is NOT 'get a region by some point in the region'. The coordinate MUST
|
||||
// be the base coordinate of the region.
|
||||
public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
|
||||
{
|
||||
GridRegion region = null;
|
||||
@@ -206,13 +210,25 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
region = rcache.GetRegionByPosition(x, y);
|
||||
if (region != null)
|
||||
{
|
||||
return region;
|
||||
// m_log.DebugFormat("{0} GetRegionByPosition. Found region {1} in cache. Pos=<{2},{3}>",
|
||||
// LogHeader, region.RegionName, x, y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then try on this sim (may be a lookup in DB if this is using MySql).
|
||||
return m_GridService.GetRegionByPosition(scopeID, x, y);
|
||||
if (region == null)
|
||||
{
|
||||
region = m_GridService.GetRegionByPosition(scopeID, x, y);
|
||||
if (region == null)
|
||||
m_log.DebugFormat("{0} GetRegionByPosition. Region not found by grid service. Pos=<{1},{2}>",
|
||||
LogHeader, x, y);
|
||||
else
|
||||
m_log.DebugFormat("{0} GetRegionByPosition. Requested region {1} from grid service. Pos=<{2},{3}>",
|
||||
LogHeader, region.RegionName, x, y);
|
||||
}
|
||||
return region;
|
||||
}
|
||||
|
||||
public GridRegion GetRegionByName(UUID scopeID, string regionName)
|
||||
@@ -268,7 +284,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
caps.AppendFormat("*** Neighbours of {0} ({1}) ***\n", kvp.Value.RegionName, kvp.Key);
|
||||
List<GridRegion> regions = kvp.Value.GetNeighbours();
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -82,11 +82,16 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
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)
|
||||
{
|
||||
uint xsnap = (uint)(x / 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))
|
||||
return m_neighbours[handle];
|
||||
|
||||
@@ -186,10 +186,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
|
||||
return rinfo;
|
||||
}
|
||||
|
||||
// Get a region given its base world 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 coordinates are world coords (meters), NOT region units.
|
||||
public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
|
||||
{
|
||||
bool inCache = false;
|
||||
GridRegion rinfo = m_RegionInfoCache.Get(scopeID, Util.UIntsToLong((uint)x, (uint)y), out inCache);
|
||||
GridRegion rinfo = m_RegionInfoCache.Get(scopeID, Util.RegionWorldLocToHandle((uint)x, (uint)y), out inCache);
|
||||
if (inCache)
|
||||
return rinfo;
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ using log4net.Config;
|
||||
using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
@@ -141,7 +142,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid.Tests
|
||||
Assert.IsNotNull(result, "Retrieved GetRegionByUUID is null");
|
||||
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.That(result.RegionLocX, Is.EqualTo(1000 * (int)Constants.RegionSize), "Retrieved region's position does not match");
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[MAP IMAGE SERVICE MODULE]";
|
||||
|
||||
private bool m_enabled = false;
|
||||
private IMapImageService m_MapService;
|
||||
@@ -192,42 +193,85 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage
|
||||
///</summary>
|
||||
private 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);
|
||||
string regionName = scene.RegionInfo.RegionName;
|
||||
|
||||
// Create a JPG map tile and upload it to the AddMapTile API
|
||||
byte[] jpgData = Utils.EmptyBytes;
|
||||
IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// is no static map tile.
|
||||
if (mapTile == null)
|
||||
return;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
if (mapTile != null)
|
||||
{
|
||||
mapTile.Save(stream, ImageFormat.Jpeg);
|
||||
jpgData = stream.ToArray();
|
||||
// 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.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY,
|
||||
scene.RegionInfo.RegionName);
|
||||
}
|
||||
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.RegionInfo.RegionLocX + (xx / Constants.RegionSize),
|
||||
scene.RegionInfo.RegionLocY + (yy / Constants.RegionSize),
|
||||
regionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("{0} Tile image generation failed", LogHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (jpgData == Utils.EmptyBytes)
|
||||
private void ConvertAndUploadMaptile(Image tileImage, uint locX, uint locY, string regionName)
|
||||
{
|
||||
byte[] jpgData = Utils.EmptyBytes;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
m_log.WarnFormat("[MAP IMAGE SERVICE MODULE]: Tile image generation failed");
|
||||
return;
|
||||
tileImage.Save(stream, ImageFormat.Jpeg);
|
||||
jpgData = stream.ToArray();
|
||||
}
|
||||
|
||||
string reason = string.Empty;
|
||||
if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, out reason))
|
||||
if (jpgData != Utils.EmptyBytes)
|
||||
{
|
||||
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);
|
||||
string reason = string.Empty;
|
||||
if (!m_MapService.AddMapTile((int)locX, (int)locY, jpgData, out reason))
|
||||
{
|
||||
m_log.DebugFormat("{0} Unable to upload tile image for {1} at {2}-{3}: {4}", LogHeader,
|
||||
regionName, locX, locY, reason);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat("{0} Tile image generation failed for region {1}", LogHeader, regionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,14 +125,14 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Neighbour
|
||||
public OpenSim.Services.Interfaces.GridRegion HelloNeighbour(ulong regionHandle, RegionInfo thisRegion)
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(regionHandle, out x, out y);
|
||||
Util.RegionHandleToRegionLoc(regionHandle, out x, out y);
|
||||
|
||||
foreach (Scene s in m_Scenes)
|
||||
{
|
||||
if (s.RegionInfo.RegionHandle == regionHandle)
|
||||
{
|
||||
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");
|
||||
return s.IncomingHelloNeighbour(thisRegion);
|
||||
|
||||
@@ -96,14 +96,42 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
/// <value>
|
||||
/// Should the archive being loaded be merged with what is already on the region?
|
||||
/// Merging usually suppresses terrain and parcel loading
|
||||
/// </value>
|
||||
protected bool m_merge;
|
||||
|
||||
/// <value>
|
||||
/// If true, force the loading of terrain from the oar file
|
||||
/// </value>
|
||||
protected bool m_forceTerrain;
|
||||
|
||||
/// <value>
|
||||
/// If true, force the loading of parcels from the oar file
|
||||
/// </value>
|
||||
protected bool m_forceParcels;
|
||||
|
||||
/// <value>
|
||||
/// Should we ignore any assets when reloading the archive?
|
||||
/// </value>
|
||||
protected bool m_skipAssets;
|
||||
|
||||
/// <value>
|
||||
/// Displacement added to each object as it is added to the world
|
||||
/// </value>
|
||||
protected Vector3 m_displacement = Vector3.Zero;
|
||||
|
||||
/// <value>
|
||||
/// Rotation (in radians) to apply to the objects as they are loaded.
|
||||
/// </value>
|
||||
protected float m_rotation = 0f;
|
||||
|
||||
/// <value>
|
||||
/// Center around which to apply the rotation relative to the origional oar position
|
||||
/// </value>
|
||||
protected Vector3 m_rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0f);
|
||||
|
||||
protected bool m_noObjects = false;
|
||||
|
||||
/// <summary>
|
||||
/// Used to cache lookups for valid uuids.
|
||||
/// </summary>
|
||||
@@ -132,7 +160,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
private IAssetService m_assetService = null;
|
||||
|
||||
|
||||
public ArchiveReadRequest(Scene scene, string loadPath, bool merge, bool skipAssets, Guid requestId)
|
||||
public ArchiveReadRequest(Scene scene, string loadPath, Guid requestId, Dictionary<string,object>options)
|
||||
{
|
||||
m_rootScene = scene;
|
||||
|
||||
@@ -150,9 +178,16 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
}
|
||||
|
||||
m_errorMessage = String.Empty;
|
||||
m_merge = merge;
|
||||
m_skipAssets = skipAssets;
|
||||
m_merge = options.ContainsKey("merge");
|
||||
m_forceTerrain = options.ContainsKey("force-terrain");
|
||||
m_forceParcels = options.ContainsKey("force-parcels");
|
||||
m_noObjects = options.ContainsKey("no-objects");
|
||||
m_skipAssets = options.ContainsKey("skipAssets");
|
||||
m_requestId = requestId;
|
||||
m_displacement = options.ContainsKey("displacement") ? (Vector3)options["displacement"] : Vector3.Zero;
|
||||
m_rotation = options.ContainsKey("rotation") ? (float)options["rotation"] : 0f;
|
||||
m_rotationCenter = options.ContainsKey("rotation-center") ? (Vector3)options["rotation-center"]
|
||||
: new Vector3(scene.RegionInfo.RegionSizeX / 2f, scene.RegionInfo.RegionSizeY / 2f, 0f);
|
||||
|
||||
// Zero can never be a valid user id
|
||||
m_validUserUuids[UUID.Zero] = false;
|
||||
@@ -161,13 +196,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
m_assetService = m_rootScene.AssetService;
|
||||
}
|
||||
|
||||
public ArchiveReadRequest(Scene scene, Stream loadStream, bool merge, bool skipAssets, Guid requestId)
|
||||
public ArchiveReadRequest(Scene scene, Stream loadStream, Guid requestId, Dictionary<string, object>options)
|
||||
{
|
||||
m_rootScene = scene;
|
||||
m_loadPath = null;
|
||||
m_loadStream = loadStream;
|
||||
m_merge = merge;
|
||||
m_skipAssets = skipAssets;
|
||||
m_skipAssets = options.ContainsKey("skipAssets");
|
||||
m_merge = options.ContainsKey("merge");
|
||||
m_requestId = requestId;
|
||||
|
||||
// Zero can never be a valid user id
|
||||
@@ -229,7 +264,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
// Process the file
|
||||
|
||||
if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH))
|
||||
if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH) && !m_noObjects)
|
||||
{
|
||||
sceneContext.SerialisedSceneObjects.Add(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
@@ -243,7 +278,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
if ((successfulAssetRestores + failedAssetRestores) % 250 == 0)
|
||||
m_log.Debug("[ARCHIVER]: Loaded " + successfulAssetRestores + " assets and failed to load " + failedAssetRestores + " assets...");
|
||||
}
|
||||
else if (!m_merge && filePath.StartsWith(ArchiveConstants.TERRAINS_PATH))
|
||||
else if (filePath.StartsWith(ArchiveConstants.TERRAINS_PATH) && (!m_merge || m_forceTerrain))
|
||||
{
|
||||
LoadTerrain(scene, filePath, data);
|
||||
}
|
||||
@@ -251,7 +286,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
LoadRegionSettings(scene, filePath, data, dearchivedScenes);
|
||||
}
|
||||
else if (!m_merge && filePath.StartsWith(ArchiveConstants.LANDDATA_PATH))
|
||||
else if (filePath.StartsWith(ArchiveConstants.LANDDATA_PATH) && (!m_merge || m_forceParcels))
|
||||
{
|
||||
sceneContext.SerialisedParcels.Add(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
@@ -422,6 +457,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
// Reload serialized prims
|
||||
m_log.InfoFormat("[ARCHIVER]: Loading {0} scene objects. Please wait.", serialisedSceneObjects.Count);
|
||||
|
||||
OpenMetaverse.Quaternion rot = OpenMetaverse.Quaternion.CreateFromAxisAngle(0, 0, 1, m_rotation);
|
||||
|
||||
UUID oldTelehubUUID = scene.RegionInfo.RegionSettings.TelehubObject;
|
||||
|
||||
IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
|
||||
@@ -445,6 +482,32 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
SceneObjectGroup sceneObject = serialiser.DeserializeGroupFromXml2(serialisedSceneObject);
|
||||
|
||||
// Happily this does not do much to the object since it hasn't been added to the scene yet
|
||||
if (sceneObject.AttachmentPoint == 0)
|
||||
{
|
||||
if (m_displacement != Vector3.Zero || m_rotation != 0f)
|
||||
{
|
||||
Vector3 pos = sceneObject.AbsolutePosition;
|
||||
if (m_rotation != 0f)
|
||||
{
|
||||
// Rotate the object
|
||||
sceneObject.RootPart.RotationOffset = rot * sceneObject.GroupRotation;
|
||||
// Get object position relative to rotation axis
|
||||
Vector3 offset = pos - m_rotationCenter;
|
||||
// Rotate the object position
|
||||
offset *= rot;
|
||||
// Restore the object position back to relative to the region
|
||||
pos = m_rotationCenter + offset;
|
||||
}
|
||||
if (m_displacement != Vector3.Zero)
|
||||
{
|
||||
pos += m_displacement;
|
||||
}
|
||||
sceneObject.AbsolutePosition = pos;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool isTelehub = (sceneObject.UUID == oldTelehubUUID) && (oldTelehubUUID != UUID.Zero);
|
||||
|
||||
// For now, give all incoming scene objects new uuids. This will allow scenes to be cloned
|
||||
@@ -549,6 +612,13 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
foreach (string serialisedParcel in serialisedParcels)
|
||||
{
|
||||
LandData parcel = LandDataSerializer.Deserialize(serialisedParcel);
|
||||
|
||||
if (m_displacement != Vector3.Zero)
|
||||
{
|
||||
Vector3 parcelDisp = new Vector3(m_displacement.X, m_displacement.Y, 0f);
|
||||
parcel.AABBMin += parcelDisp;
|
||||
parcel.AABBMax += parcelDisp;
|
||||
}
|
||||
|
||||
// Validate User and Group UUID's
|
||||
|
||||
@@ -809,7 +879,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
|
||||
|
||||
MemoryStream ms = new MemoryStream(data);
|
||||
terrainModule.LoadFromStream(terrainPath, ms);
|
||||
if (m_displacement != Vector3.Zero || m_rotation != 0f)
|
||||
{
|
||||
Vector2 rotationCenter = new Vector2(m_rotationCenter.X, m_rotationCenter.Y);
|
||||
terrainModule.LoadFromStream(terrainPath, m_displacement, m_rotation, rotationCenter, ms);
|
||||
}
|
||||
else
|
||||
{
|
||||
terrainModule.LoadFromStream(terrainPath, ms);
|
||||
}
|
||||
ms.Close();
|
||||
|
||||
m_log.DebugFormat("[ARCHIVER]: Restored terrain {0}", terrainPath);
|
||||
|
||||
@@ -533,7 +533,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
if (isMegaregion)
|
||||
size = rcMod.GetSizeOfMegaregion(scene.RegionInfo.RegionID);
|
||||
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("size_in_meters", string.Format("{0},{1}", size.X, size.Y));
|
||||
|
||||
@@ -33,11 +33,14 @@ using log4net;
|
||||
using NDesk.Options;
|
||||
using Nini.Config;
|
||||
using Mono.Addins;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
/// <summary>
|
||||
@@ -101,9 +104,59 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
{
|
||||
bool mergeOar = false;
|
||||
bool skipAssets = false;
|
||||
bool forceTerrain = false;
|
||||
bool forceParcels = false;
|
||||
bool noObjects = false;
|
||||
Vector3 displacement = new Vector3(0f, 0f, 0f);
|
||||
float rotation = 0f;
|
||||
Vector3 rotationCenter = new Vector3(Constants.RegionSize / 2f, Constants.RegionSize / 2f, 0);
|
||||
|
||||
OptionSet options = new OptionSet().Add("m|merge", delegate (string v) { mergeOar = v != null; });
|
||||
options.Add("s|skip-assets", delegate (string v) { skipAssets = v != null; });
|
||||
OptionSet options = new OptionSet();
|
||||
options.Add("m|merge", delegate (string v) { mergeOar = (v != null); });
|
||||
options.Add("s|skip-assets", delegate (string v) { skipAssets = (v != null); });
|
||||
options.Add("force-terrain", delegate (string v) { forceTerrain = (v != null); });
|
||||
options.Add("forceterrain", delegate (string v) { forceTerrain = (v != null); }); // downward compatibility
|
||||
options.Add("force-parcels", delegate (string v) { forceParcels = (v != null); });
|
||||
options.Add("forceparcels", delegate (string v) { forceParcels = (v != null); }); // downward compatibility
|
||||
options.Add("no-objects", delegate (string v) { noObjects = (v != null); });
|
||||
options.Add("displacement=", delegate (string v) {
|
||||
try
|
||||
{
|
||||
displacement = v == null ? Vector3.Zero : Vector3.Parse(v);
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing displacement");
|
||||
m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --displacement \"<128,128,0>\"");
|
||||
return;
|
||||
}
|
||||
});
|
||||
options.Add("rotation=", delegate (string v) {
|
||||
try
|
||||
{
|
||||
rotation = v == null ? 0f : float.Parse(v);
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation");
|
||||
m_log.ErrorFormat("[ARCHIVER MODULE] Must be an angle in degrees between -360 and +360: --rotation 45");
|
||||
return;
|
||||
}
|
||||
// Convert to radians for internals
|
||||
rotation = Util.Clamp<float>(rotation, -359f, 359f) / 180f * (float)Math.PI;
|
||||
});
|
||||
options.Add("rotation-center=", delegate (string v) {
|
||||
try
|
||||
{
|
||||
rotationCenter = v == null ? Vector3.Zero : Vector3.Parse(v);
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_log.ErrorFormat("[ARCHIVER MODULE] failure parsing rotation displacement");
|
||||
m_log.ErrorFormat("[ARCHIVER MODULE] Must be represented as vector3: --rotation-center \"<128,128,0>\"");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// Send a message to the region ready module
|
||||
/* bluewall* Disable this for the time being
|
||||
@@ -122,13 +175,23 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
// foreach (string param in mainParams)
|
||||
// m_log.DebugFormat("GOT PARAM [{0}]", param);
|
||||
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
|
||||
if (mergeOar) archiveOptions.Add("merge", null);
|
||||
if (skipAssets) archiveOptions.Add("skipAssets", null);
|
||||
if (forceTerrain) archiveOptions.Add("force-terrain", null);
|
||||
if (forceParcels) archiveOptions.Add("force-parcels", null);
|
||||
if (noObjects) archiveOptions.Add("no-objects", null);
|
||||
archiveOptions.Add("displacement", displacement);
|
||||
archiveOptions.Add("rotation", rotation);
|
||||
archiveOptions.Add("rotation-center", rotationCenter);
|
||||
|
||||
if (mainParams.Count > 2)
|
||||
{
|
||||
DearchiveRegion(mainParams[2], mergeOar, skipAssets, Guid.Empty);
|
||||
DearchiveRegion(mainParams[2], Guid.Empty, archiveOptions);
|
||||
}
|
||||
else
|
||||
{
|
||||
DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, mergeOar, skipAssets, Guid.Empty);
|
||||
DearchiveRegion(DEFAULT_OAR_BACKUP_FILENAME, Guid.Empty, archiveOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,25 +261,27 @@ namespace OpenSim.Region.CoreModules.World.Archiver
|
||||
|
||||
public void DearchiveRegion(string loadPath)
|
||||
{
|
||||
DearchiveRegion(loadPath, false, false, Guid.Empty);
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
|
||||
DearchiveRegion(loadPath, Guid.Empty, archiveOptions);
|
||||
}
|
||||
|
||||
public void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId)
|
||||
public void DearchiveRegion(string loadPath, Guid requestId, Dictionary<string,object> options)
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[ARCHIVER]: Loading archive to region {0} from {1}", Scene.RegionInfo.RegionName, loadPath);
|
||||
|
||||
new ArchiveReadRequest(Scene, loadPath, merge, skipAssets, requestId).DearchiveRegion();
|
||||
new ArchiveReadRequest(Scene, loadPath, requestId, options).DearchiveRegion();
|
||||
}
|
||||
|
||||
public void DearchiveRegion(Stream loadStream)
|
||||
{
|
||||
DearchiveRegion(loadStream, false, false, Guid.Empty);
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
|
||||
DearchiveRegion(loadStream, Guid.Empty, archiveOptions);
|
||||
}
|
||||
|
||||
public void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId)
|
||||
public void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary<string, object> options)
|
||||
{
|
||||
new ArchiveReadRequest(Scene, loadStream, merge, skipAssets, requestId).DearchiveRegion();
|
||||
new ArchiveReadRequest(Scene, loadStream, requestId, options).DearchiveRegion();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -224,8 +224,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
|
||||
byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
|
||||
Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
|
||||
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
|
||||
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
|
||||
arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
|
||||
|
||||
Assert.That(arr.ControlFileLoaded, Is.True);
|
||||
@@ -308,8 +309,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
|
||||
byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
|
||||
Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
|
||||
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
|
||||
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
|
||||
arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
|
||||
|
||||
Assert.That(arr.ControlFileLoaded, Is.True);
|
||||
@@ -577,7 +579,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
ArchiveConstants.CONTROL_FILE_PATH,
|
||||
new ArchiveWriteRequest(m_scene, (Stream)null, Guid.Empty).CreateControlFile(new ArchiveScenesGroup()));
|
||||
|
||||
LandObject lo = new LandObject(groupID, true, null);
|
||||
LandObject lo = new LandObject(groupID, true, m_scene);
|
||||
lo.SetLandBitmap(lo.BasicFullRegionLandBitmap());
|
||||
LandData ld = lo.LandData;
|
||||
ld.GlobalID = landID;
|
||||
@@ -752,7 +754,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
byte[] archive = archiveWriteStream.ToArray();
|
||||
MemoryStream archiveReadStream = new MemoryStream(archive);
|
||||
|
||||
m_archiverModule.DearchiveRegion(archiveReadStream, true, false, Guid.Empty);
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
|
||||
archiveOptions.Add("merge", null);
|
||||
m_archiverModule.DearchiveRegion(archiveReadStream, Guid.Empty, archiveOptions);
|
||||
|
||||
SceneObjectPart object1Existing = m_scene.GetSceneObjectPart(part1.Name);
|
||||
Assert.That(object1Existing, Is.Not.Null, "object1 was not present after merge");
|
||||
@@ -860,7 +864,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests
|
||||
byte[] data = tar.ReadEntry(out filePath, out tarEntryType);
|
||||
Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH));
|
||||
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty);
|
||||
Dictionary<string, object> archiveOptions = new Dictionary<string, object>();
|
||||
ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, Guid.Empty, archiveOptions);
|
||||
arr.LoadControlFile(filePath, data, new DearchiveScenesInfo());
|
||||
|
||||
Assert.That(arr.ControlFileLoaded, Is.True);
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
public class LandManagementModule : INonSharedRegionModule
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
|
||||
|
||||
private static readonly string remoteParcelRequestPath = "0009/";
|
||||
|
||||
@@ -74,15 +75,11 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
protected IPrimCountModule m_primCountModule;
|
||||
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>
|
||||
/// Local land ids at specified region co-ordinates (region size / 4)
|
||||
/// </value>
|
||||
private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax];
|
||||
private int[,] m_landIDList;
|
||||
private const int landUnit = 4;
|
||||
|
||||
/// <value>
|
||||
/// Land objects keyed by local id
|
||||
@@ -115,6 +112,8 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
public void AddRegion(Scene scene)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
|
||||
|
||||
m_landIDList.Initialize();
|
||||
landChannel = new LandChannel(scene, this);
|
||||
|
||||
@@ -297,6 +296,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
{
|
||||
m_landList.Clear();
|
||||
m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
|
||||
m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
|
||||
m_landIDList.Initialize();
|
||||
}
|
||||
}
|
||||
@@ -311,7 +311,8 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
"[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
|
||||
|
||||
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.ClaimDate = Util.UnixTimeSinceEpoch();
|
||||
|
||||
@@ -438,8 +439,8 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
|
||||
public void SendLandUpdate(ScenePresence avatar, bool force)
|
||||
{
|
||||
ILandObject over = GetLandObject((int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
|
||||
(int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
|
||||
ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
|
||||
(int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
|
||||
|
||||
if (over != null)
|
||||
{
|
||||
@@ -605,17 +606,29 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
new_land.LandData.LocalID = newLandLocalID;
|
||||
|
||||
bool[,] landBitmap = new_land.GetLandBitmap();
|
||||
for (int x = 0; x < landArrayMax; x++)
|
||||
// m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). newLocalID={3}",
|
||||
// LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), newLandLocalID);
|
||||
|
||||
if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1))
|
||||
{
|
||||
for (int y = 0; y < landArrayMax; y++)
|
||||
// Going to variable sized regions can cause mismatches
|
||||
m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})",
|
||||
LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1) );
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int x = 0; x < landBitmap.GetLength(0); x++)
|
||||
{
|
||||
if (landBitmap[x, y])
|
||||
for (int y = 0; y < landBitmap.GetLength(1); y++)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
|
||||
// new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
|
||||
|
||||
m_landIDList[x, y] = newLandLocalID;
|
||||
if (landBitmap[x, y])
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
|
||||
// new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
|
||||
|
||||
m_landIDList[x, y] = newLandLocalID;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,9 +650,9 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
ILandObject land;
|
||||
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)
|
||||
{
|
||||
@@ -691,9 +704,9 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
bool[,] landBitmapSlave = slave.GetLandBitmap();
|
||||
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])
|
||||
{
|
||||
@@ -727,23 +740,28 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
/// <returns>Land object at the point supplied</returns>
|
||||
public ILandObject GetLandObject(float x_float, float y_float)
|
||||
{
|
||||
return GetLandObject((int)x_float, (int)y_float, true /* returnNullIfLandObjectNotFound */);
|
||||
/*
|
||||
int x;
|
||||
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;
|
||||
|
||||
try
|
||||
{
|
||||
x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0));
|
||||
y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0));
|
||||
x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit));
|
||||
y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit));
|
||||
}
|
||||
catch (OverflowException)
|
||||
{
|
||||
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;
|
||||
}
|
||||
@@ -759,38 +777,122 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
// m_log.DebugFormat(
|
||||
// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}",
|
||||
// x, y, m_scene.RegionInfo.RegionName);
|
||||
|
||||
if (m_landList.ContainsKey(m_landIDList[x, y]))
|
||||
return m_landList[m_landIDList[x, y]];
|
||||
|
||||
try
|
||||
{
|
||||
if (m_landList.ContainsKey(m_landIDList[x, y]))
|
||||
return m_landList[m_landIDList[x, y]];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("{0} GetLandObject exception. x={1}, y={2}, m_landIDList.len=({3},{4})",
|
||||
LogHeader, x, y, m_landIDList.GetLength(0), m_landIDList.GetLength(1));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Public entry.
|
||||
// Throws exception if land object is not found
|
||||
public ILandObject GetLandObject(int x, int y)
|
||||
{
|
||||
if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0)
|
||||
return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */);
|
||||
}
|
||||
|
||||
// Given a region position, return the parcel land object for that location
|
||||
private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectNotFound)
|
||||
{
|
||||
ILandObject ret = null;
|
||||
|
||||
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
|
||||
// they happen every time at border crossings
|
||||
throw new Exception("Error: Parcel not found at point " + x + ", " + y);
|
||||
if (returnNullIfLandObjectNotFound)
|
||||
return null;
|
||||
else
|
||||
throw new Exception(
|
||||
String.Format("{0} GetLandObject for non-existant position. Region={1}, pos=<{2},{3}",
|
||||
LogHeader, m_scene.RegionInfo.RegionName, x, y)
|
||||
);
|
||||
}
|
||||
|
||||
lock (m_landIDList)
|
||||
{
|
||||
try
|
||||
{
|
||||
return m_landList[m_landIDList[x / 4, y / 4]];
|
||||
int landID = m_landIDList[x / landUnit, y / landUnit];
|
||||
if (landID == 0)
|
||||
{
|
||||
// Zero is the uninitialized value saying there is no parcel for this location.
|
||||
// This sometimes happens when terrain is resized.
|
||||
if (m_landList.Count == 1)
|
||||
{
|
||||
int onlyParcelID = 0;
|
||||
ILandObject onlyLandObject = null;
|
||||
foreach (KeyValuePair<int, ILandObject> kvp in m_landList)
|
||||
{
|
||||
onlyParcelID = kvp.Key;
|
||||
onlyLandObject = kvp.Value;
|
||||
break;
|
||||
}
|
||||
|
||||
// There is only one parcel. Grow it to fill all the unallocated spaces.
|
||||
for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
|
||||
for (int yy = 0; yy < m_landIDList.GetLength(1); yy++)
|
||||
if (m_landIDList[xx, yy] == 0)
|
||||
m_landIDList[xx, yy] = onlyParcelID;
|
||||
|
||||
onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID);
|
||||
landID = onlyParcelID;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There are several other parcels so we must create a new one for the unassigned space
|
||||
ILandObject newLand = new LandObject(UUID.Zero, false, m_scene);
|
||||
// Claim all the unclaimed "0" ids
|
||||
newLand.SetLandBitmap(CreateBitmapForID(0));
|
||||
newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
|
||||
AddLandObject(newLand);
|
||||
landID = m_lastLandLocalID;
|
||||
}
|
||||
}
|
||||
|
||||
ret = m_landList[landID];
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
// m_log.WarnFormat(
|
||||
// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
|
||||
// x, y, m_scene.RegionInfo.RegionName);
|
||||
|
||||
m_log.ErrorFormat(
|
||||
"{0} GetLandObject: Tried to retrieve land object from out of bounds co-ordinate ({1},{2}) in {3}. landListSize=({4},{5})",
|
||||
LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList.GetLength(0), m_landIDList.GetLength(1));
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"{0} GetLandObject: LandID not in landlist. XY=<{1},{2}> in {3}. landID[x,y]={4}",
|
||||
LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList[x/landUnit, y/landUnit]);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Create a 'parcel is here' bitmap for the parcel identified by the passed landID
|
||||
private bool[,] CreateBitmapForID(int landID)
|
||||
{
|
||||
bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)];
|
||||
ret.Initialize();
|
||||
|
||||
for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
|
||||
for (int yy = 0; yy < m_landIDList.GetLength(0); yy++)
|
||||
if (m_landIDList[xx, yy] == landID)
|
||||
ret[xx, yy] = true;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1053,85 +1155,93 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
|
||||
int byteArrayCount = 0;
|
||||
int sequenceID = 0;
|
||||
int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize;
|
||||
|
||||
|
||||
for (int y = 0; y < blockmeters; y++)
|
||||
// Layer data is in landUnit (4m) chunks
|
||||
for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); y++)
|
||||
{
|
||||
for (int x = 0; x < blockmeters; x++)
|
||||
for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); x++)
|
||||
{
|
||||
byte tempByte = 0; //This represents the byte for the current 4x4
|
||||
|
||||
ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4);
|
||||
|
||||
if (currentParcelBlock != null)
|
||||
byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * landUnit, y * landUnit), x, y, remote_client);
|
||||
byteArrayCount++;
|
||||
if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
|
||||
{
|
||||
if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId)
|
||||
{
|
||||
//Owner Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
|
||||
}
|
||||
else if (currentParcelBlock.LandData.SalePrice > 0 &&
|
||||
(currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
|
||||
currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
|
||||
{
|
||||
//Sale Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
|
||||
}
|
||||
else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
|
||||
{
|
||||
//Public Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Other Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
|
||||
}
|
||||
|
||||
//Now for border control
|
||||
|
||||
ILandObject westParcel = null;
|
||||
ILandObject southParcel = null;
|
||||
if (x > 0)
|
||||
{
|
||||
westParcel = GetLandObject((x - 1) * 4, y * 4);
|
||||
}
|
||||
if (y > 0)
|
||||
{
|
||||
southParcel = GetLandObject(x * 4, (y - 1) * 4);
|
||||
}
|
||||
|
||||
if (x == 0)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
|
||||
}
|
||||
else if (westParcel != null && westParcel != currentParcelBlock)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
|
||||
}
|
||||
|
||||
if (y == 0)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
|
||||
}
|
||||
else if (southParcel != null && southParcel != currentParcelBlock)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
|
||||
}
|
||||
|
||||
byteArray[byteArrayCount] = tempByte;
|
||||
byteArrayCount++;
|
||||
if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
|
||||
{
|
||||
remote_client.SendLandParcelOverlay(byteArray, sequenceID);
|
||||
byteArrayCount = 0;
|
||||
sequenceID++;
|
||||
byteArray = new byte[LAND_BLOCKS_PER_PACKET];
|
||||
}
|
||||
remote_client.SendLandParcelOverlay(byteArray, sequenceID);
|
||||
byteArrayCount = 0;
|
||||
sequenceID++;
|
||||
byteArray = new byte[LAND_BLOCKS_PER_PACKET];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (byteArrayCount != 0)
|
||||
{
|
||||
remote_client.SendLandParcelOverlay(byteArray, sequenceID);
|
||||
}
|
||||
}
|
||||
|
||||
private byte BuildLayerByte(ILandObject currentParcelBlock, int x, int y, IClientAPI remote_client)
|
||||
{
|
||||
byte tempByte = 0; //This represents the byte for the current 4x4
|
||||
|
||||
if (currentParcelBlock != null)
|
||||
{
|
||||
if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId)
|
||||
{
|
||||
//Owner Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
|
||||
}
|
||||
else if (currentParcelBlock.LandData.SalePrice > 0 &&
|
||||
(currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
|
||||
currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
|
||||
{
|
||||
//Sale Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
|
||||
}
|
||||
else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
|
||||
{
|
||||
//Public Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Other Flag
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
|
||||
}
|
||||
|
||||
//Now for border control
|
||||
|
||||
ILandObject westParcel = null;
|
||||
ILandObject southParcel = null;
|
||||
if (x > 0)
|
||||
{
|
||||
westParcel = GetLandObject((x - 1) * landUnit, y * landUnit);
|
||||
}
|
||||
if (y > 0)
|
||||
{
|
||||
southParcel = GetLandObject(x * landUnit, (y - 1) * landUnit);
|
||||
}
|
||||
|
||||
if (x == 0)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
|
||||
}
|
||||
else if (westParcel != null && westParcel != currentParcelBlock)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
|
||||
}
|
||||
|
||||
if (y == 0)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
|
||||
}
|
||||
else if (southParcel != null && southParcel != currentParcelBlock)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tempByte;
|
||||
}
|
||||
|
||||
public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
|
||||
@@ -1679,7 +1789,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
{
|
||||
// most likely still cached from building the extLandData entry
|
||||
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);
|
||||
}
|
||||
// we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
|
||||
@@ -2007,4 +2117,4 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
cdl.AddToStringBuilder(report);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
#region Member Variables
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
#pragma warning disable 0429
|
||||
private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
|
||||
#pragma warning restore 0429
|
||||
private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax];
|
||||
private static readonly string LogHeader = "[LAND OBJECT]";
|
||||
|
||||
private bool[,] m_landBitmap;
|
||||
private readonly int landUnit = 4;
|
||||
|
||||
private int m_lastSeqId = 0;
|
||||
|
||||
@@ -93,15 +93,17 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
{
|
||||
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])
|
||||
return new Vector3(x * 4, y * 4, 0);
|
||||
return new Vector3(x * landUnit, y * landUnit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>",
|
||||
LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
|
||||
return new Vector3(-1, -1, -1);
|
||||
}
|
||||
}
|
||||
@@ -110,17 +112,19 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
{
|
||||
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])
|
||||
{
|
||||
return new Vector3(x * 4 + 4, y * 4 + 4, 0);
|
||||
return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>",
|
||||
LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
|
||||
return new Vector3(-1, -1, -1);
|
||||
}
|
||||
}
|
||||
@@ -130,6 +134,11 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
|
||||
{
|
||||
m_scene = scene;
|
||||
if (m_scene == null)
|
||||
m_landBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
|
||||
else
|
||||
m_landBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
|
||||
|
||||
LandData.OwnerID = owner_id;
|
||||
if (is_group_owned)
|
||||
LandData.GroupID = owner_id;
|
||||
@@ -152,9 +161,9 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
/// <returns>Returns true if the piece of land contains the specified point</returns>
|
||||
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] == true);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -194,7 +203,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
else
|
||||
{
|
||||
// Normal Calculations
|
||||
int parcelMax = (int)(((float)LandData.Area / 65536.0f)
|
||||
int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
|
||||
* (float)m_scene.RegionInfo.ObjectCapacity
|
||||
* (float)m_scene.RegionInfo.RegionSettings.ObjectBonus);
|
||||
// TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL!
|
||||
@@ -211,7 +220,7 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
else
|
||||
{
|
||||
//Normal Calculations
|
||||
int simMax = (int)(((float)LandData.SimwideArea / 65536.0f)
|
||||
int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
|
||||
* (float)m_scene.RegionInfo.ObjectCapacity);
|
||||
return simMax;
|
||||
}
|
||||
@@ -224,7 +233,12 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
|
||||
{
|
||||
IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
|
||||
uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
|
||||
// uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
|
||||
uint regionFlags = (uint)(RegionFlags.PublicAllowed
|
||||
| RegionFlags.AllowDirectTeleport
|
||||
| RegionFlags.AllowParcelChanges
|
||||
| RegionFlags.AllowVoice );
|
||||
|
||||
if (estateModule != null)
|
||||
regionFlags = estateModule.GetRegionFlags();
|
||||
|
||||
@@ -559,8 +573,8 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
try
|
||||
{
|
||||
over =
|
||||
m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)),
|
||||
Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 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)m_scene.RegionInfo.RegionSizeY - 1)));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
@@ -707,15 +721,15 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
/// </summary>
|
||||
private void UpdateAABBAndAreaValues()
|
||||
{
|
||||
int min_x = 64;
|
||||
int min_y = 64;
|
||||
int min_x = 10000;
|
||||
int min_y = 10000;
|
||||
int max_x = 0;
|
||||
int max_y = 0;
|
||||
int tempArea = 0;
|
||||
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)
|
||||
{
|
||||
@@ -723,31 +737,31 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
if (min_y > y) min_y = y;
|
||||
if (max_x < x) max_x = x;
|
||||
if (max_y < y) max_y = y;
|
||||
tempArea += 16; //16sqm peice of land
|
||||
tempArea += landUnit * landUnit; //16sqm peice of land
|
||||
}
|
||||
}
|
||||
}
|
||||
int tx = min_x * 4;
|
||||
if (tx > ((int)Constants.RegionSize - 1))
|
||||
tx = ((int)Constants.RegionSize - 1);
|
||||
int ty = min_y * 4;
|
||||
if (ty > ((int)Constants.RegionSize - 1))
|
||||
ty = ((int)Constants.RegionSize - 1);
|
||||
int tx = min_x * landUnit;
|
||||
if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
|
||||
tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
|
||||
int ty = min_y * landUnit;
|
||||
if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
|
||||
ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
|
||||
|
||||
LandData.AABBMin =
|
||||
new Vector3(
|
||||
(float)(min_x * 4), (float)(min_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
|
||||
(float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
|
||||
|
||||
tx = max_x * 4;
|
||||
if (tx > ((int)Constants.RegionSize - 1))
|
||||
tx = ((int)Constants.RegionSize - 1);
|
||||
ty = max_y * 4;
|
||||
if (ty > ((int)Constants.RegionSize - 1))
|
||||
ty = ((int)Constants.RegionSize - 1);
|
||||
tx = max_x * landUnit;
|
||||
if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
|
||||
tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
|
||||
ty = max_y * landUnit;
|
||||
if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
|
||||
ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
|
||||
|
||||
LandData.AABBMax
|
||||
= new Vector3(
|
||||
(float)(max_x * 4), (float)(max_y * 4), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
|
||||
(float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
|
||||
|
||||
LandData.Area = tempArea;
|
||||
}
|
||||
@@ -759,20 +773,12 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
/// <summary>
|
||||
/// Sets the land's bitmap manually
|
||||
/// </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)
|
||||
{
|
||||
if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
|
||||
{
|
||||
//Throw an exception - The bitmap is not 64x64
|
||||
//throw new Exception("Error: Invalid Parcel Bitmap");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Valid: Lets set it
|
||||
LandBitmap = bitmap;
|
||||
ForceUpdateLandInfo();
|
||||
}
|
||||
LandBitmap = bitmap;
|
||||
// m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
|
||||
ForceUpdateLandInfo();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -786,15 +792,19 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
|
||||
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)
|
||||
{
|
||||
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();
|
||||
|
||||
// Fill the bitmap square area specified by state and end
|
||||
tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
|
||||
// m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>",
|
||||
// LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1));
|
||||
return tempBitmap;
|
||||
}
|
||||
|
||||
@@ -811,24 +821,20 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
|
||||
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;
|
||||
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
|
||||
&& y >= start_y / 4 && y < end_y / 4)
|
||||
if (x >= start_x / landUnit && x < end_x / landUnit
|
||||
&& y >= start_y / landUnit && y < end_y / landUnit)
|
||||
{
|
||||
land_bitmap[x, y] = set_value;
|
||||
}
|
||||
}
|
||||
}
|
||||
// m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>",
|
||||
// LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1));
|
||||
return land_bitmap;
|
||||
}
|
||||
|
||||
@@ -840,21 +846,21 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
/// <returns></returns>
|
||||
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("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps");
|
||||
}
|
||||
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");
|
||||
throw new Exception(
|
||||
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))
|
||||
);
|
||||
}
|
||||
|
||||
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])
|
||||
{
|
||||
@@ -871,13 +877,13 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
/// <returns></returns>
|
||||
private byte[] ConvertLandBitmapToBytes()
|
||||
{
|
||||
byte[] tempConvertArr = new byte[512];
|
||||
byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
|
||||
byte tempByte = 0;
|
||||
int x, y, i, byteNum = 0;
|
||||
i = 0;
|
||||
for (y = 0; y < 64; y++)
|
||||
int byteNum = 0;
|
||||
int i = 0;
|
||||
for (int y = 0; y < LandBitmap.GetLength(1); y++)
|
||||
{
|
||||
for (x = 0; x < 64; x++)
|
||||
for (int x = 0; x < LandBitmap.GetLength(0); x++)
|
||||
{
|
||||
tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8));
|
||||
if (i % 8 == 0)
|
||||
@@ -889,30 +895,52 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||
}
|
||||
}
|
||||
}
|
||||
// m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>",
|
||||
// LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
|
||||
return tempConvertArr;
|
||||
}
|
||||
|
||||
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();
|
||||
byte tempByte = 0;
|
||||
int x = 0, y = 0, i = 0, bitNum = 0;
|
||||
for (i = 0; i < 512; i++)
|
||||
// Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
|
||||
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];
|
||||
for (bitNum = 0; bitNum < 8; bitNum++)
|
||||
for (int bitNum = 0; bitNum < 8; bitNum++)
|
||||
{
|
||||
bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
|
||||
tempConvertMap[x, y] = bit;
|
||||
try
|
||||
{
|
||||
tempConvertMap[x, y] = bit;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
|
||||
}
|
||||
x++;
|
||||
if (x > 63)
|
||||
if (x >= xLen)
|
||||
{
|
||||
x = 0;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tempConvertMap;
|
||||
}
|
||||
|
||||
|
||||
@@ -102,7 +102,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
|
||||
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;
|
||||
//for (int i = 0; i < 10; ++i) {
|
||||
terrainRenderer.TerrainToBitmap(mapbmp);
|
||||
@@ -277,7 +278,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
private Bitmap DrawObjectVolume(Scene whichScene, Bitmap mapbmp)
|
||||
{
|
||||
int tc = 0;
|
||||
double[,] hm = whichScene.Heightmap.GetDoubles();
|
||||
ITerrainChannel hm = whichScene.Heightmap;
|
||||
tc = Environment.TickCount;
|
||||
m_log.Debug("[MAPTILE]: Generating Maptile Step 2: Object Volume Profile");
|
||||
EntityBase[] objs = whichScene.GetEntities();
|
||||
@@ -287,8 +288,6 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
|
||||
try
|
||||
{
|
||||
//SortedList<float, RectangleDrawStruct> z_sort = new SortedList<float, RectangleDrawStruct>();
|
||||
|
||||
lock (objs)
|
||||
{
|
||||
foreach (EntityBase obj in objs)
|
||||
@@ -298,7 +297,6 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
{
|
||||
SceneObjectGroup mapdot = (SceneObjectGroup)obj;
|
||||
Color mapdotspot = Color.Gray; // Default color when prim color is white
|
||||
|
||||
// Loop over prim in group
|
||||
foreach (SceneObjectPart part in mapdot.Parts)
|
||||
{
|
||||
@@ -363,7 +361,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
Vector3 pos = part.GetWorldPosition();
|
||||
|
||||
// skip prim outside of retion
|
||||
if (pos.X < 0f || pos.X > 256f || pos.Y < 0f || pos.Y > 256f)
|
||||
if (!m_scene.PositionIsInCurrentRegion(pos))
|
||||
continue;
|
||||
|
||||
// skip prim in non-finite position
|
||||
@@ -388,7 +386,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
Vector3 lscale = new Vector3(part.Shape.Scale.X, part.Shape.Scale.Y, part.Shape.Scale.Z);
|
||||
Vector3 scale = 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 rot = new Quaternion(llrot.W, llrot.X, llrot.Y, llrot.Z);
|
||||
@@ -406,12 +404,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
int mapdrawendY = (int)(pos.Y + scale.Y);
|
||||
|
||||
// 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)
|
||||
|| mapdrawstartY < 0 || mapdrawstartY > ((int)Constants.RegionSize - 1) || mapdrawendY < 0
|
||||
|| mapdrawendY > ((int)Constants.RegionSize - 1))
|
||||
if (mapdrawstartX < 0
|
||||
|| mapdrawstartX > (hm.Width - 1)
|
||||
|| mapdrawendX < 0
|
||||
|| mapdrawendX > (hm.Width - 1)
|
||||
|| mapdrawstartY < 0
|
||||
|| mapdrawstartY > (hm.Height - 1)
|
||||
|| mapdrawendY < 0
|
||||
|| mapdrawendY > (hm.Height - 1))
|
||||
continue;
|
||||
|
||||
#region obb face reconstruction part duex
|
||||
#region obb face reconstruction part duex
|
||||
Vector3[] vertexes = new Vector3[8];
|
||||
|
||||
// float[] distance = new float[6];
|
||||
@@ -515,7 +518,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
FaceD[2] = vertexes[7];
|
||||
FaceC[3] = vertexes[7];
|
||||
FaceD[5] = vertexes[7];
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
//int wy = 0;
|
||||
|
||||
@@ -530,11 +533,11 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
for (int i = 0; i < FaceA.Length; i++)
|
||||
{
|
||||
Point[] working = new Point[5];
|
||||
working[0] = project(FaceA[i], axPos);
|
||||
working[1] = project(FaceB[i], axPos);
|
||||
working[2] = project(FaceD[i], axPos);
|
||||
working[3] = project(FaceC[i], axPos);
|
||||
working[4] = project(FaceA[i], axPos);
|
||||
working[0] = project(hm, FaceA[i], axPos);
|
||||
working[1] = project(hm, FaceB[i], axPos);
|
||||
working[2] = project(hm, FaceD[i], axPos);
|
||||
working[3] = project(hm, FaceC[i], axPos);
|
||||
working[4] = project(hm, FaceA[i], axPos);
|
||||
|
||||
face workingface = new face();
|
||||
workingface.pts = working;
|
||||
@@ -546,27 +549,25 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
z_localIDs.Add(part.LocalId);
|
||||
z_sortheights.Add(pos.Z);
|
||||
|
||||
//for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
|
||||
//{
|
||||
//for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
|
||||
//{
|
||||
//m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
|
||||
//try
|
||||
//{
|
||||
// Remember, flip the y!
|
||||
// mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
|
||||
//}
|
||||
//catch (ArgumentException)
|
||||
//{
|
||||
// breakYN = true;
|
||||
//}
|
||||
|
||||
//if (breakYN)
|
||||
// break;
|
||||
//}
|
||||
|
||||
//if (breakYN)
|
||||
// break;
|
||||
// for (int wx = mapdrawstartX; wx < mapdrawendX; wx++)
|
||||
// {
|
||||
// for (wy = mapdrawstartY; wy < mapdrawendY; wy++)
|
||||
// {
|
||||
// m_log.InfoFormat("[MAPDEBUG]: {0},{1}({2})", wx, (255 - wy),wy);
|
||||
// try
|
||||
// {
|
||||
// // Remember, flip the y!
|
||||
// mapbmp.SetPixel(wx, (255 - wy), mapdotspot);
|
||||
// }
|
||||
// catch (ArgumentException)
|
||||
// {
|
||||
// breakYN = true;
|
||||
// }
|
||||
// }
|
||||
// if (breakYN)
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
} // Object is within 256m Z of terrain
|
||||
} // object is at least a meter wide
|
||||
@@ -609,17 +610,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
return mapbmp;
|
||||
}
|
||||
|
||||
private Point project(Vector3 point3d, Vector3 originpos)
|
||||
private Point project(ITerrainChannel hm, Vector3 point3d, Vector3 originpos)
|
||||
{
|
||||
Point returnpt = new Point();
|
||||
//originpos = point3d;
|
||||
//int d = (int)(256f / 1.5f);
|
||||
|
||||
//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.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;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Reflection;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
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 ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly string LogHeader = "[SHADED MAPTILE RENDERER]";
|
||||
|
||||
private Scene m_scene;
|
||||
//private IConfigSource m_config; // not used currently
|
||||
@@ -53,19 +54,26 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
|
||||
public void TerrainToBitmap(Bitmap mapbmp)
|
||||
{
|
||||
m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
|
||||
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 terraincorruptedwarningsaid = false;
|
||||
|
||||
float low = 255;
|
||||
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];
|
||||
if (hmval < low)
|
||||
@@ -77,12 +85,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
|
||||
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
|
||||
int yr = ((int)Constants.RegionSize - 1) - y;
|
||||
int yr = ((int)hm.Height - 1) - y;
|
||||
|
||||
float heightvalue = (float)hm[x, y];
|
||||
|
||||
@@ -109,12 +117,12 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
// .
|
||||
//
|
||||
// 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 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
|
||||
}
|
||||
@@ -179,7 +187,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
|
||||
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);
|
||||
int r = color.R;
|
||||
@@ -233,7 +241,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
terraincorruptedwarningsaid = true;
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Imaging;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
@@ -122,8 +124,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
{
|
||||
#region Constants
|
||||
|
||||
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 = "[TEXTURED MAPTILE RENDERER]";
|
||||
|
||||
// some hardcoded terrain UUIDs that work with SL 1.20 (the four default textures and "Blank").
|
||||
// The color-values were choosen because they "look right" (at least to me) ;-)
|
||||
@@ -173,7 +175,7 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
private Bitmap fetchTexture(UUID id)
|
||||
{
|
||||
AssetBase asset = m_scene.AssetService.Get(id.ToString());
|
||||
m_log.DebugFormat("[TEXTURED MAP TILE RENDERER]: Fetched texture {0}, found: {1}", id, asset != null);
|
||||
m_log.DebugFormat("{0} Fetched texture {1}, found: {2}", LogHeader, id, asset != null);
|
||||
if (asset == null) return null;
|
||||
|
||||
ManagedImage managedImage;
|
||||
@@ -188,18 +190,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
}
|
||||
catch (DllNotFoundException)
|
||||
{
|
||||
m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg is not installed correctly on this system. Asset Data is empty for {0}", id);
|
||||
|
||||
m_log.ErrorFormat("{0} OpenJpeg is not installed correctly on this system. Asset Data is empty for {1}", LogHeader, id);
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
|
||||
|
||||
m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
m_log.ErrorFormat("[TEXTURED MAP TILE RENDERER]: OpenJpeg was unable to encode this. Asset Data is empty for {0}", id);
|
||||
|
||||
m_log.ErrorFormat("{0} OpenJpeg was unable to encode this. Asset Data is empty for {1}", LogHeader, id);
|
||||
}
|
||||
return null;
|
||||
|
||||
@@ -271,8 +270,8 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
|
||||
// the heigthfield might have some jumps in values. Rendered land is smooth, though,
|
||||
// as a slope is rendered at that place. So average 4 neighbour values to emulate that.
|
||||
private float getHeight(double[,] hm, int x, int y) {
|
||||
if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1))
|
||||
private float getHeight(ITerrainChannel hm, int x, int y) {
|
||||
if (x < (hm.Width - 1) && y < (hm.Height - 1))
|
||||
return (float)(hm[x, y] * .444 + (hm[x + 1, y] + hm[x, y + 1]) * .222 + hm[x + 1, y +1] * .112);
|
||||
else
|
||||
return (float)hm[x, y];
|
||||
@@ -282,7 +281,15 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
public void TerrainToBitmap(Bitmap mapbmp)
|
||||
{
|
||||
int tc = Environment.TickCount;
|
||||
m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Terrain");
|
||||
m_log.DebugFormat("{0} Generating Maptile Step 1: Terrain", LogHeader);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// These textures should be in the AssetCache anyway, as every client conneting to this
|
||||
// region needs them. Except on start, when the map is recreated (before anyone connected),
|
||||
@@ -310,19 +317,17 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
|
||||
float waterHeight = (float)settings.WaterHeight;
|
||||
|
||||
double[,] hm = m_scene.Heightmap.GetDoubles();
|
||||
|
||||
for (int x = 0; x < (int)Constants.RegionSize; x++)
|
||||
for (int x = 0; x < hm.Width; x++)
|
||||
{
|
||||
float columnRatio = x / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation
|
||||
for (int y = 0; y < (int)Constants.RegionSize; y++)
|
||||
float columnRatio = x / (hm.Width - 1); // 0 - 1, for interpolation
|
||||
for (int y = 0; y < hm.Height; y++)
|
||||
{
|
||||
float rowRatio = y / ((float)Constants.RegionSize - 1); // 0 - 1, for interpolation
|
||||
float rowRatio = y / (hm.Height - 1); // 0 - 1, for interpolation
|
||||
|
||||
// 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 = (hm.Height - 1) - y;
|
||||
|
||||
float heightvalue = getHeight(hm, x, y);
|
||||
float heightvalue = getHeight(m_scene.Heightmap, x, y);
|
||||
if (Single.IsInfinity(heightvalue) || Single.IsNaN(heightvalue))
|
||||
heightvalue = 0;
|
||||
|
||||
@@ -372,9 +377,9 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
}
|
||||
|
||||
// Shade the terrain for shadows
|
||||
if (x < ((int)Constants.RegionSize - 1) && y < ((int)Constants.RegionSize - 1))
|
||||
if (x < (hm.Width - 1) && y < (hm.Height - 1))
|
||||
{
|
||||
float hfvaluecompare = getHeight(hm, x + 1, y + 1); // light from north-east => look at land height there
|
||||
float hfvaluecompare = getHeight(m_scene.Heightmap, x + 1, y + 1); // light from north-east => look at land height there
|
||||
if (Single.IsInfinity(hfvaluecompare) || Single.IsNaN(hfvaluecompare))
|
||||
hfvaluecompare = 0f;
|
||||
|
||||
@@ -420,4 +425,4 @@ namespace OpenSim.Region.CoreModules.World.LegacyMap
|
||||
m_log.Debug("[TEXTURED MAP TILE RENDERER]: Generating Maptile Step 1: Done in " + (Environment.TickCount - tc) + " ms");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,14 +151,9 @@ namespace OpenSim.Region.CoreModules.World.Objects.BuySell
|
||||
break;
|
||||
|
||||
case 2: // Sell a copy
|
||||
Vector3 inventoryStoredPosition = new Vector3
|
||||
(((group.AbsolutePosition.X > (int)Constants.RegionSize)
|
||||
? 250
|
||||
: group.AbsolutePosition.X)
|
||||
,
|
||||
(group.AbsolutePosition.X > (int)Constants.RegionSize)
|
||||
? 250
|
||||
: group.AbsolutePosition.X,
|
||||
Vector3 inventoryStoredPosition = new Vector3(
|
||||
Math.Min(group.AbsolutePosition.X, m_scene.RegionInfo.RegionSizeX - 6),
|
||||
Math.Min(group.AbsolutePosition.Y, m_scene.RegionInfo.RegionSizeY - 6),
|
||||
group.AbsolutePosition.Z);
|
||||
|
||||
Vector3 originalPosition = group.AbsolutePosition;
|
||||
|
||||
@@ -1571,10 +1571,10 @@ namespace OpenSim.Region.CoreModules.World.Permissions
|
||||
float X = position.X;
|
||||
float Y = position.Y;
|
||||
|
||||
if (X > ((int)Constants.RegionSize - 1))
|
||||
X = ((int)Constants.RegionSize - 1);
|
||||
if (Y > ((int)Constants.RegionSize - 1))
|
||||
Y = ((int)Constants.RegionSize - 1);
|
||||
if (X > ((int)m_scene.RegionInfo.RegionSizeX - 1))
|
||||
X = ((int)m_scene.RegionInfo.RegionSizeX - 1);
|
||||
if (Y > ((int)m_scene.RegionInfo.RegionSizeY - 1))
|
||||
Y = ((int)m_scene.RegionInfo.RegionSizeY - 1);
|
||||
if (X < 0)
|
||||
X = 0;
|
||||
if (Y < 0)
|
||||
|
||||
@@ -68,9 +68,6 @@ namespace OpenSim.Region.CoreModules
|
||||
// updating those region settings in GenSunPos()
|
||||
private bool receivedEstateToolsSunUpdate = false;
|
||||
|
||||
// Configurable values
|
||||
private string m_RegionMode = "SL";
|
||||
|
||||
// Sun's position information is updated and sent to clients every m_UpdateInterval frames
|
||||
private int m_UpdateInterval = 0;
|
||||
|
||||
@@ -90,7 +87,6 @@ namespace OpenSim.Region.CoreModules
|
||||
// private double m_longitude = 0;
|
||||
// private double m_latitude = 0;
|
||||
// Configurable defaults Defaults close to SL
|
||||
private string d_mode = "SL";
|
||||
private int d_frame_mod = 100; // Every 10 seconds (actually less)
|
||||
private double d_day_length = 4; // A VW day is 4 RW hours long
|
||||
private int d_year_length = 60; // There are 60 VW days in a VW year
|
||||
@@ -134,12 +130,15 @@ namespace OpenSim.Region.CoreModules
|
||||
|
||||
private const int TICKS_PER_SECOND = 10000000;
|
||||
|
||||
private ulong m_CurrentTimeOffset = 0;
|
||||
|
||||
// Current time in elapsed seconds since Jan 1st 1970
|
||||
private ulong CurrentTime
|
||||
{
|
||||
get
|
||||
{
|
||||
return (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND);
|
||||
ulong ctime = (ulong)(((DateTime.Now.Ticks) - TicksToEpoch + TicksUTCOffset) / TICKS_PER_SECOND);
|
||||
return ctime + m_CurrentTimeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,10 +261,8 @@ namespace OpenSim.Region.CoreModules
|
||||
|
||||
private float GetCurrentTimeAsLindenSunHour()
|
||||
{
|
||||
if (m_SunFixed)
|
||||
return m_SunFixedHour + 6;
|
||||
|
||||
return GetCurrentSunHour() + 6.0f;
|
||||
float curtime = m_SunFixed ? m_SunFixedHour : GetCurrentSunHour();
|
||||
return (curtime + 6.0f) % 24.0f;
|
||||
}
|
||||
|
||||
#region INonSharedRegion Methods
|
||||
@@ -290,8 +287,6 @@ namespace OpenSim.Region.CoreModules
|
||||
// Just in case they don't have the stanzas
|
||||
try
|
||||
{
|
||||
// Mode: determines how the sun is handled
|
||||
m_RegionMode = config.Configs["Sun"].GetString("mode", d_mode);
|
||||
// Mode: determines how the sun is handled
|
||||
// m_latitude = config.Configs["Sun"].GetDouble("latitude", d_latitude);
|
||||
// Mode: determines how the sun is handled
|
||||
@@ -314,7 +309,6 @@ namespace OpenSim.Region.CoreModules
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[SUN]: Configuration access failed, using defaults. Reason: " + e.Message);
|
||||
m_RegionMode = d_mode;
|
||||
m_YearLengthDays = d_year_length;
|
||||
m_DayLengthHours = d_day_length;
|
||||
m_HorizonShift = d_day_night;
|
||||
@@ -325,40 +319,28 @@ namespace OpenSim.Region.CoreModules
|
||||
// m_longitude = d_longitude;
|
||||
}
|
||||
|
||||
switch (m_RegionMode)
|
||||
{
|
||||
case "T1":
|
||||
default:
|
||||
case "SL":
|
||||
// Time taken to complete a cycle (day and season)
|
||||
SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
|
||||
SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
|
||||
|
||||
SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
|
||||
SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
|
||||
// Ration of real-to-virtual time
|
||||
|
||||
// Ration of real-to-virtual time
|
||||
// VWTimeRatio = 24/m_day_length;
|
||||
|
||||
// VWTimeRatio = 24/m_day_length;
|
||||
// Speed of rotation needed to complete a cycle in the
|
||||
// designated period (day and season)
|
||||
|
||||
// Speed of rotation needed to complete a cycle in the
|
||||
// designated period (day and season)
|
||||
SunSpeed = m_SunCycle/SecondsPerSunCycle;
|
||||
SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
|
||||
|
||||
SunSpeed = m_SunCycle/SecondsPerSunCycle;
|
||||
SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
|
||||
// Horizon translation
|
||||
|
||||
// Horizon translation
|
||||
|
||||
HorizonShift = m_HorizonShift; // Z axis translation
|
||||
// HoursToRadians = (SunCycle/24)*VWTimeRatio;
|
||||
|
||||
m_log.Debug("[SUN]: Mode is " + m_RegionMode);
|
||||
m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days");
|
||||
m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift);
|
||||
m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale);
|
||||
m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames");
|
||||
|
||||
break;
|
||||
}
|
||||
HorizonShift = m_HorizonShift; // Z axis translation
|
||||
// HoursToRadians = (SunCycle/24)*VWTimeRatio;
|
||||
|
||||
m_log.Debug("[SUN]: Initialization completed. Day is " + SecondsPerSunCycle + " seconds, and year is " + m_YearLengthDays + " days");
|
||||
m_log.Debug("[SUN]: Axis offset is " + m_HorizonShift);
|
||||
m_log.Debug("[SUN]: Percentage of time for daylight " + m_DayTimeSunHourScale);
|
||||
m_log.Debug("[SUN]: Positional data updated every " + m_UpdateInterval + " frames");
|
||||
}
|
||||
|
||||
public Type ReplaceableInterface
|
||||
@@ -385,7 +367,8 @@ namespace OpenSim.Region.CoreModules
|
||||
string sunCommand = string.Format("sun {0}", kvp.Key);
|
||||
m_scene.AddCommand("Regions", this, sunCommand, string.Format("{0} [<value>]", sunCommand), kvp.Value, "", HandleSunConsoleCommand);
|
||||
}
|
||||
|
||||
m_scene.AddCommand("Regions", this, "sun help", "sun help", "list parameters that can be changed", "", HandleSunConsoleCommand);
|
||||
m_scene.AddCommand("Regions", this, "sun list", "sun list", "list parameters that can be changed", "", HandleSunConsoleCommand);
|
||||
ready = true;
|
||||
}
|
||||
|
||||
@@ -419,23 +402,22 @@ namespace OpenSim.Region.CoreModules
|
||||
|
||||
public void SunToClient(IClientAPI client)
|
||||
{
|
||||
if (m_RegionMode != "T1")
|
||||
if (ready)
|
||||
{
|
||||
if (ready)
|
||||
if (m_SunFixed)
|
||||
{
|
||||
if (m_SunFixed)
|
||||
{
|
||||
// m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
|
||||
client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ", m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
|
||||
client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
|
||||
}
|
||||
// m_log.DebugFormat("[SUN]: Fixed SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ",
|
||||
// m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
|
||||
client.SendSunPos(Position, Velocity, PosTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.DebugFormat("[SUN]: SunHour {0}, Position {1}, PosTime {2}, OrbitalPosition : {3} ",
|
||||
// m_SunFixedHour, Position.ToString(), PosTime.ToString(), OrbitalPosition.ToString());
|
||||
client.SendSunPos(Position, Velocity, CurrentTime, SecondsPerSunCycle, SecondsPerYear, OrbitalPosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SunUpdate()
|
||||
{
|
||||
@@ -532,6 +514,9 @@ namespace OpenSim.Region.CoreModules
|
||||
case "update_interval":
|
||||
return m_UpdateInterval;
|
||||
|
||||
case "current_time":
|
||||
return GetCurrentTimeAsLindenSunHour();
|
||||
|
||||
default:
|
||||
throw new Exception("Unknown sun parameter.");
|
||||
}
|
||||
@@ -539,7 +524,51 @@ namespace OpenSim.Region.CoreModules
|
||||
|
||||
public void SetSunParameter(string param, double value)
|
||||
{
|
||||
HandleSunConsoleCommand("sun", new string[] {param, value.ToString() });
|
||||
switch (param)
|
||||
{
|
||||
case "year_length":
|
||||
m_YearLengthDays = (int)value;
|
||||
SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
|
||||
SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
|
||||
break;
|
||||
|
||||
case "day_length":
|
||||
m_DayLengthHours = value;
|
||||
SecondsPerSunCycle = (uint) (m_DayLengthHours * 60 * 60);
|
||||
SecondsPerYear = (uint) (SecondsPerSunCycle*m_YearLengthDays);
|
||||
SunSpeed = m_SunCycle/SecondsPerSunCycle;
|
||||
SeasonSpeed = m_SeasonalCycle/SecondsPerYear;
|
||||
break;
|
||||
|
||||
case "day_night_offset":
|
||||
m_HorizonShift = value;
|
||||
HorizonShift = m_HorizonShift;
|
||||
break;
|
||||
|
||||
case "day_time_sun_hour_scale":
|
||||
m_DayTimeSunHourScale = value;
|
||||
break;
|
||||
|
||||
case "update_interval":
|
||||
m_UpdateInterval = (int)value;
|
||||
break;
|
||||
|
||||
case "current_time":
|
||||
value = (value + 18.0) % 24.0;
|
||||
// set the current offset so that the effective sun time is the parameter
|
||||
m_CurrentTimeOffset = 0; // clear this first so we use raw time
|
||||
m_CurrentTimeOffset = (ulong)(SecondsPerSunCycle * value/ 24.0) - (CurrentTime % SecondsPerSunCycle);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Exception("Unknown sun parameter.");
|
||||
|
||||
// Generate shared values
|
||||
GenSunPos();
|
||||
|
||||
// When sun settings are updated, we should update all clients with new settings.
|
||||
SunUpdateToAllClients();
|
||||
}
|
||||
}
|
||||
|
||||
public float GetCurrentSunHour()
|
||||
@@ -572,7 +601,7 @@ namespace OpenSim.Region.CoreModules
|
||||
|
||||
foreach (string output in ParseCmdParams(cmdparams))
|
||||
{
|
||||
m_log.Info("[SUN] " + output);
|
||||
MainConsole.Instance.Output(output);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -581,10 +610,11 @@ namespace OpenSim.Region.CoreModules
|
||||
Dictionary<string, string> Params = new Dictionary<string, string>();
|
||||
|
||||
Params.Add("year_length", "number of days to a year");
|
||||
Params.Add("day_length", "number of seconds to a day");
|
||||
Params.Add("day_length", "number of hours to a day");
|
||||
Params.Add("day_night_offset", "induces a horizon shift");
|
||||
Params.Add("update_interval", "how often to update the sun's position in frames");
|
||||
Params.Add("day_time_sun_hour_scale", "scales day light vs nite hours to change day/night ratio");
|
||||
Params.Add("current_time", "time in seconds of the simulator");
|
||||
|
||||
return Params;
|
||||
}
|
||||
@@ -618,46 +648,15 @@ namespace OpenSim.Region.CoreModules
|
||||
}
|
||||
else if (args.Length == 3)
|
||||
{
|
||||
float value = 0.0f;
|
||||
if (!float.TryParse(args[2], out value))
|
||||
double value = 0.0;
|
||||
if (! double.TryParse(args[2], out value))
|
||||
{
|
||||
Output.Add(String.Format("The parameter value {0} is not a valid number.", args[2]));
|
||||
return Output;
|
||||
}
|
||||
|
||||
switch (args[1].ToLower())
|
||||
{
|
||||
case "year_length":
|
||||
m_YearLengthDays = (int)value;
|
||||
break;
|
||||
|
||||
case "day_length":
|
||||
m_DayLengthHours = value;
|
||||
break;
|
||||
|
||||
case "day_night_offset":
|
||||
m_HorizonShift = value;
|
||||
break;
|
||||
|
||||
case "day_time_sun_hour_scale":
|
||||
m_DayTimeSunHourScale = value;
|
||||
break;
|
||||
|
||||
case "update_interval":
|
||||
m_UpdateInterval = (int)value;
|
||||
break;
|
||||
|
||||
default:
|
||||
Output.Add(String.Format("Unknown parameter {0}.", args[1]));
|
||||
return Output;
|
||||
}
|
||||
|
||||
SetSunParameter(args[1].ToLower(), value);
|
||||
Output.Add(String.Format("Parameter {0} set to {1}.", args[1], value.ToString()));
|
||||
|
||||
// Generate shared values
|
||||
GenSunPos();
|
||||
|
||||
// When sun settings are updated, we should update all clients with new settings.
|
||||
SunUpdateToAllClients();
|
||||
}
|
||||
|
||||
return Output;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Effects
|
||||
for (y = 0; y < map.Height; y++)
|
||||
{
|
||||
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)
|
||||
{
|
||||
map[x, y] = spherFac;
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
|
||||
{
|
||||
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++)
|
||||
{
|
||||
|
||||
@@ -25,7 +25,10 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
@@ -116,7 +119,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FileLoaders
|
||||
|
||||
public ITerrainChannel LoadStream(Stream s)
|
||||
{
|
||||
TerrainChannel retval = new TerrainChannel();
|
||||
// The raw format doesn't contain any dimension information.
|
||||
// Guess the square dimensions by using the length of the raw file.
|
||||
double dimension = Math.Sqrt((double)(s.Length / 4));
|
||||
// Regions are always multiples of 256.
|
||||
int trimmedDimension = (int)dimension - ((int)dimension % (int)Constants.RegionSize);
|
||||
if (trimmedDimension < Constants.RegionSize)
|
||||
trimmedDimension = (int)Constants.RegionSize;
|
||||
|
||||
TerrainChannel retval = new TerrainChannel(trimmedDimension, trimmedDimension);
|
||||
|
||||
BinaryReader bs = new BinaryReader(s);
|
||||
int y;
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.FloodBrushes
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain.PaintBrushes
|
||||
z *= z;
|
||||
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)
|
||||
map[x, y] += noise * z * duration;
|
||||
|
||||
@@ -30,10 +30,14 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
|
||||
using OpenMetaverse;
|
||||
using Mono.Addins;
|
||||
|
||||
using OpenSim.Data;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
|
||||
using OpenSim.Region.CoreModules.World.Terrain.FileLoaders;
|
||||
@@ -70,6 +74,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
#endregion
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly string LogHeader = "[TERRAIN MODULE]";
|
||||
|
||||
private readonly Commander m_commander = new Commander("terrain");
|
||||
|
||||
@@ -130,15 +135,15 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
{
|
||||
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_revert = new TerrainChannel();
|
||||
UpdateRevertMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_channel = m_scene.Heightmap;
|
||||
m_revert = new TerrainChannel();
|
||||
UpdateRevertMap();
|
||||
}
|
||||
|
||||
@@ -230,11 +235,11 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
try
|
||||
{
|
||||
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
|
||||
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_scene.Heightmap = channel;
|
||||
@@ -309,12 +314,18 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
LoadFromStream(filename, URIFetch(pathToTerrainHeightmap));
|
||||
}
|
||||
|
||||
public void LoadFromStream(string filename, Stream stream)
|
||||
{
|
||||
LoadFromStream(filename, Vector3.Zero, 0f, Vector2.Zero, stream);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a terrain file from a stream and installs it in the scene.
|
||||
/// </summary>
|
||||
/// <param name="filename">Filename to terrain file. Type is determined by extension.</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)
|
||||
{
|
||||
@@ -325,8 +336,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
try
|
||||
{
|
||||
ITerrainChannel channel = loader.Value.LoadStream(stream);
|
||||
m_scene.Heightmap = channel;
|
||||
m_channel = channel;
|
||||
m_channel.Merge(channel, displacement, radianRotation, rotationDisplacement);
|
||||
UpdateRevertMap();
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
@@ -532,6 +542,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
/// </summary>
|
||||
public void UpdateRevertMap()
|
||||
{
|
||||
/*
|
||||
int x;
|
||||
for (x = 0; x < m_channel.Width; x++)
|
||||
{
|
||||
@@ -541,6 +552,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
m_revert[x, y] = m_channel[x, y];
|
||||
}
|
||||
}
|
||||
*/
|
||||
m_revert = m_channel.MakeCopy();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -567,8 +580,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
{
|
||||
ITerrainChannel channel = loader.Value.LoadFile(filename, offsetX, offsetY,
|
||||
fileWidth, fileHeight,
|
||||
(int) Constants.RegionSize,
|
||||
(int) Constants.RegionSize);
|
||||
(int) m_scene.RegionInfo.RegionSizeX,
|
||||
(int) m_scene.RegionInfo.RegionSizeY);
|
||||
m_scene.Heightmap = channel;
|
||||
m_channel = channel;
|
||||
UpdateRevertMap();
|
||||
@@ -615,8 +628,8 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
{
|
||||
loader.Value.SaveFile(m_channel, filename, offsetX, offsetY,
|
||||
fileWidth, fileHeight,
|
||||
(int)Constants.RegionSize,
|
||||
(int)Constants.RegionSize);
|
||||
(int)m_scene.RegionInfo.RegionSizeX,
|
||||
(int)m_scene.RegionInfo.RegionSizeY);
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Saved terrain from ({0},{1}) to ({2},{3}) from {4} to {5}",
|
||||
@@ -705,7 +718,7 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
private void CheckForTerrainUpdates(bool respectEstateSettings)
|
||||
{
|
||||
bool shouldTaint = false;
|
||||
float[] serialised = m_channel.GetFloatsSerialised();
|
||||
float[] terrHeights = m_channel.GetFloatsSerialised();
|
||||
int x;
|
||||
for (x = 0; x < m_channel.Width; x += Constants.TerrainPatchSize)
|
||||
{
|
||||
@@ -714,16 +727,17 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
{
|
||||
if (m_channel.Tainted(x, y))
|
||||
{
|
||||
// if we should respect the estate settings then
|
||||
// fixup and height deltas that don't respect them
|
||||
// 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.
|
||||
if (respectEstateSettings && LimitChannelChanges(x, y))
|
||||
{
|
||||
// this has been vetoed, so update
|
||||
// what we are going to send to the client
|
||||
serialised = m_channel.GetFloatsSerialised();
|
||||
// Terrain heights were modified. Refetch the terrain info.
|
||||
terrHeights = m_channel.GetFloatsSerialised();
|
||||
}
|
||||
|
||||
SendToClients(serialised, x, y);
|
||||
// m_log.DebugFormat("{0} Patch modified. Sending (x,y) = ({1},{2})", LogHeader, x, y);
|
||||
SendToClients(terrHeights, x, y);
|
||||
shouldTaint = true;
|
||||
}
|
||||
}
|
||||
@@ -792,13 +806,11 @@ 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="x">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(float[] heightMap, int x, int y)
|
||||
{
|
||||
m_scene.ForEachClient(
|
||||
delegate(IClientAPI controller)
|
||||
{ controller.SendLayerData(
|
||||
x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, serialised);
|
||||
}
|
||||
{ controller.SendLayerData( x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize, heightMap); }
|
||||
);
|
||||
}
|
||||
|
||||
@@ -984,28 +996,28 @@ namespace OpenSim.Region.CoreModules.World.Terrain
|
||||
|
||||
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 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, (int)Constants.RegionSize - 1 - y] = height;
|
||||
m_channel[x, (int)m_channel.Height - 1 - y] = height;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
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 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[(int)Constants.RegionSize - 1 - x, y] = height;
|
||||
m_channel[(int)m_channel.Width - 1 - x, y] = height;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,10 +40,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
|
||||
[Test]
|
||||
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];
|
||||
int x;
|
||||
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++)
|
||||
{
|
||||
@@ -57,13 +60,12 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
|
||||
TerrainChannel map = new TerrainChannel((int)Constants.RegionSize, (int)Constants.RegionSize);
|
||||
ITerrainPaintableEffect effect = new RaiseSphere();
|
||||
|
||||
effect.PaintEffect(map, allowMask, (int)Constants.RegionSize * 0.5f, (int)Constants.RegionSize * 0.5f, -1.0, 2, 0.1);
|
||||
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[124, (int)((int)Constants.RegionSize * 0.5f)] > 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[128, (int)((int)Constants.RegionSize * 0.5f)] == 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).");
|
||||
|
||||
effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
|
||||
Assert.That(map[127, midRegion] > 0.0, "Raise brush should raising value at this point (127,128).");
|
||||
Assert.That(map[125, midRegion] > 0.0, "Raise brush should raising value at this point (124,128).");
|
||||
Assert.That(map[120, midRegion] == 0.0, "Raise brush should not change value at this point (120,128).");
|
||||
Assert.That(map[128, midRegion] == 0.0, "Raise brush should not change value at this point (128,128).");
|
||||
Assert.That(map[0, midRegion] == 0.0, "Raise brush should not change value at this point (0,128).");
|
||||
//
|
||||
// Test LowerSphere
|
||||
//
|
||||
@@ -77,13 +79,13 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
|
||||
}
|
||||
effect = new LowerSphere();
|
||||
|
||||
effect.PaintEffect(map, allowMask, ((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), -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, (int)((int)Constants.RegionSize * 0.5f)] == 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[123, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (123,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[0, (int)((int)Constants.RegionSize * 0.5f)] == 1.0, "Lower brush should not change value at this point (0,128).");
|
||||
effect.PaintEffect(map, allowMask, midRegion, midRegion, -1.0, 2, 6.0);
|
||||
Assert.That(map[127, midRegion] >= 0.0, "Lower should not lowering value below 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[125, midRegion] < 1.0, "Lower brush should lowering value at this point (124,128).");
|
||||
Assert.That(map[120, midRegion] == 1.0, "Lower brush should not change value at this point (120,128).");
|
||||
Assert.That(map[128, midRegion] == 1.0, "Lower brush should not change value at this point (128,128).");
|
||||
Assert.That(map[0, midRegion] == 1.0, "Lower brush should not change value at this point (0,128).");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -100,10 +102,6 @@ namespace OpenSim.Region.CoreModules.World.Terrain.Tests
|
||||
x[0, 0] -= 1.0;
|
||||
Assert.That(x[0, 0] == 4.0, "Terrain addition/subtraction error.");
|
||||
|
||||
x[0, 0] = Math.PI;
|
||||
double[,] doublesExport = x.GetDoubles();
|
||||
Assert.That(doublesExport[0, 0] == Math.PI, "Export to double[,] array not working correctly.");
|
||||
|
||||
x[0, 0] = 1.0;
|
||||
float[] floatsExport = x.GetFloatsSerialised();
|
||||
Assert.That(floatsExport[0] == 1.0f, "Export to float[] not working correctly.");
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
@@ -32,6 +32,7 @@ using System.Drawing.Imaging;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Services.Interfaces;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
@@ -66,261 +67,271 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
#endregion Constants
|
||||
|
||||
private static readonly ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||
private static string LogHeader = "[WARP3D TERRAIN SPLAT]";
|
||||
|
||||
/// <summary>
|
||||
/// Builds a composited terrain texture given the region texture
|
||||
/// and heightmap settings
|
||||
/// </summary>
|
||||
/// <param name="heightmap">Terrain heightmap</param>
|
||||
/// <param name="terrain">Terrain heightmap</param>
|
||||
/// <param name="regionInfo">Region information including terrain texture parameters</param>
|
||||
/// <returns>A composited 256x256 RGB texture ready for rendering</returns>
|
||||
/// <returns>A 256x256 square RGB texture ready for rendering</returns>
|
||||
/// <remarks>Based on the algorithm described at http://opensimulator.org/wiki/Terrain_Splatting
|
||||
/// Note we create a 256x256 dimension texture even if the actual terrain is larger.
|
||||
/// </remarks>
|
||||
public static Bitmap Splat(float[] heightmap, UUID[] textureIDs, float[] startHeights, float[] heightRanges, Vector3d regionPosition, IAssetService assetService, bool textureTerrain)
|
||||
public static Bitmap Splat(ITerrainChannel terrain,
|
||||
UUID[] textureIDs, float[] startHeights, float[] heightRanges,
|
||||
Vector3d regionPosition, IAssetService assetService, bool textureTerrain)
|
||||
{
|
||||
Debug.Assert(heightmap.Length == 256 * 256);
|
||||
Debug.Assert(textureIDs.Length == 4);
|
||||
Debug.Assert(startHeights.Length == 4);
|
||||
Debug.Assert(heightRanges.Length == 4);
|
||||
|
||||
Bitmap[] detailTexture = new Bitmap[4];
|
||||
Bitmap output = null;
|
||||
BitmapData outputData = null;
|
||||
|
||||
try
|
||||
if (textureTerrain)
|
||||
{
|
||||
if (textureTerrain)
|
||||
// Swap empty terrain textureIDs with default IDs
|
||||
for (int i = 0; i < textureIDs.Length; i++)
|
||||
{
|
||||
// Swap empty terrain textureIDs with default IDs
|
||||
for (int i = 0; i < textureIDs.Length; i++)
|
||||
if (textureIDs[i] == UUID.Zero)
|
||||
textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
|
||||
}
|
||||
|
||||
#region Texture Fetching
|
||||
|
||||
if (assetService != null)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (textureIDs[i] == UUID.Zero)
|
||||
textureIDs[i] = DEFAULT_TERRAIN_DETAIL[i];
|
||||
}
|
||||
|
||||
#region Texture Fetching
|
||||
|
||||
if (assetService != null)
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
AssetBase asset;
|
||||
UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]);
|
||||
|
||||
// Try to fetch a cached copy of the decoded/resized version of this texture
|
||||
asset = assetService.GetCached(cacheID.ToString());
|
||||
if (asset != null)
|
||||
{
|
||||
AssetBase asset;
|
||||
UUID cacheID = UUID.Combine(TERRAIN_CACHE_MAGIC, textureIDs[i]);
|
||||
|
||||
// Try to fetch a cached copy of the decoded/resized version of this texture
|
||||
asset = assetService.GetCached(cacheID.ToString());
|
||||
try
|
||||
{
|
||||
using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
|
||||
detailTexture[i] = (Bitmap)Image.FromStream(stream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("Failed to decode cached terrain texture " + cacheID +
|
||||
" (textureID: " + textureIDs[i] + "): " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (detailTexture[i] == null)
|
||||
{
|
||||
// Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
|
||||
asset = assetService.Get(textureIDs[i].ToString());
|
||||
if (asset != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[TERRAIN SPLAT]: Got asset service cached terrain texture {0} {1}", i, asset.ID);
|
||||
|
||||
try
|
||||
{
|
||||
using (System.IO.MemoryStream stream = new System.IO.MemoryStream(asset.Data))
|
||||
detailTexture[i] = (Bitmap)Image.FromStream(stream);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("Failed to decode cached terrain texture " + cacheID +
|
||||
" (textureID: " + textureIDs[i] + "): " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (detailTexture[i] == null)
|
||||
{
|
||||
// Try to fetch the original JPEG2000 texture, resize if needed, and cache as PNG
|
||||
asset = assetService.Get(textureIDs[i].ToString());
|
||||
if (asset != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[TERRAIN SPLAT]: Got cached original JPEG2000 terrain texture {0} {1}", i, asset.ID);
|
||||
|
||||
try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
|
||||
catch (Exception ex)
|
||||
try { detailTexture[i] = (Bitmap)CSJ2K.J2kImage.FromBytes(asset.Data); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
if (detailTexture[i] != null)
|
||||
{
|
||||
// Make sure this texture is the correct size, otherwise resize
|
||||
if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
|
||||
{
|
||||
using (Bitmap origBitmap = detailTexture[i])
|
||||
{
|
||||
m_log.Warn("Failed to decode terrain texture " + asset.ID + ": " + ex.Message);
|
||||
detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256);
|
||||
}
|
||||
}
|
||||
|
||||
if (detailTexture[i] != null)
|
||||
{
|
||||
// Make sure this texture is the correct size, otherwise resize
|
||||
if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
|
||||
{
|
||||
using (Bitmap origBitmap = detailTexture[i])
|
||||
{
|
||||
detailTexture[i] = ImageUtils.ResizeImage(origBitmap, 256, 256);
|
||||
}
|
||||
}
|
||||
|
||||
// Save the decoded and resized texture to the cache
|
||||
byte[] data;
|
||||
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
|
||||
{
|
||||
detailTexture[i].Save(stream, ImageFormat.Png);
|
||||
data = stream.ToArray();
|
||||
}
|
||||
|
||||
// Cache a PNG copy of this terrain texture
|
||||
AssetBase newAsset = new AssetBase
|
||||
{
|
||||
Data = data,
|
||||
Description = "PNG",
|
||||
Flags = AssetFlags.Collectable,
|
||||
FullID = cacheID,
|
||||
ID = cacheID.ToString(),
|
||||
Local = true,
|
||||
Name = String.Empty,
|
||||
Temporary = true,
|
||||
Type = (sbyte)AssetType.Unknown
|
||||
};
|
||||
newAsset.Metadata.ContentType = "image/png";
|
||||
assetService.Store(newAsset);
|
||||
|
||||
// Save the decoded and resized texture to the cache
|
||||
byte[] data;
|
||||
using (System.IO.MemoryStream stream = new System.IO.MemoryStream())
|
||||
{
|
||||
detailTexture[i].Save(stream, ImageFormat.Png);
|
||||
data = stream.ToArray();
|
||||
}
|
||||
|
||||
// Cache a PNG copy of this terrain texture
|
||||
AssetBase newAsset = new AssetBase
|
||||
{
|
||||
Data = data,
|
||||
Description = "PNG",
|
||||
Flags = AssetFlags.Collectable,
|
||||
FullID = cacheID,
|
||||
ID = cacheID.ToString(),
|
||||
Local = true,
|
||||
Name = String.Empty,
|
||||
Temporary = true,
|
||||
Type = (sbyte)AssetType.Unknown
|
||||
};
|
||||
newAsset.Metadata.ContentType = "image/png";
|
||||
assetService.Store(newAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Texture Fetching
|
||||
}
|
||||
|
||||
// Fill in any missing textures with a solid color
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (detailTexture[i] == null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[TERRAIN SPLAT]: Generating solid colour for missing texture {0}", i);
|
||||
|
||||
// Create a solid color texture for this layer
|
||||
detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
||||
using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
|
||||
{
|
||||
using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
|
||||
gfx.FillRectangle(brush, 0, 0, 256, 256);
|
||||
}
|
||||
#endregion Texture Fetching
|
||||
}
|
||||
|
||||
// Fill in any missing textures with a solid color
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
if (detailTexture[i] == null)
|
||||
{
|
||||
m_log.DebugFormat("{0} Missing terrain texture for layer {1}. Filling with solid default color",
|
||||
LogHeader, i);
|
||||
// Create a solid color texture for this layer
|
||||
detailTexture[i] = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
||||
using (Graphics gfx = Graphics.FromImage(detailTexture[i]))
|
||||
{
|
||||
using (SolidBrush brush = new SolidBrush(DEFAULT_TERRAIN_COLOR[i]))
|
||||
gfx.FillRectangle(brush, 0, 0, 256, 256);
|
||||
}
|
||||
}
|
||||
|
||||
#region Layer Map
|
||||
|
||||
float[] layermap = new float[256 * 256];
|
||||
|
||||
else
|
||||
{
|
||||
if (detailTexture[i].Width != 256 || detailTexture[i].Height != 256)
|
||||
{
|
||||
detailTexture[i] = ResizeBitmap(detailTexture[i], 256, 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Layer Map
|
||||
|
||||
float[,] layermap = new float[256, 256];
|
||||
|
||||
// Scale difference between actual region size and the 256 texture being created
|
||||
int xFactor = terrain.Width / 256;
|
||||
int yFactor = terrain.Height / 256;
|
||||
|
||||
// Create 'layermap' where each value is the fractional layer number to place
|
||||
// at that point. For instance, a value of 1.345 gives the blending of
|
||||
// layer 1 and layer 2 for that point.
|
||||
for (int y = 0; y < 256; y++)
|
||||
{
|
||||
for (int x = 0; x < 256; x++)
|
||||
{
|
||||
float height = (float)terrain[x * xFactor, y * yFactor];
|
||||
|
||||
float pctX = (float)x / 255f;
|
||||
float pctY = (float)y / 255f;
|
||||
|
||||
// Use bilinear interpolation between the four corners of start height and
|
||||
// height range to select the current values at this position
|
||||
float startHeight = ImageUtils.Bilinear(
|
||||
startHeights[0],
|
||||
startHeights[2],
|
||||
startHeights[1],
|
||||
startHeights[3],
|
||||
pctX, pctY);
|
||||
startHeight = Utils.Clamp(startHeight, 0f, 255f);
|
||||
|
||||
float heightRange = ImageUtils.Bilinear(
|
||||
heightRanges[0],
|
||||
heightRanges[2],
|
||||
heightRanges[1],
|
||||
heightRanges[3],
|
||||
pctX, pctY);
|
||||
heightRange = Utils.Clamp(heightRange, 0f, 255f);
|
||||
|
||||
// Generate two frequencies of perlin noise based on our global position
|
||||
// The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
|
||||
Vector3 vec = new Vector3
|
||||
(
|
||||
((float)regionPosition.X + (x * xFactor)) * 0.20319f,
|
||||
((float)regionPosition.Y + (y * yFactor)) * 0.20319f,
|
||||
height * 0.25f
|
||||
);
|
||||
|
||||
float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
|
||||
float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
|
||||
float noise = (lowFreq + highFreq) * 2f;
|
||||
|
||||
// Combine the current height, generated noise, start height, and height range parameters, then scale all of it
|
||||
float layer = ((height + noise - startHeight) / heightRange) * 4f;
|
||||
if (Single.IsNaN(layer))
|
||||
layer = 0f;
|
||||
layermap[x, y] = Utils.Clamp(layer, 0f, 3f);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Layer Map
|
||||
|
||||
#region Texture Compositing
|
||||
|
||||
Bitmap output = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
||||
BitmapData outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
|
||||
|
||||
// Unsafe work as we lock down the source textures for quicker access and access the
|
||||
// pixel data directly
|
||||
unsafe
|
||||
{
|
||||
// Get handles to all of the texture data arrays
|
||||
BitmapData[] datas = new BitmapData[]
|
||||
{
|
||||
detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
|
||||
detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
|
||||
detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
|
||||
detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
|
||||
};
|
||||
|
||||
// Compute size of each pixel data (used to address into the pixel data array)
|
||||
int[] comps = new int[]
|
||||
{
|
||||
(datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||
(datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||
(datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||
(datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
|
||||
};
|
||||
|
||||
for (int y = 0; y < 256; y++)
|
||||
{
|
||||
for (int x = 0; x < 256; x++)
|
||||
{
|
||||
float height = heightmap[y * 256 + x];
|
||||
|
||||
float pctX = (float)x / 255f;
|
||||
float pctY = (float)y / 255f;
|
||||
|
||||
// Use bilinear interpolation between the four corners of start height and
|
||||
// height range to select the current values at this position
|
||||
float startHeight = ImageUtils.Bilinear(
|
||||
startHeights[0],
|
||||
startHeights[2],
|
||||
startHeights[1],
|
||||
startHeights[3],
|
||||
pctX, pctY);
|
||||
startHeight = Utils.Clamp(startHeight, 0f, 255f);
|
||||
|
||||
float heightRange = ImageUtils.Bilinear(
|
||||
heightRanges[0],
|
||||
heightRanges[2],
|
||||
heightRanges[1],
|
||||
heightRanges[3],
|
||||
pctX, pctY);
|
||||
heightRange = Utils.Clamp(heightRange, 0f, 255f);
|
||||
|
||||
// Generate two frequencies of perlin noise based on our global position
|
||||
// The magic values were taken from http://opensimulator.org/wiki/Terrain_Splatting
|
||||
Vector3 vec = new Vector3
|
||||
(
|
||||
((float)regionPosition.X + x) * 0.20319f,
|
||||
((float)regionPosition.Y + y) * 0.20319f,
|
||||
height * 0.25f
|
||||
);
|
||||
|
||||
float lowFreq = Perlin.noise2(vec.X * 0.222222f, vec.Y * 0.222222f) * 6.5f;
|
||||
float highFreq = Perlin.turbulence2(vec.X, vec.Y, 2f) * 2.25f;
|
||||
float noise = (lowFreq + highFreq) * 2f;
|
||||
|
||||
// Combine the current height, generated noise, start height, and height range parameters, then scale all of it
|
||||
float layer = ((height + noise - startHeight) / heightRange) * 4f;
|
||||
if (Single.IsNaN(layer)) layer = 0f;
|
||||
layermap[y * 256 + x] = Utils.Clamp(layer, 0f, 3f);
|
||||
float layer = layermap[x, y];
|
||||
|
||||
// Select two textures
|
||||
int l0 = (int)Math.Floor(layer);
|
||||
int l1 = Math.Min(l0 + 1, 3);
|
||||
|
||||
byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
|
||||
byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
|
||||
byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;
|
||||
|
||||
float aB = *(ptrA + 0);
|
||||
float aG = *(ptrA + 1);
|
||||
float aR = *(ptrA + 2);
|
||||
|
||||
float bB = *(ptrB + 0);
|
||||
float bG = *(ptrB + 1);
|
||||
float bR = *(ptrB + 2);
|
||||
|
||||
float layerDiff = layer - l0;
|
||||
|
||||
// Interpolate between the two selected textures
|
||||
*(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
|
||||
*(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
|
||||
*(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Layer Map
|
||||
|
||||
#region Texture Compositing
|
||||
|
||||
output = new Bitmap(256, 256, PixelFormat.Format24bppRgb);
|
||||
outputData = output.LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
|
||||
|
||||
unsafe
|
||||
{
|
||||
// Get handles to all of the texture data arrays
|
||||
BitmapData[] datas = new BitmapData[]
|
||||
{
|
||||
detailTexture[0].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[0].PixelFormat),
|
||||
detailTexture[1].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[1].PixelFormat),
|
||||
detailTexture[2].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[2].PixelFormat),
|
||||
detailTexture[3].LockBits(new Rectangle(0, 0, 256, 256), ImageLockMode.ReadOnly, detailTexture[3].PixelFormat)
|
||||
};
|
||||
|
||||
int[] comps = new int[]
|
||||
{
|
||||
(datas[0].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||
(datas[1].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||
(datas[2].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3,
|
||||
(datas[3].PixelFormat == PixelFormat.Format32bppArgb) ? 4 : 3
|
||||
};
|
||||
|
||||
for (int y = 0; y < 256; y++)
|
||||
{
|
||||
for (int x = 0; x < 256; x++)
|
||||
{
|
||||
float layer = layermap[y * 256 + x];
|
||||
|
||||
// Select two textures
|
||||
int l0 = (int)Math.Floor(layer);
|
||||
int l1 = Math.Min(l0 + 1, 3);
|
||||
|
||||
byte* ptrA = (byte*)datas[l0].Scan0 + y * datas[l0].Stride + x * comps[l0];
|
||||
byte* ptrB = (byte*)datas[l1].Scan0 + y * datas[l1].Stride + x * comps[l1];
|
||||
byte* ptrO = (byte*)outputData.Scan0 + y * outputData.Stride + x * 3;
|
||||
|
||||
float aB = *(ptrA + 0);
|
||||
float aG = *(ptrA + 1);
|
||||
float aR = *(ptrA + 2);
|
||||
|
||||
float bB = *(ptrB + 0);
|
||||
float bG = *(ptrB + 1);
|
||||
float bR = *(ptrB + 2);
|
||||
|
||||
float layerDiff = layer - l0;
|
||||
|
||||
// Interpolate between the two selected textures
|
||||
*(ptrO + 0) = (byte)Math.Floor(aB + layerDiff * (bB - aB));
|
||||
*(ptrO + 1) = (byte)Math.Floor(aG + layerDiff * (bG - aG));
|
||||
*(ptrO + 2) = (byte)Math.Floor(aR + layerDiff * (bR - aR));
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
detailTexture[i].UnlockBits(datas[i]);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
for (int i = 0; i < 4; i++)
|
||||
if (detailTexture[i] != null)
|
||||
detailTexture[i].Dispose();
|
||||
|
||||
for (int i = 0; i < detailTexture.Length; i++)
|
||||
detailTexture[i].UnlockBits(datas[i]);
|
||||
}
|
||||
|
||||
for (int i = 0; i < detailTexture.Length; i++)
|
||||
if (detailTexture[i] != null)
|
||||
detailTexture[i].Dispose();
|
||||
|
||||
output.UnlockBits(outputData);
|
||||
|
||||
// We generated the texture upside down, so flip it
|
||||
@@ -331,6 +342,17 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
return output;
|
||||
}
|
||||
|
||||
public static Bitmap ResizeBitmap(Bitmap b, int nWidth, int nHeight)
|
||||
{
|
||||
m_log.DebugFormat("{0} ResizeBitmap. From <{1},{2}> to <{3},{4}>",
|
||||
LogHeader, b.Width, b.Height, nWidth, nHeight);
|
||||
Bitmap result = new Bitmap(nWidth, nHeight);
|
||||
using (Graphics g = Graphics.FromImage(result))
|
||||
g.DrawImage(b, 0, 0, nWidth, nHeight);
|
||||
b.Dispose();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Bitmap SplatSimple(float[] heightmap)
|
||||
{
|
||||
const float BASE_HSV_H = 93f / 360f;
|
||||
|
||||
@@ -31,21 +31,25 @@ using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
using CSJ2K;
|
||||
using Nini.Config;
|
||||
using log4net;
|
||||
using Rednettle.Warp3D;
|
||||
using Mono.Addins;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Imaging;
|
||||
using OpenMetaverse.Rendering;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.Physics.Manager;
|
||||
using OpenSim.Services.Interfaces;
|
||||
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Assets;
|
||||
using OpenMetaverse.Imaging;
|
||||
using OpenMetaverse.Rendering;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
using WarpRenderer = global::Warp3D.Warp3D;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
@@ -57,12 +61,20 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
private static readonly Color4 WATER_COLOR = new Color4(29, 72, 96, 216);
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static string LogHeader = "[WARP 3D IMAGE MODULE]";
|
||||
|
||||
private Scene m_scene;
|
||||
private IRendering m_primMesher;
|
||||
private IConfigSource m_config;
|
||||
private Dictionary<UUID, Color4> m_colors = new Dictionary<UUID, Color4>();
|
||||
private bool m_useAntiAliasing = false; // TODO: Make this a config option
|
||||
|
||||
private IConfigSource m_config;
|
||||
private bool m_drawPrimVolume = true; // true if should render the prims on the tile
|
||||
private bool m_textureTerrain = true; // true if to create terrain splatting texture
|
||||
private bool m_texturePrims = true; // true if should texture the rendered prims
|
||||
private float m_texturePrimSize = 48f; // size of prim before we consider texturing it
|
||||
private bool m_renderMeshes = false; // true if to render meshes rather than just bounding boxes
|
||||
private bool m_useAntiAliasing = false; // true if to anti-alias the rendered image
|
||||
|
||||
private bool m_Enabled = false;
|
||||
|
||||
#region Region Module interface
|
||||
@@ -71,11 +83,27 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
{
|
||||
m_config = source;
|
||||
|
||||
string[] configSections = new string[] { "Map", "Startup" };
|
||||
|
||||
if (Util.GetConfigVarFromSections<string>(
|
||||
m_config, "MapImageModule", new string[] { "Startup", "Map" }, "MapImageModule") != "Warp3DImageModule")
|
||||
m_config, "MapImageModule", configSections, "MapImageModule") != "Warp3DImageModule")
|
||||
return;
|
||||
|
||||
m_Enabled = true;
|
||||
|
||||
m_drawPrimVolume
|
||||
= Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, m_drawPrimVolume);
|
||||
m_textureTerrain
|
||||
= Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, m_textureTerrain);
|
||||
m_texturePrims
|
||||
= Util.GetConfigVarFromSections<bool>(m_config, "TexturePrims", configSections, m_texturePrims);
|
||||
m_texturePrimSize
|
||||
= Util.GetConfigVarFromSections<float>(m_config, "TexturePrimSize", configSections, m_texturePrimSize);
|
||||
m_renderMeshes
|
||||
= Util.GetConfigVarFromSections<bool>(m_config, "RenderMeshes", configSections, m_renderMeshes);
|
||||
m_useAntiAliasing
|
||||
= Util.GetConfigVarFromSections<bool>(m_config, "UseAntiAliasing", configSections, m_useAntiAliasing);
|
||||
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
@@ -127,29 +155,28 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
|
||||
public Bitmap CreateMapTile()
|
||||
{
|
||||
Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f);
|
||||
Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f, (int)Constants.RegionSize, (int)Constants.RegionSize, (float)Constants.RegionSize, (float)Constants.RegionSize);
|
||||
// Vector3 camPos = new Vector3(127.5f, 127.5f, 221.7025033688163f);
|
||||
// Camera above the middle of the region
|
||||
Vector3 camPos = new Vector3(
|
||||
m_scene.RegionInfo.RegionSizeX/2 - 0.5f,
|
||||
m_scene.RegionInfo.RegionSizeY/2 - 0.5f,
|
||||
221.7025033688163f);
|
||||
// Viewport viewing down onto the region
|
||||
Viewport viewport = new Viewport(camPos, -Vector3.UnitZ, 1024f, 0.1f,
|
||||
(int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY,
|
||||
(float)m_scene.RegionInfo.RegionSizeX, (float)m_scene.RegionInfo.RegionSizeY );
|
||||
// Fill the viewport and return the image
|
||||
return CreateMapTile(viewport, false);
|
||||
}
|
||||
|
||||
public Bitmap CreateViewImage(Vector3 camPos, Vector3 camDir, float fov, int width, int height, bool useTextures)
|
||||
{
|
||||
Viewport viewport = new Viewport(camPos, camDir, fov, (float)Constants.RegionSize, 0.1f, width, height);
|
||||
Viewport viewport = new Viewport(camPos, camDir, fov, Constants.RegionSize, 0.1f, width, height);
|
||||
return CreateMapTile(viewport, useTextures);
|
||||
}
|
||||
|
||||
public Bitmap CreateMapTile(Viewport viewport, bool useTextures)
|
||||
{
|
||||
bool drawPrimVolume = true;
|
||||
bool textureTerrain = true;
|
||||
|
||||
string[] configSections = new string[] { "Map", "Startup" };
|
||||
|
||||
drawPrimVolume
|
||||
= Util.GetConfigVarFromSections<bool>(m_config, "DrawPrimOnMapTile", configSections, drawPrimVolume);
|
||||
textureTerrain
|
||||
= Util.GetConfigVarFromSections<bool>(m_config, "TextureOnMapTile", configSections, textureTerrain);
|
||||
|
||||
m_colors.Clear();
|
||||
|
||||
int width = viewport.Width;
|
||||
@@ -193,8 +220,8 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
renderer.Scene.addLight("Light2", new warp_Light(new warp_Vector(-1f, -1f, 1f), 0xffffff, 0, 100, 40));
|
||||
|
||||
CreateWater(renderer);
|
||||
CreateTerrain(renderer, textureTerrain);
|
||||
if (drawPrimVolume)
|
||||
CreateTerrain(renderer, m_textureTerrain);
|
||||
if (m_drawPrimVolume)
|
||||
CreateAllPrims(renderer, useTextures);
|
||||
|
||||
renderer.Render();
|
||||
@@ -210,6 +237,16 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
// afterwards. It's generally regarded as a bad idea to manually GC. If Warp3D is using lots of memory
|
||||
// then this may be some issue with the Warp3D code itself, though it's also quite possible that generating
|
||||
// this map tile simply takes a lot of memory.
|
||||
foreach (var o in renderer.Scene.objectData.Values)
|
||||
{
|
||||
warp_Object obj = (warp_Object)o;
|
||||
obj.vertexData = null;
|
||||
obj.triangleData = null;
|
||||
}
|
||||
renderer.Scene.removeAllObjects();
|
||||
renderer = null;
|
||||
viewport = null;
|
||||
m_colors.Clear();
|
||||
GC.Collect();
|
||||
m_log.Debug("[WARP 3D IMAGE MODULE]: GC.Collect()");
|
||||
|
||||
@@ -236,61 +273,74 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
|
||||
#region Rendering Methods
|
||||
|
||||
// Add a water plane to the renderer.
|
||||
private void CreateWater(WarpRenderer renderer)
|
||||
{
|
||||
float waterHeight = (float)m_scene.RegionInfo.RegionSettings.WaterHeight;
|
||||
|
||||
renderer.AddPlane("Water", 256f * 0.5f);
|
||||
renderer.Scene.sceneobject("Water").setPos(127.5f, waterHeight, 127.5f);
|
||||
renderer.AddPlane("Water", m_scene.RegionInfo.RegionSizeX * 0.5f);
|
||||
renderer.Scene.sceneobject("Water").setPos(m_scene.RegionInfo.RegionSizeX/2 - 0.5f,
|
||||
waterHeight,
|
||||
m_scene.RegionInfo.RegionSizeY/2 - 0.5f );
|
||||
|
||||
renderer.AddMaterial("WaterColor", ConvertColor(WATER_COLOR));
|
||||
renderer.Scene.material("WaterColor").setReflectivity(0); // match water color with standard map module thanks lkalif
|
||||
renderer.Scene.material("WaterColor").setTransparency((byte)((1f - WATER_COLOR.A) * 255f));
|
||||
warp_Material waterColorMaterial = new warp_Material(ConvertColor(WATER_COLOR));
|
||||
waterColorMaterial.setReflectivity(0); // match water color with standard map module thanks lkalif
|
||||
waterColorMaterial.setTransparency((byte)((1f - WATER_COLOR.A) * 255f));
|
||||
renderer.Scene.addMaterial("WaterColor", waterColorMaterial);
|
||||
renderer.SetObjectMaterial("Water", "WaterColor");
|
||||
}
|
||||
|
||||
// Add a terrain to the renderer.
|
||||
// Note that we create a 'low resolution' 256x256 vertex terrain rather than trying for
|
||||
// full resolution. This saves a lot of memory especially for very large regions.
|
||||
private void CreateTerrain(WarpRenderer renderer, bool textureTerrain)
|
||||
{
|
||||
ITerrainChannel terrain = m_scene.Heightmap;
|
||||
float[] heightmap = terrain.GetFloatsSerialised();
|
||||
|
||||
// 'diff' is the difference in scale between the real region size and the size of terrain we're buiding
|
||||
float diff = (float)m_scene.RegionInfo.RegionSizeX / 256f;
|
||||
|
||||
warp_Object obj = new warp_Object(256 * 256, 255 * 255 * 2);
|
||||
|
||||
for (int y = 0; y < 256; y++)
|
||||
// Create all the vertices for the terrain
|
||||
for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
|
||||
{
|
||||
for (int x = 0; x < 256; x++)
|
||||
for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
|
||||
{
|
||||
int v = y * 256 + x;
|
||||
float height = heightmap[v];
|
||||
|
||||
warp_Vector pos = ConvertVector(new Vector3(x, y, height));
|
||||
obj.addVertex(new warp_Vertex(pos, (float)x / 255f, (float)(255 - y) / 255f));
|
||||
warp_Vector pos = ConvertVector(x, y, (float)terrain[(int)x, (int)y]);
|
||||
obj.addVertex(new warp_Vertex(pos,
|
||||
x / (float)m_scene.RegionInfo.RegionSizeX,
|
||||
(((float)m_scene.RegionInfo.RegionSizeY) - y) / m_scene.RegionInfo.RegionSizeY) );
|
||||
}
|
||||
}
|
||||
|
||||
for (int y = 0; y < 256; y++)
|
||||
// Now that we have all the vertices, make another pass and create
|
||||
// the normals for each of the surface triangles and
|
||||
// create the list of triangle indices.
|
||||
for (float y = 0; y < m_scene.RegionInfo.RegionSizeY; y += diff)
|
||||
{
|
||||
for (int x = 0; x < 256; x++)
|
||||
for (float x = 0; x < m_scene.RegionInfo.RegionSizeX; x += diff)
|
||||
{
|
||||
if (x < 255 && y < 255)
|
||||
float newX = x / diff;
|
||||
float newY = y / diff;
|
||||
if (newX < 255 && newY < 255)
|
||||
{
|
||||
int v = y * 256 + x;
|
||||
int v = (int)newY * 256 + (int)newX;
|
||||
|
||||
// Normal
|
||||
Vector3 v1 = new Vector3(x, y, heightmap[y * 256 + x]);
|
||||
Vector3 v2 = new Vector3(x + 1, y, heightmap[y * 256 + x + 1]);
|
||||
Vector3 v3 = new Vector3(x, y + 1, heightmap[(y + 1) * 256 + x]);
|
||||
// Normal for a triangle made up of three adjacent vertices
|
||||
Vector3 v1 = new Vector3(newX, newY, (float)terrain[(int)x, (int)y]);
|
||||
Vector3 v2 = new Vector3(newX + 1, newY, (float)terrain[(int)(x + 1), (int)y]);
|
||||
Vector3 v3 = new Vector3(newX, newY + 1, (float)terrain[(int)x, ((int)(y + 1))]);
|
||||
warp_Vector norm = ConvertVector(SurfaceNormal(v1, v2, v3));
|
||||
norm = norm.reverse();
|
||||
obj.vertex(v).n = norm;
|
||||
|
||||
// Triangle 1
|
||||
// Make two triangles for each of the squares in the grid of vertices
|
||||
obj.addTriangle(
|
||||
v,
|
||||
v + 1,
|
||||
v + 256);
|
||||
|
||||
// Triangle 2
|
||||
obj.addTriangle(
|
||||
v + 256 + 1,
|
||||
v + 256,
|
||||
@@ -305,7 +355,7 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
float[] startHeights = new float[4];
|
||||
float[] heightRanges = new float[4];
|
||||
|
||||
RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;
|
||||
OpenSim.Framework.RegionSettings regionInfo = m_scene.RegionInfo.RegionSettings;
|
||||
|
||||
textureIDs[0] = regionInfo.TerrainTexture1;
|
||||
textureIDs[1] = regionInfo.TerrainTexture2;
|
||||
@@ -323,14 +373,12 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
heightRanges[3] = (float)regionInfo.Elevation2NE;
|
||||
|
||||
uint globalX, globalY;
|
||||
Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);
|
||||
Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out globalX, out globalY);
|
||||
|
||||
warp_Texture texture;
|
||||
|
||||
using (
|
||||
Bitmap image
|
||||
= TerrainSplat.Splat(
|
||||
heightmap, textureIDs, startHeights, heightRanges,
|
||||
= TerrainSplat.Splat(terrain, textureIDs, startHeights, heightRanges,
|
||||
new Vector3d(globalX, globalY, 0.0), m_scene.AssetService, textureTerrain))
|
||||
{
|
||||
texture = new warp_Texture(image);
|
||||
@@ -368,8 +416,48 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
if (prim.Scale.LengthSquared() < MIN_SIZE * MIN_SIZE)
|
||||
return;
|
||||
|
||||
FacetedMesh renderMesh = null;
|
||||
Primitive omvPrim = prim.Shape.ToOmvPrimitive(prim.OffsetPosition, prim.RotationOffset);
|
||||
FacetedMesh renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
|
||||
|
||||
if (m_renderMeshes)
|
||||
{
|
||||
if (omvPrim.Sculpt != null && omvPrim.Sculpt.SculptTexture != UUID.Zero)
|
||||
{
|
||||
// Try fetchinng the asset
|
||||
byte[] sculptAsset = m_scene.AssetService.GetData(omvPrim.Sculpt.SculptTexture.ToString());
|
||||
if (sculptAsset != null)
|
||||
{
|
||||
// Is it a mesh?
|
||||
if (omvPrim.Sculpt.Type == SculptType.Mesh)
|
||||
{
|
||||
AssetMesh meshAsset = new AssetMesh(omvPrim.Sculpt.SculptTexture, sculptAsset);
|
||||
FacetedMesh.TryDecodeFromAsset(omvPrim, meshAsset, DetailLevel.Highest, out renderMesh);
|
||||
meshAsset = null;
|
||||
}
|
||||
else // It's sculptie
|
||||
{
|
||||
IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
|
||||
if (imgDecoder != null)
|
||||
{
|
||||
Image sculpt = imgDecoder.DecodeToImage(sculptAsset);
|
||||
if (sculpt != null)
|
||||
{
|
||||
renderMesh = m_primMesher.GenerateFacetedSculptMesh(omvPrim, (Bitmap)sculpt,
|
||||
DetailLevel.Medium);
|
||||
sculpt.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If not a mesh or sculptie, try the regular mesher
|
||||
if (renderMesh == null)
|
||||
{
|
||||
renderMesh = m_primMesher.GenerateFacetedMesh(omvPrim, DetailLevel.Medium);
|
||||
}
|
||||
|
||||
if (renderMesh == null)
|
||||
return;
|
||||
|
||||
@@ -428,7 +516,11 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
|
||||
Primitive.TextureEntryFace teFace = prim.Shape.Textures.GetFace((uint)i);
|
||||
Color4 faceColor = GetFaceColor(teFace);
|
||||
string materialName = GetOrCreateMaterial(renderer, faceColor);
|
||||
string materialName = String.Empty;
|
||||
if (m_texturePrims && prim.Scale.LengthSquared() > m_texturePrimSize*m_texturePrimSize)
|
||||
materialName = GetOrCreateMaterial(renderer, faceColor, teFace.TextureID);
|
||||
else
|
||||
materialName = GetOrCreateMaterial(renderer, faceColor);
|
||||
|
||||
faceObj.transform(m);
|
||||
faceObj.setPos(primPos);
|
||||
@@ -517,10 +609,51 @@ namespace OpenSim.Region.CoreModules.World.Warp3DMap
|
||||
return name;
|
||||
}
|
||||
|
||||
public string GetOrCreateMaterial(WarpRenderer renderer, Color4 faceColor, UUID textureID)
|
||||
{
|
||||
string materialName = "Color-" + faceColor.ToString() + "-Texture-" + textureID.ToString();
|
||||
|
||||
if (renderer.Scene.material(materialName) == null)
|
||||
{
|
||||
renderer.AddMaterial(materialName, ConvertColor(faceColor));
|
||||
if (faceColor.A < 1f)
|
||||
{
|
||||
renderer.Scene.material(materialName).setTransparency((byte) ((1f - faceColor.A)*255f));
|
||||
}
|
||||
warp_Texture texture = GetTexture(textureID);
|
||||
if (texture != null)
|
||||
renderer.Scene.material(materialName).setTexture(texture);
|
||||
}
|
||||
|
||||
return materialName;
|
||||
}
|
||||
|
||||
private warp_Texture GetTexture(UUID id)
|
||||
{
|
||||
warp_Texture ret = null;
|
||||
byte[] asset = m_scene.AssetService.GetData(id.ToString());
|
||||
if (asset != null)
|
||||
{
|
||||
IJ2KDecoder imgDecoder = m_scene.RequestModuleInterface<IJ2KDecoder>();
|
||||
Bitmap img = (Bitmap) imgDecoder.DecodeToImage(asset);
|
||||
if (img != null)
|
||||
{
|
||||
return new warp_Texture(img);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endregion Rendering Methods
|
||||
|
||||
#region Static Helpers
|
||||
|
||||
// Note: axis change.
|
||||
private static warp_Vector ConvertVector(float x, float y, float z)
|
||||
{
|
||||
return new warp_Vector(x, z, y);
|
||||
}
|
||||
|
||||
private static warp_Vector ConvertVector(Vector3 vector)
|
||||
{
|
||||
return new warp_Vector(vector.X, vector.Z, vector.Y);
|
||||
|
||||
@@ -184,8 +184,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
data.Name = info.RegionName;
|
||||
data.RegionFlags = 0; // TODO not used?
|
||||
data.WaterHeight = 0; // not used
|
||||
data.X = (ushort)(info.RegionLocX / Constants.RegionSize);
|
||||
data.Y = (ushort)(info.RegionLocY / Constants.RegionSize);
|
||||
data.X = (ushort)Util.WorldToRegionLoc((uint)info.RegionLocX);
|
||||
data.Y = (ushort)Util.WorldToRegionLoc((uint)info.RegionLocY);
|
||||
blocks.Add(data);
|
||||
}
|
||||
}
|
||||
@@ -214,7 +214,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
// final block, closing the search result
|
||||
MapBlockData data = new MapBlockData();
|
||||
data.Agents = 0;
|
||||
data.Access = 255;
|
||||
data.Access = (byte)SimAccess.NonExistent;
|
||||
data.MapImageId = UUID.Zero;
|
||||
data.Name = "";
|
||||
data.RegionFlags = 0;
|
||||
|
||||
@@ -59,8 +59,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WorldMapModule")]
|
||||
public class WorldMapModule : INonSharedRegionModule, IWorldMapModule
|
||||
{
|
||||
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 = "[WORLD MAP]";
|
||||
|
||||
private static readonly string DEFAULT_WORLD_MAP_EXPORT_PATH = "exportmap.jpg";
|
||||
private static readonly UUID STOP_UUID = UUID.Random();
|
||||
@@ -282,15 +282,15 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
{
|
||||
List<MapBlockData> mapBlocks = new List<MapBlockData>(); ;
|
||||
|
||||
// Get regions that are within 8 regions of here
|
||||
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
|
||||
(int)(m_scene.RegionInfo.RegionLocX - 8) * (int)Constants.RegionSize,
|
||||
(int)(m_scene.RegionInfo.RegionLocX + 8) * (int)Constants.RegionSize,
|
||||
(int)(m_scene.RegionInfo.RegionLocY - 8) * (int)Constants.RegionSize,
|
||||
(int)(m_scene.RegionInfo.RegionLocY + 8) * (int)Constants.RegionSize);
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 8),
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 8),
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 8),
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 8) );
|
||||
foreach (GridRegion r in regions)
|
||||
{
|
||||
MapBlockData block = new MapBlockData();
|
||||
MapBlockFromGridRegion(block, r, 0);
|
||||
MapBlockData block = MapBlockFromGridRegion(r, 0);
|
||||
mapBlocks.Add(block);
|
||||
}
|
||||
avatarPresence.ControllingClient.SendMapBlock(mapBlocks, 0);
|
||||
@@ -410,24 +410,23 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
}
|
||||
uint xstart = 0;
|
||||
uint ystart = 0;
|
||||
Utils.LongToUInts(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
|
||||
if (itemtype == 6) // Service 6 right now (MAP_ITEM_AGENTS_LOCATION; green dots)
|
||||
Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle, out xstart, out ystart);
|
||||
if (itemtype == (int)GridItemType.AgentLocations)
|
||||
{
|
||||
if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
|
||||
{
|
||||
// Local Map Item Request
|
||||
// Just requesting map info about the current, local region
|
||||
int tc = Environment.TickCount;
|
||||
List<mapItemReply> mapitems = new List<mapItemReply>();
|
||||
mapItemReply mapitem = new mapItemReply();
|
||||
if (m_scene.GetRootAgentCount() <= 1)
|
||||
{
|
||||
mapitem = new mapItemReply();
|
||||
mapitem.x = (uint)(xstart + 1);
|
||||
mapitem.y = (uint)(ystart + 1);
|
||||
mapitem.id = UUID.Zero;
|
||||
mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
|
||||
mapitem.Extra = 0;
|
||||
mapitem.Extra2 = 0;
|
||||
mapitem = new mapItemReply(
|
||||
xstart + 1,
|
||||
ystart + 1,
|
||||
UUID.Zero,
|
||||
Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
|
||||
0, 0);
|
||||
mapitems.Add(mapitem);
|
||||
}
|
||||
else
|
||||
@@ -437,13 +436,12 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
// Don't send a green dot for yourself
|
||||
if (sp.UUID != remoteClient.AgentId)
|
||||
{
|
||||
mapitem = new mapItemReply();
|
||||
mapitem.x = (uint)(xstart + sp.AbsolutePosition.X);
|
||||
mapitem.y = (uint)(ystart + sp.AbsolutePosition.Y);
|
||||
mapitem.id = UUID.Zero;
|
||||
mapitem.name = Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString());
|
||||
mapitem.Extra = 1;
|
||||
mapitem.Extra2 = 0;
|
||||
mapitem = new mapItemReply(
|
||||
xstart + (uint)sp.AbsolutePosition.X,
|
||||
ystart + (uint)sp.AbsolutePosition.Y,
|
||||
UUID.Zero,
|
||||
Util.Md5Hash(m_scene.RegionInfo.RegionName + tc.ToString()),
|
||||
1, 0);
|
||||
mapitems.Add(mapitem);
|
||||
}
|
||||
});
|
||||
@@ -458,7 +456,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
|
||||
}
|
||||
}
|
||||
else if (itemtype == 7) // Service 7 (MAP_ITEM_LAND_FOR_SALE)
|
||||
else if (itemtype == (int)GridItemType.LandForSale) // Service 7 (MAP_ITEM_LAND_FOR_SALE)
|
||||
{
|
||||
if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
|
||||
{
|
||||
@@ -488,14 +486,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
float x = (min.X+max.X)/2;
|
||||
float y = (min.Y+max.Y)/2;
|
||||
|
||||
mapitem = new mapItemReply();
|
||||
mapitem.x = (uint)(xstart + x);
|
||||
mapitem.y = (uint)(ystart + y);
|
||||
// mapitem.z = (uint)m_scene.GetGroundHeight(x,y);
|
||||
mapitem.id = parcel.GlobalID;
|
||||
mapitem.name = parcel.Name;
|
||||
mapitem.Extra = parcel.Area;
|
||||
mapitem.Extra2 = parcel.SalePrice;
|
||||
mapitem = new mapItemReply(
|
||||
xstart + (uint)x,
|
||||
ystart + (uint)y,
|
||||
parcel.GlobalID,
|
||||
parcel.Name,
|
||||
parcel.Area,
|
||||
parcel.SalePrice
|
||||
);
|
||||
mapitems.Add(mapitem);
|
||||
}
|
||||
}
|
||||
@@ -510,7 +508,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
RequestMapItems("",remoteClient.AgentId,flags,EstateID,godlike,itemtype,regionhandle);
|
||||
}
|
||||
}
|
||||
else if (itemtype == 1) // Service 1 (MAP_ITEM_TELEHUB)
|
||||
else if (itemtype == (int)GridItemType.Telehub) // Service 1 (MAP_ITEM_TELEHUB)
|
||||
{
|
||||
if (regionhandle == 0 || regionhandle == m_scene.RegionInfo.RegionHandle)
|
||||
{
|
||||
@@ -520,13 +518,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
SceneObjectGroup sog = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
|
||||
if (sog != null)
|
||||
{
|
||||
mapitem = new mapItemReply();
|
||||
mapitem.x = (uint)(xstart + sog.AbsolutePosition.X);
|
||||
mapitem.y = (uint)(ystart + sog.AbsolutePosition.Y);
|
||||
mapitem.id = UUID.Zero;
|
||||
mapitem.name = sog.Name;
|
||||
mapitem.Extra = 0; // color (not used)
|
||||
mapitem.Extra2 = 0; // 0 = telehub / 1 = infohub
|
||||
mapitem = new mapItemReply(
|
||||
xstart + (uint)sog.AbsolutePosition.X,
|
||||
ystart + (uint)sog.AbsolutePosition.Y,
|
||||
UUID.Zero,
|
||||
sog.Name,
|
||||
0, // color (not used)
|
||||
0 // 0 = telehub / 1 = infohub
|
||||
);
|
||||
mapitems.Add(mapitem);
|
||||
|
||||
remoteClient.SendMapItemReply(mapitems.ToArray(), itemtype, flags);
|
||||
@@ -676,19 +675,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
{
|
||||
OSDMap mapitem = (OSDMap)itemarray[i];
|
||||
mapItemReply mi = new mapItemReply();
|
||||
mi.x = (uint)mapitem["X"].AsInteger();
|
||||
mi.y = (uint)mapitem["Y"].AsInteger();
|
||||
mi.id = mapitem["ID"].AsUUID();
|
||||
mi.Extra = mapitem["Extra"].AsInteger();
|
||||
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
||||
mi.name = mapitem["Name"].AsString();
|
||||
mi.FromOSD(mapitem);
|
||||
returnitems.Add(mi);
|
||||
}
|
||||
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), mrs.itemtype, mrs.flags);
|
||||
}
|
||||
|
||||
// Service 7 (MAP_ITEM_LAND_FOR_SALE)
|
||||
uint itemtype = 7;
|
||||
uint itemtype = (uint)GridItemType.LandForSale;
|
||||
|
||||
if (response.ContainsKey(itemtype.ToString()))
|
||||
{
|
||||
@@ -698,19 +692,14 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
{
|
||||
OSDMap mapitem = (OSDMap)itemarray[i];
|
||||
mapItemReply mi = new mapItemReply();
|
||||
mi.x = (uint)mapitem["X"].AsInteger();
|
||||
mi.y = (uint)mapitem["Y"].AsInteger();
|
||||
mi.id = mapitem["ID"].AsUUID();
|
||||
mi.Extra = mapitem["Extra"].AsInteger();
|
||||
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
||||
mi.name = mapitem["Name"].AsString();
|
||||
mi.FromOSD(mapitem);
|
||||
returnitems.Add(mi);
|
||||
}
|
||||
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
|
||||
}
|
||||
|
||||
// Service 1 (MAP_ITEM_TELEHUB)
|
||||
itemtype = 1;
|
||||
itemtype = (uint)GridItemType.Telehub;
|
||||
|
||||
if (response.ContainsKey(itemtype.ToString()))
|
||||
{
|
||||
@@ -720,12 +709,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
{
|
||||
OSDMap mapitem = (OSDMap)itemarray[i];
|
||||
mapItemReply mi = new mapItemReply();
|
||||
mi.x = (uint)mapitem["X"].AsInteger();
|
||||
mi.y = (uint)mapitem["Y"].AsInteger();
|
||||
mi.id = mapitem["ID"].AsUUID();
|
||||
mi.Extra = mapitem["Extra"].AsInteger();
|
||||
mi.Extra2 = mapitem["Extra2"].AsInteger();
|
||||
mi.name = mapitem["Name"].AsString();
|
||||
mi.FromOSD(mapitem);
|
||||
returnitems.Add(mi);
|
||||
}
|
||||
av.ControllingClient.SendMapItemReply(returnitems.ToArray(), itemtype, mrs.flags);
|
||||
@@ -808,7 +792,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
if (httpserver.Length == 0)
|
||||
{
|
||||
uint x = 0, y = 0;
|
||||
Utils.LongToUInts(regionhandle, out x, out y);
|
||||
Util.RegionHandleToWorldLoc(regionhandle, out x, out y);
|
||||
GridRegion mreg = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
|
||||
|
||||
if (mreg != null)
|
||||
@@ -915,7 +899,7 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
finally
|
||||
{
|
||||
if (os != null)
|
||||
os.Close();
|
||||
os.Dispose();
|
||||
}
|
||||
|
||||
string response_mapItems_reply = null;
|
||||
@@ -1007,7 +991,6 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
/// <param name="maxY"></param>
|
||||
public virtual void RequestMapBlocks(IClientAPI remoteClient, int minX, int minY, int maxX, int maxY, uint flag)
|
||||
{
|
||||
//m_log.ErrorFormat("[YYY] RequestMapBlocks {0}={1}={2}={3} {4}", minX, minY, maxX, maxY, flag);
|
||||
if ((flag & 0x10000) != 0) // user clicked on qthe map a tile that isn't visible
|
||||
{
|
||||
List<MapBlockData> response = new List<MapBlockData>();
|
||||
@@ -1016,22 +999,24 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
// on an unloaded square.
|
||||
// But make sure: Look whether the one we requested is in there
|
||||
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
|
||||
minX * (int)Constants.RegionSize,
|
||||
maxX * (int)Constants.RegionSize,
|
||||
minY * (int)Constants.RegionSize,
|
||||
maxY * (int)Constants.RegionSize);
|
||||
(int)Util.RegionToWorldLoc((uint)minX), (int)Util.RegionToWorldLoc((uint)maxX),
|
||||
(int)Util.RegionToWorldLoc((uint)minY), (int)Util.RegionToWorldLoc((uint)maxY) );
|
||||
|
||||
m_log.DebugFormat("[WORLD MAP MODULE] RequestMapBlocks min=<{0},{1}>, max=<{2},{3}>, flag={4}, cntFound={5}",
|
||||
minX, minY, maxX, maxY, flag.ToString("X"), regions.Count);
|
||||
if (regions != null)
|
||||
{
|
||||
foreach (GridRegion r in regions)
|
||||
{
|
||||
if ((r.RegionLocX == minX * (int)Constants.RegionSize) &&
|
||||
(r.RegionLocY == minY * (int)Constants.RegionSize))
|
||||
if (r.RegionLocX == Util.RegionToWorldLoc((uint)minX)
|
||||
&& r.RegionLocY == Util.RegionToWorldLoc((uint)minY) )
|
||||
{
|
||||
// found it => add it to response
|
||||
MapBlockData block = new MapBlockData();
|
||||
MapBlockFromGridRegion(block, r, flag);
|
||||
response.Add(block);
|
||||
// Version 2 viewers can handle the larger regions
|
||||
if ((flag & 2) == 2)
|
||||
response.AddRange(Map2BlockFromGridRegion(r, flag));
|
||||
else
|
||||
response.Add(MapBlockFromGridRegion(r, flag));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1043,7 +1028,8 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
MapBlockData block = new MapBlockData();
|
||||
block.X = (ushort)minX;
|
||||
block.Y = (ushort)minY;
|
||||
block.Access = 254; // means 'simulator is offline'
|
||||
block.Access = (byte)SimAccess.Down; // means 'simulator is offline'
|
||||
// block.Access = (byte)SimAccess.NonExistant;
|
||||
response.Add(block);
|
||||
}
|
||||
// The lower 16 bits are an unsigned int16
|
||||
@@ -1060,41 +1046,112 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
{
|
||||
List<MapBlockData> mapBlocks = new List<MapBlockData>();
|
||||
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
|
||||
(minX - 4) * (int)Constants.RegionSize,
|
||||
(maxX + 4) * (int)Constants.RegionSize,
|
||||
(minY - 4) * (int)Constants.RegionSize,
|
||||
(maxY + 4) * (int)Constants.RegionSize);
|
||||
(int)Util.RegionToWorldLoc((uint)(minX - 4)), (int)Util.RegionToWorldLoc((uint)(maxX + 4)),
|
||||
(int)Util.RegionToWorldLoc((uint)(minY - 4)), (int)Util.RegionToWorldLoc((uint)(maxY + 4)) );
|
||||
m_log.DebugFormat("{0} GetAndSendBlocks. min=<{1},{2}>, max=<{3},{4}>, cntFound={5}",
|
||||
LogHeader, minX, minY, maxX, maxY, regions.Count);
|
||||
foreach (GridRegion r in regions)
|
||||
{
|
||||
MapBlockData block = new MapBlockData();
|
||||
MapBlockFromGridRegion(block, r, flag);
|
||||
mapBlocks.Add(block);
|
||||
// Version 2 viewers can handle the larger regions
|
||||
if ((flag & 2) == 2)
|
||||
mapBlocks.AddRange(Map2BlockFromGridRegion(r, flag));
|
||||
else
|
||||
mapBlocks.Add(MapBlockFromGridRegion(r, flag));
|
||||
}
|
||||
remoteClient.SendMapBlock(mapBlocks, flag & 0xffff);
|
||||
|
||||
return mapBlocks;
|
||||
}
|
||||
|
||||
protected void MapBlockFromGridRegion(MapBlockData block, GridRegion r, uint flag)
|
||||
// Fill a passed MapBlockData from a GridRegion
|
||||
protected MapBlockData MapBlockFromGridRegion(GridRegion r, uint flag)
|
||||
{
|
||||
MapBlockData block = new MapBlockData();
|
||||
|
||||
block.Access = r.Access;
|
||||
switch (flag & 0xffff)
|
||||
{
|
||||
case 0:
|
||||
block.MapImageId = r.TerrainImage;
|
||||
break;
|
||||
case 2:
|
||||
block.MapImageId = r.ParcelImage;
|
||||
break;
|
||||
default:
|
||||
block.MapImageId = UUID.Zero;
|
||||
break;
|
||||
case 0:
|
||||
block.MapImageId = r.TerrainImage;
|
||||
break;
|
||||
case 2:
|
||||
block.MapImageId = r.ParcelImage;
|
||||
break;
|
||||
default:
|
||||
block.MapImageId = UUID.Zero;
|
||||
break;
|
||||
}
|
||||
block.Name = r.RegionName;
|
||||
block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
|
||||
block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
|
||||
block.X = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocX);
|
||||
block.Y = (ushort)Util.WorldToRegionLoc((uint)r.RegionLocY);
|
||||
block.SizeX = (ushort) r.RegionSizeX;
|
||||
block.SizeY = (ushort) r.RegionSizeY;
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
protected List<MapBlockData> Map2BlockFromGridRegion(GridRegion r, uint flag)
|
||||
{
|
||||
List<MapBlockData> blocks = new List<MapBlockData>();
|
||||
MapBlockData block = new MapBlockData();
|
||||
if (r == null)
|
||||
{
|
||||
block.Access = (byte)SimAccess.Down;
|
||||
block.MapImageId = UUID.Zero;
|
||||
blocks.Add(block);
|
||||
}
|
||||
else
|
||||
{
|
||||
block.Access = r.Access;
|
||||
switch (flag & 0xffff)
|
||||
{
|
||||
case 0:
|
||||
block.MapImageId = r.TerrainImage;
|
||||
break;
|
||||
case 2:
|
||||
block.MapImageId = r.ParcelImage;
|
||||
break;
|
||||
default:
|
||||
block.MapImageId = UUID.Zero;
|
||||
break;
|
||||
}
|
||||
block.Name = r.RegionName;
|
||||
block.X = (ushort)(r.RegionLocX / Constants.RegionSize);
|
||||
block.Y = (ushort)(r.RegionLocY / Constants.RegionSize);
|
||||
block.SizeX = (ushort)r.RegionSizeX;
|
||||
block.SizeY = (ushort)r.RegionSizeY;
|
||||
blocks.Add(block);
|
||||
// If these are larger than legacy regions, create fake map entries for the covered
|
||||
// regions. The map system only does legacy sized regions so we have to fake map
|
||||
// entries for all the covered regions.
|
||||
if (r.RegionSizeX > Constants.RegionSize || r.RegionSizeY > Constants.RegionSize)
|
||||
{
|
||||
for (int x = 0; x < r.RegionSizeX / Constants.RegionSize; x++)
|
||||
{
|
||||
for (int y = 0; y < r.RegionSizeY / Constants.RegionSize; y++)
|
||||
{
|
||||
if (x == 0 && y == 0)
|
||||
continue;
|
||||
block = new MapBlockData
|
||||
{
|
||||
Access = r.Access,
|
||||
MapImageId = r.TerrainImage,
|
||||
Name = r.RegionName,
|
||||
X = (ushort)((r.RegionLocX / Constants.RegionSize) + x),
|
||||
Y = (ushort)((r.RegionLocY / Constants.RegionSize) + y),
|
||||
SizeX = (ushort)r.RegionSizeX,
|
||||
SizeY = (ushort)r.RegionSizeY
|
||||
};
|
||||
//Child piece, so ignore it
|
||||
blocks.Add(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
|
||||
public Hashtable OnHTTPThrottled(Hashtable keysvals)
|
||||
{
|
||||
Hashtable reply = new Hashtable();
|
||||
@@ -1223,17 +1280,16 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
|
||||
List<MapBlockData> mapBlocks = new List<MapBlockData>();
|
||||
List<GridRegion> regions = m_scene.GridService.GetRegionRange(m_scene.RegionInfo.ScopeID,
|
||||
(int)(m_scene.RegionInfo.RegionLocX - 9) * (int)Constants.RegionSize,
|
||||
(int)(m_scene.RegionInfo.RegionLocX + 9) * (int)Constants.RegionSize,
|
||||
(int)(m_scene.RegionInfo.RegionLocY - 9) * (int)Constants.RegionSize,
|
||||
(int)(m_scene.RegionInfo.RegionLocY + 9) * (int)Constants.RegionSize);
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX - 9),
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocX + 9),
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY - 9),
|
||||
(int)Util.RegionToWorldLoc(m_scene.RegionInfo.RegionLocY + 9));
|
||||
List<AssetBase> textures = new List<AssetBase>();
|
||||
List<Image> bitImages = new List<Image>();
|
||||
|
||||
foreach (GridRegion r in regions)
|
||||
{
|
||||
MapBlockData mapBlock = new MapBlockData();
|
||||
MapBlockFromGridRegion(mapBlock, r, 0);
|
||||
MapBlockData mapBlock = MapBlockFromGridRegion(r, 0);
|
||||
AssetBase texAsset = m_scene.AssetService.Get(mapBlock.MapImageId.ToString());
|
||||
|
||||
if (texAsset != null)
|
||||
@@ -1294,7 +1350,9 @@ namespace OpenSim.Region.CoreModules.World.WorldMap
|
||||
uint xstart = 0;
|
||||
uint ystart = 0;
|
||||
|
||||
Utils.LongToUInts(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
|
||||
Util.RegionHandleToWorldLoc(m_scene.RegionInfo.RegionHandle,out xstart,out ystart);
|
||||
// m_log.DebugFormat("{0} HandleRemoteMapItemRequest. loc=<{1},{2}>",
|
||||
// LogHeader, Util.WorldToRegionLoc(xstart), Util.WorldToRegionLoc(ystart));
|
||||
|
||||
// Service 6 (MAP_ITEM_AGENTS_LOCATION; green dots)
|
||||
|
||||
|
||||
@@ -92,12 +92,12 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
|
||||
void EnableChildAgent(ScenePresence agent, GridRegion region);
|
||||
|
||||
GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out uint xDest, out uint yDest, out string version, out Vector3 newpos);
|
||||
GridRegion GetDestination(Scene scene, UUID agentID, Vector3 pos, out string version,
|
||||
out Vector3 newpos, out string reason);
|
||||
|
||||
void Cross(SceneObjectGroup sog, Vector3 position, bool silent);
|
||||
|
||||
ScenePresence CrossAgentToNewRegionAsync(ScenePresence agent, Vector3 pos, GridRegion neighbourRegion, bool isFlying, string version);
|
||||
|
||||
}
|
||||
|
||||
public interface IUserAgentVerificationModule
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
@@ -25,6 +25,7 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System.Drawing;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.Imaging;
|
||||
|
||||
@@ -53,5 +54,12 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// <param name="components">number of components</param>
|
||||
/// <returns>true if decode was successful. false otherwise.</returns>
|
||||
bool Decode(UUID assetID, byte[] j2kData, out OpenJPEG.J2KLayerInfo[] layers, out int components);
|
||||
|
||||
/// <summary>
|
||||
/// Provides a synchronous decode direct to an image object
|
||||
/// </summary>
|
||||
/// <param name="j2kData"></param>
|
||||
/// <returns>decoded image or 'null' of unsuccessful</returns>
|
||||
Image DecodeToImage(byte[] j2kData);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,32 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
UUID owner, bool senseAsAgent, Scene scene,
|
||||
AvatarAppearance appearance);
|
||||
|
||||
/// <summary>
|
||||
/// Create an NPC with a user-supplied agentID
|
||||
/// </summary>
|
||||
/// <param name="firstname"></param>
|
||||
/// <param name="lastname"></param>
|
||||
/// <param name="position"></param>
|
||||
/// <param name="agentID"></param>
|
||||
/// The desired agent ID
|
||||
/// <param name="owner"></param>
|
||||
/// <param name="senseAsAgent">
|
||||
/// Make the NPC show up as an agent on LSL sensors. The default is
|
||||
/// that they show up as the NPC type instead, but this is currently
|
||||
/// an OpenSim-only extension.
|
||||
/// </param>
|
||||
/// <param name="scene"></param>
|
||||
/// <param name="appearance">
|
||||
/// The avatar appearance to use for the new NPC.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The UUID of the ScenePresence created. UUID.Zero if there was a
|
||||
/// failure.
|
||||
/// </returns>
|
||||
UUID CreateNPC(string firstname, string lastname,
|
||||
Vector3 position, UUID agentID, UUID owner, bool senseAsAgent, Scene scene,
|
||||
AvatarAppearance appearance);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the agent is an NPC.
|
||||
/// </summary>
|
||||
|
||||
@@ -29,6 +29,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.Framework.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
@@ -100,16 +102,11 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event.
|
||||
///
|
||||
/// <param name="loadPath"></param>
|
||||
/// <param name="merge">
|
||||
/// If true, the loaded region merges with the existing one rather than replacing it. Any terrain or region
|
||||
/// settings in the archive will be ignored.
|
||||
/// </param>
|
||||
/// <param name="skipAssets">
|
||||
/// If true, the archive is loaded without loading any assets contained within it. This is useful if the
|
||||
/// assets are already known to be present in the grid's asset service.
|
||||
/// </param>
|
||||
/// <param name="requestId">If supplied, this request Id is later returned in the saved event</param>
|
||||
void DearchiveRegion(string loadPath, bool merge, bool skipAssets, Guid requestId);
|
||||
/// <param name="options">
|
||||
/// Dictionary of options.
|
||||
/// </param>
|
||||
void DearchiveRegion(string loadPath, Guid requestId, Dictionary<string,object> options);
|
||||
|
||||
/// <summary>
|
||||
/// Dearchive a region from a stream. This replaces the existing scene.
|
||||
@@ -127,15 +124,10 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event.
|
||||
///
|
||||
/// <param name="loadStream"></param>
|
||||
/// <param name="merge">
|
||||
/// If true, the loaded region merges with the existing one rather than replacing it. Any terrain or region
|
||||
/// settings in the archive will be ignored.
|
||||
/// </param>
|
||||
/// <param name="skipAssets">
|
||||
/// If true, the archive is loaded without loading any assets contained within it. This is useful if the
|
||||
/// assets are already known to be present in the grid's asset service.
|
||||
/// </param
|
||||
/// <param name="requestId">If supplied, this request Id is later returned in the saved event</param>
|
||||
void DearchiveRegion(Stream loadStream, bool merge, bool skipAssets, Guid requestId);
|
||||
/// <param name="options">
|
||||
/// Dictionary of options.
|
||||
/// </param>
|
||||
void DearchiveRegion(Stream loadStream, Guid requestId, Dictionary<string,object> options);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,5 +55,10 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// Currently, will throw an exception if this does not match a root region.
|
||||
/// </param>
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -68,13 +68,22 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// </summary>
|
||||
/// <param name="ter">HeightField data</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);
|
||||
|
||||
/// <summary>
|
||||
/// Load the latest terrain revision from region storage
|
||||
/// </summary>
|
||||
/// <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>
|
||||
TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ);
|
||||
|
||||
// Legacy version kept for downward compabibility
|
||||
double[,] LoadTerrain(UUID regionID);
|
||||
|
||||
void StoreLandObject(ILandObject Parcel);
|
||||
|
||||
@@ -79,13 +79,22 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// </summary>
|
||||
/// <param name="ter">HeightField data</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);
|
||||
|
||||
/// <summary>
|
||||
/// Load the latest terrain revision from region storage
|
||||
/// </summary>
|
||||
/// <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>
|
||||
TerrainData LoadTerrain(UUID regionID, int pSizeX, int pSizeY, int pSizeZ);
|
||||
|
||||
// Legacy version kept for downward compabibility
|
||||
double[,] LoadTerrain(UUID regionID);
|
||||
|
||||
void StoreLandObject(ILandObject Parcel);
|
||||
@@ -135,4 +144,5 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
|
||||
void Shutdown();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,13 +25,23 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using OpenSim.Framework;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Region.Framework.Interfaces
|
||||
{
|
||||
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; }
|
||||
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>
|
||||
/// Squash the entire heightmap into a single dimensioned array
|
||||
@@ -40,9 +50,14 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
float[] GetFloatsSerialised();
|
||||
|
||||
double[,] GetDoubles();
|
||||
|
||||
// Check if a location has been updated. Clears the taint flag as a side effect.
|
||||
bool Tainted(int x, int y);
|
||||
|
||||
ITerrainChannel MakeCopy();
|
||||
string SaveToXmlString();
|
||||
void LoadFromXmlString(string data);
|
||||
// Merge some terrain into this channel
|
||||
void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// </param>
|
||||
/// <param name="stream"></param>
|
||||
void LoadFromStream(string filename, Stream stream);
|
||||
void LoadFromStream(string filename, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement, Stream stream);
|
||||
void LoadFromStream(string filename, System.Uri pathToTerrainHeightmap);
|
||||
/// <summary>
|
||||
/// Save a terrain to a stream.
|
||||
|
||||
@@ -46,8 +46,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
public partial class Scene
|
||||
{
|
||||
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 = "[SCENE INVENTORY]";
|
||||
|
||||
/// <summary>
|
||||
/// Allows asynchronous derezzing of objects from the scene into a client's inventory.
|
||||
|
||||
@@ -160,11 +160,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// </summary>
|
||||
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>
|
||||
/// Controls whether physics can be applied to prims. Even if false, prims still have entries in a
|
||||
/// PhysicsScene in order to perform collision detection
|
||||
@@ -349,7 +344,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
// TODO: Possibly stop other classes being able to manipulate this directly.
|
||||
private SceneGraph m_sceneGraph;
|
||||
private volatile int m_bordersLocked;
|
||||
private readonly Timer m_restartTimer = new Timer(15000); // Wait before firing
|
||||
private volatile bool m_backingup;
|
||||
private Dictionary<UUID, ReturnInfo> m_returns = new Dictionary<UUID, ReturnInfo>();
|
||||
@@ -426,18 +420,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
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
|
||||
{
|
||||
get { return m_sceneGraph.PhysicsScene.TimeDilation; }
|
||||
@@ -1031,28 +1013,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
PeriodicBackup = true;
|
||||
UseBackup = true;
|
||||
|
||||
BordersLocked = true;
|
||||
Border northBorder = new Border();
|
||||
northBorder.BorderLine = new Vector3(float.MinValue, float.MaxValue, (int)Constants.RegionSize); //<---
|
||||
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, (int)Constants.RegionSize); //<---
|
||||
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_permissions = new ScenePermissions(this);
|
||||
@@ -1099,8 +1059,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <returns>True after all operations complete, throws exceptions otherwise.</returns>
|
||||
public override void OtherRegionUp(GridRegion otherRegion)
|
||||
{
|
||||
uint xcell = (uint)((int)otherRegion.RegionLocX / (int)Constants.RegionSize);
|
||||
uint ycell = (uint)((int)otherRegion.RegionLocY / (int)Constants.RegionSize);
|
||||
uint xcell = Util.WorldToRegionLoc((uint)otherRegion.RegionLocX);
|
||||
uint ycell = Util.WorldToRegionLoc((uint)otherRegion.RegionLocY);
|
||||
|
||||
//m_log.InfoFormat("[SCENE]: (on region {0}): Region {1} up in coords {2}-{3}",
|
||||
// RegionInfo.RegionName, otherRegion.RegionName, xcell, ycell);
|
||||
|
||||
@@ -1172,46 +1133,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
return found;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether this region has a neighbour in the given direction.
|
||||
/// </summary>
|
||||
/// <param name="car"></param>
|
||||
/// <param name="fix"></param>
|
||||
/// <returns>
|
||||
/// An integer which represents a compass point. N == 1, going clockwise until we reach NW == 8.
|
||||
/// Returns a positive integer if there is a region in that direction, a negative integer if not.
|
||||
/// </returns>
|
||||
public int HaveNeighbor(Cardinals car, ref int[] fix)
|
||||
{
|
||||
uint neighbourx = RegionInfo.RegionLocX;
|
||||
uint neighboury = RegionInfo.RegionLocY;
|
||||
|
||||
int dir = (int)car;
|
||||
|
||||
if (dir > 1 && dir < 5) //Heading East
|
||||
neighbourx++;
|
||||
else if (dir > 5) // Heading West
|
||||
neighbourx--;
|
||||
|
||||
if (dir < 3 || dir == 8) // Heading North
|
||||
neighboury++;
|
||||
else if (dir > 3 && dir < 7) // Heading Sout
|
||||
neighboury--;
|
||||
|
||||
int x = (int)(neighbourx * Constants.RegionSize);
|
||||
int y = (int)(neighboury * Constants.RegionSize);
|
||||
GridRegion neighbourRegion = GridService.GetRegionByPosition(RegionInfo.ScopeID, x, y);
|
||||
|
||||
if (neighbourRegion == null)
|
||||
{
|
||||
fix[0] = (int)(RegionInfo.RegionLocX - neighbourx);
|
||||
fix[1] = (int)(RegionInfo.RegionLocY - neighboury);
|
||||
return dir * (-1);
|
||||
}
|
||||
else
|
||||
return dir;
|
||||
}
|
||||
|
||||
// Alias IncomingHelloNeighbour OtherRegionUp, for now
|
||||
public GridRegion IncomingHelloNeighbour(RegionInfo neighbour)
|
||||
{
|
||||
@@ -1894,7 +1815,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
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)
|
||||
{
|
||||
// This should be in the Terrain module, but it isn't because
|
||||
@@ -1905,7 +1826,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
m_InitialTerrain = terrainConfig.GetString("InitialTerrain", 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);
|
||||
}
|
||||
@@ -2483,185 +2404,35 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
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)
|
||||
{
|
||||
case Cardinals.N:
|
||||
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;
|
||||
|
||||
}
|
||||
// Regular region. Just check for region size
|
||||
if (xx < RegionInfo.RegionSizeX || yy < RegionInfo.RegionSizeY )
|
||||
ret = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (gridline)
|
||||
{
|
||||
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;
|
||||
|
||||
}
|
||||
// We're in a mega-region so see if we are still in that larger region
|
||||
ret = regionCombinerModule.PositionIsInMegaregion(this.RegionInfo.RegionID, xx, yy);
|
||||
}
|
||||
|
||||
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>
|
||||
/// Called when objects or attachments cross the border, or teleport, between regions.
|
||||
/// </summary>
|
||||
@@ -3896,60 +3667,11 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
// CleanDroppedAttachments();
|
||||
|
||||
if (TestBorderCross(acd.startpos, Cardinals.E))
|
||||
{
|
||||
Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E);
|
||||
acd.startpos.X = crossedBorder.BorderLine.Z - 1;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
// 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;
|
||||
if (acd.startpos.X >= RegionInfo.RegionSizeX) acd.startpos.X = RegionInfo.RegionSizeX - 1f;
|
||||
if (acd.startpos.Y < 0) acd.startpos.Y = 1f;
|
||||
if (acd.startpos.Y >= RegionInfo.RegionSizeY) acd.startpos.Y = RegionInfo.RegionSizeY - 1f;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE]: Found telehub object {0} for new user connection {1} to {2}",
|
||||
@@ -4019,12 +3741,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
if (posX < 0)
|
||||
posX = 0;
|
||||
else if (posX >= 256)
|
||||
posX = 255.999f;
|
||||
else if (posX >= (float)RegionInfo.RegionSizeX)
|
||||
posX = (float)RegionInfo.RegionSizeX - 0.001f;
|
||||
if (posY < 0)
|
||||
posY = 0;
|
||||
else if (posY >= 256)
|
||||
posY = 255.999f;
|
||||
else if (posY >= (float)RegionInfo.RegionSizeY)
|
||||
posY = (float)RegionInfo.RegionSizeY - 0.001f;
|
||||
|
||||
reason = String.Empty;
|
||||
if (Permissions.IsGod(agentID))
|
||||
@@ -4318,7 +4040,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
"[SCENE]: Incoming child agent update for {0} in {1}", cAgentData.AgentID, RegionInfo.RegionName);
|
||||
|
||||
// TODO: This check should probably be in QueryAccess().
|
||||
ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, Constants.RegionSize / 2, Constants.RegionSize / 2);
|
||||
ILandObject nearestParcel = GetNearestAllowedParcel(cAgentData.AgentID, RegionInfo.RegionSizeX / 2, RegionInfo.RegionSizeY / 2);
|
||||
if (nearestParcel == null)
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
@@ -4613,44 +4335,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
ScenePresence sp = GetScenePresence(remoteClient.AgentId);
|
||||
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)
|
||||
{
|
||||
EntityTransferModule.Teleport(sp, regionHandle, position, lookAt, teleportFlags);
|
||||
@@ -4830,7 +4514,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
else
|
||||
{
|
||||
|
||||
if (pos.X > 0f && pos.X < Constants.RegionSize && pos.Y > 0f && pos.Y < Constants.RegionSize)
|
||||
if (pos.X > 0f && pos.X < RegionInfo.RegionSizeX && pos.Y > 0f && pos.Y < RegionInfo.RegionSizeY)
|
||||
{
|
||||
// The only time parcel != null when an object is inside a region is when
|
||||
// there is nothing behind the landchannel. IE, no land plugin loaded.
|
||||
@@ -5491,7 +5175,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
Vector3 unitDirection = Vector3.Normalize(direction);
|
||||
//Making distance to search go through some sane limit of distance
|
||||
for (float distance = 0; distance < Constants.RegionSize * 2; distance += .5f)
|
||||
for (float distance = 0; distance < Math.Max(RegionInfo.RegionSizeX, RegionInfo.RegionSizeY) * 2; distance += .5f)
|
||||
{
|
||||
Vector3 testPos = Vector3.Add(pos, Vector3.Multiply(unitDirection, distance));
|
||||
if (parcel.ContainsPoint((int)testPos.X, (int)testPos.Y))
|
||||
@@ -5545,9 +5229,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
int count = 0;
|
||||
int avgx = 0;
|
||||
int avgy = 0;
|
||||
for (int x = 0; x < Constants.RegionSize; x++)
|
||||
for (int x = 0; x < RegionInfo.RegionSizeX; x++)
|
||||
{
|
||||
for (int y = 0; y < Constants.RegionSize; y++)
|
||||
for (int y = 0; y < RegionInfo.RegionSizeY; y++)
|
||||
{
|
||||
//Just keep a running average as we check if all the points are inside or not
|
||||
if (parcel.ContainsPoint(x, y))
|
||||
@@ -5571,31 +5255,33 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
private Vector3 GetNearestRegionEdgePosition(ScenePresence avatar)
|
||||
{
|
||||
float xdistance = avatar.AbsolutePosition.X < Constants.RegionSize / 2 ? avatar.AbsolutePosition.X : Constants.RegionSize - avatar.AbsolutePosition.X;
|
||||
float ydistance = avatar.AbsolutePosition.Y < Constants.RegionSize / 2 ? avatar.AbsolutePosition.Y : Constants.RegionSize - avatar.AbsolutePosition.Y;
|
||||
float xdistance = avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2
|
||||
? avatar.AbsolutePosition.X : RegionInfo.RegionSizeX - avatar.AbsolutePosition.X;
|
||||
float ydistance = avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2
|
||||
? avatar.AbsolutePosition.Y : RegionInfo.RegionSizeY - avatar.AbsolutePosition.Y;
|
||||
|
||||
//find out what vertical edge to go to
|
||||
if (xdistance < ydistance)
|
||||
{
|
||||
if (avatar.AbsolutePosition.X < Constants.RegionSize / 2)
|
||||
if (avatar.AbsolutePosition.X < RegionInfo.RegionSizeX / 2)
|
||||
{
|
||||
return GetPositionAtAvatarHeightOrGroundHeight(avatar, 0.0f, avatar.AbsolutePosition.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetPositionAtAvatarHeightOrGroundHeight(avatar, Constants.RegionSize, avatar.AbsolutePosition.Y);
|
||||
return GetPositionAtAvatarHeightOrGroundHeight(avatar, RegionInfo.RegionSizeY, avatar.AbsolutePosition.Y);
|
||||
}
|
||||
}
|
||||
//find out what horizontal edge to go to
|
||||
else
|
||||
{
|
||||
if (avatar.AbsolutePosition.Y < Constants.RegionSize / 2)
|
||||
if (avatar.AbsolutePosition.Y < RegionInfo.RegionSizeY / 2)
|
||||
{
|
||||
return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, Constants.RegionSize);
|
||||
return GetPositionAtAvatarHeightOrGroundHeight(avatar, avatar.AbsolutePosition.X, RegionInfo.RegionSizeY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,8 +42,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
public abstract class SceneBase : IScene
|
||||
{
|
||||
protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
protected static readonly string LogHeader = "[SCENE]";
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly string LogHeader = "[SCENE]";
|
||||
|
||||
#region Events
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[SCENE COMMUNICATION SERVICE]: Region {0} successfully informed neighbour {1} at {2}-{3} that it is up",
|
||||
m_scene.Name, neighbour.RegionName, x / Constants.RegionSize, y / Constants.RegionSize);
|
||||
m_scene.Name, neighbour.RegionName, Util.WorldToRegionLoc(x), Util.WorldToRegionLoc(y));
|
||||
|
||||
m_scene.EventManager.TriggerOnRegionUp(neighbour);
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[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 +166,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// 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
|
||||
// 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);
|
||||
if (dest == null)
|
||||
continue;
|
||||
@@ -203,7 +203,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
//m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
|
||||
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);
|
||||
|
||||
|
||||
@@ -334,7 +334,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
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 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
|
||||
|
||||
@@ -429,7 +429,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// <returns></returns>
|
||||
public bool IsAttachmentCheckFull()
|
||||
{
|
||||
return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
|
||||
return (IsAttachment || (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0));
|
||||
}
|
||||
|
||||
private struct avtocrossInfo
|
||||
@@ -451,25 +451,15 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (Scene != null)
|
||||
{
|
||||
if (
|
||||
// (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E)
|
||||
// || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
|
||||
// || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N)
|
||||
// || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
|
||||
// Experimental change for better border crossings.
|
||||
// The commented out original lines above would, it seems, trigger
|
||||
// a border crossing a little early or late depending on which
|
||||
// direction the object was moving.
|
||||
(Scene.TestBorderCross(val, Cardinals.E)
|
||||
|| Scene.TestBorderCross(val, Cardinals.W)
|
||||
|| Scene.TestBorderCross(val, Cardinals.N)
|
||||
|| Scene.TestBorderCross(val, Cardinals.S))
|
||||
&& !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
|
||||
!Scene.PositionIsInCurrentRegion(val)
|
||||
&& !IsAttachmentCheckFull()
|
||||
&& (!Scene.LoadingPrims)
|
||||
)
|
||||
{
|
||||
IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
|
||||
uint x = 0;
|
||||
uint y = 0;
|
||||
string version = String.Empty;
|
||||
Vector3 newpos = Vector3.Zero;
|
||||
string failureReason = String.Empty;
|
||||
OpenSim.Services.Interfaces.GridRegion destination = null;
|
||||
|
||||
if (m_rootPart.KeyframeMotion != null)
|
||||
@@ -487,7 +477,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
// We set the avatar position as being the object
|
||||
// position to get the region to send to
|
||||
if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
|
||||
if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out version, out newpos, out failureReason)) == null)
|
||||
{
|
||||
canCross = false;
|
||||
break;
|
||||
@@ -522,14 +512,14 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
|
||||
|
||||
// Normalize
|
||||
if (val.X >= Constants.RegionSize)
|
||||
val.X -= Constants.RegionSize;
|
||||
if (val.Y >= Constants.RegionSize)
|
||||
val.Y -= Constants.RegionSize;
|
||||
if (val.X >= m_scene.RegionInfo.RegionSizeX)
|
||||
val.X -= m_scene.RegionInfo.RegionSizeX;
|
||||
if (val.Y >= m_scene.RegionInfo.RegionSizeY)
|
||||
val.Y -= m_scene.RegionInfo.RegionSizeY;
|
||||
if (val.X < 0)
|
||||
val.X += Constants.RegionSize;
|
||||
val.X += m_scene.RegionInfo.RegionSizeX;
|
||||
if (val.Y < 0)
|
||||
val.Y += Constants.RegionSize;
|
||||
val.Y += m_scene.RegionInfo.RegionSizeY;
|
||||
|
||||
// If it's deleted, crossing was successful
|
||||
if (IsDeleted)
|
||||
@@ -577,9 +567,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
Vector3 oldp = AbsolutePosition;
|
||||
val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
|
||||
val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
|
||||
val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
|
||||
val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f);
|
||||
val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f);
|
||||
val.Z = Util.Clamp<float>(oldp.Z, 0.5f, Constants.RegionHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -996,9 +986,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
maxX = -256f;
|
||||
maxY = -256f;
|
||||
maxZ = -256f;
|
||||
minX = 256f;
|
||||
minY = 256f;
|
||||
minZ = 8192f;
|
||||
minX = 10000f;
|
||||
minY = 10000f;
|
||||
minZ = 10000f;
|
||||
|
||||
SceneObjectPart[] parts = m_parts.GetArray();
|
||||
for (int i = 0; i < parts.Length; i++)
|
||||
|
||||
@@ -2479,13 +2479,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
if (pa != null)
|
||||
{
|
||||
Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0);
|
||||
|
||||
if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N)
|
||||
| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
|
||||
| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
|
||||
| ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
|
||||
Vector3 newpos = pa.Position;
|
||||
if (!ParentGroup.Scene.PositionIsInCurrentRegion(newpos))
|
||||
{
|
||||
// Setting position outside current region will start region crossing
|
||||
ParentGroup.AbsolutePosition = newpos;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
public class ScenePresence : EntityBase, IScenePresence
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly String LogHeader = "[SCENE PRESENCE]";
|
||||
|
||||
// ~ScenePresence()
|
||||
// {
|
||||
@@ -759,9 +760,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
foreach (ulong handle in seeds.Keys)
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(handle, out x, out y);
|
||||
x = x / Constants.RegionSize;
|
||||
y = y / Constants.RegionSize;
|
||||
Util.RegionHandleToRegionLoc(handle, out x, out y);
|
||||
|
||||
if (Util.IsOutsideView(DrawDistance, x, Scene.RegionInfo.RegionLocX, y, Scene.RegionInfo.RegionLocY))
|
||||
{
|
||||
old.Add(handle);
|
||||
@@ -783,9 +783,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
foreach (KeyValuePair<ulong, string> kvp in KnownRegions)
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(kvp.Key, out x, out y);
|
||||
x = x / Constants.RegionSize;
|
||||
y = y / Constants.RegionSize;
|
||||
Util.RegionHandleToRegionLoc(kvp.Key, out x, out y);
|
||||
m_log.Info(" >> "+x+", "+y+": "+kvp.Value);
|
||||
}
|
||||
}
|
||||
@@ -1059,30 +1057,32 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
m_scene.EventManager.TriggerSetRootAgentScene(m_uuid, m_scene);
|
||||
|
||||
UUID groupUUID = UUID.Zero;
|
||||
string GroupName = string.Empty;
|
||||
UUID groupUUID = ControllingClient.ActiveGroupId;
|
||||
string groupName = string.Empty;
|
||||
ulong groupPowers = 0;
|
||||
|
||||
// ----------------------------------
|
||||
// Previous Agent Difference - AGNI sends an unsolicited AgentDataUpdate upon root agent status
|
||||
try
|
||||
{
|
||||
if (gm != null)
|
||||
if (groupUUID != UUID.Zero && gm != null)
|
||||
{
|
||||
groupUUID = ControllingClient.ActiveGroupId;
|
||||
GroupRecord record = gm.GetGroupRecord(groupUUID);
|
||||
if (record != null)
|
||||
GroupName = record.GroupName;
|
||||
groupName = record.GroupName;
|
||||
|
||||
GroupMembershipData groupMembershipData = gm.GetMembershipData(groupUUID, m_uuid);
|
||||
|
||||
if (groupMembershipData != null)
|
||||
groupPowers = groupMembershipData.GroupPowers;
|
||||
}
|
||||
ControllingClient.SendAgentDataUpdate(m_uuid, groupUUID, Firstname, Lastname, groupPowers, GroupName,
|
||||
Grouptitle);
|
||||
|
||||
ControllingClient.SendAgentDataUpdate(
|
||||
m_uuid, groupUUID, Firstname, Lastname, groupPowers, groupName, Grouptitle);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Debug("[AGENTUPDATE]: " + e.ToString());
|
||||
m_log.Error("[AGENTUPDATE]: Error ", e);
|
||||
}
|
||||
// ------------------------------------
|
||||
|
||||
@@ -1092,6 +1092,10 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// before the inventory is processed in MakeRootAgent. This fixes a race condition
|
||||
// related to the handling of attachments
|
||||
//m_scene.GetAvatarAppearance(ControllingClient, out Appearance);
|
||||
|
||||
/* RA 20140111: Commented out these TestBorderCross's.
|
||||
* Not sure why this code is here. It is not checking all the borders
|
||||
* and 'in region' sanity checking is done in CheckAndAdjustLandingPoint and below.
|
||||
if (m_scene.TestBorderCross(pos, Cardinals.E))
|
||||
{
|
||||
Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.E);
|
||||
@@ -1103,6 +1107,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
Border crossedBorder = m_scene.GetCrossedBorder(pos, Cardinals.N);
|
||||
pos.Y = crossedBorder.BorderLine.Z - 1;
|
||||
}
|
||||
*/
|
||||
|
||||
CheckAndAdjustLandingPoint(ref pos);
|
||||
|
||||
@@ -1123,7 +1128,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
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];
|
||||
|
||||
float newPosZ = posZLimit + localAVHeight / 2;
|
||||
@@ -2400,7 +2405,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (regionCombinerModule != null)
|
||||
regionSize = regionCombinerModule.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
|
||||
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
|
||||
|| pos.Y < 0 || pos.Y >= regionSize.Y
|
||||
@@ -2418,8 +2423,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
// }
|
||||
|
||||
// Get terrain height for sub-region in a megaregion if necessary
|
||||
int X = (int)((m_scene.RegionInfo.RegionLocX * Constants.RegionSize) + pos.X);
|
||||
int Y = (int)((m_scene.RegionInfo.RegionLocY * Constants.RegionSize) + pos.Y);
|
||||
int X = (int)((m_scene.RegionInfo.WorldLocX) + pos.X);
|
||||
int Y = (int)((m_scene.RegionInfo.WorldLocY) + pos.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 (target_region == null)
|
||||
@@ -2430,7 +2435,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (!SceneManager.Instance.TryGetScene(target_regionID, out targetScene))
|
||||
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)];
|
||||
pos.Z = Math.Max(terrainHeight, pos.Z);
|
||||
|
||||
// Fudge factor. It appears that if one clicks "go here" on a piece of ground, the go here request is
|
||||
@@ -3466,10 +3471,12 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (!IsInTransit)
|
||||
{
|
||||
Vector3 pos2 = AbsolutePosition;
|
||||
Vector3 origPosition = pos2;
|
||||
Vector3 vel = Velocity;
|
||||
int neighbor = 0;
|
||||
int[] fix = new int[2];
|
||||
|
||||
// Compute the avatar position in the next physics tick.
|
||||
// If the avatar will be crossing, we force the crossing to happen now
|
||||
// in the hope that this will make the avatar movement smoother when crossing.
|
||||
float timeStep = 0.1f;
|
||||
pos2.X = pos2.X + (vel.X * timeStep);
|
||||
pos2.Y = pos2.Y + (vel.Y * timeStep);
|
||||
@@ -3477,107 +3484,30 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
if (!IsInTransit)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE PRESENCE]: Testing border check for projected position {0} of {1} in {2}",
|
||||
// pos2, Name, Scene.Name);
|
||||
|
||||
// Checks if where it's headed exists a region
|
||||
bool needsTransit = false;
|
||||
if (m_scene.TestBorderCross(pos2, Cardinals.W))
|
||||
if (!m_scene.PositionIsInCurrentRegion(pos2))
|
||||
{
|
||||
if (m_scene.TestBorderCross(pos2, Cardinals.S))
|
||||
m_log.DebugFormat("{0} CheckForBorderCrossing: position outside region. {1} in {2} at pos {3}",
|
||||
LogHeader, Name, Scene.Name, pos2);
|
||||
|
||||
// Disconnect from the current region
|
||||
bool isFlying = Flying;
|
||||
RemoveFromPhysicalScene();
|
||||
// pos2 is the forcasted position so make that the 'current' position so the crossing
|
||||
// code will move us into the newly addressed region.
|
||||
m_pos = pos2;
|
||||
if (CrossToNewRegion())
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.SW, ref fix);
|
||||
}
|
||||
else if (m_scene.TestBorderCross(pos2, Cardinals.N))
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.NW, ref fix);
|
||||
AddToPhysicalScene(isFlying);
|
||||
}
|
||||
else
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.W, ref fix);
|
||||
}
|
||||
}
|
||||
else if (m_scene.TestBorderCross(pos2, Cardinals.E))
|
||||
{
|
||||
if (m_scene.TestBorderCross(pos2, Cardinals.S))
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.SE, ref fix);
|
||||
}
|
||||
else if (m_scene.TestBorderCross(pos2, Cardinals.N))
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.NE, ref fix);
|
||||
}
|
||||
else
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.E, ref fix);
|
||||
}
|
||||
}
|
||||
else if (m_scene.TestBorderCross(pos2, Cardinals.S))
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.S, ref fix);
|
||||
}
|
||||
else if (m_scene.TestBorderCross(pos2, Cardinals.N))
|
||||
{
|
||||
needsTransit = true;
|
||||
neighbor = m_scene.HaveNeighbor(Cardinals.N, ref fix);
|
||||
}
|
||||
|
||||
// Makes sure avatar does not end up outside region
|
||||
if (neighbor <= 0)
|
||||
{
|
||||
if (needsTransit)
|
||||
{
|
||||
// Tried to make crossing happen but it failed.
|
||||
if (m_requestedSitTargetUUID == UUID.Zero)
|
||||
{
|
||||
bool isFlying = Flying;
|
||||
RemoveFromPhysicalScene();
|
||||
m_log.DebugFormat("{0} CheckForBorderCrossing: Crossing failed. Restoring old position.", LogHeader);
|
||||
|
||||
Vector3 pos = AbsolutePosition;
|
||||
if (AbsolutePosition.X < 0)
|
||||
pos.X += Velocity.X * 2;
|
||||
else if (AbsolutePosition.X > Constants.RegionSize)
|
||||
pos.X -= Velocity.X * 2;
|
||||
if (AbsolutePosition.Y < 0)
|
||||
pos.Y += Velocity.Y * 2;
|
||||
else if (AbsolutePosition.Y > Constants.RegionSize)
|
||||
pos.Y -= Velocity.Y * 2;
|
||||
Velocity = Vector3.Zero;
|
||||
AbsolutePosition = pos;
|
||||
|
||||
// m_log.DebugFormat("[SCENE PRESENCE]: Prevented flyoff for {0} at {1}", Name, AbsolutePosition);
|
||||
|
||||
AddToPhysicalScene(isFlying);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (neighbor > 0)
|
||||
{
|
||||
if (!CrossToNewRegion())
|
||||
{
|
||||
if (m_requestedSitTargetUUID == UUID.Zero)
|
||||
{
|
||||
bool isFlying = Flying;
|
||||
RemoveFromPhysicalScene();
|
||||
|
||||
Vector3 pos = AbsolutePosition;
|
||||
if (AbsolutePosition.X < 0)
|
||||
pos.X += Velocity.X * 2;
|
||||
else if (AbsolutePosition.X > Constants.RegionSize)
|
||||
pos.X -= Velocity.X * 2;
|
||||
if (AbsolutePosition.Y < 0)
|
||||
pos.Y += Velocity.Y * 2;
|
||||
else if (AbsolutePosition.Y > Constants.RegionSize)
|
||||
pos.Y -= Velocity.Y * 2;
|
||||
Velocity = Vector3.Zero;
|
||||
AbsolutePosition = pos;
|
||||
AbsolutePosition = EnforceSanityOnPosition(origPosition);
|
||||
|
||||
AddToPhysicalScene(isFlying);
|
||||
}
|
||||
@@ -3599,6 +3529,36 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
// Given a position, make sure it is within the current region.
|
||||
// If just outside some border, the returned position will be just inside the border on that side.
|
||||
private Vector3 EnforceSanityOnPosition(Vector3 origPosition)
|
||||
{
|
||||
const float borderFudge = 0.1f;
|
||||
Vector3 ret = origPosition;
|
||||
|
||||
// Sanity checking on the position to make sure it is in the region we couldn't cross from
|
||||
float extentX = (float)m_scene.RegionInfo.RegionSizeX;
|
||||
float extentY = (float)m_scene.RegionInfo.RegionSizeY;
|
||||
IRegionCombinerModule combiner = m_scene.RequestModuleInterface<IRegionCombinerModule>();
|
||||
if (combiner != null)
|
||||
{
|
||||
// If a mega-region, the size could be much bigger
|
||||
Vector2 megaExtent = combiner.GetSizeOfMegaregion(m_scene.RegionInfo.RegionID);
|
||||
extentX = megaExtent.X;
|
||||
extentY = megaExtent.Y;
|
||||
}
|
||||
if (ret.X < 0)
|
||||
ret.X = borderFudge;
|
||||
else if (ret.X >= extentX)
|
||||
ret.X = extentX - borderFudge;
|
||||
if (ret.Y < 0)
|
||||
ret.Y = borderFudge;
|
||||
else if (ret.Y >= extentY)
|
||||
ret.Y = extentY - borderFudge;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves the agent outside the region bounds
|
||||
/// Tells neighbor region that we're crossing to it
|
||||
@@ -3623,7 +3583,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
|
||||
// Put the child agent back at the center
|
||||
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();
|
||||
}
|
||||
@@ -3650,9 +3610,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
if (handle != Scene.RegionInfo.RegionHandle)
|
||||
{
|
||||
uint x, y;
|
||||
Utils.LongToUInts(handle, out x, out y);
|
||||
x = x / Constants.RegionSize;
|
||||
y = y / Constants.RegionSize;
|
||||
Util.RegionHandleToRegionLoc(handle, out x, out y);
|
||||
|
||||
// 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)));
|
||||
@@ -3733,8 +3691,9 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
return;
|
||||
|
||||
//m_log.Debug(" >>> ChildAgentPositionUpdate <<< " + rRegionX + "-" + rRegionY);
|
||||
int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize;
|
||||
int shifty = ((int)rRegionY - (int)tRegionY) * (int)Constants.RegionSize;
|
||||
// Find the distance (in meters) between the two regions
|
||||
uint shiftx = Util.RegionToWorldLoc(rRegionX - tRegionX);
|
||||
uint shifty = Util.RegionToWorldLoc(rRegionY - tRegionY);
|
||||
|
||||
Vector3 offset = new Vector3(shiftx, shifty, 0f);
|
||||
|
||||
@@ -4770,6 +4729,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
// Modify landing point based on possible banning, telehubs or parcel restrictions.
|
||||
private void CheckAndAdjustLandingPoint(ref Vector3 pos)
|
||||
{
|
||||
string reason;
|
||||
|
||||
@@ -25,13 +25,20 @@
|
||||
* 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.Region.Framework.Interfaces;
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
using OpenMetaverse;
|
||||
|
||||
using log4net;
|
||||
|
||||
namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
@@ -40,132 +47,146 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
/// </summary>
|
||||
public class TerrainChannel : ITerrainChannel
|
||||
{
|
||||
private readonly bool[,] taint;
|
||||
private double[,] map;
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
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()
|
||||
{
|
||||
map = new double[Constants.RegionSize, Constants.RegionSize];
|
||||
taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16];
|
||||
|
||||
PinHeadIsland();
|
||||
m_terrainData = new HeightmapTerrainData((int)Constants.RegionSize, (int)Constants.RegionSize, (int)Constants.RegionHeight);
|
||||
FlatLand();
|
||||
// PinHeadIsland();
|
||||
}
|
||||
|
||||
public TerrainChannel(String type)
|
||||
// Create terrain of given size
|
||||
public TerrainChannel(int pX, int pY)
|
||||
{
|
||||
map = new double[Constants.RegionSize, Constants.RegionSize];
|
||||
taint = new bool[Constants.RegionSize / 16, Constants.RegionSize / 16];
|
||||
m_terrainData = new HeightmapTerrainData(pX, pY, (int)Constants.RegionHeight);
|
||||
}
|
||||
|
||||
// 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"))
|
||||
FlatLand();
|
||||
else
|
||||
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;
|
||||
taint = new bool[import.GetLength(0),import.GetLength(1)];
|
||||
int hmSizeX = pM.GetLength(0);
|
||||
int hmSizeY = pM.GetLength(1);
|
||||
|
||||
m_terrainData = new HeightmapTerrainData(pSizeX, pSizeY, pAltitude);
|
||||
|
||||
for (int xx = 0; xx < pSizeX; xx++)
|
||||
for (int yy = 0; yy < pSizeY; yy++)
|
||||
if (xx > hmSizeX || yy > hmSizeY)
|
||||
m_terrainData[xx, yy] = TerrainData.DefaultTerrainHeight;
|
||||
else
|
||||
m_terrainData[xx, yy] = (float)pM[xx, yy];
|
||||
}
|
||||
|
||||
public TerrainChannel(bool createMap)
|
||||
public TerrainChannel(TerrainData pTerrData)
|
||||
{
|
||||
if (createMap)
|
||||
{
|
||||
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];
|
||||
m_terrainData = pTerrData;
|
||||
}
|
||||
|
||||
#region ITerrainChannel Members
|
||||
|
||||
public int Width
|
||||
{
|
||||
get { return map.GetLength(0); }
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get { return map.GetLength(1); }
|
||||
}
|
||||
|
||||
// ITerrainChannel.MakeCopy()
|
||||
public ITerrainChannel MakeCopy()
|
||||
{
|
||||
TerrainChannel copy = new TerrainChannel(false);
|
||||
copy.map = (double[,]) map.Clone();
|
||||
|
||||
return copy;
|
||||
return this.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()
|
||||
{
|
||||
// Move the member variables into local variables, calling
|
||||
// member variables 256*256 times gets expensive
|
||||
int w = Width;
|
||||
int h = Height;
|
||||
float[] heights = new float[w * h];
|
||||
int points = Width * Height;
|
||||
float[] heights = new float[points];
|
||||
|
||||
int i, j; // map coordinates
|
||||
int idx = 0; // index into serialized array
|
||||
for (i = 0; i < h; i++)
|
||||
{
|
||||
for (j = 0; j < w; j++)
|
||||
int idx = 0;
|
||||
for (int jj = 0; jj < Height; jj++)
|
||||
for (int ii = 0; ii < Width; ii++)
|
||||
{
|
||||
heights[idx++] = (float)map[j, i];
|
||||
heights[idx++] = m_terrainData[ii, jj];
|
||||
}
|
||||
|
||||
return heights;
|
||||
}
|
||||
|
||||
// ITerrainChannel.GetDoubles()
|
||||
public double[,] GetDoubles()
|
||||
{
|
||||
double[,] heights = new double[Width, Height];
|
||||
|
||||
int idx = 0; // index into serialized array
|
||||
for (int ii = 0; ii < Width; ii++)
|
||||
{
|
||||
for (int jj = 0; jj < Height; jj++)
|
||||
{
|
||||
heights[ii, jj] = (double)m_terrainData[ii, jj];
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
return heights;
|
||||
}
|
||||
|
||||
public double[,] GetDoubles()
|
||||
{
|
||||
return map;
|
||||
}
|
||||
|
||||
// ITerrainChannel.this[x,y]
|
||||
public double this[int x, int y]
|
||||
{
|
||||
get { return map[x, y]; }
|
||||
get {
|
||||
if (x < 0 || x >= Width || y < 0 || y >= Height)
|
||||
return 0;
|
||||
return (double)m_terrainData[x, y];
|
||||
}
|
||||
set
|
||||
{
|
||||
// Will "fix" terrain hole problems. Although not fantastically.
|
||||
if (Double.IsNaN(value) || Double.IsInfinity(value))
|
||||
return;
|
||||
|
||||
if (map[x, y] != value)
|
||||
{
|
||||
taint[x / 16, y / 16] = true;
|
||||
map[x, y] = value;
|
||||
}
|
||||
m_terrainData[x, y] = (float)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)
|
||||
{
|
||||
if (taint[x / 16, y / 16])
|
||||
{
|
||||
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;
|
||||
return m_terrainData.IsTaintedAt(x, y);
|
||||
}
|
||||
|
||||
// ITerrainChannel.SaveToXmlString()
|
||||
public string SaveToXmlString()
|
||||
{
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
@@ -181,13 +202,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
private void WriteXml(XmlWriter writer)
|
||||
{
|
||||
writer.WriteStartElement(String.Empty, "TerrainMap", String.Empty);
|
||||
ToXml(writer);
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
// ITerrainChannel.LoadFromXmlString()
|
||||
public void LoadFromXmlString(string data)
|
||||
{
|
||||
StringReader sr = new StringReader(data);
|
||||
@@ -199,12 +214,124 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
sr.Close();
|
||||
}
|
||||
|
||||
private void ReadXml(XmlReader reader)
|
||||
// ITerrainChannel.Merge
|
||||
public void Merge(ITerrainChannel newTerrain, Vector3 displacement, float radianRotation, Vector2 rotationDisplacement)
|
||||
{
|
||||
reader.ReadStartElement("TerrainMap");
|
||||
FromXml(reader);
|
||||
m_log.DebugFormat("{0} Merge. inSize=<{1},{2}>, disp={3}, rot={4}, rotDisp={5}, outSize=<{6},{7}>", LogHeader,
|
||||
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)
|
||||
{
|
||||
float[] mapData = GetFloatsSerialised();
|
||||
@@ -218,12 +345,15 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
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)
|
||||
{
|
||||
XmlSerializer serializer = new XmlSerializer(typeof(byte[]));
|
||||
byte[] dataArray = (byte[])serializer.Deserialize(xmlReader);
|
||||
int index = 0;
|
||||
|
||||
m_terrainData = new HeightmapTerrainData(Height, Width, (int)Constants.RegionHeight);
|
||||
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
for (int x = 0; x < Width; x++)
|
||||
@@ -236,35 +366,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 short[] Map;
|
||||
public TerrainChannelXMLPackage(int pX, int pY, int pZ, float pCompressionFactor, short[] 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()
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < Constants.RegionSize; x++)
|
||||
for (int x = 0; x < Width; x++)
|
||||
{
|
||||
int y;
|
||||
for (y = 0; y < Constants.RegionSize; y++)
|
||||
for (int y = 0; y < Height; y++)
|
||||
{
|
||||
map[x, y] = 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;
|
||||
double spherFacB = TerrainUtil.SphericalFactor(x, y, Constants.RegionSize / 2.0, Constants.RegionSize / 2.0, 100) * 0.001;
|
||||
if (map[x, y] < spherFacA)
|
||||
map[x, y] = spherFacA;
|
||||
if (map[x, y] < spherFacB)
|
||||
map[x, y] = spherFacB;
|
||||
m_terrainData[x, y] = (float)TerrainUtil.PerlinNoise2D(x, y, 2, 0.125) * 10;
|
||||
float spherFacA = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 50) * 0.01d);
|
||||
float spherFacB = (float)(TerrainUtil.SphericalFactor(x, y, m_terrainData.SizeX / 2.0, m_terrainData.SizeY / 2.0, 100) * 0.001d);
|
||||
if (m_terrainData[x, y]< spherFacA)
|
||||
m_terrainData[x, y]= spherFacA;
|
||||
if (m_terrainData[x, y]< spherFacB)
|
||||
m_terrainData[x, y] = spherFacB;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void FlatLand()
|
||||
{
|
||||
int x;
|
||||
for (x = 0; x < Constants.RegionSize; x++)
|
||||
{
|
||||
int y;
|
||||
for (y = 0; y < Constants.RegionSize; y++)
|
||||
map[x, y] = 21;
|
||||
}
|
||||
m_terrainData.ClearLand();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
942
OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
Normal file
942
OpenSim/Region/Framework/Scenes/TerrainCompressor.cs
Normal file
@@ -0,0 +1,942 @@
|
||||
/*
|
||||
* 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);
|
||||
private static string LogHeader = "[TERRAIN COMPRESSOR]";
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
// Unused: left for historical reference.
|
||||
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;
|
||||
|
||||
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>
|
||||
/// <param name="pRegionSizeX"></param>
|
||||
/// <param name="pRegionSizeY"></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, (uint)pRegionSizeX, (uint)pRegionSizeY, 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
|
||||
}
|
||||
}
|
||||
@@ -161,7 +161,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
{
|
||||
// Get the prim's default texture. This will be used for faces which don't have their own texture
|
||||
if (textureEntry.DefaultTexture != null)
|
||||
assetUuids[textureEntry.DefaultTexture.TextureID] = (sbyte)AssetType.Texture;
|
||||
GatherTextureEntryAssets(textureEntry.DefaultTexture, assetUuids);
|
||||
|
||||
if (textureEntry.FaceTextures != null)
|
||||
{
|
||||
@@ -169,7 +169,7 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
foreach (Primitive.TextureEntryFace texture in textureEntry.FaceTextures)
|
||||
{
|
||||
if (texture != null)
|
||||
assetUuids[texture.TextureID] = (sbyte)AssetType.Texture;
|
||||
GatherTextureEntryAssets(texture, assetUuids);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,6 +233,19 @@ namespace OpenSim.Region.Framework.Scenes
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gather all the asset uuids found in one face of a Texture Entry.
|
||||
/// </summary>
|
||||
private void GatherTextureEntryAssets(Primitive.TextureEntryFace texture, IDictionary<UUID, sbyte> assetUuids)
|
||||
{
|
||||
assetUuids[texture.TextureID] = (sbyte)AssetType.Texture;
|
||||
|
||||
if (texture.MaterialID != UUID.Zero)
|
||||
{
|
||||
GatherAssetUuids(texture.MaterialID, (sbyte)OpenSimAssetType.Material, assetUuids);
|
||||
}
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// The callback made when we request the asset for an object from the asset service.
|
||||
// /// </summary>
|
||||
|
||||
@@ -516,7 +516,7 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
|
||||
|
||||
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 { }
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
|
||||
|
||||
// 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 char[] CS_SPACE = { ' ' };
|
||||
|
||||
|
||||
@@ -44,6 +44,8 @@ namespace OpenSim.Region.OptionalModules.Avatar.Chat
|
||||
private static readonly ILog m_log =
|
||||
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 const int DEBUG_CHANNEL = 2147483647;
|
||||
|
||||
|
||||
@@ -1012,7 +1012,7 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||
Hashtable respData = (Hashtable)resp.Value;
|
||||
if (respData.Contains("error") && !respData.Contains("succeed"))
|
||||
{
|
||||
LogRespDataToConsoleError(respData);
|
||||
LogRespDataToConsoleError(requestingAgentID, function, param, respData);
|
||||
}
|
||||
|
||||
return respData;
|
||||
@@ -1040,20 +1040,11 @@ namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
|
||||
return error;
|
||||
}
|
||||
|
||||
private void LogRespDataToConsoleError(Hashtable respData)
|
||||
private void LogRespDataToConsoleError(UUID requestingAgentID, string function, Hashtable param, Hashtable respData)
|
||||
{
|
||||
m_log.Error("[XMLRPC-GROUPS-CONNECTOR]: Error:");
|
||||
|
||||
foreach (string key in respData.Keys)
|
||||
{
|
||||
m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: Key: {0}", key);
|
||||
|
||||
string[] lines = respData[key].ToString().Split(new char[] { '\n' });
|
||||
foreach (string line in lines)
|
||||
{
|
||||
m_log.ErrorFormat("[XMLRPC-GROUPS-CONNECTOR]: {0}", line);
|
||||
}
|
||||
}
|
||||
m_log.ErrorFormat(
|
||||
"[XMLRPC-GROUPS-CONNECTOR]: Error when calling {0} for {1} with params {2}. Response params are {3}",
|
||||
function, requestingAgentID, Util.PrettyFormatToSingleLine(param), Util.PrettyFormatToSingleLine(respData));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -314,6 +314,19 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||
return m_store.TestStore(storeID) ? 1 : 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
[ScriptInvocation]
|
||||
public UUID JsonRezAtRoot(UUID hostID, UUID scriptID, string item, Vector3 pos, Vector3 vel, Quaternion rot, string param)
|
||||
{
|
||||
UUID reqID = UUID.Random();
|
||||
Util.FireAndForget(o => DoJsonRezObject(hostID, scriptID, reqID, item, pos, vel, rot, param));
|
||||
return reqID;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
@@ -682,5 +695,103 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||
return path;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
private void DoJsonRezObject(UUID hostID, UUID scriptID, UUID reqID, string name, Vector3 pos, Vector3 vel, Quaternion rot, string param)
|
||||
{
|
||||
if (Double.IsNaN(rot.X) || Double.IsNaN(rot.Y) || Double.IsNaN(rot.Z) || Double.IsNaN(rot.W))
|
||||
{
|
||||
GenerateRuntimeError("Invalid rez rotation");
|
||||
return;
|
||||
}
|
||||
|
||||
SceneObjectGroup host = m_scene.GetSceneObjectGroup(hostID);
|
||||
if (host == null)
|
||||
{
|
||||
GenerateRuntimeError(String.Format("Unable to find rezzing host '{0}'",hostID));
|
||||
return;
|
||||
}
|
||||
|
||||
// hpos = host.RootPart.GetWorldPosition()
|
||||
// float dist = (float)llVecDist(hpos, pos);
|
||||
// if (dist > m_ScriptDistanceFactor * 10.0f)
|
||||
// return;
|
||||
|
||||
TaskInventoryItem item = host.RootPart.Inventory.GetInventoryItem(name);
|
||||
if (item == null)
|
||||
{
|
||||
GenerateRuntimeError(String.Format("Unable to find object to rez '{0}'",name));
|
||||
return;
|
||||
}
|
||||
|
||||
if (item.InvType != (int)InventoryType.Object)
|
||||
{
|
||||
GenerateRuntimeError("Can't create requested object; object is missing from database");
|
||||
return;
|
||||
}
|
||||
|
||||
List<SceneObjectGroup> objlist;
|
||||
List<Vector3> veclist;
|
||||
|
||||
bool success = host.RootPart.Inventory.GetRezReadySceneObjects(item, out objlist, out veclist);
|
||||
if (! success)
|
||||
{
|
||||
GenerateRuntimeError("Failed to create object");
|
||||
return;
|
||||
}
|
||||
|
||||
int totalPrims = 0;
|
||||
foreach (SceneObjectGroup group in objlist)
|
||||
totalPrims += group.PrimCount;
|
||||
|
||||
if (! m_scene.Permissions.CanRezObject(totalPrims, item.OwnerID, pos))
|
||||
{
|
||||
GenerateRuntimeError("Not allowed to create the object");
|
||||
return;
|
||||
}
|
||||
|
||||
if (! m_scene.Permissions.BypassPermissions())
|
||||
{
|
||||
if ((item.CurrentPermissions & (uint)PermissionMask.Copy) == 0)
|
||||
host.RootPart.Inventory.RemoveInventoryItem(item.ItemID);
|
||||
}
|
||||
|
||||
for (int i = 0; i < objlist.Count; i++)
|
||||
{
|
||||
SceneObjectGroup group = objlist[i];
|
||||
Vector3 curpos = pos + veclist[i];
|
||||
|
||||
if (group.IsAttachment == false && group.RootPart.Shape.State != 0)
|
||||
{
|
||||
group.RootPart.AttachedPos = group.AbsolutePosition;
|
||||
group.RootPart.Shape.LastAttachPoint = (byte)group.AttachmentPoint;
|
||||
}
|
||||
|
||||
group.FromPartID = host.RootPart.UUID;
|
||||
m_scene.AddNewSceneObject(group, true, curpos, rot, vel);
|
||||
|
||||
UUID storeID = group.UUID;
|
||||
if (! m_store.CreateStore(param, ref storeID))
|
||||
{
|
||||
GenerateRuntimeError("Unable to create jsonstore for new object");
|
||||
continue;
|
||||
}
|
||||
|
||||
// We can only call this after adding the scene object, since the scene object references the scene
|
||||
// to find out if scripts should be activated at all.
|
||||
group.RootPart.SetDieAtEdge(true);
|
||||
group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 3);
|
||||
group.ResumeScripts();
|
||||
|
||||
group.ScheduleGroupForFullUpdate();
|
||||
|
||||
// send the reply back to the host object, use the integer param to indicate the number
|
||||
// of remaining objects
|
||||
m_comms.DispatchReply(scriptID, objlist.Count-i-1, group.RootPart.UUID.ToString(), reqID.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +170,10 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
|
||||
c.Channel = m_channelNotify;
|
||||
c.Message += numScriptsFailed.ToString() + "," + message;
|
||||
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.SenderUUID = UUID.Zero;
|
||||
c.Scene = m_scene;
|
||||
@@ -301,7 +304,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.RegionReady
|
||||
finally
|
||||
{
|
||||
if (os != null)
|
||||
os.Close();
|
||||
os.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||
private readonly string m_firstname;
|
||||
private readonly string m_lastname;
|
||||
private readonly Vector3 m_startPos;
|
||||
private readonly UUID m_uuid = UUID.Random();
|
||||
private readonly UUID m_uuid;
|
||||
private readonly Scene m_scene;
|
||||
private readonly UUID m_ownerID;
|
||||
|
||||
@@ -71,6 +71,19 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||
m_firstname = firstname;
|
||||
m_lastname = lastname;
|
||||
m_startPos = position;
|
||||
m_uuid = UUID.Random();
|
||||
m_scene = scene;
|
||||
m_ownerID = ownerID;
|
||||
SenseAsAgent = senseAsAgent;
|
||||
}
|
||||
|
||||
public NPCAvatar(
|
||||
string firstname, string lastname, UUID agentID, Vector3 position, UUID ownerID, bool senseAsAgent, Scene scene)
|
||||
{
|
||||
m_firstname = firstname;
|
||||
m_lastname = lastname;
|
||||
m_startPos = position;
|
||||
m_uuid = agentID;
|
||||
m_scene = scene;
|
||||
m_ownerID = ownerID;
|
||||
SenseAsAgent = senseAsAgent;
|
||||
|
||||
@@ -140,8 +140,30 @@ namespace OpenSim.Region.OptionalModules.World.NPC
|
||||
Vector3 position, UUID owner, bool senseAsAgent, Scene scene,
|
||||
AvatarAppearance appearance)
|
||||
{
|
||||
NPCAvatar npcAvatar = new NPCAvatar(firstname, lastname, position,
|
||||
owner, senseAsAgent, scene);
|
||||
return CreateNPC(firstname, lastname, position, UUID.Zero, owner, senseAsAgent, scene, appearance);
|
||||
}
|
||||
|
||||
public UUID CreateNPC(string firstname, string lastname,
|
||||
Vector3 position, UUID agentID, UUID owner, bool senseAsAgent, Scene scene,
|
||||
AvatarAppearance appearance)
|
||||
{
|
||||
NPCAvatar npcAvatar = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (agentID == UUID.Zero)
|
||||
npcAvatar = new NPCAvatar(firstname, lastname, position,
|
||||
owner, senseAsAgent, scene);
|
||||
else
|
||||
npcAvatar = new NPCAvatar(firstname, lastname, agentID, position,
|
||||
owner, senseAsAgent, scene);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Info("[NPC MODULE]: exception creating NPC avatar: " + e.ToString());
|
||||
return UUID.Zero;
|
||||
}
|
||||
|
||||
npcAvatar.CircuitCode = (uint)Util.RandomClass.Next(0,
|
||||
int.MaxValue);
|
||||
|
||||
|
||||
@@ -116,37 +116,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Attachments
|
||||
+ "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.",
|
||||
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)
|
||||
|
||||
@@ -748,8 +748,8 @@ namespace OpenSim.Region.OptionalModules.World.TreePopulator
|
||||
position.X = s_tree.AbsolutePosition.X + (float)randX;
|
||||
position.Y = s_tree.AbsolutePosition.Y + (float)randY;
|
||||
|
||||
if (position.X <= ((int)Constants.RegionSize - 1) && position.X >= 0 &&
|
||||
position.Y <= ((int)Constants.RegionSize - 1) && position.Y >= 0 &&
|
||||
if (position.X <= (m_scene.RegionInfo.RegionSizeX - 1) && position.X >= 0 &&
|
||||
position.Y <= (m_scene.RegionInfo.RegionSizeY - 1) && position.Y >= 0 &&
|
||||
Util.GetDistanceTo(position, copse.m_seed_point) <= copse.m_range)
|
||||
{
|
||||
UUID uuid = m_scene.RegionInfo.EstateSettings.EstateOwner;
|
||||
|
||||
@@ -1311,7 +1311,7 @@ private sealed class BulletConstraintXNA : BulletConstraint
|
||||
/* TODO */
|
||||
ConfigurationParameters[] configparms = new ConfigurationParameters[1];
|
||||
configparms[0] = parms;
|
||||
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||
Vector3 worldExtent = maxPosition;
|
||||
m_maxCollisions = maxCollisions;
|
||||
m_maxUpdatesPerFrame = maxUpdates;
|
||||
specialCollisionObjects = new Dictionary<uint, GhostObject>();
|
||||
|
||||
@@ -1011,8 +1011,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||
VDetailLog("{0}, MoveLinear,clampMax,origVelW={1},lenSq={2},maxVelSq={3},,newVelW={4}",
|
||||
ControllingPrim.LocalID, origVelW, newVelocityLengthSq, BSParam.VehicleMaxLinearVelocitySquared, VehicleVelocity);
|
||||
}
|
||||
else if (newVelocityLengthSq < 0.001f)
|
||||
else if (newVelocityLengthSq < BSParam.VehicleMinLinearVelocitySquared)
|
||||
{
|
||||
Vector3 origVelW = VehicleVelocity; // DEBUG DEBUG
|
||||
VDetailLog("{0}, MoveLinear,clampMin,origVelW={1},lenSq={2}",
|
||||
ControllingPrim.LocalID, origVelW, newVelocityLengthSq);
|
||||
VehicleVelocity = Vector3.Zero;
|
||||
}
|
||||
|
||||
VDetailLog("{0}, MoveLinear,done,isColl={1},newVel={2}", ControllingPrim.LocalID, ControllingPrim.HasSomeCollision, VehicleVelocity );
|
||||
|
||||
|
||||
@@ -147,6 +147,8 @@ public static class BSParam
|
||||
// Vehicle parameters
|
||||
public static float VehicleMaxLinearVelocity { get; private set; }
|
||||
public static float VehicleMaxLinearVelocitySquared { get; private set; }
|
||||
public static float VehicleMinLinearVelocity { get; private set; }
|
||||
public static float VehicleMinLinearVelocitySquared { get; private set; }
|
||||
public static float VehicleMaxAngularVelocity { get; private set; }
|
||||
public static float VehicleMaxAngularVelocitySq { get; private set; }
|
||||
public static float VehicleAngularDamping { get; private set; }
|
||||
@@ -538,7 +540,7 @@ public static class BSParam
|
||||
(s,o) => { s.PE.SetContactProcessingThreshold(o.PhysBody, ContactProcessingThreshold); } ),
|
||||
|
||||
new ParameterDefn<float>("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
|
||||
(float)BSTerrainPhys.TerrainImplementation.Mesh ),
|
||||
(float)BSTerrainPhys.TerrainImplementation.Heightmap ),
|
||||
new ParameterDefn<int>("TerrainMeshMagnification", "Number of times the 256x256 heightmap is multiplied to create the terrain mesh" ,
|
||||
2 ),
|
||||
new ParameterDefn<float>("TerrainFriction", "Factor to reduce movement against terrain surface" ,
|
||||
@@ -598,6 +600,10 @@ public static class BSParam
|
||||
1000.0f,
|
||||
(s) => { return (float)VehicleMaxLinearVelocity; },
|
||||
(s,v) => { VehicleMaxLinearVelocity = v; VehicleMaxLinearVelocitySquared = v * v; } ),
|
||||
new ParameterDefn<float>("VehicleMinLinearVelocity", "Maximum velocity magnitude that can be assigned to a vehicle",
|
||||
0.001f,
|
||||
(s) => { return (float)VehicleMinLinearVelocity; },
|
||||
(s,v) => { VehicleMinLinearVelocity = v; VehicleMinLinearVelocitySquared = v * v; } ),
|
||||
new ParameterDefn<float>("VehicleMaxAngularVelocity", "Maximum rotational velocity magnitude that can be assigned to a vehicle",
|
||||
12.0f,
|
||||
(s) => { return (float)VehicleMaxAngularVelocity; },
|
||||
|
||||
@@ -376,18 +376,19 @@ public class BSPrim : BSPhysObject
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
uint wayOutThere = Constants.RegionSize * Constants.RegionSize;
|
||||
int wayOverThere = -1000;
|
||||
int wayOutThere = 10000;
|
||||
// There have been instances of objects getting thrown way out of bounds and crashing
|
||||
// the border crossing code.
|
||||
if ( RawPosition.X < -Constants.RegionSize || RawPosition.X > wayOutThere
|
||||
|| RawPosition.Y < -Constants.RegionSize || RawPosition.Y > wayOutThere
|
||||
|| RawPosition.Z < -Constants.RegionSize || RawPosition.Z > wayOutThere)
|
||||
if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
|
||||
|| RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
|
||||
|| RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
|
||||
{
|
||||
RawPosition = new OMV.Vector3(10, 10, 50);
|
||||
ZeroMotion(inTaintTime);
|
||||
ret = true;
|
||||
}
|
||||
if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocity)
|
||||
if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
|
||||
{
|
||||
RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
|
||||
ret = true;
|
||||
|
||||
@@ -208,7 +208,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||
Name = EngineType + "/" + RegionName;
|
||||
}
|
||||
|
||||
// Old version of initialization that assumes legacy sized regions (256x256)
|
||||
public override void Initialise(IMesher meshmerizer, IConfigSource config)
|
||||
{
|
||||
m_log.ErrorFormat("{0} WARNING WARNING WARNING! BulletSim initialized without region extent specification. Terrain will be messed up.");
|
||||
Vector3 regionExtent = new Vector3( Constants.RegionSize, Constants.RegionSize, Constants.RegionSize);
|
||||
Initialise(meshmerizer, config, regionExtent);
|
||||
|
||||
}
|
||||
|
||||
public override void Initialise(IMesher meshmerizer, IConfigSource config, Vector3 regionExtent)
|
||||
{
|
||||
mesher = meshmerizer;
|
||||
_taintOperations = new List<TaintCallbackEntry>();
|
||||
@@ -226,6 +235,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||
// Set default values for physics parameters plus any overrides from the ini file
|
||||
GetInitialParameterValues(config);
|
||||
|
||||
// Force some parameters to values depending on other configurations
|
||||
// Only use heightmap terrain implementation if terrain larger than legacy size
|
||||
if ((uint)regionExtent.X > Constants.RegionSize || (uint)regionExtent.Y > Constants.RegionSize)
|
||||
{
|
||||
m_log.WarnFormat("{0} Forcing terrain implementation to heightmap for large region", LogHeader);
|
||||
BSParam.TerrainImplementation = (float)BSTerrainPhys.TerrainImplementation.Heightmap;
|
||||
}
|
||||
|
||||
// Get the connection to the physics engine (could be native or one of many DLLs)
|
||||
PE = SelectUnderlyingBulletEngine(BulletEngineName);
|
||||
|
||||
@@ -250,13 +267,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
|
||||
// a child in a mega-region.
|
||||
// Bullet actually doesn't care about the extents of the simulated
|
||||
// area. It tracks active objects no matter where they are.
|
||||
Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
|
||||
Vector3 worldExtent = regionExtent;
|
||||
|
||||
World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
|
||||
|
||||
Constraints = new BSConstraintCollection(World);
|
||||
|
||||
TerrainManager = new BSTerrainManager(this);
|
||||
TerrainManager = new BSTerrainManager(this, worldExtent);
|
||||
TerrainManager.CreateInitialGroundPlaneAndTerrain();
|
||||
|
||||
// Put some informational messages into the log file.
|
||||
|
||||
@@ -58,7 +58,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||
{
|
||||
initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
|
||||
}
|
||||
m_mapInfo = new BulletHMapInfo(id, initialMap);
|
||||
m_mapInfo = new BulletHMapInfo(id, initialMap, regionSize.X, regionSize.Y);
|
||||
m_mapInfo.minCoords = minTerrainCoords;
|
||||
m_mapInfo.maxCoords = maxTerrainCoords;
|
||||
m_mapInfo.terrainRegionBase = TerrainBase;
|
||||
@@ -72,7 +72,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
|
||||
Vector3 minCoords, Vector3 maxCoords)
|
||||
: base(physicsScene, regionBase, id)
|
||||
{
|
||||
m_mapInfo = new BulletHMapInfo(id, initialMap);
|
||||
m_mapInfo = new BulletHMapInfo(id, initialMap, maxCoords.X - minCoords.X, maxCoords.Y - minCoords.Y);
|
||||
m_mapInfo.minCoords = minCoords;
|
||||
m_mapInfo.maxCoords = maxCoords;
|
||||
m_mapInfo.minZ = minCoords.Z;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user