diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs index 51ed83f43c..3f21f85ddd 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs @@ -65,6 +65,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/"; @@ -76,15 +77,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 - /// /// Local land ids at specified region co-ordinates (region size / 4) /// - private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; + private int[,] m_landIDList; + private const int landUnit = 4; /// /// Land objects keyed by local id @@ -117,6 +114,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); @@ -326,6 +325,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(); } } @@ -340,7 +340,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(); @@ -467,8 +468,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) { @@ -634,17 +635,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}). 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( -// "[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; + } } } } @@ -666,9 +679,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) { @@ -720,9 +733,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]) { @@ -756,23 +769,28 @@ namespace OpenSim.Region.CoreModules.World.Land /// Land object at the point supplied public ILandObject GetLandObject(float x_float, float y_float) { + return GetLandObject((int)x_float, (int)y_float); + /* 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; } @@ -788,38 +806,112 @@ 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; } + */ } + // Given a region position, return the parcel land object for that location 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 // 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) { 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 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 @@ -1082,85 +1174,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, diff --git a/OpenSim/Region/CoreModules/World/Land/LandObject.cs b/OpenSim/Region/CoreModules/World/Land/LandObject.cs index e55c9ed87f..0bde877ea1 100644 --- a/OpenSim/Region/CoreModules/World/Land/LandObject.cs +++ b/OpenSim/Region/CoreModules/World/Land/LandObject.cs @@ -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,12 +93,12 @@ 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); } } @@ -110,13 +110,13 @@ 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); } } } @@ -130,6 +130,8 @@ namespace OpenSim.Region.CoreModules.World.Land public LandObject(UUID owner_id, bool is_group_owned, Scene scene) { m_scene = scene; + 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 +154,9 @@ namespace OpenSim.Region.CoreModules.World.Land /// Returns true if the piece of land contains the specified point 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 +196,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 +213,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 +226,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(); - 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(); @@ -546,8 +553,8 @@ namespace OpenSim.Region.CoreModules.World.Land try { over = - m_scene.LandChannel.GetLandObject(Util.Clamp((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)Constants.RegionSize - 1)), - Util.Clamp((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)Constants.RegionSize - 1))); + m_scene.LandChannel.GetLandObject(Util.Clamp((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)), + Util.Clamp((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1))); } catch (Exception) { @@ -694,15 +701,15 @@ namespace OpenSim.Region.CoreModules.World.Land /// 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) { @@ -710,31 +717,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; } @@ -746,20 +753,11 @@ namespace OpenSim.Region.CoreModules.World.Land /// /// Sets the land's bitmap manually /// - /// 64x64 block representing where this land is on a map + /// block representing where this land is on a map mapped in a 4x4 meter grid 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; + ForceUpdateLandInfo(); } /// @@ -773,12 +771,12 @@ 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]; + bool[,] tempBitmap = new bool[(end_x-start_x)/landUnit,(end_y-start_y)/landUnit]; tempBitmap.Initialize(); 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, 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; } @@ -827,21 +819,21 @@ namespace OpenSim.Region.CoreModules.World.Land /// 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]) { @@ -858,13 +850,13 @@ namespace OpenSim.Region.CoreModules.World.Land /// 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) @@ -881,25 +873,45 @@ namespace OpenSim.Region.CoreModules.World.Land 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; }