clockwerk-opensim-stable – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Diagnostics;
32 using System.Reflection;
33 using System.Text;
34 using log4net;
35 using Nini.Config;
36 using OpenMetaverse;
37 using OpenMetaverse.StructuredData;
38 using OpenMetaverse.Messages.Linden;
39 using Mono.Addins;
40 using OpenSim.Framework;
41 using OpenSim.Framework.Capabilities;
42 using OpenSim.Framework.Console;
43 using OpenSim.Framework.Servers;
44 using OpenSim.Framework.Servers.HttpServer;
45 using OpenSim.Region.CoreModules.Framework.InterfaceCommander;
46 using OpenSim.Region.Framework.Interfaces;
47 using OpenSim.Region.Framework.Scenes;
48 using OpenSim.Region.Physics.Manager;
49 using OpenSim.Services.Interfaces;
50 using Caps = OpenSim.Framework.Capabilities.Caps;
51 using GridRegion = OpenSim.Services.Interfaces.GridRegion;
52  
53 namespace OpenSim.Region.CoreModules.World.Land
54 {
55 // used for caching
56 internal class ExtendedLandData
57 {
58 public LandData LandData;
59 public ulong RegionHandle;
60 public uint X, Y;
61 public byte RegionAccess;
62 }
63  
64 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LandManagementModule")]
65 public class LandManagementModule : INonSharedRegionModule
66 {
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
68  
69 private static readonly string remoteParcelRequestPath = "0009/";
70  
71 private LandChannel landChannel;
72 private Scene m_scene;
73 protected Commander m_commander = new Commander("land");
74  
75 protected IUserManagement m_userManager;
76 protected IPrimCountModule m_primCountModule;
77 protected IDialogModule m_Dialog;
78  
79 // Minimum for parcels to work is 64m even if we don't actually use them.
80 #pragma warning disable 0429
81 private const int landArrayMax = ((int)((int)Constants.RegionSize / 4) >= 64) ? (int)((int)Constants.RegionSize / 4) : 64;
82 #pragma warning restore 0429
83  
84 /// <value>
85 /// Local land ids at specified region co-ordinates (region size / 4)
86 /// </value>
87 private readonly int[,] m_landIDList = new int[landArrayMax, landArrayMax];
88  
89 /// <value>
90 /// Land objects keyed by local id
91 /// </value>
92 private readonly Dictionary<int, ILandObject> m_landList = new Dictionary<int, ILandObject>();
93  
94 private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
95  
96 private bool m_allowedForcefulBans = true;
97  
98 // caches ExtendedLandData
99 private Cache parcelInfoCache;
100  
101 /// <summary>
102 /// Record positions that avatar's are currently being forced to move to due to parcel entry restrictions.
103 /// </summary>
104 private Dictionary<UUID, Vector3> forcedPosition = new Dictionary<UUID, Vector3>();
105  
106 #region INonSharedRegionModule Members
107  
108 public Type ReplaceableInterface
109 {
110 get { return null; }
111 }
112  
113 public void Initialise(IConfigSource source)
114 {
115 }
116  
117 public void AddRegion(Scene scene)
118 {
119 m_scene = scene;
120 m_landIDList.Initialize();
121 landChannel = new LandChannel(scene, this);
122  
123 parcelInfoCache = new Cache();
124 parcelInfoCache.Size = 30; // the number of different parcel requests in this region to cache
125 parcelInfoCache.DefaultTTL = new TimeSpan(0, 5, 0);
126  
127 m_scene.EventManager.OnParcelPrimCountAdd += EventManagerOnParcelPrimCountAdd;
128 m_scene.EventManager.OnParcelPrimCountUpdate += EventManagerOnParcelPrimCountUpdate;
129 m_scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene;
130 m_scene.EventManager.OnRequestParcelPrimCountUpdate += EventManagerOnRequestParcelPrimCountUpdate;
131  
132 m_scene.EventManager.OnAvatarEnteringNewParcel += EventManagerOnAvatarEnteringNewParcel;
133 m_scene.EventManager.OnClientMovement += EventManagerOnClientMovement;
134 m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy;
135 m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy;
136 m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
137 m_scene.EventManager.OnMakeChildAgent += EventMakeChildAgent;
138 m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement;
139 m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage;
140 m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
141 m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan;
142 m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
143 m_scene.EventManager.OnPluginConsole += EventManagerOnPluginConsole;
144  
145 lock (m_scene)
146 {
147 m_scene.LandChannel = (ILandChannel)landChannel;
148 }
149  
150 InstallInterfaces();
151 }
152  
153 public void RegionLoaded(Scene scene)
154 {
155 m_userManager = m_scene.RequestModuleInterface<IUserManagement>();
156 m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>();
157 m_Dialog = m_scene.RequestModuleInterface<IDialogModule>();
158 }
159  
160 public void RemoveRegion(Scene scene)
161 {
162 // TODO: Also release other event manager listeners here
163  
164 m_scene.EventManager.OnPluginConsole -= EventManagerOnPluginConsole;
165 m_scene.UnregisterModuleCommander(m_commander.Name);
166 }
167  
168 // private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
169 // {
170 // ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
171 // reason = "You are not allowed to enter this sim.";
172 // return nearestParcel != null;
173 // }
174  
175 /// <summary>
176 /// Processes commandline input. Do not call directly.
177 /// </summary>
178 /// <param name="args">Commandline arguments</param>
179 protected void EventManagerOnPluginConsole(string[] args)
180 {
181 if (args[0] == "land")
182 {
183 if (args.Length == 1)
184 {
185 m_commander.ProcessConsoleCommand("help", new string[0]);
186 return;
187 }
188  
189 string[] tmpArgs = new string[args.Length - 2];
190 int i;
191 for (i = 2; i < args.Length; i++)
192 tmpArgs[i - 2] = args[i];
193  
194 m_commander.ProcessConsoleCommand(args[1], tmpArgs);
195 }
196 }
197  
198 void EventManagerOnNewClient(IClientAPI client)
199 {
200 //Register some client events
201 client.OnParcelPropertiesRequest += ClientOnParcelPropertiesRequest;
202 client.OnParcelDivideRequest += ClientOnParcelDivideRequest;
203 client.OnParcelJoinRequest += ClientOnParcelJoinRequest;
204 client.OnParcelPropertiesUpdateRequest += ClientOnParcelPropertiesUpdateRequest;
205 client.OnParcelSelectObjects += ClientOnParcelSelectObjects;
206 client.OnParcelObjectOwnerRequest += ClientOnParcelObjectOwnerRequest;
207 client.OnParcelAccessListRequest += ClientOnParcelAccessListRequest;
208 client.OnParcelAccessListUpdateRequest += ClientOnParcelAccessListUpdateRequest;
209 client.OnParcelAbandonRequest += ClientOnParcelAbandonRequest;
210 client.OnParcelGodForceOwner += ClientOnParcelGodForceOwner;
211 client.OnParcelReclaim += ClientOnParcelReclaim;
212 client.OnParcelInfoRequest += ClientOnParcelInfoRequest;
213 client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup;
214 client.OnPreAgentUpdate += ClientOnPreAgentUpdate;
215 client.OnParcelEjectUser += ClientOnParcelEjectUser;
216 client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
217 client.OnSetStartLocationRequest += ClientOnSetHome;
218  
219  
220 EntityBase presenceEntity;
221 if (m_scene.Entities.TryGetValue(client.AgentId, out presenceEntity) && presenceEntity is ScenePresence)
222 {
223 SendLandUpdate((ScenePresence)presenceEntity, true);
224 SendParcelOverlay(client);
225 }
226 }
227  
228 public void EventMakeChildAgent(ScenePresence avatar)
229 {
230 avatar.currentParcelUUID = UUID.Zero;
231 }
232  
233 void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
234 {
235 //If we are forcing a position for them to go
236 if (forcedPosition.ContainsKey(remoteClient.AgentId))
237 {
238 ScenePresence clientAvatar = m_scene.GetScenePresence(remoteClient.AgentId);
239  
240 //Putting the user into flying, both keeps the avatar in fligth when it bumps into something and stopped from going another direction AND
241 //When the avatar walks into a ban line on the ground, it prevents getting stuck
242 agentData.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_FLY;
243  
244 //Make sure we stop if they get about to the right place to prevent yoyo and prevents getting stuck on banlines
245 if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) < .2)
246 {
247 // m_log.DebugFormat(
248 // "[LAND MANAGEMENT MODULE]: Stopping force position of {0} because {1} is close enough to {2}",
249 // clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]);
250  
251 forcedPosition.Remove(remoteClient.AgentId);
252 }
253 //if we are far away, teleport
254 else if (Vector3.Distance(clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]) > 3)
255 {
256 Vector3 forcePosition = forcedPosition[remoteClient.AgentId];
257 // m_log.DebugFormat(
258 // "[LAND MANAGEMENT MODULE]: Teleporting out {0} because {1} is too far from avatar position {2}",
259 // clientAvatar.Name, clientAvatar.AbsolutePosition, forcePosition);
260  
261 m_scene.RequestTeleportLocation(remoteClient, m_scene.RegionInfo.RegionHandle,
262 forcePosition, clientAvatar.Lookat, (uint)Constants.TeleportFlags.ForceRedirect);
263  
264 forcedPosition.Remove(remoteClient.AgentId);
265 }
266 else
267 {
268 // m_log.DebugFormat(
269 // "[LAND MANAGEMENT MODULE]: Forcing {0} from {1} to {2}",
270 // clientAvatar.Name, clientAvatar.AbsolutePosition, forcedPosition[remoteClient.AgentId]);
271  
272 //Forces them toward the forced position we want if they aren't there yet
273 agentData.UseClientAgentPosition = true;
274 agentData.ClientAgentPosition = forcedPosition[remoteClient.AgentId];
275 }
276 }
277 }
278  
279 public void Close()
280 {
281 }
282  
283 public string Name
284 {
285 get { return "LandManagementModule"; }
286 }
287  
288 #endregion
289  
290 #region Parcel Add/Remove/Get/Create
291  
292 public void EventManagerOnSetAllowedForcefulBan(bool forceful)
293 {
294 AllowedForcefulBans = forceful;
295 }
296  
297 public void UpdateLandObject(int local_id, LandData data)
298 {
299 LandData newData = data.Copy();
300 newData.LocalID = local_id;
301  
302 ILandObject land;
303 lock (m_landList)
304 {
305 if (m_landList.TryGetValue(local_id, out land))
306 land.LandData = newData;
307 }
308  
309 if (land != null)
310 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land);
311 }
312  
313 public bool AllowedForcefulBans
314 {
315 get { return m_allowedForcefulBans; }
316 set { m_allowedForcefulBans = value; }
317 }
318  
319 /// <summary>
320 /// Resets the sim to the default land object (full sim piece of land owned by the default user)
321 /// </summary>
322 public void ResetSimLandObjects()
323 {
324 //Remove all the land objects in the sim and add a blank, full sim land object set to public
325 lock (m_landList)
326 {
327 m_landList.Clear();
328 m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
329 m_landIDList.Initialize();
330 }
331 }
332  
333 /// <summary>
334 /// Create a default parcel that spans the entire region and is owned by the estate owner.
335 /// </summary>
336 /// <returns>The parcel created.</returns>
337 protected ILandObject CreateDefaultParcel()
338 {
339 m_log.DebugFormat(
340 "[LAND MANAGEMENT MODULE]: Creating default parcel for region {0}", m_scene.RegionInfo.RegionName);
341  
342 ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
343 fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
344 fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
345 fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
346  
347 return AddLandObject(fullSimParcel);
348 }
349  
350 public List<ILandObject> AllParcels()
351 {
352 lock (m_landList)
353 {
354 return new List<ILandObject>(m_landList.Values);
355 }
356 }
357  
358 public List<ILandObject> ParcelsNearPoint(Vector3 position)
359 {
360 List<ILandObject> parcelsNear = new List<ILandObject>();
361 for (int x = -4; x <= 4; x += 4)
362 {
363 for (int y = -4; y <= 4; y += 4)
364 {
365 ILandObject check = GetLandObject(position.X + x, position.Y + y);
366 if (check != null)
367 {
368 if (!parcelsNear.Contains(check))
369 {
370 parcelsNear.Add(check);
371 }
372 }
373 }
374 }
375  
376 return parcelsNear;
377 }
378  
379 public void SendYouAreBannedNotice(ScenePresence avatar)
380 {
381 if (AllowedForcefulBans)
382 {
383 avatar.ControllingClient.SendAlertMessage(
384 "You are not allowed on this parcel because you are banned. Please go away.");
385 }
386 else
387 {
388 avatar.ControllingClient.SendAlertMessage(
389 "You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim!");
390 }
391 }
392  
393 private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position)
394 {
395 if (m_scene.Permissions.IsGod(avatar.UUID)) return;
396 if (position.HasValue)
397 {
398 forcedPosition[avatar.ControllingClient.AgentId] = (Vector3)position;
399 }
400 }
401  
402 public void SendYouAreRestrictedNotice(ScenePresence avatar)
403 {
404 avatar.ControllingClient.SendAlertMessage(
405 "You are not allowed on this parcel because the land owner has restricted access.");
406 }
407  
408 public void EventManagerOnAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID)
409 {
410 if (m_scene.RegionInfo.RegionID == regionID)
411 {
412 ILandObject parcelAvatarIsEntering;
413 lock (m_landList)
414 {
415 parcelAvatarIsEntering = m_landList[localLandID];
416 }
417  
418 if (parcelAvatarIsEntering != null)
419 {
420 if (avatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT)
421 {
422 if (parcelAvatarIsEntering.IsBannedFromLand(avatar.UUID))
423 {
424 SendYouAreBannedNotice(avatar);
425 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar));
426 }
427 else if (parcelAvatarIsEntering.IsRestrictedFromLand(avatar.UUID))
428 {
429 SendYouAreRestrictedNotice(avatar);
430 ForceAvatarToPosition(avatar, m_scene.GetNearestAllowedPosition(avatar));
431 }
432 else
433 {
434 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
435 }
436 }
437 else
438 {
439 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
440 }
441 }
442 }
443 }
444  
445 public void SendOutNearestBanLine(IClientAPI client)
446 {
447 ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
448 if (sp == null || sp.IsChildAgent)
449 return;
450  
451 List<ILandObject> checkLandParcels = ParcelsNearPoint(sp.AbsolutePosition);
452 foreach (ILandObject checkBan in checkLandParcels)
453 {
454 if (checkBan.IsBannedFromLand(client.AgentId))
455 {
456 checkBan.SendLandProperties((int)ParcelPropertiesStatus.CollisionBanned, false, (int)ParcelResult.Single, client);
457 return; //Only send one
458 }
459 if (checkBan.IsRestrictedFromLand(client.AgentId))
460 {
461 checkBan.SendLandProperties((int)ParcelPropertiesStatus.CollisionNotOnAccessList, false, (int)ParcelResult.Single, client);
462 return; //Only send one
463 }
464 }
465 return;
466 }
467  
468 public void SendLandUpdate(ScenePresence avatar, bool force)
469 {
470 ILandObject over = GetLandObject((int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
471 (int)Math.Min(((int)Constants.RegionSize - 1), Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
472  
473 if (over != null)
474 {
475 if (force)
476 {
477 if (!avatar.IsChildAgent)
478 {
479 over.SendLandUpdateToClient(avatar.ControllingClient);
480 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.LandData.LocalID,
481 m_scene.RegionInfo.RegionID);
482 }
483 }
484  
485 if (avatar.currentParcelUUID != over.LandData.GlobalID)
486 {
487 if (!avatar.IsChildAgent)
488 {
489 over.SendLandUpdateToClient(avatar.ControllingClient);
490 avatar.currentParcelUUID = over.LandData.GlobalID;
491 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.LandData.LocalID,
492 m_scene.RegionInfo.RegionID);
493 }
494 }
495 }
496 }
497  
498 public void SendLandUpdate(ScenePresence avatar)
499 {
500 SendLandUpdate(avatar, false);
501 }
502  
503 public void EventManagerOnSignificantClientMovement(ScenePresence clientAvatar)
504 {
505 SendLandUpdate(clientAvatar);
506 SendOutNearestBanLine(clientAvatar.ControllingClient);
507 ILandObject parcel = GetLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y);
508 if (parcel != null)
509 {
510 if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT &&
511 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown)
512 {
513 EventManagerOnAvatarEnteringNewParcel(clientAvatar, parcel.LandData.LocalID,
514 m_scene.RegionInfo.RegionID);
515 //They are going under the safety line!
516 if (!parcel.IsBannedFromLand(clientAvatar.UUID))
517 {
518 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false;
519 }
520 }
521 else if (clientAvatar.AbsolutePosition.Z < LandChannel.BAN_LINE_SAFETY_HIEGHT &&
522 parcel.IsBannedFromLand(clientAvatar.UUID))
523 {
524 //once we've sent the message once, keep going toward the target until we are done
525 if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId))
526 {
527 SendYouAreBannedNotice(clientAvatar);
528 ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar));
529 }
530 }
531 else if (parcel.IsRestrictedFromLand(clientAvatar.UUID))
532 {
533 //once we've sent the message once, keep going toward the target until we are done
534 if (forcedPosition.ContainsKey(clientAvatar.ControllingClient.AgentId))
535 {
536 SendYouAreRestrictedNotice(clientAvatar);
537 ForceAvatarToPosition(clientAvatar, m_scene.GetNearestAllowedPosition(clientAvatar));
538 }
539 }
540 else
541 {
542 //when we are finally in a safe place, lets release the forced position lock
543 forcedPosition.Remove(clientAvatar.ControllingClient.AgentId);
544 }
545 }
546 }
547  
548 /// <summary>
549 /// Like handleEventManagerOnSignificantClientMovement, but called with an AgentUpdate regardless of distance.
550 /// </summary>
551 /// <param name="avatar"></param>
552 public void EventManagerOnClientMovement(ScenePresence avatar)
553 //
554 {
555 ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
556 if (over != null)
557 {
558 if (!over.IsRestrictedFromLand(avatar.UUID) && (!over.IsBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= LandChannel.BAN_LINE_SAFETY_HIEGHT))
559 {
560 avatar.lastKnownAllowedPosition =
561 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
562 }
563 }
564 }
565  
566 public void ClientOnParcelAccessListRequest(UUID agentID, UUID sessionID, uint flags, int sequenceID,
567 int landLocalID, IClientAPI remote_client)
568 {
569 ILandObject land;
570 lock (m_landList)
571 {
572 m_landList.TryGetValue(landLocalID, out land);
573 }
574  
575 if (land != null)
576 {
577 land.SendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
578 }
579 }
580  
581 public void ClientOnParcelAccessListUpdateRequest(UUID agentID,
582 uint flags, int landLocalID, UUID transactionID, int sequenceID,
583 int sections, List<LandAccessEntry> entries,
584 IClientAPI remote_client)
585 {
586 // Flags is the list to update, it can mean either the ban or
587 // the access list (WTH is a pass list? Mentioned in ParcelFlags)
588 //
589 // There may be multiple packets, because these can get LONG.
590 // Use transactionID to determine a new chain of packets since
591 // packets may have come in out of sequence and that would be
592 // a big mess if using the sequenceID
593 ILandObject land;
594 lock (m_landList)
595 {
596 m_landList.TryGetValue(landLocalID, out land);
597 }
598  
599 if (land != null)
600 {
601 GroupPowers requiredPowers = GroupPowers.LandManageAllowed;
602 if (flags == (uint)AccessList.Ban)
603 requiredPowers = GroupPowers.LandManageBanned;
604  
605 if (m_scene.Permissions.CanEditParcelProperties(agentID,
606 land, requiredPowers))
607 {
608 land.UpdateAccessList(flags, transactionID, sequenceID,
609 sections, entries, remote_client);
610 }
611 }
612 else
613 {
614 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Invalid local land ID {0}", landLocalID);
615 }
616 }
617  
618 /// <summary>
619 /// Adds a land object to the stored list and adds them to the landIDList to what they own
620 /// </summary>
621 /// <param name="new_land">The land object being added</param>
622 public ILandObject AddLandObject(ILandObject land)
623 {
624 ILandObject new_land = land.Copy();
625  
626 // Only now can we add the prim counts to the land object - we rely on the global ID which is generated
627 // as a random UUID inside LandData initialization
628 if (m_primCountModule != null)
629 new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID);
630  
631 lock (m_landList)
632 {
633 int newLandLocalID = ++m_lastLandLocalID;
634 new_land.LandData.LocalID = newLandLocalID;
635  
636 bool[,] landBitmap = new_land.GetLandBitmap();
637 for (int x = 0; x < landArrayMax; x++)
638 {
639 for (int y = 0; y < landArrayMax; y++)
640 {
641 if (landBitmap[x, y])
642 {
643 // m_log.DebugFormat(
644 // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
645 // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
646  
647 m_landIDList[x, y] = newLandLocalID;
648 }
649 }
650 }
651  
652 m_landList.Add(newLandLocalID, new_land);
653 }
654  
655 new_land.ForceUpdateLandInfo();
656 m_scene.EventManager.TriggerLandObjectAdded(new_land);
657 return new_land;
658 }
659  
660 /// <summary>
661 /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
662 /// </summary>
663 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
664 public void removeLandObject(int local_id)
665 {
666 ILandObject land;
667 lock (m_landList)
668 {
669 for (int x = 0; x < 64; x++)
670 {
671 for (int y = 0; y < 64; y++)
672 {
673 if (m_landIDList[x, y] == local_id)
674 {
675 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Not removing land object {0}; still being used at {1}, {2}",
676 local_id, x, y);
677 return;
678 //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
679 }
680 }
681 }
682  
683 land = m_landList[local_id];
684 m_landList.Remove(local_id);
685 }
686  
687 m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID);
688 }
689  
690 /// <summary>
691 /// Clear the scene of all parcels
692 /// </summary>
693 public void Clear(bool setupDefaultParcel)
694 {
695 List<ILandObject> parcels;
696 lock (m_landList)
697 {
698 parcels = new List<ILandObject>(m_landList.Values);
699 }
700  
701 foreach (ILandObject lo in parcels)
702 {
703 //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID);
704 m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID);
705 }
706  
707 lock (m_landList)
708 {
709 m_landList.Clear();
710  
711 ResetSimLandObjects();
712 }
713  
714 if (setupDefaultParcel)
715 CreateDefaultParcel();
716 }
717  
718 private void performFinalLandJoin(ILandObject master, ILandObject slave)
719 {
720 bool[,] landBitmapSlave = slave.GetLandBitmap();
721 lock (m_landList)
722 {
723 for (int x = 0; x < 64; x++)
724 {
725 for (int y = 0; y < 64; y++)
726 {
727 if (landBitmapSlave[x, y])
728 {
729 m_landIDList[x, y] = master.LandData.LocalID;
730 }
731 }
732 }
733 }
734  
735 removeLandObject(slave.LandData.LocalID);
736 UpdateLandObject(master.LandData.LocalID, master.LandData);
737 }
738  
739 public ILandObject GetLandObject(int parcelLocalID)
740 {
741 lock (m_landList)
742 {
743 if (m_landList.ContainsKey(parcelLocalID))
744 {
745 return m_landList[parcelLocalID];
746 }
747 }
748 return null;
749 }
750  
751 /// <summary>
752 /// Get the land object at the specified point
753 /// </summary>
754 /// <param name="x_float">Value between 0 - 256 on the x axis of the point</param>
755 /// <param name="y_float">Value between 0 - 256 on the y axis of the point</param>
756 /// <returns>Land object at the point supplied</returns>
757 public ILandObject GetLandObject(float x_float, float y_float)
758 {
759 int x;
760 int y;
761  
762 if (x_float >= Constants.RegionSize || x_float < 0 || y_float >= Constants.RegionSize || y_float < 0)
763 return null;
764  
765 try
766 {
767 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / 4.0));
768 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / 4.0));
769 }
770 catch (OverflowException)
771 {
772 return null;
773 }
774  
775 if (x >= 64 || y >= 64 || x < 0 || y < 0)
776 {
777 return null;
778 }
779  
780 lock (m_landList)
781 {
782 // Corner case. If an autoreturn happens during sim startup
783 // we will come here with the list uninitialized
784 //
785 // int landId = m_landIDList[x, y];
786  
787 // if (landId == 0)
788 // m_log.DebugFormat(
789 // "[LAND MANAGEMENT MODULE]: No land object found at ({0}, {1}) on {2}",
790 // x, y, m_scene.RegionInfo.RegionName);
791  
792 if (m_landList.ContainsKey(m_landIDList[x, y]))
793 return m_landList[m_landIDList[x, y]];
794  
795 return null;
796 }
797 }
798  
799 public ILandObject GetLandObject(int x, int y)
800 {
801 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0)
802 {
803 // These exceptions here will cause a lot of complaints from the users specifically because
804 // they happen every time at border crossings
805 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
806 }
807  
808 lock (m_landIDList)
809 {
810 try
811 {
812 return m_landList[m_landIDList[x / 4, y / 4]];
813 }
814 catch (IndexOutOfRangeException)
815 {
816 // m_log.WarnFormat(
817 // "[LAND MANAGEMENT MODULE]: Tried to retrieve land object from out of bounds co-ordinate ({0},{1}) in {2}",
818 // x, y, m_scene.RegionInfo.RegionName);
819  
820 return null;
821 }
822 }
823 }
824  
825 #endregion
826  
827 #region Parcel Modification
828  
829 public void ResetOverMeRecords()
830 {
831 lock (m_landList)
832 {
833 foreach (LandObject p in m_landList.Values)
834 {
835 p.ResetOverMeRecord();
836 }
837 }
838 }
839  
840 public void EventManagerOnParcelPrimCountAdd(SceneObjectGroup obj)
841 {
842 Vector3 position = obj.AbsolutePosition;
843 ILandObject landUnderPrim = GetLandObject(position.X, position.Y);
844 if (landUnderPrim != null)
845 {
846 ((LandObject)landUnderPrim).AddPrimOverMe(obj);
847 }
848 }
849  
850 public void EventManagerOnObjectBeingRemovedFromScene(SceneObjectGroup obj)
851 {
852 lock (m_landList)
853 {
854 foreach (LandObject p in m_landList.Values)
855 {
856 p.RemovePrimFromOverMe(obj);
857 }
858 }
859 }
860  
861 public void FinalizeLandPrimCountUpdate()
862 {
863 //Get Simwide prim count for owner
864 Dictionary<UUID, List<LandObject>> landOwnersAndParcels = new Dictionary<UUID, List<LandObject>>();
865 lock (m_landList)
866 {
867 foreach (LandObject p in m_landList.Values)
868 {
869 if (!landOwnersAndParcels.ContainsKey(p.LandData.OwnerID))
870 {
871 List<LandObject> tempList = new List<LandObject>();
872 tempList.Add(p);
873 landOwnersAndParcels.Add(p.LandData.OwnerID, tempList);
874 }
875 else
876 {
877 landOwnersAndParcels[p.LandData.OwnerID].Add(p);
878 }
879 }
880 }
881  
882 foreach (UUID owner in landOwnersAndParcels.Keys)
883 {
884 int simArea = 0;
885 int simPrims = 0;
886 foreach (LandObject p in landOwnersAndParcels[owner])
887 {
888 simArea += p.LandData.Area;
889 simPrims += p.PrimCounts.Total;
890 }
891  
892 foreach (LandObject p in landOwnersAndParcels[owner])
893 {
894 p.LandData.SimwideArea = simArea;
895 p.LandData.SimwidePrims = simPrims;
896 }
897 }
898 }
899  
900 public void EventManagerOnParcelPrimCountUpdate()
901 {
902 // m_log.DebugFormat(
903 // "[LAND MANAGEMENT MODULE]: Triggered EventManagerOnParcelPrimCountUpdate() for {0}",
904 // m_scene.RegionInfo.RegionName);
905  
906 ResetOverMeRecords();
907 EntityBase[] entities = m_scene.Entities.GetEntities();
908 foreach (EntityBase obj in entities)
909 {
910 if (obj != null)
911 {
912 if ((obj is SceneObjectGroup) && !obj.IsDeleted && !((SceneObjectGroup) obj).IsAttachment)
913 {
914 m_scene.EventManager.TriggerParcelPrimCountAdd((SceneObjectGroup) obj);
915 }
916 }
917 }
918 FinalizeLandPrimCountUpdate();
919 }
920  
921 public void EventManagerOnRequestParcelPrimCountUpdate()
922 {
923 ResetOverMeRecords();
924 m_scene.EventManager.TriggerParcelPrimCountUpdate();
925 FinalizeLandPrimCountUpdate();
926 }
927  
928 /// <summary>
929 /// Subdivides a piece of land
930 /// </summary>
931 /// <param name="start_x">West Point</param>
932 /// <param name="start_y">South Point</param>
933 /// <param name="end_x">East Point</param>
934 /// <param name="end_y">North Point</param>
935 /// <param name="attempting_user_id">UUID of user who is trying to subdivide</param>
936 /// <returns>Returns true if successful</returns>
937 private void subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
938 {
939 //First, lets loop through the points and make sure they are all in the same peice of land
940 //Get the land object at start
941  
942 ILandObject startLandObject = GetLandObject(start_x, start_y);
943  
944 if (startLandObject == null) return;
945  
946 //Loop through the points
947 try
948 {
949 int totalX = end_x - start_x;
950 int totalY = end_y - start_y;
951 for (int y = 0; y < totalY; y++)
952 {
953 for (int x = 0; x < totalX; x++)
954 {
955 ILandObject tempLandObject = GetLandObject(start_x + x, start_y + y);
956 if (tempLandObject == null) return;
957 if (tempLandObject != startLandObject) return;
958 }
959 }
960 }
961 catch (Exception)
962 {
963 return;
964 }
965  
966 //If we are still here, then they are subdividing within one piece of land
967 //Check owner
968 if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, startLandObject, GroupPowers.LandDivideJoin))
969 {
970 return;
971 }
972  
973 //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
974 ILandObject newLand = startLandObject.Copy();
975 newLand.LandData.Name = newLand.LandData.Name;
976 newLand.LandData.GlobalID = UUID.Random();
977 newLand.LandData.Dwell = 0;
978  
979 newLand.SetLandBitmap(newLand.GetSquareLandBitmap(start_x, start_y, end_x, end_y));
980  
981 //Now, lets set the subdivision area of the original to false
982 int startLandObjectIndex = startLandObject.LandData.LocalID;
983 lock (m_landList)
984 {
985 m_landList[startLandObjectIndex].SetLandBitmap(
986 newLand.ModifyLandBitmapSquare(startLandObject.GetLandBitmap(), start_x, start_y, end_x, end_y, false));
987 m_landList[startLandObjectIndex].ForceUpdateLandInfo();
988 }
989  
990 //Now add the new land object
991 ILandObject result = AddLandObject(newLand);
992 UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData);
993 result.SendLandUpdateToAvatarsOverMe();
994 }
995  
996 /// <summary>
997 /// Join 2 land objects together
998 /// </summary>
999 /// <param name="start_x">x value in first piece of land</param>
1000 /// <param name="start_y">y value in first piece of land</param>
1001 /// <param name="end_x">x value in second peice of land</param>
1002 /// <param name="end_y">y value in second peice of land</param>
1003 /// <param name="attempting_user_id">UUID of the avatar trying to join the land objects</param>
1004 /// <returns>Returns true if successful</returns>
1005 private void join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
1006 {
1007 end_x -= 4;
1008 end_y -= 4;
1009  
1010 List<ILandObject> selectedLandObjects = new List<ILandObject>();
1011 int stepYSelected;
1012 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
1013 {
1014 int stepXSelected;
1015 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
1016 {
1017 ILandObject p = GetLandObject(stepXSelected, stepYSelected);
1018  
1019 if (p != null)
1020 {
1021 if (!selectedLandObjects.Contains(p))
1022 {
1023 selectedLandObjects.Add(p);
1024 }
1025 }
1026 }
1027 }
1028 ILandObject masterLandObject = selectedLandObjects[0];
1029 selectedLandObjects.RemoveAt(0);
1030  
1031 if (selectedLandObjects.Count < 1)
1032 {
1033 return;
1034 }
1035 if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, masterLandObject, GroupPowers.LandDivideJoin))
1036 {
1037 return;
1038 }
1039 foreach (ILandObject p in selectedLandObjects)
1040 {
1041 if (p.LandData.OwnerID != masterLandObject.LandData.OwnerID)
1042 {
1043 return;
1044 }
1045 }
1046  
1047 lock (m_landList)
1048 {
1049 foreach (ILandObject slaveLandObject in selectedLandObjects)
1050 {
1051 m_landList[masterLandObject.LandData.LocalID].SetLandBitmap(
1052 slaveLandObject.MergeLandBitmaps(masterLandObject.GetLandBitmap(), slaveLandObject.GetLandBitmap()));
1053 performFinalLandJoin(masterLandObject, slaveLandObject);
1054 }
1055 }
1056  
1057 masterLandObject.SendLandUpdateToAvatarsOverMe();
1058 }
1059  
1060 public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
1061 {
1062 join(start_x, start_y, end_x, end_y, attempting_user_id);
1063 }
1064  
1065 public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
1066 {
1067 subdivide(start_x, start_y, end_x, end_y, attempting_user_id);
1068 }
1069  
1070 #endregion
1071  
1072 #region Parcel Updating
1073  
1074 /// <summary>
1075 /// Where we send the ParcelOverlay packet to the client
1076 /// </summary>
1077 /// <param name="remote_client">The object representing the client</param>
1078 public void SendParcelOverlay(IClientAPI remote_client)
1079 {
1080 const int LAND_BLOCKS_PER_PACKET = 1024;
1081  
1082 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1083 int byteArrayCount = 0;
1084 int sequenceID = 0;
1085 int blockmeters = 4 * (int) Constants.RegionSize/(int)Constants.TerrainPatchSize;
1086  
1087  
1088 for (int y = 0; y < blockmeters; y++)
1089 {
1090 for (int x = 0; x < blockmeters; x++)
1091 {
1092 byte tempByte = 0; //This represents the byte for the current 4x4
1093  
1094 ILandObject currentParcelBlock = GetLandObject(x * 4, y * 4);
1095  
1096 if (currentParcelBlock != null)
1097 {
1098 if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId)
1099 {
1100 //Owner Flag
1101 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_REQUESTER);
1102 }
1103 else if (currentParcelBlock.LandData.SalePrice > 0 &&
1104 (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1105 currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1106 {
1107 //Sale Flag
1108 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_IS_FOR_SALE);
1109 }
1110 else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1111 {
1112 //Public Flag
1113 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_PUBLIC);
1114 }
1115 else
1116 {
1117 //Other Flag
1118 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_TYPE_OWNED_BY_OTHER);
1119 }
1120  
1121 //Now for border control
1122  
1123 ILandObject westParcel = null;
1124 ILandObject southParcel = null;
1125 if (x > 0)
1126 {
1127 westParcel = GetLandObject((x - 1) * 4, y * 4);
1128 }
1129 if (y > 0)
1130 {
1131 southParcel = GetLandObject(x * 4, (y - 1) * 4);
1132 }
1133  
1134 if (x == 0)
1135 {
1136 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1137 }
1138 else if (westParcel != null && westParcel != currentParcelBlock)
1139 {
1140 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST);
1141 }
1142  
1143 if (y == 0)
1144 {
1145 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1146 }
1147 else if (southParcel != null && southParcel != currentParcelBlock)
1148 {
1149 tempByte = Convert.ToByte(tempByte | LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH);
1150 }
1151  
1152 byteArray[byteArrayCount] = tempByte;
1153 byteArrayCount++;
1154 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
1155 {
1156 remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1157 byteArrayCount = 0;
1158 sequenceID++;
1159 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1160 }
1161 }
1162 }
1163 }
1164 }
1165  
1166 public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
1167 bool snap_selection, IClientAPI remote_client)
1168 {
1169 //Get the land objects within the bounds
1170 List<ILandObject> temp = new List<ILandObject>();
1171 int inc_x = end_x - start_x;
1172 int inc_y = end_y - start_y;
1173 for (int x = 0; x < inc_x; x++)
1174 {
1175 for (int y = 0; y < inc_y; y++)
1176 {
1177 ILandObject currentParcel = GetLandObject(start_x + x, start_y + y);
1178  
1179 if (currentParcel != null)
1180 {
1181 if (!temp.Contains(currentParcel))
1182 {
1183 currentParcel.ForceUpdateLandInfo();
1184 temp.Add(currentParcel);
1185 }
1186 }
1187 }
1188 }
1189  
1190 int requestResult = LandChannel.LAND_RESULT_SINGLE;
1191 if (temp.Count > 1)
1192 {
1193 requestResult = LandChannel.LAND_RESULT_MULTIPLE;
1194 }
1195  
1196 for (int i = 0; i < temp.Count; i++)
1197 {
1198 temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
1199 }
1200  
1201 SendParcelOverlay(remote_client);
1202 }
1203  
1204 public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
1205 {
1206 ILandObject land;
1207 lock (m_landList)
1208 {
1209 m_landList.TryGetValue(localID, out land);
1210 }
1211  
1212 if (land != null)
1213 {
1214 land.UpdateLandProperties(args, remote_client);
1215 m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(args, localID, remote_client);
1216 }
1217 }
1218  
1219 public void ClientOnParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
1220 {
1221 subdivide(west, south, east, north, remote_client.AgentId);
1222 }
1223  
1224 public void ClientOnParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
1225 {
1226 join(west, south, east, north, remote_client.AgentId);
1227 }
1228  
1229 public void ClientOnParcelSelectObjects(int local_id, int request_type,
1230 List<UUID> returnIDs, IClientAPI remote_client)
1231 {
1232 m_landList[local_id].SendForceObjectSelect(local_id, request_type, returnIDs, remote_client);
1233 }
1234  
1235 public void ClientOnParcelObjectOwnerRequest(int local_id, IClientAPI remote_client)
1236 {
1237 ILandObject land;
1238 lock (m_landList)
1239 {
1240 m_landList.TryGetValue(local_id, out land);
1241 }
1242  
1243 if (land != null)
1244 {
1245 m_scene.EventManager.TriggerParcelPrimCountUpdate();
1246 m_landList[local_id].SendLandObjectOwners(remote_client);
1247 }
1248 else
1249 {
1250 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Invalid land object {0} passed for parcel object owner request", local_id);
1251 }
1252 }
1253  
1254 public void ClientOnParcelGodForceOwner(int local_id, UUID ownerID, IClientAPI remote_client)
1255 {
1256 ILandObject land;
1257 lock (m_landList)
1258 {
1259 m_landList.TryGetValue(local_id, out land);
1260 }
1261  
1262 if (land != null)
1263 {
1264 if (m_scene.Permissions.IsGod(remote_client.AgentId))
1265 {
1266 land.LandData.OwnerID = ownerID;
1267 land.LandData.GroupID = UUID.Zero;
1268 land.LandData.IsGroupOwned = false;
1269 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1270  
1271 m_scene.ForEachClient(SendParcelOverlay);
1272 land.SendLandUpdateToClient(true, remote_client);
1273 }
1274 }
1275 }
1276  
1277 public void ClientOnParcelAbandonRequest(int local_id, IClientAPI remote_client)
1278 {
1279 ILandObject land;
1280 lock (m_landList)
1281 {
1282 m_landList.TryGetValue(local_id, out land);
1283 }
1284  
1285 if (land != null)
1286 {
1287 if (m_scene.Permissions.CanAbandonParcel(remote_client.AgentId, land))
1288 {
1289 land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1290 land.LandData.GroupID = UUID.Zero;
1291 land.LandData.IsGroupOwned = false;
1292 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1293 m_scene.ForEachClient(SendParcelOverlay);
1294 land.SendLandUpdateToClient(true, remote_client);
1295 }
1296 }
1297 }
1298  
1299 public void ClientOnParcelReclaim(int local_id, IClientAPI remote_client)
1300 {
1301 ILandObject land;
1302 lock (m_landList)
1303 {
1304 m_landList.TryGetValue(local_id, out land);
1305 }
1306  
1307 if (land != null)
1308 {
1309 if (m_scene.Permissions.CanReclaimParcel(remote_client.AgentId, land))
1310 {
1311 land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1312 land.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
1313 land.LandData.GroupID = UUID.Zero;
1314 land.LandData.IsGroupOwned = false;
1315 land.LandData.SalePrice = 0;
1316 land.LandData.AuthBuyerID = UUID.Zero;
1317 land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1318  
1319 m_scene.ForEachClient(SendParcelOverlay);
1320 land.SendLandUpdateToClient(true, remote_client);
1321 }
1322 }
1323 }
1324 #endregion
1325  
1326 // If the economy has been validated by the economy module,
1327 // and land has been validated as well, this method transfers
1328 // the land ownership
1329  
1330 public void EventManagerOnLandBuy(Object o, EventManager.LandBuyArgs e)
1331 {
1332 if (e.economyValidated && e.landValidated)
1333 {
1334 ILandObject land;
1335 lock (m_landList)
1336 {
1337 m_landList.TryGetValue(e.parcelLocalID, out land);
1338 }
1339  
1340 if (land != null)
1341 {
1342 land.UpdateLandSold(e.agentId, e.groupId, e.groupOwned, (uint)e.transactionID, e.parcelPrice, e.parcelArea);
1343 }
1344 }
1345 }
1346  
1347 // After receiving a land buy packet, first the data needs to
1348 // be validated. This method validates the right to buy the
1349 // parcel
1350  
1351 public void EventManagerOnValidateLandBuy(Object o, EventManager.LandBuyArgs e)
1352 {
1353 if (e.landValidated == false)
1354 {
1355 ILandObject lob = null;
1356 lock (m_landList)
1357 {
1358 m_landList.TryGetValue(e.parcelLocalID, out lob);
1359 }
1360  
1361 if (lob != null)
1362 {
1363 UUID AuthorizedID = lob.LandData.AuthBuyerID;
1364 int saleprice = lob.LandData.SalePrice;
1365 UUID pOwnerID = lob.LandData.OwnerID;
1366  
1367 bool landforsale = ((lob.LandData.Flags &
1368 (uint)(ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects)) != 0);
1369 if ((AuthorizedID == UUID.Zero || AuthorizedID == e.agentId) && e.parcelPrice >= saleprice && landforsale)
1370 {
1371 // TODO I don't think we have to lock it here, no?
1372 //lock (e)
1373 //{
1374 e.parcelOwnerID = pOwnerID;
1375 e.landValidated = true;
1376 //}
1377 }
1378 }
1379 }
1380 }
1381  
1382 void ClientOnParcelDeedToGroup(int parcelLocalID, UUID groupID, IClientAPI remote_client)
1383 {
1384 ILandObject land;
1385 lock (m_landList)
1386 {
1387 m_landList.TryGetValue(parcelLocalID, out land);
1388 }
1389  
1390 if (!m_scene.Permissions.CanDeedParcel(remote_client.AgentId, land))
1391 return;
1392  
1393 if (land != null)
1394 {
1395 land.DeedToGroup(groupID);
1396 }
1397 }
1398  
1399 #region Land Object From Storage Functions
1400  
1401 public void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1402 {
1403 // m_log.DebugFormat(
1404 // "[LAND MANAGMENT MODULE]: Processing {0} incoming parcels on {1}", data.Count, m_scene.Name);
1405  
1406 for (int i = 0; i < data.Count; i++)
1407 IncomingLandObjectFromStorage(data[i]);
1408 }
1409  
1410 public void IncomingLandObjectFromStorage(LandData data)
1411 {
1412 ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene);
1413 new_land.LandData = data.Copy();
1414 new_land.SetLandBitmapFromByteArray();
1415 AddLandObject(new_land);
1416 }
1417  
1418 public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
1419 {
1420 if (localID != -1)
1421 {
1422 ILandObject selectedParcel = null;
1423 lock (m_landList)
1424 {
1425 m_landList.TryGetValue(localID, out selectedParcel);
1426 }
1427  
1428 if (selectedParcel == null)
1429 return;
1430  
1431 selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
1432 }
1433 else
1434 {
1435 if (returnType != 1)
1436 {
1437 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType);
1438 return;
1439 }
1440  
1441 // We get here when the user returns objects from the list of Top Colliders or Top Scripts.
1442 // In that case we receive specific object UUID's, but no parcel ID.
1443  
1444 Dictionary<UUID, HashSet<SceneObjectGroup>> returns = new Dictionary<UUID, HashSet<SceneObjectGroup>>();
1445  
1446 foreach (UUID groupID in taskIDs)
1447 {
1448 SceneObjectGroup obj = m_scene.GetSceneObjectGroup(groupID);
1449 if (obj != null)
1450 {
1451 if (!returns.ContainsKey(obj.OwnerID))
1452 returns[obj.OwnerID] = new HashSet<SceneObjectGroup>();
1453 returns[obj.OwnerID].Add(obj);
1454 }
1455 else
1456 {
1457 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID);
1458 }
1459 }
1460  
1461 int num = 0;
1462 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1463 num += objs.Count;
1464 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num);
1465  
1466 foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1467 {
1468 List<SceneObjectGroup> objs2 = new List<SceneObjectGroup>(objs);
1469 if (m_scene.Permissions.CanReturnObjects(null, remoteClient.AgentId, objs2))
1470 {
1471 m_scene.returnObjects(objs2.ToArray(), remoteClient.AgentId);
1472 }
1473 else
1474 {
1475 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
1476 objs2.Count, objs2[0].OwnerID);
1477 }
1478 }
1479 }
1480 }
1481  
1482 public void EventManagerOnNoLandDataFromStorage()
1483 {
1484 ResetSimLandObjects();
1485 CreateDefaultParcel();
1486 }
1487  
1488 #endregion
1489  
1490 public void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
1491 {
1492 lock (m_landList)
1493 {
1494 foreach (LandObject obj in m_landList.Values)
1495 {
1496 obj.SetParcelObjectMaxOverride(overrideDel);
1497 }
1498 }
1499 }
1500  
1501 public void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
1502 {
1503 }
1504  
1505 #region CAPS handler
1506  
1507 private void EventManagerOnRegisterCaps(UUID agentID, Caps caps)
1508 {
1509 string capsBase = "/CAPS/" + caps.CapsObjectPath;
1510 caps.RegisterHandler(
1511 "RemoteParcelRequest",
1512 new RestStreamHandler(
1513 "POST",
1514 capsBase + remoteParcelRequestPath,
1515 (request, path, param, httpRequest, httpResponse)
1516 => RemoteParcelRequest(request, path, param, agentID, caps),
1517 "RemoteParcelRequest",
1518 agentID.ToString()));
1519  
1520 UUID parcelCapID = UUID.Random();
1521 caps.RegisterHandler(
1522 "ParcelPropertiesUpdate",
1523 new RestStreamHandler(
1524 "POST",
1525 "/CAPS/" + parcelCapID,
1526 (request, path, param, httpRequest, httpResponse)
1527 => ProcessPropertiesUpdate(request, path, param, agentID, caps),
1528 "ParcelPropertiesUpdate",
1529 agentID.ToString()));
1530 }
1531 private string ProcessPropertiesUpdate(string request, string path, string param, UUID agentID, Caps caps)
1532 {
1533 IClientAPI client;
1534 if (!m_scene.TryGetClient(agentID, out client))
1535 {
1536 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to retrieve IClientAPI for {0}", agentID);
1537 return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty());
1538 }
1539  
1540 ParcelPropertiesUpdateMessage properties = new ParcelPropertiesUpdateMessage();
1541 OpenMetaverse.StructuredData.OSDMap args = (OpenMetaverse.StructuredData.OSDMap) OSDParser.DeserializeLLSDXml(request);
1542  
1543 properties.Deserialize(args);
1544  
1545 LandUpdateArgs land_update = new LandUpdateArgs();
1546 int parcelID = properties.LocalID;
1547 land_update.AuthBuyerID = properties.AuthBuyerID;
1548 land_update.Category = properties.Category;
1549 land_update.Desc = properties.Desc;
1550 land_update.GroupID = properties.GroupID;
1551 land_update.LandingType = (byte) properties.Landing;
1552 land_update.MediaAutoScale = (byte) Convert.ToInt32(properties.MediaAutoScale);
1553 land_update.MediaID = properties.MediaID;
1554 land_update.MediaURL = properties.MediaURL;
1555 land_update.MusicURL = properties.MusicURL;
1556 land_update.Name = properties.Name;
1557 land_update.ParcelFlags = (uint) properties.ParcelFlags;
1558 land_update.PassHours = (int) properties.PassHours;
1559 land_update.PassPrice = (int) properties.PassPrice;
1560 land_update.SalePrice = (int) properties.SalePrice;
1561 land_update.SnapshotID = properties.SnapshotID;
1562 land_update.UserLocation = properties.UserLocation;
1563 land_update.UserLookAt = properties.UserLookAt;
1564 land_update.MediaDescription = properties.MediaDesc;
1565 land_update.MediaType = properties.MediaType;
1566 land_update.MediaWidth = properties.MediaWidth;
1567 land_update.MediaHeight = properties.MediaHeight;
1568 land_update.MediaLoop = properties.MediaLoop;
1569 land_update.ObscureMusic = properties.ObscureMusic;
1570 land_update.ObscureMedia = properties.ObscureMedia;
1571  
1572 ILandObject land;
1573 lock (m_landList)
1574 {
1575 m_landList.TryGetValue(parcelID, out land);
1576 }
1577  
1578 if (land != null)
1579 {
1580 land.UpdateLandProperties(land_update, client);
1581 m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(land_update, parcelID, client);
1582 }
1583 else
1584 {
1585 m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to find parcelID {0}", parcelID);
1586 }
1587 return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty());
1588 }
1589 // we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the
1590 // "real" parcelID, because we wouldn't be able to map that to the region the parcel belongs to.
1591 // So, we create a "fake" parcelID by using the regionHandle (64 bit), and the local (integer) x
1592 // and y coordinate (each 8 bit), encoded in a UUID (128 bit).
1593 //
1594 // Request format:
1595 // <llsd>
1596 // <map>
1597 // <key>location</key>
1598 // <array>
1599 // <real>1.23</real>
1600 // <real>45..6</real>
1601 // <real>78.9</real>
1602 // </array>
1603 // <key>region_id</key>
1604 // <uuid>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</uuid>
1605 // </map>
1606 // </llsd>
1607 private string RemoteParcelRequest(string request, string path, string param, UUID agentID, Caps caps)
1608 {
1609 UUID parcelID = UUID.Zero;
1610 try
1611 {
1612 Hashtable hash = new Hashtable();
1613 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
1614 if (hash.ContainsKey("region_id") && hash.ContainsKey("location"))
1615 {
1616 UUID regionID = (UUID)hash["region_id"];
1617 ArrayList list = (ArrayList)hash["location"];
1618 uint x = (uint)(double)list[0];
1619 uint y = (uint)(double)list[1];
1620 if (hash.ContainsKey("region_handle"))
1621 {
1622 // if you do a "About Landmark" on a landmark a second time, the viewer sends the
1623 // region_handle it got earlier via RegionHandleRequest
1624 ulong regionHandle = Util.BytesToUInt64Big((byte[])hash["region_handle"]);
1625 parcelID = Util.BuildFakeParcelID(regionHandle, x, y);
1626 }
1627 else if (regionID == m_scene.RegionInfo.RegionID)
1628 {
1629 // a parcel request for a local parcel => no need to query the grid
1630 parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y);
1631 }
1632 else
1633 {
1634 // a parcel request for a parcel in another region. Ask the grid about the region
1635 GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, regionID);
1636 if (info != null)
1637 parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y);
1638 }
1639 }
1640 }
1641 catch (LLSD.LLSDParseException e)
1642 {
1643 m_log.ErrorFormat("[LAND MANAGEMENT MODULE]: Fetch error: {0}", e.Message);
1644 m_log.ErrorFormat("[LAND MANAGEMENT MODULE]: ... in request {0}", request);
1645 }
1646 catch (InvalidCastException)
1647 {
1648 m_log.ErrorFormat("[LAND MANAGEMENT MODULE]: Wrong type in request {0}", request);
1649 }
1650  
1651 LLSDRemoteParcelResponse response = new LLSDRemoteParcelResponse();
1652 response.parcel_id = parcelID;
1653 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelID {0}", parcelID);
1654  
1655 return LLSDHelpers.SerialiseLLSDReply(response);
1656 }
1657  
1658 #endregion
1659  
1660 private void ClientOnParcelInfoRequest(IClientAPI remoteClient, UUID parcelID)
1661 {
1662 if (parcelID == UUID.Zero)
1663 return;
1664  
1665 ExtendedLandData data = (ExtendedLandData)parcelInfoCache.Get(parcelID.ToString(),
1666 delegate(string id)
1667 {
1668 UUID parcel = UUID.Zero;
1669 UUID.TryParse(id, out parcel);
1670 // assume we've got the parcelID we just computed in RemoteParcelRequest
1671 ExtendedLandData extLandData = new ExtendedLandData();
1672 Util.ParseFakeParcelID(parcel, out extLandData.RegionHandle,
1673 out extLandData.X, out extLandData.Y);
1674 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelinfo request for regionHandle {0}, x/y {1}/{2}",
1675 extLandData.RegionHandle, extLandData.X, extLandData.Y);
1676  
1677 // for this region or for somewhere else?
1678 if (extLandData.RegionHandle == m_scene.RegionInfo.RegionHandle)
1679 {
1680 extLandData.LandData = this.GetLandObject(extLandData.X, extLandData.Y).LandData;
1681 extLandData.RegionAccess = m_scene.RegionInfo.AccessLevel;
1682 }
1683 else
1684 {
1685 ILandService landService = m_scene.RequestModuleInterface<ILandService>();
1686 extLandData.LandData = landService.GetLandData(m_scene.RegionInfo.ScopeID,
1687 extLandData.RegionHandle,
1688 extLandData.X,
1689 extLandData.Y,
1690 out extLandData.RegionAccess);
1691 if (extLandData.LandData == null)
1692 {
1693 // we didn't find the region/land => don't cache
1694 return null;
1695 }
1696 }
1697 return extLandData;
1698 });
1699  
1700 if (data != null) // if we found some data, send it
1701 {
1702 GridRegion info;
1703 if (data.RegionHandle == m_scene.RegionInfo.RegionHandle)
1704 {
1705 info = new GridRegion(m_scene.RegionInfo);
1706 }
1707 else
1708 {
1709 // most likely still cached from building the extLandData entry
1710 uint x = 0, y = 0;
1711 Utils.LongToUInts(data.RegionHandle, out x, out y);
1712 info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
1713 }
1714 // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
1715 m_log.DebugFormat("[LAND MANAGEMENT MODULE]: got parcelinfo for parcel {0} in region {1}; sending...",
1716 data.LandData.Name, data.RegionHandle);
1717 // HACK for now
1718 RegionInfo r = new RegionInfo();
1719 r.RegionName = info.RegionName;
1720 r.RegionLocX = (uint)info.RegionLocX;
1721 r.RegionLocY = (uint)info.RegionLocY;
1722 r.RegionSettings.Maturity = (int)Util.ConvertAccessLevelToMaturity(data.RegionAccess);
1723 remoteClient.SendParcelInfo(r, data.LandData, parcelID, data.X, data.Y);
1724 }
1725 else
1726 m_log.Debug("[LAND MANAGEMENT MODULE]: got no parcelinfo; not sending");
1727 }
1728  
1729 public void setParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
1730 {
1731 ILandObject land;
1732 lock (m_landList)
1733 {
1734 m_landList.TryGetValue(localID, out land);
1735 }
1736  
1737 if (land == null) return;
1738  
1739 if (!m_scene.Permissions.CanEditParcelProperties(remoteClient.AgentId, land, GroupPowers.LandOptions))
1740 return;
1741  
1742 land.LandData.OtherCleanTime = otherCleanTime;
1743  
1744 UpdateLandObject(localID, land.LandData);
1745 }
1746  
1747 Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
1748  
1749 public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1750 {
1751 ScenePresence targetAvatar = null;
1752 ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
1753 ScenePresence parcelManager = null;
1754 ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
1755 System.Threading.Timer Timer;
1756  
1757 if (targetAvatar.UserLevel == 0)
1758 {
1759 ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1760 if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze))
1761 return;
1762 if (flags == 0)
1763 {
1764 targetAvatar.AllowMovement = false;
1765 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
1766 parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
1767 System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
1768 Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
1769 Timers.Add(targetAvatar.UUID, Timer);
1770 }
1771 else
1772 {
1773 targetAvatar.AllowMovement = true;
1774 targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
1775 parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
1776 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1777 Timers.Remove(targetAvatar.UUID);
1778 Timer.Dispose();
1779 }
1780 }
1781 }
1782  
1783 private void OnEndParcelFrozen(object avatar)
1784 {
1785 ScenePresence targetAvatar = (ScenePresence)avatar;
1786 targetAvatar.AllowMovement = true;
1787 System.Threading.Timer Timer;
1788 Timers.TryGetValue(targetAvatar.UUID, out Timer);
1789 Timers.Remove(targetAvatar.UUID);
1790 targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
1791 }
1792  
1793 public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
1794 {
1795 ScenePresence targetAvatar = null;
1796 ScenePresence parcelManager = null;
1797  
1798 // Must have presences
1799 if (!m_scene.TryGetScenePresence(target, out targetAvatar) ||
1800 !m_scene.TryGetScenePresence(client.AgentId, out parcelManager))
1801 return;
1802  
1803 // Cannot eject estate managers or gods
1804 if (m_scene.Permissions.IsAdministrator(target))
1805 return;
1806  
1807 // Check if you even have permission to do this
1808 ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
1809 if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze) &&
1810 !m_scene.Permissions.IsAdministrator(client.AgentId))
1811 return;
1812 Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land);
1813  
1814 targetAvatar.TeleportWithMomentum(pos, null);
1815 targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
1816 parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
1817  
1818 if ((flags & 1) != 0) // Ban TODO: Remove magic number
1819 {
1820 LandAccessEntry entry = new LandAccessEntry();
1821 entry.AgentID = targetAvatar.UUID;
1822 entry.Flags = AccessList.Ban;
1823 entry.Expires = 0; // Perm
1824  
1825 land.LandData.ParcelAccessList.Add(entry);
1826 }
1827 }
1828  
1829 /// <summary>
1830 /// Sets the Home Point. The LoginService uses this to know where to put a user when they log-in
1831 /// </summary>
1832 /// <param name="remoteClient"></param>
1833 /// <param name="regionHandle"></param>
1834 /// <param name="position"></param>
1835 /// <param name="lookAt"></param>
1836 /// <param name="flags"></param>
1837 public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
1838 {
1839 // Let's find the parcel in question
1840 ILandObject land = landChannel.GetLandObject(position);
1841 if (land == null || m_scene.GridUserService == null)
1842 {
1843 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
1844 return;
1845 }
1846  
1847 // Gather some data
1848 ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID);
1849 SceneObjectGroup telehub = null;
1850 if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
1851 // Does the telehub exist in the scene?
1852 telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
1853  
1854 // Can the user set home here?
1855 if (// (a) gods and land managers can set home
1856 m_scene.Permissions.IsAdministrator(remoteClient.AgentId) ||
1857 m_scene.Permissions.IsGod(remoteClient.AgentId) ||
1858 // (b) land owners can set home
1859 remoteClient.AgentId == land.LandData.OwnerID ||
1860 // (c) members of the land-associated group in roles that can set home
1861 ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) ||
1862 // (d) parcels with telehubs can be the home of anyone
1863 (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y)))
1864 {
1865 if (m_scene.GridUserService.SetHome(remoteClient.AgentId.ToString(), land.RegionUUID, position, lookAt))
1866 // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
1867 m_Dialog.SendAlertToUser(remoteClient, "Home position set.");
1868 else
1869 m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
1870 }
1871 else
1872 m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel.");
1873 }
1874  
1875  
1876 protected void InstallInterfaces()
1877 {
1878 Command clearCommand
1879 = new Command("clear", CommandIntentions.COMMAND_HAZARDOUS, ClearCommand, "Clears all the parcels from the region.");
1880 Command showCommand
1881 = new Command("show", CommandIntentions.COMMAND_STATISTICAL, ShowParcelsCommand, "Shows all parcels on the region.");
1882  
1883 m_commander.RegisterCommand("clear", clearCommand);
1884 m_commander.RegisterCommand("show", showCommand);
1885  
1886 // Add this to our scene so scripts can call these functions
1887 m_scene.RegisterModuleCommander(m_commander);
1888 }
1889  
1890 protected void ClearCommand(Object[] args)
1891 {
1892 string response = MainConsole.Instance.CmdPrompt(
1893 string.Format(
1894 "Are you sure that you want to clear all land parcels from {0} (y or n)",
1895 m_scene.RegionInfo.RegionName),
1896 "n");
1897  
1898 if (response.ToLower() == "y")
1899 {
1900 Clear(true);
1901 MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.RegionInfo.RegionName);
1902 }
1903 else
1904 {
1905 MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.RegionInfo.RegionName);
1906 }
1907 }
1908  
1909 protected void ShowParcelsCommand(Object[] args)
1910 {
1911 StringBuilder report = new StringBuilder();
1912  
1913 report.AppendFormat("Land information for {0}\n", m_scene.RegionInfo.RegionName);
1914 report.AppendFormat(
1915 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n",
1916 "Parcel Name",
1917 "Local ID",
1918 "Area",
1919 "Starts",
1920 "Ends",
1921 "Owner");
1922  
1923 lock (m_landList)
1924 {
1925 foreach (ILandObject lo in m_landList.Values)
1926 {
1927 LandData ld = lo.LandData;
1928  
1929 report.AppendFormat(
1930 "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n",
1931 ld.Name, ld.LocalID, ld.Area, lo.StartPoint, lo.EndPoint, m_userManager.GetUserName(ld.OwnerID));
1932 }
1933 }
1934  
1935 MainConsole.Instance.Output(report.ToString());
1936 }
1937 }
1938 }