OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
LandObject.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.Generic;
30 using System.Reflection;
31 using log4net;
32 using OpenMetaverse;
33 using OpenSim.Framework;
34 using OpenSim.Region.Framework.Interfaces;
35 using OpenSim.Region.Framework.Scenes;
37 
38 namespace OpenSim.Region.CoreModules.World.Land
39 {
43  public class LandObject : ILandObject
44  {
45  #region Member Variables
46 
47  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48  private static readonly string LogHeader = "[LAND OBJECT]";
49 
50  private readonly int landUnit = 4;
51 
52  private int m_lastSeqId = 0;
53  private int m_expiryCounter = 0;
54 
55  protected Scene m_scene;
56  protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
57  protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>();
58 
59  protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>();
60  protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds
61 
62  private bool[,] m_landBitmap;
63  public bool[,] LandBitmap
64  {
65  get { return m_landBitmap; }
66  set { m_landBitmap = value; }
67  }
68 
69  #endregion
70 
71  public int GetPrimsFree()
72  {
73  m_scene.EventManager.TriggerParcelPrimCountUpdate();
74  int free = GetSimulatorMaxPrimCount() - LandData.SimwidePrims;
75  return free;
76  }
77 
78  protected LandData m_landData;
79  public LandData LandData
80  {
81  get { return m_landData; }
82 
83  set { m_landData = value; }
84  }
85 
86  public IPrimCounts PrimCounts { get; set; }
87 
88  public UUID RegionUUID
89  {
90  get { return m_scene.RegionInfo.RegionID; }
91  }
92 
93  private Vector2 m_startPoint = Vector2.Zero;
94  private Vector2 m_endPoint = Vector2.Zero;
95  private Vector2 m_centerPoint = Vector2.Zero;
96  private Vector2 m_AABBmin = Vector2.Zero;
97  private Vector2 m_AABBmax = Vector2.Zero;
98 
99  public Vector2 StartPoint
100  {
101  get
102  {
103  return m_startPoint;
104  }
105  }
106 
107  public Vector2 EndPoint
108  {
109  get
110  {
111  return m_endPoint;
112  }
113  }
114 
115  //estimate a center point of a parcel
116  public Vector2 CenterPoint
117  {
118  get
119  {
120  return m_centerPoint;
121  }
122  }
123 
124  public Vector2? GetNearestPoint(Vector3 pos)
125  {
126  Vector3 direction = new Vector3(m_centerPoint.X - pos.X, m_centerPoint.Y - pos.Y, 0f );
127  return GetNearestPointAlongDirection(pos, direction);
128  }
129 
130  public Vector2? GetNearestPointAlongDirection(Vector3 pos, Vector3 pdirection)
131  {
132  Vector2 testpos;
133  Vector2 direction;
134 
135  testpos.X = pos.X / landUnit;
136  testpos.Y = pos.Y / landUnit;
137 
138  if(LandBitmap[(int)testpos.X, (int)testpos.Y])
139  return new Vector2(pos.X, pos.Y); // we are already here
140 
141  direction.X = pdirection.X;
142  direction.Y = pdirection.Y;
143 
144  if(direction.X == 0f && direction.Y == 0f)
145  return null; // we can't look anywhere
146 
147  direction.Normalize();
148 
149  int minx = (int)(m_AABBmin.X / landUnit);
150  int maxx = (int)(m_AABBmax.X / landUnit);
151 
152  // check against AABB
153  if(direction.X > 0f)
154  {
155  if(testpos.X >= maxx)
156  return null; // will never get there
157  if(testpos.X < minx)
158  testpos.X = minx;
159  }
160  else if(direction.X < 0f)
161  {
162  if(testpos.X < minx)
163  return null; // will never get there
164  if(testpos.X >= maxx)
165  testpos.X = maxx - 1;
166  }
167  else
168  {
169  if(testpos.X < minx)
170  return null; // will never get there
171  else if(testpos.X >= maxx)
172  return null; // will never get there
173  }
174 
175  int miny = (int)(m_AABBmin.Y / landUnit);
176  int maxy = (int)(m_AABBmax.Y / landUnit);
177 
178  if(direction.Y > 0f)
179  {
180  if(testpos.Y >= maxy)
181  return null; // will never get there
182  if(testpos.Y < miny)
183  testpos.Y = miny;
184  }
185  else if(direction.Y < 0f)
186  {
187  if(testpos.Y < miny)
188  return null; // will never get there
189  if(testpos.Y >= maxy)
190  testpos.Y = maxy - 1;
191  }
192  else
193  {
194  if(testpos.Y < miny)
195  return null; // will never get there
196  else if(testpos.Y >= maxy)
197  return null; // will never get there
198  }
199 
200  while(!LandBitmap[(int)testpos.X, (int)testpos.Y])
201  {
202  testpos += direction;
203 
204  if(testpos.X < minx)
205  return null;
206  if (testpos.X >= maxx)
207  return null;
208  if(testpos.Y < miny)
209  return null;
210  if (testpos.Y >= maxy)
211  return null;
212  }
213 
214  testpos *= landUnit;
215  float ftmp;
216 
217  if(Math.Abs(direction.X) > Math.Abs(direction.Y))
218  {
219  if(direction.X < 0)
220  testpos.X += landUnit - 0.5f;
221  else
222  testpos.X += 0.5f;
223  ftmp = testpos.X - pos.X;
224  ftmp /= direction.X;
225  ftmp = Math.Abs(ftmp);
226  ftmp *= direction.Y;
227  ftmp += pos.Y;
228 
229  if(ftmp < testpos.Y + .5f)
230  ftmp = testpos.Y + .5f;
231  else
232  {
233  testpos.Y += landUnit - 0.5f;
234  if(ftmp > testpos.Y)
235  ftmp = testpos.Y;
236  }
237  testpos.Y = ftmp;
238  }
239  else
240  {
241  if(direction.Y < 0)
242  testpos.Y += landUnit - 0.5f;
243  else
244  testpos.Y += 0.5f;
245  ftmp = testpos.Y - pos.Y;
246  ftmp /= direction.Y;
247  ftmp = Math.Abs(ftmp);
248  ftmp *= direction.X;
249  ftmp += pos.X;
250 
251  if(ftmp < testpos.X + .5f)
252  ftmp = testpos.X + .5f;
253  else
254  {
255  testpos.X += landUnit - 0.5f;
256  if(ftmp > testpos.X)
257  ftmp = testpos.X;
258  }
259  testpos.X = ftmp;
260  }
261  return testpos;
262  }
263 
264 
265  #region Constructors
266 
267  public LandObject(LandData landData, Scene scene)
268  {
269  LandData = landData.Copy();
270  m_scene = scene;
271  }
272 
273  public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
274  {
275  m_scene = scene;
276  if (m_scene == null)
277  LandBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
278  else
279  LandBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
280 
281  LandData = new LandData();
282  LandData.OwnerID = owner_id;
283  if (is_group_owned)
284  LandData.GroupID = owner_id;
285  else
286  LandData.GroupID = UUID.Zero;
287  LandData.IsGroupOwned = is_group_owned;
288 
289  m_scene.EventManager.OnFrame += OnFrame;
290  }
291 
292  #endregion
293 
294  #region Member Functions
295 
296  #region General Functions
297 
304  public bool ContainsPoint(int x, int y)
305  {
306  if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
307  {
308  return LandBitmap[x / landUnit, y / landUnit];
309  }
310  else
311  {
312  return false;
313  }
314  }
315 
316  public ILandObject Copy()
317  {
318  ILandObject newLand = new LandObject(LandData, m_scene);
319  newLand.LandBitmap = (bool[,]) (LandBitmap.Clone());
320  return newLand;
321  }
322 
323  static overrideParcelMaxPrimCountDelegate overrideParcelMaxPrimCount;
324  static overrideSimulatorMaxPrimCountDelegate overrideSimulatorMaxPrimCount;
325 
327  {
328  overrideParcelMaxPrimCount = overrideDel;
329  }
331  {
332  overrideSimulatorMaxPrimCount = overrideDel;
333  }
334 
336  {
337  if (overrideParcelMaxPrimCount != null)
338  {
339  return overrideParcelMaxPrimCount(this);
340  }
341  else
342  {
343  // Normal Calculations
344  int parcelMax = (int)( (long)LandData.Area
345  * (long)m_scene.RegionInfo.ObjectCapacity
346  * (long)m_scene.RegionInfo.RegionSettings.ObjectBonus
347  / (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) );
348  //m_log.DebugFormat("Area: {0}, Capacity {1}, Bonus {2}, Parcel {3}", LandData.Area, m_scene.RegionInfo.ObjectCapacity, m_scene.RegionInfo.RegionSettings.ObjectBonus, parcelMax);
349  return parcelMax;
350  }
351  }
352 
353  private int GetParcelBasePrimCount()
354  {
355  if (overrideParcelMaxPrimCount != null)
356  {
357  return overrideParcelMaxPrimCount(this);
358  }
359  else
360  {
361  // Normal Calculations
362  int parcelMax = (int)((long)LandData.Area
363  * (long)m_scene.RegionInfo.ObjectCapacity
364  / 65536L);
365  return parcelMax;
366  }
367  }
368 
370  {
371  if (overrideSimulatorMaxPrimCount != null)
372  {
373  return overrideSimulatorMaxPrimCount(this);
374  }
375  else
376  {
377  //Normal Calculations
378  int simMax = (int)( (long)LandData.SimwideArea
379  * (long)m_scene.RegionInfo.ObjectCapacity
380  / (long)(m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY) );
381  // m_log.DebugFormat("Simwide Area: {0}, Capacity {1}, SimMax {2}", LandData.SimwideArea, m_scene.RegionInfo.ObjectCapacity, simMax);
382  return simMax;
383  }
384  }
385 
386  #endregion
387 
388  #region Packet Request Handling
389 
390  public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
391  {
392  if (remote_client.SceneAgent.PresenceType == PresenceType.Npc)
393  return;
394 
395  IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
396  // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
397  uint regionFlags = (uint)(RegionFlags.PublicAllowed
398  | RegionFlags.AllowDirectTeleport
399  | RegionFlags.AllowParcelChanges
400  | RegionFlags.AllowVoice );
401 
402  if (estateModule != null)
403  regionFlags = estateModule.GetRegionFlags();
404 
405  int seq_id;
406  if (snap_selection && (sequence_id == 0))
407  {
408  seq_id = m_lastSeqId;
409  }
410  else
411  {
412  seq_id = sequence_id;
413  m_lastSeqId = seq_id;
414  }
415 
416  remote_client.SendLandProperties(seq_id,
417  snap_selection, request_result, this,
418  (float)m_scene.RegionInfo.RegionSettings.ObjectBonus,
419  GetParcelBasePrimCount(),
420  GetSimulatorMaxPrimCount(), regionFlags);
421  }
422 
423  public bool UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client, out bool snap_selection, out bool needOverlay)
424  {
425  //Needs later group support
426  snap_selection = false;
427  needOverlay = false;
428  LandData newData = LandData.Copy();
429 
430  uint allowedDelta = 0;
431 
432  // These two are always blocked as no client can set them anyway
433  // ParcelFlags.ForSaleObjects
434  // ParcelFlags.LindenHome
435 
436  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, false))
437  {
438  allowedDelta |= (uint)(ParcelFlags.AllowLandmark |
439  ParcelFlags.AllowTerraform |
440  ParcelFlags.AllowDamage |
441  ParcelFlags.CreateObjects |
442  ParcelFlags.RestrictPushObject |
443  ParcelFlags.AllowOtherScripts |
444  ParcelFlags.AllowGroupScripts |
445  ParcelFlags.CreateGroupObjects |
446  ParcelFlags.AllowAPrimitiveEntry |
447  ParcelFlags.AllowGroupObjectEntry |
448  ParcelFlags.AllowFly);
449  newData.SeeAVs = args.SeeAVs;
450  newData.AnyAVSounds = args.AnyAVSounds;
451  newData.GroupAVSounds = args.GroupAVSounds;
452  }
453 
454  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale, true))
455  {
456  if (args.AuthBuyerID != newData.AuthBuyerID ||
457  args.SalePrice != newData.SalePrice)
458  {
459  snap_selection = true;
460  }
461 
462  newData.AuthBuyerID = args.AuthBuyerID;
463  newData.SalePrice = args.SalePrice;
464 
465  if (!LandData.IsGroupOwned)
466  {
467  newData.GroupID = args.GroupID;
468 
469  allowedDelta |= (uint)(ParcelFlags.AllowDeedToGroup |
470  ParcelFlags.ContributeWithDeed |
471  ParcelFlags.SellParcelObjects);
472  }
473 
474  allowedDelta |= (uint)ParcelFlags.ForSale;
475  }
476 
477  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces, false))
478  {
479  newData.Category = args.Category;
480 
481  allowedDelta |= (uint)(ParcelFlags.ShowDirectory |
482  ParcelFlags.AllowPublish |
483  ParcelFlags.MaturePublish) | (uint)(1 << 23);
484  }
485 
486  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity, false))
487  {
488  newData.Description = args.Desc;
489  newData.Name = args.Name;
490  newData.SnapshotID = args.SnapshotID;
491  }
492 
493  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint, false))
494  {
495  newData.LandingType = args.LandingType;
496  newData.UserLocation = args.UserLocation;
497  newData.UserLookAt = args.UserLookAt;
498  }
499 
500  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia, false))
501  {
502  newData.MediaAutoScale = args.MediaAutoScale;
503  newData.MediaID = args.MediaID;
504  newData.MediaURL = args.MediaURL;
505  newData.MusicURL = args.MusicURL;
506  newData.MediaType = args.MediaType;
507  newData.MediaDescription = args.MediaDescription;
508  newData.MediaWidth = args.MediaWidth;
509  newData.MediaHeight = args.MediaHeight;
510  newData.MediaLoop = args.MediaLoop;
511  newData.ObscureMusic = args.ObscureMusic;
512  newData.ObscureMedia = args.ObscureMedia;
513 
514  allowedDelta |= (uint)(ParcelFlags.SoundLocal |
515  ParcelFlags.UrlWebPage |
516  ParcelFlags.UrlRawHtml |
517  ParcelFlags.AllowVoiceChat |
518  ParcelFlags.UseEstateVoiceChan);
519  }
520 
521  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses, false))
522  {
523  newData.PassHours = args.PassHours;
524  newData.PassPrice = args.PassPrice;
525 
526  allowedDelta |= (uint)ParcelFlags.UsePassList;
527  }
528 
529  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed, false))
530  {
531  allowedDelta |= (uint)(ParcelFlags.UseAccessGroup |
532  ParcelFlags.UseAccessList);
533  }
534 
535  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned, false))
536  {
537  allowedDelta |= (uint)(ParcelFlags.UseBanList |
538  ParcelFlags.DenyAnonymous |
539  ParcelFlags.DenyAgeUnverified);
540  }
541 
542  if (allowedDelta != (uint)ParcelFlags.None)
543  {
544  uint preserve = LandData.Flags & ~allowedDelta;
545  newData.Flags = preserve | (args.ParcelFlags & allowedDelta);
546 
547  uint curdelta = LandData.Flags ^ newData.Flags;
548  curdelta &= (uint)(ParcelFlags.SoundLocal);
549 
550  if(curdelta != 0 || newData.SeeAVs != LandData.SeeAVs)
551  needOverlay = true;
552 
553  m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
554  return true;
555  }
556  return false;
557  }
558 
559  public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
560  {
561  LandData newData = LandData.Copy();
562  newData.OwnerID = avatarID;
563  newData.GroupID = groupID;
564  newData.IsGroupOwned = groupOwned;
565  //newData.auctionID = AuctionID;
566  newData.ClaimDate = Util.UnixTimeSinceEpoch();
567  newData.ClaimPrice = claimprice;
568  newData.SalePrice = 0;
569  newData.AuthBuyerID = UUID.Zero;
570  newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
571 
572  bool sellObjects = (LandData.Flags & (uint)(ParcelFlags.SellParcelObjects)) != 0
573  && !LandData.IsGroupOwned && !groupOwned;
574  UUID previousOwner = LandData.OwnerID;
575 
576  m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
577 // m_scene.EventManager.TriggerParcelPrimCountUpdate();
578  SendLandUpdateToAvatarsOverMe(true);
579 
580  if (sellObjects) SellLandObjects(previousOwner);
581  }
582 
583  public void DeedToGroup(UUID groupID)
584  {
585  LandData newData = LandData.Copy();
586  newData.OwnerID = groupID;
587  newData.GroupID = groupID;
588  newData.IsGroupOwned = true;
589 
590  // Reset show in directory flag on deed
591  newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
592 
593  m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
594  m_scene.EventManager.TriggerParcelPrimCountUpdate();
595  SendLandUpdateToAvatarsOverMe(true);
596  }
597 
598  public bool IsEitherBannedOrRestricted(UUID avatar)
599  {
600  if (IsBannedFromLand(avatar))
601  {
602  return true;
603  }
604  else if (IsRestrictedFromLand(avatar))
605  {
606  return true;
607  }
608  return false;
609  }
610 
611  public bool CanBeOnThisLand(UUID avatar, float posHeight)
612  {
613  if (posHeight < LandChannel.BAN_LINE_SAFETY_HEIGHT && IsBannedFromLand(avatar))
614  {
615  return false;
616  }
617  else if (IsRestrictedFromLand(avatar))
618  {
619  return false;
620  }
621  return true;
622  }
623 
624  public bool HasGroupAccess(UUID avatar)
625  {
626  if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
627  {
628  ScenePresence sp;
629  if (!m_scene.TryGetScenePresence(avatar, out sp))
630  {
631  bool isMember;
632  if (m_groupMemberCache.TryGetValue(avatar, out isMember))
633  {
634  m_groupMemberCache.Update(avatar, isMember, m_groupMemberCacheTimeout);
635  return isMember;
636  }
637 
638  IGroupsModule groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
639  if (groupsModule == null)
640  return false;
641 
642  GroupMembershipData[] membership = groupsModule.GetMembershipData(avatar);
643  if (membership == null || membership.Length == 0)
644  {
645  m_groupMemberCache.Add(avatar, false, m_groupMemberCacheTimeout);
646  return false;
647  }
648 
649  foreach (GroupMembershipData d in membership)
650  {
651  if (d.GroupID == LandData.GroupID)
652  {
653  m_groupMemberCache.Add(avatar, true, m_groupMemberCacheTimeout);
654  return true;
655  }
656  }
657  m_groupMemberCache.Add(avatar, false, m_groupMemberCacheTimeout);
658  return false;
659  }
660 
661  return sp.ControllingClient.IsGroupMember(LandData.GroupID);
662  }
663  return false;
664  }
665 
666  public bool IsBannedFromLand(UUID avatar)
667  {
668  ExpireAccessList();
669 
670  if (m_scene.Permissions.IsAdministrator(avatar))
671  return false;
672 
673  if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar))
674  return false;
675 
676  if (avatar == LandData.OwnerID)
677  return false;
678 
679  if ((LandData.Flags & (uint) ParcelFlags.UseBanList) > 0)
680  {
681  if (LandData.ParcelAccessList.FindIndex(
682  delegate(LandAccessEntry e)
683  {
684  if (e.AgentID == avatar && e.Flags == AccessList.Ban)
685  return true;
686  return false;
687  }) != -1)
688  {
689  return true;
690  }
691  }
692  return false;
693  }
694 
695  public bool IsRestrictedFromLand(UUID avatar)
696  {
697  if ((LandData.Flags & (uint) ParcelFlags.UseAccessList) == 0)
698  return false;
699 
700  if (m_scene.Permissions.IsAdministrator(avatar))
701  return false;
702 
703  if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar))
704  return false;
705 
706  if (avatar == LandData.OwnerID)
707  return false;
708 
709  if (HasGroupAccess(avatar))
710  return false;
711 
712  return !IsInLandAccessList(avatar);
713  }
714 
715  public bool IsInLandAccessList(UUID avatar)
716  {
717  ExpireAccessList();
718 
719  if (LandData.ParcelAccessList.FindIndex(
720  delegate(LandAccessEntry e)
721  {
722  if (e.AgentID == avatar && e.Flags == AccessList.Access)
723  return true;
724  return false;
725  }) == -1)
726  {
727  return false;
728  }
729  return true;
730  }
731 
732  public void SendLandUpdateToClient(IClientAPI remote_client)
733  {
734  SendLandProperties(0, false, 0, remote_client);
735  }
736 
737  public void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client)
738  {
739  m_scene.EventManager.TriggerParcelPrimCountUpdate();
740  SendLandProperties(0, snap_selection, 0, remote_client);
741  }
742 
744  {
745  SendLandUpdateToAvatarsOverMe(false);
746  }
747 
748  public void SendLandUpdateToAvatarsOverMe(bool snap_selection)
749  {
750  m_scene.EventManager.TriggerParcelPrimCountUpdate();
751  m_scene.ForEachRootScenePresence(delegate(ScenePresence avatar)
752  {
753  ILandObject over = null;
754  try
755  {
756  over =
757  m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
758  Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
759  }
760  catch (Exception)
761  {
762  m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " +
763  Math.Round(avatar.AbsolutePosition.Y));
764  }
765 
766  if (over != null)
767  {
768  if (over.LandData.LocalID == LandData.LocalID)
769  {
770  if (((over.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0) &&
771  m_scene.RegionInfo.RegionSettings.AllowDamage)
772  avatar.Invulnerable = false;
773  else
774  avatar.Invulnerable = true;
775 
776  SendLandUpdateToClient(snap_selection, avatar.ControllingClient);
777  avatar.currentParcelUUID = LandData.GlobalID;
778  }
779  }
780  });
781  }
782 
783  #endregion
784 
785  #region AccessList Functions
786 
787  public List<LandAccessEntry> CreateAccessListArrayByFlag(AccessList flag)
788  {
789  ExpireAccessList();
790 
791  List<LandAccessEntry> list = new List<LandAccessEntry>();
792  foreach (LandAccessEntry entry in LandData.ParcelAccessList)
793  {
794  if (entry.Flags == flag)
795  list.Add(entry);
796  }
797  if (list.Count == 0)
798  {
800  e.AgentID = UUID.Zero;
801  e.Flags = 0;
802  e.Expires = 0;
803 
804  list.Add(e);
805  }
806 
807  return list;
808  }
809 
810  public void SendAccessList(UUID agentID, UUID sessionID, uint flags, int sequenceID,
811  IClientAPI remote_client)
812  {
813 
814  if ((flags & (uint) AccessList.Access) != 0)
815  {
816  List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Access);
817  remote_client.SendLandAccessListData(accessEntries,(uint) AccessList.Access,LandData.LocalID);
818  }
819 
820  if ((flags & (uint) AccessList.Ban) != 0)
821  {
822  List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Ban);
823  remote_client.SendLandAccessListData(accessEntries, (uint)AccessList.Ban, LandData.LocalID);
824  }
825  }
826 
827  public void UpdateAccessList(uint flags, UUID transactionID,
828  int sequenceID, int sections,
829  List<LandAccessEntry> entries,
830  IClientAPI remote_client)
831  {
832  LandData newData = LandData.Copy();
833 
834  if ((!m_listTransactions.ContainsKey(flags)) ||
835  m_listTransactions[flags] != transactionID)
836  {
837  m_listTransactions[flags] = transactionID;
838 
839  List<LandAccessEntry> toRemove =
840  new List<LandAccessEntry>();
841 
842  foreach (LandAccessEntry entry in newData.ParcelAccessList)
843  {
844  if (entry.Flags == (AccessList)flags)
845  toRemove.Add(entry);
846  }
847 
848  foreach (LandAccessEntry entry in toRemove)
849  {
850  newData.ParcelAccessList.Remove(entry);
851  }
852 
853  // Checked here because this will always be the first
854  // and only packet in a transaction
855  if (entries.Count == 1 && entries[0].AgentID == UUID.Zero)
856  {
857  m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
858 
859  return;
860  }
861  }
862 
863  foreach (LandAccessEntry entry in entries)
864  {
865  LandAccessEntry temp =
866  new LandAccessEntry();
867 
868  temp.AgentID = entry.AgentID;
869  temp.Expires = entry.Expires;
870  temp.Flags = (AccessList)flags;
871 
872  newData.ParcelAccessList.Add(temp);
873  }
874 
875  // update use lists flags
876  // rights already checked or we wont be here
877  uint parcelflags = newData.Flags;
878 
879  if((flags & (uint)AccessList.Access) != 0)
880  parcelflags |= (uint)ParcelFlags.UseAccessList;
881  if((flags & (uint)AccessList.Ban) != 0)
882  parcelflags |= (uint)ParcelFlags.UseBanList;
883 
884  newData.Flags = parcelflags;
885 
886  m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
887  }
888 
889  #endregion
890 
891  #region Update Functions
892 
894  {
895  LandData.Bitmap = ConvertLandBitmapToBytes();
896  }
897 
901  public void ForceUpdateLandInfo()
902  {
903  UpdateGeometryValues();
904  UpdateLandBitmapByteArray();
905  }
906 
908  {
909  LandBitmap = ConvertBytesToLandBitmap();
910  }
911 
915  private void UpdateGeometryValues()
916  {
917  int min_x = Int32.MaxValue;
918  int min_y = Int32.MaxValue;
919  int max_x = Int32.MinValue;
920  int max_y = Int32.MinValue;
921  int tempArea = 0;
922  int x, y;
923 
924  int lastX = 0;
925  int lastY = 0;
926  float avgx = 0f;
927  float avgy = 0f;
928 
929  bool needFirst = true;
930 
931  for (x = 0; x < LandBitmap.GetLength(0); x++)
932  {
933  for (y = 0; y < LandBitmap.GetLength(1); y++)
934  {
935  if (LandBitmap[x, y])
936  {
937  if (min_x > x)
938  min_x = x;
939  if (min_y > y)
940  min_y = y;
941  if (max_x < x)
942  max_x = x;
943  if (max_y < y)
944  max_y = y;
945 
946  if(needFirst)
947  {
948  avgx = x;
949  avgy = y;
950  m_startPoint.X = x * landUnit;
951  m_startPoint.Y = y * landUnit;
952  needFirst = false;
953  }
954  else
955  {
956  // keeping previus odd average
957  avgx = (avgx * tempArea + x) / (tempArea + 1);
958  avgy = (avgy * tempArea + y) / (tempArea + 1);
959  }
960 
961  tempArea++;
962 
963  lastX = x;
964  lastY = y;
965  }
966  }
967  }
968 
969  int halfunit = landUnit/2;
970 
971  m_centerPoint.X = avgx * landUnit + halfunit;
972  m_centerPoint.Y = avgy * landUnit + halfunit;
973 
974  m_endPoint.X = lastX * landUnit + landUnit;
975  m_endPoint.Y = lastY * landUnit + landUnit;
976 
977  // next tests should not be needed
978  // if they fail, something is wrong
979 
980  int regionSizeX = (int)Constants.RegionSize;
981  int regionSizeY = (int)Constants.RegionSize;
982 
983  if(m_scene != null)
984  {
985  regionSizeX = (int)m_scene.RegionInfo.RegionSizeX;
986  regionSizeY = (int)m_scene.RegionInfo.RegionSizeX;
987  }
988 
989  int tx = min_x * landUnit;
990  if (tx >= regionSizeX)
991  tx = regionSizeX - 1;
992 
993  int ty = min_y * landUnit;
994  if (ty >= regionSizeY)
995  ty = regionSizeY - 1;
996 
997  m_AABBmin.X = tx;
998  m_AABBmin.Y = ty;
999 
1000  if(m_scene == null || m_scene.Heightmap == null)
1001  LandData.AABBMin = new Vector3(tx, ty, 0f);
1002  else
1003  LandData.AABBMin = new Vector3(tx, ty, (float)m_scene.Heightmap[tx, ty]);
1004 
1005  max_x++;
1006  tx = max_x * landUnit;
1007  if (tx > regionSizeX)
1008  tx = regionSizeX;
1009 
1010  max_y++;
1011  ty = max_y * landUnit;
1012  if (ty > regionSizeY)
1013  ty = regionSizeY;
1014 
1015  m_AABBmax.X = tx;
1016  m_AABBmax.Y = ty;
1017 
1018  if(m_scene == null || m_scene.Heightmap == null)
1019  LandData.AABBMax = new Vector3(tx, ty, 0f);
1020  else
1021  LandData.AABBMax = new Vector3(tx, ty, (float)m_scene.Heightmap[tx - 1, ty - 1]);
1022 
1023  LandData.Area = tempArea * landUnit * landUnit;
1024  }
1025 
1026  #endregion
1027 
1028  #region Land Bitmap Functions
1029 
1034  public void SetLandBitmap(bool[,] bitmap)
1035  {
1036  LandBitmap = bitmap;
1037  ForceUpdateLandInfo();
1038  }
1039 
1044  public bool[,] GetLandBitmap()
1045  {
1046  return LandBitmap;
1047  }
1048 
1049  public bool[,] BasicFullRegionLandBitmap()
1050  {
1051  return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY, true);
1052  }
1053 
1054  public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y, bool set_value = true)
1055  {
1056  // Empty bitmap for the whole region
1057  bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
1058  tempBitmap.Initialize();
1059 
1060  // Fill the bitmap square area specified by state and end
1061  tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, set_value);
1062  // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>",
1063  // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1));
1064  return tempBitmap;
1065  }
1066 
1077  public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
1078  bool set_value)
1079  {
1080  int x, y;
1081  for (y = 0; y < land_bitmap.GetLength(1); y++)
1082  {
1083  for (x = 0; x < land_bitmap.GetLength(0); x++)
1084  {
1085  if (x >= start_x / landUnit && x < end_x / landUnit
1086  && y >= start_y / landUnit && y < end_y / landUnit)
1087  {
1088  land_bitmap[x, y] = set_value;
1089  }
1090  }
1091  }
1092  // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>",
1093  // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1));
1094  return land_bitmap;
1095  }
1096 
1103  public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
1104  {
1105  if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
1106  || bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
1107  || bitmap_add.Rank != 2
1108  || bitmap_base.Rank != 2)
1109  {
1110  throw new Exception(
1111  String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
1112  LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
1113  );
1114  }
1115 
1116  int x, y;
1117  for (y = 0; y < bitmap_base.GetLength(1); y++)
1118  {
1119  for (x = 0; x < bitmap_add.GetLength(0); x++)
1120  {
1121  if (bitmap_add[x, y])
1122  {
1123  bitmap_base[x, y] = true;
1124  }
1125  }
1126  }
1127  return bitmap_base;
1128  }
1129 
1144  public bool[,] RemapLandBitmap(bool[,] bitmap_base, Vector2 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Vector2 regionSize, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax)
1145  {
1146  // get the size of the incoming bitmap
1147  int baseX = bitmap_base.GetLength(0);
1148  int baseY = bitmap_base.GetLength(1);
1149 
1150  // create an intermediate bitmap that is 25% bigger on each side that we can work with to handle rotations
1151  int offsetX = baseX / 4; // the original origin will now be at these coordinates so now we can have imaginary negative coordinates ;)
1152  int offsetY = baseY / 4;
1153  int tmpX = baseX + baseX / 2;
1154  int tmpY = baseY + baseY / 2;
1155  int centreX = tmpX / 2;
1156  int centreY = tmpY / 2;
1157  bool[,] bitmap_tmp = new bool[tmpX, tmpY];
1158 
1159  double radianRotation = Math.PI * rotationDegrees / 180f;
1160  double cosR = Math.Cos(radianRotation);
1161  double sinR = Math.Sin(radianRotation);
1162  if (rotationDegrees < 0f) rotationDegrees += 360f; //-90=270 -180=180 -270=90
1163 
1164  // So first we apply the rotation to the incoming bitmap, storing the result in bitmap_tmp
1165  // We special case orthogonal rotations for accuracy because even using double precision math, Math.Cos(90 degrees) is never fully 0
1166  // and we can never rotate around a centre pixel because the bitmap size is always even
1167  int x, y, sx, sy;
1168  for (y = 0; y <= tmpY; y++)
1169  {
1170  for (x = 0; x <= tmpX; x++)
1171  {
1172  if (rotationDegrees == 0f)
1173  {
1174  sx = x - offsetX;
1175  sy = y - offsetY;
1176  }
1177  else if (rotationDegrees == 90f)
1178  {
1179  sx = y - offsetX;
1180  sy = tmpY - 1 - x - offsetY;
1181  }
1182  else if (rotationDegrees == 180f)
1183  {
1184  sx = tmpX - 1 - x - offsetX;
1185  sy = tmpY - 1 - y - offsetY;
1186  }
1187  else if (rotationDegrees == 270f)
1188  {
1189  sx = tmpX - 1 - y - offsetX;
1190  sy = x - offsetY;
1191  }
1192  else
1193  {
1194  // arbitary rotation: hmmm should I be using (centreX - 0.5) and (centreY - 0.5) and round cosR and sinR to say only 5 decimal places?
1195  sx = centreX + (int)Math.Round((((double)x - centreX) * cosR) + (((double)y - centreY) * sinR)) - offsetX;
1196  sy = centreY + (int)Math.Round((((double)y - centreY) * cosR) - (((double)x - centreX) * sinR)) - offsetY;
1197  }
1198  if (sx >= 0 && sx < baseX && sy >= 0 && sy < baseY)
1199  {
1200  try
1201  {
1202  if (bitmap_base[sx, sy]) bitmap_tmp[x, y] = true;
1203  }
1204  catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;)
1205  {
1206  m_log.DebugFormat("{0} RemapLandBitmap Rotate: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, sx, sy, x, y);
1207  }
1208  }
1209  }
1210  }
1211 
1212  // We could also incorporate the next steps, bounding-rectangle and displacement in the loop above, but it's simpler to visualise if done separately
1213  // and will also make it much easier when later I want the option for maybe a circular or oval bounding shape too ;).
1214  // So... our output land bitmap must be the size of the current region but rememeber, parcel landbitmaps are landUnit metres (4x4 metres) per point,
1215  // and region sizes, boundaries and displacements are in metres so we need to scale down
1216 
1217  int newX = (int)(regionSize.X / landUnit);
1218  int newY = (int)(regionSize.Y / landUnit);
1219  bool[,] bitmap_new = new bool[newX, newY];
1220  // displacement is relative to <0,0> in the destination region and defines where the origin of the data selected by the bounding-rectangle is placed
1221  int dispX = (int)Math.Floor(displacement.X / landUnit);
1222  int dispY = (int)Math.Floor(displacement.Y / landUnit);
1223 
1224  // startX/Y and endX/Y are coordinates in bitmap_tmp
1225  int startX = (int)Math.Floor(boundingOrigin.X / landUnit) + offsetX;
1226  if (startX > tmpX) startX = tmpX;
1227  if (startX < 0) startX = 0;
1228  int startY = (int)Math.Floor(boundingOrigin.Y / landUnit) + offsetY;
1229  if (startY > tmpY) startY = tmpY;
1230  if (startY < 0) startY = 0;
1231 
1232  int endX = (int)Math.Floor((boundingOrigin.X + boundingSize.X) / landUnit) + offsetX;
1233  if (endX > tmpX) endX = tmpX;
1234  if (endX < 0) endX = 0;
1235  int endY = (int)Math.Floor((boundingOrigin.Y + boundingSize.Y) / landUnit) + offsetY;
1236  if (endY > tmpY) endY = tmpY;
1237  if (endY < 0) endY = 0;
1238 
1239  //m_log.DebugFormat("{0} RemapLandBitmap: inSize=<{1},{2}>, disp=<{3},{4}> rot={5}, offset=<{6},{7}>, boundingStart=<{8},{9}>, boundingEnd=<{10},{11}>, cosR={12}, sinR={13}, outSize=<{14},{15}>", LogHeader,
1240  // baseX, baseY, dispX, dispY, radianRotation, offsetX, offsetY, startX, startY, endX, endY, cosR, sinR, newX, newY);
1241 
1242  isEmptyNow = true;
1243  int minX = newX;
1244  int minY = newY;
1245  int maxX = 0;
1246  int maxY = 0;
1247 
1248  int dx, dy;
1249  for (y = startY; y < endY; y++)
1250  {
1251  for (x = startX; x < endX; x++)
1252  {
1253  dx = x - startX + dispX;
1254  dy = y - startY + dispY;
1255  if (dx >= 0 && dx < newX && dy >= 0 && dy < newY)
1256  {
1257  try
1258  {
1259  if (bitmap_tmp[x, y])
1260  {
1261  bitmap_new[dx, dy] = true;
1262  isEmptyNow = false;
1263  if (dx < minX) minX = dx;
1264  if (dy < minY) minY = dy;
1265  if (dx > maxX) maxX = dx;
1266  if (dy > maxY) maxY = dy;
1267  }
1268  }
1269  catch (Exception) //just in case we've still not taken care of every way the arrays might go out of bounds! ;)
1270  {
1271  m_log.DebugFormat("{0} RemapLandBitmap - Bound & Displace: Out of Bounds sx={1} sy={2} dx={3} dy={4}", LogHeader, x, y, dx, dy);
1272  }
1273  }
1274  }
1275  }
1276  if (isEmptyNow)
1277  {
1278  //m_log.DebugFormat("{0} RemapLandBitmap: Land bitmap is marked as Empty", LogHeader);
1279  minX = 0;
1280  minY = 0;
1281  }
1282 
1283  AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0);
1284  AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0);
1285  return bitmap_new;
1286  }
1287 
1298  public bool[,] RemoveFromLandBitmap(bool[,] bitmap_base, bool[,] bitmap_new, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax)
1299  {
1300  // get the size of the incoming bitmaps
1301  int baseX = bitmap_base.GetLength(0);
1302  int baseY = bitmap_base.GetLength(1);
1303  int newX = bitmap_new.GetLength(0);
1304  int newY = bitmap_new.GetLength(1);
1305 
1306  if (baseX != newX || baseY != newY)
1307  {
1308  throw new Exception(
1309  String.Format("{0} RemoveFromLandBitmap: Land bitmaps are not the same size! baseX={1} baseY={2} newX={3} newY={4}", LogHeader, baseX, baseY, newX, newY));
1310  }
1311 
1312  isEmptyNow = true;
1313  int minX = baseX;
1314  int minY = baseY;
1315  int maxX = 0;
1316  int maxY = 0;
1317 
1318  for (int y = 0; y < baseY; y++)
1319  {
1320  for (int x = 0; x < baseX; x++)
1321  {
1322  if (bitmap_new[x, y]) bitmap_base[x, y] = false;
1323  if (bitmap_base[x, y])
1324  {
1325  isEmptyNow = false;
1326  if (x < minX) minX = x;
1327  if (y < minY) minY = y;
1328  if (x > maxX) maxX = x;
1329  if (y > maxY) maxY = y;
1330  }
1331  }
1332  }
1333  if (isEmptyNow)
1334  {
1335  //m_log.DebugFormat("{0} RemoveFromLandBitmap: Land bitmap is marked as Empty", LogHeader);
1336  minX = 0;
1337  minY = 0;
1338  }
1339  AABBMin = new Vector3(minX * landUnit, minY * landUnit, 0);
1340  AABBMax = new Vector3(maxX * landUnit, maxY * landUnit, 0);
1341  return bitmap_base;
1342  }
1343 
1349  {
1350  byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
1351 
1352  int tempByte = 0;
1353  int i, byteNum = 0;
1354  int mask = 1;
1355  i = 0;
1356  for (int y = 0; y < LandBitmap.GetLength(1); y++)
1357  {
1358  for (int x = 0; x < LandBitmap.GetLength(0); x++)
1359  {
1360  if (LandBitmap[x, y])
1361  tempByte |= mask;
1362  mask = mask << 1;
1363  if (mask == 0x100)
1364  {
1365  mask = 1;
1366  tempConvertArr[byteNum++] = (byte)tempByte;
1367  tempByte = 0;
1368  }
1369  }
1370  }
1371 
1372  if(tempByte != 0 && byteNum < 512)
1373  tempConvertArr[byteNum] = (byte)tempByte;
1374 
1375  return tempConvertArr;
1376  }
1377 
1378  public bool[,] ConvertBytesToLandBitmap(bool overrideRegionSize = false)
1379  {
1380  int bitmapLen;
1381  int xLen;
1382  bool[,] tempConvertMap;
1383 
1384  if (overrideRegionSize)
1385  {
1386  // Importing land parcel data from an OAR where the source region is a different size to the dest region requires us
1387  // to make a LandBitmap that's not derived from the current region's size. We use the LandData.Bitmap size in bytes
1388  // to figure out what the OAR's region dimensions are. (Is there a better way to get the src region x and y from the OAR?)
1389  // This method assumes we always will have square regions
1390 
1391  bitmapLen = LandData.Bitmap.Length;
1392  xLen = (int)Math.Abs(Math.Sqrt(bitmapLen * 8));
1393  tempConvertMap = new bool[xLen, xLen];
1394  tempConvertMap.Initialize();
1395  }
1396  else
1397  {
1398  tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
1399  tempConvertMap.Initialize();
1400  // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
1401  bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
1402  xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
1403  if (bitmapLen == 512)
1404  {
1405  // Legacy bitmap being passed in. Use the legacy region size
1406  // and only set the lower area of the larger region.
1407  xLen = (int)(Constants.RegionSize / landUnit);
1408  }
1409  }
1410  // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
1411 
1412  byte tempByte;
1413  int x = 0, y = 0;
1414  for (int i = 0; i < bitmapLen; i++)
1415  {
1416  tempByte = LandData.Bitmap[i];
1417  for (int bitNum = 0; bitNum < 8; bitNum++)
1418  {
1419  bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
1420  try
1421  {
1422  tempConvertMap[x, y] = bit;
1423  }
1424  catch (Exception)
1425  {
1426  m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
1427  }
1428  x++;
1429  if (x >= xLen)
1430  {
1431  x = 0;
1432  y++;
1433  }
1434  }
1435  }
1436 
1437  return tempConvertMap;
1438  }
1439 
1440  public bool IsLandBitmapEmpty(bool[,] landBitmap)
1441  {
1442  for (int y = 0; y < landBitmap.GetLength(1); y++)
1443  {
1444  for (int x = 0; x < landBitmap.GetLength(0); x++)
1445  {
1446  if (landBitmap[x, y]) return false;
1447  }
1448  }
1449  return true;
1450  }
1451 
1452  public void DebugLandBitmap(bool[,] landBitmap)
1453  {
1454  m_log.InfoFormat("{0}: Map Key: #=claimed land .=unclaimed land.", LogHeader);
1455  for (int y = landBitmap.GetLength(1) - 1; y >= 0; y--)
1456  {
1457  string row = "";
1458  for (int x = 0; x < landBitmap.GetLength(0); x++)
1459  {
1460  row += landBitmap[x, y] ? "#" : ".";
1461  }
1462  m_log.InfoFormat("{0}: {1}", LogHeader, row);
1463  }
1464  }
1465 
1466  #endregion
1467 
1468  #region Object Select and Object Owner Listing
1469 
1470  public void SendForceObjectSelect(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client)
1471  {
1472  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true))
1473  {
1474  List<uint> resultLocalIDs = new List<uint>();
1475  try
1476  {
1477  lock (primsOverMe)
1478  {
1479  foreach (SceneObjectGroup obj in primsOverMe)
1480  {
1481  if (obj.LocalId > 0)
1482  {
1483  if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == LandData.OwnerID)
1484  {
1485  resultLocalIDs.Add(obj.LocalId);
1486  }
1487  else if (request_type == LandChannel.LAND_SELECT_OBJECTS_GROUP && obj.GroupID == LandData.GroupID && LandData.GroupID != UUID.Zero)
1488  {
1489  resultLocalIDs.Add(obj.LocalId);
1490  }
1491  else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
1492  obj.OwnerID != remote_client.AgentId)
1493  {
1494  resultLocalIDs.Add(obj.LocalId);
1495  }
1496  else if (request_type == (int)ObjectReturnType.List && returnIDs.Contains(obj.OwnerID))
1497  {
1498  resultLocalIDs.Add(obj.LocalId);
1499  }
1500  }
1501  }
1502  }
1503  } catch (InvalidOperationException)
1504  {
1505  m_log.Error("[LAND]: Unable to force select the parcel objects. Arr.");
1506  }
1507 
1508  remote_client.SendForceClientSelectObjects(resultLocalIDs);
1509  }
1510  }
1511 
1520  public void SendLandObjectOwners(IClientAPI remote_client)
1521  {
1522  if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions, true))
1523  {
1524  Dictionary<UUID, int> primCount = new Dictionary<UUID, int>();
1525  List<UUID> groups = new List<UUID>();
1526 
1527  lock (primsOverMe)
1528  {
1529 // m_log.DebugFormat(
1530 // "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region",
1531 // remote_client.Name, primsOverMe.Count);
1532 
1533  try
1534  {
1535  foreach (SceneObjectGroup obj in primsOverMe)
1536  {
1537  try
1538  {
1539  if (!primCount.ContainsKey(obj.OwnerID))
1540  {
1541  primCount.Add(obj.OwnerID, 0);
1542  }
1543  }
1544  catch (NullReferenceException)
1545  {
1546  m_log.Error("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
1547  }
1548  try
1549  {
1550  primCount[obj.OwnerID] += obj.PrimCount;
1551  }
1552  catch (KeyNotFoundException)
1553  {
1554  m_log.Error("[LAND]: Unable to match a prim with it's owner.");
1555  }
1556  if (obj.OwnerID == obj.GroupID && (!groups.Contains(obj.OwnerID)))
1557  groups.Add(obj.OwnerID);
1558  }
1559  }
1560  catch (InvalidOperationException)
1561  {
1562  m_log.Error("[LAND]: Unable to Enumerate Land object arr.");
1563  }
1564  }
1565 
1566  remote_client.SendLandObjectOwners(LandData, groups, primCount);
1567  }
1568  }
1569 
1570  public Dictionary<UUID, int> GetLandObjectOwners()
1571  {
1572  Dictionary<UUID, int> ownersAndCount = new Dictionary<UUID, int>();
1573 
1574  lock (primsOverMe)
1575  {
1576  try
1577  {
1578 
1579  foreach (SceneObjectGroup obj in primsOverMe)
1580  {
1581  if (!ownersAndCount.ContainsKey(obj.OwnerID))
1582  {
1583  ownersAndCount.Add(obj.OwnerID, 0);
1584  }
1585  ownersAndCount[obj.OwnerID] += obj.PrimCount;
1586  }
1587  }
1588  catch (InvalidOperationException)
1589  {
1590  m_log.Error("[LAND]: Unable to enumerate land owners. arr.");
1591  }
1592 
1593  }
1594  return ownersAndCount;
1595  }
1596 
1597  #endregion
1598 
1599  #region Object Sales
1600 
1601  public void SellLandObjects(UUID previousOwner)
1602  {
1603  // m_log.DebugFormat(
1604  // "[LAND OBJECT]: Request to sell objects in {0} from {1}", LandData.Name, previousOwner);
1605 
1606  if (LandData.IsGroupOwned)
1607  return;
1608 
1609  IBuySellModule m_BuySellModule = m_scene.RequestModuleInterface<IBuySellModule>();
1610  if (m_BuySellModule == null)
1611  {
1612  m_log.Error("[LAND OBJECT]: BuySellModule not found");
1613  return;
1614  }
1615 
1616  ScenePresence sp;
1617  if (!m_scene.TryGetScenePresence(LandData.OwnerID, out sp))
1618  {
1619  m_log.Error("[LAND OBJECT]: New owner is not present in scene");
1620  return;
1621  }
1622 
1623  lock (primsOverMe)
1624  {
1625  foreach (SceneObjectGroup obj in primsOverMe)
1626  {
1627  if (obj.OwnerID == previousOwner && obj.GroupID == UUID.Zero &&
1628  (obj.GetEffectivePermissions() & (uint)(OpenSim.Framework.PermissionMask.Transfer)) != 0)
1629  m_BuySellModule.BuyObject(sp.ControllingClient, UUID.Zero, obj.LocalId, 1, 0);
1630  }
1631  }
1632  }
1633 
1634  #endregion
1635 
1636  #region Object Returning
1637 
1639  {
1640  SceneObjectGroup[] objs = new SceneObjectGroup[1];
1641  objs[0] = obj;
1642  m_scene.returnObjects(objs, obj.OwnerID);
1643  }
1644 
1645  public void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client)
1646  {
1647 // m_log.DebugFormat(
1648 // "[LAND OBJECT]: Request to return objects in {0} from {1}", LandData.Name, remote_client.Name);
1649 
1650  Dictionary<UUID,List<SceneObjectGroup>> returns = new Dictionary<UUID,List<SceneObjectGroup>>();
1651 
1652  lock (primsOverMe)
1653  {
1654  if (type == (uint)ObjectReturnType.Owner)
1655  {
1656  foreach (SceneObjectGroup obj in primsOverMe)
1657  {
1658  if (obj.OwnerID == LandData.OwnerID)
1659  {
1660  if (!returns.ContainsKey(obj.OwnerID))
1661  returns[obj.OwnerID] =
1662  new List<SceneObjectGroup>();
1663  returns[obj.OwnerID].Add(obj);
1664  }
1665  }
1666  }
1667  else if (type == (uint)ObjectReturnType.Group && LandData.GroupID != UUID.Zero)
1668  {
1669  foreach (SceneObjectGroup obj in primsOverMe)
1670  {
1671  if (obj.GroupID == LandData.GroupID)
1672  {
1673  if (!returns.ContainsKey(obj.OwnerID))
1674  returns[obj.OwnerID] =
1675  new List<SceneObjectGroup>();
1676  returns[obj.OwnerID].Add(obj);
1677  }
1678  }
1679  }
1680  else if (type == (uint)ObjectReturnType.Other)
1681  {
1682  foreach (SceneObjectGroup obj in primsOverMe)
1683  {
1684  if (obj.OwnerID != LandData.OwnerID &&
1685  (obj.GroupID != LandData.GroupID ||
1686  LandData.GroupID == UUID.Zero))
1687  {
1688  if (!returns.ContainsKey(obj.OwnerID))
1689  returns[obj.OwnerID] =
1690  new List<SceneObjectGroup>();
1691  returns[obj.OwnerID].Add(obj);
1692  }
1693  }
1694  }
1695  else if (type == (uint)ObjectReturnType.List)
1696  {
1697  List<UUID> ownerlist = new List<UUID>(owners);
1698 
1699  foreach (SceneObjectGroup obj in primsOverMe)
1700  {
1701  if (ownerlist.Contains(obj.OwnerID))
1702  {
1703  if (!returns.ContainsKey(obj.OwnerID))
1704  returns[obj.OwnerID] =
1705  new List<SceneObjectGroup>();
1706  returns[obj.OwnerID].Add(obj);
1707  }
1708  }
1709  }
1710  }
1711 
1712  foreach (List<SceneObjectGroup> ol in returns.Values)
1713  {
1714  if (m_scene.Permissions.CanReturnObjects(this, remote_client.AgentId, ol))
1715  m_scene.returnObjects(ol.ToArray(), remote_client.AgentId);
1716  }
1717  }
1718 
1719  #endregion
1720 
1721  #region Object Adding/Removing from Parcel
1722 
1723  public void ResetOverMeRecord()
1724  {
1725  lock (primsOverMe)
1726  primsOverMe.Clear();
1727  }
1728 
1730  {
1731 // m_log.DebugFormat("[LAND OBJECT]: Adding scene object {0} {1} over {2}", obj.Name, obj.LocalId, LandData.Name);
1732 
1733  lock (primsOverMe)
1734  primsOverMe.Add(obj);
1735  }
1736 
1738  {
1739 // m_log.DebugFormat("[LAND OBJECT]: Removing scene object {0} {1} from over {2}", obj.Name, obj.LocalId, LandData.Name);
1740 
1741  lock (primsOverMe)
1742  primsOverMe.Remove(obj);
1743  }
1744 
1745  #endregion
1746 
1751  public void SetMediaUrl(string url)
1752  {
1753  LandData.MediaURL = url;
1754  m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData);
1755  SendLandUpdateToAvatarsOverMe();
1756  }
1757 
1762  public void SetMusicUrl(string url)
1763  {
1764  LandData.MusicURL = url;
1765  m_scene.LandChannel.UpdateLandObject(LandData.LocalID, LandData);
1766  SendLandUpdateToAvatarsOverMe();
1767  }
1768 
1773  public string GetMusicUrl()
1774  {
1775  return LandData.MusicURL;
1776  }
1777 
1778  #endregion
1779 
1780  private void OnFrame()
1781  {
1782  m_expiryCounter++;
1783 
1784  if (m_expiryCounter >= 50)
1785  {
1786  ExpireAccessList();
1787  m_expiryCounter = 0;
1788  }
1789  }
1790 
1791  private void ExpireAccessList()
1792  {
1793  List<LandAccessEntry> delete = new List<LandAccessEntry>();
1794 
1795  foreach (LandAccessEntry entry in LandData.ParcelAccessList)
1796  {
1797  if (entry.Expires != 0 && entry.Expires < Util.UnixTimeSinceEpoch())
1798  delete.Add(entry);
1799  }
1800  foreach (LandAccessEntry entry in delete)
1801  {
1802  LandData.ParcelAccessList.Remove(entry);
1803  ScenePresence presence;
1804 
1805  if (m_scene.TryGetScenePresence(entry.AgentID, out presence) && (!presence.IsChildAgent))
1806  {
1807  ILandObject land = m_scene.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
1808  if (land.LandData.LocalID == LandData.LocalID)
1809  {
1810  Vector3 pos = m_scene.GetNearestAllowedPosition(presence, land);
1811  presence.TeleportWithMomentum(pos, null);
1812  presence.ControllingClient.SendAlertMessage("You have been ejected from this land");
1813  }
1814  }
1815  m_log.DebugFormat("[LAND]: Removing entry {0} because it has expired", entry.AgentID);
1816  }
1817 
1818  if (delete.Count > 0)
1819  m_scene.EventManager.TriggerLandObjectUpdated((uint)LandData.LocalID, this);
1820  }
1821  }
1822 }
List< LandAccessEntry > CreateAccessListArrayByFlag(AccessList flag)
Definition: LandObject.cs:787
void SendLandUpdateToClient(IClientAPI remote_client)
Definition: LandObject.cs:732
bool[,] GetLandBitmap()
Gets the land's bitmap manually
Definition: LandObject.cs:1044
void ForceUpdateLandInfo()
Update all settings in land such as area, bitmap byte array, etc
Definition: LandObject.cs:901
LandObject(LandData landData, Scene scene)
Definition: LandObject.cs:267
bool[,] ConvertBytesToLandBitmap(bool overrideRegionSize=false)
Definition: LandObject.cs:1378
void SendLandUpdateToAvatarsOverMe(bool snap_selection)
Definition: LandObject.cs:748
bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, bool set_value)
Change a land bitmap at within a square and set those points to a specific value
Definition: LandObject.cs:1077
int Expires
Definition: LandData.cs:40
void RemovePrimFromOverMe(SceneObjectGroup obj)
Definition: LandObject.cs:1737
AccessList Flags
Definition: LandData.cs:41
List< LandAccessEntry > ParcelAccessList
List of access data for the parcel. User data, some bitflags, and a time
Definition: LandData.cs:566
LandObject(UUID owner_id, bool is_group_owned, Scene scene)
Definition: LandObject.cs:273
OpenMetaverse.RegionFlags RegionFlags
Definition: LandObject.cs:36
bool CanBeOnThisLand(UUID avatar, float posHeight)
Definition: LandObject.cs:611
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
Definition: LandObject.cs:559
bool[,] RemoveFromLandBitmap(bool[,] bitmap_base, bool[,] bitmap_new, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax)
Clears any parcel data in bitmap_base where there exists parcel data in bitmap_new. In other words the parcel data in bitmap_new takes over the space of the parcel data in bitmap_base.
Definition: LandObject.cs:1298
void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client)
Definition: LandObject.cs:1645
Definition: LandData.cs:37
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
void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client)
Definition: LandObject.cs:737
byte[] ConvertLandBitmapToBytes()
Converts the land bitmap to a packet friendly byte array
Definition: LandObject.cs:1348
bool UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client, out bool snap_selection, out bool needOverlay)
Definition: LandObject.cs:423
void UpdateAccessList(uint flags, UUID transactionID, int sequenceID, int sections, List< LandAccessEntry > entries, IClientAPI remote_client)
Definition: LandObject.cs:827
Keeps track of a specific piece of land's information
Definition: LandObject.cs:43
bool[,] BasicFullRegionLandBitmap()
Get a land bitmap that would cover an entire region.
Definition: LandObject.cs:1049
UUID GroupID
Unique ID of the Group that owns
Definition: LandData.cs:342
RegionFlags
Region flags used internally by OpenSimulator to store installation specific information about region...
Definition: RegionFlags.cs:40
override Vector3 AbsolutePosition
Position of this avatar relative to the region the avatar is in
bool ContainsPoint(int x, int y)
Checks to see if this land object contains a point
Definition: LandObject.cs:304
void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
Definition: LandObject.cs:390
void SetMusicUrl(string url)
Set the music url for this land parcel
Definition: LandObject.cs:1762
bool[,] RemapLandBitmap(bool[,] bitmap_base, Vector2 displacement, float rotationDegrees, Vector2 boundingOrigin, Vector2 boundingSize, Vector2 regionSize, out bool isEmptyNow, out Vector3 AABBMin, out Vector3 AABBMax)
Remap a land bitmap. Takes the supplied land bitmap and rotates it, crops it and finally offsets it i...
Definition: LandObject.cs:1144
Details of a Parcel of land
Definition: LandData.cs:47
void SendForceObjectSelect(int local_id, int request_type, List< UUID > returnIDs, IClientAPI remote_client)
Definition: LandObject.cs:1470
void SetLandBitmap(bool[,] bitmap)
Sets the land's bitmap manually
Definition: LandObject.cs:1034
delegate int overrideParcelMaxPrimCountDelegate(ILandObject obj)
void SendAccessList(UUID agentID, UUID sessionID, uint flags, int sequenceID, IClientAPI remote_client)
Definition: LandObject.cs:810
void SetSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
Definition: LandObject.cs:330
void SetParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
Definition: LandObject.cs:326
Interactive OpenSim region server
Definition: OpenSim.cs:55
delegate int overrideSimulatorMaxPrimCountDelegate(ILandObject obj)
void SendLandObjectOwners(IClientAPI remote_client)
Notify the parcel owner each avatar that owns prims situated on their land. This notification include...
Definition: LandObject.cs:1520
void SetMediaUrl(string url)
Set the media url for this land parcel
Definition: LandObject.cs:1751
UUID AgentID
Definition: LandData.cs:39
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
bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
Join the true values of 2 bitmaps together
Definition: LandObject.cs:1103
string GetMusicUrl()
Get the music url for this land parcel
Definition: LandObject.cs:1773
int LocalID
Internal ID of the parcel. Sometimes the client will try to use this value
Definition: LandData.cs:463
UUID AuthBuyerID
UUID of authorized buyer of parcel. This is UUID.Zero if anyone can buy it.
Definition: LandData.cs:267
Vector2 GetNearestPointAlongDirection(Vector3 pos, Vector3 pdirection)
Definition: LandObject.cs:130
bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y, bool set_value=true)
Create a square land bitmap.
Definition: LandObject.cs:1054
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