aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/LandManagement
diff options
context:
space:
mode:
authormingchen2008-03-22 23:10:22 +0000
committermingchen2008-03-22 23:10:22 +0000
commit71ca162821ac0e5aae5f91c433b91549ae6d5419 (patch)
treefa2f13c2541075aba6807fcf95364466a785bd51 /OpenSim/Region/Environment/Modules/LandManagement
parentImplements llLoopSound(), llStopSound(), and llAdjustSoundVolume(). (diff)
downloadopensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.zip
opensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.tar.gz
opensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.tar.bz2
opensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.tar.xz
*Moved LandManagement into its own region module (spiffy!)
Diffstat (limited to 'OpenSim/Region/Environment/Modules/LandManagement')
-rw-r--r--OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs916
-rw-r--r--OpenSim/Region/Environment/Modules/LandManagement/LandManagementModule.cs62
-rw-r--r--OpenSim/Region/Environment/Modules/LandManagement/LandObject.cs879
3 files changed, 1857 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs b/OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs
new file mode 100644
index 0000000..ba0c550
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/LandManagement/LandChannel.cs
@@ -0,0 +1,916 @@
1using System;
2using System.Collections.Generic;
3using System.Text;
4
5using Axiom.Math;
6using libsecondlife;
7using libsecondlife.Packets;
8using OpenSim.Framework;
9using OpenSim.Framework.Console;
10using OpenSim.Region.Environment.Scenes;
11using OpenSim.Region.Environment.Interfaces;
12using OpenSim.Region.Physics.Manager;
13
14namespace OpenSim.Region.Environment.Modules.LandManagement
15{
16 public class LandChannel : ILandChannel
17 {
18 #region Constants
19
20 //Land types set with flags in ParcelOverlay.
21 //Only one of these can be used.
22 public const byte LAND_TYPE_PUBLIC = (byte)0; //Equals 00000000
23 public const byte LAND_TYPE_OWNED_BY_OTHER = (byte)1; //Equals 00000001
24 public const byte LAND_TYPE_OWNED_BY_GROUP = (byte)2; //Equals 00000010
25 public const byte LAND_TYPE_OWNED_BY_REQUESTER = (byte)3; //Equals 00000011
26 public const byte LAND_TYPE_IS_FOR_SALE = (byte)4; //Equals 00000100
27 public const byte LAND_TYPE_IS_BEING_AUCTIONED = (byte)5; //Equals 00000101
28
29 //Flags that when set, a border on the given side will be placed
30 //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)
31 //This took forever to figure out -- jeesh. /blame LL for even having to send these
32 public const byte LAND_FLAG_PROPERTY_BORDER_WEST = (byte)64; //Equals 01000000
33 public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = (byte)128; //Equals 10000000
34
35 //RequestResults (I think these are right, they seem to work):
36 public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land
37 public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land
38
39 //ParcelSelectObjects
40 public const int LAND_SELECT_OBJECTS_OWNER = 2;
41 public const int LAND_SELECT_OBJECTS_GROUP = 4;
42 public const int LAND_SELECT_OBJECTS_OTHER = 8;
43
44 //These are other constants. Yay!
45 public const int START_LAND_LOCAL_ID = 1;
46
47 public const float BAN_LINE_SAFETY_HIEGHT = 100;
48
49 #endregion
50
51 private Scene m_scene;
52
53 private Dictionary<int, ILandObject> landList = new Dictionary<int, ILandObject>();
54 private int lastLandLocalID = START_LAND_LOCAL_ID - 1;
55 private int[,] landIDList = new int[64, 64];
56
57 private bool landPrimCountTainted = false;
58
59 private bool m_allowedForcefulBans = true;
60 public bool allowedForcefulBans
61 {
62 get
63 {
64 return m_allowedForcefulBans;
65 }
66 set
67 {
68 m_allowedForcefulBans = value;
69 }
70 }
71
72 public LandChannel(Scene scene)
73 {
74 m_scene = scene;
75 landIDList.Initialize();
76 }
77 #region Land Object From Storage Functions
78
79 public void IncomingLandObjectsFromStorage(List<LandData> data)
80 {
81 for (int i = 0; i < data.Count; i++)
82 {
83 //try
84 //{
85 IncomingLandObjectFromStorage(data[i]);
86 //}
87 //catch (Exception ex)
88 //{
89 //m_log.Error("[LandManager]: IncomingLandObjectsFromStorage: Exception: " + ex.ToString());
90 //throw ex;
91 //}
92 }
93 //foreach (LandData parcel in data)
94 //{
95 // IncomingLandObjectFromStorage(parcel);
96 //}
97 }
98
99 public void IncomingLandObjectFromStorage(LandData data)
100 {
101 ILandObject new_land = new LandObject(data.ownerID, data.isGroupOwned, m_scene);
102 new_land.landData = data.Copy();
103 new_land.setLandBitmapFromByteArray();
104 addLandObject(new_land);
105 }
106
107 public void NoLandDataFromStorage()
108 {
109 resetSimLandObjects();
110 }
111
112 #endregion
113
114 #region Parcel Add/Remove/Get/Create
115
116 /// <summary>
117 /// Creates a basic Parcel object without an owner (a zeroed key)
118 /// </summary>
119 /// <returns></returns>
120 public ILandObject createBaseLand()
121 {
122 return new LandObject(LLUUID.Zero, false, m_scene);
123 }
124
125 /// <summary>
126 /// Adds a land object to the stored list and adds them to the landIDList to what they own
127 /// </summary>
128 /// <param name="new_land">The land object being added</param>
129 public ILandObject addLandObject(ILandObject new_land)
130 {
131 lastLandLocalID++;
132 new_land.landData.localID = lastLandLocalID;
133 landList.Add(lastLandLocalID, (LandObject)new_land.Copy());
134
135
136 bool[,] landBitmap = new_land.getLandBitmap();
137 int x, y;
138 for (x = 0; x < 64; x++)
139 {
140 for (y = 0; y < 64; y++)
141 {
142 if (landBitmap[x, y])
143 {
144 landIDList[x, y] = lastLandLocalID;
145 }
146 }
147 }
148 landList[lastLandLocalID].forceUpdateLandInfo();
149 m_scene.EventManager.TriggerLandObjectAdded(new_land);
150 return new_land;
151 }
152
153 /// <summary>
154 /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
155 /// </summary>
156 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
157 public void removeLandObject(int local_id)
158 {
159 int x, y;
160 for (x = 0; x < 64; x++)
161 {
162 for (y = 0; y < 64; y++)
163 {
164 if (landIDList[x, y] == local_id)
165 {
166 return;
167 //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
168 }
169 }
170 }
171
172 m_scene.EventManager.TriggerLandObjectRemoved(landList[local_id].landData.globalID);
173 landList.Remove(local_id);
174 }
175
176 public void updateLandObject(int local_id, LandData newData)
177 {
178 if (landList.ContainsKey(local_id))
179 {
180 landList[local_id].landData = newData.Copy();
181 m_scene.EventManager.TriggerLandObjectUpdated((uint)local_id, landList[local_id]);
182 }
183 }
184
185 private void performFinalLandJoin(ILandObject master, ILandObject slave)
186 {
187 int x, y;
188 bool[,] landBitmapSlave = slave.getLandBitmap();
189 for (x = 0; x < 64; x++)
190 {
191 for (y = 0; y < 64; y++)
192 {
193 if (landBitmapSlave[x, y])
194 {
195 landIDList[x, y] = master.landData.localID;
196 }
197 }
198 }
199
200 removeLandObject(slave.landData.localID);
201 updateLandObject(master.landData.localID, master.landData);
202 }
203
204 /// <summary>
205 /// Get the land object at the specified point
206 /// </summary>
207 /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
208 /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
209 /// <returns>Land object at the point supplied</returns>
210 public ILandObject getLandObject(float x_float, float y_float)
211 {
212 int x;
213 int y;
214
215 try
216 {
217 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / Convert.ToDouble(4.0)));
218 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / Convert.ToDouble(4.0)));
219 }
220 catch (System.OverflowException)
221 {
222 return null;
223 }
224
225 if (x >= 64 || y >= 64 || x < 0 || y < 0)
226 {
227 return null;
228 }
229 else
230 {
231 return landList[landIDList[x, y]];
232 }
233 }
234
235 public ILandObject getLandObject(int x, int y)
236 {
237 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0)
238 {
239 // These exceptions here will cause a lot of complaints from the users specifically because
240 // they happen every time at border crossings
241 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
242 }
243 else
244 {
245 return landList[landIDList[x / 4, y / 4]];
246 }
247 }
248
249 #endregion
250
251 #region Parcel Modification
252
253 /// <summary>
254 /// Subdivides a piece of land
255 /// </summary>
256 /// <param name="start_x">West Point</param>
257 /// <param name="start_y">South Point</param>
258 /// <param name="end_x">East Point</param>
259 /// <param name="end_y">North Point</param>
260 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
261 /// <returns>Returns true if successful</returns>
262 private bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
263 {
264 //First, lets loop through the points and make sure they are all in the same peice of land
265 //Get the land object at start
266 ILandObject startLandObject = null;
267 try
268 {
269 startLandObject = getLandObject(start_x, start_y);
270 }
271 catch (Exception)
272 {
273 //m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + start_x + " y:" + start_y);
274 }
275 if (startLandObject == null) return false; //No such land object at the beginning
276
277 //Loop through the points
278 try
279 {
280 int totalX = end_x - start_x;
281 int totalY = end_y - start_y;
282 int x, y;
283 for (y = 0; y < totalY; y++)
284 {
285 for (x = 0; x < totalX; x++)
286 {
287 ILandObject tempLandObject = getLandObject(start_x + x, start_y + y);
288 if (tempLandObject == null) return false; //No such land object at that point
289 if (tempLandObject != startLandObject) return false; //Subdividing over 2 land objects; no-no
290 }
291 }
292 }
293 catch (Exception)
294 {
295 return false; //Exception. For now, lets skip subdivision
296 }
297
298 //If we are still here, then they are subdividing within one piece of land
299 //Check owner
300 if (startLandObject.landData.ownerID != attempting_user_id)
301 {
302 return false; //They cant do this!
303 }
304
305 //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
306 ILandObject newLand = startLandObject.Copy();
307 newLand.landData.landName = "Subdivision of " + newLand.landData.landName;
308 newLand.landData.globalID = LLUUID.Random();
309
310 newLand.setLandBitmap(newLand.getSquareLandBitmap(start_x, start_y, end_x, end_y));
311
312 //Now, lets set the subdivision area of the original to false
313 int startLandObjectIndex = startLandObject.landData.localID;
314 landList[startLandObjectIndex].setLandBitmap(
315 newLand.modifyLandBitmapSquare(startLandObject.getLandBitmap(), start_x, start_y, end_x, end_y, false));
316 landList[startLandObjectIndex].forceUpdateLandInfo();
317
318 setPrimsTainted();
319
320 //Now add the new land object
321 ILandObject result = addLandObject(newLand);
322 updateLandObject(startLandObject.landData.localID, startLandObject.landData);
323 result.sendLandUpdateToAvatarsOverMe();
324
325
326 return true;
327 }
328
329 /// <summary>
330 /// Join 2 land objects together
331 /// </summary>
332 /// <param name="start_x">x value in first piece of land</param>
333 /// <param name="start_y">y value in first piece of land</param>
334 /// <param name="end_x">x value in second peice of land</param>
335 /// <param name="end_y">y value in second peice of land</param>
336 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the land objects</param>
337 /// <returns>Returns true if successful</returns>
338 private bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
339 {
340 end_x -= 4;
341 end_y -= 4;
342
343 List<ILandObject> selectedLandObjects = new List<ILandObject>();
344 int stepXSelected = 0;
345 int stepYSelected = 0;
346 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
347 {
348 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
349 {
350 ILandObject p = null;
351 try
352 {
353 p = getLandObject(stepXSelected, stepYSelected);
354 }
355 catch (Exception)
356 {
357 //m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + stepXSelected + " y:" + stepYSelected);
358 }
359 if (p != null)
360 {
361 if (!selectedLandObjects.Contains(p))
362 {
363 selectedLandObjects.Add(p);
364 }
365 }
366 }
367 }
368 ILandObject masterLandObject = selectedLandObjects[0];
369 selectedLandObjects.RemoveAt(0);
370
371
372 if (selectedLandObjects.Count < 1)
373 {
374 return false; //Only one piece of land selected
375 }
376 if (masterLandObject.landData.ownerID != attempting_user_id)
377 {
378 return false; //Not the same owner
379 }
380 foreach (ILandObject p in selectedLandObjects)
381 {
382 if (p.landData.ownerID != masterLandObject.landData.ownerID)
383 {
384 return false; //Over multiple users. TODO: make this just ignore this piece of land?
385 }
386 }
387 foreach (ILandObject slaveLandObject in selectedLandObjects)
388 {
389 landList[masterLandObject.landData.localID].setLandBitmap(
390 slaveLandObject.mergeLandBitmaps(masterLandObject.getLandBitmap(), slaveLandObject.getLandBitmap()));
391 performFinalLandJoin(masterLandObject, slaveLandObject);
392 }
393
394
395 setPrimsTainted();
396
397 masterLandObject.sendLandUpdateToAvatarsOverMe();
398
399 return true;
400 }
401
402 public void resetAllLandPrimCounts()
403 {
404 foreach (LandObject p in landList.Values)
405 {
406 p.resetLandPrimCounts();
407 }
408 }
409
410 public void setPrimsTainted()
411 {
412 landPrimCountTainted = true;
413 }
414
415 public bool isLandPrimCountTainted()
416 {
417 return landPrimCountTainted;
418 }
419
420 public void addPrimToLandPrimCounts(SceneObjectGroup obj)
421 {
422 LLVector3 position = obj.AbsolutePosition;
423 ILandObject landUnderPrim = getLandObject(position.X, position.Y);
424 if (landUnderPrim != null)
425 {
426 landUnderPrim.addPrimToCount(obj);
427 }
428 }
429
430 public void removePrimFromLandPrimCounts(SceneObjectGroup obj)
431 {
432 foreach (LandObject p in landList.Values)
433 {
434 p.removePrimFromCount(obj);
435 }
436 }
437
438 public void finalizeLandPrimCountUpdate()
439 {
440 //Get Simwide prim count for owner
441 Dictionary<LLUUID, List<LandObject>> landOwnersAndParcels = new Dictionary<LLUUID, List<LandObject>>();
442 foreach (LandObject p in landList.Values)
443 {
444 if (!landOwnersAndParcels.ContainsKey(p.landData.ownerID))
445 {
446 List<LandObject> tempList = new List<LandObject>();
447 tempList.Add(p);
448 landOwnersAndParcels.Add(p.landData.ownerID, tempList);
449 }
450 else
451 {
452 landOwnersAndParcels[p.landData.ownerID].Add(p);
453 }
454 }
455
456 foreach (LLUUID owner in landOwnersAndParcels.Keys)
457 {
458 int simArea = 0;
459 int simPrims = 0;
460 foreach (LandObject p in landOwnersAndParcels[owner])
461 {
462 simArea += p.landData.area;
463 simPrims += p.landData.ownerPrims + p.landData.otherPrims + p.landData.groupPrims +
464 p.landData.selectedPrims;
465 }
466
467 foreach (LandObject p in landOwnersAndParcels[owner])
468 {
469 p.landData.simwideArea = simArea;
470 p.landData.simwidePrims = simPrims;
471 }
472 }
473 }
474
475 public void updateLandPrimCounts()
476 {
477 foreach (EntityBase obj in m_scene.Entities.Values)
478 {
479 if (obj is SceneObjectGroup)
480 {
481 m_scene.EventManager.TriggerParcelPrimCountAdd((SceneObjectGroup)obj);
482 }
483 }
484 }
485
486 public void performParcelPrimCountUpdate()
487 {
488 resetAllLandPrimCounts();
489 m_scene.EventManager.TriggerParcelPrimCountUpdate();
490 finalizeLandPrimCountUpdate();
491 landPrimCountTainted = false;
492 }
493 #endregion
494
495 #region Parcel Updating
496
497 /// <summary>
498 /// Where we send the ParcelOverlay packet to the client
499 /// </summary>
500 /// <param name="remote_client">The object representing the client</param>
501 public void sendParcelOverlay(IClientAPI remote_client)
502 {
503 const int LAND_BLOCKS_PER_PACKET = 1024;
504 int x, y = 0;
505 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
506 int byteArrayCount = 0;
507 int sequenceID = 0;
508 ParcelOverlayPacket packet;
509
510 for (y = 0; y < 64; y++)
511 {
512 for (x = 0; x < 64; x++)
513 {
514 byte tempByte = (byte)0; //This represents the byte for the current 4x4
515 ILandObject currentParcelBlock = null;
516
517 try
518 {
519 currentParcelBlock = getLandObject(x * 4, y * 4);
520 }
521 catch (Exception)
522 {
523 //m_log.Warn("[LAND]: " + "unable to get land at x: " + (x * 4) + " y: " + (y * 4));
524 }
525
526
527 if (currentParcelBlock != null)
528 {
529 if (currentParcelBlock.landData.ownerID == remote_client.AgentId)
530 {
531 //Owner Flag
532 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_REQUESTER);
533 }
534 else if (currentParcelBlock.landData.salePrice > 0 &&
535 (currentParcelBlock.landData.authBuyerID == LLUUID.Zero ||
536 currentParcelBlock.landData.authBuyerID == remote_client.AgentId))
537 {
538 //Sale Flag
539 tempByte = Convert.ToByte(tempByte | LAND_TYPE_IS_FOR_SALE);
540 }
541 else if (currentParcelBlock.landData.ownerID == LLUUID.Zero)
542 {
543 //Public Flag
544 tempByte = Convert.ToByte(tempByte | LAND_TYPE_PUBLIC);
545 }
546 else
547 {
548 //Other Flag
549 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_OTHER);
550 }
551
552
553 //Now for border control
554 try
555 {
556 ILandObject westParcel = null;
557 ILandObject southParcel = null;
558 if (x > 0)
559 {
560 westParcel = getLandObject((x - 1) * 4, y * 4);
561 }
562 if (y > 0)
563 {
564 southParcel = getLandObject(x * 4, (y - 1) * 4);
565 }
566
567 if (x == 0)
568 {
569 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
570 }
571 else if (westParcel != null && westParcel != currentParcelBlock)
572 {
573 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
574 }
575
576 if (y == 0)
577 {
578 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
579 }
580 else if (southParcel != null && southParcel != currentParcelBlock)
581 {
582 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
583 }
584
585 byteArray[byteArrayCount] = tempByte;
586 byteArrayCount++;
587 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
588 {
589 byteArrayCount = 0;
590 packet = (ParcelOverlayPacket)PacketPool.Instance.GetPacket(PacketType.ParcelOverlay);
591 packet.ParcelData.Data = byteArray;
592 packet.ParcelData.SequenceID = sequenceID;
593 remote_client.OutPacket((Packet)packet, ThrottleOutPacketType.Task);
594 sequenceID++;
595 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
596 }
597 }
598 catch (Exception e)
599 {
600 //m_log.Debug("[LAND]: Skipped Land checks because avatar is out of bounds: " + e.Message);
601 }
602 }
603 }
604 }
605 }
606
607 public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
608 bool snap_selection, IClientAPI remote_client)
609 {
610 //Get the land objects within the bounds
611 List<ILandObject> temp = new List<ILandObject>();
612 int x, y, i;
613 int inc_x = end_x - start_x;
614 int inc_y = end_y - start_y;
615 for (x = 0; x < inc_x; x++)
616 {
617 for (y = 0; y < inc_y; y++)
618 {
619
620 ILandObject currentParcel = null;
621 try
622 {
623 currentParcel = getLandObject(start_x + x, start_y + y);
624 }
625 catch (Exception)
626 {
627 //m_log.Warn("[LAND]: " + "unable to get land at x: " + (start_x + x) + " y: " + (start_y + y));
628 }
629 if (currentParcel != null)
630 {
631 if (!temp.Contains(currentParcel))
632 {
633 currentParcel.forceUpdateLandInfo();
634 temp.Add(currentParcel);
635 }
636 }
637 }
638 }
639
640 int requestResult = LAND_RESULT_SINGLE;
641 if (temp.Count > 1)
642 {
643 requestResult = LAND_RESULT_MULTIPLE;
644 }
645
646 for (i = 0; i < temp.Count; i++)
647 {
648 temp[i].sendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
649 }
650
651
652 sendParcelOverlay(remote_client);
653 }
654
655 public void handleParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
656 {
657 if (landList.ContainsKey(packet.ParcelData.LocalID))
658 {
659 landList[packet.ParcelData.LocalID].updateLandProperties(packet, remote_client);
660 }
661 }
662
663 public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
664 {
665 subdivide(west, south, east, north, remote_client.AgentId);
666 }
667
668 public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
669 {
670 join(west, south, east, north, remote_client.AgentId);
671 }
672
673 public void handleParcelSelectObjectsRequest(int local_id, int request_type, IClientAPI remote_client)
674 {
675 landList[local_id].sendForceObjectSelect(local_id, request_type, remote_client);
676 }
677
678 public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client)
679 {
680 landList[local_id].sendLandObjectOwners(remote_client);
681 }
682
683 #endregion
684
685 /// <summary>
686 /// Resets the sim to the default land object (full sim piece of land owned by the default user)
687 /// </summary>
688 public void resetSimLandObjects()
689 {
690 //Remove all the land objects in the sim and add a blank, full sim land object set to public
691 landList.Clear();
692 lastLandLocalID = START_LAND_LOCAL_ID - 1;
693 landIDList.Initialize();
694
695 ILandObject fullSimParcel = new LandObject(LLUUID.Zero, false, m_scene);
696
697 fullSimParcel.setLandBitmap(fullSimParcel.getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
698 fullSimParcel.landData.ownerID = m_scene.RegionInfo.MasterAvatarAssignedUUID;
699
700 addLandObject(fullSimParcel);
701 }
702
703 public List<ILandObject> parcelsNearPoint(LLVector3 position)
704 {
705 List<ILandObject> parcelsNear = new List<ILandObject>();
706 int x, y;
707 for (x = -4; x <= 4; x += 4)
708 {
709 for (y = -4; y <= 4; y += 4)
710 {
711 ILandObject check = getLandObject(position.X + x, position.Y + y);
712 if (check != null)
713 {
714 if (!parcelsNear.Contains(check))
715 {
716 parcelsNear.Add(check);
717 }
718 }
719 }
720 }
721
722 return parcelsNear;
723 }
724
725 public void sendYouAreBannedNotice(ScenePresence avatar)
726 {
727 if (allowedForcefulBans)
728 {
729 avatar.ControllingClient.SendAlertMessage(
730 "You are not allowed on this parcel because you are banned. Please go away. <3 OpenSim Developers");
731
732 avatar.PhysicsActor.Position =
733 new PhysicsVector(avatar.lastKnownAllowedPosition.x, avatar.lastKnownAllowedPosition.y,
734 avatar.lastKnownAllowedPosition.z);
735 avatar.PhysicsActor.Velocity = new PhysicsVector(0, 0, 0);
736 }
737 else
738 {
739 avatar.ControllingClient.SendAlertMessage(
740 "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");
741 }
742 }
743
744 public void handleAvatarChangingParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
745 {
746 if (m_scene.RegionInfo.RegionID == regionID)
747 {
748 if (landList[localLandID] != null)
749 {
750 ILandObject parcelAvatarIsEntering = landList[localLandID];
751 if (avatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT)
752 {
753 if (parcelAvatarIsEntering.isBannedFromLand(avatar.UUID))
754 {
755 sendYouAreBannedNotice(avatar);
756 }
757 else if (parcelAvatarIsEntering.isRestrictedFromLand(avatar.UUID))
758 {
759 avatar.ControllingClient.SendAlertMessage(
760 "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");
761 }
762 else
763 {
764 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
765 }
766 }
767 else
768 {
769 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
770 }
771 }
772 }
773 }
774
775 public void sendOutNearestBanLine(IClientAPI avatar)
776 {
777 List<ScenePresence> avatars = m_scene.GetAvatars();
778 foreach (ScenePresence presence in avatars)
779 {
780 if (presence.UUID == avatar.AgentId)
781 {
782
783 List<ILandObject> checkLandParcels = parcelsNearPoint(presence.AbsolutePosition);
784 foreach (ILandObject checkBan in checkLandParcels)
785 {
786 if (checkBan.isBannedFromLand(avatar.AgentId))
787 {
788 checkBan.sendLandProperties(-30000, false, (int)ParcelManager.ParcelResult.Single, avatar);
789 return; //Only send one
790 }
791 else if (checkBan.isRestrictedFromLand(avatar.AgentId))
792 {
793 checkBan.sendLandProperties(-40000, false, (int)ParcelManager.ParcelResult.Single, avatar);
794 return; //Only send one
795 }
796 }
797 return;
798 }
799 }
800 }
801
802 public void sendLandUpdate(ScenePresence avatar, bool force)
803 {
804 ILandObject over = null;
805 try
806 {
807 over = getLandObject((int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
808 (int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
809 }
810 catch (Exception)
811 {
812 //m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " + Math.Round(avatar.AbsolutePosition.Y));
813 }
814
815 if (over != null)
816 {
817 if (force)
818 {
819 if (!avatar.IsChildAgent)
820 {
821 over.sendLandUpdateToClient(avatar.ControllingClient);
822 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
823 m_scene.RegionInfo.RegionID);
824 }
825 }
826
827 if (avatar.currentParcelUUID != over.landData.globalID)
828 {
829 if (!avatar.IsChildAgent)
830 {
831 over.sendLandUpdateToClient(avatar.ControllingClient);
832 avatar.currentParcelUUID = over.landData.globalID;
833 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
834 m_scene.RegionInfo.RegionID);
835 }
836 }
837 }
838 }
839 public void sendLandUpdate(ScenePresence avatar)
840 {
841 sendLandUpdate(avatar, false);
842
843 }
844 public void handleSignificantClientMovement(IClientAPI remote_client)
845 {
846 ScenePresence clientAvatar = m_scene.GetScenePresence(remote_client.AgentId);
847
848 if (clientAvatar != null)
849 {
850 sendLandUpdate(clientAvatar);
851 sendOutNearestBanLine(remote_client);
852 ILandObject parcel = getLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y);
853 if (parcel != null)
854 {
855 if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
856 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown)
857 {
858 handleAvatarChangingParcel(clientAvatar, parcel.landData.localID, m_scene.RegionInfo.RegionID);
859 //They are going below the safety line!
860 if (!parcel.isBannedFromLand(clientAvatar.UUID))
861 {
862 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false;
863 }
864 }
865 else if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
866 parcel.isBannedFromLand(clientAvatar.UUID))
867 {
868 sendYouAreBannedNotice(clientAvatar);
869 }
870 }
871 }
872 }
873
874 public void handleAnyClientMovement(ScenePresence avatar)
875 //Like handleSignificantClientMovement, but called with an AgentUpdate regardless of distance.
876 {
877 ILandObject over = getLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
878 if (over != null)
879 {
880 if (!over.isBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= BAN_LINE_SAFETY_HIEGHT)
881 {
882 avatar.lastKnownAllowedPosition =
883 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
884 }
885 }
886 }
887
888
889 public void handleParcelAccessRequest(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID,
890 int landLocalID, IClientAPI remote_client)
891 {
892 if (landList.ContainsKey(landLocalID))
893 {
894 landList[landLocalID].sendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
895 }
896 }
897
898 public void handleParcelAccessUpdateRequest(LLUUID agentID, LLUUID sessionID, uint flags, int landLocalID,
899 List<ParcelManager.ParcelAccessEntry> entries,
900 IClientAPI remote_client)
901 {
902 if (landList.ContainsKey(landLocalID))
903 {
904 if (agentID == landList[landLocalID].landData.ownerID)
905 {
906 landList[landLocalID].updateAccessList(flags, entries, remote_client);
907 }
908 }
909 else
910 {
911 Console.WriteLine("INVALID LOCAL LAND ID");
912 }
913 }
914
915 }
916}
diff --git a/OpenSim/Region/Environment/Modules/LandManagement/LandManagementModule.cs b/OpenSim/Region/Environment/Modules/LandManagement/LandManagementModule.cs
new file mode 100644
index 0000000..ac8c1a8
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/LandManagement/LandManagementModule.cs
@@ -0,0 +1,62 @@
1using System;
2using System.Collections.Generic;
3using libsecondlife;
4using libsecondlife.Packets;
5using OpenSim.Framework;
6using OpenSim.Framework.Console;
7using OpenSim.Region.Environment.Scenes;
8using OpenSim.Region.Environment.Interfaces;
9using Nini.Config;
10
11namespace OpenSim.Region.Environment.Modules.LandManagement
12{
13 public class LandManagementModule : IRegionModule
14 {
15 private LandChannel landChannel;
16 private Scene m_scene;
17
18 #region IRegionModule Members
19
20 public void Initialise(Scene scene, IConfigSource source)
21 {
22 m_scene = scene;
23 landChannel = new LandChannel(scene);
24
25 m_scene.EventManager.OnParcelPrimCountAdd += landChannel.addPrimToLandPrimCounts;
26 m_scene.EventManager.OnParcelPrimCountUpdate += landChannel.updateLandPrimCounts;
27 m_scene.EventManager.OnAvatarEnteringNewParcel += new EventManager.AvatarEnteringNewParcel(landChannel.handleAvatarChangingParcel);
28 m_scene.EventManager.OnClientMovement += new EventManager.ClientMovement(landChannel.handleAnyClientMovement);
29
30 lock (m_scene)
31 {
32 m_scene.LandChannel = (ILandChannel)landChannel;
33 }
34 }
35
36 public void PostInitialise()
37 {
38
39 }
40
41 public void Close()
42 {
43
44 }
45
46 public string Name
47 {
48 get { return "LandManagementModule"; }
49 }
50
51 public bool IsSharedModule
52 {
53 get { return false; }
54 }
55
56
57
58
59
60 #endregion
61 }
62}
diff --git a/OpenSim/Region/Environment/Modules/LandManagement/LandObject.cs b/OpenSim/Region/Environment/Modules/LandManagement/LandObject.cs
new file mode 100644
index 0000000..4e2fbd3
--- /dev/null
+++ b/OpenSim/Region/Environment/Modules/LandManagement/LandObject.cs
@@ -0,0 +1,879 @@
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 libsecondlife;
31using libsecondlife.Packets;
32using OpenSim.Framework;
33using OpenSim.Framework.Console;
34using OpenSim.Region.Environment.Scenes;
35using OpenSim.Region.Environment.Interfaces;
36
37namespace OpenSim.Region.Environment.Modules.LandManagement
38{
39
40 #region LandObject Class
41
42 /// <summary>
43 /// Keeps track of a specific piece of land's information
44 /// </summary>
45 public class LandObject : ILandObject
46 {
47 #region Member Variables
48
49 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50
51 protected LandData m_landData = new LandData();
52 protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
53 protected Scene m_scene;
54
55 private bool[,] m_landBitmap = new bool[64,64];
56
57 public bool[,] landBitmap
58 {
59 get
60 {
61 return m_landBitmap;
62 }
63 set
64 {
65 m_landBitmap = value;
66 }
67 }
68
69 #endregion
70
71 #region ILandObject Members
72
73 public LandData landData
74 {
75 get
76 {
77 return m_landData;
78 }
79
80 set
81 {
82 m_landData = value;
83 }
84 }
85
86 public LLUUID regionUUID
87 {
88 get { return m_scene.RegionInfo.RegionID; }
89 }
90
91 #endregion
92
93
94 #region Constructors
95
96 public LandObject(LLUUID owner_id, bool is_group_owned, Scene scene)
97 {
98 m_scene = scene;
99 landData.ownerID = owner_id;
100 landData.isGroupOwned = is_group_owned;
101 }
102
103 #endregion
104
105 #region Member Functions
106
107 #region General Functions
108
109 /// <summary>
110 /// Checks to see if this land object contains a point
111 /// </summary>
112 /// <param name="x"></param>
113 /// <param name="y"></param>
114 /// <returns>Returns true if the piece of land contains the specified point</returns>
115 public bool containsPoint(int x, int y)
116 {
117 if (x >= 0 && y >= 0 && x <= Constants.RegionSize && x <= Constants.RegionSize)
118 {
119 return (landBitmap[x/4, y/4] == true);
120 }
121 else
122 {
123 return false;
124 }
125 }
126
127 public ILandObject Copy()
128 {
129 ILandObject newLand = new LandObject(landData.ownerID, landData.isGroupOwned, m_scene);
130
131 //Place all new variables here!
132 newLand.landBitmap = (bool[,]) (landBitmap.Clone());
133 newLand.landData = landData.Copy();
134
135 return newLand;
136 }
137
138 #endregion
139
140 #region Packet Request Handling
141
142 /// <summary>
143 /// Sends land properties as requested
144 /// </summary>
145 /// <param name="sequence_id">ID sent by client for them to keep track of</param>
146 /// <param name="snap_selection">Bool sent by client for them to use</param>
147 /// <param name="remote_client">Object representing the client</param>
148 public void sendLandProperties(int sequence_id, bool snap_selection, int request_result,
149 IClientAPI remote_client)
150 {
151 ParcelPropertiesPacket updatePacket = (ParcelPropertiesPacket) PacketPool.Instance.GetPacket(PacketType.ParcelProperties);
152 // TODO: don't create new blocks if recycling an old packet
153
154 updatePacket.ParcelData.AABBMax = landData.AABBMax;
155 updatePacket.ParcelData.AABBMin = landData.AABBMin;
156 updatePacket.ParcelData.Area = landData.area;
157 updatePacket.ParcelData.AuctionID = landData.auctionID;
158 updatePacket.ParcelData.AuthBuyerID = landData.authBuyerID; //unemplemented
159
160 updatePacket.ParcelData.Bitmap = landData.landBitmapByteArray;
161
162 updatePacket.ParcelData.Desc = Helpers.StringToField(landData.landDesc);
163 updatePacket.ParcelData.Category = (byte) landData.category;
164 updatePacket.ParcelData.ClaimDate = landData.claimDate;
165 updatePacket.ParcelData.ClaimPrice = landData.claimPrice;
166 updatePacket.ParcelData.GroupID = landData.groupID;
167 updatePacket.ParcelData.GroupPrims = landData.groupPrims;
168 updatePacket.ParcelData.IsGroupOwned = landData.isGroupOwned;
169 updatePacket.ParcelData.LandingType = (byte) landData.landingType;
170 updatePacket.ParcelData.LocalID = landData.localID;
171 if (landData.area > 0)
172 {
173 updatePacket.ParcelData.MaxPrims =
174 Convert.ToInt32(
175 Math.Round((Convert.ToDecimal(landData.area)/Convert.ToDecimal(65536))*15000*
176 Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor)));
177 }
178 else
179 {
180 updatePacket.ParcelData.MaxPrims = 0;
181 }
182 updatePacket.ParcelData.MediaAutoScale = landData.mediaAutoScale;
183 updatePacket.ParcelData.MediaID = landData.mediaID;
184 updatePacket.ParcelData.MediaURL = Helpers.StringToField(landData.mediaURL);
185 updatePacket.ParcelData.MusicURL = Helpers.StringToField(landData.musicURL);
186 updatePacket.ParcelData.Name = Helpers.StringToField(landData.landName);
187 updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
188 updatePacket.ParcelData.OtherCount = 0; //unemplemented
189 updatePacket.ParcelData.OtherPrims = landData.otherPrims;
190 updatePacket.ParcelData.OwnerID = landData.ownerID;
191 updatePacket.ParcelData.OwnerPrims = landData.ownerPrims;
192 updatePacket.ParcelData.ParcelFlags = landData.landFlags;
193 updatePacket.ParcelData.ParcelPrimBonus = m_scene.RegionInfo.EstateSettings.objectBonusFactor;
194 updatePacket.ParcelData.PassHours = landData.passHours;
195 updatePacket.ParcelData.PassPrice = landData.passPrice;
196 updatePacket.ParcelData.PublicCount = 0; //unemplemented
197
198 uint regionFlags = (uint) m_scene.RegionInfo.EstateSettings.regionFlags;
199 updatePacket.ParcelData.RegionDenyAnonymous = ((regionFlags & (uint) Simulator.RegionFlags.DenyAnonymous) >
200 0);
201 updatePacket.ParcelData.RegionDenyIdentified = ((regionFlags & (uint) Simulator.RegionFlags.DenyIdentified) >
202 0);
203 updatePacket.ParcelData.RegionDenyTransacted = ((regionFlags & (uint) Simulator.RegionFlags.DenyTransacted) >
204 0);
205 updatePacket.ParcelData.RegionPushOverride = ((regionFlags & (uint) Simulator.RegionFlags.RestrictPushObject) >
206 0);
207
208 updatePacket.ParcelData.RentPrice = 0;
209 updatePacket.ParcelData.RequestResult = request_result;
210 updatePacket.ParcelData.SalePrice = landData.salePrice;
211 updatePacket.ParcelData.SelectedPrims = landData.selectedPrims;
212 updatePacket.ParcelData.SelfCount = 0; //unemplemented
213 updatePacket.ParcelData.SequenceID = sequence_id;
214 if (landData.simwideArea > 0)
215 {
216 updatePacket.ParcelData.SimWideMaxPrims =
217 Convert.ToInt32(
218 Math.Round((Convert.ToDecimal(landData.simwideArea)/Convert.ToDecimal(65536))*15000*
219 Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor)));
220 }
221 else
222 {
223 updatePacket.ParcelData.SimWideMaxPrims = 0;
224 }
225 updatePacket.ParcelData.SimWideTotalPrims = landData.simwidePrims;
226 updatePacket.ParcelData.SnapSelection = snap_selection;
227 updatePacket.ParcelData.SnapshotID = landData.snapshotID;
228 updatePacket.ParcelData.Status = (byte) landData.landStatus;
229 updatePacket.ParcelData.TotalPrims = landData.ownerPrims + landData.groupPrims + landData.otherPrims +
230 landData.selectedPrims;
231 updatePacket.ParcelData.UserLocation = landData.userLocation;
232 updatePacket.ParcelData.UserLookAt = landData.userLookAt;
233 remote_client.OutPacket((Packet) updatePacket, ThrottleOutPacketType.Task);
234 }
235
236 public void updateLandProperties(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
237 {
238 if (remote_client.AgentId == landData.ownerID)
239 {
240 //Needs later group support
241 LandData newData = landData.Copy();
242 newData.authBuyerID = packet.ParcelData.AuthBuyerID;
243 newData.category = (Parcel.ParcelCategory) packet.ParcelData.Category;
244 newData.landDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc);
245 newData.groupID = packet.ParcelData.GroupID;
246 newData.landingType = packet.ParcelData.LandingType;
247 newData.mediaAutoScale = packet.ParcelData.MediaAutoScale;
248 newData.mediaID = packet.ParcelData.MediaID;
249 newData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL);
250 newData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL);
251 newData.landName = Helpers.FieldToUTF8String(packet.ParcelData.Name);
252 newData.landFlags = packet.ParcelData.ParcelFlags;
253 newData.passHours = packet.ParcelData.PassHours;
254 newData.passPrice = packet.ParcelData.PassPrice;
255 newData.salePrice = packet.ParcelData.SalePrice;
256 newData.snapshotID = packet.ParcelData.SnapshotID;
257 newData.userLocation = packet.ParcelData.UserLocation;
258 newData.userLookAt = packet.ParcelData.UserLookAt;
259
260 m_scene.LandChannel.updateLandObject(landData.localID, newData);
261
262 sendLandUpdateToAvatarsOverMe();
263 }
264 }
265
266 public bool isEitherBannedOrRestricted(LLUUID avatar)
267 {
268 if (isBannedFromLand(avatar))
269 {
270 return true;
271 }
272 else if (isRestrictedFromLand(avatar))
273 {
274 return true;
275 }
276 return false;
277 }
278
279 public bool isBannedFromLand(LLUUID avatar)
280 {
281 if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseBanList) > 0)
282 {
283 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
284 entry.AgentID = avatar;
285 entry.Flags = ParcelManager.AccessList.Ban;
286 entry.Time = new DateTime();
287 if (landData.parcelAccessList.Contains(entry))
288 {
289 //They are banned, so lets send them a notice about this parcel
290 return true;
291 }
292 }
293 return false;
294 }
295
296 public bool isRestrictedFromLand(LLUUID avatar)
297 {
298 if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseAccessList) > 0)
299 {
300 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
301 entry.AgentID = avatar;
302 entry.Flags = ParcelManager.AccessList.Access;
303 entry.Time = new DateTime();
304 if (!landData.parcelAccessList.Contains(entry))
305 {
306 //They are not allowed in this parcel, but not banned, so lets send them a notice about this parcel
307 return true;
308 }
309 }
310 return false;
311 }
312
313 public void sendLandUpdateToClient(IClientAPI remote_client)
314 {
315 sendLandProperties(0, false, 0, remote_client);
316 }
317
318 public void sendLandUpdateToAvatarsOverMe()
319 {
320 List<ScenePresence> avatars = m_scene.GetAvatars();
321 ILandObject over = null;
322 for (int i = 0; i < avatars.Count; i++)
323 {
324 try
325 {
326 over =
327 m_scene.LandChannel.getLandObject((int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.X))),
328 (int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.Y))));
329 }
330 catch (Exception)
331 {
332 m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatars[i].AbsolutePosition.X) + " y: " + Math.Round(avatars[i].AbsolutePosition.Y));
333 }
334
335 if (over != null)
336 {
337 if (over.landData.localID == landData.localID)
338 {
339 sendLandUpdateToClient(avatars[i].ControllingClient);
340 }
341 }
342 }
343 }
344
345 #endregion
346
347 #region AccessList Functions
348
349 public ParcelAccessListReplyPacket.ListBlock[] createAccessListArrayByFlag(ParcelManager.AccessList flag)
350 {
351 List<ParcelAccessListReplyPacket.ListBlock> list = new List<ParcelAccessListReplyPacket.ListBlock>();
352 foreach (ParcelManager.ParcelAccessEntry entry in landData.parcelAccessList)
353 {
354 if (entry.Flags == flag)
355 {
356 ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock();
357
358 listBlock.Flags = (uint) 0;
359 listBlock.ID = entry.AgentID;
360 listBlock.Time = 0;
361
362 list.Add(listBlock);
363 }
364 }
365
366 if (list.Count == 0)
367 {
368 ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock();
369
370 listBlock.Flags = (uint) 0;
371 listBlock.ID = LLUUID.Zero;
372 listBlock.Time = 0;
373
374 list.Add(listBlock);
375 }
376 return list.ToArray();
377 }
378
379 public void sendAccessList(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID,
380 IClientAPI remote_client)
381 {
382 ParcelAccessListReplyPacket replyPacket;
383
384 if (flags == (uint) ParcelManager.AccessList.Access || flags == (uint) ParcelManager.AccessList.Both)
385 {
386 replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
387 replyPacket.Data.AgentID = agentID;
388 replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Access;
389 replyPacket.Data.LocalID = landData.localID;
390 replyPacket.Data.SequenceID = 0;
391
392 replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Access);
393 remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task);
394 }
395
396 if (flags == (uint) ParcelManager.AccessList.Ban || flags == (uint) ParcelManager.AccessList.Both)
397 {
398 replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
399 replyPacket.Data.AgentID = agentID;
400 replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Ban;
401 replyPacket.Data.LocalID = landData.localID;
402 replyPacket.Data.SequenceID = 0;
403
404 replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Ban);
405 remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task);
406 }
407 }
408
409 public void updateAccessList(uint flags, List<ParcelManager.ParcelAccessEntry> entries, IClientAPI remote_client)
410 {
411 LandData newData = landData.Copy();
412
413 if (entries.Count == 1 && entries[0].AgentID == LLUUID.Zero)
414 {
415 entries.Clear();
416 }
417
418 List<ParcelManager.ParcelAccessEntry> toRemove = new List<ParcelManager.ParcelAccessEntry>();
419 foreach (ParcelManager.ParcelAccessEntry entry in newData.parcelAccessList)
420 {
421 if (entry.Flags == (ParcelManager.AccessList) flags)
422 {
423 toRemove.Add(entry);
424 }
425 }
426
427 foreach (ParcelManager.ParcelAccessEntry entry in toRemove)
428 {
429 newData.parcelAccessList.Remove(entry);
430 }
431 foreach (ParcelManager.ParcelAccessEntry entry in entries)
432 {
433 ParcelManager.ParcelAccessEntry temp = new ParcelManager.ParcelAccessEntry();
434 temp.AgentID = entry.AgentID;
435 temp.Time = new DateTime(); //Pointless? Yes.
436 temp.Flags = (ParcelManager.AccessList) flags;
437
438 if (!newData.parcelAccessList.Contains(temp))
439 {
440 newData.parcelAccessList.Add(temp);
441 }
442 }
443
444 m_scene.LandChannel.updateLandObject(landData.localID, newData);
445 }
446
447 #endregion
448
449 #region Update Functions
450
451 /// <summary>
452 /// Updates the AABBMin and AABBMax values after area/shape modification of the land object
453 /// </summary>
454 private void updateAABBAndAreaValues()
455 {
456 int min_x = 64;
457 int min_y = 64;
458 int max_x = 0;
459 int max_y = 0;
460 int tempArea = 0;
461 int x, y;
462 for (x = 0; x < 64; x++)
463 {
464 for (y = 0; y < 64; y++)
465 {
466 if (landBitmap[x, y] == true)
467 {
468 if (min_x > x) min_x = x;
469 if (min_y > y) min_y = y;
470 if (max_x < x) max_x = x;
471 if (max_y < y) max_y = y;
472 tempArea += 16; //16sqm peice of land
473 }
474 }
475 }
476 int tx = min_x * 4;
477 if (tx > 255)
478 tx = 255;
479 int ty = min_y * 4;
480 if (ty > 255)
481 ty = 255;
482 landData.AABBMin =
483 new LLVector3((float)(min_x * 4), (float)(min_y * 4),
484 (float)m_scene.Heightmap[tx, ty]);
485
486 tx = max_x * 4;
487 if (tx > 255)
488 tx = 255;
489 ty = max_y * 4;
490 if (ty > 255)
491 ty = 255;
492 landData.AABBMax =
493 new LLVector3((float)(max_x * 4), (float)(max_y * 4),
494 (float)m_scene.Heightmap[tx, ty]);
495 landData.area = tempArea;
496 }
497
498 public void updateLandBitmapByteArray()
499 {
500 landData.landBitmapByteArray = convertLandBitmapToBytes();
501 }
502
503 /// <summary>
504 /// Update all settings in land such as area, bitmap byte array, etc
505 /// </summary>
506 public void forceUpdateLandInfo()
507 {
508 updateAABBAndAreaValues();
509 updateLandBitmapByteArray();
510 }
511
512 public void setLandBitmapFromByteArray()
513 {
514 landBitmap = convertBytesToLandBitmap();
515 }
516
517 #endregion
518
519 #region Land Bitmap Functions
520
521 /// <summary>
522 /// Sets the land's bitmap manually
523 /// </summary>
524 /// <param name="bitmap">64x64 block representing where this land is on a map</param>
525 public void setLandBitmap(bool[,] bitmap)
526 {
527 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
528 {
529 //Throw an exception - The bitmap is not 64x64
530 //throw new Exception("Error: Invalid Parcel Bitmap");
531 }
532 else
533 {
534 //Valid: Lets set it
535 landBitmap = bitmap;
536 forceUpdateLandInfo();
537 }
538 }
539
540 /// <summary>
541 /// Gets the land's bitmap manually
542 /// </summary>
543 /// <returns></returns>
544 public bool[,] getLandBitmap()
545 {
546 return landBitmap;
547 }
548
549 /// <summary>
550 /// Converts the land bitmap to a packet friendly byte array
551 /// </summary>
552 /// <returns></returns>
553 private byte[] convertLandBitmapToBytes()
554 {
555 byte[] tempConvertArr = new byte[512];
556 byte tempByte = 0;
557 int x, y, i, byteNum = 0;
558 i = 0;
559 for (y = 0; y < 64; y++)
560 {
561 for (x = 0; x < 64; x++)
562 {
563 tempByte = Convert.ToByte(tempByte | Convert.ToByte(landBitmap[x, y]) << (i++%8));
564 if (i%8 == 0)
565 {
566 tempConvertArr[byteNum] = tempByte;
567 tempByte = (byte) 0;
568 i = 0;
569 byteNum++;
570 }
571 }
572 }
573 return tempConvertArr;
574 }
575
576 private bool[,] convertBytesToLandBitmap()
577 {
578 bool[,] tempConvertMap = new bool[64,64];
579 tempConvertMap.Initialize();
580 byte tempByte = 0;
581 int x = 0, y = 0, i = 0, bitNum = 0;
582 for (i = 0; i < 512; i++)
583 {
584 tempByte = landData.landBitmapByteArray[i];
585 for (bitNum = 0; bitNum < 8; bitNum++)
586 {
587 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
588 tempConvertMap[x, y] = bit;
589 x++;
590 if (x > 63)
591 {
592 x = 0;
593 y++;
594 }
595 }
596 }
597 return tempConvertMap;
598 }
599
600 /// <summary>
601 /// Full sim land object creation
602 /// </summary>
603 /// <returns></returns>
604 public bool[,] basicFullRegionLandBitmap()
605 {
606 return getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize);
607 }
608
609 /// <summary>
610 /// Used to modify the bitmap between the x and y points. Points use 64 scale
611 /// </summary>
612 /// <param name="start_x"></param>
613 /// <param name="start_y"></param>
614 /// <param name="end_x"></param>
615 /// <param name="end_y"></param>
616 /// <returns></returns>
617 public bool[,] getSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
618 {
619 bool[,] tempBitmap = new bool[64,64];
620 tempBitmap.Initialize();
621
622 tempBitmap = modifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
623 return tempBitmap;
624 }
625
626 /// <summary>
627 /// Change a land bitmap at within a square and set those points to a specific value
628 /// </summary>
629 /// <param name="land_bitmap"></param>
630 /// <param name="start_x"></param>
631 /// <param name="start_y"></param>
632 /// <param name="end_x"></param>
633 /// <param name="end_y"></param>
634 /// <param name="set_value"></param>
635 /// <returns></returns>
636 public bool[,] modifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
637 bool set_value)
638 {
639 if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
640 {
641 //Throw an exception - The bitmap is not 64x64
642 //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
643 }
644
645 int x, y;
646 for (y = 0; y < 64; y++)
647 {
648 for (x = 0; x < 64; x++)
649 {
650 if (x >= start_x/4 && x < end_x/4
651 && y >= start_y/4 && y < end_y/4)
652 {
653 land_bitmap[x, y] = set_value;
654 }
655 }
656 }
657 return land_bitmap;
658 }
659
660 /// <summary>
661 /// Join the true values of 2 bitmaps together
662 /// </summary>
663 /// <param name="bitmap_base"></param>
664 /// <param name="bitmap_add"></param>
665 /// <returns></returns>
666 public bool[,] mergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
667 {
668 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2)
669 {
670 //Throw an exception - The bitmap is not 64x64
671 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps");
672 }
673 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
674 {
675 //Throw an exception - The bitmap is not 64x64
676 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
677 }
678
679 int x, y;
680 for (y = 0; y < 64; y++)
681 {
682 for (x = 0; x < 64; x++)
683 {
684 if (bitmap_add[x, y])
685 {
686 bitmap_base[x, y] = true;
687 }
688 }
689 }
690 return bitmap_base;
691 }
692
693 #endregion
694
695 #region Object Select and Object Owner Listing
696
697 public void sendForceObjectSelect(int local_id, int request_type, IClientAPI remote_client)
698 {
699 List<uint> resultLocalIDs = new List<uint>();
700 foreach (SceneObjectGroup obj in primsOverMe)
701 {
702 if (obj.LocalId > 0)
703 {
704 if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == landData.ownerID)
705 {
706 resultLocalIDs.Add(obj.LocalId);
707 }
708 // else if (request_type == LandManager.LAND_SELECT_OBJECTS_GROUP && ...) // TODO: group support
709 // {
710 // }
711 else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER &&
712 obj.OwnerID != remote_client.AgentId)
713 {
714 resultLocalIDs.Add(obj.LocalId);
715 }
716 }
717 }
718
719
720 bool firstCall = true;
721 int MAX_OBJECTS_PER_PACKET = 251;
722 ForceObjectSelectPacket pack = (ForceObjectSelectPacket) PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
723 // TODO: don't create new blocks if recycling an old packet
724 ForceObjectSelectPacket.DataBlock[] data;
725 while (resultLocalIDs.Count > 0)
726 {
727 if (firstCall)
728 {
729 pack._Header.ResetList = true;
730 firstCall = false;
731 }
732 else
733 {
734 pack._Header.ResetList = false;
735 }
736
737 if (resultLocalIDs.Count > MAX_OBJECTS_PER_PACKET)
738 {
739 data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET];
740 }
741 else
742 {
743 data = new ForceObjectSelectPacket.DataBlock[resultLocalIDs.Count];
744 }
745
746 int i;
747 for (i = 0; i < MAX_OBJECTS_PER_PACKET && resultLocalIDs.Count > 0; i++)
748 {
749 data[i] = new ForceObjectSelectPacket.DataBlock();
750 data[i].LocalID = Convert.ToUInt32(resultLocalIDs[0]);
751 resultLocalIDs.RemoveAt(0);
752 }
753 pack.Data = data;
754 remote_client.OutPacket((Packet) pack, ThrottleOutPacketType.Task);
755 }
756 }
757
758 public void sendLandObjectOwners(IClientAPI remote_client)
759 {
760 Dictionary<LLUUID, int> ownersAndCount = new Dictionary<LLUUID, int>();
761 ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply);
762 // TODO: don't create new blocks if recycling an old packet
763
764 foreach (SceneObjectGroup obj in primsOverMe)
765 {
766 if (!ownersAndCount.ContainsKey(obj.OwnerID))
767 {
768 ownersAndCount.Add(obj.OwnerID, 0);
769 }
770 ownersAndCount[obj.OwnerID] += obj.PrimCount;
771 }
772 if (ownersAndCount.Count > 0)
773 {
774 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[32];
775
776 if (ownersAndCount.Count < 32)
777 {
778 dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[ownersAndCount.Count];
779 }
780
781
782 int num = 0;
783 foreach (LLUUID owner in ownersAndCount.Keys)
784 {
785 dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock();
786 dataBlock[num].Count = ownersAndCount[owner];
787 dataBlock[num].IsGroupOwned = false; //TODO: fix me when group support is added
788 dataBlock[num].OnlineStatus = true; //TODO: fix me later
789 dataBlock[num].OwnerID = owner;
790
791 num++;
792 }
793 pack.Data = dataBlock;
794 }
795 remote_client.OutPacket(pack, ThrottleOutPacketType.Task);
796 }
797
798 #endregion
799
800 #region Object Returning
801
802 public void returnObject(SceneObjectGroup obj)
803 {
804 }
805
806 public void returnLandObjects(int type, LLUUID owner)
807 {
808 }
809
810 #endregion
811
812 #region Object Adding/Removing from Parcel
813
814 public void resetLandPrimCounts()
815 {
816 landData.groupPrims = 0;
817 landData.ownerPrims = 0;
818 landData.otherPrims = 0;
819 landData.selectedPrims = 0;
820 primsOverMe.Clear();
821 }
822
823 public void addPrimToCount(SceneObjectGroup obj)
824 {
825 LLUUID prim_owner = obj.OwnerID;
826 int prim_count = obj.PrimCount;
827
828 if (obj.IsSelected)
829 {
830 landData.selectedPrims += prim_count;
831 }
832 else
833 {
834 if (prim_owner == landData.ownerID)
835 {
836 landData.ownerPrims += prim_count;
837 }
838 else
839 {
840 landData.otherPrims += prim_count;
841 }
842 }
843
844 primsOverMe.Add(obj);
845 }
846
847 public void removePrimFromCount(SceneObjectGroup obj)
848 {
849 if (primsOverMe.Contains(obj))
850 {
851 LLUUID prim_owner = obj.OwnerID;
852 int prim_count = obj.PrimCount;
853
854 if (prim_owner == landData.ownerID)
855 {
856 landData.ownerPrims -= prim_count;
857 }
858 else if (prim_owner == landData.groupID)
859 {
860 landData.groupPrims -= prim_count;
861 }
862 else
863 {
864 landData.otherPrims -= prim_count;
865 }
866
867 primsOverMe.Remove(obj);
868 }
869 }
870
871 #endregion
872
873 #endregion
874
875
876}
877
878 #endregion
879}