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