varregion: Massive work to LandManagementModule and LandObject to

handle variable sized regions. Many changes for both the region and parcels.
Most of the constant "4" (for the 4x4 parcel units) have been replaced
with symbols and math.
varregion
Robert Adams 2013-11-08 20:51:09 -08:00
parent f7bd0da026
commit a7a837550e
2 changed files with 300 additions and 188 deletions

View File

@ -65,6 +65,7 @@ namespace OpenSim.Region.CoreModules.World.Land
public class LandManagementModule : INonSharedRegionModule public class LandManagementModule : INonSharedRegionModule
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
private static readonly string remoteParcelRequestPath = "0009/"; private static readonly string remoteParcelRequestPath = "0009/";
@ -76,15 +77,11 @@ namespace OpenSim.Region.CoreModules.World.Land
protected IPrimCountModule m_primCountModule; protected IPrimCountModule m_primCountModule;
protected IDialogModule m_Dialog; protected IDialogModule m_Dialog;
// Minimum for parcels to work is 64m even if we don't actually use them.
#pragma warning disable 0429
private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
#pragma warning restore 0429
/// <value> /// <value>
/// Local land ids at specified region co-ordinates (region size / 4) /// Local land ids at specified region co-ordinates (region size / 4)
/// </value> /// </value>
private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; private int[,] m_landIDList;
private const int landUnit = 4;
/// <value> /// <value>
/// Land objects keyed by local id /// Land objects keyed by local id
@ -117,6 +114,8 @@ namespace OpenSim.Region.CoreModules.World.Land
public void AddRegion(Scene scene) public void AddRegion(Scene scene)
{ {
m_scene = scene; m_scene = scene;
m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
m_landIDList.Initialize(); m_landIDList.Initialize();
landChannel = new LandChannel(scene, this); landChannel = new LandChannel(scene, this);
@ -326,6 +325,7 @@ namespace OpenSim.Region.CoreModules.World.Land
{ {
m_landList.Clear(); m_landList.Clear();
m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
m_landIDList.Initialize(); m_landIDList.Initialize();
} }
} }
@ -340,7 +340,8 @@ namespace OpenSim.Region.CoreModules.World.Land
"[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0,
(int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY));
fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
@ -467,8 +468,8 @@ namespace OpenSim.Region.CoreModules.World.Land
public void SendLandUpdate(ScenePresence avatar, bool force) 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))), ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
(int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); (int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
if (over != null) if (over != null)
{ {
@ -634,17 +635,29 @@ namespace OpenSim.Region.CoreModules.World.Land
new_land.LandData.LocalID = newLandLocalID; new_land.LandData.LocalID = newLandLocalID;
bool[,] landBitmap = new_land.GetLandBitmap(); bool[,] landBitmap = new_land.GetLandBitmap();
for (int x = 0; x < landArrayMax; x++) m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). bitmap[600/4,600/4]={3}, newLocalID={4}",
LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), landBitmap[600/4, 600/4], 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), m_landIDList.GetLength(1), landBitmap.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( if (landBitmap[x, y])
// "[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_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
m_landIDList[x, y] = newLandLocalID; // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
m_landIDList[x, y] = newLandLocalID;
}
} }
} }
} }
@ -666,9 +679,9 @@ namespace OpenSim.Region.CoreModules.World.Land
ILandObject land; ILandObject land;
lock (m_landList) lock (m_landList)
{ {
for (int x = 0; x < 64; x++) for (int x = 0; x < m_landIDList.GetLength(0); x++)
{ {
for (int y = 0; y < 64; y++) for (int y = 0; y < m_landIDList.GetLength(1); y++)
{ {
if (m_landIDList[x, y] == local_id) if (m_landIDList[x, y] == local_id)
{ {
@ -720,9 +733,9 @@ namespace OpenSim.Region.CoreModules.World.Land
bool[,] landBitmapSlave = slave.GetLandBitmap(); bool[,] landBitmapSlave = slave.GetLandBitmap();
lock (m_landList) lock (m_landList)
{ {
for (int x = 0; x < 64; x++) for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
{ {
for (int y = 0; y < 64; y++) for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
{ {
if (landBitmapSlave[x, y]) if (landBitmapSlave[x, y])
{ {
@ -756,23 +769,28 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns>Land object at the point supplied</returns> /// <returns>Land object at the point supplied</returns>
public ILandObject GetLandObject(float x_float, float y_float) public ILandObject GetLandObject(float x_float, float y_float)
{ {
return GetLandObject((int)x_float, (int)y_float);
/*
int x; int x;
int y; int y;
if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0)
return null; return null;
try try
{ {
x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit));
y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit));
} }
catch (OverflowException) catch (OverflowException)
{ {
return null; return null;
} }
if (x >= 64 || y >= 64 || x < 0 || y < 0) if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit)
|| y >= (m_scene.RegionInfo.RegionSizeY / landUnit)
|| x < 0
|| y < 0)
{ {
return null; return null;
} }
@ -788,38 +806,112 @@ namespace OpenSim.Region.CoreModules.World.Land
// m_log.DebugFormat( // m_log.DebugFormat(
// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", // "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}",
// x, y, m_scene.RegionInfo.RegionName); // x, y, m_scene.RegionInfo.RegionName);
if (m_landList.ContainsKey(m_landIDList[x, y])) try
return m_landList[m_landIDList[x, y]]; {
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; return null;
} }
*/
} }
// Given a region position, return the parcel land object for that location
public ILandObject GetLandObject(int x, int y) public ILandObject GetLandObject(int x, int y)
{ {
if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) 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 // These exceptions here will cause a lot of complaints from the users specifically because
// they happen every time at border crossings // they happen every time at border crossings
throw new Exception("Error: Parcel not found at point " + x + ", " + y); 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) lock (m_landIDList)
{ {
try 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) catch (IndexOutOfRangeException)
{ {
// m_log.WarnFormat( m_log.ErrorFormat(
// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}", "{0} GetLandObject: Tried to retrieve land object from out of bounds co-ordinate ({1},{2}) in {3}. landListSize=({4},{5})",
// x, y, m_scene.RegionInfo.RegionName); 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 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 #endregion
@ -1082,85 +1174,93 @@ namespace OpenSim.Region.CoreModules.World.Land
byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
int byteArrayCount = 0; int byteArrayCount = 0;
int sequenceID = 0; int sequenceID = 0;
int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize;
// Layer data is in landUnit (4m) chunks
for (int y = 0; y < blockmeters; y++) 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 byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * landUnit, y * landUnit), x, y, remote_client);
byteArrayCount++;
ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4); if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
if (currentParcelBlock != null)
{ {
if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) remote_client.SendLandParcelOverlay(byteArray, sequenceID);
{ byteArrayCount = 0;
//Owner Flag sequenceID++;
tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); byteArray = new byte[LAND_BLOCKS_PER_PACKET];
}
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];
}
} }
} }
} }
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, public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,

View File

@ -45,10 +45,10 @@ namespace OpenSim.Region.CoreModules.World.Land
#region Member Variables #region Member Variables
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
#pragma warning disable 0429 private static readonly string LogHeader = "[LAND OBJECT]";
private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
#pragma warning restore 0429 private bool[,] m_landBitmap;
private bool[,] m_landBitmap = new bool[landArrayMax,landArrayMax]; private readonly int landUnit = 4;
private int m_lastSeqId = 0; private int m_lastSeqId = 0;
@ -93,12 +93,12 @@ namespace OpenSim.Region.CoreModules.World.Land
{ {
get get
{ {
for (int y = 0; y < landArrayMax; y++) for (int y = 0; y < LandBitmap.GetLength(1); y++)
{ {
for (int x = 0; x < landArrayMax; x++) for (int x = 0; x < LandBitmap.GetLength(0); x++)
{ {
if (LandBitmap[x, y]) if (LandBitmap[x, y])
return new Vector3(x * 4, y * 4, 0); return new Vector3(x * landUnit, y * landUnit, 0);
} }
} }
@ -110,13 +110,13 @@ namespace OpenSim.Region.CoreModules.World.Land
{ {
get get
{ {
for (int y = landArrayMax - 1; y >= 0; y--) for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--)
{ {
for (int x = landArrayMax - 1; x >= 0; x--) for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--)
{ {
if (LandBitmap[x, y]) if (LandBitmap[x, y])
{ {
return new Vector3(x * 4 + 4, y * 4 + 4, 0); return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
} }
} }
} }
@ -130,6 +130,8 @@ namespace OpenSim.Region.CoreModules.World.Land
public LandObject(UUID owner_id, bool is_group_owned, Scene scene) public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
{ {
m_scene = scene; m_scene = scene;
m_landBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
LandData.OwnerID = owner_id; LandData.OwnerID = owner_id;
if (is_group_owned) if (is_group_owned)
LandData.GroupID = owner_id; LandData.GroupID = owner_id;
@ -152,9 +154,9 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns>Returns true if the piece of land contains the specified point</returns> /// <returns>Returns true if the piece of land contains the specified point</returns>
public bool ContainsPoint(int x, int y) public bool ContainsPoint(int x, int y)
{ {
if (x >= 0 && y >= 0 && x < Constants.RegionSize && y < Constants.RegionSize) if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
{ {
return (LandBitmap[x / 4, y / 4] == true); return (LandBitmap[x / landUnit, y / landUnit] == true);
} }
else else
{ {
@ -194,7 +196,7 @@ namespace OpenSim.Region.CoreModules.World.Land
else else
{ {
// Normal Calculations // 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.ObjectCapacity
* (float)m_scene.RegionInfo.RegionSettings.ObjectBonus); * (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! // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL!
@ -211,7 +213,7 @@ namespace OpenSim.Region.CoreModules.World.Land
else else
{ {
//Normal Calculations //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); * (float)m_scene.RegionInfo.ObjectCapacity);
return simMax; return simMax;
} }
@ -224,7 +226,12 @@ namespace OpenSim.Region.CoreModules.World.Land
public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client) public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
{ {
IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>(); 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) if (estateModule != null)
regionFlags = estateModule.GetRegionFlags(); regionFlags = estateModule.GetRegionFlags();
@ -546,8 +553,8 @@ namespace OpenSim.Region.CoreModules.World.Land
try try
{ {
over = over =
m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
} }
catch (Exception) catch (Exception)
{ {
@ -694,15 +701,15 @@ namespace OpenSim.Region.CoreModules.World.Land
/// </summary> /// </summary>
private void UpdateAABBAndAreaValues() private void UpdateAABBAndAreaValues()
{ {
int min_x = 64; int min_x = 10000;
int min_y = 64; int min_y = 10000;
int max_x = 0; int max_x = 0;
int max_y = 0; int max_y = 0;
int tempArea = 0; int tempArea = 0;
int x, y; int x, y;
for (x = 0; x < 64; x++) for (x = 0; x < LandBitmap.GetLength(0); x++)
{ {
for (y = 0; y < 64; y++) for (y = 0; y < LandBitmap.GetLength(1); y++)
{ {
if (LandBitmap[x, y] == true) if (LandBitmap[x, y] == true)
{ {
@ -710,31 +717,31 @@ namespace OpenSim.Region.CoreModules.World.Land
if (min_y > y) min_y = y; if (min_y > y) min_y = y;
if (max_x < x) max_x = x; if (max_x < x) max_x = x;
if (max_y < y) max_y = y; 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; int tx = min_x * landUnit;
if (tx > ((int)Constants.RegionSize - 1)) if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
tx = ((int)Constants.RegionSize - 1); tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
int ty = min_y * 4; int ty = min_y * landUnit;
if (ty > ((int)Constants.RegionSize - 1)) if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
ty = ((int)Constants.RegionSize - 1); ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
LandData.AABBMin = LandData.AABBMin =
new Vector3( 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; tx = max_x * landUnit;
if (tx > ((int)Constants.RegionSize - 1)) if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
tx = ((int)Constants.RegionSize - 1); tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
ty = max_y * 4; ty = max_y * landUnit;
if (ty > ((int)Constants.RegionSize - 1)) if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
ty = ((int)Constants.RegionSize - 1); ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
LandData.AABBMax LandData.AABBMax
= new Vector3( = 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; LandData.Area = tempArea;
} }
@ -746,20 +753,11 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <summary> /// <summary>
/// Sets the land's bitmap manually /// Sets the land's bitmap manually
/// </summary> /// </summary>
/// <param name="bitmap">64x64 block representing where this land is on a map</param> /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
public void SetLandBitmap(bool[,] bitmap) public void SetLandBitmap(bool[,] bitmap)
{ {
if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) LandBitmap = bitmap;
{ ForceUpdateLandInfo();
//Throw an exception - The bitmap is not 64x64
//throw new Exception("Error: Invalid Parcel Bitmap");
}
else
{
//Valid: Lets set it
LandBitmap = bitmap;
ForceUpdateLandInfo();
}
} }
/// <summary> /// <summary>
@ -773,12 +771,12 @@ namespace OpenSim.Region.CoreModules.World.Land
public bool[,] BasicFullRegionLandBitmap() public bool[,] BasicFullRegionLandBitmap()
{ {
return GetSquareLandBitmap(0, 0, (int) Constants.RegionSize, (int) Constants.RegionSize); return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY);
} }
public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
{ {
bool[,] tempBitmap = new bool[64,64]; bool[,] tempBitmap = new bool[(end_x-start_x)/landUnit,(end_y-start_y)/landUnit];
tempBitmap.Initialize(); tempBitmap.Initialize();
tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
@ -798,19 +796,13 @@ namespace OpenSim.Region.CoreModules.World.Land
public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
bool set_value) bool set_value)
{ {
if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
{
//Throw an exception - The bitmap is not 64x64
//throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
}
int x, y; int x, y;
for (y = 0; y < 64; y++) for (y = 0; y < land_bitmap.GetLength(1); y++)
{ {
for (x = 0; x < 64; x++) for (x = 0; x < land_bitmap.GetLength(0); x++)
{ {
if (x >= start_x / 4 && x < end_x / 4 if (x >= start_x / landUnit && x < end_x / landUnit
&& y >= start_y / 4 && y < end_y / 4) && y >= start_y / landUnit && y < end_y / landUnit)
{ {
land_bitmap[x, y] = set_value; land_bitmap[x, y] = set_value;
} }
@ -827,21 +819,21 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns></returns> /// <returns></returns>
public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
{ {
if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
|| bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
|| bitmap_add.Rank != 2
|| bitmap_base.Rank != 2)
{ {
//Throw an exception - The bitmap is not 64x64 throw new Exception(
throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
} LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2) );
{
//Throw an exception - The bitmap is not 64x64
throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
} }
int x, y; int x, y;
for (y = 0; y < 64; y++) for (y = 0; y < bitmap_base.GetLength(1); y++)
{ {
for (x = 0; x < 64; x++) for (x = 0; x < bitmap_add.GetLength(0); x++)
{ {
if (bitmap_add[x, y]) if (bitmap_add[x, y])
{ {
@ -858,13 +850,13 @@ namespace OpenSim.Region.CoreModules.World.Land
/// <returns></returns> /// <returns></returns>
private byte[] ConvertLandBitmapToBytes() private byte[] ConvertLandBitmapToBytes()
{ {
byte[] tempConvertArr = new byte[512]; byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
byte tempByte = 0; byte tempByte = 0;
int x, y, i, byteNum = 0; int byteNum = 0;
i = 0; int i = 0;
for (y = 0; y < 64; y++) for (int y = 0; y < LandBitmap.GetLength(1); y++)
{ {
for (x = 0; x < 64; x++) for (int x = 0; x < LandBitmap.GetLength(0); x++)
{ {
tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8)); tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8));
if (i % 8 == 0) if (i % 8 == 0)
@ -881,25 +873,45 @@ namespace OpenSim.Region.CoreModules.World.Land
private bool[,] ConvertBytesToLandBitmap() private bool[,] ConvertBytesToLandBitmap()
{ {
bool[,] tempConvertMap = new bool[landArrayMax, landArrayMax]; bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
tempConvertMap.Initialize(); tempConvertMap.Initialize();
byte tempByte = 0; byte tempByte = 0;
int x = 0, y = 0, i = 0, bitNum = 0; // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
for (i = 0; i < 512; i++) int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
if (bitmapLen == 512)
{
// Legacy bitmap being passed in. Use the legacy region size
// and only set the lower area of the larger region.
xLen = (int)(Constants.RegionSize / landUnit);
}
m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
int x = 0, y = 0;
for (int i = 0; i < bitmapLen; i++)
{ {
tempByte = LandData.Bitmap[i]; tempByte = LandData.Bitmap[i];
for (bitNum = 0; bitNum < 8; bitNum++) for (int bitNum = 0; bitNum < 8; bitNum++)
{ {
bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
tempConvertMap[x, y] = bit; try
{
tempConvertMap[x, y] = bit;
}
catch (Exception e)
{
m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
}
x++; x++;
if (x > 63) if (x >= xLen)
{ {
x = 0; x = 0;
y++; y++;
} }
} }
} }
return tempConvertMap; return tempConvertMap;
} }