aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/World/Land
diff options
context:
space:
mode:
authorAdam Frisby2008-04-30 21:22:29 +0000
committerAdam Frisby2008-04-30 21:22:29 +0000
commit4a8c1e4393ac64c84b03aeb16bacb9ddd0a2fae6 (patch)
tree49dde0575502e89aeed428b4190c68306e929b69 /OpenSim/Region/Environment/Modules/World/Land
parent* Previous commit managed to miss some files despite me hitting 'Select all'. (diff)
downloadopensim-SC-4a8c1e4393ac64c84b03aeb16bacb9ddd0a2fae6.zip
opensim-SC-4a8c1e4393ac64c84b03aeb16bacb9ddd0a2fae6.tar.gz
opensim-SC-4a8c1e4393ac64c84b03aeb16bacb9ddd0a2fae6.tar.bz2
opensim-SC-4a8c1e4393ac64c84b03aeb16bacb9ddd0a2fae6.tar.xz
* Commiting a bunch of missed files.
Diffstat (limited to 'OpenSim/Region/Environment/Modules/World/Land')
-rw-r--r--OpenSim/Region/Environment/Modules/World/Land/LandChannel.cs1008
-rw-r--r--OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs86
-rw-r--r--OpenSim/Region/Environment/Modules/World/Land/LandObject.cs943
3 files changed, 2037 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/World/Land/LandChannel.cs b/OpenSim/Region/Environment/Modules/World/Land/LandChannel.cs
new file mode 100644
index 0000000..cbea07a
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/World/Land/LandChannel.cs
@@ -0,0 +1,1008 @@
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 Axiom.Math;
31using libsecondlife;
32using libsecondlife.Packets;
33using OpenSim.Framework;
34using OpenSim.Region.Environment.Interfaces;
35using OpenSim.Region.Environment.Scenes;
36using OpenSim.Region.Physics.Manager;
37
38namespace OpenSim.Region.Environment.Modules.World.Land
39{
40 public class LandChannel : ILandChannel
41 {
42 #region Constants
43
44 //Land types set with flags in ParcelOverlay.
45 //Only one of these can be used.
46 public const byte LAND_TYPE_PUBLIC = (byte)0; //Equals 00000000
47 public const byte LAND_TYPE_OWNED_BY_OTHER = (byte)1; //Equals 00000001
48 public const byte LAND_TYPE_OWNED_BY_GROUP = (byte)2; //Equals 00000010
49 public const byte LAND_TYPE_OWNED_BY_REQUESTER = (byte)3; //Equals 00000011
50 public const byte LAND_TYPE_IS_FOR_SALE = (byte)4; //Equals 00000100
51 public const byte LAND_TYPE_IS_BEING_AUCTIONED = (byte)5; //Equals 00000101
52
53 //Flags that when set, a border on the given side will be placed
54 //NOTE: North and East is assumable by the west and south sides (if land to east has a west border, then I have an east border; etc)
55 //This took forever to figure out -- jeesh. /blame LL for even having to send these
56 public const byte LAND_FLAG_PROPERTY_BORDER_WEST = (byte)64; //Equals 01000000
57 public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = (byte)128; //Equals 10000000
58
59 //RequestResults (I think these are right, they seem to work):
60 public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land
61 public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land
62
63 //ParcelSelectObjects
64 public const int LAND_SELECT_OBJECTS_OWNER = 2;
65 public const int LAND_SELECT_OBJECTS_GROUP = 4;
66 public const int LAND_SELECT_OBJECTS_OTHER = 8;
67
68 //These are other constants. Yay!
69 public const int START_LAND_LOCAL_ID = 1;
70
71 public const float BAN_LINE_SAFETY_HIEGHT = 100;
72
73 #endregion
74
75 private Scene m_scene;
76
77 private Dictionary<int, ILandObject> landList = new Dictionary<int, ILandObject>();
78 private int lastLandLocalID = START_LAND_LOCAL_ID - 1;
79 private int[,] landIDList = new int[64, 64];
80
81 private bool landPrimCountTainted = false;
82
83 private bool m_allowedForcefulBans = true;
84 public bool allowedForcefulBans
85 {
86 get
87 {
88 return m_allowedForcefulBans;
89 }
90 set
91 {
92 m_allowedForcefulBans = value;
93 }
94 }
95
96 public LandChannel(Scene scene)
97 {
98 m_scene = scene;
99 landIDList.Initialize();
100 }
101 #region Land Object From Storage Functions
102
103 public void IncomingLandObjectsFromStorage(List<LandData> data)
104 {
105 for (int i = 0; i < data.Count; i++)
106 {
107 //try
108 //{
109 IncomingLandObjectFromStorage(data[i]);
110 //}
111 //catch (Exception ex)
112 //{
113 //m_log.Error("[LandManager]: IncomingLandObjectsFromStorage: Exception: " + ex.ToString());
114 //throw ex;
115 //}
116 }
117 //foreach (LandData parcel in data)
118 //{
119 // IncomingLandObjectFromStorage(parcel);
120 //}
121 }
122
123 public void IncomingLandObjectFromStorage(LandData data)
124 {
125 ILandObject new_land = new LandObject(data.ownerID, data.isGroupOwned, m_scene);
126 new_land.landData = data.Copy();
127 new_land.setLandBitmapFromByteArray();
128 addLandObject(new_land);
129 }
130
131 public void NoLandDataFromStorage()
132 {
133 resetSimLandObjects();
134 }
135
136 #endregion
137
138 #region Parcel Add/Remove/Get/Create
139
140 /// <summary>
141 /// Creates a basic Parcel object without an owner (a zeroed key)
142 /// </summary>
143 /// <returns></returns>
144 public ILandObject createBaseLand()
145 {
146 return new LandObject(LLUUID.Zero, false, m_scene);
147 }
148
149 /// <summary>
150 /// Adds a land object to the stored list and adds them to the landIDList to what they own
151 /// </summary>
152 /// <param name="new_land">The land object being added</param>
153 public ILandObject addLandObject(ILandObject new_land)
154 {
155 lastLandLocalID++;
156 new_land.landData.localID = lastLandLocalID;
157 landList.Add(lastLandLocalID, (LandObject)new_land.Copy());
158
159
160 bool[,] landBitmap = new_land.getLandBitmap();
161 int x, y;
162 for (x = 0; x < 64; x++)
163 {
164 for (y = 0; y < 64; y++)
165 {
166 if (landBitmap[x, y])
167 {
168 landIDList[x, y] = lastLandLocalID;
169 }
170 }
171 }
172 landList[lastLandLocalID].forceUpdateLandInfo();
173 m_scene.EventManager.TriggerLandObjectAdded(new_land);
174 return new_land;
175 }
176
177 /// <summary>
178 /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
179 /// </summary>
180 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
181 public void removeLandObject(int local_id)
182 {
183 int x, y;
184 for (x = 0; x < 64; x++)
185 {
186 for (y = 0; y < 64; y++)
187 {
188 if (landIDList[x, y] == local_id)
189 {
190 return;
191 //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
192 }
193 }
194 }
195
196 m_scene.EventManager.TriggerLandObjectRemoved(landList[local_id].landData.globalID);
197 landList.Remove(local_id);
198 }
199
200 public void updateLandObject(int local_id, LandData newData)
201 {
202 if (landList.ContainsKey(local_id))
203 {
204 landList[local_id].landData = newData.Copy();
205 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, landList[local_id]);
206 }
207 }
208
209 private void performFinalLandJoin(ILandObject master, ILandObject slave)
210 {
211 int x, y;
212 bool[,] landBitmapSlave = slave.getLandBitmap();
213 for (x = 0; x < 64; x++)
214 {
215 for (y = 0; y < 64; y++)
216 {
217 if (landBitmapSlave[x, y])
218 {
219 landIDList[x, y] = master.landData.localID;
220 }
221 }
222 }
223
224 removeLandObject(slave.landData.localID);
225 updateLandObject(master.landData.localID, master.landData);
226 }
227
228 /// <summary>
229 /// Get the land object at the specified point
230 /// </summary>
231 /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
232 /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
233 /// <returns>Land object at the point supplied</returns>
234 public ILandObject getLandObject(float x_float, float y_float)
235 {
236 int x;
237 int y;
238
239 try
240 {
241 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / Convert.ToDouble(4.0)));
242 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / Convert.ToDouble(4.0)));
243 }
244 catch (OverflowException)
245 {
246 return null;
247 }
248
249 if (x >= 64 || y >= 64 || x < 0 || y < 0)
250 {
251 return null;
252 }
253 else
254 {
255 return landList[landIDList[x, y]];
256 }
257 }
258
259 public ILandObject getLandObject(int parcelLocalID)
260 {
261 lock (landList)
262 {
263 if (landList.ContainsKey(parcelLocalID))
264 {
265 return landList[parcelLocalID];
266 }
267 }
268 return null;
269 }
270
271 public ILandObject getLandObject(int x, int y)
272 {
273 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0)
274 {
275 // These exceptions here will cause a lot of complaints from the users specifically because
276 // they happen every time at border crossings
277 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
278 }
279 else
280 {
281 return landList[landIDList[x / 4, y / 4]];
282 }
283 }
284
285 #endregion
286
287 #region Parcel Modification
288
289 /// <summary>
290 /// Subdivides a piece of land
291 /// </summary>
292 /// <param name="start_x">West Point</param>
293 /// <param name="start_y">South Point</param>
294 /// <param name="end_x">East Point</param>
295 /// <param name="end_y">North Point</param>
296 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
297 /// <returns>Returns true if successful</returns>
298 private bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
299 {
300 //First, lets loop through the points and make sure they are all in the same peice of land
301 //Get the land object at start
302 ILandObject startLandObject = null;
303 try
304 {
305 startLandObject = getLandObject(start_x, start_y);
306 }
307 catch (Exception)
308 {
309 //m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + start_x + " y:" + start_y);
310 }
311 if (startLandObject == null) return false; //No such land object at the beginning
312
313 //Loop through the points
314 try
315 {
316 int totalX = end_x - start_x;
317 int totalY = end_y - start_y;
318 int x, y;
319 for (y = 0; y < totalY; y++)
320 {
321 for (x = 0; x < totalX; x++)
322 {
323 ILandObject tempLandObject = getLandObject(start_x + x, start_y + y);
324 if (tempLandObject == null) return false; //No such land object at that point
325 if (tempLandObject != startLandObject) return false; //Subdividing over 2 land objects; no-no
326 }
327 }
328 }
329 catch (Exception)
330 {
331 return false; //Exception. For now, lets skip subdivision
332 }
333
334 //If we are still here, then they are subdividing within one piece of land
335 //Check owner
336 if (startLandObject.landData.ownerID != attempting_user_id)
337 {
338 return false; //They cant do this!
339 }
340
341 //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
342 ILandObject newLand = startLandObject.Copy();
343 newLand.landData.landName = "Subdivision of " + newLand.landData.landName;
344 newLand.landData.globalID = LLUUID.Random();
345
346 newLand.setLandBitmap(newLand.getSquareLandBitmap(start_x, start_y, end_x, end_y));
347
348 //Now, lets set the subdivision area of the original to false
349 int startLandObjectIndex = startLandObject.landData.localID;
350 landList[startLandObjectIndex].setLandBitmap(
351 newLand.modifyLandBitmapSquare(startLandObject.getLandBitmap(), start_x, start_y, end_x, end_y, false));
352 landList[startLandObjectIndex].forceUpdateLandInfo();
353
354 setPrimsTainted();
355
356 //Now add the new land object
357 ILandObject result = addLandObject(newLand);
358 updateLandObject(startLandObject.landData.localID, startLandObject.landData);
359 result.sendLandUpdateToAvatarsOverMe();
360
361
362 return true;
363 }
364
365 /// <summary>
366 /// Join 2 land objects together
367 /// </summary>
368 /// <param name="start_x">x value in first piece of land</param>
369 /// <param name="start_y">y value in first piece of land</param>
370 /// <param name="end_x">x value in second peice of land</param>
371 /// <param name="end_y">y value in second peice of land</param>
372 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the land objects</param>
373 /// <returns>Returns true if successful</returns>
374 private bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
375 {
376 end_x -= 4;
377 end_y -= 4;
378
379 List<ILandObject> selectedLandObjects = new List<ILandObject>();
380 int stepXSelected = 0;
381 int stepYSelected = 0;
382 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
383 {
384 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
385 {
386 ILandObject p = null;
387 try
388 {
389 p = getLandObject(stepXSelected, stepYSelected);
390 }
391 catch (Exception)
392 {
393 //m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + stepXSelected + " y:" + stepYSelected);
394 }
395 if (p != null)
396 {
397 if (!selectedLandObjects.Contains(p))
398 {
399 selectedLandObjects.Add(p);
400 }
401 }
402 }
403 }
404 ILandObject masterLandObject = selectedLandObjects[0];
405 selectedLandObjects.RemoveAt(0);
406
407
408 if (selectedLandObjects.Count < 1)
409 {
410 return false; //Only one piece of land selected
411 }
412 if (masterLandObject.landData.ownerID != attempting_user_id)
413 {
414 return false; //Not the same owner
415 }
416 foreach (ILandObject p in selectedLandObjects)
417 {
418 if (p.landData.ownerID != masterLandObject.landData.ownerID)
419 {
420 return false; //Over multiple users. TODO: make this just ignore this piece of land?
421 }
422 }
423 foreach (ILandObject slaveLandObject in selectedLandObjects)
424 {
425 landList[masterLandObject.landData.localID].setLandBitmap(
426 slaveLandObject.mergeLandBitmaps(masterLandObject.getLandBitmap(), slaveLandObject.getLandBitmap()));
427 performFinalLandJoin(masterLandObject, slaveLandObject);
428 }
429
430
431 setPrimsTainted();
432
433 masterLandObject.sendLandUpdateToAvatarsOverMe();
434
435 return true;
436 }
437
438 public void resetAllLandPrimCounts()
439 {
440 foreach (LandObject p in landList.Values)
441 {
442 p.resetLandPrimCounts();
443 }
444 }
445
446 public void setPrimsTainted()
447 {
448 landPrimCountTainted = true;
449 }
450
451 public bool isLandPrimCountTainted()
452 {
453 return landPrimCountTainted;
454 }
455
456 public void addPrimToLandPrimCounts(SceneObjectGroup obj)
457 {
458 LLVector3 position = obj.AbsolutePosition;
459 ILandObject landUnderPrim = getLandObject(position.X, position.Y);
460 if (landUnderPrim != null)
461 {
462 landUnderPrim.addPrimToCount(obj);
463 }
464 }
465
466 public void removePrimFromLandPrimCounts(SceneObjectGroup obj)
467 {
468 foreach (LandObject p in landList.Values)
469 {
470 p.removePrimFromCount(obj);
471 }
472 }
473
474 public void finalizeLandPrimCountUpdate()
475 {
476 //Get Simwide prim count for owner
477 Dictionary<LLUUID, List<LandObject>> landOwnersAndParcels = new Dictionary<LLUUID, List<LandObject>>();
478 foreach (LandObject p in landList.Values)
479 {
480 if (!landOwnersAndParcels.ContainsKey(p.landData.ownerID))
481 {
482 List<LandObject> tempList = new List<LandObject>();
483 tempList.Add(p);
484 landOwnersAndParcels.Add(p.landData.ownerID, tempList);
485 }
486 else
487 {
488 landOwnersAndParcels[p.landData.ownerID].Add(p);
489 }
490 }
491
492 foreach (LLUUID owner in landOwnersAndParcels.Keys)
493 {
494 int simArea = 0;
495 int simPrims = 0;
496 foreach (LandObject p in landOwnersAndParcels[owner])
497 {
498 simArea += p.landData.area;
499 simPrims += p.landData.ownerPrims + p.landData.otherPrims + p.landData.groupPrims +
500 p.landData.selectedPrims;
501 }
502
503 foreach (LandObject p in landOwnersAndParcels[owner])
504 {
505 p.landData.simwideArea = simArea;
506 p.landData.simwidePrims = simPrims;
507 }
508 }
509 }
510
511 public void updateLandPrimCounts()
512 {
513 foreach (EntityBase obj in m_scene.Entities.Values)
514 {
515 if (obj is SceneObjectGroup)
516 {
517 m_scene.EventManager.TriggerParcelPrimCountAdd((SceneObjectGroup)obj);
518 }
519 }
520 }
521
522 public void performParcelPrimCountUpdate()
523 {
524 resetAllLandPrimCounts();
525 m_scene.EventManager.TriggerParcelPrimCountUpdate();
526 finalizeLandPrimCountUpdate();
527 landPrimCountTainted = false;
528 }
529 #endregion
530
531 #region Parcel Updating
532
533 /// <summary>
534 /// Where we send the ParcelOverlay packet to the client
535 /// </summary>
536 /// <param name="remote_client">The object representing the client</param>
537 public void sendParcelOverlay(IClientAPI remote_client)
538 {
539 const int LAND_BLOCKS_PER_PACKET = 1024;
540 int x, y = 0;
541 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
542 int byteArrayCount = 0;
543 int sequenceID = 0;
544 ParcelOverlayPacket packet;
545
546 for (y = 0; y < 64; y++)
547 {
548 for (x = 0; x < 64; x++)
549 {
550 byte tempByte = (byte)0; //This represents the byte for the current 4x4
551 ILandObject currentParcelBlock = null;
552
553 try
554 {
555 currentParcelBlock = getLandObject(x * 4, y * 4);
556 }
557 catch (Exception)
558 {
559 //m_log.Warn("[LAND]: " + "unable to get land at x: " + (x * 4) + " y: " + (y * 4));
560 }
561
562
563 if (currentParcelBlock != null)
564 {
565 if (currentParcelBlock.landData.ownerID == remote_client.AgentId)
566 {
567 //Owner Flag
568 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_REQUESTER);
569 }
570 else if (currentParcelBlock.landData.salePrice > 0 &&
571 (currentParcelBlock.landData.authBuyerID == LLUUID.Zero ||
572 currentParcelBlock.landData.authBuyerID == remote_client.AgentId))
573 {
574 //Sale Flag
575 tempByte = Convert.ToByte(tempByte | LAND_TYPE_IS_FOR_SALE);
576 }
577 else if (currentParcelBlock.landData.ownerID == LLUUID.Zero)
578 {
579 //Public Flag
580 tempByte = Convert.ToByte(tempByte | LAND_TYPE_PUBLIC);
581 }
582 else
583 {
584 //Other Flag
585 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_OTHER);
586 }
587
588
589 //Now for border control
590 try
591 {
592 ILandObject westParcel = null;
593 ILandObject southParcel = null;
594 if (x > 0)
595 {
596 westParcel = getLandObject((x - 1) * 4, y * 4);
597 }
598 if (y > 0)
599 {
600 southParcel = getLandObject(x * 4, (y - 1) * 4);
601 }
602
603 if (x == 0)
604 {
605 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
606 }
607 else if (westParcel != null && westParcel != currentParcelBlock)
608 {
609 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
610 }
611
612 if (y == 0)
613 {
614 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
615 }
616 else if (southParcel != null && southParcel != currentParcelBlock)
617 {
618 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
619 }
620
621 byteArray[byteArrayCount] = tempByte;
622 byteArrayCount++;
623 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
624 {
625 byteArrayCount = 0;
626 packet = (ParcelOverlayPacket)PacketPool.Instance.GetPacket(PacketType.ParcelOverlay);
627 packet.ParcelData.Data = byteArray;
628 packet.ParcelData.SequenceID = sequenceID;
629 remote_client.OutPacket((Packet)packet, ThrottleOutPacketType.Task);
630 sequenceID++;
631 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
632 }
633 }
634 catch (Exception)
635 {
636 //m_log.Debug("[LAND]: Skipped Land checks because avatar is out of bounds: " + e.Message);
637 }
638 }
639 }
640 }
641 }
642
643 public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
644 bool snap_selection, IClientAPI remote_client)
645 {
646 //Get the land objects within the bounds
647 List<ILandObject> temp = new List<ILandObject>();
648 int x, y, i;
649 int inc_x = end_x - start_x;
650 int inc_y = end_y - start_y;
651 for (x = 0; x < inc_x; x++)
652 {
653 for (y = 0; y < inc_y; y++)
654 {
655
656 ILandObject currentParcel = null;
657 try
658 {
659 currentParcel = getLandObject(start_x + x, start_y + y);
660 }
661 catch (Exception)
662 {
663 //m_log.Warn("[LAND]: " + "unable to get land at x: " + (start_x + x) + " y: " + (start_y + y));
664 }
665 if (currentParcel != null)
666 {
667 if (!temp.Contains(currentParcel))
668 {
669 currentParcel.forceUpdateLandInfo();
670 temp.Add(currentParcel);
671 }
672 }
673 }
674 }
675
676 int requestResult = LAND_RESULT_SINGLE;
677 if (temp.Count > 1)
678 {
679 requestResult = LAND_RESULT_MULTIPLE;
680 }
681
682 for (i = 0; i < temp.Count; i++)
683 {
684 temp[i].sendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
685 }
686
687
688 sendParcelOverlay(remote_client);
689 }
690
691 public void handleParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
692 {
693 if (landList.ContainsKey(packet.ParcelData.LocalID))
694 {
695 landList[packet.ParcelData.LocalID].updateLandProperties(packet, remote_client);
696
697 }
698 }
699
700 public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
701 {
702 subdivide(west, south, east, north, remote_client.AgentId);
703 }
704
705 public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
706 {
707 join(west, south, east, north, remote_client.AgentId);
708 }
709
710 public void handleParcelSelectObjectsRequest(int local_id, int request_type, IClientAPI remote_client)
711 {
712 landList[local_id].sendForceObjectSelect(local_id, request_type, remote_client);
713 }
714
715 public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client)
716 {
717 landList[local_id].sendLandObjectOwners(remote_client);
718 }
719
720 #endregion
721
722 /// <summary>
723 /// Resets the sim to the default land object (full sim piece of land owned by the default user)
724 /// </summary>
725 public void resetSimLandObjects()
726 {
727 //Remove all the land objects in the sim and add a blank, full sim land object set to public
728 landList.Clear();
729 lastLandLocalID = START_LAND_LOCAL_ID - 1;
730 landIDList.Initialize();
731
732 ILandObject fullSimParcel = new LandObject(LLUUID.Zero, false, m_scene);
733
734 fullSimParcel.setLandBitmap(fullSimParcel.getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
735 fullSimParcel.landData.ownerID = m_scene.RegionInfo.MasterAvatarAssignedUUID;
736
737 addLandObject(fullSimParcel);
738 }
739
740 public List<ILandObject> parcelsNearPoint(LLVector3 position)
741 {
742 List<ILandObject> parcelsNear = new List<ILandObject>();
743 int x, y;
744 for (x = -4; x <= 4; x += 4)
745 {
746 for (y = -4; y <= 4; y += 4)
747 {
748 ILandObject check = getLandObject(position.X + x, position.Y + y);
749 if (check != null)
750 {
751 if (!parcelsNear.Contains(check))
752 {
753 parcelsNear.Add(check);
754 }
755 }
756 }
757 }
758
759 return parcelsNear;
760 }
761
762 public void sendYouAreBannedNotice(ScenePresence avatar)
763 {
764 if (allowedForcefulBans)
765 {
766 avatar.ControllingClient.SendAlertMessage(
767 "You are not allowed on this parcel because you are banned. Please go away. <3 OpenSim Developers");
768
769 avatar.PhysicsActor.Position =
770 new PhysicsVector(avatar.lastKnownAllowedPosition.x, avatar.lastKnownAllowedPosition.y,
771 avatar.lastKnownAllowedPosition.z);
772 avatar.PhysicsActor.Velocity = new PhysicsVector(0, 0, 0);
773 }
774 else
775 {
776 avatar.ControllingClient.SendAlertMessage(
777 "You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim! <3 OpenSim Developers");
778 }
779 }
780
781 public void handleAvatarChangingParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
782 {
783 if (m_scene.RegionInfo.RegionID == regionID)
784 {
785 if (landList[localLandID] != null)
786 {
787 ILandObject parcelAvatarIsEntering = landList[localLandID];
788 if (avatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT)
789 {
790 if (parcelAvatarIsEntering.isBannedFromLand(avatar.UUID))
791 {
792 sendYouAreBannedNotice(avatar);
793 }
794 else if (parcelAvatarIsEntering.isRestrictedFromLand(avatar.UUID))
795 {
796 avatar.ControllingClient.SendAlertMessage(
797 "You are not allowed on this parcel because the land owner has restricted access. For now, you can enter, but please respect the land owner's decisions (or he can ban you!). <3 OpenSim Developers");
798 }
799 else
800 {
801 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
802 }
803 }
804 else
805 {
806 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
807 }
808 }
809 }
810 }
811
812 public void sendOutNearestBanLine(IClientAPI avatar)
813 {
814 List<ScenePresence> avatars = m_scene.GetAvatars();
815 foreach (ScenePresence presence in avatars)
816 {
817 if (presence.UUID == avatar.AgentId)
818 {
819
820 List<ILandObject> checkLandParcels = parcelsNearPoint(presence.AbsolutePosition);
821 foreach (ILandObject checkBan in checkLandParcels)
822 {
823 if (checkBan.isBannedFromLand(avatar.AgentId))
824 {
825 checkBan.sendLandProperties(-30000, false, (int)ParcelManager.ParcelResult.Single, avatar);
826 return; //Only send one
827 }
828 else if (checkBan.isRestrictedFromLand(avatar.AgentId))
829 {
830 checkBan.sendLandProperties(-40000, false, (int)ParcelManager.ParcelResult.Single, avatar);
831 return; //Only send one
832 }
833 }
834 return;
835 }
836 }
837 }
838
839 public void sendLandUpdate(ScenePresence avatar, bool force)
840 {
841 ILandObject over = null;
842 try
843 {
844 over = getLandObject((int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
845 (int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
846 }
847 catch (Exception)
848 {
849 //m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " + Math.Round(avatar.AbsolutePosition.Y));
850 }
851
852 if (over != null)
853 {
854 if (force)
855 {
856 if (!avatar.IsChildAgent)
857 {
858 over.sendLandUpdateToClient(avatar.ControllingClient);
859 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
860 m_scene.RegionInfo.RegionID);
861 }
862 }
863
864 if (avatar.currentParcelUUID != over.landData.globalID)
865 {
866 if (!avatar.IsChildAgent)
867 {
868 over.sendLandUpdateToClient(avatar.ControllingClient);
869 avatar.currentParcelUUID = over.landData.globalID;
870 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
871 m_scene.RegionInfo.RegionID);
872 }
873 }
874 }
875 }
876 public void sendLandUpdate(ScenePresence avatar)
877 {
878 sendLandUpdate(avatar, false);
879
880 }
881 public void handleSignificantClientMovement(IClientAPI remote_client)
882 {
883 ScenePresence clientAvatar = m_scene.GetScenePresence(remote_client.AgentId);
884
885 if (clientAvatar != null)
886 {
887 sendLandUpdate(clientAvatar);
888 sendOutNearestBanLine(remote_client);
889 ILandObject parcel = getLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y);
890 if (parcel != null)
891 {
892 if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
893 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown)
894 {
895 handleAvatarChangingParcel(clientAvatar, parcel.landData.localID, m_scene.RegionInfo.RegionID);
896 //They are going below the safety line!
897 if (!parcel.isBannedFromLand(clientAvatar.UUID))
898 {
899 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false;
900 }
901 }
902 else if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
903 parcel.isBannedFromLand(clientAvatar.UUID))
904 {
905 sendYouAreBannedNotice(clientAvatar);
906 }
907 }
908 }
909 }
910
911 public void handleAnyClientMovement(ScenePresence avatar)
912 //Like handleSignificantClientMovement, but called with an AgentUpdate regardless of distance.
913 {
914 ILandObject over = getLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
915 if (over != null)
916 {
917 if (!over.isBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= BAN_LINE_SAFETY_HIEGHT)
918 {
919 avatar.lastKnownAllowedPosition =
920 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
921 }
922 }
923 }
924
925
926 public void handleParcelAccessRequest(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID,
927 int landLocalID, IClientAPI remote_client)
928 {
929 if (landList.ContainsKey(landLocalID))
930 {
931 landList[landLocalID].sendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
932 }
933 }
934
935 public void handleParcelAccessUpdateRequest(LLUUID agentID, LLUUID sessionID, uint flags, int landLocalID,
936 List<ParcelManager.ParcelAccessEntry> entries,
937 IClientAPI remote_client)
938 {
939 if (landList.ContainsKey(landLocalID))
940 {
941 if (agentID == landList[landLocalID].landData.ownerID)
942 {
943 landList[landLocalID].updateAccessList(flags, entries, remote_client);
944 }
945 }
946 else
947 {
948 Console.WriteLine("INVALID LOCAL LAND ID");
949 }
950 }
951
952 // If the economy has been validated by the economy module,
953 // and land has been validated as well, this method transfers
954 // the land ownership
955
956 public void handleLandBuyRequest(Object o, EventManager.LandBuyArgs e)
957 {
958 if (e.economyValidated && e.landValidated)
959 {
960 lock (landList)
961 {
962 if (landList.ContainsKey(e.parcelLocalID))
963 {
964 landList[e.parcelLocalID].updateLandSold(e.agentId, e.groupId, e.groupOwned, (uint)e.transactionID, e.parcelPrice, e.parcelArea);
965 return;
966 }
967 }
968 }
969 }
970
971 // After receiving a land buy packet, first the data needs to
972 // be validated. This method validates the right to buy the
973 // parcel
974
975 public void handleLandValidationRequest(Object o, EventManager.LandBuyArgs e)
976 {
977 if (e.landValidated == false)
978 {
979 ILandObject lob = null;
980 lock (landList)
981 {
982 if (landList.ContainsKey(e.parcelLocalID))
983 {
984 lob = landList[e.parcelLocalID];
985 }
986 }
987 if (lob != null)
988 {
989 LLUUID AuthorizedID = lob.landData.authBuyerID;
990 int saleprice = lob.landData.salePrice;
991 LLUUID pOwnerID = lob.landData.ownerID;
992
993 bool landforsale = ((lob.landData.landFlags & (uint)(Parcel.ParcelFlags.ForSale | Parcel.ParcelFlags.ForSaleObjects | Parcel.ParcelFlags.SellParcelObjects)) != 0);
994 if ((AuthorizedID == LLUUID.Zero || AuthorizedID == e.agentId) && e.parcelPrice >= saleprice && landforsale)
995 {
996 lock (e)
997 {
998 e.parcelOwnerID = pOwnerID;
999 e.landValidated = true;
1000
1001 }
1002
1003 }
1004 }
1005 }
1006 }
1007 }
1008} \ No newline at end of file
diff --git a/OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs b/OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs
new file mode 100644
index 0000000..c5ffdca
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/World/Land/LandManagementModule.cs
@@ -0,0 +1,86 @@
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 Nini.Config;
29using OpenSim.Region.Environment.Interfaces;
30using OpenSim.Region.Environment.Modules.World.Land;
31using OpenSim.Region.Environment.Scenes;
32
33namespace OpenSim.Region.Environment.Modules.World.Land
34{
35 public class LandManagementModule : IRegionModule
36 {
37 private LandChannel landChannel;
38 private Scene m_scene;
39
40 #region IRegionModule Members
41
42 public void Initialise(Scene scene, IConfigSource source)
43 {
44 m_scene = scene;
45 landChannel = new LandChannel(scene);
46
47 m_scene.EventManager.OnParcelPrimCountAdd += landChannel.addPrimToLandPrimCounts;
48 m_scene.EventManager.OnParcelPrimCountUpdate += landChannel.updateLandPrimCounts;
49 m_scene.EventManager.OnAvatarEnteringNewParcel += new EventManager.AvatarEnteringNewParcel(landChannel.handleAvatarChangingParcel);
50 m_scene.EventManager.OnClientMovement += new EventManager.ClientMovement(landChannel.handleAnyClientMovement);
51 m_scene.EventManager.OnValidateLandBuy += landChannel.handleLandValidationRequest;
52 m_scene.EventManager.OnLandBuy += landChannel.handleLandBuyRequest;
53
54 lock (m_scene)
55 {
56 m_scene.LandChannel = (ILandChannel)landChannel;
57 }
58 }
59
60 public void PostInitialise()
61 {
62
63 }
64
65 public void Close()
66 {
67
68 }
69
70 public string Name
71 {
72 get { return "LandManagementModule"; }
73 }
74
75 public bool IsSharedModule
76 {
77 get { return false; }
78 }
79
80
81
82
83
84 #endregion
85 }
86} \ No newline at end of file
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