opensim-development – Blame information for rev 1

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