aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs938
1 files changed, 711 insertions, 227 deletions
diff --git a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
index bad7205..92f6c1b 100644
--- a/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
+++ b/OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs
@@ -42,10 +42,9 @@ using OpenSim.Framework.Capabilities;
42using OpenSim.Framework.Console; 42using OpenSim.Framework.Console;
43using OpenSim.Framework.Servers; 43using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 44using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
46using OpenSim.Region.Framework.Interfaces; 45using OpenSim.Region.Framework.Interfaces;
47using OpenSim.Region.Framework.Scenes; 46using OpenSim.Region.Framework.Scenes;
48using OpenSim.Region.Physics.Manager; 47using OpenSim.Region.PhysicsModules.SharedBase;
49using OpenSim.Services.Interfaces; 48using OpenSim.Services.Interfaces;
50using Caps = OpenSim.Framework.Capabilities.Caps; 49using Caps = OpenSim.Framework.Capabilities.Caps;
51using GridRegion = OpenSim.Services.Interfaces.GridRegion; 50using GridRegion = OpenSim.Services.Interfaces.GridRegion;
@@ -65,25 +64,27 @@ namespace OpenSim.Region.CoreModules.World.Land
65 public class LandManagementModule : INonSharedRegionModule 64 public class LandManagementModule : INonSharedRegionModule
66 { 65 {
67 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]";
68
69 /// <summary>
70 /// Minimum land unit size in region co-ordinates.
71 /// </summary>
72 public const int LandUnit = 4;
68 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;
72 private Scene m_scene; 77 private Scene m_scene;
73 protected Commander m_commander = new Commander("land"); 78
74 79 protected IGroupsModule m_groupManager;
75 protected IUserManagement m_userManager; 80 protected IUserManagement m_userManager;
76 protected IPrimCountModule m_primCountModule; 81 protected IPrimCountModule m_primCountModule;
77 82 protected IDialogModule m_Dialog;
78 // Minimum for parcels to work is 64m even if we don't actually use them.
79 #pragma warning disable 0429
80 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
81 #pragma warning restore 0429
82 83
83 /// <value> 84 /// <value>
84 /// Local land ids at specified region co-ordinates (region size / 4) 85 /// Local land ids at specified region co-ordinates (region size / 4)
85 /// </value> 86 /// </value>
86 private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax]; 87 private int[,] m_landIDList;
87 88
88 /// <value> 89 /// <value>
89 /// Land objects keyed by local id 90 /// Land objects keyed by local id
@@ -97,11 +98,17 @@ namespace OpenSim.Region.CoreModules.World.Land
97 // caches ExtendedLandData 98 // caches ExtendedLandData
98 private Cache parcelInfoCache; 99 private Cache parcelInfoCache;
99 100
101
100 /// <summary> 102 /// <summary>
101 /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions. 103 /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
102 /// </summary> 104 /// </summary>
103 private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>(); 105 private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>();
104 106
107 // Enables limiting parcel layer info transmission when doing simple updates
108 private bool shouldLimitParcelLayerInfoToViewDistance { get; set; }
109 // "View distance" for sending parcel layer info if asked for from a view point in the region
110 private int parcelLayerViewDistance { get; set; }
111
105 #region INonSharedRegionModule Members 112 #region INonSharedRegionModule Members
106 113
107 public Type ReplaceableInterface 114 public Type ReplaceableInterface
@@ -111,12 +118,20 @@ namespace OpenSim.Region.CoreModules.World.Land
111 118
112 public void Initialise(IConfigSource source) 119 public void Initialise(IConfigSource source)
113 { 120 {
121 shouldLimitParcelLayerInfoToViewDistance = true;
122 parcelLayerViewDistance = 128;
123 IConfig landManagementConfig = source.Configs["LandManagement"];
124 if (landManagementConfig != null)
125 {
126 shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance);
127 parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance);
128 }
114 } 129 }
115 130
116 public void AddRegion(Scene scene) 131 public void AddRegion(Scene scene)
117 { 132 {
118 m_scene = scene; 133 m_scene = scene;
119 m_landIDList.Initialize(); 134 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
120 landChannel = new LandChannel(scene, this); 135 landChannel = new LandChannel(scene, this);
121 136
122 parcelInfoCache = new Cache(); 137 parcelInfoCache = new Cache();
@@ -139,28 +154,26 @@ namespace OpenSim.Region.CoreModules.World.Land
139 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage; 154 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
140 m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan; 155 m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan;
141 m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps; 156 m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
142 m_scene.EventManager.OnPluginConsole += EventManagerOnPluginConsole;
143 157
144 lock (m_scene) 158 lock (m_scene)
145 { 159 {
146 m_scene.LandChannel = (ILandChannel)landChannel; 160 m_scene.LandChannel = (ILandChannel)landChannel;
147 } 161 }
148 162
149 InstallInterfaces(); 163 RegisterCommands();
150 } 164 }
151 165
152 public void RegionLoaded(Scene scene) 166 public void RegionLoaded(Scene scene)
153 { 167 {
154 m_userManager = m_scene.RequestModuleInterface<IUserManagement>(); 168 m_userManager = m_scene.RequestModuleInterface<IUserManagement>();
155 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>(); 169 m_groupManager = m_scene.RequestModuleInterface<IGroupsModule>();
170 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>();
171 m_Dialog = m_scene.RequestModuleInterface<IDialogModule>();
156 } 172 }
157 173
158 public void RemoveRegion(Scene scene) 174 public void RemoveRegion(Scene scene)
159 { 175 {
160 // TODO: Also release other event manager listeners here 176 // TODO: Release event manager listeners here
161
162 m_scene.EventManager.OnPluginConsole -= EventManagerOnPluginConsole;
163 m_scene.UnregisterModuleCommander(m_commander.Name);
164 } 177 }
165 178
166// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason) 179// private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
@@ -168,30 +181,7 @@ namespace OpenSim.Region.CoreModules.World.Land
168// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y); 181// ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
169// reason = "You are not allowed to enter this sim."; 182// reason = "You are not allowed to enter this sim.";
170// return nearestParcel != null; 183// return nearestParcel != null;
171// } 184// }
172
173 /// <summary>
174 /// Processes commandline input. Do not call directly.
175 /// </summary>
176 /// <param name="args">Commandline arguments</param>
177 protected void EventManagerOnPluginConsole(string[] args)
178 {
179 if (args[0] == "land")
180 {
181 if (args.Length == 1)
182 {
183 m_commander.ProcessConsoleCommand("help", new string[0]);
184 return;
185 }
186
187 string[] tmpArgs = new string[args.Length - 2];
188 int i;
189 for (i = 2; i < args.Length; i++)
190 tmpArgs[i - 2] = args[i];
191
192 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
193 }
194 }
195 185
196 void EventManagerOnNewClient(IClientAPI client) 186 void EventManagerOnNewClient(IClientAPI client)
197 { 187 {
@@ -210,6 +200,10 @@ namespace OpenSim.Region.CoreModules.World.Land
210 client.OnParcelInfoRequest += ClientOnParcelInfoRequest; 200 client.OnParcelInfoRequest += ClientOnParcelInfoRequest;
211 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup; 201 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup;
212 client.OnPreAgentUpdate += ClientOnPreAgentUpdate; 202 client.OnPreAgentUpdate += ClientOnPreAgentUpdate;
203 client.OnParcelEjectUser += ClientOnParcelEjectUser;
204 client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
205 client.OnSetStartLocationRequest += ClientOnSetHome;
206
213 207
214 EntityBase presenceEntity; 208 EntityBase presenceEntity;
215 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence) 209 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence)
@@ -293,14 +287,15 @@ namespace OpenSim.Region.CoreModules.World.Land
293 LandData newData = data.Copy(); 287 LandData newData = data.Copy();
294 newData.LocalID = local_id; 288 newData.LocalID = local_id;
295 289
290 ILandObject land;
296 lock (m_landList) 291 lock (m_landList)
297 { 292 {
298 if (m_landList.ContainsKey(local_id)) 293 if (m_landList.TryGetValue(local_id, out land))
299 { 294 land.LandData = newData;
300 m_landList[local_id].LandData = newData;
301 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, m_landList[local_id]);
302 }
303 } 295 }
296
297 if (land != null)
298 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land);
304 } 299 }
305 300
306 public bool AllowedForcefulBans 301 public bool AllowedForcefulBans
@@ -319,7 +314,7 @@ namespace OpenSim.Region.CoreModules.World.Land
319 { 314 {
320 m_landList.Clear(); 315 m_landList.Clear();
321 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1; 316 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
322 m_landIDList.Initialize(); 317 m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
323 } 318 }
324 } 319 }
325 320
@@ -333,7 +328,8 @@ namespace OpenSim.Region.CoreModules.World.Land
333 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName); 328 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
334 329
335 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene); 330 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
336 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize)); 331 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0,
332 (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY));
337 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner; 333 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
338 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch(); 334 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
339 335
@@ -460,8 +456,8 @@ namespace OpenSim.Region.CoreModules.World.Land
460 456
461 public void SendLandUpdate(ScenePresence avatar, bool force) 457 public void SendLandUpdate(ScenePresence avatar, bool force)
462 { 458 {
463 ILandObject over = GetLandObject((int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))), 459 ILandObject over = GetLandObject((int)Math.Min(((int)m_scene.RegionInfo.RegionSizeX - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
464 (int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y)))); 460 (int)Math.Min(((int)m_scene.RegionInfo.RegionSizeY - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
465 461
466 if (over != null) 462 if (over != null)
467 { 463 {
@@ -543,16 +539,13 @@ namespace OpenSim.Region.CoreModules.World.Land
543 /// </summary> 539 /// </summary>
544 /// <param name="avatar"></param> 540 /// <param name="avatar"></param>
545 public void EventManagerOnClientMovement(ScenePresence avatar) 541 public void EventManagerOnClientMovement(ScenePresence avatar)
546 //
547 { 542 {
548 ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); 543 Vector3 pos = avatar.AbsolutePosition;
544 ILandObject over = GetLandObject(pos.X, pos.Y);
549 if (over != null) 545 if (over != null)
550 { 546 {
551 if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT)) 547 if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || pos.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT))
552 { 548 avatar.lastKnownAllowedPosition = pos;
553 avatar.lastKnownAllowedPosition =
554 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
555 }
556 } 549 }
557 } 550 }
558 551
@@ -611,7 +604,10 @@ namespace OpenSim.Region.CoreModules.World.Land
611 /// <summary> 604 /// <summary>
612 /// Adds a land object to the stored list and adds them to the landIDList to what they own 605 /// Adds a land object to the stored list and adds them to the landIDList to what they own
613 /// </summary> 606 /// </summary>
614 /// <param name="new_land">The land object being added</param> 607 /// <param name="new_land">
608 /// The land object being added.
609 /// Will return null if this overlaps with an existing parcel that has not had its bitmap adjusted.
610 /// </param>
615 public ILandObject AddLandObject(ILandObject land) 611 public ILandObject AddLandObject(ILandObject land)
616 { 612 {
617 ILandObject new_land = land.Copy(); 613 ILandObject new_land = land.Copy();
@@ -619,34 +615,76 @@ namespace OpenSim.Region.CoreModules.World.Land
619 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated 615 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated
620 // as a random UUID inside LandData initialization 616 // as a random UUID inside LandData initialization
621 if (m_primCountModule != null) 617 if (m_primCountModule != null)
622 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID); 618 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID);
623 619
624 lock (m_landList) 620 lock (m_landList)
625 { 621 {
626 int newLandLocalID = ++m_lastLandLocalID; 622 int newLandLocalID = m_lastLandLocalID + 1;
627 new_land.LandData.LocalID = newLandLocalID; 623 new_land.LandData.LocalID = newLandLocalID;
628 624
629 bool[,] landBitmap = new_land.GetLandBitmap(); 625 bool[,] landBitmap = new_land.GetLandBitmap();
630 for (int x = 0; x < landArrayMax; x++) 626 // m_log.DebugFormat("{0} AddLandObject. new_land.bitmapSize=({1},{2}). newLocalID={3}",
627 // LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), newLandLocalID);
628
629 if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1))
630 {
631 // Going to variable sized regions can cause mismatches
632 m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})",
633 LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1) );
634 }
635 else
631 { 636 {
632 for (int y = 0; y < landArrayMax; y++) 637 // If other land objects still believe that they occupy any parts of the same space,
638 // then do not allow the add to proceed.
639 for (int x = 0; x < landBitmap.GetLength(0); x++)
633 { 640 {
634 if (landBitmap[x, y]) 641 for (int y = 0; y < landBitmap.GetLength(1); y++)
635 { 642 {
636// m_log.DebugFormat( 643 if (landBitmap[x, y])
637// "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}", 644 {
638// new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName); 645 int lastRecordedLandId = m_landIDList[x, y];
639 646
640 m_landIDList[x, y] = newLandLocalID; 647 if (lastRecordedLandId > 0)
648 {
649 ILandObject lastRecordedLo = m_landList[lastRecordedLandId];
650
651 if (lastRecordedLo.LandBitmap[x, y])
652 {
653 m_log.ErrorFormat(
654 "{0}: Cannot add parcel \"{1}\", local ID {2} at tile {3},{4} because this is still occupied by parcel \"{5}\", local ID {6} in {7}",
655 LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y,
656 lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name);
657
658 return null;
659 }
660 }
661 }
662 }
663 }
664
665 for (int x = 0; x < landBitmap.GetLength(0); x++)
666 {
667 for (int y = 0; y < landBitmap.GetLength(1); y++)
668 {
669 if (landBitmap[x, y])
670 {
671 // m_log.DebugFormat(
672 // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
673 // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
674
675 m_landIDList[x, y] = newLandLocalID;
676 }
641 } 677 }
642 } 678 }
643 } 679 }
644 680
645 m_landList.Add(newLandLocalID, new_land); 681 m_landList.Add(newLandLocalID, new_land);
682 m_lastLandLocalID++;
646 } 683 }
647 684
648 new_land.ForceUpdateLandInfo(); 685 new_land.ForceUpdateLandInfo();
649 m_scene.EventManager.TriggerLandObjectAdded(new_land); 686 m_scene.EventManager.TriggerLandObjectAdded(new_land);
687
650 return new_land; 688 return new_land;
651 } 689 }
652 690
@@ -656,11 +694,12 @@ namespace OpenSim.Region.CoreModules.World.Land
656 /// <param name="local_id">Land.localID of the peice of land to remove.</param> 694 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
657 public void removeLandObject(int local_id) 695 public void removeLandObject(int local_id)
658 { 696 {
697 ILandObject land;
659 lock (m_landList) 698 lock (m_landList)
660 { 699 {
661 for (int x = 0; x < 64; x++) 700 for (int x = 0; x < m_landIDList.GetLength(0); x++)
662 { 701 {
663 for (int y = 0; y < 64; y++) 702 for (int y = 0; y < m_landIDList.GetLength(1); y++)
664 { 703 {
665 if (m_landIDList[x, y] == local_id) 704 if (m_landIDList[x, y] == local_id)
666 { 705 {
@@ -672,9 +711,11 @@ namespace OpenSim.Region.CoreModules.World.Land
672 } 711 }
673 } 712 }
674 713
675 m_scene.EventManager.TriggerLandObjectRemoved(m_landList[local_id].LandData.GlobalID); 714 land = m_landList[local_id];
676 m_landList.Remove(local_id); 715 m_landList.Remove(local_id);
677 } 716 }
717
718 m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID);
678 } 719 }
679 720
680 /// <summary> 721 /// <summary>
@@ -682,21 +723,27 @@ namespace OpenSim.Region.CoreModules.World.Land
682 /// </summary> 723 /// </summary>
683 public void Clear(bool setupDefaultParcel) 724 public void Clear(bool setupDefaultParcel)
684 { 725 {
726 List<ILandObject> parcels;
685 lock (m_landList) 727 lock (m_landList)
686 { 728 {
687 foreach (ILandObject lo in m_landList.Values) 729 parcels = new List<ILandObject>(m_landList.Values);
688 { 730 }
689 //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID); 731
690 m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID); 732 foreach (ILandObject lo in parcels)
691 } 733 {
734 //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID);
735 m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID);
736 }
692 737
738 lock (m_landList)
739 {
693 m_landList.Clear(); 740 m_landList.Clear();
694 741
695 ResetSimLandObjects(); 742 ResetSimLandObjects();
696
697 if (setupDefaultParcel)
698 CreateDefaultParcel();
699 } 743 }
744
745 if (setupDefaultParcel)
746 CreateDefaultParcel();
700 } 747 }
701 748
702 private void performFinalLandJoin(ILandObject master, ILandObject slave) 749 private void performFinalLandJoin(ILandObject master, ILandObject slave)
@@ -704,9 +751,9 @@ namespace OpenSim.Region.CoreModules.World.Land
704 bool[,] landBitmapSlave = slave.GetLandBitmap(); 751 bool[,] landBitmapSlave = slave.GetLandBitmap();
705 lock (m_landList) 752 lock (m_landList)
706 { 753 {
707 for (int x = 0; x < 64; x++) 754 for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
708 { 755 {
709 for (int y = 0; y < 64; y++) 756 for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
710 { 757 {
711 if (landBitmapSlave[x, y]) 758 if (landBitmapSlave[x, y])
712 { 759 {
@@ -740,23 +787,28 @@ namespace OpenSim.Region.CoreModules.World.Land
740 /// <returns>Land object at the point supplied</returns> 787 /// <returns>Land object at the point supplied</returns>
741 public ILandObject GetLandObject(float x_float, float y_float) 788 public ILandObject GetLandObject(float x_float, float y_float)
742 { 789 {
790 return GetLandObject((int)x_float, (int)y_float, true /* returnNullIfLandObjectNotFound */);
791 /*
743 int x; 792 int x;
744 int y; 793 int y;
745 794
746 if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0) 795 if (x_float >= m_scene.RegionInfo.RegionSizeX || x_float < 0 || y_float >= m_scene.RegionInfo.RegionSizeX || y_float < 0)
747 return null; 796 return null;
748 797
749 try 798 try
750 { 799 {
751 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0)); 800 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / (float)landUnit));
752 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0)); 801 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / (float)landUnit));
753 } 802 }
754 catch (OverflowException) 803 catch (OverflowException)
755 { 804 {
756 return null; 805 return null;
757 } 806 }
758 807
759 if (x >= 64 || y >= 64 || x < 0 || y < 0) 808 if (x >= (m_scene.RegionInfo.RegionSizeX / landUnit)
809 || y >= (m_scene.RegionInfo.RegionSizeY / landUnit)
810 || x < 0
811 || y < 0)
760 { 812 {
761 return null; 813 return null;
762 } 814 }
@@ -772,38 +824,70 @@ namespace OpenSim.Region.CoreModules.World.Land
772// m_log.DebugFormat( 824// m_log.DebugFormat(
773// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}", 825// "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}",
774// x, y, m_scene.RegionInfo.RegionName); 826// x, y, m_scene.RegionInfo.RegionName);
775 827
776 if (m_landList.ContainsKey(m_landIDList[x, y])) 828 try
777 return m_landList[m_landIDList[x, y]]; 829 {
830 if (m_landList.ContainsKey(m_landIDList[x, y]))
831 return m_landList[m_landIDList[x, y]];
832 }
833 catch (Exception e)
834 {
835 m_log.DebugFormat("{0} GetLandObject exception. x={1}, y={2}, m_landIDList.len=({3},{4})",
836 LogHeader, x, y, m_landIDList.GetLength(0), m_landIDList.GetLength(1));
837 }
778 838
779 return null; 839 return null;
780 } 840 }
841 */
781 } 842 }
782 843
844 // Public entry.
845 // Throws exception if land object is not found
783 public ILandObject GetLandObject(int x, int y) 846 public ILandObject GetLandObject(int x, int y)
784 { 847 {
785 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0) 848 return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */);
849 }
850
851 /// <summary>
852 /// Given a region position, return the parcel land object for that location
853 /// </summary>
854 /// <returns>
855 /// The land object.
856 /// </returns>
857 /// <param name='x'></param>
858 /// <param name='y'></param>
859 /// <param name='returnNullIfLandObjectNotFound'>
860 /// Return null if the land object requested is not within the region's bounds.
861 /// </param>
862 private ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds)
863 {
864 if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0)
786 { 865 {
787 // These exceptions here will cause a lot of complaints from the users specifically because 866 // These exceptions here will cause a lot of complaints from the users specifically because
788 // they happen every time at border crossings 867 // they happen every time at border crossings
789 throw new Exception("Error: Parcel not found at point " + x + ", " + y); 868 if (returnNullIfLandObjectOutsideBounds)
790 }
791
792 lock (m_landIDList)
793 {
794 try
795 {
796 return m_landList[m_landIDList[x / 4, y / 4]];
797 }
798 catch (IndexOutOfRangeException)
799 {
800// m_log.WarnFormat(
801// "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
802// x, y, m_scene.RegionInfo.RegionName);
803
804 return null; 869 return null;
805 } 870 else
871 throw new Exception(
872 String.Format("{0} GetLandObject for non-existent position. Region={1}, pos=<{2},{3}",
873 LogHeader, m_scene.RegionInfo.RegionName, x, y)
874 );
806 } 875 }
876
877 return m_landList[m_landIDList[x / 4, y / 4]];
878 }
879
880 // Create a 'parcel is here' bitmap for the parcel identified by the passed landID
881 private bool[,] CreateBitmapForID(int landID)
882 {
883 bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)];
884
885 for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
886 for (int yy = 0; yy < m_landIDList.GetLength(0); yy++)
887 if (m_landIDList[xx, yy] == landID)
888 ret[xx, yy] = true;
889
890 return ret;
807 } 891 }
808 892
809 #endregion 893 #endregion
@@ -973,8 +1057,12 @@ namespace OpenSim.Region.CoreModules.World.Land
973 1057
974 //Now add the new land object 1058 //Now add the new land object
975 ILandObject result = AddLandObject(newLand); 1059 ILandObject result = AddLandObject(newLand);
976 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData); 1060
977 result.SendLandUpdateToAvatarsOverMe(); 1061 if (result != null)
1062 {
1063 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData);
1064 result.SendLandUpdateToAvatarsOverMe();
1065 }
978 } 1066 }
979 1067
980 /// <summary> 1068 /// <summary>
@@ -1055,96 +1143,164 @@ namespace OpenSim.Region.CoreModules.World.Land
1055 1143
1056 #region Parcel Updating 1144 #region Parcel Updating
1057 1145
1146 // Send parcel layer info for the whole region
1147 public void SendParcelOverlay(IClientAPI remote_client)
1148 {
1149 SendParcelOverlay(remote_client, 0, 0, (int)Constants.MaximumRegionSize);
1150 }
1151
1058 /// <summary> 1152 /// <summary>
1059 /// Where we send the ParcelOverlay packet to the client 1153 /// Send the parcel overlay blocks to the client. We send the overlay packets
1154 /// around a location and limited by the 'parcelLayerViewDistance'. This number
1155 /// is usually 128 and the code is arranged so it sends all the parcel overlay
1156 /// information for a whole region if the region is legacy sized (256x256). If
1157 /// the region is larger, only the parcel layer information is sent around
1158 /// the point specified. This reduces the problem of parcel layer information
1159 /// blocks increasing exponentially as region size increases.
1060 /// </summary> 1160 /// </summary>
1061 /// <param name="remote_client">The object representing the client</param> 1161 /// <param name="remote_client">The object representing the client</param>
1062 public void SendParcelOverlay(IClientAPI remote_client) 1162 /// <param name="xPlace">X position in the region to send surrounding parcel layer info</param>
1163 /// <param name="yPlace">y position in the region to send surrounding parcel layer info</param>
1164 /// <param name="layerViewDistance">Distance from x,y position to send parcel layer info</param>
1165 private void SendParcelOverlay(IClientAPI remote_client, int xPlace, int yPlace, int layerViewDistance)
1063 { 1166 {
1064 const int LAND_BLOCKS_PER_PACKET = 1024; 1167 const int LAND_BLOCKS_PER_PACKET = 1024;
1065 1168
1066 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 1169 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1067 int byteArrayCount = 0; 1170 int byteArrayCount = 0;
1068 int sequenceID = 0; 1171 int sequenceID = 0;
1069 int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize;
1070 1172
1173 int xLow = 0;
1174 int xHigh = (int)m_scene.RegionInfo.RegionSizeX;
1175 int yLow = 0;
1176 int yHigh = (int)m_scene.RegionInfo.RegionSizeY;
1071 1177
1072 for (int y = 0; y < blockmeters; y++) 1178 if (shouldLimitParcelLayerInfoToViewDistance)
1073 { 1179 {
1074 for (int x = 0; x < blockmeters; x++) 1180 // Compute view distance around the given point
1181 int txLow = xPlace - layerViewDistance;
1182 int txHigh = xPlace + layerViewDistance;
1183 // If the distance is outside the region area, move the view distance to ba all in the region
1184 if (txLow < xLow)
1185 {
1186 txLow = xLow;
1187 txHigh = Math.Min(yLow + (layerViewDistance * 2), xHigh);
1188 }
1189 if (txHigh > xHigh)
1075 { 1190 {
1076 byte tempByte = 0; //This represents the byte for the current 4x4 1191 txLow = Math.Max(xLow, xHigh - (layerViewDistance * 2));
1192 txHigh = xHigh;
1193 }
1194 xLow = txLow;
1195 xHigh = txHigh;
1077 1196
1078 ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4); 1197 int tyLow = yPlace - layerViewDistance;
1198 int tyHigh = yPlace + layerViewDistance;
1199 if (tyLow < yLow)
1200 {
1201 tyLow = yLow;
1202 tyHigh = Math.Min(yLow + (layerViewDistance * 2), yHigh);
1203 }
1204 if (tyHigh > yHigh)
1205 {
1206 tyLow = Math.Max(yLow, yHigh - (layerViewDistance * 2));
1207 tyHigh = yHigh;
1208 }
1209 yLow = tyLow;
1210 yHigh = tyHigh;
1211 }
1212 // m_log.DebugFormat("{0} SendParcelOverlay: place=<{1},{2}>, vDist={3}, xLH=<{4},{5}, yLH=<{6},{7}>",
1213 // LogHeader, xPlace, yPlace, layerViewDistance, xLow, xHigh, yLow, yHigh);
1079 1214
1080 if (currentParcelBlock != null) 1215 // Layer data is in landUnit (4m) chunks
1216 for (int y = yLow; y < yHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1217 {
1218 for (int x = xLow; x < xHigh / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1219 {
1220 byteArray[byteArrayCount] = BuildLayerByte(GetLandObject(x * LandUnit, y * LandUnit), x, y, remote_client);
1221 byteArrayCount++;
1222 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
1081 { 1223 {
1082 if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId) 1224 // m_log.DebugFormat("{0} SendParcelOverlay, sending packet, bytes={1}", LogHeader, byteArray.Length);
1083 { 1225 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1084 //Owner Flag 1226 byteArrayCount = 0;
1085 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER); 1227 sequenceID++;
1086 } 1228 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1087 else if (currentParcelBlock.LandData.SalePrice > 0 && 1229 }
1088 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1089 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1090 {
1091 //Sale Flag
1092 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
1093 }
1094 else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1095 {
1096 //Public Flag
1097 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
1098 }
1099 else
1100 {
1101 //Other Flag
1102 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
1103 }
1104 1230
1105 //Now for border control 1231 }
1232 }
1106 1233
1107 ILandObject westParcel = null; 1234 if (byteArrayCount != 0)
1108 ILandObject southParcel = null; 1235 {
1109 if (x > 0) 1236 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1110 { 1237 // m_log.DebugFormat("{0} SendParcelOverlay, complete sending packet, bytes={1}", LogHeader, byteArray.Length);
1111 westParcel = GetLandObject((x - 1) * 4, y * 4); 1238 }
1112 } 1239 }
1113 if (y > 0)
1114 {
1115 southParcel = GetLandObject(x * 4, (y - 1) * 4);
1116 }
1117 1240
1118 if (x == 0) 1241 private byte BuildLayerByte(ILandObject currentParcelBlock, int x, int y, IClientAPI remote_client)
1119 { 1242 {
1120 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST); 1243 byte tempByte = 0; //This represents the byte for the current 4x4
1121 }
1122 else if (westParcel != null && westParcel != currentParcelBlock)
1123 {
1124 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1125 }
1126 1244
1127 if (y == 0) 1245 if (currentParcelBlock != null)
1128 { 1246 {
1129 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); 1247 if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId)
1130 } 1248 {
1131 else if (southParcel != null && southParcel != currentParcelBlock) 1249 //Owner Flag
1132 { 1250 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
1133 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH); 1251 }
1134 } 1252 else if (currentParcelBlock.LandData.SalePrice > 0 &&
1253 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1254 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1255 {
1256 //Sale Flag
1257 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
1258 }
1259 else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1260 {
1261 //Public Flag
1262 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
1263 }
1264 else
1265 {
1266 //Other Flag
1267 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
1268 }
1135 1269
1136 byteArray[byteArrayCount] = tempByte; 1270 //Now for border control
1137 byteArrayCount++; 1271
1138 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET) 1272 ILandObject westParcel = null;
1139 { 1273 ILandObject southParcel = null;
1140 remote_client.SendLandParcelOverlay(byteArray, sequenceID); 1274 if (x > 0)
1141 byteArrayCount = 0; 1275 {
1142 sequenceID++; 1276 westParcel = GetLandObject((x - 1) * LandUnit, y * LandUnit);
1143 byteArray = new byte[LAND_BLOCKS_PER_PACKET]; 1277 }
1144 } 1278 if (y > 0)
1145 } 1279 {
1280 southParcel = GetLandObject(x * LandUnit, (y - 1) * LandUnit);
1281 }
1282
1283 if (x == 0)
1284 {
1285 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1286 }
1287 else if (westParcel != null && westParcel != currentParcelBlock)
1288 {
1289 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1146 } 1290 }
1291
1292 if (y == 0)
1293 {
1294 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1295 }
1296 else if (southParcel != null && southParcel != currentParcelBlock)
1297 {
1298 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1299 }
1300
1147 } 1301 }
1302
1303 return tempByte;
1148 } 1304 }
1149 1305
1150 public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, 1306 public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
@@ -1182,7 +1338,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1182 temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client); 1338 temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
1183 } 1339 }
1184 1340
1185 SendParcelOverlay(remote_client); 1341 // Also send the layer data around the point of interest
1342 SendParcelOverlay(remote_client, (start_x + end_x) / 2, (start_y + end_y) / 2, parcelLayerViewDistance);
1186 } 1343 }
1187 1344
1188 public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client) 1345 public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
@@ -1254,6 +1411,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1254 1411
1255 m_scene.ForEachClient(SendParcelOverlay); 1412 m_scene.ForEachClient(SendParcelOverlay);
1256 land.SendLandUpdateToClient(true, remote_client); 1413 land.SendLandUpdateToClient(true, remote_client);
1414 UpdateLandObject(land.LandData.LocalID, land.LandData);
1257 } 1415 }
1258 } 1416 }
1259 } 1417 }
@@ -1274,8 +1432,10 @@ namespace OpenSim.Region.CoreModules.World.Land
1274 land.LandData.GroupID = UUID.Zero; 1432 land.LandData.GroupID = UUID.Zero;
1275 land.LandData.IsGroupOwned = false; 1433 land.LandData.IsGroupOwned = false;
1276 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory); 1434 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1435
1277 m_scene.ForEachClient(SendParcelOverlay); 1436 m_scene.ForEachClient(SendParcelOverlay);
1278 land.SendLandUpdateToClient(true, remote_client); 1437 land.SendLandUpdateToClient(true, remote_client);
1438 UpdateLandObject(land.LandData.LocalID, land.LandData);
1279 } 1439 }
1280 } 1440 }
1281 } 1441 }
@@ -1302,6 +1462,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1302 1462
1303 m_scene.ForEachClient(SendParcelOverlay); 1463 m_scene.ForEachClient(SendParcelOverlay);
1304 land.SendLandUpdateToClient(true, remote_client); 1464 land.SendLandUpdateToClient(true, remote_client);
1465 UpdateLandObject(land.LandData.LocalID, land.LandData);
1305 } 1466 }
1306 } 1467 }
1307 } 1468 }
@@ -1382,19 +1543,78 @@ namespace OpenSim.Region.CoreModules.World.Land
1382 1543
1383 #region Land Object From Storage Functions 1544 #region Land Object From Storage Functions
1384 1545
1385 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data) 1546 private void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1386 { 1547 {
1387// m_log.DebugFormat( 1548// m_log.DebugFormat(
1388// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name); 1549// "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name);
1389 1550
1390 for (int i = 0; i < data.Count; i++) 1551 // Prevent race conditions from any auto-creation of new parcels for varregions whilst we are still loading
1391 IncomingLandObjectFromStorage(data[i]); 1552 // the existing parcels.
1553 lock (m_landList)
1554 {
1555 for (int i = 0; i < data.Count; i++)
1556 IncomingLandObjectFromStorage(data[i]);
1557
1558 // Layer data is in landUnit (4m) chunks
1559 for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1560 {
1561 for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1562 {
1563 if (m_landIDList[x, y] == 0)
1564 {
1565 if (m_landList.Count == 1)
1566 {
1567 m_log.DebugFormat(
1568 "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}",
1569 LogHeader, x, y, m_scene.Name);
1570
1571 int onlyParcelID = 0;
1572 ILandObject onlyLandObject = null;
1573 foreach (KeyValuePair<int, ILandObject> kvp in m_landList)
1574 {
1575 onlyParcelID = kvp.Key;
1576 onlyLandObject = kvp.Value;
1577 break;
1578 }
1579
1580 // There is only one parcel. Grow it to fill all the unallocated spaces.
1581 for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
1582 for (int yy = 0; yy < m_landIDList.GetLength(1); yy++)
1583 if (m_landIDList[xx, yy] == 0)
1584 m_landIDList[xx, yy] = onlyParcelID;
1585
1586 onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID);
1587 }
1588 else if (m_landList.Count > 1)
1589 {
1590 m_log.DebugFormat(
1591 "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}",
1592 LogHeader, x, y, m_scene.Name);
1593
1594 // There are several other parcels so we must create a new one for the unassigned space
1595 ILandObject newLand = new LandObject(UUID.Zero, false, m_scene);
1596 // Claim all the unclaimed "0" ids
1597 newLand.SetLandBitmap(CreateBitmapForID(0));
1598 newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1599 newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
1600 newLand = AddLandObject(newLand);
1601 }
1602 else
1603 {
1604 // We should never reach this point as the separate code path when no land data exists should have fired instead.
1605 m_log.WarnFormat(
1606 "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present",
1607 LogHeader, m_scene.Name);
1608 }
1609 }
1610 }
1611 }
1612 }
1392 } 1613 }
1393 1614
1394 public void IncomingLandObjectFromStorage(LandData data) 1615 private void IncomingLandObjectFromStorage(LandData data)
1395 { 1616 {
1396 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene); 1617 ILandObject new_land = new LandObject(data, m_scene);
1397 new_land.LandData = data.Copy();
1398 new_land.SetLandBitmapFromByteArray(); 1618 new_land.SetLandBitmapFromByteArray();
1399 AddLandObject(new_land); 1619 AddLandObject(new_land);
1400 } 1620 }
@@ -1409,7 +1629,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1409 m_landList.TryGetValue(localID, out selectedParcel); 1629 m_landList.TryGetValue(localID, out selectedParcel);
1410 } 1630 }
1411 1631
1412 if (selectedParcel == null) return; 1632 if (selectedParcel == null)
1633 return;
1413 1634
1414 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient); 1635 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
1415 } 1636 }
@@ -1417,7 +1638,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1417 { 1638 {
1418 if (returnType != 1) 1639 if (returnType != 1)
1419 { 1640 {
1420 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown return type {0}", returnType); 1641 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType);
1421 return; 1642 return;
1422 } 1643 }
1423 1644
@@ -1437,14 +1658,14 @@ namespace OpenSim.Region.CoreModules.World.Land
1437 } 1658 }
1438 else 1659 else
1439 { 1660 {
1440 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: unknown object {0}", groupID); 1661 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID);
1441 } 1662 }
1442 } 1663 }
1443 1664
1444 int num = 0; 1665 int num = 0;
1445 foreach (HashSet<SceneObjectGroup> objs in returns.Values) 1666 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1446 num += objs.Count; 1667 num += objs.Count;
1447 m_log.DebugFormat("[LAND MANAGEMENT MODULE] Returning {0} specific object(s)", num); 1668 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num);
1448 1669
1449 foreach (HashSet<SceneObjectGroup> objs in returns.Values) 1670 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1450 { 1671 {
@@ -1455,7 +1676,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1455 } 1676 }
1456 else 1677 else
1457 { 1678 {
1458 m_log.WarnFormat("[LAND MANAGEMENT MODULE] ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}", 1679 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
1459 objs2.Count, objs2[0].OwnerID); 1680 objs2.Count, objs2[0].OwnerID);
1460 } 1681 }
1461 } 1682 }
@@ -1464,11 +1685,8 @@ namespace OpenSim.Region.CoreModules.World.Land
1464 1685
1465 public void EventManagerOnNoLandDataFromStorage() 1686 public void EventManagerOnNoLandDataFromStorage()
1466 { 1687 {
1467 lock (m_landList) 1688 ResetSimLandObjects();
1468 { 1689 CreateDefaultParcel();
1469 ResetSimLandObjects();
1470 CreateDefaultParcel();
1471 }
1472 } 1690 }
1473 1691
1474 #endregion 1692 #endregion
@@ -1694,7 +1912,7 @@ namespace OpenSim.Region.CoreModules.World.Land
1694 { 1912 {
1695 // most likely still cached from building the extLandData entry 1913 // most likely still cached from building the extLandData entry
1696 uint x = 0, y = 0; 1914 uint x = 0, y = 0;
1697 Utils.LongToUInts(data.RegionHandle, out x, out y); 1915 Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y);
1698 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y); 1916 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
1699 } 1917 }
1700 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark. 1918 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
@@ -1730,66 +1948,332 @@ namespace OpenSim.Region.CoreModules.World.Land
1730 UpdateLandObject(localID, land.LandData); 1948 UpdateLandObject(localID, land.LandData);
1731 } 1949 }
1732 1950
1733 protected void InstallInterfaces() 1951 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1952
1953 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1954 {
1955 ScenePresence targetAvatar = null;
1956 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1957 ScenePresence parcelManager = null;
1958 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1959 System.Threading.Timer Timer;
1960
1961 if (targetAvatar.UserLevel == 0)
1962 {
1963 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1964 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1965 return;
1966 if (flags == 0)
1967 {
1968 targetAvatar.AllowMovement = false;
1969 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1970 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1971 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1972 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1973 Timers.Add(targetAvatar.UUID, Timer);
1974 }
1975 else
1976 {
1977 targetAvatar.AllowMovement = true;
1978 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1979 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1980 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1981 Timers.Remove(targetAvatar.UUID);
1982 Timer.Dispose();
1983 }
1984 }
1985 }
1986
1987 private void OnEndParcelFrozen(object avatar)
1734 { 1988 {
1735 Command clearCommand 1989 ScenePresence targetAvatar = (ScenePresence)avatar;
1736 = new Command("clear", CommandIntentions.COMMAND_HAZARDOUS, ClearCommand, "Clears all the parcels from the region."); 1990 targetAvatar.AllowMovement = true;
1737 Command showCommand 1991 System.Threading.Timer Timer;
1738 = new Command("show", CommandIntentions.COMMAND_STATISTICAL, ShowParcelsCommand, "Shows all parcels on the region."); 1992 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1993 Timers.Remove(targetAvatar.UUID);
1994 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1995 }
1996
1997 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1998 {
1999 ScenePresence targetAvatar = null;
2000 ScenePresence parcelManager = null;
2001
2002 // Must have presences
2003 if (!m_scene.TryGetScenePresence(target, out targetAvatar) ||
2004 !m_scene.TryGetScenePresence(client.AgentId, out parcelManager))
2005 return;
2006
2007 // Cannot eject estate managers or gods
2008 if (m_scene.Permissions.IsAdministrator(target))
2009 return;
2010
2011 // Check if you even have permission to do this
2012 ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
2013 if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) &&
2014 !m_scene.Permissions.IsAdministrator(client.AgentId))
2015 return;
2016 Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land);
2017
2018 targetAvatar.TeleportWithMomentum(pos, null);
2019 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
2020 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1739 2021
1740 m_commander.RegisterCommand("clear", clearCommand); 2022 if ((flags & 1) != 0) // Ban TODO: Remove magic number
1741 m_commander.RegisterCommand("show", showCommand); 2023 {
2024 LandAccessEntry entry = new LandAccessEntry();
2025 entry.AgentID = targetAvatar.UUID;
2026 entry.Flags = AccessList.Ban;
2027 entry.Expires = 0; // Perm
1742 2028
1743 // Add this to our scene so scripts can call these functions 2029 land.LandData.ParcelAccessList.Add(entry);
1744 m_scene.RegisterModuleCommander(m_commander); 2030 }
2031 }
2032
2033 /// <summary>
2034 /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
2035 /// </summary>
2036 /// <param name="remoteClient"></param>
2037 /// <param name="regionHandle"></param>
2038 /// <param name="position"></param>
2039 /// <param name="lookAt"></param>
2040 /// <param name="flags"></param>
2041 public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2042 {
2043 // Let's find the parcel in question
2044 ILandObject land = landChannel.GetLandObject(position);
2045 if (land == null || m_scene.GridUserService == null)
2046 {
2047 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2048 return;
2049 }
2050
2051 // Gather some data
2052 ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID);
2053 SceneObjectGroup telehub = null;
2054 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
2055 // Does the telehub exist in the scene?
2056 telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
2057
2058 // Can the user set home here?
2059 if (// Required: local user; foreign users cannot set home
2060 m_scene.UserManagementModule.IsLocalGridUser(remoteClient.AgentId) &&
2061 (// (a) gods and land managers can set home
2062 m_scene.Permissions.IsAdministrator(remoteClient.AgentId) ||
2063 m_scene.Permissions.IsGod(remoteClient.AgentId) ||
2064 // (b) land owners can set home
2065 remoteClient.AgentId == land.LandData.OwnerID ||
2066 // (c) members of the land-associated group in roles that can set home
2067 ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) ||
2068 // (d) parcels with telehubs can be the home of anyone
2069 (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))))
2070 {
2071 string userId;
2072 UUID test;
2073 if (!m_scene.UserManagementModule.GetUserUUI(remoteClient.AgentId, out userId))
2074 {
2075 /* Do not set a home position in this grid for a HG visitor */
2076 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (User Lookup)");
2077 }
2078 else if (!UUID.TryParse(userId, out test))
2079 {
2080 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (HG visitor)");
2081 }
2082 else if (m_scene.GridUserService.SetHome(userId, land.RegionUUID, position, lookAt))
2083 {
2084 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2085 m_Dialog.SendAlertToUser(remoteClient, "Home position set.");
2086 }
2087 else
2088 {
2089 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2090 }
2091 }
2092 else
2093 m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel.");
2094 }
2095
2096 protected void RegisterCommands()
2097 {
2098 ICommands commands = MainConsole.Instance.Commands;
2099
2100 commands.AddCommand(
2101 "Land", false, "land clear",
2102 "land clear",
2103 "Clear all the parcels from the region.",
2104 "Command will ask for confirmation before proceeding.",
2105 HandleClearCommand);
2106
2107 commands.AddCommand(
2108 "Land", false, "land show",
2109 "land show [<local-land-id>]",
2110 "Show information about the parcels on the region.",
2111 "If no local land ID is given, then summary information about all the parcels is shown.\n"
2112 + "If a local land ID is given then full information about that parcel is shown.",
2113 HandleShowCommand);
1745 } 2114 }
1746 2115
1747 protected void ClearCommand(Object[] args) 2116 protected void HandleClearCommand(string module, string[] args)
1748 { 2117 {
2118 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
2119 return;
2120
1749 string response = MainConsole.Instance.CmdPrompt( 2121 string response = MainConsole.Instance.CmdPrompt(
1750 string.Format( 2122 string.Format(
1751 "Are you sure that you want to clear all land parcels from {0} (y or n)", 2123 "Are you sure that you want to clear all land parcels from {0} (y or n)", m_scene.Name),
1752 m_scene.RegionInfo.RegionName),
1753 "n"); 2124 "n");
1754 2125
1755 if (response.ToLower() == "y") 2126 if (response.ToLower() == "y")
1756 { 2127 {
1757 Clear(true); 2128 Clear(true);
1758 MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.RegionInfo.RegionName); 2129 MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.Name);
1759 } 2130 }
1760 else 2131 else
1761 { 2132 {
1762 MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.RegionInfo.RegionName); 2133 MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.Name);
1763 } 2134 }
1764 } 2135 }
1765 2136
1766 protected void ShowParcelsCommand(Object[] args) 2137 protected void HandleShowCommand(string module, string[] args)
1767 { 2138 {
1768 StringBuilder report = new StringBuilder(); 2139 if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
1769 2140 return;
1770 report.AppendFormat("Land information for {0}\n", m_scene.RegionInfo.RegionName); 2141
1771 report.AppendFormat( 2142 StringBuilder report = new StringBuilder();
1772 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", 2143
1773 "Parcel Name", 2144 if (args.Length <= 2)
1774 "Local ID", 2145 {
1775 "Area", 2146 AppendParcelsSummaryReport(report);
1776 "Starts", 2147 }
1777 "Ends", 2148 else
1778 "Owner"); 2149 {
2150 int landLocalId;
2151
2152 if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[2], out landLocalId))
2153 return;
2154
2155 ILandObject lo;
2156
2157 lock (m_landList)
2158 {
2159 if (!m_landList.TryGetValue(landLocalId, out lo))
2160 {
2161 MainConsole.Instance.OutputFormat("No parcel found with local ID {0}", landLocalId);
2162 return;
2163 }
2164 }
2165
2166 AppendParcelReport(report, lo);
2167 }
2168
2169 MainConsole.Instance.Output(report.ToString());
2170 }
2171
2172 private void AppendParcelsSummaryReport(StringBuilder report)
2173 {
2174 report.AppendFormat("Land information for {0}\n", m_scene.Name);
2175
2176 ConsoleDisplayTable cdt = new ConsoleDisplayTable();
2177 cdt.AddColumn("Parcel Name", ConsoleDisplayUtil.ParcelNameSize);
2178 cdt.AddColumn("ID", 3);
2179 cdt.AddColumn("Area", 6);
2180 cdt.AddColumn("Starts", ConsoleDisplayUtil.VectorSize);
2181 cdt.AddColumn("Ends", ConsoleDisplayUtil.VectorSize);
2182 cdt.AddColumn("Owner", ConsoleDisplayUtil.UserNameSize);
1779 2183
1780 lock (m_landList) 2184 lock (m_landList)
1781 { 2185 {
1782 foreach (ILandObject lo in m_landList.Values) 2186 foreach (ILandObject lo in m_landList.Values)
1783 { 2187 {
1784 LandData ld = lo.LandData; 2188 LandData ld = lo.LandData;
1785 2189 string ownerName;
1786 report.AppendFormat( 2190 if (ld.IsGroupOwned)
1787 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n", 2191 {
1788 ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, m_userManager.GetUserName(ld.OwnerID)); 2192 GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
2193 ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
2194 }
2195 else
2196 {
2197 ownerName = m_userManager.GetUserName(ld.OwnerID);
2198 }
2199 cdt.AddRow(
2200 ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, ownerName);
1789 } 2201 }
1790 } 2202 }
1791 2203
1792 MainConsole.Instance.Output(report.ToString()); 2204 report.Append(cdt.ToString());
1793 } 2205 }
2206
2207 private void AppendParcelReport(StringBuilder report, ILandObject lo)
2208 {
2209 LandData ld = lo.LandData;
2210
2211 ConsoleDisplayList cdl = new ConsoleDisplayList();
2212 cdl.AddRow("Parcel name", ld.Name);
2213 cdl.AddRow("Local ID", ld.LocalID);
2214 cdl.AddRow("Description", ld.Description);
2215 cdl.AddRow("Snapshot ID", ld.SnapshotID);
2216 cdl.AddRow("Area", ld.Area);
2217 cdl.AddRow("Starts", lo.StartPoint);
2218 cdl.AddRow("Ends", lo.EndPoint);
2219 cdl.AddRow("AABB Min", ld.AABBMin);
2220 cdl.AddRow("AABB Max", ld.AABBMax);
2221 string ownerName;
2222 if (ld.IsGroupOwned)
2223 {
2224 GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
2225 ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
2226 }
2227 else
2228 {
2229 ownerName = m_userManager.GetUserName(ld.OwnerID);
2230 }
2231 cdl.AddRow("Owner", ownerName);
2232 cdl.AddRow("Is group owned?", ld.IsGroupOwned);
2233 cdl.AddRow("GroupID", ld.GroupID);
2234
2235 cdl.AddRow("Status", ld.Status);
2236 cdl.AddRow("Flags", (ParcelFlags)ld.Flags);
2237
2238 cdl.AddRow("Landing Type", (LandingType)ld.LandingType);
2239 cdl.AddRow("User Location", ld.UserLocation);
2240 cdl.AddRow("User look at", ld.UserLookAt);
2241
2242 cdl.AddRow("Other clean time", ld.OtherCleanTime);
2243
2244 cdl.AddRow("Max Prims", lo.GetParcelMaxPrimCount());
2245 IPrimCounts pc = lo.PrimCounts;
2246 cdl.AddRow("Owner Prims", pc.Owner);
2247 cdl.AddRow("Group Prims", pc.Group);
2248 cdl.AddRow("Other Prims", pc.Others);
2249 cdl.AddRow("Selected Prims", pc.Selected);
2250 cdl.AddRow("Total Prims", pc.Total);
2251
2252 cdl.AddRow("Music URL", ld.MusicURL);
2253 cdl.AddRow("Obscure Music", ld.ObscureMusic);
2254
2255 cdl.AddRow("Media ID", ld.MediaID);
2256 cdl.AddRow("Media Autoscale", Convert.ToBoolean(ld.MediaAutoScale));
2257 cdl.AddRow("Media URL", ld.MediaURL);
2258 cdl.AddRow("Media Type", ld.MediaType);
2259 cdl.AddRow("Media Description", ld.MediaDescription);
2260 cdl.AddRow("Media Width", ld.MediaWidth);
2261 cdl.AddRow("Media Height", ld.MediaHeight);
2262 cdl.AddRow("Media Loop", ld.MediaLoop);
2263 cdl.AddRow("Obscure Media", ld.ObscureMedia);
2264
2265 cdl.AddRow("Parcel Category", ld.Category);
2266
2267 cdl.AddRow("Claim Date", ld.ClaimDate);
2268 cdl.AddRow("Claim Price", ld.ClaimPrice);
2269 cdl.AddRow("Pass Hours", ld.PassHours);
2270 cdl.AddRow("Pass Price", ld.PassPrice);
2271
2272 cdl.AddRow("Auction ID", ld.AuctionID);
2273 cdl.AddRow("Authorized Buyer ID", ld.AuthBuyerID);
2274 cdl.AddRow("Sale Price", ld.SalePrice);
2275
2276 cdl.AddToStringBuilder(report);
2277 }
1794 } 2278 }
1795} 2279}