opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.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;
36 using RegionFlags = OpenMetaverse.RegionFlags;
37  
38 namespace OpenSim.Region.CoreModules.World.Land
39 {
40 /// <summary>
41 /// Keeps track of a specific piece of land's information
42 /// </summary>
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 bool[,] m_landBitmap;
51 private readonly int landUnit = 4;
52  
53 private int m_lastSeqId = 0;
54  
55 protected LandData m_landData = new LandData();
56 protected Scene m_scene;
57 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
58 protected Dictionary<uint, UUID> m_listTransactions = new Dictionary<uint, UUID>();
59  
60 protected ExpiringCache<UUID, bool> m_groupMemberCache = new ExpiringCache<UUID, bool>();
61 protected TimeSpan m_groupMemberCacheTimeout = TimeSpan.FromSeconds(30); // cache invalidation after 30 seconds
62  
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() - m_landData.SimwidePrims;
75 return free;
76 }
77  
78 public LandData LandData
79 {
80 get { return m_landData; }
81  
82 set { m_landData = value; }
83 }
84  
85 public IPrimCounts PrimCounts { get; set; }
86  
87 public UUID RegionUUID
88 {
89 get { return m_scene.RegionInfo.RegionID; }
90 }
91  
92 public Vector3 StartPoint
93 {
94 get
95 {
96 for (int y = 0; y < LandBitmap.GetLength(1); y++)
97 {
98 for (int x = 0; x < LandBitmap.GetLength(0); x++)
99 {
100 if (LandBitmap[x, y])
101 return new Vector3(x * landUnit, y * landUnit, 0);
102 }
103 }
104  
105 m_log.ErrorFormat("{0} StartPoint. No start point found. bitmapSize=<{1},{2}>",
106 LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
107 return new Vector3(-1, -1, -1);
108 }
109 }
110  
111 public Vector3 EndPoint
112 {
113 get
114 {
115 for (int y = LandBitmap.GetLength(1) - 1; y >= 0; y--)
116 {
117 for (int x = LandBitmap.GetLength(0) - 1; x >= 0; x--)
118 {
119 if (LandBitmap[x, y])
120 {
121 return new Vector3(x * landUnit + landUnit, y * landUnit + landUnit, 0);
122 }
123 }
124 }
125  
126 m_log.ErrorFormat("{0} EndPoint. No end point found. bitmapSize=<{1},{2}>",
127 LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
128 return new Vector3(-1, -1, -1);
129 }
130 }
131  
132 #region Constructors
133  
134 public LandObject(UUID owner_id, bool is_group_owned, Scene scene)
135 {
136 m_scene = scene;
137 if (m_scene == null)
138 m_landBitmap = new bool[Constants.RegionSize / landUnit, Constants.RegionSize / landUnit];
139 else
140 m_landBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
141  
142 LandData.OwnerID = owner_id;
143 if (is_group_owned)
144 LandData.GroupID = owner_id;
145 else
146 LandData.GroupID = UUID.Zero;
147 LandData.IsGroupOwned = is_group_owned;
148 }
149  
150 #endregion
151  
152 #region Member Functions
153  
154 #region General Functions
155  
156 /// <summary>
157 /// Checks to see if this land object contains a point
158 /// </summary>
159 /// <param name="x"></param>
160 /// <param name="y"></param>
161 /// <returns>Returns true if the piece of land contains the specified point</returns>
162 public bool ContainsPoint(int x, int y)
163 {
164 if (x >= 0 && y >= 0 && x < m_scene.RegionInfo.RegionSizeX && y < m_scene.RegionInfo.RegionSizeY)
165 {
166 return (LandBitmap[x / landUnit, y / landUnit] == true);
167 }
168 else
169 {
170 return false;
171 }
172 }
173  
174 public ILandObject Copy()
175 {
176 ILandObject newLand = new LandObject(LandData.OwnerID, LandData.IsGroupOwned, m_scene);
177  
178 //Place all new variables here!
179 newLand.LandBitmap = (bool[,]) (LandBitmap.Clone());
180 newLand.LandData = LandData.Copy();
181  
182 return newLand;
183 }
184  
185 static overrideParcelMaxPrimCountDelegate overrideParcelMaxPrimCount;
186 static overrideSimulatorMaxPrimCountDelegate overrideSimulatorMaxPrimCount;
187  
188 public void SetParcelObjectMaxOverride(overrideParcelMaxPrimCountDelegate overrideDel)
189 {
190 overrideParcelMaxPrimCount = overrideDel;
191 }
192 public void SetSimulatorObjectMaxOverride(overrideSimulatorMaxPrimCountDelegate overrideDel)
193 {
194 overrideSimulatorMaxPrimCount = overrideDel;
195 }
196  
197 public int GetParcelMaxPrimCount()
198 {
199 if (overrideParcelMaxPrimCount != null)
200 {
201 return overrideParcelMaxPrimCount(this);
202 }
203 else
204 {
205 // Normal Calculations
206 int parcelMax = (int)(((float)LandData.Area / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
207 * (float)m_scene.RegionInfo.ObjectCapacity
208 * (float)m_scene.RegionInfo.RegionSettings.ObjectBonus);
209 // TODO: The calculation of ObjectBonus should be refactored. It does still not work in the same manner as SL!
210 return parcelMax;
211 }
212 }
213  
214 public int GetSimulatorMaxPrimCount()
215 {
216 if (overrideSimulatorMaxPrimCount != null)
217 {
218 return overrideSimulatorMaxPrimCount(this);
219 }
220 else
221 {
222 //Normal Calculations
223 int simMax = (int)(((float)LandData.SimwideArea / (m_scene.RegionInfo.RegionSizeX * m_scene.RegionInfo.RegionSizeY))
224 * (float)m_scene.RegionInfo.ObjectCapacity);
225 return simMax;
226 }
227 }
228  
229 #endregion
230  
231 #region Packet Request Handling
232  
233 public void SendLandProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
234 {
235 IEstateModule estateModule = m_scene.RequestModuleInterface<IEstateModule>();
236 // uint regionFlags = 336723974 & ~((uint)(RegionFlags.AllowLandmark | RegionFlags.AllowSetHome));
237 uint regionFlags = (uint)(RegionFlags.PublicAllowed
238 | RegionFlags.AllowDirectTeleport
239 | RegionFlags.AllowParcelChanges
240 | RegionFlags.AllowVoice );
241  
242 if (estateModule != null)
243 regionFlags = estateModule.GetRegionFlags();
244  
245 int seq_id;
246 if (snap_selection && (sequence_id == 0))
247 {
248 seq_id = m_lastSeqId;
249 }
250 else
251 {
252 seq_id = sequence_id;
253 m_lastSeqId = seq_id;
254 }
255  
256 remote_client.SendLandProperties(seq_id,
257 snap_selection, request_result, this,
258 (float)m_scene.RegionInfo.RegionSettings.ObjectBonus,
259 GetParcelMaxPrimCount(),
260 GetSimulatorMaxPrimCount(), regionFlags);
261 }
262  
263 public void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client)
264 {
265 //Needs later group support
266 bool snap_selection = false;
267 LandData newData = LandData.Copy();
268  
269 uint allowedDelta = 0;
270  
271 // These two are always blocked as no client can set them anyway
272 // ParcelFlags.ForSaleObjects
273 // ParcelFlags.LindenHome
274  
275 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions))
276 {
277 allowedDelta |= (uint)(ParcelFlags.AllowLandmark |
278 ParcelFlags.AllowTerraform |
279 ParcelFlags.AllowDamage |
280 ParcelFlags.CreateObjects |
281 ParcelFlags.RestrictPushObject |
282 ParcelFlags.AllowOtherScripts |
283 ParcelFlags.AllowGroupScripts |
284 ParcelFlags.CreateGroupObjects |
285 ParcelFlags.AllowAPrimitiveEntry |
286 ParcelFlags.AllowGroupObjectEntry |
287 ParcelFlags.AllowFly);
288 }
289  
290 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandSetSale))
291 {
292 if (args.AuthBuyerID != newData.AuthBuyerID ||
293 args.SalePrice != newData.SalePrice)
294 {
295 snap_selection = true;
296 }
297  
298 newData.AuthBuyerID = args.AuthBuyerID;
299 newData.SalePrice = args.SalePrice;
300  
301 if (!LandData.IsGroupOwned)
302 {
303 newData.GroupID = args.GroupID;
304  
305 allowedDelta |= (uint)(ParcelFlags.AllowDeedToGroup |
306 ParcelFlags.ContributeWithDeed |
307 ParcelFlags.SellParcelObjects);
308 }
309  
310 allowedDelta |= (uint)ParcelFlags.ForSale;
311 }
312  
313 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.FindPlaces))
314 {
315 newData.Category = args.Category;
316  
317 allowedDelta |= (uint)(ParcelFlags.ShowDirectory |
318 ParcelFlags.AllowPublish |
319 ParcelFlags.MaturePublish);
320 }
321  
322 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandChangeIdentity))
323 {
324 newData.Description = args.Desc;
325 newData.Name = args.Name;
326 newData.SnapshotID = args.SnapshotID;
327 }
328  
329 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.SetLandingPoint))
330 {
331 newData.LandingType = args.LandingType;
332 newData.UserLocation = args.UserLocation;
333 newData.UserLookAt = args.UserLookAt;
334 }
335  
336 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.ChangeMedia))
337 {
338 newData.MediaAutoScale = args.MediaAutoScale;
339 newData.MediaID = args.MediaID;
340 newData.MediaURL = args.MediaURL;
341 newData.MusicURL = args.MusicURL;
342 newData.MediaType = args.MediaType;
343 newData.MediaDescription = args.MediaDescription;
344 newData.MediaWidth = args.MediaWidth;
345 newData.MediaHeight = args.MediaHeight;
346 newData.MediaLoop = args.MediaLoop;
347 newData.ObscureMusic = args.ObscureMusic;
348 newData.ObscureMedia = args.ObscureMedia;
349  
350 allowedDelta |= (uint)(ParcelFlags.SoundLocal |
351 ParcelFlags.UrlWebPage |
352 ParcelFlags.UrlRawHtml |
353 ParcelFlags.AllowVoiceChat |
354 ParcelFlags.UseEstateVoiceChan);
355 }
356  
357 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId,this, GroupPowers.LandManagePasses))
358 {
359 newData.PassHours = args.PassHours;
360 newData.PassPrice = args.PassPrice;
361  
362 allowedDelta |= (uint)ParcelFlags.UsePassList;
363 }
364  
365 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageAllowed))
366 {
367 allowedDelta |= (uint)(ParcelFlags.UseAccessGroup |
368 ParcelFlags.UseAccessList);
369 }
370  
371 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandManageBanned))
372 {
373 allowedDelta |= (uint)(ParcelFlags.UseBanList |
374 ParcelFlags.DenyAnonymous |
375 ParcelFlags.DenyAgeUnverified);
376 }
377  
378 uint preserve = LandData.Flags & ~allowedDelta;
379 newData.Flags = preserve | (args.ParcelFlags & allowedDelta);
380  
381 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
382  
383 SendLandUpdateToAvatarsOverMe(snap_selection);
384 }
385  
386 public void UpdateLandSold(UUID avatarID, UUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
387 {
388 LandData newData = LandData.Copy();
389 newData.OwnerID = avatarID;
390 newData.GroupID = groupID;
391 newData.IsGroupOwned = groupOwned;
392 //newData.auctionID = AuctionID;
393 newData.ClaimDate = Util.UnixTimeSinceEpoch();
394 newData.ClaimPrice = claimprice;
395 newData.SalePrice = 0;
396 newData.AuthBuyerID = UUID.Zero;
397 newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
398 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
399 m_scene.EventManager.TriggerParcelPrimCountUpdate();
400 SendLandUpdateToAvatarsOverMe(true);
401 }
402  
403 public void DeedToGroup(UUID groupID)
404 {
405 LandData newData = LandData.Copy();
406 newData.OwnerID = groupID;
407 newData.GroupID = groupID;
408 newData.IsGroupOwned = true;
409  
410 // Reset show in directory flag on deed
411 newData.Flags &= ~(uint) (ParcelFlags.ForSale | ParcelFlags.ForSaleObjects | ParcelFlags.SellParcelObjects | ParcelFlags.ShowDirectory);
412  
413 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
414 m_scene.EventManager.TriggerParcelPrimCountUpdate();
415 SendLandUpdateToAvatarsOverMe(true);
416 }
417  
418 public bool IsEitherBannedOrRestricted(UUID avatar)
419 {
420 if (IsBannedFromLand(avatar))
421 {
422 return true;
423 }
424 else if (IsRestrictedFromLand(avatar))
425 {
426 return true;
427 }
428 return false;
429 }
430  
431 public bool CanBeOnThisLand(UUID avatar, float posHeight)
432 {
433 if (posHeight < LandChannel.BAN_LINE_SAFETY_HIEGHT && IsBannedFromLand(avatar))
434 {
435 return false;
436 }
437 else if (IsRestrictedFromLand(avatar))
438 {
439 return false;
440 }
441 return true;
442 }
443  
444 public bool HasGroupAccess(UUID avatar)
445 {
446 if (LandData.GroupID != UUID.Zero && (LandData.Flags & (uint)ParcelFlags.UseAccessGroup) == (uint)ParcelFlags.UseAccessGroup)
447 {
448 ScenePresence sp;
449 if (!m_scene.TryGetScenePresence(avatar, out sp))
450 {
451 bool isMember;
452 if (m_groupMemberCache.TryGetValue(avatar, out isMember))
453 {
454 m_groupMemberCache.Update(avatar, isMember, m_groupMemberCacheTimeout);
455 return isMember;
456 }
457  
458 IGroupsModule groupsModule = m_scene.RequestModuleInterface<IGroupsModule>();
459 if (groupsModule == null)
460 return false;
461  
462 GroupMembershipData[] membership = groupsModule.GetMembershipData(avatar);
463 if (membership == null || membership.Length == 0)
464 {
465 m_groupMemberCache.Add(avatar, false, m_groupMemberCacheTimeout);
466 return false;
467 }
468  
469 foreach (GroupMembershipData d in membership)
470 {
471 if (d.GroupID == LandData.GroupID)
472 {
473 m_groupMemberCache.Add(avatar, true, m_groupMemberCacheTimeout);
474 return true;
475 }
476 }
477 m_groupMemberCache.Add(avatar, false, m_groupMemberCacheTimeout);
478 return false;
479 }
480  
481 return sp.ControllingClient.IsGroupMember(LandData.GroupID);
482 }
483 return false;
484 }
485  
486 public bool IsBannedFromLand(UUID avatar)
487 {
488 ExpireAccessList();
489  
490 if (m_scene.Permissions.IsAdministrator(avatar))
491 return false;
492  
493 if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar))
494 return false;
495  
496 if (avatar == LandData.OwnerID)
497 return false;
498  
499 if ((LandData.Flags & (uint) ParcelFlags.UseBanList) > 0)
500 {
501 if (LandData.ParcelAccessList.FindIndex(
502 delegate(LandAccessEntry e)
503 {
504 if (e.AgentID == avatar && e.Flags == AccessList.Ban)
505 return true;
506 return false;
507 }) != -1)
508 {
509 return true;
510 }
511 }
512 return false;
513 }
514  
515 public bool IsRestrictedFromLand(UUID avatar)
516 {
517 if ((LandData.Flags & (uint) ParcelFlags.UseAccessList) == 0)
518 return false;
519  
520 if (m_scene.Permissions.IsAdministrator(avatar))
521 return false;
522  
523 if (m_scene.RegionInfo.EstateSettings.IsEstateManagerOrOwner(avatar))
524 return false;
525  
526 if (avatar == LandData.OwnerID)
527 return false;
528  
529 if (HasGroupAccess(avatar))
530 return false;
531  
532 return !IsInLandAccessList(avatar);
533 }
534  
535 public bool IsInLandAccessList(UUID avatar)
536 {
537 ExpireAccessList();
538  
539 if (LandData.ParcelAccessList.FindIndex(
540 delegate(LandAccessEntry e)
541 {
542 if (e.AgentID == avatar && e.Flags == AccessList.Access)
543 return true;
544 return false;
545 }) == -1)
546 {
547 return false;
548 }
549 return true;
550 }
551  
552 public void SendLandUpdateToClient(IClientAPI remote_client)
553 {
554 SendLandProperties(0, false, 0, remote_client);
555 }
556  
557 public void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client)
558 {
559 m_scene.EventManager.TriggerParcelPrimCountUpdate();
560 SendLandProperties(0, snap_selection, 0, remote_client);
561 }
562  
563 public void SendLandUpdateToAvatarsOverMe()
564 {
565 SendLandUpdateToAvatarsOverMe(false);
566 }
567  
568 public void SendLandUpdateToAvatarsOverMe(bool snap_selection)
569 {
570 m_scene.ForEachRootScenePresence(delegate(ScenePresence avatar)
571 {
572 ILandObject over = null;
573 try
574 {
575 over =
576 m_scene.LandChannel.GetLandObject(Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.X), 0, ((int)m_scene.RegionInfo.RegionSizeX - 1)),
577 Util.Clamp<int>((int)Math.Round(avatar.AbsolutePosition.Y), 0, ((int)m_scene.RegionInfo.RegionSizeY - 1)));
578 }
579 catch (Exception)
580 {
581 m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " +
582 Math.Round(avatar.AbsolutePosition.Y));
583 }
584  
585 if (over != null)
586 {
587 if (over.LandData.LocalID == LandData.LocalID)
588 {
589 if (((over.LandData.Flags & (uint)ParcelFlags.AllowDamage) != 0) &&
590 m_scene.RegionInfo.RegionSettings.AllowDamage)
591 avatar.Invulnerable = false;
592 else
593 avatar.Invulnerable = true;
594  
595 SendLandUpdateToClient(snap_selection, avatar.ControllingClient);
596 }
597 }
598 });
599 }
600  
601 #endregion
602  
603 #region AccessList Functions
604  
605 public List<LandAccessEntry> CreateAccessListArrayByFlag(AccessList flag)
606 {
607 ExpireAccessList();
608  
609 List<LandAccessEntry> list = new List<LandAccessEntry>();
610 foreach (LandAccessEntry entry in LandData.ParcelAccessList)
611 {
612 if (entry.Flags == flag)
613 list.Add(entry);
614 }
615 if (list.Count == 0)
616 {
617 LandAccessEntry e = new LandAccessEntry();
618 e.AgentID = UUID.Zero;
619 e.Flags = 0;
620 e.Expires = 0;
621  
622 list.Add(e);
623 }
624  
625 return list;
626 }
627  
628 public void SendAccessList(UUID agentID, UUID sessionID, uint flags, int sequenceID,
629 IClientAPI remote_client)
630 {
631  
632 if (flags == (uint) AccessList.Access || flags == (uint) AccessList.Both)
633 {
634 List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Access);
635 remote_client.SendLandAccessListData(accessEntries,(uint) AccessList.Access,LandData.LocalID);
636 }
637  
638 if (flags == (uint) AccessList.Ban || flags == (uint) AccessList.Both)
639 {
640 List<LandAccessEntry> accessEntries = CreateAccessListArrayByFlag(AccessList.Ban);
641 remote_client.SendLandAccessListData(accessEntries, (uint)AccessList.Ban, LandData.LocalID);
642 }
643 }
644  
645 public void UpdateAccessList(uint flags, UUID transactionID,
646 int sequenceID, int sections,
647 List<LandAccessEntry> entries,
648 IClientAPI remote_client)
649 {
650 LandData newData = LandData.Copy();
651  
652 if ((!m_listTransactions.ContainsKey(flags)) ||
653 m_listTransactions[flags] != transactionID)
654 {
655 m_listTransactions[flags] = transactionID;
656  
657 List<LandAccessEntry> toRemove =
658 new List<LandAccessEntry>();
659  
660 foreach (LandAccessEntry entry in newData.ParcelAccessList)
661 {
662 if (entry.Flags == (AccessList)flags)
663 toRemove.Add(entry);
664 }
665  
666 foreach (LandAccessEntry entry in toRemove)
667 {
668 newData.ParcelAccessList.Remove(entry);
669 }
670  
671 // Checked here because this will always be the first
672 // and only packet in a transaction
673 if (entries.Count == 1 && entries[0].AgentID == UUID.Zero)
674 {
675 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
676  
677 return;
678 }
679 }
680  
681 foreach (LandAccessEntry entry in entries)
682 {
683 LandAccessEntry temp =
684 new LandAccessEntry();
685  
686 temp.AgentID = entry.AgentID;
687 temp.Expires = entry.Expires;
688 temp.Flags = (AccessList)flags;
689  
690 newData.ParcelAccessList.Add(temp);
691 }
692  
693 m_scene.LandChannel.UpdateLandObject(LandData.LocalID, newData);
694 }
695  
696 #endregion
697  
698 #region Update Functions
699  
700 public void UpdateLandBitmapByteArray()
701 {
702 LandData.Bitmap = ConvertLandBitmapToBytes();
703 }
704  
705 /// <summary>
706 /// Update all settings in land such as area, bitmap byte array, etc
707 /// </summary>
708 public void ForceUpdateLandInfo()
709 {
710 UpdateAABBAndAreaValues();
711 UpdateLandBitmapByteArray();
712 }
713  
714 public void SetLandBitmapFromByteArray()
715 {
716 LandBitmap = ConvertBytesToLandBitmap();
717 }
718  
719 /// <summary>
720 /// Updates the AABBMin and AABBMax values after area/shape modification of the land object
721 /// </summary>
722 private void UpdateAABBAndAreaValues()
723 {
724 int min_x = 10000;
725 int min_y = 10000;
726 int max_x = 0;
727 int max_y = 0;
728 int tempArea = 0;
729 int x, y;
730 for (x = 0; x < LandBitmap.GetLength(0); x++)
731 {
732 for (y = 0; y < LandBitmap.GetLength(1); y++)
733 {
734 if (LandBitmap[x, y] == true)
735 {
736 if (min_x > x) min_x = x;
737 if (min_y > y) min_y = y;
738 if (max_x < x) max_x = x;
739 if (max_y < y) max_y = y;
740 tempArea += landUnit * landUnit; //16sqm peice of land
741 }
742 }
743 }
744 int tx = min_x * landUnit;
745 if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
746 tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
747 int ty = min_y * landUnit;
748 if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
749 ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
750  
751 LandData.AABBMin =
752 new Vector3(
753 (float)(min_x * landUnit), (float)(min_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
754  
755 tx = max_x * landUnit;
756 if (tx > ((int)m_scene.RegionInfo.RegionSizeX - 1))
757 tx = ((int)m_scene.RegionInfo.RegionSizeX - 1);
758 ty = max_y * landUnit;
759 if (ty > ((int)m_scene.RegionInfo.RegionSizeY - 1))
760 ty = ((int)m_scene.RegionInfo.RegionSizeY - 1);
761  
762 LandData.AABBMax
763 = new Vector3(
764 (float)(max_x * landUnit), (float)(max_y * landUnit), m_scene != null ? (float)m_scene.Heightmap[tx, ty] : 0);
765  
766 LandData.Area = tempArea;
767 }
768  
769 #endregion
770  
771 #region Land Bitmap Functions
772  
773 /// <summary>
774 /// Sets the land's bitmap manually
775 /// </summary>
776 /// <param name="bitmap">block representing where this land is on a map mapped in a 4x4 meter grid</param>
777 public void SetLandBitmap(bool[,] bitmap)
778 {
779 LandBitmap = bitmap;
780 // m_log.DebugFormat("{0} SetLandBitmap. BitmapSize=<{1},{2}>", LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
781 ForceUpdateLandInfo();
782 }
783  
784 /// <summary>
785 /// Gets the land's bitmap manually
786 /// </summary>
787 /// <returns></returns>
788 public bool[,] GetLandBitmap()
789 {
790 return LandBitmap;
791 }
792  
793 public bool[,] BasicFullRegionLandBitmap()
794 {
795 return GetSquareLandBitmap(0, 0, (int)m_scene.RegionInfo.RegionSizeX, (int) m_scene.RegionInfo.RegionSizeY);
796 }
797  
798 public bool[,] GetSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
799 {
800 // Empty bitmap for the whole region
801 bool[,] tempBitmap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
802 tempBitmap.Initialize();
803  
804 // Fill the bitmap square area specified by state and end
805 tempBitmap = ModifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
806 // m_log.DebugFormat("{0} GetSquareLandBitmap. tempBitmapSize=<{1},{2}>",
807 // LogHeader, tempBitmap.GetLength(0), tempBitmap.GetLength(1));
808 return tempBitmap;
809 }
810  
811 /// <summary>
812 /// Change a land bitmap at within a square and set those points to a specific value
813 /// </summary>
814 /// <param name="land_bitmap"></param>
815 /// <param name="start_x"></param>
816 /// <param name="start_y"></param>
817 /// <param name="end_x"></param>
818 /// <param name="end_y"></param>
819 /// <param name="set_value"></param>
820 /// <returns></returns>
821 public bool[,] ModifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
822 bool set_value)
823 {
824 int x, y;
825 for (y = 0; y < land_bitmap.GetLength(1); y++)
826 {
827 for (x = 0; x < land_bitmap.GetLength(0); x++)
828 {
829 if (x >= start_x / landUnit && x < end_x / landUnit
830 && y >= start_y / landUnit && y < end_y / landUnit)
831 {
832 land_bitmap[x, y] = set_value;
833 }
834 }
835 }
836 // m_log.DebugFormat("{0} ModifyLandBitmapSquare. startXY=<{1},{2}>, endXY=<{3},{4}>, val={5}, landBitmapSize=<{6},{7}>",
837 // LogHeader, start_x, start_y, end_x, end_y, set_value, land_bitmap.GetLength(0), land_bitmap.GetLength(1));
838 return land_bitmap;
839 }
840  
841 /// <summary>
842 /// Join the true values of 2 bitmaps together
843 /// </summary>
844 /// <param name="bitmap_base"></param>
845 /// <param name="bitmap_add"></param>
846 /// <returns></returns>
847 public bool[,] MergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
848 {
849 if (bitmap_base.GetLength(0) != bitmap_add.GetLength(0)
850 || bitmap_base.GetLength(1) != bitmap_add.GetLength(1)
851 || bitmap_add.Rank != 2
852 || bitmap_base.Rank != 2)
853 {
854 throw new Exception(
855 String.Format("{0} MergeLandBitmaps. merging maps not same size. baseSizeXY=<{1},{2}>, addSizeXY=<{3},{4}>",
856 LogHeader, bitmap_base.GetLength(0), bitmap_base.GetLength(1), bitmap_add.GetLength(0), bitmap_add.GetLength(1))
857 );
858 }
859  
860 int x, y;
861 for (y = 0; y < bitmap_base.GetLength(1); y++)
862 {
863 for (x = 0; x < bitmap_add.GetLength(0); x++)
864 {
865 if (bitmap_add[x, y])
866 {
867 bitmap_base[x, y] = true;
868 }
869 }
870 }
871 return bitmap_base;
872 }
873  
874 /// <summary>
875 /// Converts the land bitmap to a packet friendly byte array
876 /// </summary>
877 /// <returns></returns>
878 private byte[] ConvertLandBitmapToBytes()
879 {
880 byte[] tempConvertArr = new byte[LandBitmap.GetLength(0) * LandBitmap.GetLength(1) / 8];
881 byte tempByte = 0;
882 int byteNum = 0;
883 int i = 0;
884 for (int y = 0; y < LandBitmap.GetLength(1); y++)
885 {
886 for (int x = 0; x < LandBitmap.GetLength(0); x++)
887 {
888 tempByte = Convert.ToByte(tempByte | Convert.ToByte(LandBitmap[x, y]) << (i++ % 8));
889 if (i % 8 == 0)
890 {
891 tempConvertArr[byteNum] = tempByte;
892 tempByte = (byte) 0;
893 i = 0;
894 byteNum++;
895 }
896 }
897 }
898 // m_log.DebugFormat("{0} ConvertLandBitmapToBytes. BitmapSize=<{1},{2}>",
899 // LogHeader, LandBitmap.GetLength(0), LandBitmap.GetLength(1));
900 return tempConvertArr;
901 }
902  
903 private bool[,] ConvertBytesToLandBitmap()
904 {
905 bool[,] tempConvertMap = new bool[m_scene.RegionInfo.RegionSizeX / landUnit, m_scene.RegionInfo.RegionSizeY / landUnit];
906 tempConvertMap.Initialize();
907 byte tempByte = 0;
908 // Math.Min overcomes an old bug that might have made it into the database. Only use the bytes that fit into convertMap.
909 int bitmapLen = Math.Min(LandData.Bitmap.Length, tempConvertMap.GetLength(0) * tempConvertMap.GetLength(1) / 8);
910 int xLen = (int)(m_scene.RegionInfo.RegionSizeX / landUnit);
911  
912 if (bitmapLen == 512)
913 {
914 // Legacy bitmap being passed in. Use the legacy region size
915 // and only set the lower area of the larger region.
916 xLen = (int)(Constants.RegionSize / landUnit);
917 }
918 // m_log.DebugFormat("{0} ConvertBytesToLandBitmap: bitmapLen={1}, xLen={2}", LogHeader, bitmapLen, xLen);
919  
920 int x = 0, y = 0;
921 for (int i = 0; i < bitmapLen; i++)
922 {
923 tempByte = LandData.Bitmap[i];
924 for (int bitNum = 0; bitNum < 8; bitNum++)
925 {
926 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
927 try
928 {
929 tempConvertMap[x, y] = bit;
930 }
931 catch (Exception e)
932 {
933 m_log.DebugFormat("{0} ConvertBytestoLandBitmap: i={1}, x={2}, y={3}", LogHeader, i, x, y);
934 }
935 x++;
936 if (x >= xLen)
937 {
938 x = 0;
939 y++;
940 }
941 }
942 }
943  
944 return tempConvertMap;
945 }
946  
947 #endregion
948  
949 #region Object Select and Object Owner Listing
950  
951 public void SendForceObjectSelect(int local_id, int request_type, List<UUID> returnIDs, IClientAPI remote_client)
952 {
953 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions))
954 {
955 List<uint> resultLocalIDs = new List<uint>();
956 try
957 {
958 lock (primsOverMe)
959 {
960 foreach (SceneObjectGroup obj in primsOverMe)
961 {
962 if (obj.LocalId > 0)
963 {
964 if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == LandData.OwnerID)
965 {
966 resultLocalIDs.Add(obj.LocalId);
967 }
968 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_GROUP && obj.GroupID == LandData.GroupID && LandData.GroupID != UUID.Zero)
969 {
970 resultLocalIDs.Add(obj.LocalId);
971 }
972 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
973 obj.OwnerID != remote_client.AgentId)
974 {
975 resultLocalIDs.Add(obj.LocalId);
976 }
977 else if (request_type == (int)ObjectReturnType.List && returnIDs.Contains(obj.OwnerID))
978 {
979 resultLocalIDs.Add(obj.LocalId);
980 }
981 }
982 }
983 }
984 } catch (InvalidOperationException)
985 {
986 m_log.Error("[LAND]: Unable to force select the parcel objects. Arr.");
987 }
988  
989 remote_client.SendForceClientSelectObjects(resultLocalIDs);
990 }
991 }
992  
993 /// <summary>
994 /// Notify the parcel owner each avatar that owns prims situated on their land. This notification includes
995 /// aggreagete details such as the number of prims.
996 ///
997 /// </summary>
998 /// <param name="remote_client">
999 /// A <see cref="IClientAPI"/>
1000 /// </param>
1001 public void SendLandObjectOwners(IClientAPI remote_client)
1002 {
1003 if (m_scene.Permissions.CanEditParcelProperties(remote_client.AgentId, this, GroupPowers.LandOptions))
1004 {
1005 Dictionary<UUID, int> primCount = new Dictionary<UUID, int>();
1006 List<UUID> groups = new List<UUID>();
1007  
1008 lock (primsOverMe)
1009 {
1010 // m_log.DebugFormat(
1011 // "[LAND OBJECT]: Request for SendLandObjectOwners() from {0} with {1} known prims on region",
1012 // remote_client.Name, primsOverMe.Count);
1013  
1014 try
1015 {
1016 foreach (SceneObjectGroup obj in primsOverMe)
1017 {
1018 try
1019 {
1020 if (!primCount.ContainsKey(obj.OwnerID))
1021 {
1022 primCount.Add(obj.OwnerID, 0);
1023 }
1024 }
1025 catch (NullReferenceException)
1026 {
1027 m_log.Error("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
1028 }
1029 try
1030 {
1031 primCount[obj.OwnerID] += obj.PrimCount;
1032 }
1033 catch (KeyNotFoundException)
1034 {
1035 m_log.Error("[LAND]: Unable to match a prim with it's owner.");
1036 }
1037 if (obj.OwnerID == obj.GroupID && (!groups.Contains(obj.OwnerID)))
1038 groups.Add(obj.OwnerID);
1039 }
1040 }
1041 catch (InvalidOperationException)
1042 {
1043 m_log.Error("[LAND]: Unable to Enumerate Land object arr.");
1044 }
1045 }
1046  
1047 remote_client.SendLandObjectOwners(LandData, groups, primCount);
1048 }
1049 }
1050  
1051 public Dictionary<UUID, int> GetLandObjectOwners()
1052 {
1053 Dictionary<UUID, int> ownersAndCount = new Dictionary<UUID, int>();
1054  
1055 lock (primsOverMe)
1056 {
1057 try
1058 {
1059  
1060 foreach (SceneObjectGroup obj in primsOverMe)
1061 {
1062 if (!ownersAndCount.ContainsKey(obj.OwnerID))
1063 {
1064 ownersAndCount.Add(obj.OwnerID, 0);
1065 }
1066 ownersAndCount[obj.OwnerID] += obj.PrimCount;
1067 }
1068 }
1069 catch (InvalidOperationException)
1070 {
1071 m_log.Error("[LAND]: Unable to enumerate land owners. arr.");
1072 }
1073  
1074 }
1075 return ownersAndCount;
1076 }
1077  
1078 #endregion
1079  
1080 #region Object Returning
1081  
1082 public void ReturnObject(SceneObjectGroup obj)
1083 {
1084 SceneObjectGroup[] objs = new SceneObjectGroup[1];
1085 objs[0] = obj;
1086 m_scene.returnObjects(objs, obj.OwnerID);
1087 }
1088  
1089 public void ReturnLandObjects(uint type, UUID[] owners, UUID[] tasks, IClientAPI remote_client)
1090 {
1091 // m_log.DebugFormat(
1092 // "[LAND OBJECT]: Request to return objects in {0} from {1}", LandData.Name, remote_client.Name);
1093  
1094 Dictionary<UUID,List<SceneObjectGroup>> returns = new Dictionary<UUID,List<SceneObjectGroup>>();
1095  
1096 lock (primsOverMe)
1097 {
1098 if (type == (uint)ObjectReturnType.Owner)
1099 {
1100 foreach (SceneObjectGroup obj in primsOverMe)
1101 {
1102 if (obj.OwnerID == m_landData.OwnerID)
1103 {
1104 if (!returns.ContainsKey(obj.OwnerID))
1105 returns[obj.OwnerID] =
1106 new List<SceneObjectGroup>();
1107 returns[obj.OwnerID].Add(obj);
1108 }
1109 }
1110 }
1111 else if (type == (uint)ObjectReturnType.Group && m_landData.GroupID != UUID.Zero)
1112 {
1113 foreach (SceneObjectGroup obj in primsOverMe)
1114 {
1115 if (obj.GroupID == m_landData.GroupID)
1116 {
1117 if (!returns.ContainsKey(obj.OwnerID))
1118 returns[obj.OwnerID] =
1119 new List<SceneObjectGroup>();
1120 returns[obj.OwnerID].Add(obj);
1121 }
1122 }
1123 }
1124 else if (type == (uint)ObjectReturnType.Other)
1125 {
1126 foreach (SceneObjectGroup obj in primsOverMe)
1127 {
1128 if (obj.OwnerID != m_landData.OwnerID &&
1129 (obj.GroupID != m_landData.GroupID ||
1130 m_landData.GroupID == UUID.Zero))
1131 {
1132 if (!returns.ContainsKey(obj.OwnerID))
1133 returns[obj.OwnerID] =
1134 new List<SceneObjectGroup>();
1135 returns[obj.OwnerID].Add(obj);
1136 }
1137 }
1138 }
1139 else if (type == (uint)ObjectReturnType.List)
1140 {
1141 List<UUID> ownerlist = new List<UUID>(owners);
1142  
1143 foreach (SceneObjectGroup obj in primsOverMe)
1144 {
1145 if (ownerlist.Contains(obj.OwnerID))
1146 {
1147 if (!returns.ContainsKey(obj.OwnerID))
1148 returns[obj.OwnerID] =
1149 new List<SceneObjectGroup>();
1150 returns[obj.OwnerID].Add(obj);
1151 }
1152 }
1153 }
1154 }
1155  
1156 foreach (List<SceneObjectGroup> ol in returns.Values)
1157 {
1158 if (m_scene.Permissions.CanReturnObjects(this, remote_client.AgentId, ol))
1159 m_scene.returnObjects(ol.ToArray(), remote_client.AgentId);
1160 }
1161 }
1162  
1163 #endregion
1164  
1165 #region Object Adding/Removing from Parcel
1166  
1167 public void ResetOverMeRecord()
1168 {
1169 lock (primsOverMe)
1170 primsOverMe.Clear();
1171 }
1172  
1173 public void AddPrimOverMe(SceneObjectGroup obj)
1174 {
1175 // m_log.DebugFormat("[LAND OBJECT]: Adding scene object {0} {1} over {2}", obj.Name, obj.LocalId, LandData.Name);
1176  
1177 lock (primsOverMe)
1178 primsOverMe.Add(obj);
1179 }
1180  
1181 public void RemovePrimFromOverMe(SceneObjectGroup obj)
1182 {
1183 // m_log.DebugFormat("[LAND OBJECT]: Removing scene object {0} {1} from over {2}", obj.Name, obj.LocalId, LandData.Name);
1184  
1185 lock (primsOverMe)
1186 primsOverMe.Remove(obj);
1187 }
1188  
1189 #endregion
1190  
1191 /// <summary>
1192 /// Set the media url for this land parcel
1193 /// </summary>
1194 /// <param name="url"></param>
1195 public void SetMediaUrl(string url)
1196 {
1197 LandData.MediaURL = url;
1198 SendLandUpdateToAvatarsOverMe();
1199 }
1200  
1201 /// <summary>
1202 /// Set the music url for this land parcel
1203 /// </summary>
1204 /// <param name="url"></param>
1205 public void SetMusicUrl(string url)
1206 {
1207 LandData.MusicURL = url;
1208 SendLandUpdateToAvatarsOverMe();
1209 }
1210  
1211 /// <summary>
1212 /// Get the music url for this land parcel
1213 /// </summary>
1214 /// <returns>The music url.</returns>
1215 public string GetMusicUrl()
1216 {
1217 return LandData.MusicURL;
1218 }
1219  
1220 #endregion
1221  
1222 private void ExpireAccessList()
1223 {
1224 List<LandAccessEntry> delete = new List<LandAccessEntry>();
1225  
1226 foreach (LandAccessEntry entry in LandData.ParcelAccessList)
1227 {
1228 if (entry.Expires != 0 && entry.Expires < Util.UnixTimeSinceEpoch())
1229 delete.Add(entry);
1230 }
1231 foreach (LandAccessEntry entry in delete)
1232 LandData.ParcelAccessList.Remove(entry);
1233  
1234 if (delete.Count > 0)
1235 m_scene.EventManager.TriggerLandObjectUpdated((uint)LandData.LocalID, this);
1236 }
1237 }
1238 }