OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
LandManagementModule.cs
Go to the documentation of this file.
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.PhysicsModules.SharedBase;
48 using OpenSim.Services.Interfaces;
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")]
65  {
66  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
67  private static readonly string LogHeader = "[LAND MANAGEMENT MODULE]";
68 
72 
73  public const int LandUnit = 4;
74 
75  private static readonly string remoteParcelRequestPath = "0009/";
76 
77  private LandChannel landChannel;
78  private Scene m_scene;
79 
84 
88  private int[,] m_landIDList;
89 
93 // private readonly Dictionary<int, ILandObject> m_landList = new Dictionary<int, ILandObject>();
94 
95  //ubit: removed the readonly so i can move it around
96  private Dictionary<int, ILandObject> m_landList = new Dictionary<int, ILandObject>();
97 
98  private int m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
99 
100  private bool m_allowedForcefulBans = true;
101  private bool m_showBansLines = true;
102  private UUID DefaultGodParcelGroup;
103  private string DefaultGodParcelName;
104 
105  // caches ExtendedLandData
106  private Cache parcelInfoCache;
107 
111  private HashSet<UUID> forcedPosition = new HashSet<UUID>();
112 
113 
114  // Enables limiting parcel layer info transmission when doing simple updates
115  private bool shouldLimitParcelLayerInfoToViewDistance { get; set; }
116  // "View distance" for sending parcel layer info if asked for from a view point in the region
117  private int parcelLayerViewDistance { get; set; }
118 
119  #region INonSharedRegionModule Members
120 
121  public Type ReplaceableInterface
122  {
123  get { return null; }
124  }
125 
126  public void Initialise(IConfigSource source)
127  {
128  shouldLimitParcelLayerInfoToViewDistance = true;
129  parcelLayerViewDistance = 128;
130  IConfig landManagementConfig = source.Configs["LandManagement"];
131  if (landManagementConfig != null)
132  {
133  shouldLimitParcelLayerInfoToViewDistance = landManagementConfig.GetBoolean("LimitParcelLayerUpdateDistance", shouldLimitParcelLayerInfoToViewDistance);
134  parcelLayerViewDistance = landManagementConfig.GetInt("ParcelLayerViewDistance", parcelLayerViewDistance);
135  DefaultGodParcelGroup = new UUID(landManagementConfig.GetString("DefaultAdministratorGroupUUID", UUID.Zero.ToString()));
136  DefaultGodParcelName = landManagementConfig.GetString("DefaultAdministratorParcelName", "Default Parcel");
137  bool disablebans = landManagementConfig.GetBoolean("DisableParcelBans", !m_allowedForcefulBans);
138  m_allowedForcefulBans = !disablebans;
139  m_showBansLines = landManagementConfig.GetBoolean("ShowParcelBansLines", m_showBansLines);
140  }
141  }
142 
143  public void AddRegion(Scene scene)
144  {
145  m_scene = scene;
146  m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
147 
148  landChannel = new LandChannel(scene, this);
149 
150  parcelInfoCache = new Cache();
151  parcelInfoCache.Size = 30; // the number of different parcel requests in this region to cache
152  parcelInfoCache.DefaultTTL = new TimeSpan(0, 5, 0);
153 
154  m_scene.EventManager.OnParcelPrimCountAdd += EventManagerOnParcelPrimCountAdd;
155  m_scene.EventManager.OnParcelPrimCountUpdate += EventManagerOnParcelPrimCountUpdate;
156  m_scene.EventManager.OnObjectBeingRemovedFromScene += EventManagerOnObjectBeingRemovedFromScene;
157  m_scene.EventManager.OnRequestParcelPrimCountUpdate += EventManagerOnRequestParcelPrimCountUpdate;
158 
159  m_scene.EventManager.OnAvatarEnteringNewParcel += EventManagerOnAvatarEnteringNewParcel;
160  m_scene.EventManager.OnClientMovement += EventManagerOnClientMovement;
161  m_scene.EventManager.OnValidateLandBuy += EventManagerOnValidateLandBuy;
162  m_scene.EventManager.OnLandBuy += EventManagerOnLandBuy;
163  m_scene.EventManager.OnNewClient += EventManagerOnNewClient;
164  m_scene.EventManager.OnMakeChildAgent += EventMakeChildAgent;
165  m_scene.EventManager.OnSignificantClientMovement += EventManagerOnSignificantClientMovement;
166  m_scene.EventManager.OnNoticeNoLandDataFromStorage += EventManagerOnNoLandDataFromStorage;
167  m_scene.EventManager.OnIncomingLandDataFromStorage += EventManagerOnIncomingLandDataFromStorage;
168  m_scene.EventManager.OnSetAllowForcefulBan += EventManagerOnSetAllowedForcefulBan;
169  m_scene.EventManager.OnRegisterCaps += EventManagerOnRegisterCaps;
170 
171  lock (m_scene)
172  {
173  m_scene.LandChannel = (ILandChannel)landChannel;
174  }
175 
176  RegisterCommands();
177  }
178 
179  public void RegionLoaded(Scene scene)
180  {
181  m_userManager = m_scene.RequestModuleInterface<IUserManagement>();
182  m_groupManager = m_scene.RequestModuleInterface<IGroupsModule>();
183  m_primCountModule = m_scene.RequestModuleInterface<IPrimCountModule>();
184  m_Dialog = m_scene.RequestModuleInterface<IDialogModule>();
185  }
186 
187  public void RemoveRegion(Scene scene)
188  {
189  // TODO: Release event manager listeners here
190  }
191 
192 // private bool OnVerifyUserConnection(ScenePresence scenePresence, out string reason)
193 // {
194 // ILandObject nearestParcel = m_scene.GetNearestAllowedParcel(scenePresence.UUID, scenePresence.AbsolutePosition.X, scenePresence.AbsolutePosition.Y);
195 // reason = "You are not allowed to enter this sim.";
196 // return nearestParcel != null;
197 // }
198 
199  void EventManagerOnNewClient(IClientAPI client)
200  {
201  //Register some client events
202  client.OnParcelPropertiesRequest += ClientOnParcelPropertiesRequest;
203  client.OnParcelDivideRequest += ClientOnParcelDivideRequest;
204  client.OnParcelJoinRequest += ClientOnParcelJoinRequest;
205  client.OnParcelPropertiesUpdateRequest += ClientOnParcelPropertiesUpdateRequest;
206  client.OnParcelSelectObjects += ClientOnParcelSelectObjects;
207  client.OnParcelObjectOwnerRequest += ClientOnParcelObjectOwnerRequest;
208  client.OnParcelAccessListRequest += ClientOnParcelAccessListRequest;
209  client.OnParcelAccessListUpdateRequest += ClientOnParcelAccessListUpdateRequest;
210  client.OnParcelAbandonRequest += ClientOnParcelAbandonRequest;
211  client.OnParcelGodForceOwner += ClientOnParcelGodForceOwner;
212  client.OnParcelReclaim += ClientOnParcelReclaim;
213  client.OnParcelInfoRequest += ClientOnParcelInfoRequest;
214  client.OnParcelDeedToGroup += ClientOnParcelDeedToGroup;
215  client.OnPreAgentUpdate += ClientOnPreAgentUpdate;
216  client.OnParcelEjectUser += ClientOnParcelEjectUser;
217  client.OnParcelFreezeUser += ClientOnParcelFreezeUser;
218  client.OnSetStartLocationRequest += ClientOnSetHome;
219  }
220 
221  public void EventMakeChildAgent(ScenePresence avatar)
222  {
223  avatar.currentParcelUUID = UUID.Zero;
224  }
225 
226  void ClientOnPreAgentUpdate(IClientAPI remoteClient, AgentUpdateArgs agentData)
227  {
228  }
229 
230  public void Close()
231  {
232  }
233 
234  public string Name
235  {
236  get { return "LandManagementModule"; }
237  }
238 
239  #endregion
240 
241  #region Parcel Add/Remove/Get/Create
242 
243  public void EventManagerOnSetAllowedForcefulBan(bool forceful)
244  {
245  AllowedForcefulBans = forceful;
246  }
247 
248  public void UpdateLandObject(int local_id, LandData data)
249  {
250  LandData newData = data.Copy();
251  newData.LocalID = local_id;
252 
254  lock (m_landList)
255  {
256  if (m_landList.TryGetValue(local_id, out land))
257  land.LandData = newData;
258  }
259 
260  if (land != null)
261  m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, land);
262  }
263 
264  public bool AllowedForcefulBans
265  {
266  get { return m_allowedForcefulBans; }
267  set { m_allowedForcefulBans = value; }
268  }
269 
273  public void ResetSimLandObjects()
274  {
275  //Remove all the land objects in the sim and add a blank, full sim land object set to public
276  lock (m_landList)
277  {
278  m_landList.Clear();
279  m_lastLandLocalID = LandChannel.START_LAND_LOCAL_ID - 1;
280 
281  m_landIDList = new int[m_scene.RegionInfo.RegionSizeX / LandUnit, m_scene.RegionInfo.RegionSizeY / LandUnit];
282  }
283  }
284 
290  {
291  m_log.DebugFormat("{0} Creating default parcel for region {1}", LogHeader, m_scene.RegionInfo.RegionName);
292 
293  ILandObject fullSimParcel = new LandObject(UUID.Zero, false, m_scene);
294 
295  fullSimParcel.SetLandBitmap(fullSimParcel.GetSquareLandBitmap(0, 0,
296  (int)m_scene.RegionInfo.RegionSizeX, (int)m_scene.RegionInfo.RegionSizeY));
297  fullSimParcel.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
298  fullSimParcel.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
299 
300  return AddLandObject(fullSimParcel);
301  }
302 
303  public List<ILandObject> AllParcels()
304  {
305  lock (m_landList)
306  {
307  return new List<ILandObject>(m_landList.Values);
308  }
309  }
310 
311  public List<ILandObject> ParcelsNearPoint(Vector3 position)
312  {
313  List<ILandObject> parcelsNear = new List<ILandObject>();
314  for (int x = -8; x <= 8; x += 4)
315  {
316  for (int y = -8; y <= 8; y += 4)
317  {
318  ILandObject check = GetLandObject(position.X + x, position.Y + y);
319  if (check != null)
320  {
321  if (!parcelsNear.Contains(check))
322  {
323  parcelsNear.Add(check);
324  }
325  }
326  }
327  }
328 
329  return parcelsNear;
330  }
331 
332  // checks and enforces bans or restrictions
333  // returns true if enforced
334  public bool EnforceBans(ILandObject land, ScenePresence avatar)
335  {
336  Vector3 agentpos = avatar.AbsolutePosition;
337  float h = m_scene.GetGroundHeight(agentpos.X, agentpos.Y) + LandChannel.BAN_LINE_SAFETY_HEIGHT;
338  float zdif = avatar.AbsolutePosition.Z - h;
339  if (zdif > 0 )
340  {
341  forcedPosition.Remove(avatar.UUID);
342  avatar.lastKnownAllowedPosition = agentpos;
343  return false;
344  }
345 
346  bool ban = false;
347  string reason = "";
348  if (land.IsRestrictedFromLand(avatar.UUID))
349  {
350  reason = "You do not have access to the parcel";
351  ban = true;
352  }
353 
354  if (land.IsBannedFromLand(avatar.UUID))
355  {
356  if ( m_allowedForcefulBans)
357  {
358  reason ="You are banned from parcel";
359  ban = true;
360  }
361  else if(!ban)
362  {
363  if (forcedPosition.Contains(avatar.UUID))
364  avatar.ControllingClient.SendAlertMessage("You are banned from parcel, please leave by your own will");
365  forcedPosition.Remove(avatar.UUID);
366  avatar.lastKnownAllowedPosition = agentpos;
367  return false;
368  }
369  }
370 
371  if(ban)
372  {
373  if (!forcedPosition.Contains(avatar.UUID))
374  avatar.ControllingClient.SendAlertMessage(reason);
375 
376  if(zdif > -4f)
377  {
378 
379  agentpos.Z = h + 4.0f;
380  ForceAvatarToPosition(avatar, agentpos);
381  return true;
382  }
383 
384  if (land.ContainsPoint((int)avatar.lastKnownAllowedPosition.X,
385  (int) avatar.lastKnownAllowedPosition.Y))
386  {
387  Vector3? pos = m_scene.GetNearestAllowedPosition(avatar);
388  if (pos == null)
389  {
390  forcedPosition.Remove(avatar.UUID);
391  m_scene.TeleportClientHome(avatar.UUID, avatar.ControllingClient);
392  }
393  else
394  ForceAvatarToPosition(avatar, (Vector3)pos);
395  }
396  else
397  {
398  ForceAvatarToPosition(avatar, avatar.lastKnownAllowedPosition);
399  }
400  return true;
401  }
402  else
403  {
404  forcedPosition.Remove(avatar.UUID);
405  avatar.lastKnownAllowedPosition = agentpos;
406  return false;
407  }
408  }
409 
410  private void ForceAvatarToPosition(ScenePresence avatar, Vector3? position)
411  {
412  if (m_scene.Permissions.IsGod(avatar.UUID)) return;
413 
414  if (!position.HasValue)
415  return;
416 
417  if(avatar.MovingToTarget)
418  avatar.ResetMoveToTarget();
419  avatar.AbsolutePosition = position.Value;
420  avatar.lastKnownAllowedPosition = position.Value;
421  avatar.Velocity = Vector3.Zero;
422  if(avatar.IsSatOnObject)
423  avatar.StandUp();
424  forcedPosition.Add(avatar.UUID);
425  }
426 
427  public void EventManagerOnAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID)
428  {
429  if (m_scene.RegionInfo.RegionID == regionID)
430  {
431  ILandObject parcelAvatarIsEntering;
432  lock (m_landList)
433  {
434  parcelAvatarIsEntering = m_landList[localLandID];
435  }
436 
437  if (parcelAvatarIsEntering != null &&
438  avatar.currentParcelUUID != parcelAvatarIsEntering.LandData.GlobalID)
439  {
440  SendLandUpdate(avatar, parcelAvatarIsEntering);
441  avatar.currentParcelUUID = parcelAvatarIsEntering.LandData.GlobalID;
442  EnforceBans(parcelAvatarIsEntering, avatar);
443  }
444  }
445  }
446 
447  public void SendOutNearestBanLine(IClientAPI client)
448  {
449  ScenePresence sp = m_scene.GetScenePresence(client.AgentId);
450  if (sp == null || sp.IsDeleted)
451  return;
452 
453  List<ILandObject> checkLandParcels = ParcelsNearPoint(sp.AbsolutePosition);
454  foreach (ILandObject checkBan in checkLandParcels)
455  {
456  if (checkBan.IsBannedFromLand(client.AgentId))
457  {
458  checkBan.SendLandProperties((int)ParcelPropertiesStatus.CollisionBanned, false, (int)ParcelResult.Single, client);
459  return; //Only send one
460  }
461  if (checkBan.IsRestrictedFromLand(client.AgentId))
462  {
463  checkBan.SendLandProperties((int)ParcelPropertiesStatus.CollisionNotOnAccessList, false, (int)ParcelResult.Single, client);
464  return; //Only send one
465  }
466  }
467  return;
468  }
469 
470  public void sendClientInitialLandInfo(IClientAPI remoteClient)
471  {
472  ScenePresence avatar;
473 
474  if (!m_scene.TryGetScenePresence(remoteClient.AgentId, out avatar))
475  return;
476 
477  if (!avatar.IsChildAgent)
478  {
479  ILandObject over = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
480  if (over == null)
481  return;
482 
483  avatar.currentParcelUUID = over.LandData.GlobalID;
484  over.SendLandUpdateToClient(avatar.ControllingClient);
485  }
486  SendParcelOverlay(remoteClient);
487  }
488 
489  public void SendLandUpdate(ScenePresence avatar, ILandObject over)
490  {
491  if (avatar.IsChildAgent)
492  return;
493 
494  if (over != null)
495  {
496  over.SendLandUpdateToClient(avatar.ControllingClient);
497 // sl doesnt seem to send this now, as it used 2
498 // SendParcelOverlay(avatar.ControllingClient);
499  }
500  }
501 
503  {
504  if (avatar.IsChildAgent)
505  return;
506 
507  if ( m_allowedForcefulBans && m_showBansLines)
508  SendOutNearestBanLine(avatar.ControllingClient);
509  }
510 
516  {
517  if (avatar.IsChildAgent)
518  return;
519 
520  Vector3 pos = avatar.AbsolutePosition;
521  ILandObject over = GetLandObject(pos.X, pos.Y);
522  if (over != null)
523  {
524  EnforceBans(over, avatar);
525  pos = avatar.AbsolutePosition;
526  ILandObject newover = GetLandObject(pos.X, pos.Y);
527  if(over != newover || avatar.currentParcelUUID != newover.LandData.GlobalID)
528  {
529  avatar.currentParcelUUID = newover.LandData.GlobalID;
530  m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar,
531  newover.LandData.LocalID, m_scene.RegionInfo.RegionID);
532  }
533  }
534  }
535 
536  public void ClientOnParcelAccessListRequest(UUID agentID, UUID sessionID, uint flags, int sequenceID,
537  int landLocalID, IClientAPI remote_client)
538  {
540  lock (m_landList)
541  {
542  m_landList.TryGetValue(landLocalID, out land);
543  }
544 
545  if (land != null)
546  {
547  land.SendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
548  }
549  }
550 
551  public void ClientOnParcelAccessListUpdateRequest(UUID agentID,
552  uint flags, int landLocalID, UUID transactionID, int sequenceID,
553  int sections, List<LandAccessEntry> entries,
554  IClientAPI remote_client)
555  {
556  // Flags is the list to update, it can mean either the ban or
557  // the access list (WTH is a pass list? Mentioned in ParcelFlags)
558  //
559  // There may be multiple packets, because these can get LONG.
560  // Use transactionID to determine a new chain of packets since
561  // packets may have come in out of sequence and that would be
562  // a big mess if using the sequenceID
564  lock (m_landList)
565  {
566  m_landList.TryGetValue(landLocalID, out land);
567  }
568 
569  if (land != null)
570  {
571  GroupPowers requiredPowers = GroupPowers.LandManageAllowed;
572  if (flags == (uint)AccessList.Ban)
573  requiredPowers = GroupPowers.LandManageBanned;
574 
575  if (m_scene.Permissions.CanEditParcelProperties(agentID,
576  land, requiredPowers, false))
577  {
578  land.UpdateAccessList(flags, transactionID, sequenceID,
579  sections, entries, remote_client);
580  }
581  }
582  else
583  {
584  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Invalid local land ID {0}", landLocalID);
585  }
586  }
587 
596  {
597  ILandObject new_land = land.Copy();
598 
599  // Only now can we add the prim counts to the land object - we rely on the global ID which is generated
600  // as a random UUID inside LandData initialization
601  if (m_primCountModule != null)
602  new_land.PrimCounts = m_primCountModule.GetPrimCounts(new_land.LandData.GlobalID);
603 
604  lock (m_landList)
605  {
606  int newLandLocalID = m_lastLandLocalID + 1;
607  new_land.LandData.LocalID = newLandLocalID;
608 
609  bool[,] landBitmap = new_land.GetLandBitmap();
610  if (landBitmap.GetLength(0) != m_landIDList.GetLength(0) || landBitmap.GetLength(1) != m_landIDList.GetLength(1))
611  {
612  // Going to variable sized regions can cause mismatches
613  m_log.ErrorFormat("{0} AddLandObject. Added land bitmap different size than region ID map. bitmapSize=({1},{2}), landIDSize=({3},{4})",
614  LogHeader, landBitmap.GetLength(0), landBitmap.GetLength(1), m_landIDList.GetLength(0), m_landIDList.GetLength(1));
615  }
616  else
617  {
618  // If other land objects still believe that they occupy any parts of the same space,
619  // then do not allow the add to proceed.
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  int lastRecordedLandId = m_landIDList[x, y];
627 
628  if (lastRecordedLandId > 0)
629  {
630  ILandObject lastRecordedLo = m_landList[lastRecordedLandId];
631 
632  if (lastRecordedLo.LandBitmap[x, y])
633  {
634  m_log.ErrorFormat(
635  "{0}: Cannot add parcel \"{1}\", local ID {2} at tile {3},{4} because this is still occupied by parcel \"{5}\", local ID {6} in {7}",
636  LogHeader, new_land.LandData.Name, new_land.LandData.LocalID, x, y,
637  lastRecordedLo.LandData.Name, lastRecordedLo.LandData.LocalID, m_scene.Name);
638 
639  return null;
640  }
641  }
642  }
643  }
644  }
645 
646  for (int x = 0; x < landBitmap.GetLength(0); x++)
647  {
648  for (int y = 0; y < landBitmap.GetLength(1); y++)
649  {
650  if (landBitmap[x, y])
651  {
652  // m_log.DebugFormat(
653  // "[LAND MANAGEMENT MODULE]: Registering parcel {0} for land co-ord ({1}, {2}) on {3}",
654  // new_land.LandData.Name, x, y, m_scene.RegionInfo.RegionName);
655 
656  m_landIDList[x, y] = newLandLocalID;
657  }
658  }
659  }
660  }
661 
662  m_landList.Add(newLandLocalID, new_land);
663  m_lastLandLocalID++;
664  }
665 
666  new_land.ForceUpdateLandInfo();
667  m_scene.EventManager.TriggerLandObjectAdded(new_land);
668 
669  return new_land;
670  }
671 
676  public void removeLandObject(int local_id)
677  {
679  lock (m_landList)
680  {
681  for (int x = 0; x < m_landIDList.GetLength(0); x++)
682  {
683  for (int y = 0; y < m_landIDList.GetLength(1); y++)
684  {
685  if (m_landIDList[x, y] == local_id)
686  {
687  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Not removing land object {0}; still being used at {1}, {2}",
688  local_id, x, y);
689  return;
690  //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
691  }
692  }
693  }
694 
695  land = m_landList[local_id];
696  m_landList.Remove(local_id);
697  }
698 
699  m_scene.EventManager.TriggerLandObjectRemoved(land.LandData.GlobalID);
700  }
701 
705  public void Clear(bool setupDefaultParcel)
706  {
707  Dictionary<int, ILandObject> landworkList;
708  // move to work pointer since we are deleting it all
709  lock (m_landList)
710  {
711  landworkList = m_landList;
712  m_landList = new Dictionary<int, ILandObject>();
713  }
714 
715  // this 2 methods have locks (now)
716  ResetSimLandObjects();
717 
718  if (setupDefaultParcel)
719  CreateDefaultParcel();
720 
721  // fire outside events unlocked
722  foreach (ILandObject lo in landworkList.Values)
723  {
724  //m_scene.SimulationDataService.RemoveLandObject(lo.LandData.GlobalID);
725  m_scene.EventManager.TriggerLandObjectRemoved(lo.LandData.GlobalID);
726  }
727  landworkList.Clear();
728 
729  }
730 
731  private void performFinalLandJoin(ILandObject master, ILandObject slave)
732  {
733  bool[,] landBitmapSlave = slave.GetLandBitmap();
734  lock (m_landList)
735  {
736  for (int x = 0; x < landBitmapSlave.GetLength(0); x++)
737  {
738  for (int y = 0; y < landBitmapSlave.GetLength(1); y++)
739  {
740  if (landBitmapSlave[x, y])
741  {
742  m_landIDList[x, y] = master.LandData.LocalID;
743  }
744  }
745  }
746  }
747 
748  removeLandObject(slave.LandData.LocalID);
749  UpdateLandObject(master.LandData.LocalID, master.LandData);
750  }
751 
752  public ILandObject GetLandObject(int parcelLocalID)
753  {
754  lock (m_landList)
755  {
756  if (m_landList.ContainsKey(parcelLocalID))
757  {
758  return m_landList[parcelLocalID];
759  }
760  }
761  return null;
762  }
763 
770  public ILandObject GetLandObject(float x_float, float y_float)
771  {
772  return GetLandObject((int)x_float, (int)y_float, true);
773  }
774 
775  // if x,y is off region this will return the parcel at cliped x,y
776  // as did code it replaces
777  public ILandObject GetLandObjectClipedXY(float x, float y)
778  {
779  //do clip inline
780  int avx = (int)x;
781  if (avx < 0)
782  avx = 0;
783  else if (avx >= m_scene.RegionInfo.RegionSizeX)
784  avx = (int)Constants.RegionSize - 1;
785 
786  int avy = (int)y;
787  if (avy < 0)
788  avy = 0;
789  else if (avy >= m_scene.RegionInfo.RegionSizeY)
790  avy = (int)Constants.RegionSize - 1;
791 
792  lock (m_landIDList)
793  {
794  try
795  {
796  return m_landList[m_landIDList[avx / LandUnit, avy / LandUnit]];
797  }
798  catch (IndexOutOfRangeException)
799  {
800  return null;
801  }
802  }
803  }
804 
805  // Public entry.
806  // Throws exception if land object is not found
807  public ILandObject GetLandObject(int x, int y)
808  {
809  return GetLandObject(x, y, false /* returnNullIfLandObjectNotFound */);
810  }
811 
812  public ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds)
813  {
814  if (x >= m_scene.RegionInfo.RegionSizeX || y >= m_scene.RegionInfo.RegionSizeY || x < 0 || y < 0)
815  {
816  // These exceptions here will cause a lot of complaints from the users specifically because
817  // they happen every time at border crossings
818  if (returnNullIfLandObjectOutsideBounds)
819  return null;
820  else
821  throw new Exception("Error: Parcel not found at point " + x + ", " + y);
822  }
823 
824  lock (m_landIDList)
825  {
826  try
827  {
828  return m_landList[m_landIDList[x / 4, y / 4]];
829  }
830  catch (IndexOutOfRangeException)
831  {
832  return null;
833  }
834  }
835 
836  return m_landList[m_landIDList[x / 4, y / 4]];
837  }
838 
839  // Create a 'parcel is here' bitmap for the parcel identified by the passed landID
840  private bool[,] CreateBitmapForID(int landID)
841  {
842  bool[,] ret = new bool[m_landIDList.GetLength(0), m_landIDList.GetLength(1)];
843 
844  for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
845  for (int yy = 0; yy < m_landIDList.GetLength(0); yy++)
846  if (m_landIDList[xx, yy] == landID)
847  ret[xx, yy] = true;
848 
849  return ret;
850  }
851 
852  #endregion
853 
854  #region Parcel Modification
855 
856  public void ResetOverMeRecords()
857  {
858  lock (m_landList)
859  {
860  foreach (LandObject p in m_landList.Values)
861  {
862  p.ResetOverMeRecord();
863  }
864  }
865  }
866 
868  {
869  Vector3 position = obj.AbsolutePosition;
870  ILandObject landUnderPrim = GetLandObject(position.X, position.Y);
871  if (landUnderPrim != null)
872  {
873  ((LandObject)landUnderPrim).AddPrimOverMe(obj);
874  }
875  }
876 
878  {
879  lock (m_landList)
880  {
881  foreach (LandObject p in m_landList.Values)
882  {
883  p.RemovePrimFromOverMe(obj);
884  }
885  }
886  }
887 
889  {
890  //Get Simwide prim count for owner
891  Dictionary<UUID, List<LandObject>> landOwnersAndParcels = new Dictionary<UUID, List<LandObject>>();
892  lock (m_landList)
893  {
894  foreach (LandObject p in m_landList.Values)
895  {
896  if (!landOwnersAndParcels.ContainsKey(p.LandData.OwnerID))
897  {
898  List<LandObject> tempList = new List<LandObject>();
899  tempList.Add(p);
900  landOwnersAndParcels.Add(p.LandData.OwnerID, tempList);
901  }
902  else
903  {
904  landOwnersAndParcels[p.LandData.OwnerID].Add(p);
905  }
906  }
907  }
908 
909  foreach (UUID owner in landOwnersAndParcels.Keys)
910  {
911  int simArea = 0;
912  int simPrims = 0;
913  foreach (LandObject p in landOwnersAndParcels[owner])
914  {
915  simArea += p.LandData.Area;
916  simPrims += p.PrimCounts.Total;
917  }
918 
919  foreach (LandObject p in landOwnersAndParcels[owner])
920  {
921  p.LandData.SimwideArea = simArea;
922  p.LandData.SimwidePrims = simPrims;
923  }
924  }
925  }
926 
928  {
929 // m_log.DebugFormat(
930 // "[LAND MANAGEMENT MODULE]: Triggered EventManagerOnParcelPrimCountUpdate() for {0}",
931 // m_scene.RegionInfo.RegionName);
932 
933  ResetOverMeRecords();
934  EntityBase[] entities = m_scene.Entities.GetEntities();
935  foreach (EntityBase obj in entities)
936  {
937  if (obj != null)
938  {
939  if ((obj is SceneObjectGroup) && !obj.IsDeleted && !((SceneObjectGroup) obj).IsAttachment)
940  {
941  m_scene.EventManager.TriggerParcelPrimCountAdd((SceneObjectGroup) obj);
942  }
943  }
944  }
945  FinalizeLandPrimCountUpdate();
946  }
947 
949  {
950  ResetOverMeRecords();
951  m_scene.EventManager.TriggerParcelPrimCountUpdate();
952  FinalizeLandPrimCountUpdate();
953  }
954 
964  public void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
965  {
966  //First, lets loop through the points and make sure they are all in the same peice of land
967  //Get the land object at start
968 
969  ILandObject startLandObject = GetLandObject(start_x, start_y);
970 
971  if (startLandObject == null)
972  return;
973 
974  if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, startLandObject, GroupPowers.LandDivideJoin, true))
975  {
976  return;
977  }
978 
979  //Loop through the points
980  try
981  {
982  for (int y = start_y; y < end_y; y++)
983  {
984  for (int x = start_x; x < end_x; x++)
985  {
986  ILandObject tempLandObject = GetLandObject(x, y);
987  if (tempLandObject == null)
988  return;
989  if (tempLandObject != startLandObject)
990  return;
991  }
992  }
993  }
994  catch (Exception)
995  {
996  return;
997  }
998 
999  //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
1000  ILandObject newLand = startLandObject.Copy();
1001 
1002  newLand.LandData.Name = newLand.LandData.Name;
1003  newLand.LandData.GlobalID = UUID.Random();
1004  newLand.LandData.Dwell = 0;
1005  // Clear "Show in search" on the cut out parcel to prevent double-charging
1006  newLand.LandData.Flags &= ~(uint)ParcelFlags.ShowDirectory;
1007  // invalidate landing point
1008  newLand.LandData.LandingType = (byte)LandingType.Direct;
1009  newLand.LandData.UserLocation = Vector3.Zero;
1010  newLand.LandData.UserLookAt = Vector3.Zero;
1011 
1012  newLand.SetLandBitmap(newLand.GetSquareLandBitmap(start_x, start_y, end_x, end_y));
1013 
1014  //lets set the subdivision area of the original to false
1015  int startLandObjectIndex = startLandObject.LandData.LocalID;
1016  lock (m_landList)
1017  {
1018  m_landList[startLandObjectIndex].SetLandBitmap(
1019  newLand.ModifyLandBitmapSquare(startLandObject.GetLandBitmap(), start_x, start_y, end_x, end_y, false));
1020  m_landList[startLandObjectIndex].ForceUpdateLandInfo();
1021  }
1022 
1023  //add the new land object
1024  ILandObject result = AddLandObject(newLand);
1025 
1026  UpdateLandObject(startLandObject.LandData.LocalID, startLandObject.LandData);
1027 
1028  if(startLandObject.LandData.LandingType == (byte)LandingType.LandingPoint)
1029  {
1030  int x = (int)startLandObject.LandData.UserLocation.X;
1031  int y = (int)startLandObject.LandData.UserLocation.Y;
1032  if(!startLandObject.ContainsPoint(x, y))
1033  {
1034  startLandObject.LandData.LandingType = (byte)LandingType.Direct;
1035  startLandObject.LandData.UserLocation = Vector3.Zero;
1036  startLandObject.LandData.UserLookAt = Vector3.Zero;
1037  }
1038  }
1039 
1040  m_scene.EventManager.TriggerParcelPrimCountTainted();
1041 
1042  result.SendLandUpdateToAvatarsOverMe();
1043  startLandObject.SendLandUpdateToAvatarsOverMe();
1044  m_scene.ForEachClient(SendParcelOverlay);
1045 
1046  }
1047 
1057  public void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
1058  {
1059  int index = 0;
1060  int maxindex = -1;
1061  int maxArea = 0;
1062 
1063  List<ILandObject> selectedLandObjects = new List<ILandObject>();
1064  for (int x = start_x; x < end_x; x += 4)
1065  {
1066  for (int y = start_y; y < end_y; y += 4)
1067  {
1068  ILandObject p = GetLandObject(x, y);
1069 
1070  if (p != null)
1071  {
1072  if (!selectedLandObjects.Contains(p))
1073  {
1074  selectedLandObjects.Add(p);
1075  if(p.LandData.Area > maxArea)
1076  {
1077  maxArea = p.LandData.Area;
1078  maxindex = index;
1079  }
1080  index++;
1081  }
1082  }
1083  }
1084  }
1085 
1086  if(maxindex < 0 || selectedLandObjects.Count < 2)
1087  return;
1088 
1089  ILandObject masterLandObject = selectedLandObjects[maxindex];
1090  selectedLandObjects.RemoveAt(maxindex);
1091 
1092  if (!m_scene.Permissions.CanEditParcelProperties(attempting_user_id, masterLandObject, GroupPowers.LandDivideJoin, true))
1093  {
1094  return;
1095  }
1096 
1097  UUID masterOwner = masterLandObject.LandData.OwnerID;
1098  foreach (ILandObject p in selectedLandObjects)
1099  {
1100  if (p.LandData.OwnerID != masterOwner)
1101  return;
1102  }
1103 
1104  lock (m_landList)
1105  {
1106  foreach (ILandObject slaveLandObject in selectedLandObjects)
1107  {
1108  m_landList[masterLandObject.LandData.LocalID].SetLandBitmap(
1109  slaveLandObject.MergeLandBitmaps(masterLandObject.GetLandBitmap(), slaveLandObject.GetLandBitmap()));
1110  performFinalLandJoin(masterLandObject, slaveLandObject);
1111  }
1112  }
1113 
1114  m_scene.EventManager.TriggerParcelPrimCountTainted();
1115  masterLandObject.SendLandUpdateToAvatarsOverMe();
1116  m_scene.ForEachClient(SendParcelOverlay);
1117  }
1118  #endregion
1119 
1120  #region Parcel Updating
1121 
1135  public void SendParcelOverlay(IClientAPI remote_client)
1136  {
1137  if (remote_client.SceneAgent.PresenceType == PresenceType.Npc)
1138  return;
1139 
1140  const int LAND_BLOCKS_PER_PACKET = 1024;
1141 
1142  byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1143  int byteArrayCount = 0;
1144  int sequenceID = 0;
1145 
1146  // Layer data is in LandUnit (4m) chunks
1147  for (int y = 0; y < m_scene.RegionInfo.RegionSizeY; y += LandUnit)
1148  {
1149  for (int x = 0; x < m_scene.RegionInfo.RegionSizeX; x += LandUnit)
1150  {
1151  byte tempByte = 0; //This represents the byte for the current 4x4
1152 
1153  ILandObject currentParcelBlock = GetLandObject(x, y);
1154 
1155  if (currentParcelBlock != null)
1156  {
1157  // types
1158  if (currentParcelBlock.LandData.OwnerID == remote_client.AgentId)
1159  {
1160  //Owner Flag
1161  tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_REQUESTER;
1162  }
1163  else if (currentParcelBlock.LandData.IsGroupOwned && remote_client.IsGroupMember(currentParcelBlock.LandData.GroupID))
1164  {
1165  tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_GROUP;
1166  }
1167  else if (currentParcelBlock.LandData.SalePrice > 0 &&
1168  (currentParcelBlock.LandData.AuthBuyerID == UUID.Zero ||
1169  currentParcelBlock.LandData.AuthBuyerID == remote_client.AgentId))
1170  {
1171  //Sale type
1172  tempByte = (byte)LandChannel.LAND_TYPE_IS_FOR_SALE;
1173  }
1174  else if (currentParcelBlock.LandData.OwnerID == UUID.Zero)
1175  {
1176  //Public type
1177  tempByte = (byte)LandChannel.LAND_TYPE_PUBLIC; // this does nothing, its zero
1178  }
1179  // LAND_TYPE_IS_BEING_AUCTIONED still unsuported
1180  else
1181  {
1182  //Other Flag
1183  tempByte = (byte)LandChannel.LAND_TYPE_OWNED_BY_OTHER;
1184  }
1185 
1186  // now flags
1187  // border control
1188 
1189  ILandObject westParcel = null;
1190  ILandObject southParcel = null;
1191  if (x > 0)
1192  {
1193  westParcel = GetLandObject((x - 1), y);
1194  }
1195  if (y > 0)
1196  {
1197  southParcel = GetLandObject(x, (y - 1));
1198  }
1199 
1200  if (x == 0)
1201  {
1202  tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST;
1203  }
1204  else if (westParcel != null && westParcel != currentParcelBlock)
1205  {
1206  tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_WEST;
1207  }
1208 
1209  if (y == 0)
1210  {
1211  tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH;
1212  }
1213  else if (southParcel != null && southParcel != currentParcelBlock)
1214  {
1215  tempByte |= (byte)LandChannel.LAND_FLAG_PROPERTY_BORDER_SOUTH;
1216  }
1217 
1218  // local sound
1219  if ((currentParcelBlock.LandData.Flags & (uint)ParcelFlags.SoundLocal) != 0)
1220  tempByte |= (byte)LandChannel.LAND_FLAG_LOCALSOUND;
1221 
1222  // hide avatars
1223  if (!currentParcelBlock.LandData.SeeAVs)
1224  tempByte |= (byte)LandChannel.LAND_FLAG_HIDEAVATARS;
1225 
1226 
1227  byteArray[byteArrayCount] = tempByte;
1228  byteArrayCount++;
1229  if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
1230  {
1231  remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1232  byteArrayCount = 0;
1233  sequenceID++;
1234  byteArray = new byte[LAND_BLOCKS_PER_PACKET];
1235  }
1236  }
1237  }
1238  }
1239 
1240  if (byteArrayCount > 0)
1241  {
1242  remote_client.SendLandParcelOverlay(byteArray, sequenceID);
1243  }
1244  }
1245 
1246  public void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
1247  bool snap_selection, IClientAPI remote_client)
1248  {
1249  //Get the land objects within the bounds
1250  List<ILandObject> temp = new List<ILandObject>();
1251  int inc_x = end_x - start_x;
1252  int inc_y = end_y - start_y;
1253  for (int x = 0; x < inc_x; x++)
1254  {
1255  for (int y = 0; y < inc_y; y++)
1256  {
1257  ILandObject currentParcel = GetLandObject(start_x + x, start_y + y);
1258 
1259  if (currentParcel != null)
1260  {
1261  if (!temp.Contains(currentParcel))
1262  {
1263  if (!currentParcel.IsEitherBannedOrRestricted(remote_client.AgentId))
1264  {
1265  currentParcel.ForceUpdateLandInfo();
1266  temp.Add(currentParcel);
1267  }
1268  }
1269  }
1270  }
1271  }
1272 
1273  int requestResult = LandChannel.LAND_RESULT_SINGLE;
1274  if (temp.Count > 1)
1275  {
1276  requestResult = LandChannel.LAND_RESULT_MULTIPLE;
1277  }
1278 
1279  for (int i = 0; i < temp.Count; i++)
1280  {
1281  temp[i].SendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
1282  }
1283 
1284 // SendParcelOverlay(remote_client);
1285  }
1286 
1287  public void UpdateLandProperties(ILandObject land, LandUpdateArgs args, IClientAPI remote_client)
1288  {
1289  bool snap_selection = false;
1290  bool needOverlay = false;
1291  if (land.UpdateLandProperties(args, remote_client, out snap_selection, out needOverlay))
1292  {
1293  //the proprieties to who changed them
1294  ScenePresence av = m_scene.GetScenePresence(remote_client.AgentId);
1295  if(av.IsChildAgent || land != GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y))
1296  land.SendLandProperties(-10000, false, LandChannel.LAND_RESULT_SINGLE, remote_client);
1297  else
1298  land.SendLandProperties(0, false, LandChannel.LAND_RESULT_SINGLE, remote_client);
1299 
1300  UUID parcelID = land.LandData.GlobalID;
1301  m_scene.ForEachScenePresence(delegate(ScenePresence avatar)
1302  {
1303  if (avatar.IsDeleted || avatar.isNPC)
1304  return;
1305 
1306  IClientAPI client = avatar.ControllingClient;
1307  if (needOverlay)
1308  SendParcelOverlay(client);
1309 
1310  if (avatar.IsChildAgent)
1311  return;
1312 
1313  ILandObject aland = GetLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
1314  if (aland != null)
1315  {
1316  if (client != remote_client && land == aland)
1317  aland.SendLandProperties(0, false, LandChannel.LAND_RESULT_SINGLE, client);
1318  }
1319  if (avatar.currentParcelUUID == parcelID)
1320  avatar.currentParcelUUID = parcelID; // force parcel flags review
1321  });
1322  }
1323  }
1324 
1325  public void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
1326  {
1327  ILandObject land;
1328  lock (m_landList)
1329  {
1330  m_landList.TryGetValue(localID, out land);
1331  }
1332 
1333  if (land != null)
1334  {
1335  UpdateLandProperties(land, args, remote_client);
1336  m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(args, localID, remote_client);
1337  }
1338  }
1339 
1340  public void ClientOnParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
1341  {
1342  Subdivide(west, south, east, north, remote_client.AgentId);
1343  }
1344 
1345  public void ClientOnParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
1346  {
1347  Join(west, south, east, north, remote_client.AgentId);
1348  }
1349 
1350  public void ClientOnParcelSelectObjects(int local_id, int request_type,
1351  List<UUID> returnIDs, IClientAPI remote_client)
1352  {
1353  m_landList[local_id].SendForceObjectSelect(local_id, request_type, returnIDs, remote_client);
1354  }
1355 
1356  public void ClientOnParcelObjectOwnerRequest(int local_id, IClientAPI remote_client)
1357  {
1358  ILandObject land;
1359  lock (m_landList)
1360  {
1361  m_landList.TryGetValue(local_id, out land);
1362  }
1363 
1364  if (land != null)
1365  {
1366  m_scene.EventManager.TriggerParcelPrimCountUpdate();
1367  m_landList[local_id].SendLandObjectOwners(remote_client);
1368  }
1369  else
1370  {
1371  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Invalid land object {0} passed for parcel object owner request", local_id);
1372  }
1373  }
1374 
1375  public void ClientOnParcelGodForceOwner(int local_id, UUID ownerID, IClientAPI remote_client)
1376  {
1377  ILandObject land;
1378  lock (m_landList)
1379  {
1380  m_landList.TryGetValue(local_id, out land);
1381  }
1382 
1383  if (land != null)
1384  {
1385  if (m_scene.Permissions.IsGod(remote_client.AgentId))
1386  {
1387  land.LandData.OwnerID = ownerID;
1388  land.LandData.GroupID = UUID.Zero;
1389  land.LandData.IsGroupOwned = false;
1390  land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1391  m_scene.ForEachClient(SendParcelOverlay);
1392  land.SendLandUpdateToClient(true, remote_client);
1393  UpdateLandObject(land.LandData.LocalID, land.LandData);
1394  }
1395  }
1396  }
1397 
1398  public void ClientOnParcelAbandonRequest(int local_id, IClientAPI remote_client)
1399  {
1400  ILandObject land;
1401  lock (m_landList)
1402  {
1403  m_landList.TryGetValue(local_id, out land);
1404  }
1405 
1406  if (land != null)
1407  {
1408  if (m_scene.Permissions.CanAbandonParcel(remote_client.AgentId, land))
1409  {
1410  land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1411  land.LandData.GroupID = UUID.Zero;
1412  land.LandData.IsGroupOwned = false;
1413  land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1414 
1415  m_scene.ForEachClient(SendParcelOverlay);
1416  land.SendLandUpdateToClient(true, remote_client);
1417  UpdateLandObject(land.LandData.LocalID, land.LandData);
1418  }
1419  }
1420  }
1421 
1422  public void ClientOnParcelReclaim(int local_id, IClientAPI remote_client)
1423  {
1424  ILandObject land;
1425  lock (m_landList)
1426  {
1427  m_landList.TryGetValue(local_id, out land);
1428  }
1429 
1430  if (land != null)
1431  {
1432  if (m_scene.Permissions.CanReclaimParcel(remote_client.AgentId, land))
1433  {
1434  land.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1435  land.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
1436  land.LandData.GroupID = UUID.Zero;
1437  land.LandData.IsGroupOwned = false;
1438  land.LandData.SalePrice = 0;
1439  land.LandData.AuthBuyerID = UUID.Zero;
1440  land.LandData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
1441  m_scene.ForEachClient(SendParcelOverlay);
1442  land.SendLandUpdateToClient(true, remote_client);
1443  UpdateLandObject(land.LandData.LocalID, land.LandData);
1444  }
1445  }
1446  }
1447  #endregion
1448 
1449  // If the economy has been validated by the economy module,
1450  // and land has been validated as well, this method transfers
1451  // the land ownership
1452 
1453  public void EventManagerOnLandBuy(Object o, EventManager.LandBuyArgs e)
1454  {
1455  if (e.economyValidated && e.landValidated)
1456  {
1457  ILandObject land;
1458  lock (m_landList)
1459  {
1460  m_landList.TryGetValue(e.parcelLocalID, out land);
1461  }
1462 
1463  if (land != null)
1464  {
1465  land.UpdateLandSold(e.agentId, e.groupId, e.groupOwned, (uint)e.transactionID, e.parcelPrice, e.parcelArea);
1466  }
1467  }
1468  }
1469 
1470  // After receiving a land buy packet, first the data needs to
1471  // be validated. This method validates the right to buy the
1472  // parcel
1473 
1474  public void EventManagerOnValidateLandBuy(Object o, EventManager.LandBuyArgs e)
1475  {
1476  if (e.landValidated == false)
1477  {
1478  ILandObject lob = null;
1479  lock (m_landList)
1480  {
1481  m_landList.TryGetValue(e.parcelLocalID, out lob);
1482  }
1483 
1484  if (lob != null)
1485  {
1486  UUID AuthorizedID = lob.LandData.AuthBuyerID;
1487  int saleprice = lob.LandData.SalePrice;
1488  UUID pOwnerID = lob.LandData.OwnerID;
1489 
1490  bool landforsale = ((lob.LandData.Flags &
1491  (uint)(ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects)) != 0);
1492  if ((AuthorizedID == UUID.Zero || AuthorizedID == e.agentId) && e.parcelPrice >= saleprice && landforsale)
1493  {
1494  // TODO I don't think we have to lock it here, no?
1495  //lock (e)
1496  //{
1497  e.parcelOwnerID = pOwnerID;
1498  e.landValidated = true;
1499  //}
1500  }
1501  }
1502  }
1503  }
1504 
1505  void ClientOnParcelDeedToGroup(int parcelLocalID, UUID groupID, IClientAPI remote_client)
1506  {
1507  ILandObject land;
1508  lock (m_landList)
1509  {
1510  m_landList.TryGetValue(parcelLocalID, out land);
1511  }
1512 
1513  if (!m_scene.Permissions.CanDeedParcel(remote_client.AgentId, land))
1514  return;
1515 
1516  if (land != null)
1517  {
1518  land.DeedToGroup(groupID);
1519  }
1520  }
1521 
1522  #region Land Object From Storage Functions
1523 
1524  private void EventManagerOnIncomingLandDataFromStorage(List<LandData> data)
1525  {
1526  lock (m_landList)
1527  {
1528  for (int i = 0; i < data.Count; i++)
1529  IncomingLandObjectFromStorage(data[i]);
1530 
1531  // Layer data is in LandUnit (4m) chunks
1532  for (int y = 0; y < m_scene.RegionInfo.RegionSizeY / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); y++)
1533  {
1534  for (int x = 0; x < m_scene.RegionInfo.RegionSizeX / Constants.TerrainPatchSize * (Constants.TerrainPatchSize / LandUnit); x++)
1535  {
1536  if (m_landIDList[x, y] == 0)
1537  {
1538  if (m_landList.Count == 1)
1539  {
1540  m_log.DebugFormat(
1541  "[{0}]: Auto-extending land parcel as landID at {1},{2} is 0 and only one land parcel is present in {3}",
1542  LogHeader, x, y, m_scene.Name);
1543 
1544  int onlyParcelID = 0;
1545  ILandObject onlyLandObject = null;
1546  foreach (KeyValuePair<int, ILandObject> kvp in m_landList)
1547  {
1548  onlyParcelID = kvp.Key;
1549  onlyLandObject = kvp.Value;
1550  break;
1551  }
1552 
1553  // There is only one parcel. Grow it to fill all the unallocated spaces.
1554  for (int xx = 0; xx < m_landIDList.GetLength(0); xx++)
1555  for (int yy = 0; yy < m_landIDList.GetLength(1); yy++)
1556  if (m_landIDList[xx, yy] == 0)
1557  m_landIDList[xx, yy] = onlyParcelID;
1558 
1559  onlyLandObject.LandBitmap = CreateBitmapForID(onlyParcelID);
1560  }
1561  else if (m_landList.Count > 1)
1562  {
1563  m_log.DebugFormat(
1564  "{0}: Auto-creating land parcel as landID at {1},{2} is 0 and more than one land parcel is present in {3}",
1565  LogHeader, x, y, m_scene.Name);
1566 
1567  // There are several other parcels so we must create a new one for the unassigned space
1568  ILandObject newLand = new LandObject(UUID.Zero, false, m_scene);
1569  // Claim all the unclaimed "0" ids
1570  newLand.SetLandBitmap(CreateBitmapForID(0));
1571  newLand.LandData.OwnerID = m_scene.RegionInfo.EstateSettings.EstateOwner;
1572  newLand.LandData.ClaimDate = Util.UnixTimeSinceEpoch();
1573  newLand = AddLandObject(newLand);
1574  }
1575  else
1576  {
1577  // We should never reach this point as the separate code path when no land data exists should have fired instead.
1578  m_log.WarnFormat(
1579  "{0}: Ignoring request to auto-create parcel in {1} as there are no other parcels present",
1580  LogHeader, m_scene.Name);
1581  }
1582  }
1583  }
1584  }
1585  }
1586  }
1587 
1588  private void IncomingLandObjectFromStorage(LandData data)
1589  {
1590  ILandObject new_land = new LandObject(data.OwnerID, data.IsGroupOwned, m_scene);
1591  new_land.LandData = data.Copy();
1592 
1593  new_land.SetLandBitmapFromByteArray();
1594  AddLandObject(new_land);
1595 // new_land.SendLandUpdateToAvatarsOverMe();
1596  }
1597 
1598  public void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
1599  {
1600  if (localID != -1)
1601  {
1602  ILandObject selectedParcel = null;
1603  lock (m_landList)
1604  {
1605  m_landList.TryGetValue(localID, out selectedParcel);
1606  }
1607 
1608  if (selectedParcel == null)
1609  return;
1610 
1611  selectedParcel.ReturnLandObjects(returnType, agentIDs, taskIDs, remoteClient);
1612  }
1613  else
1614  {
1615  if (returnType != 1)
1616  {
1617  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown return type {0}", returnType);
1618  return;
1619  }
1620 
1621  // We get here when the user returns objects from the list of Top Colliders or Top Scripts.
1622  // In that case we receive specific object UUID's, but no parcel ID.
1623 
1624  Dictionary<UUID, HashSet<SceneObjectGroup>> returns = new Dictionary<UUID, HashSet<SceneObjectGroup>>();
1625 
1626  foreach (UUID groupID in taskIDs)
1627  {
1628  SceneObjectGroup obj = m_scene.GetSceneObjectGroup(groupID);
1629  if (obj != null)
1630  {
1631  if (!returns.ContainsKey(obj.OwnerID))
1632  returns[obj.OwnerID] = new HashSet<SceneObjectGroup>();
1633  returns[obj.OwnerID].Add(obj);
1634  }
1635  else
1636  {
1637  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: unknown object {0}", groupID);
1638  }
1639  }
1640 
1641  int num = 0;
1642  foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1643  num += objs.Count;
1644  m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Returning {0} specific object(s)", num);
1645 
1646  foreach (HashSet<SceneObjectGroup> objs in returns.Values)
1647  {
1648  List<SceneObjectGroup> objs2 = new List<SceneObjectGroup>(objs);
1649  if (m_scene.Permissions.CanReturnObjects(null, remoteClient.AgentId, objs2))
1650  {
1651  m_scene.returnObjects(objs2.ToArray(), remoteClient.AgentId);
1652  }
1653  else
1654  {
1655  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: ReturnObjectsInParcel: not permitted to return {0} object(s) belonging to user {1}",
1656  objs2.Count, objs2[0].OwnerID);
1657  }
1658  }
1659  }
1660  }
1661 
1663  {
1664  ResetSimLandObjects();
1665  CreateDefaultParcel();
1666  }
1667 
1668  #endregion
1669 
1671  {
1672  lock (m_landList)
1673  {
1674  foreach (LandObject obj in m_landList.Values)
1675  {
1676  obj.SetParcelObjectMaxOverride(overrideDel);
1677  }
1678  }
1679  }
1680 
1682  {
1683  }
1684 
1685  #region CAPS handler
1686 
1687  private void EventManagerOnRegisterCaps(UUID agentID, Caps caps)
1688  {
1689  string capsBase = "/CAPS/" + caps.CapsObjectPath;
1690  caps.RegisterHandler(
1691  "RemoteParcelRequest",
1692  new RestStreamHandler(
1693  "POST",
1694  capsBase + remoteParcelRequestPath,
1695  (request, path, param, httpRequest, httpResponse)
1696  => RemoteParcelRequest(request, path, param, agentID, caps),
1697  "RemoteParcelRequest",
1698  agentID.ToString()));
1699 
1700  UUID parcelCapID = UUID.Random();
1701  caps.RegisterHandler(
1702  "ParcelPropertiesUpdate",
1703  new RestStreamHandler(
1704  "POST",
1705  "/CAPS/" + parcelCapID,
1706  (request, path, param, httpRequest, httpResponse)
1707  => ProcessPropertiesUpdate(request, path, param, agentID, caps),
1708  "ParcelPropertiesUpdate",
1709  agentID.ToString()));
1710  }
1711  private string ProcessPropertiesUpdate(string request, string path, string param, UUID agentID, Caps caps)
1712  {
1713  IClientAPI client;
1714  if (!m_scene.TryGetClient(agentID, out client))
1715  {
1716  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to retrieve IClientAPI for {0}", agentID);
1717  return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty());
1718  }
1719 
1720  ParcelPropertiesUpdateMessage properties = new ParcelPropertiesUpdateMessage();
1721  OpenMetaverse.StructuredData.OSDMap args = (OpenMetaverse.StructuredData.OSDMap) OSDParser.DeserializeLLSDXml(request);
1722 
1723  properties.Deserialize(args);
1724 
1725  LandUpdateArgs land_update = new LandUpdateArgs();
1726  int parcelID = properties.LocalID;
1727  land_update.AuthBuyerID = properties.AuthBuyerID;
1728  land_update.Category = properties.Category;
1729  land_update.Desc = properties.Desc;
1730  land_update.GroupID = properties.GroupID;
1731  land_update.LandingType = (byte) properties.Landing;
1732  land_update.MediaAutoScale = (byte) Convert.ToInt32(properties.MediaAutoScale);
1733  land_update.MediaID = properties.MediaID;
1734  land_update.MediaURL = properties.MediaURL;
1735  land_update.MusicURL = properties.MusicURL;
1736  land_update.Name = properties.Name;
1737  land_update.ParcelFlags = (uint) properties.ParcelFlags;
1738  land_update.PassHours = (int) properties.PassHours;
1739  land_update.PassPrice = (int) properties.PassPrice;
1740  land_update.SalePrice = (int) properties.SalePrice;
1741  land_update.SnapshotID = properties.SnapshotID;
1742  land_update.UserLocation = properties.UserLocation;
1743  land_update.UserLookAt = properties.UserLookAt;
1744  land_update.MediaDescription = properties.MediaDesc;
1745  land_update.MediaType = properties.MediaType;
1746  land_update.MediaWidth = properties.MediaWidth;
1747  land_update.MediaHeight = properties.MediaHeight;
1748  land_update.MediaLoop = properties.MediaLoop;
1749  land_update.ObscureMusic = properties.ObscureMusic;
1750  land_update.ObscureMedia = properties.ObscureMedia;
1751 
1752  if (args.ContainsKey("see_avs"))
1753  {
1754  land_update.SeeAVs = args["see_avs"].AsBoolean();
1755  land_update.AnyAVSounds = args["any_av_sounds"].AsBoolean();
1756  land_update.GroupAVSounds = args["group_av_sounds"].AsBoolean();
1757  }
1758  else
1759  {
1760  land_update.SeeAVs = true;
1761  land_update.AnyAVSounds = true;
1762  land_update.GroupAVSounds = true;
1763  }
1764 
1765  ILandObject land;
1766  lock (m_landList)
1767  {
1768  m_landList.TryGetValue(parcelID, out land);
1769  }
1770 
1771  if (land != null)
1772  {
1773  UpdateLandProperties(land,land_update, client);
1774  m_scene.EventManager.TriggerOnParcelPropertiesUpdateRequest(land_update, parcelID, client);
1775  }
1776  else
1777  {
1778  m_log.WarnFormat("[LAND MANAGEMENT MODULE]: Unable to find parcelID {0}", parcelID);
1779  }
1780 
1781  return LLSDHelpers.SerialiseLLSDReply(new LLSDEmpty());
1782  }
1783  // we cheat here: As we don't have (and want) a grid-global parcel-store, we can't return the
1784  // "real" parcelID, because we wouldn't be able to map that to the region the parcel belongs to.
1785  // So, we create a "fake" parcelID by using the regionHandle (64 bit), and the local (integer) x
1786  // and y coordinate (each 8 bit), encoded in a UUID (128 bit).
1787  //
1788  // Request format:
1789  // <llsd>
1790  // <map>
1791  // <key>location</key>
1792  // <array>
1793  // <real>1.23</real>
1794  // <real>45..6</real>
1795  // <real>78.9</real>
1796  // </array>
1797  // <key>region_id</key>
1798  // <uuid>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx</uuid>
1799  // </map>
1800  // </llsd>
1801  private string RemoteParcelRequest(string request, string path, string param, UUID agentID, Caps caps)
1802  {
1803  UUID parcelID = UUID.Zero;
1804  try
1805  {
1806  Hashtable hash = new Hashtable();
1807  hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
1808  if (hash.ContainsKey("region_id") && hash.ContainsKey("location"))
1809  {
1810  UUID regionID = (UUID)hash["region_id"];
1811  ArrayList list = (ArrayList)hash["location"];
1812  uint x = (uint)(double)list[0];
1813  uint y = (uint)(double)list[1];
1814  if (hash.ContainsKey("region_handle"))
1815  {
1816  // if you do a "About Landmark" on a landmark a second time, the viewer sends the
1817  // region_handle it got earlier via RegionHandleRequest
1818  ulong regionHandle = Util.BytesToUInt64Big((byte[])hash["region_handle"]);
1819  parcelID = Util.BuildFakeParcelID(regionHandle, x, y);
1820  }
1821  else if (regionID == m_scene.RegionInfo.RegionID)
1822  {
1823  // a parcel request for a local parcel => no need to query the grid
1824  parcelID = Util.BuildFakeParcelID(m_scene.RegionInfo.RegionHandle, x, y);
1825  }
1826  else
1827  {
1828  // a parcel request for a parcel in another region. Ask the grid about the region
1829  GridRegion info = m_scene.GridService.GetRegionByUUID(UUID.Zero, regionID);
1830  if (info != null)
1831  parcelID = Util.BuildFakeParcelID(info.RegionHandle, x, y);
1832  }
1833  }
1834  }
1835  catch (LLSD.LLSDParseException e)
1836  {
1837  m_log.ErrorFormat("[LAND MANAGEMENT MODULE]: Fetch error: {0}", e.Message);
1838  m_log.ErrorFormat("[LAND MANAGEMENT MODULE]: ... in request {0}", request);
1839  }
1840  catch (InvalidCastException)
1841  {
1842  m_log.ErrorFormat("[LAND MANAGEMENT MODULE]: Wrong type in request {0}", request);
1843  }
1844 
1846  response.parcel_id = parcelID;
1847  m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelID {0}", parcelID);
1848 
1849  return LLSDHelpers.SerialiseLLSDReply(response);
1850  }
1851 
1852  #endregion
1853 
1854  private void ClientOnParcelInfoRequest(IClientAPI remoteClient, UUID parcelID)
1855  {
1856  if (parcelID == UUID.Zero)
1857  return;
1858 
1859  ExtendedLandData data = (ExtendedLandData)parcelInfoCache.Get(parcelID.ToString(),
1860  delegate(string id)
1861  {
1862  UUID parcel = UUID.Zero;
1863  UUID.TryParse(id, out parcel);
1864  // assume we've got the parcelID we just computed in RemoteParcelRequest
1865  ExtendedLandData extLandData = new ExtendedLandData();
1866  Util.ParseFakeParcelID(parcel, out extLandData.RegionHandle,
1867  out extLandData.X, out extLandData.Y);
1868  m_log.DebugFormat("[LAND MANAGEMENT MODULE]: Got parcelinfo request for regionHandle {0}, x/y {1}/{2}",
1869  extLandData.RegionHandle, extLandData.X, extLandData.Y);
1870 
1871  // for this region or for somewhere else?
1872  if (extLandData.RegionHandle == m_scene.RegionInfo.RegionHandle)
1873  {
1874  extLandData.LandData = this.GetLandObject(extLandData.X, extLandData.Y).LandData;
1875  extLandData.RegionAccess = m_scene.RegionInfo.AccessLevel;
1876  }
1877  else
1878  {
1879  ILandService landService = m_scene.RequestModuleInterface<ILandService>();
1880  extLandData.LandData = landService.GetLandData(m_scene.RegionInfo.ScopeID,
1881  extLandData.RegionHandle,
1882  extLandData.X,
1883  extLandData.Y,
1884  out extLandData.RegionAccess);
1885  if (extLandData.LandData == null)
1886  {
1887  // we didn't find the region/land => don't cache
1888  return null;
1889  }
1890  }
1891  return extLandData;
1892  });
1893 
1894  if (data != null) // if we found some data, send it
1895  {
1896  GridRegion info;
1897  if (data.RegionHandle == m_scene.RegionInfo.RegionHandle)
1898  {
1899  info = new GridRegion(m_scene.RegionInfo);
1900  }
1901  else
1902  {
1903  // most likely still cached from building the extLandData entry
1904  uint x = 0, y = 0;
1905  Util.RegionHandleToWorldLoc(data.RegionHandle, out x, out y);
1906  info = m_scene.GridService.GetRegionByPosition(m_scene.RegionInfo.ScopeID, (int)x, (int)y);
1907  }
1908  // we need to transfer the fake parcelID, not the one in landData, so the viewer can match it to the landmark.
1909  m_log.DebugFormat("[LAND MANAGEMENT MODULE]: got parcelinfo for parcel {0} in region {1}; sending...",
1910  data.LandData.Name, data.RegionHandle);
1911  // HACK for now
1912  RegionInfo r = new RegionInfo();
1913  r.RegionName = info.RegionName;
1914  r.RegionLocX = (uint)info.RegionLocX;
1915  r.RegionLocY = (uint)info.RegionLocY;
1916  r.RegionSettings.Maturity = (int)Util.ConvertAccessLevelToMaturity(data.RegionAccess);
1917  remoteClient.SendParcelInfo(r, data.LandData, parcelID, data.X, data.Y);
1918  }
1919  else
1920  m_log.Debug("[LAND MANAGEMENT MODULE]: got no parcelinfo; not sending");
1921  }
1922 
1923  public void setParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
1924  {
1925  ILandObject land;
1926  lock (m_landList)
1927  {
1928  m_landList.TryGetValue(localID, out land);
1929  }
1930 
1931  if (land == null) return;
1932 
1933  if (!m_scene.Permissions.CanEditParcelProperties(remoteClient.AgentId, land, GroupPowers.LandOptions, false))
1934  return;
1935 
1936  land.LandData.OtherCleanTime = otherCleanTime;
1937 
1938  UpdateLandObject(localID, land.LandData);
1939  }
1940 
1941  public void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID)
1942  {
1943  ILandObject land = null;
1944  List<ILandObject> Land = ((Scene)client.Scene).LandChannel.AllParcels();
1945  foreach (ILandObject landObject in Land)
1946  {
1947  if (landObject.LandData.LocalID == landID)
1948  {
1949  land = landObject;
1950  }
1951  }
1952  land.DeedToGroup(DefaultGodParcelGroup);
1953  land.LandData.Name = DefaultGodParcelName;
1954  land.SendLandUpdateToAvatarsOverMe();
1955  }
1956 
1957  private void ClientOnSimWideDeletes(IClientAPI client, UUID agentID, int flags, UUID targetID)
1958  {
1959  ScenePresence SP;
1960  ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out SP);
1961  List<SceneObjectGroup> returns = new List<SceneObjectGroup>();
1962  if (SP.UserLevel != 0)
1963  {
1964  if (flags == 0) //All parcels, scripted or not
1965  {
1966  ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1967  {
1968  if (e.OwnerID == targetID)
1969  {
1970  returns.Add(e);
1971  }
1972  }
1973  );
1974  }
1975  if (flags == 4) //All parcels, scripted object
1976  {
1977  ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1978  {
1979  if (e.OwnerID == targetID)
1980  {
1981  if (e.ContainsScripts())
1982  {
1983  returns.Add(e);
1984  }
1985  }
1986  });
1987  }
1988  if (flags == 4) //not target parcel, scripted object
1989  {
1990  ((Scene)client.Scene).ForEachSOG(delegate(SceneObjectGroup e)
1991  {
1992  if (e.OwnerID == targetID)
1993  {
1994  ILandObject landobject = ((Scene)client.Scene).LandChannel.GetLandObject(e.AbsolutePosition.X, e.AbsolutePosition.Y);
1995  if (landobject.LandData.OwnerID != e.OwnerID)
1996  {
1997  if (e.ContainsScripts())
1998  {
1999  returns.Add(e);
2000  }
2001  }
2002  }
2003  });
2004  }
2005  foreach (SceneObjectGroup ol in returns)
2006  {
2007  ReturnObject(ol, client);
2008  }
2009  }
2010  }
2011  public void ReturnObject(SceneObjectGroup obj, IClientAPI client)
2012  {
2013  SceneObjectGroup[] objs = new SceneObjectGroup[1];
2014  objs[0] = obj;
2015  ((Scene)client.Scene).returnObjects(objs, client.AgentId);
2016  }
2017 
2018  Dictionary<UUID, System.Threading.Timer> Timers = new Dictionary<UUID, System.Threading.Timer>();
2019 
2020  public void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
2021  {
2022  ScenePresence targetAvatar = null;
2023  ((Scene)client.Scene).TryGetScenePresence(target, out targetAvatar);
2024  ScenePresence parcelManager = null;
2025  ((Scene)client.Scene).TryGetScenePresence(client.AgentId, out parcelManager);
2026  System.Threading.Timer Timer;
2027 
2028  if (targetAvatar.UserLevel == 0)
2029  {
2030  ILandObject land = ((Scene)client.Scene).LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
2031  if (!((Scene)client.Scene).Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze, true))
2032  return;
2033  if (flags == 0)
2034  {
2035  targetAvatar.AllowMovement = false;
2036  targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has frozen you for 30 seconds. You cannot move or interact with the world.");
2037  parcelManager.ControllingClient.SendAlertMessage("Avatar Frozen.");
2038  System.Threading.TimerCallback timeCB = new System.Threading.TimerCallback(OnEndParcelFrozen);
2039  Timer = new System.Threading.Timer(timeCB, targetAvatar, 30000, 0);
2040  Timers.Add(targetAvatar.UUID, Timer);
2041  }
2042  else
2043  {
2044  targetAvatar.AllowMovement = true;
2045  targetAvatar.ControllingClient.SendAlertMessage(parcelManager.Firstname + " " + parcelManager.Lastname + " has unfrozen you.");
2046  parcelManager.ControllingClient.SendAlertMessage("Avatar Unfrozen.");
2047  Timers.TryGetValue(targetAvatar.UUID, out Timer);
2048  Timers.Remove(targetAvatar.UUID);
2049  Timer.Dispose();
2050  }
2051  }
2052  }
2053  private void OnEndParcelFrozen(object avatar)
2054  {
2055  ScenePresence targetAvatar = (ScenePresence)avatar;
2056  targetAvatar.AllowMovement = true;
2057  System.Threading.Timer Timer;
2058  Timers.TryGetValue(targetAvatar.UUID, out Timer);
2059  Timers.Remove(targetAvatar.UUID);
2060  targetAvatar.ControllingClient.SendAgentAlertMessage("The freeze has worn off; you may go about your business.", false);
2061  }
2062 
2063  public void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
2064  {
2065  ScenePresence targetAvatar = null;
2066  ScenePresence parcelManager = null;
2067 
2068  // Must have presences
2069  if (!m_scene.TryGetScenePresence(target, out targetAvatar) ||
2070  !m_scene.TryGetScenePresence(client.AgentId, out parcelManager))
2071  return;
2072 
2073  // Cannot eject estate managers or gods
2074  if (m_scene.Permissions.IsAdministrator(target))
2075  return;
2076 
2077  // Check if you even have permission to do this
2078  ILandObject land = m_scene.LandChannel.GetLandObject(targetAvatar.AbsolutePosition.X, targetAvatar.AbsolutePosition.Y);
2079  if (!m_scene.Permissions.CanEditParcelProperties(client.AgentId, land, GroupPowers.LandEjectAndFreeze, true) &&
2080  !m_scene.Permissions.IsAdministrator(client.AgentId))
2081  return;
2082 
2083  Vector3 pos = m_scene.GetNearestAllowedPosition(targetAvatar, land);
2084 
2085  targetAvatar.TeleportWithMomentum(pos, null);
2086  targetAvatar.ControllingClient.SendAlertMessage("You have been ejected by " + parcelManager.Firstname + " " + parcelManager.Lastname);
2087  parcelManager.ControllingClient.SendAlertMessage("Avatar Ejected.");
2088 
2089  if ((flags & 1) != 0) // Ban TODO: Remove magic number
2090  {
2091  LandAccessEntry entry = new LandAccessEntry();
2092  entry.AgentID = targetAvatar.UUID;
2093  entry.Flags = AccessList.Ban;
2094  entry.Expires = 0; // Perm
2095 
2096  land.LandData.ParcelAccessList.Add(entry);
2097  }
2098  }
2099 
2108  public virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
2109  {
2110  // Let's find the parcel in question
2111  ILandObject land = landChannel.GetLandObject(position);
2112  if (land == null || m_scene.GridUserService == null)
2113  {
2114  m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2115  return;
2116  }
2117 
2118  // Gather some data
2119  ulong gpowers = remoteClient.GetGroupPowers(land.LandData.GroupID);
2120  SceneObjectGroup telehub = null;
2121  if (m_scene.RegionInfo.RegionSettings.TelehubObject != UUID.Zero)
2122  // Does the telehub exist in the scene?
2123  telehub = m_scene.GetSceneObjectGroup(m_scene.RegionInfo.RegionSettings.TelehubObject);
2124 
2125  // Can the user set home here?
2126  if (// Required: local user; foreign users cannot set home
2127  m_scene.UserManagementModule.IsLocalGridUser(remoteClient.AgentId) &&
2128  (// (a) gods and land managers can set home
2129  m_scene.Permissions.IsAdministrator(remoteClient.AgentId) ||
2130  m_scene.Permissions.IsGod(remoteClient.AgentId) ||
2131  // (b) land owners can set home
2132  remoteClient.AgentId == land.LandData.OwnerID ||
2133  // (c) members of the land-associated group in roles that can set home
2134  ((gpowers & (ulong)GroupPowers.AllowSetHome) == (ulong)GroupPowers.AllowSetHome) ||
2135  // (d) parcels with telehubs can be the home of anyone
2136  (telehub != null && land.ContainsPoint((int)telehub.AbsolutePosition.X, (int)telehub.AbsolutePosition.Y))))
2137  {
2138  string userId;
2139  UUID test;
2140  if (!m_scene.UserManagementModule.GetUserUUI(remoteClient.AgentId, out userId))
2141  {
2142  /* Do not set a home position in this grid for a HG visitor */
2143  m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (User Lookup)");
2144  }
2145  else if (!UUID.TryParse(userId, out test))
2146  {
2147  m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed. (HG visitor)");
2148  }
2149  else if (m_scene.GridUserService.SetHome(userId, land.RegionUUID, position, lookAt))
2150  {
2151  // FUBAR ALERT: this needs to be "Home position set." so the viewer saves a home-screenshot.
2152  m_Dialog.SendAlertToUser(remoteClient, "Home position set.");
2153  }
2154  else
2155  {
2156  m_Dialog.SendAlertToUser(remoteClient, "Set Home request failed.");
2157  }
2158  }
2159  else
2160  m_Dialog.SendAlertToUser(remoteClient, "You are not allowed to set your home location in this parcel.");
2161  }
2162 
2163  protected void RegisterCommands()
2164  {
2165  ICommands commands = MainConsole.Instance.Commands;
2166 
2167  commands.AddCommand(
2168  "Land", false, "land clear",
2169  "land clear",
2170  "Clear all the parcels from the region.",
2171  "Command will ask for confirmation before proceeding.",
2172  HandleClearCommand);
2173 
2174  commands.AddCommand(
2175  "Land", false, "land show",
2176  "land show [<local-land-id>]",
2177  "Show information about the parcels on the region.",
2178  "If no local land ID is given, then summary information about all the parcels is shown.\n"
2179  + "If a local land ID is given then full information about that parcel is shown.",
2180  HandleShowCommand);
2181  }
2182 
2183  protected void HandleClearCommand(string module, string[] args)
2184  {
2185  if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
2186  return;
2187 
2188  string response = MainConsole.Instance.CmdPrompt(
2189  string.Format(
2190  "Are you sure that you want to clear all land parcels from {0} (y or n)", m_scene.Name),
2191  "n");
2192 
2193  if (response.ToLower() == "y")
2194  {
2195  Clear(true);
2196  MainConsole.Instance.OutputFormat("Cleared all parcels from {0}", m_scene.Name);
2197  }
2198  else
2199  {
2200  MainConsole.Instance.OutputFormat("Aborting clear of all parcels from {0}", m_scene.Name);
2201  }
2202  }
2203 
2204  protected void HandleShowCommand(string module, string[] args)
2205  {
2206  if (!(MainConsole.Instance.ConsoleScene == null || MainConsole.Instance.ConsoleScene == m_scene))
2207  return;
2208 
2209  StringBuilder report = new StringBuilder();
2210 
2211  if (args.Length <= 2)
2212  {
2213  AppendParcelsSummaryReport(report);
2214  }
2215  else
2216  {
2217  int landLocalId;
2218 
2219  if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[2], out landLocalId))
2220  return;
2221 
2222  ILandObject lo;
2223 
2224  lock (m_landList)
2225  {
2226  if (!m_landList.TryGetValue(landLocalId, out lo))
2227  {
2228  MainConsole.Instance.OutputFormat("No parcel found with local ID {0}", landLocalId);
2229  return;
2230  }
2231  }
2232 
2233  AppendParcelReport(report, lo);
2234  }
2235 
2236  MainConsole.Instance.Output(report.ToString());
2237  }
2238 
2239  private void AppendParcelsSummaryReport(StringBuilder report)
2240  {
2241  report.AppendFormat("Land information for {0}\n", m_scene.RegionInfo.RegionName);
2242  report.AppendFormat(
2243  "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n",
2244  "Parcel Name",
2245  "Local ID",
2246  "Area",
2247  "AABBMin",
2248  "AABBMax",
2249  "Owner");
2250 
2251  lock (m_landList)
2252  {
2253  foreach (ILandObject lo in m_landList.Values)
2254  {
2255  LandData ld = lo.LandData;
2256 
2257  report.AppendFormat(
2258  "{0,-20} {1,-10} {2,-9} {3,-18} {4,-18} {5,-20}\n",
2259  ld.Name, ld.LocalID, ld.Area, ld.AABBMin, ld.AABBMax, m_userManager.GetUserName(ld.OwnerID));
2260  }
2261  }
2262 
2263  }
2264 
2265  private void AppendParcelReport(StringBuilder report, ILandObject lo)
2266  {
2267  LandData ld = lo.LandData;
2268 
2270  cdl.AddRow("Parcel name", ld.Name);
2271  cdl.AddRow("Local ID", ld.LocalID);
2272  cdl.AddRow("Description", ld.Description);
2273  cdl.AddRow("Snapshot ID", ld.SnapshotID);
2274  cdl.AddRow("Area", ld.Area);
2275  cdl.AddRow("AABB Min", ld.AABBMin);
2276  cdl.AddRow("AABB Max", ld.AABBMax);
2277  string ownerName;
2278  if (ld.IsGroupOwned)
2279  {
2280  GroupRecord rec = m_groupManager.GetGroupRecord(ld.GroupID);
2281  ownerName = (rec != null) ? rec.GroupName : "Unknown Group";
2282  }
2283  else
2284  {
2285  ownerName = m_userManager.GetUserName(ld.OwnerID);
2286  }
2287  cdl.AddRow("Owner", ownerName);
2288  cdl.AddRow("Is group owned?", ld.IsGroupOwned);
2289  cdl.AddRow("GroupID", ld.GroupID);
2290 
2291  cdl.AddRow("Status", ld.Status);
2292  cdl.AddRow("Flags", (ParcelFlags)ld.Flags);
2293 
2294  cdl.AddRow("Landing Type", (LandingType)ld.LandingType);
2295  cdl.AddRow("User Location", ld.UserLocation);
2296  cdl.AddRow("User look at", ld.UserLookAt);
2297 
2298  cdl.AddRow("Other clean time", ld.OtherCleanTime);
2299 
2300  cdl.AddRow("Max Prims", lo.GetParcelMaxPrimCount());
2301  IPrimCounts pc = lo.PrimCounts;
2302  cdl.AddRow("Owner Prims", pc.Owner);
2303  cdl.AddRow("Group Prims", pc.Group);
2304  cdl.AddRow("Other Prims", pc.Others);
2305  cdl.AddRow("Selected Prims", pc.Selected);
2306  cdl.AddRow("Total Prims", pc.Total);
2307 
2308  cdl.AddRow("Music URL", ld.MusicURL);
2309  cdl.AddRow("Obscure Music", ld.ObscureMusic);
2310 
2311  cdl.AddRow("Media ID", ld.MediaID);
2312  cdl.AddRow("Media Autoscale", Convert.ToBoolean(ld.MediaAutoScale));
2313  cdl.AddRow("Media URL", ld.MediaURL);
2314  cdl.AddRow("Media Type", ld.MediaType);
2315  cdl.AddRow("Media Description", ld.MediaDescription);
2316  cdl.AddRow("Media Width", ld.MediaWidth);
2317  cdl.AddRow("Media Height", ld.MediaHeight);
2318  cdl.AddRow("Media Loop", ld.MediaLoop);
2319  cdl.AddRow("Obscure Media", ld.ObscureMedia);
2320 
2321  cdl.AddRow("Parcel Category", ld.Category);
2322 
2323  cdl.AddRow("Claim Date", ld.ClaimDate);
2324  cdl.AddRow("Claim Price", ld.ClaimPrice);
2325  cdl.AddRow("Pass Hours", ld.PassHours);
2326  cdl.AddRow("Pass Price", ld.PassPrice);
2327 
2328  cdl.AddRow("Auction ID", ld.AuctionID);
2329  cdl.AddRow("Authorized Buyer ID", ld.AuthBuyerID);
2330  cdl.AddRow("Sale Price", ld.SalePrice);
2331 
2332  cdl.AddToStringBuilder(report);
2333  }
2334  }
2335 }
Used to generated a formatted table for the console.
void ReturnObjectsInParcel(int localID, uint returnType, UUID[] agentIDs, UUID[] taskIDs, IClientAPI remoteClient)
void ClientOnParcelObjectOwnerRequest(int local_id, IClientAPI remote_client)
void ClientOnParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
void SendParcelOverlay(IClientAPI remote_client)
Send the parcel overlay blocks to the client. We send the overlay packets around a location and limit...
static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
Convert a console input to an int, automatically complaining if a console is given.
Definition: ConsoleUtil.cs:185
bool ContainsScripts()
Returns true if any part in the scene object contains scripts, false otherwise.
ILandObject GetLandObject(int x, int y, bool returnNullIfLandObjectOutsideBounds)
Client provided parameters for avatar movement
bool IsRestrictedFromLand(UUID avatar)
void ClientOnParcelEjectUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
void setSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
OpenSim.Framework.RegionInfo RegionInfo
OpenSim.Server.Handlers.Simulation.Utils Utils
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
void ReturnObject(SceneObjectGroup obj, IClientAPI client)
Vector3 UserLocation
When teleporting is restricted to a certain point, this is the location that the user will be redirec...
Definition: LandData.cs:674
void SendAlertMessage(string message)
OpenMetaverse.StructuredData.OSDMap OSDMap
Vector3 UserLookAt
When teleporting is restricted to a certain point, this is the rotation that the user will be positio...
Definition: LandData.cs:690
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void ClientOnParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
void ClientOnParcelAccessListRequest(UUID agentID, UUID sessionID, uint flags, int sequenceID, int landLocalID, IClientAPI remote_client)
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
void setParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
void EventManagerOnValidateLandBuy(Object o, EventManager.LandBuyArgs e)
Definition: LandData.cs:37
void ClientOnParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, bool snap_selection, IClientAPI remote_client)
void Clear(bool setupDefaultParcel)
Clear the scene of all parcels
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
bool IsEitherBannedOrRestricted(UUID avatar)
PresenceType
Indicate the type of ScenePresence.
Definition: PresenceType.cs:34
ISceneAgent SceneAgent
The scene agent for this client. This will only be set if the client has an agent in a scene (i...
Definition: IClientAPI.cs:724
System.Timers.Timer Timer
OpenSim.Framework.Capabilities.Caps Caps
void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
void ClientOnParcelPropertiesUpdateRequest(LandUpdateArgs args, int localID, IClientAPI remote_client)
void EventManagerOnClientMovement(ScenePresence avatar)
Like handleEventManagerOnSignificantClientMovement, but called with an AgentUpdate regardless of dist...
UUID GlobalID
Global ID for the parcel. (3rd Party Integration)
Definition: LandData.cs:327
bool IsDeleted
Signals whether this entity was in a scene but has since been removed from it.
Definition: EntityBase.cs:73
ILandObject AddLandObject(ILandObject land)
Adds a land object to the stored list and adds them to the landIDList to what they own ...
void EventManagerOnAvatarEnteringNewParcel(ScenePresence avatar, int localLandID, UUID regionID)
Keeps track of a specific piece of land's information
Definition: LandObject.cs:43
bool IsBannedFromLand(UUID avatar)
UUID GroupID
Unique ID of the Group that owns
Definition: LandData.cs:342
override Vector3 AbsolutePosition
Position of this avatar relative to the region the avatar is in
virtual void ClientOnSetHome(IClientAPI remoteClient, ulong regionHandle, Vector3 position, Vector3 lookAt, uint flags)
Sets the Home Point. The LoginService uses this to know where to put a user when they log-in ...
void ClientOnParcelSelectObjects(int local_id, int request_type, List< UUID > returnIDs, IClientAPI remote_client)
bool IsGroupMember(UUID GroupID)
void ClientOnParcelReclaim(int local_id, IClientAPI remote_client)
static ICommandConsole Instance
Definition: MainConsole.cs:35
void EventManagerOnLandBuy(Object o, EventManager.LandBuyArgs e)
Details of a Parcel of land
Definition: LandData.cs:47
void setParcelOtherCleanTime(IClientAPI remoteClient, int localID, int otherCleanTime)
delegate int overrideParcelMaxPrimCountDelegate(ILandObject obj)
void ResetSimLandObjects()
Resets the sim to the default land object (full sim piece of land owned by the default user) ...
bool ContainsPoint(int x, int y)
OpenSim.Services.Interfaces.GridRegion GridRegion
void removeLandObject(int local_id)
Removes a land object from the list. Will not remove if local_id is still owning an area in landIDLis...
byte LandingType
Determines if people are able to teleport where they please on the parcel or if they get constrainted...
Definition: LandData.cs:418
void ClientOnParcelGodMark(IClientAPI client, UUID god, int landID)
void Subdivide(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
Subdivides a piece of land
A class for triggering remote scene events.
Definition: EventManager.cs:44
delegate int overrideSimulatorMaxPrimCountDelegate(ILandObject obj)
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
void ClientOnParcelAbandonRequest(int local_id, IClientAPI remote_client)
bool IsSatOnObject
Are we sitting on an object?
bool EnforceBans(ILandObject land, ScenePresence avatar)
void ClientOnParcelGodForceOwner(int local_id, UUID ownerID, IClientAPI remote_client)
bool IsGroupOwned
Returns true if the Land Parcel is owned by a group
Definition: LandData.cs:357
uint Flags
Parcel settings. Access flags, Fly, NoPush, Voice, Scripts allowed, etc. ParcelFlags ...
Definition: LandData.cs:402
int SalePrice
When the parcel is being sold, this is the price to purchase the parcel
Definition: LandData.cs:611
ILandObject CreateDefaultParcel()
Create a default parcel that spans the entire region and is owned by the estate owner.
void Join(int start_x, int start_y, int end_x, int end_y, UUID attempting_user_id)
Join 2 land objects together
ILandObject GetLandObject(float x_float, float y_float)
Get the land object at the specified point
bool UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client, out bool snap_selection, out bool needOverlay)
void ClientOnParcelFreezeUser(IClientAPI client, UUID parcelowner, uint flags, UUID target)
void UpdateLandProperties(ILandObject land, LandUpdateArgs args, IClientAPI remote_client)
This maintains the relationship between a UUID and a user name.
void ClientOnParcelAccessListUpdateRequest(UUID agentID, uint flags, int landLocalID, UUID transactionID, int sequenceID, int sections, List< LandAccessEntry > entries, IClientAPI remote_client)
int LocalID
Internal ID of the parcel. Sometimes the client will try to use this value
Definition: LandData.cs:463
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
int Area
Area in meters^2 the parcel contains
Definition: LandData.cs:237
UUID AuthBuyerID
UUID of authorized buyer of parcel. This is UUID.Zero if anyone can buy it.
Definition: LandData.cs:267
void SendLandUpdate(ScenePresence avatar, ILandObject over)
PresenceType PresenceType
What type of presence is this? User, NPC, etc.
Definition: ISceneAgent.cs:49
UUID OwnerID
Owner Avatar or Group of the parcel. Naturally, all land masses must be owned by someone ...
Definition: LandData.cs:551