aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2014-03-06 00:11:13 +0000
committerJustin Clark-Casey (justincc)2014-03-06 00:11:13 +0000
commit14569992e149b4c6ee097d88e3f5034edd653645 (patch)
tree458e4fb3f08567b29bec0ad141e05a3cf71e20d7 /OpenSim/Region/CoreModules/World
parentAdd UUID and ready status (whether region has finished starting up) to "show ... (diff)
downloadopensim-SC_OLD-14569992e149b4c6ee097d88e3f5034edd653645.zip
opensim-SC_OLD-14569992e149b4c6ee097d88e3f5034edd653645.tar.gz
opensim-SC_OLD-14569992e149b4c6ee097d88e3f5034edd653645.tar.bz2
opensim-SC_OLD-14569992e149b4c6ee097d88e3f5034edd653645.tar.xz
Prevent adding a land object if it overlaps any existing objects that have not had their bitmaps adjusted.
This is to prevent an immediate problem in http://opensimulator.org/mantis/view.php?id=7035 where a development code bug occasionally overlays all the existing parcels with a blank parcel owned by the estate manager and to gather more data. My guess is that this parcel is being created by the new code in LandManagementModule.GetLandObject(), probably some race between threads since this only happens occasionally. Adds regression tests for this case and for parcel subdivide.
Diffstat (limited to 'OpenSim/Region/CoreModules/World')
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs95
-rw-r--r--OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs114
2 files changed, 190 insertions, 19 deletions
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index 99db7ff..5c20899 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -66,6 +66,11 @@ namespace OpenSim.Region.CoreModules.World.Land
66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 66 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67 private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]"; 67 private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
68 68
69 /// <summary>
70 /// Minimum land unit size in region co-ordinates.
71 /// </summary>
72 public const int LandUnit = 4;
73
69 private static readonly string remoteParcelRequestPath = "0009/"; 74 private static readonly string remoteParcelRequestPath = "0009/";
70 75
71 private LandChannel landChannel; 76 private LandChannel landChannel;
@@ -79,7 +84,6 @@ namespace OpenSim.Region.CoreModules.World.Land
79 /// Local land ids at specified region co-ordinates (region size / 4) 84 /// Local land ids at specified region co-ordinates (region size / 4)
80 /// </value> 85 /// </value>
81 private int[,] m_landIDList; 86 private int[,] m_landIDList;
82 private const int landUnit = 4;
83 87
84 /// <value> 88 /// <value>
85 /// Land objects keyed by local id 89 /// Land objects keyed by local id
@@ -112,7 +116,7 @@ namespace OpenSim.Region.CoreModules.World.Land
112 public void AddRegion(Scene scene) 116 public void AddRegion(Scene scene)
113 { 117 {
114 m_scene = scene; 118 m_scene = scene;
115 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; 119 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
116 120
117 m_landIDList.Initialize(); 121 m_landIDList.Initialize();
118 landChannel = new LandChannel(scene, this); 122 landChannel = new LandChannel(scene, this);
@@ -296,7 +300,7 @@ namespace OpenSim.Region.CoreModules.World.Land
296 { 300 {
297 m_landList.Clear(); 301 m_landList.Clear();
298 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 302 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
299 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit]; 303 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
300 m_landIDList.Initialize(); 304 m_landIDList.Initialize();
301 } 305 }
302 } 306 }
@@ -590,7 +594,10 @@ namespace OpenSim.Region.CoreModules.World.Land
590 /// <summary> 594 /// <summary>
591 /// Adds a land object to the stored list and adds them to the landIDList to what they own 595 /// Adds a land object to the stored list and adds them to the landIDList to what they own
592 /// </summary> 596 /// </summary>
593 /// <param name="new_land">The land object being added</param> 597 /// <param name="new_land">
598 /// The land object being added.
599 /// Will return null if this overlaps with an existing parcel that has not had its bitmap adjusted.
600 /// </param>
594 public ILandObject AddLandObject(ILandObject land) 601 public ILandObject AddLandObject(ILandObject land)
595 { 602 {
596 ILandObject new_land = land.Copy(); 603 ILandObject new_land = land.Copy();
@@ -602,7 +609,7 @@ namespace OpenSim.Region.CoreModules.World.Land
602 609
603 lock (m_landList) 610 lock (m_landList)
604 { 611 {
605 int newLandLocalID = ++m_lastLandLocalID; 612 int newLandLocalID = m_lastLandLocalID + 1;
606 new_land.LandData.LocalID = newLandLocalID; 613 new_land.LandData.LocalID = newLandLocalID;
607 614
608 bool[,] landBitmap = new_land.GetLandBitmap(); 615 bool[,] landBitmap = new_land.GetLandBitmap();
@@ -617,6 +624,33 @@ namespace OpenSim.Region.CoreModules.World.Land
617 } 624 }
618 else 625 else
619 { 626 {
627 // If other land objects still believe that they occupy any parts of the same space,
628 // then do not allow the add to proceed.
629 for (int x = 0; x < landBitmap.GetLength(0); x++)
630 {
631 for (int y = 0; y < landBitmap.GetLength(1); y++)
632 {
633 if (landBitmap[x, y])
634 {
635 int lastRecordedLandId = m_landIDList[x, y];
636
637 if (lastRecordedLandId > 0)
638 {
639 ILandObject lastRecordedLo = m_landList[lastRecordedLandId];
640
641 if (lastRecordedLo.LandBitmap[x, y])
642 {
643 m_log.ErrorFormat(
644 "{0}: Cannot add parcel \"{1}\", local ID {2} at tile {3},{4} because this is still occupied by parcel \"{5}\", local ID {6}.",
645 LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y, lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID);
646
647 return null;
648 }
649 }
650 }
651 }
652 }
653
620 for (int x = 0; x < landBitmap.GetLength(0); x++) 654 for (int x = 0; x < landBitmap.GetLength(0); x++)
621 { 655 {
622 for (int y = 0; y < landBitmap.GetLength(1); y++) 656 for (int y = 0; y < landBitmap.GetLength(1); y++)
@@ -626,7 +660,7 @@ namespace OpenSim.Region.CoreModules.World.Land
626 // m_log.DebugFormat( 660 // m_log.DebugFormat(
627 // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", 661 // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
628 // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); 662 // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
629 663
630 m_landIDList[x, y] = newLandLocalID; 664 m_landIDList[x, y] = newLandLocalID;
631 } 665 }
632 } 666 }
@@ -634,10 +668,12 @@ namespace OpenSim.Region.CoreModules.World.Land
634 } 668 }
635 669
636 m_landList.Add(newLandLocalID, new_land); 670 m_landList.Add(newLandLocalID, new_land);
671 m_lastLandLocalID++;
637 } 672 }
638 673
639 new_land.ForceUpdateLandInfo(); 674 new_land.ForceUpdateLandInfo();
640 m_scene.EventManager.TriggerLandObjectAdded(new_land); 675 m_scene.EventManager.TriggerLandObjectAdded(new_land);
676
641 return new_land; 677 return new_land;
642 } 678 }
643 679
@@ -801,8 +837,18 @@ namespace OpenSim.Region.CoreModules.World.Land
801 return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */); 837 return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */);
802 } 838 }
803 839
804 // Given a region position, return the parcel land object for that location 840 /// <summary>
805 private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectNotFound) 841 /// Given a region position, return the parcel land object for that location
842 /// </summary>
843 /// <returns>
844 /// The land object.
845 /// </returns>
846 /// <param name='x'></param>
847 /// <param name='y'></param>
848 /// <param name='returnNullIfLandObjectNotFound'>
849 /// Return null if the land object requested is not within the region's bounds.
850 /// </param>
851 private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds)
806 { 852 {
807 ILandObject ret = null; 853 ILandObject ret = null;
808 854
@@ -810,7 +856,7 @@ namespace OpenSim.Region.CoreModules.World.Land
810 { 856 {
811 // These exceptions here will cause a lot of complaints from the users specifically because 857 // These exceptions here will cause a lot of complaints from the users specifically because
812 // they happen every time at border crossings 858 // they happen every time at border crossings
813 if (returnNullIfLandObjectNotFound) 859 if (returnNullIfLandObjectOutsideBounds)
814 return null; 860 return null;
815 else 861 else
816 throw new Exception( 862 throw new Exception(
@@ -823,7 +869,7 @@ namespace OpenSim.Region.CoreModules.World.Land
823 { 869 {
824 try 870 try
825 { 871 {
826 int landID = m_landIDList[x / landUnit, y / landUnit]; 872 int landID = m_landIDList[x / LandUnit, y / LandUnit];
827 if (landID == 0) 873 if (landID == 0)
828 { 874 {
829 // Zero is the uninitialized value saying there is no parcel for this location. 875 // Zero is the uninitialized value saying there is no parcel for this location.
@@ -856,7 +902,11 @@ namespace OpenSim.Region.CoreModules.World.Land
856 newLand.SetLandBitmap(CreateBitmapForID(0)); 902 newLand.SetLandBitmap(CreateBitmapForID(0));
857 newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 903 newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
858 newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); 904 newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
859 AddLandObject(newLand); 905 newLand = AddLandObject(newLand);
906
907 if (newLand == null)
908 return null;
909
860 landID = m_lastLandLocalID; 910 landID = m_lastLandLocalID;
861 } 911 }
862 } 912 }
@@ -868,16 +918,19 @@ namespace OpenSim.Region.CoreModules.World.Land
868 m_log.ErrorFormat( 918 m_log.ErrorFormat(
869 "{0} GetLandObject: Tried to retrieve land object from out of bounds co-ordinate ({1},{2}) in {3}. landListSize=({4},{5})", 919 "{0} GetLandObject: Tried to retrieve land object from out of bounds co-ordinate ({1},{2}) in {3}. landListSize=({4},{5})",
870 LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList.GetLength(0), m_landIDList.GetLength(1)); 920 LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList.GetLength(0), m_landIDList.GetLength(1));
921
871 return null; 922 return null;
872 } 923 }
873 catch 924 catch
874 { 925 {
875 m_log.ErrorFormat( 926 m_log.ErrorFormat(
876 "{0} GetLandObject: LandID not in landlist. XY=<{1},{2}> in {3}. landID[x,y]={4}", 927 "{0} GetLandObject: LandID not in landlist. XY=<{1},{2}> in {3}. landID[x,y]={4}",
877 LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList[x/landUnit, y/landUnit]); 928 LogHeader, x, y, m_scene.RegionInfo.RegionName, m_landIDList[x/LandUnit, y/LandUnit]);
929
878 return null; 930 return null;
879 } 931 }
880 } 932 }
933
881 return ret; 934 return ret;
882 } 935 }
883 936
@@ -1062,8 +1115,12 @@ namespace OpenSim.Region.CoreModules.World.Land
1062 1115
1063 //Now add the new land object 1116 //Now add the new land object
1064 ILandObject result = AddLandObject(newLand); 1117 ILandObject result = AddLandObject(newLand);
1065 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); 1118
1066 result.SendLandUpdateToAvatarsOverMe(); 1119 if (result != null)
1120 {
1121 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData);
1122 result.SendLandUpdateToAvatarsOverMe();
1123 }
1067 } 1124 }
1068 1125
1069 /// <summary> 1126 /// <summary>
@@ -1157,11 +1214,11 @@ namespace OpenSim.Region.CoreModules.World.Land
1157 int sequenceID = 0; 1214 int sequenceID = 0;
1158 1215
1159 // Layer data is in landUnit (4m) chunks 1216 // Layer data is in landUnit (4m) chunks
1160 for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); y++) 1217 for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1161 { 1218 {
1162 for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / landUnit); x++) 1219 for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1163 { 1220 {
1164 byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * landUnit, y * landUnit), x, y, remote_client); 1221 byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client);
1165 byteArrayCount++; 1222 byteArrayCount++;
1166 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) 1223 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
1167 { 1224 {
@@ -1214,11 +1271,11 @@ namespace OpenSim.Region.CoreModules.World.Land
1214 ILandObject southParcel = null; 1271 ILandObject southParcel = null;
1215 if (x > 0) 1272 if (x > 0)
1216 { 1273 {
1217 westParcel = GetLandObject((x - 1) * landUnit, y * landUnit); 1274 westParcel = GetLandObject((x - 1) * LandUnit, y * LandUnit);
1218 } 1275 }
1219 if (y > 0) 1276 if (y > 0)
1220 { 1277 {
1221 southParcel = GetLandObject(x * landUnit, (y - 1) * landUnit); 1278 southParcel = GetLandObject(x * LandUnit, (y - 1) * LandUnit);
1222 } 1279 }
1223 1280
1224 if (x == 0) 1281 if (x == 0)
diff --git a/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs
new file mode 100644
index 0000000..a886e33
--- /dev/null
+++ b/OpenSim/Region/CoreModules/World/Land/Tests/LandManagementModuleTests.cs
@@ -0,0 +1,114 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using NUnit.Framework;
30using OpenMetaverse;
31using OpenSim.Framework;
32using OpenSim.Region.Framework.Scenes;
33using OpenSim.Tests.Common;
34using OpenSim.Tests.Common.Mock;
35
36namespace OpenSim.Region.CoreModules.World.Land.Tests
37{
38 public class LandManagementModuleTests
39 {
40 [Test]
41 public void TestAddLandObject()
42 {
43 TestHelpers.InMethod();
44// TestHelpers.EnableLogging();
45
46 UUID userId = TestHelpers.ParseTail(0x1);
47
48 LandManagementModule lmm = new LandManagementModule();
49 Scene scene = new SceneHelpers().SetupScene();
50 SceneHelpers.SetupSceneModules(scene, lmm);
51
52 ILandObject lo = new LandObject(userId, false, scene);
53 lo.LandData.Name = "lo1";
54 lo.SetLandBitmap(
55 lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
56 lo = lmm.AddLandObject(lo);
57
58 // TODO: Should add asserts to check that land object was added properly.
59
60 // At the moment, this test just makes sure that we can't add a land object that overlaps the areas that
61 // the first still holds.
62 ILandObject lo2 = new LandObject(userId, false, scene);
63 lo2.SetLandBitmap(
64 lo2.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
65 lo2.LandData.Name = "lo2";
66 lo2 = lmm.AddLandObject(lo2);
67
68 {
69 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
70 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
71 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
72 }
73
74 {
75 ILandObject loAtCoord = lmm.GetLandObject((int)Constants.RegionSize - 1, ((int)Constants.RegionSize - 1));
76 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
77 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
78 }
79 }
80
81 [Test]
82 public void TestSubdivide()
83 {
84 TestHelpers.InMethod();
85// TestHelpers.EnableLogging();
86
87 UUID userId = TestHelpers.ParseTail(0x1);
88
89 LandManagementModule lmm = new LandManagementModule();
90 Scene scene = new SceneHelpers().SetupScene();
91 SceneHelpers.SetupSceneModules(scene, lmm);
92
93 ILandObject lo = new LandObject(userId, false, scene);
94 lo.LandData.Name = "lo1";
95 lo.SetLandBitmap(
96 lo.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
97 lo = lmm.AddLandObject(lo);
98
99 lmm.Subdivide(0, 0, LandManagementModule.LandUnit, LandManagementModule.LandUnit, userId);
100
101 {
102 ILandObject loAtCoord = lmm.GetLandObject(0, 0);
103 Assert.That(loAtCoord.LandData.LocalID, Is.Not.EqualTo(lo.LandData.LocalID));
104 Assert.That(loAtCoord.LandData.GlobalID, Is.Not.EqualTo(lo.LandData.GlobalID));
105 }
106
107 {
108 ILandObject loAtCoord = lmm.GetLandObject(LandManagementModule.LandUnit, LandManagementModule.LandUnit);
109 Assert.That(loAtCoord.LandData.LocalID, Is.EqualTo(lo.LandData.LocalID));
110 Assert.That(loAtCoord.LandData.GlobalID, Is.EqualTo(lo.LandData.GlobalID));
111 }
112 }
113 }
114} \ No newline at end of file