clockwerk-opensim – Blame information for rev 1

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