aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Environment/Modules/World/Land/LandObject.cs943
1 files changed, 943 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs b/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs
new file mode 100644
index 0000000..693c55d
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs
@@ -0,0 +1,943 @@
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 OpenSim 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
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using libsecondlife;
32using libsecondlife.Packets;
33using log4net;
34using OpenSim.Framework;
35using OpenSim.Region.Environment.Interfaces;
36using OpenSim.Region.Environment.Modules.World.Land;
37using OpenSim.Region.Environment.Scenes;
38
39namespace OpenSim.Region.Environment.Modules.World.Land
40{
41 /// <summary>
42 /// Keeps track of a specific piece of land's information
43 /// </summary>
44 public class LandObject : ILandObject
45 {
46 #region Member Variables
47
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49
50 protected LandData m_landData = new LandData();
51 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
52 protected Scene m_scene;
53
54 private bool[,] m_landBitmap = new bool[64,64];
55
56 public bool[,] landBitmap
57 {
58 get
59 {
60 return m_landBitmap;
61 }
62 set
63 {
64 m_landBitmap = value;
65 }
66 }
67
68 #endregion
69
70 #region ILandObject Members
71
72 public LandData landData
73 {
74 get
75 {
76 return m_landData;
77 }
78
79 set
80 {
81 m_landData = value;
82 }
83 }
84
85 public LLUUID regionUUID
86 {
87 get { return m_scene.RegionInfo.RegionID; }
88 }
89
90 #endregion
91
92
93 #region Constructors
94
95 public LandObject(LLUUID owner_id, bool is_group_owned, Scene scene)
96 {
97 m_scene = scene;
98 landData.ownerID = owner_id;
99 landData.isGroupOwned = is_group_owned;
100 }
101
102 #endregion
103
104 #region Member Functions
105
106 #region General Functions
107
108 /// <summary>
109 /// Checks to see if this land object contains a point
110 /// </summary>
111 /// <param name="x"></param>
112 /// <param name="y"></param>
113 /// <returns>Returns true if the piece of land contains the specified point</returns>
114 public bool containsPoint(int x, int y)
115 {
116 if (x >= 0 && y >= 0 && x <= Constants.RegionSize && x <= Constants.RegionSize)
117 {
118 return (landBitmap[x/4, y/4] == true);
119 }
120 else
121 {
122 return false;
123 }
124 }
125
126 public ILandObject Copy()
127 {
128 ILandObject newLand = new LandObject(landData.ownerID, landData.isGroupOwned, m_scene);
129
130 //Place all new variables here!
131 newLand.landBitmap = (bool[,]) (landBitmap.Clone());
132 newLand.landData = landData.Copy();
133
134 return newLand;
135 }
136
137 #endregion
138
139 #region Packet Request Handling
140
141 /// <summary>
142 /// Sends land properties as requested
143 /// </summary>
144 /// <param name="sequence_id">ID sent by client for them to keep track of</param>
145 /// <param name="snap_selection">Bool sent by client for them to use</param>
146 /// <param name="remote_client">Object representing the client</param>
147 public void sendLandProperties(int sequence_id, bool snap_selection, int request_result,
148 IClientAPI remote_client)
149 {
150 ParcelPropertiesPacket updatePacket = (ParcelPropertiesPacket) PacketPool.Instance.GetPacket(PacketType.ParcelProperties);
151 // TODO: don't create new blocks if recycling an old packet
152
153 updatePacket.ParcelData.AABBMax = landData.AABBMax;
154 updatePacket.ParcelData.AABBMin = landData.AABBMin;
155 updatePacket.ParcelData.Area = landData.area;
156 updatePacket.ParcelData.AuctionID = landData.auctionID;
157 updatePacket.ParcelData.AuthBuyerID = landData.authBuyerID; //unemplemented
158
159 updatePacket.ParcelData.Bitmap = landData.landBitmapByteArray;
160
161 updatePacket.ParcelData.Desc = Helpers.StringToField(landData.landDesc);
162 updatePacket.ParcelData.Category = (byte) landData.category;
163 updatePacket.ParcelData.ClaimDate = landData.claimDate;
164 updatePacket.ParcelData.ClaimPrice = landData.claimPrice;
165 updatePacket.ParcelData.GroupID = landData.groupID;
166 updatePacket.ParcelData.GroupPrims = landData.groupPrims;
167 updatePacket.ParcelData.IsGroupOwned = landData.isGroupOwned;
168 updatePacket.ParcelData.LandingType = (byte) landData.landingType;
169 updatePacket.ParcelData.LocalID = landData.localID;
170 if (landData.area > 0)
171 {
172 updatePacket.ParcelData.MaxPrims =
173 Convert.ToInt32(
174 Math.Round((Convert.ToDecimal(landData.area)/Convert.ToDecimal(65536))*m_scene.objectCapacity*
175 Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor)));
176 }
177 else
178 {
179 updatePacket.ParcelData.MaxPrims = 0;
180 }
181 updatePacket.ParcelData.MediaAutoScale = landData.mediaAutoScale;
182 updatePacket.ParcelData.MediaID = landData.mediaID;
183 updatePacket.ParcelData.MediaURL = Helpers.StringToField(landData.mediaURL);
184 updatePacket.ParcelData.MusicURL = Helpers.StringToField(landData.musicURL);
185 updatePacket.ParcelData.Name = Helpers.StringToField(landData.landName);
186 updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
187 updatePacket.ParcelData.OtherCount = 0; //unemplemented
188 updatePacket.ParcelData.OtherPrims = landData.otherPrims;
189 updatePacket.ParcelData.OwnerID = landData.ownerID;
190 updatePacket.ParcelData.OwnerPrims = landData.ownerPrims;
191 updatePacket.ParcelData.ParcelFlags = landData.landFlags;
192 updatePacket.ParcelData.ParcelPrimBonus = m_scene.RegionInfo.EstateSettings.objectBonusFactor;
193 updatePacket.ParcelData.PassHours = landData.passHours;
194 updatePacket.ParcelData.PassPrice = landData.passPrice;
195 updatePacket.ParcelData.PublicCount = 0; //unemplemented
196
197 uint regionFlags = (uint) m_scene.RegionInfo.EstateSettings.regionFlags;
198 updatePacket.ParcelData.RegionDenyAnonymous = ((regionFlags & (uint) Simulator.RegionFlags.DenyAnonymous) >
199 0);
200 updatePacket.ParcelData.RegionDenyIdentified = ((regionFlags & (uint) Simulator.RegionFlags.DenyIdentified) >
201 0);
202 updatePacket.ParcelData.RegionDenyTransacted = ((regionFlags & (uint) Simulator.RegionFlags.DenyTransacted) >
203 0);
204 updatePacket.ParcelData.RegionPushOverride = ((regionFlags & (uint) Simulator.RegionFlags.RestrictPushObject) >
205 0);
206
207 updatePacket.ParcelData.RentPrice = 0;
208 updatePacket.ParcelData.RequestResult = request_result;
209 updatePacket.ParcelData.SalePrice = landData.salePrice;
210 updatePacket.ParcelData.SelectedPrims = landData.selectedPrims;
211 updatePacket.ParcelData.SelfCount = 0; //unemplemented
212 updatePacket.ParcelData.SequenceID = sequence_id;
213 if (landData.simwideArea > 0)
214 {
215 updatePacket.ParcelData.SimWideMaxPrims =
216 Convert.ToInt32(
217 Math.Round((Convert.ToDecimal(landData.simwideArea) / Convert.ToDecimal(65536)) * m_scene.objectCapacity *
218 Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor)));
219 }
220 else
221 {
222 updatePacket.ParcelData.SimWideMaxPrims = 0;
223 }
224 updatePacket.ParcelData.SimWideTotalPrims = landData.simwidePrims;
225 updatePacket.ParcelData.SnapSelection = snap_selection;
226 updatePacket.ParcelData.SnapshotID = landData.snapshotID;
227 updatePacket.ParcelData.Status = (byte) landData.landStatus;
228 updatePacket.ParcelData.TotalPrims = landData.ownerPrims + landData.groupPrims + landData.otherPrims +
229 landData.selectedPrims;
230 updatePacket.ParcelData.UserLocation = landData.userLocation;
231 updatePacket.ParcelData.UserLookAt = landData.userLookAt;
232 remote_client.OutPacket((Packet) updatePacket, ThrottleOutPacketType.Task);
233 }
234
235 public void updateLandProperties(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
236 {
237 if (remote_client.AgentId == landData.ownerID)
238 {
239 //Needs later group support
240 LandData newData = landData.Copy();
241 newData.authBuyerID = packet.ParcelData.AuthBuyerID;
242 newData.category = (Parcel.ParcelCategory) packet.ParcelData.Category;
243 newData.landDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc);
244 newData.groupID = packet.ParcelData.GroupID;
245 newData.landingType = packet.ParcelData.LandingType;
246 newData.mediaAutoScale = packet.ParcelData.MediaAutoScale;
247 newData.mediaID = packet.ParcelData.MediaID;
248 newData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL);
249 newData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL);
250 newData.landName = Helpers.FieldToUTF8String(packet.ParcelData.Name);
251 newData.landFlags = packet.ParcelData.ParcelFlags;
252 newData.passHours = packet.ParcelData.PassHours;
253 newData.passPrice = packet.ParcelData.PassPrice;
254 newData.salePrice = packet.ParcelData.SalePrice;
255 newData.snapshotID = packet.ParcelData.SnapshotID;
256 newData.userLocation = packet.ParcelData.UserLocation;
257 newData.userLookAt = packet.ParcelData.UserLookAt;
258
259 m_scene.LandChannel.updateLandObject(landData.localID, newData);
260
261 sendLandUpdateToAvatarsOverMe();
262 }
263 }
264 public void updateLandSold(LLUUID avatarID, LLUUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area)
265 {
266 LandData newData = landData.Copy();
267 newData.ownerID = avatarID;
268 newData.groupID = groupID;
269 newData.isGroupOwned = groupOwned;
270 //newData.auctionID = AuctionID;
271 newData.claimDate = Util.UnixTimeSinceEpoch();
272 newData.claimPrice = claimprice;
273 newData.salePrice = 0;
274 newData.authBuyerID = LLUUID.Zero;
275 newData.landFlags &= ~(uint)(Parcel.ParcelFlags.ForSale | Parcel.ParcelFlags.ForSaleObjects | Parcel.ParcelFlags.SellParcelObjects);
276 m_scene.LandChannel.updateLandObject(landData.localID, newData);
277
278 sendLandUpdateToAvatarsOverMe();
279 }
280
281 public bool isEitherBannedOrRestricted(LLUUID avatar)
282 {
283 if (isBannedFromLand(avatar))
284 {
285 return true;
286 }
287 else if (isRestrictedFromLand(avatar))
288 {
289 return true;
290 }
291 return false;
292 }
293
294 public bool isBannedFromLand(LLUUID avatar)
295 {
296 if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseBanList) > 0)
297 {
298 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
299 entry.AgentID = avatar;
300 entry.Flags = ParcelManager.AccessList.Ban;
301 entry.Time = new DateTime();
302 if (landData.parcelAccessList.Contains(entry))
303 {
304 //They are banned, so lets send them a notice about this parcel
305 return true;
306 }
307 }
308 return false;
309 }
310
311 public bool isRestrictedFromLand(LLUUID avatar)
312 {
313 if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseAccessList) > 0)
314 {
315 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
316 entry.AgentID = avatar;
317 entry.Flags = ParcelManager.AccessList.Access;
318 entry.Time = new DateTime();
319 if (!landData.parcelAccessList.Contains(entry))
320 {
321 //They are not allowed in this parcel, but not banned, so lets send them a notice about this parcel
322 return true;
323 }
324 }
325 return false;
326 }
327
328 public void sendLandUpdateToClient(IClientAPI remote_client)
329 {
330 sendLandProperties(0, false, 0, remote_client);
331 }
332
333 public void sendLandUpdateToAvatarsOverMe()
334 {
335 List<ScenePresence> avatars = m_scene.GetAvatars();
336 ILandObject over = null;
337 for (int i = 0; i < avatars.Count; i++)
338 {
339 try
340 {
341 over =
342 m_scene.LandChannel.getLandObject((int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.X))),
343 (int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.Y))));
344 }
345 catch (Exception)
346 {
347 m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatars[i].AbsolutePosition.X) + " y: " + Math.Round(avatars[i].AbsolutePosition.Y));
348 }
349
350 if (over != null)
351 {
352 if (over.landData.localID == landData.localID)
353 {
354 sendLandUpdateToClient(avatars[i].ControllingClient);
355 }
356 }
357 }
358 }
359
360 #endregion
361
362 #region AccessList Functions
363
364 public ParcelAccessListReplyPacket.ListBlock[] createAccessListArrayByFlag(ParcelManager.AccessList flag)
365 {
366 List<ParcelAccessListReplyPacket.ListBlock> list = new List<ParcelAccessListReplyPacket.ListBlock>();
367 foreach (ParcelManager.ParcelAccessEntry entry in landData.parcelAccessList)
368 {
369 if (entry.Flags == flag)
370 {
371 ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock();
372
373 listBlock.Flags = (uint) 0;
374 listBlock.ID = entry.AgentID;
375 listBlock.Time = 0;
376
377 list.Add(listBlock);
378 }
379 }
380
381 if (list.Count == 0)
382 {
383 ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock();
384
385 listBlock.Flags = (uint) 0;
386 listBlock.ID = LLUUID.Zero;
387 listBlock.Time = 0;
388
389 list.Add(listBlock);
390 }
391 return list.ToArray();
392 }
393
394 public void sendAccessList(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID,
395 IClientAPI remote_client)
396 {
397 ParcelAccessListReplyPacket replyPacket;
398
399 if (flags == (uint) ParcelManager.AccessList.Access || flags == (uint) ParcelManager.AccessList.Both)
400 {
401 replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
402 replyPacket.Data.AgentID = agentID;
403 replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Access;
404 replyPacket.Data.LocalID = landData.localID;
405 replyPacket.Data.SequenceID = 0;
406
407 replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Access);
408 remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task);
409 }
410
411 if (flags == (uint) ParcelManager.AccessList.Ban || flags == (uint) ParcelManager.AccessList.Both)
412 {
413 replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
414 replyPacket.Data.AgentID = agentID;
415 replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Ban;
416 replyPacket.Data.LocalID = landData.localID;
417 replyPacket.Data.SequenceID = 0;
418
419 replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Ban);
420 remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task);
421 }
422 }
423
424 public void updateAccessList(uint flags, List<ParcelManager.ParcelAccessEntry> entries, IClientAPI remote_client)
425 {
426 LandData newData = landData.Copy();
427
428 if (entries.Count == 1 && entries[0].AgentID == LLUUID.Zero)
429 {
430 entries.Clear();
431 }
432
433 List<ParcelManager.ParcelAccessEntry> toRemove = new List<ParcelManager.ParcelAccessEntry>();
434 foreach (ParcelManager.ParcelAccessEntry entry in newData.parcelAccessList)
435 {
436 if (entry.Flags == (ParcelManager.AccessList) flags)
437 {
438 toRemove.Add(entry);
439 }
440 }
441
442 foreach (ParcelManager.ParcelAccessEntry entry in toRemove)
443 {
444 newData.parcelAccessList.Remove(entry);
445 }
446 foreach (ParcelManager.ParcelAccessEntry entry in entries)
447 {
448 ParcelManager.ParcelAccessEntry temp = new ParcelManager.ParcelAccessEntry();
449 temp.AgentID = entry.AgentID;
450 temp.Time = new DateTime(); //Pointless? Yes.
451 temp.Flags = (ParcelManager.AccessList) flags;
452
453 if (!newData.parcelAccessList.Contains(temp))
454 {
455 newData.parcelAccessList.Add(temp);
456 }
457 }
458
459 m_scene.LandChannel.updateLandObject(landData.localID, newData);
460 }
461
462 #endregion
463
464 #region Update Functions
465
466 /// <summary>
467 /// Updates the AABBMin and AABBMax values after area/shape modification of the land object
468 /// </summary>
469 private void updateAABBAndAreaValues()
470 {
471 int min_x = 64;
472 int min_y = 64;
473 int max_x = 0;
474 int max_y = 0;
475 int tempArea = 0;
476 int x, y;
477 for (x = 0; x < 64; x++)
478 {
479 for (y = 0; y < 64; y++)
480 {
481 if (landBitmap[x, y] == true)
482 {
483 if (min_x > x) min_x = x;
484 if (min_y > y) min_y = y;
485 if (max_x < x) max_x = x;
486 if (max_y < y) max_y = y;
487 tempArea += 16; //16sqm peice of land
488 }
489 }
490 }
491 int tx = min_x * 4;
492 if (tx > 255)
493 tx = 255;
494 int ty = min_y * 4;
495 if (ty > 255)
496 ty = 255;
497 landData.AABBMin =
498 new LLVector3((float)(min_x * 4), (float)(min_y * 4),
499 (float)m_scene.Heightmap[tx, ty]);
500
501 tx = max_x * 4;
502 if (tx > 255)
503 tx = 255;
504 ty = max_y * 4;
505 if (ty > 255)
506 ty = 255;
507 landData.AABBMax =
508 new LLVector3((float)(max_x * 4), (float)(max_y * 4),
509 (float)m_scene.Heightmap[tx, ty]);
510 landData.area = tempArea;
511 }
512
513 public void updateLandBitmapByteArray()
514 {
515 landData.landBitmapByteArray = convertLandBitmapToBytes();
516 }
517
518 /// <summary>
519 /// Update all settings in land such as area, bitmap byte array, etc
520 /// </summary>
521 public void forceUpdateLandInfo()
522 {
523 updateAABBAndAreaValues();
524 updateLandBitmapByteArray();
525 }
526
527 public void setLandBitmapFromByteArray()
528 {
529 landBitmap = convertBytesToLandBitmap();
530 }
531
532 #endregion
533
534 #region Land Bitmap Functions
535
536 /// <summary>
537 /// Sets the land's bitmap manually
538 /// </summary>
539 /// <param name="bitmap">64x64 block representing where this land is on a map</param>
540 public void setLandBitmap(bool[,] bitmap)
541 {
542 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
543 {
544 //Throw an exception - The bitmap is not 64x64
545 //throw new Exception("Error: Invalid Parcel Bitmap");
546 }
547 else
548 {
549 //Valid: Lets set it
550 landBitmap = bitmap;
551 forceUpdateLandInfo();
552 }
553 }
554
555 /// <summary>
556 /// Gets the land's bitmap manually
557 /// </summary>
558 /// <returns></returns>
559 public bool[,] getLandBitmap()
560 {
561 return landBitmap;
562 }
563
564 /// <summary>
565 /// Converts the land bitmap to a packet friendly byte array
566 /// </summary>
567 /// <returns></returns>
568 private byte[] convertLandBitmapToBytes()
569 {
570 byte[] tempConvertArr = new byte[512];
571 byte tempByte = 0;
572 int x, y, i, byteNum = 0;
573 i = 0;
574 for (y = 0; y < 64; y++)
575 {
576 for (x = 0; x < 64; x++)
577 {
578 tempByte = Convert.ToByte(tempByte | Convert.ToByte(landBitmap[x, y]) << (i++%8));
579 if (i%8 == 0)
580 {
581 tempConvertArr[byteNum] = tempByte;
582 tempByte = (byte) 0;
583 i = 0;
584 byteNum++;
585 }
586 }
587 }
588 return tempConvertArr;
589 }
590
591 private bool[,] convertBytesToLandBitmap()
592 {
593 bool[,] tempConvertMap = new bool[64,64];
594 tempConvertMap.Initialize();
595 byte tempByte = 0;
596 int x = 0, y = 0, i = 0, bitNum = 0;
597 for (i = 0; i < 512; i++)
598 {
599 tempByte = landData.landBitmapByteArray[i];
600 for (bitNum = 0; bitNum < 8; bitNum++)
601 {
602 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
603 tempConvertMap[x, y] = bit;
604 x++;
605 if (x > 63)
606 {
607 x = 0;
608 y++;
609 }
610 }
611 }
612 return tempConvertMap;
613 }
614
615 /// <summary>
616 /// Full sim land object creation
617 /// </summary>
618 /// <returns></returns>
619 public bool[,] basicFullRegionLandBitmap()
620 {
621 return getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize);
622 }
623
624 /// <summary>
625 /// Used to modify the bitmap between the x and y points. Points use 64 scale
626 /// </summary>
627 /// <param name="start_x"></param>
628 /// <param name="start_y"></param>
629 /// <param name="end_x"></param>
630 /// <param name="end_y"></param>
631 /// <returns></returns>
632 public bool[,] getSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
633 {
634 bool[,] tempBitmap = new bool[64,64];
635 tempBitmap.Initialize();
636
637 tempBitmap = modifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
638 return tempBitmap;
639 }
640
641 /// <summary>
642 /// Change a land bitmap at within a square and set those points to a specific value
643 /// </summary>
644 /// <param name="land_bitmap"></param>
645 /// <param name="start_x"></param>
646 /// <param name="start_y"></param>
647 /// <param name="end_x"></param>
648 /// <param name="end_y"></param>
649 /// <param name="set_value"></param>
650 /// <returns></returns>
651 public bool[,] modifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
652 bool set_value)
653 {
654 if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
655 {
656 //Throw an exception - The bitmap is not 64x64
657 //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
658 }
659
660 int x, y;
661 for (y = 0; y < 64; y++)
662 {
663 for (x = 0; x < 64; x++)
664 {
665 if (x >= start_x/4 && x < end_x/4
666 && y >= start_y/4 && y < end_y/4)
667 {
668 land_bitmap[x, y] = set_value;
669 }
670 }
671 }
672 return land_bitmap;
673 }
674
675 /// <summary>
676 /// Join the true values of 2 bitmaps together
677 /// </summary>
678 /// <param name="bitmap_base"></param>
679 /// <param name="bitmap_add"></param>
680 /// <returns></returns>
681 public bool[,] mergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
682 {
683 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2)
684 {
685 //Throw an exception - The bitmap is not 64x64
686 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps");
687 }
688 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
689 {
690 //Throw an exception - The bitmap is not 64x64
691 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
692 }
693
694 int x, y;
695 for (y = 0; y < 64; y++)
696 {
697 for (x = 0; x < 64; x++)
698 {
699 if (bitmap_add[x, y])
700 {
701 bitmap_base[x, y] = true;
702 }
703 }
704 }
705 return bitmap_base;
706 }
707
708 #endregion
709
710 #region Object Select and Object Owner Listing
711
712 public void sendForceObjectSelect(int local_id, int request_type, IClientAPI remote_client)
713 {
714 List<uint> resultLocalIDs = new List<uint>();
715 foreach (SceneObjectGroup obj in primsOverMe)
716 {
717 if (obj.LocalId > 0)
718 {
719 if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == landData.ownerID)
720 {
721 resultLocalIDs.Add(obj.LocalId);
722 }
723 // else if (request_type == LandManager.LAND_SELECT_OBJECTS_GROUP && ...) // TODO: group support
724 // {
725 // }
726 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
727 obj.OwnerID != remote_client.AgentId)
728 {
729 resultLocalIDs.Add(obj.LocalId);
730 }
731 }
732 }
733
734
735 bool firstCall = true;
736 int MAX_OBJECTS_PER_PACKET = 251;
737 ForceObjectSelectPacket pack = (ForceObjectSelectPacket) PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
738 // TODO: don't create new blocks if recycling an old packet
739 ForceObjectSelectPacket.DataBlock[] data;
740 while (resultLocalIDs.Count > 0)
741 {
742 if (firstCall)
743 {
744 pack._Header.ResetList = true;
745 firstCall = false;
746 }
747 else
748 {
749 pack._Header.ResetList = false;
750 }
751
752 if (resultLocalIDs.Count > MAX_OBJECTS_PER_PACKET)
753 {
754 data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET];
755 }
756 else
757 {
758 data = new ForceObjectSelectPacket.DataBlock[resultLocalIDs.Count];
759 }
760
761 int i;
762 for (i = 0; i < MAX_OBJECTS_PER_PACKET && resultLocalIDs.Count > 0; i++)
763 {
764 data[i] = new ForceObjectSelectPacket.DataBlock();
765 data[i].LocalID = Convert.ToUInt32(resultLocalIDs[0]);
766 resultLocalIDs.RemoveAt(0);
767 }
768 pack.Data = data;
769 remote_client.OutPacket((Packet) pack, ThrottleOutPacketType.Task);
770 }
771 }
772
773 /// <summary>
774 /// Notify the parcel owner each avatar that owns prims situated on their land. This notification includes
775 /// aggreagete details such as the number of prims.
776 ///
777 /// </summary>
778 /// <param name="remote_client">
779 /// A <see cref="IClientAPI"/>
780 /// </param>
781 public void sendLandObjectOwners(IClientAPI remote_client)
782 {
783 Dictionary<LLUUID, int> primCount = new Dictionary<LLUUID, int>();
784 ParcelObjectOwnersReplyPacket pack
785 = (ParcelObjectOwnersReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply);
786 // TODO: don't create new blocks if recycling an old packet
787
788 foreach (SceneObjectGroup obj in primsOverMe)
789 {
790 try
791 {
792 if (!primCount.ContainsKey(obj.OwnerID))
793 {
794 primCount.Add(obj.OwnerID, 0);
795 }
796 }
797 catch (NullReferenceException)
798 {
799 m_log.Info("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel");
800 }
801 try
802 {
803 primCount[obj.OwnerID] += obj.PrimCount;
804 }
805 catch (KeyNotFoundException)
806 {
807 m_log.Error("[LAND]: Unable to match a prim with it's owner.");
808 }
809 }
810
811 int notifyCount = primCount.Count;
812
813 if (notifyCount > 0)
814 {
815 if (notifyCount > 32)
816 {
817 m_log.InfoFormat(
818 "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}"
819 + " - a developer might want to investigate whether this is a hard limit", 32);
820
821 notifyCount = 32;
822 }
823
824 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock
825 = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount];
826
827 int num = 0;
828 foreach (LLUUID owner in primCount.Keys)
829 {
830 dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock();
831 dataBlock[num].Count = primCount[owner];
832 dataBlock[num].IsGroupOwned = false; //TODO: fix me when group support is added
833 dataBlock[num].OnlineStatus = true; //TODO: fix me later
834 dataBlock[num].OwnerID = owner;
835
836 num++;
837
838 if (num >= notifyCount)
839 {
840 break;
841 }
842 }
843
844 pack.Data = dataBlock;
845 }
846
847 remote_client.OutPacket(pack, ThrottleOutPacketType.Task);
848 }
849
850 public Dictionary<LLUUID, int> getLandObjectOwners()
851 {
852 Dictionary<LLUUID, int> ownersAndCount = new Dictionary<LLUUID, int>();
853 foreach (SceneObjectGroup obj in primsOverMe)
854 {
855 if (!ownersAndCount.ContainsKey(obj.OwnerID))
856 {
857 ownersAndCount.Add(obj.OwnerID, 0);
858 }
859 ownersAndCount[obj.OwnerID] += obj.PrimCount;
860 }
861 return ownersAndCount;
862 }
863
864 #endregion
865
866 #region Object Returning
867
868 public void returnObject(SceneObjectGroup obj)
869 {
870 }
871
872 public void returnLandObjects(int type, LLUUID owner)
873 {
874 }
875
876 #endregion
877
878 #region Object Adding/Removing from Parcel
879
880 public void resetLandPrimCounts()
881 {
882 landData.groupPrims = 0;
883 landData.ownerPrims = 0;
884 landData.otherPrims = 0;
885 landData.selectedPrims = 0;
886 primsOverMe.Clear();
887 }
888
889 public void addPrimToCount(SceneObjectGroup obj)
890 {
891 LLUUID prim_owner = obj.OwnerID;
892 int prim_count = obj.PrimCount;
893
894 if (obj.IsSelected)
895 {
896 landData.selectedPrims += prim_count;
897 }
898 else
899 {
900 if (prim_owner == landData.ownerID)
901 {
902 landData.ownerPrims += prim_count;
903 }
904 else
905 {
906 landData.otherPrims += prim_count;
907 }
908 }
909
910 primsOverMe.Add(obj);
911 }
912
913 public void removePrimFromCount(SceneObjectGroup obj)
914 {
915 if (primsOverMe.Contains(obj))
916 {
917 LLUUID prim_owner = obj.OwnerID;
918 int prim_count = obj.PrimCount;
919
920 if (prim_owner == landData.ownerID)
921 {
922 landData.ownerPrims -= prim_count;
923 }
924 else if (prim_owner == landData.groupID)
925 {
926 landData.groupPrims -= prim_count;
927 }
928 else
929 {
930 landData.otherPrims -= prim_count;
931 }
932
933 primsOverMe.Remove(obj);
934 }
935 }
936
937 #endregion
938
939 #endregion
940
941
942 }
943} \ No newline at end of file