diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/CoreModules/World/Land/LandManagementModule.cs | 938 |
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; | |||
42 | using OpenSim.Framework.Console; | 42 | using OpenSim.Framework.Console; |
43 | using OpenSim.Framework.Servers; | 43 | using OpenSim.Framework.Servers; |
44 | using OpenSim.Framework.Servers.HttpServer; | 44 | using OpenSim.Framework.Servers.HttpServer; |
45 | using OpenSim.Region.CoreModules.Framework.InterfaceCommander; | ||
46 | using OpenSim.Region.Framework.Interfaces; | 45 | using OpenSim.Region.Framework.Interfaces; |
47 | using OpenSim.Region.Framework.Scenes; | 46 | using OpenSim.Region.Framework.Scenes; |
48 | using OpenSim.Region.Physics.Manager; | 47 | using OpenSim.Region.PhysicsModules.SharedBase; |
49 | using OpenSim.Services.Interfaces; | 48 | using OpenSim.Services.Interfaces; |
50 | using Caps = OpenSim.Framework.Capabilities.Caps; | 49 | using Caps = OpenSim.Framework.Capabilities.Caps; |
51 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 50 | using 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 | } |