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