aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/ParcelManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/ParcelManager.cs')
-rw-r--r--OpenSim/Region/Environment/ParcelManager.cs1206
1 files changed, 0 insertions, 1206 deletions
diff --git a/OpenSim/Region/Environment/ParcelManager.cs b/OpenSim/Region/Environment/ParcelManager.cs
deleted file mode 100644
index fbff556..0000000
--- a/OpenSim/Region/Environment/ParcelManager.cs
+++ /dev/null
@@ -1,1206 +0,0 @@
1/*
2* Copyright (c) Contributors, http://www.openmetaverse.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.Interfaces;
33using OpenSim.Framework.Types;
34using OpenSim.Region.Environment.Scenes;
35using Avatar = OpenSim.Region.Environment.Scenes.ScenePresence;
36using System.IO;
37
38namespace OpenSim.Region.Environment
39{
40
41
42 #region ParcelManager Class
43 /// <summary>
44 /// Handles Parcel objects and operations requiring information from other Parcel objects (divide, join, etc)
45 /// </summary>
46 public class ParcelManager : ILocalStorageParcelReceiver
47 {
48
49 #region Constants
50 //Parcel types set with flags in ParcelOverlay.
51 //Only one of these can be used.
52 public const byte PARCEL_TYPE_PUBLIC = (byte)0; //Equals 00000000
53 public const byte PARCEL_TYPE_OWNED_BY_OTHER = (byte)1; //Equals 00000001
54 public const byte PARCEL_TYPE_OWNED_BY_GROUP = (byte)2; //Equals 00000010
55 public const byte PARCEL_TYPE_OWNED_BY_REQUESTER = (byte)3; //Equals 00000011
56 public const byte PARCEL_TYPE_IS_FOR_SALE = (byte)4; //Equals 00000100
57 public const byte PARCEL_TYPE_IS_BEING_AUCTIONED = (byte)5; //Equals 00000101
58
59
60 //Flags that when set, a border on the given side will be placed
61 //NOTE: North and East is assumable by the west and south sides (if parcel to east has a west border, then I have an east border; etc)
62 //This took forever to figure out -- jeesh. /blame LL for even having to send these
63 public const byte PARCEL_FLAG_PROPERTY_BORDER_WEST = (byte)64; //Equals 01000000
64 public const byte PARCEL_FLAG_PROPERTY_BORDER_SOUTH = (byte)128; //Equals 10000000
65
66 //RequestResults (I think these are right, they seem to work):
67 public const int PARCEL_RESULT_ONE_PARCEL = 0; // The request they made contained only one parcel
68 public const int PARCEL_RESULT_MULTIPLE_PARCELS = 1; // The request they made contained more than one parcel
69
70 //ParcelSelectObjects
71 public const int PARCEL_SELECT_OBJECTS_OWNER = 2;
72 public const int PARCEL_SELECT_OBJECTS_GROUP = 4;
73 public const int PARCEL_SELECT_OBJECTS_OTHER = 8;
74
75
76 //These are other constants. Yay!
77 public const int START_PARCEL_LOCAL_ID = 1;
78 #endregion
79
80 #region Member Variables
81 public Dictionary<int, Parcel> parcelList = new Dictionary<int, Parcel>();
82 private int lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
83 private int[,] parcelIDList = new int[64, 64];
84
85 /// <summary>
86 /// Set to true when a prim is moved, created, added. Performs a prim count update
87 /// </summary>
88 public bool parcelPrimCountTainted = false;
89
90 private Scene m_world;
91 private RegionInfo m_regInfo;
92
93 #endregion
94
95 #region Constructors
96 public ParcelManager(Scene world, RegionInfo reginfo)
97 {
98
99 m_world = world;
100 m_regInfo = reginfo;
101 parcelIDList.Initialize();
102
103 }
104 #endregion
105
106 #region Member Functions
107
108 #region Parcel From Storage Functions
109 public void ParcelFromStorage(ParcelData data)
110 {
111 Parcel new_parcel = new Parcel(data.ownerID, data.isGroupOwned, m_world);
112 new_parcel.parcelData = data.Copy();
113 new_parcel.setParcelBitmapFromByteArray();
114 addParcel(new_parcel);
115
116 }
117
118 public void NoParcelDataFromStorage()
119 {
120 resetSimParcels();
121 }
122 #endregion
123
124 #region Parcel Add/Remove/Get/Create
125 /// <summary>
126 /// Creates a basic Parcel object without an owner (a zeroed key)
127 /// </summary>
128 /// <returns></returns>
129 public Parcel createBaseParcel()
130 {
131 return new Parcel(new LLUUID(), false, m_world);
132 }
133
134 /// <summary>
135 /// Adds a parcel to the stored list and adds them to the parcelIDList to what they own
136 /// </summary>
137 /// <param name="new_parcel">The parcel being added</param>
138 public Parcel addParcel(Parcel new_parcel)
139 {
140 lastParcelLocalID++;
141 new_parcel.parcelData.localID = lastParcelLocalID;
142 parcelList.Add(lastParcelLocalID, new_parcel.Copy());
143
144
145 bool[,] parcelBitmap = new_parcel.getParcelBitmap();
146 int x, y;
147 for (x = 0; x < 64; x++)
148 {
149 for (y = 0; y < 64; y++)
150 {
151 if (parcelBitmap[x, y])
152 {
153 parcelIDList[x, y] = lastParcelLocalID;
154 }
155 }
156 }
157 parcelList[lastParcelLocalID].forceUpdateParcelInfo();
158
159 return new_parcel;
160
161 }
162 /// <summary>
163 /// Removes a parcel from the list. Will not remove if local_id is still owning an area in parcelIDList
164 /// </summary>
165 /// <param name="local_id">Parcel.localID of the parcel to remove.</param>
166 public void removeParcel(int local_id)
167 {
168 int x, y;
169 for (x = 0; x < 64; x++)
170 {
171 for (y = 0; y < 64; y++)
172 {
173 if (parcelIDList[x, y] == local_id)
174 {
175 throw new Exception("Could not remove parcel. Still being used at " + x + ", " + y);
176 }
177 }
178 }
179 m_world.localStorage.RemoveParcel(parcelList[local_id].parcelData);
180 parcelList.Remove(local_id);
181 }
182
183 private void performFinalParcelJoin(Parcel master, Parcel slave)
184 {
185 int x, y;
186 bool[,] parcelBitmapSlave = slave.getParcelBitmap();
187 for (x = 0; x < 64; x++)
188 {
189 for (y = 0; y < 64; y++)
190 {
191 if (parcelBitmapSlave[x, y])
192 {
193 parcelIDList[x, y] = master.parcelData.localID;
194 }
195 }
196 }
197 removeParcel(slave.parcelData.localID);
198 }
199 /// <summary>
200 /// Get the parcel at the specified point
201 /// </summary>
202 /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
203 /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
204 /// <returns>Parcel at the point supplied</returns>
205 public Parcel getParcel(float x_float, float y_float)
206 {
207 int x = Convert.ToInt32(Math.Floor(Convert.ToDecimal(x_float) / Convert.ToDecimal(4.0)));
208 int y = Convert.ToInt32(Math.Floor(Convert.ToDecimal(y_float) / Convert.ToDecimal(4.0)));
209
210 if (x > 63 || y > 63 || x < 0 || y < 0)
211 {
212 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
213 }
214 else
215 {
216 // Console.WriteLine("Point (" + x + ", " + y + ") determined from point (" + x_float + ", " + y_float + ")");
217 return parcelList[parcelIDList[x, y]];
218 }
219 }
220
221 public Parcel getParcel(int x, int y)
222 {
223 if (x > 256 || y > 256 || x < 0 || y < 0)
224 {
225 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
226 }
227 else
228 {
229 return parcelList[parcelIDList[x / 4, y / 4]];
230 }
231 }
232 #endregion
233
234 #region Parcel Modification
235 /// <summary>
236 /// Subdivides a parcel
237 /// </summary>
238 /// <param name="start_x">West Point</param>
239 /// <param name="start_y">South Point</param>
240 /// <param name="end_x">East Point</param>
241 /// <param name="end_y">North Point</param>
242 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
243 /// <returns>Returns true if successful</returns>
244 private bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
245 {
246
247 //First, lets loop through the points and make sure they are all in the same parcel
248 //Get the parcel at start
249 Parcel startParcel = getParcel(start_x, start_y);
250 if (startParcel == null) return false; //No such parcel at the beginning
251
252 //Loop through the points
253 try
254 {
255 int totalX = end_x - start_x;
256 int totalY = end_y - start_y;
257 int x, y;
258 for (y = 0; y < totalY; y++)
259 {
260 for (x = 0; x < totalX; x++)
261 {
262 Parcel tempParcel = getParcel(start_x + x, start_y + y);
263 if (tempParcel == null) return false; //No such parcel at that point
264 if (tempParcel != startParcel) return false; //Subdividing over 2 parcels; no-no
265 }
266 }
267 }
268 catch (Exception)
269 {
270 return false; //Exception. For now, lets skip subdivision
271 }
272
273 //If we are still here, then they are subdividing within one parcel
274 //Check owner
275 if (startParcel.parcelData.ownerID != attempting_user_id)
276 {
277 return false; //They cant do this!
278 }
279
280 //Lets create a new parcel with bitmap activated at that point (keeping the old parcels info)
281 Parcel newParcel = startParcel.Copy();
282 newParcel.parcelData.parcelName = "Subdivision of " + newParcel.parcelData.parcelName;
283 newParcel.parcelData.globalID = LLUUID.Random();
284
285 newParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(start_x, start_y, end_x, end_y));
286
287 //Now, lets set the subdivision area of the original to false
288 int startParcelIndex = startParcel.parcelData.localID;
289 parcelList[startParcelIndex].setParcelBitmap(Parcel.modifyParcelBitmapSquare(startParcel.getParcelBitmap(), start_x, start_y, end_x, end_y, false));
290 parcelList[startParcelIndex].forceUpdateParcelInfo();
291
292
293 this.setPrimsTainted();
294
295 //Now add the new parcel
296 Parcel result = addParcel(newParcel);
297 result.sendParcelUpdateToAvatarsOverMe();
298
299
300
301
302 return true;
303 }
304 /// <summary>
305 /// Join 2 parcels together
306 /// </summary>
307 /// <param name="start_x">x value in first parcel</param>
308 /// <param name="start_y">y value in first parcel</param>
309 /// <param name="end_x">x value in second parcel</param>
310 /// <param name="end_y">y value in second parcel</param>
311 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the parcels</param>
312 /// <returns>Returns true if successful</returns>
313 private bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
314 {
315 end_x -= 4;
316 end_y -= 4;
317
318 List<Parcel> selectedParcels = new List<Parcel>();
319 int stepXSelected = 0;
320 int stepYSelected = 0;
321 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
322 {
323 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
324 {
325 Parcel p = getParcel(stepXSelected,stepYSelected);
326 if (!selectedParcels.Contains(p))
327 {
328 selectedParcels.Add(p);
329 }
330 }
331 }
332 Parcel masterParcel = selectedParcels[0];
333 selectedParcels.RemoveAt(0);
334
335
336 if (selectedParcels.Count < 1)
337 {
338 return false; //Only one parcel selected
339 }
340 if (masterParcel.parcelData.ownerID != attempting_user_id)
341 {
342 return false; //Not the same owner
343 }
344 foreach (Parcel p in selectedParcels)
345 {
346 if (p.parcelData.ownerID != masterParcel.parcelData.ownerID)
347 {
348 return false; //Over multiple users. TODO: make this just ignore this parcel?
349 }
350 }
351 foreach (Parcel slaveParcel in selectedParcels)
352 {
353 parcelList[masterParcel.parcelData.localID].setParcelBitmap(Parcel.mergeParcelBitmaps(masterParcel.getParcelBitmap(), slaveParcel.getParcelBitmap()));
354 performFinalParcelJoin(masterParcel, slaveParcel);
355 }
356
357
358 this.setPrimsTainted();
359
360 masterParcel.sendParcelUpdateToAvatarsOverMe();
361
362 return true;
363
364
365
366 }
367 #endregion
368
369 #region Parcel Updating
370 /// <summary>
371 /// Where we send the ParcelOverlay packet to the client
372 /// </summary>
373 /// <param name="remote_client">The object representing the client</param>
374 public void sendParcelOverlay(IClientAPI remote_client)
375 {
376 const int PARCEL_BLOCKS_PER_PACKET = 1024;
377 int x, y = 0;
378 byte[] byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
379 int byteArrayCount = 0;
380 int sequenceID = 0;
381 ParcelOverlayPacket packet;
382
383 for (y = 0; y < 64; y++)
384 {
385 for (x = 0; x < 64; x++)
386 {
387 byte tempByte = (byte)0; //This represents the byte for the current 4x4
388 Parcel currentParcelBlock = getParcel(x * 4, y * 4);
389
390 if (currentParcelBlock.parcelData.ownerID == remote_client.AgentId)
391 {
392 //Owner Flag
393 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_REQUESTER);
394 }
395 else if (currentParcelBlock.parcelData.salePrice > 0 && (currentParcelBlock.parcelData.authBuyerID == LLUUID.Zero || currentParcelBlock.parcelData.authBuyerID == remote_client.AgentId))
396 {
397 //Sale Flag
398 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_IS_FOR_SALE);
399 }
400 else if (currentParcelBlock.parcelData.ownerID == LLUUID.Zero)
401 {
402 //Public Flag
403 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_PUBLIC);
404 }
405 else
406 {
407 //Other Flag
408 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_OTHER);
409 }
410
411
412 //Now for border control
413 if (x == 0)
414 {
415 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
416 }
417 else if (getParcel((x - 1) * 4, y * 4) != currentParcelBlock)
418 {
419 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
420 }
421
422 if (y == 0)
423 {
424 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
425 }
426 else if (getParcel(x * 4, (y - 1) * 4) != currentParcelBlock)
427 {
428 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
429 }
430
431 byteArray[byteArrayCount] = tempByte;
432 byteArrayCount++;
433 if (byteArrayCount >= PARCEL_BLOCKS_PER_PACKET)
434 {
435 byteArrayCount = 0;
436 packet = new ParcelOverlayPacket();
437 packet.ParcelData.Data = byteArray;
438 packet.ParcelData.SequenceID = sequenceID;
439 remote_client.OutPacket((Packet)packet);
440 sequenceID++;
441 byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
442 }
443 }
444 }
445
446
447 }
448
449 public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, bool snap_selection, IClientAPI remote_client)
450 {
451 //Get the parcels within the bounds
452 List<Parcel> temp = new List<Parcel>();
453 int x, y, i;
454 int inc_x = end_x - start_x;
455 int inc_y = end_y - start_y;
456 for (x = 0; x < inc_x; x++)
457 {
458 for (y = 0; y < inc_y; y++)
459 {
460 Parcel currentParcel = getParcel(start_x + x, start_y + y);
461 if (!temp.Contains(currentParcel))
462 {
463 currentParcel.forceUpdateParcelInfo();
464 temp.Add(currentParcel);
465 }
466 }
467 }
468
469 int requestResult = PARCEL_RESULT_ONE_PARCEL;
470 if (temp.Count > 1)
471 {
472 requestResult = PARCEL_RESULT_MULTIPLE_PARCELS;
473 }
474
475 for (i = 0; i < temp.Count; i++)
476 {
477 temp[i].sendParcelProperties(sequence_id, snap_selection, requestResult, remote_client);
478 }
479
480
481 sendParcelOverlay(remote_client);
482 }
483
484 public void handleParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
485 {
486 if (parcelList.ContainsKey(packet.ParcelData.LocalID))
487 {
488 parcelList[packet.ParcelData.LocalID].updateParcelProperties(packet, remote_client);
489 }
490 }
491 public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
492 {
493 subdivide(west, south, east, north, remote_client.AgentId);
494 }
495 public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
496 {
497 join(west, south, east, north, remote_client.AgentId);
498
499 }
500
501 public void handleParcelSelectObjectsRequest(int local_id, int request_type, IClientAPI remote_client)
502 {
503 parcelList[local_id].sendForceObjectSelect(local_id, request_type, remote_client);
504 }
505
506 public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client)
507 {
508 parcelList[local_id].sendParcelObjectOwners(remote_client);
509 }
510 #endregion
511
512 /// <summary>
513 /// Resets the sim to the default parcel (full sim parcel owned by the default user)
514 /// </summary>
515 public void resetSimParcels()
516 {
517 //Remove all the parcels in the sim and add a blank, full sim parcel set to public
518 parcelList.Clear();
519 lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
520 parcelIDList.Initialize();
521
522 Parcel fullSimParcel = new Parcel(LLUUID.Zero, false, m_world);
523
524 fullSimParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(0, 0, 256, 256));
525 fullSimParcel.parcelData.ownerID = m_regInfo.MasterAvatarAssignedUUID;
526
527 addParcel(fullSimParcel);
528
529 }
530
531
532 public void handleSignificantClientMovement(IClientAPI remote_client)
533 {
534 Avatar clientAvatar = m_world.RequestAvatar(remote_client.AgentId);
535 if (clientAvatar != null)
536 {
537 Parcel over = getParcel(clientAvatar.Pos.X,clientAvatar.Pos.Y);
538 if (over != null)
539 {
540 over.sendParcelProperties(0, false, 0, remote_client);
541 }
542 }
543 }
544
545 public void resetAllParcelPrimCounts()
546 {
547 foreach (Parcel p in parcelList.Values)
548 {
549 p.resetParcelPrimCounts();
550 }
551 }
552 public void setPrimsTainted()
553 {
554 this.parcelPrimCountTainted = true;
555 }
556
557 public void addPrimToParcelCounts(SceneObject obj)
558 {
559 LLVector3 position = obj.Pos;
560 Parcel parcelUnderPrim = getParcel(position.X, position.Y);
561 if (parcelUnderPrim != null)
562 {
563 parcelUnderPrim.addPrimToCount(obj);
564 }
565 }
566
567 public void removePrimFromParcelCounts(SceneObject obj)
568 {
569 foreach (Parcel p in parcelList.Values)
570 {
571 p.removePrimFromCount(obj);
572 }
573 }
574
575 public void finalizeParcelPrimCountUpdate()
576 {
577 //Get Simwide prim count for owner
578 Dictionary<LLUUID, List<Parcel>> parcelOwnersAndParcels = new Dictionary<LLUUID,List<Parcel>>();
579 foreach (Parcel p in parcelList.Values)
580 {
581 if(!parcelOwnersAndParcels.ContainsKey(p.parcelData.ownerID))
582 {
583 List<Parcel> tempList = new List<Parcel>();
584 tempList.Add(p);
585 parcelOwnersAndParcels.Add(p.parcelData.ownerID,tempList);
586 }
587 else
588 {
589 parcelOwnersAndParcels[p.parcelData.ownerID].Add(p);
590 }
591 }
592
593 foreach (LLUUID owner in parcelOwnersAndParcels.Keys)
594 {
595 int simArea = 0;
596 int simPrims = 0;
597 foreach (Parcel p in parcelOwnersAndParcels[owner])
598 {
599 simArea += p.parcelData.area;
600 simPrims += p.parcelData.ownerPrims + p.parcelData.otherPrims + p.parcelData.groupPrims + p.parcelData.selectedPrims;
601 }
602
603 foreach (Parcel p in parcelOwnersAndParcels[owner])
604 {
605 p.parcelData.simwideArea = simArea;
606 p.parcelData.simwidePrims = simPrims;
607 }
608 }
609
610 }
611 #endregion
612 }
613 #endregion
614
615
616 #region Parcel Class
617 /// <summary>
618 /// Keeps track of a specific parcel's information
619 /// </summary>
620 public class Parcel
621 {
622 #region Member Variables
623 public ParcelData parcelData = new ParcelData();
624 public List<SceneObject> primsOverMe = new List<SceneObject>();
625
626 public Scene m_world;
627
628 private bool[,] parcelBitmap = new bool[64, 64];
629
630 #endregion
631
632
633 #region Constructors
634 public Parcel(LLUUID owner_id, bool is_group_owned, Scene world)
635 {
636 m_world = world;
637 parcelData.ownerID = owner_id;
638 parcelData.isGroupOwned = is_group_owned;
639
640 }
641 #endregion
642
643
644 #region Member Functions
645
646 #region General Functions
647 /// <summary>
648 /// Checks to see if this parcel contains a point
649 /// </summary>
650 /// <param name="x"></param>
651 /// <param name="y"></param>
652 /// <returns>Returns true if the parcel contains the specified point</returns>
653 public bool containsPoint(int x, int y)
654 {
655 if (x >= 0 && y >= 0 && x <= 256 && x <= 256)
656 {
657 return (parcelBitmap[x / 4, y / 4] == true);
658 }
659 else
660 {
661 return false;
662 }
663 }
664
665 public Parcel Copy()
666 {
667 Parcel newParcel = new Parcel(this.parcelData.ownerID, this.parcelData.isGroupOwned, m_world);
668
669 //Place all new variables here!
670 newParcel.parcelBitmap = (bool[,])(this.parcelBitmap.Clone());
671 newParcel.parcelData = parcelData.Copy();
672
673 return newParcel;
674 }
675
676 #endregion
677
678
679 #region Packet Request Handling
680 /// <summary>
681 /// Sends parcel properties as requested
682 /// </summary>
683 /// <param name="sequence_id">ID sent by client for them to keep track of</param>
684 /// <param name="snap_selection">Bool sent by client for them to use</param>
685 /// <param name="remote_client">Object representing the client</param>
686 public void sendParcelProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
687 {
688
689 ParcelPropertiesPacket updatePacket = new ParcelPropertiesPacket();
690 updatePacket.ParcelData.AABBMax = parcelData.AABBMax;
691 updatePacket.ParcelData.AABBMin = parcelData.AABBMin;
692 updatePacket.ParcelData.Area = parcelData.area;
693 updatePacket.ParcelData.AuctionID = parcelData.auctionID;
694 updatePacket.ParcelData.AuthBuyerID = parcelData.authBuyerID; //unemplemented
695
696 updatePacket.ParcelData.Bitmap = parcelData.parcelBitmapByteArray;
697
698 updatePacket.ParcelData.Desc = Helpers.StringToField(parcelData.parcelDesc);
699 updatePacket.ParcelData.Category = (byte)parcelData.category;
700 updatePacket.ParcelData.ClaimDate = parcelData.claimDate;
701 updatePacket.ParcelData.ClaimPrice = parcelData.claimPrice;
702 updatePacket.ParcelData.GroupID = parcelData.groupID;
703 updatePacket.ParcelData.GroupPrims = parcelData.groupPrims;
704 updatePacket.ParcelData.IsGroupOwned = parcelData.isGroupOwned;
705 updatePacket.ParcelData.LandingType = (byte)parcelData.landingType;
706 updatePacket.ParcelData.LocalID = parcelData.localID;
707 if (parcelData.area > 0)
708 {
709 updatePacket.ParcelData.MaxPrims = Convert.ToInt32(Math.Round((Convert.ToDecimal(parcelData.area) / Convert.ToDecimal(65536)) * 15000 * Convert.ToDecimal(m_world.RegionInfo.estateSettings.objectBonusFactor)));
710 }
711 else
712 {
713 updatePacket.ParcelData.MaxPrims = 0;
714 }
715 updatePacket.ParcelData.MediaAutoScale = parcelData.mediaAutoScale;
716 updatePacket.ParcelData.MediaID = parcelData.mediaID;
717 updatePacket.ParcelData.MediaURL = Helpers.StringToField(parcelData.mediaURL);
718 updatePacket.ParcelData.MusicURL = Helpers.StringToField(parcelData.musicURL);
719 updatePacket.ParcelData.Name = Helpers.StringToField(parcelData.parcelName);
720 updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
721 updatePacket.ParcelData.OtherCount = 0; //unemplemented
722 updatePacket.ParcelData.OtherPrims = parcelData.otherPrims;
723 updatePacket.ParcelData.OwnerID = parcelData.ownerID;
724 updatePacket.ParcelData.OwnerPrims = parcelData.ownerPrims;
725 updatePacket.ParcelData.ParcelFlags = parcelData.parcelFlags;
726 updatePacket.ParcelData.ParcelPrimBonus = m_world.RegionInfo.estateSettings.objectBonusFactor;
727 updatePacket.ParcelData.PassHours = parcelData.passHours;
728 updatePacket.ParcelData.PassPrice = parcelData.passPrice;
729 updatePacket.ParcelData.PublicCount = 0; //unemplemented
730 updatePacket.ParcelData.RegionDenyAnonymous = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.DenyAnonymous) > 0);
731 updatePacket.ParcelData.RegionDenyIdentified = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.DenyIdentified) > 0);
732 updatePacket.ParcelData.RegionDenyTransacted = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.DenyTransacted) > 0);
733 updatePacket.ParcelData.RegionPushOverride = (((uint)m_world.RegionInfo.estateSettings.regionFlags & (uint)Simulator.RegionFlags.RestrictPushObject) > 0);
734 updatePacket.ParcelData.RentPrice = 0;
735 updatePacket.ParcelData.RequestResult = request_result;
736 updatePacket.ParcelData.SalePrice = parcelData.salePrice;
737 updatePacket.ParcelData.SelectedPrims = parcelData.selectedPrims;
738 updatePacket.ParcelData.SelfCount = 0;//unemplemented
739 updatePacket.ParcelData.SequenceID = sequence_id;
740 if (parcelData.simwideArea > 0)
741 {
742 updatePacket.ParcelData.SimWideMaxPrims = Convert.ToInt32(Math.Round((Convert.ToDecimal(parcelData.simwideArea) / Convert.ToDecimal(65536)) * 15000 * Convert.ToDecimal(m_world.RegionInfo.estateSettings.objectBonusFactor)));
743 }
744 else
745 {
746 updatePacket.ParcelData.SimWideMaxPrims = 0;
747 }
748 updatePacket.ParcelData.SimWideTotalPrims = parcelData.simwidePrims;
749 updatePacket.ParcelData.SnapSelection = snap_selection;
750 updatePacket.ParcelData.SnapshotID = parcelData.snapshotID;
751 updatePacket.ParcelData.Status = (byte)parcelData.parcelStatus;
752 updatePacket.ParcelData.TotalPrims = parcelData.ownerPrims + parcelData.groupPrims + parcelData.otherPrims + parcelData.selectedPrims;
753 updatePacket.ParcelData.UserLocation = parcelData.userLocation;
754 updatePacket.ParcelData.UserLookAt = parcelData.userLookAt;
755 remote_client.OutPacket((Packet)updatePacket);
756 }
757
758 public void updateParcelProperties(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
759 {
760 if (remote_client.AgentId == parcelData.ownerID)
761 {
762 //Needs later group support
763 parcelData.authBuyerID = packet.ParcelData.AuthBuyerID;
764 parcelData.category = (libsecondlife.Parcel.ParcelCategory)packet.ParcelData.Category;
765 parcelData.parcelDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc);
766 parcelData.groupID = packet.ParcelData.GroupID;
767 parcelData.landingType = packet.ParcelData.LandingType;
768 parcelData.mediaAutoScale = packet.ParcelData.MediaAutoScale;
769 parcelData.mediaID = packet.ParcelData.MediaID;
770 parcelData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL);
771 parcelData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL);
772 parcelData.parcelName = Helpers.FieldToUTF8String(packet.ParcelData.Name);
773 parcelData.parcelFlags = packet.ParcelData.ParcelFlags;
774 parcelData.passHours = packet.ParcelData.PassHours;
775 parcelData.passPrice = packet.ParcelData.PassPrice;
776 parcelData.salePrice = packet.ParcelData.SalePrice;
777 parcelData.snapshotID = packet.ParcelData.SnapshotID;
778 parcelData.userLocation = packet.ParcelData.UserLocation;
779 parcelData.userLookAt = packet.ParcelData.UserLookAt;
780 sendParcelUpdateToAvatarsOverMe();
781
782
783 }
784 }
785
786 public void sendParcelUpdateToAvatarsOverMe()
787 {
788 List<Avatar> avatars = m_world.RequestAvatarList();
789 for (int i = 0; i < avatars.Count; i++)
790 {
791 Parcel over = m_world.ParcelManager.getParcel((int)Math.Round(avatars[i].Pos.X), (int)Math.Round(avatars[i].Pos.Y));
792 if (over.parcelData.localID == this.parcelData.localID)
793 {
794 sendParcelProperties(0, false, 0, avatars[i].ControllingClient);
795 }
796 }
797 }
798 #endregion
799
800
801 #region Update Functions
802 /// <summary>
803 /// Updates the AABBMin and AABBMax values after area/shape modification of parcel
804 /// </summary>
805 private void updateAABBAndAreaValues()
806 {
807 int min_x = 64;
808 int min_y = 64;
809 int max_x = 0;
810 int max_y = 0;
811 int tempArea = 0;
812 int x, y;
813 for (x = 0; x < 64; x++)
814 {
815 for (y = 0; y < 64; y++)
816 {
817 if (parcelBitmap[x, y] == true)
818 {
819 if (min_x > x) min_x = x;
820 if (min_y > y) min_y = y;
821 if (max_x < x) max_x = x;
822 if (max_y < y) max_y = y;
823 tempArea += 16; //16sqm parcel
824 }
825 }
826 }
827 parcelData.AABBMin = new LLVector3((float)(min_x * 4), (float)(min_y * 4), (float)m_world.Terrain.get((min_x * 4), (min_y * 4)));
828 parcelData.AABBMax = new LLVector3((float)(max_x * 4), (float)(max_y * 4), (float)m_world.Terrain.get((max_x * 4), (max_y * 4)));
829 parcelData.area = tempArea;
830 }
831
832 public void updateParcelBitmapByteArray()
833 {
834 parcelData.parcelBitmapByteArray = convertParcelBitmapToBytes();
835 }
836
837 /// <summary>
838 /// Update all settings in parcel such as area, bitmap byte array, etc
839 /// </summary>
840 public void forceUpdateParcelInfo()
841 {
842 this.updateAABBAndAreaValues();
843 this.updateParcelBitmapByteArray();
844 }
845
846 public void setParcelBitmapFromByteArray()
847 {
848 parcelBitmap = convertBytesToParcelBitmap();
849 }
850 #endregion
851
852
853 #region Parcel Bitmap Functions
854 /// <summary>
855 /// Sets the parcel's bitmap manually
856 /// </summary>
857 /// <param name="bitmap">64x64 block representing where this parcel is on a map</param>
858 public void setParcelBitmap(bool[,] bitmap)
859 {
860 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
861 {
862 //Throw an exception - The bitmap is not 64x64
863 throw new Exception("Error: Invalid Parcel Bitmap");
864 }
865 else
866 {
867 //Valid: Lets set it
868 parcelBitmap = bitmap;
869 forceUpdateParcelInfo();
870
871 }
872 }
873 /// <summary>
874 /// Gets the parcels bitmap manually
875 /// </summary>
876 /// <returns></returns>
877 public bool[,] getParcelBitmap()
878 {
879 return parcelBitmap;
880 }
881 /// <summary>
882 /// Converts the parcel bitmap to a packet friendly byte array
883 /// </summary>
884 /// <returns></returns>
885 private byte[] convertParcelBitmapToBytes()
886 {
887 byte[] tempConvertArr = new byte[512];
888 byte tempByte = 0;
889 int x, y, i, byteNum = 0;
890 i = 0;
891 for (y = 0; y < 64; y++)
892 {
893 for (x = 0; x < 64; x++)
894 {
895 tempByte = Convert.ToByte(tempByte | Convert.ToByte(parcelBitmap[x, y]) << (i++ % 8));
896 if (i % 8 == 0)
897 {
898 tempConvertArr[byteNum] = tempByte;
899 tempByte = (byte)0;
900 i = 0;
901 byteNum++;
902 }
903 }
904 }
905 return tempConvertArr;
906 }
907
908 private bool[,] convertBytesToParcelBitmap()
909 {
910 bool[,] tempConvertMap = new bool[64, 64];
911 tempConvertMap.Initialize();
912 byte tempByte = 0;
913 int x = 0, y = 0, i = 0, bitNum = 0;
914 for (i = 0; i < 512; i++)
915 {
916 tempByte = parcelData.parcelBitmapByteArray[i];
917 for (bitNum = 0; bitNum < 8; bitNum++)
918 {
919 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte)1);
920 tempConvertMap[x, y] = bit;
921 x++;
922 if (x > 63)
923 {
924 x = 0;
925 y++;
926 }
927
928 }
929
930 }
931 return tempConvertMap;
932 }
933 /// <summary>
934 /// Full sim parcel creation
935 /// </summary>
936 /// <returns></returns>
937 public static bool[,] basicFullRegionParcelBitmap()
938 {
939 return getSquareParcelBitmap(0, 0, 256, 256);
940 }
941
942 /// <summary>
943 /// Used to modify the bitmap between the x and y points. Points use 64 scale
944 /// </summary>
945 /// <param name="start_x"></param>
946 /// <param name="start_y"></param>
947 /// <param name="end_x"></param>
948 /// <param name="end_y"></param>
949 /// <returns></returns>
950 public static bool[,] getSquareParcelBitmap(int start_x, int start_y, int end_x, int end_y)
951 {
952
953 bool[,] tempBitmap = new bool[64, 64];
954 tempBitmap.Initialize();
955
956 tempBitmap = modifyParcelBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
957 return tempBitmap;
958 }
959
960 /// <summary>
961 /// Change a parcel's bitmap at within a square and set those points to a specific value
962 /// </summary>
963 /// <param name="parcel_bitmap"></param>
964 /// <param name="start_x"></param>
965 /// <param name="start_y"></param>
966 /// <param name="end_x"></param>
967 /// <param name="end_y"></param>
968 /// <param name="set_value"></param>
969 /// <returns></returns>
970 public static bool[,] modifyParcelBitmapSquare(bool[,] parcel_bitmap, int start_x, int start_y, int end_x, int end_y, bool set_value)
971 {
972 if (parcel_bitmap.GetLength(0) != 64 || parcel_bitmap.GetLength(1) != 64 || parcel_bitmap.Rank != 2)
973 {
974 //Throw an exception - The bitmap is not 64x64
975 throw new Exception("Error: Invalid Parcel Bitmap in modifyParcelBitmapSquare()");
976 }
977
978 int x, y;
979 for (y = 0; y < 64; y++)
980 {
981 for (x = 0; x < 64; x++)
982 {
983 if (x >= start_x / 4 && x < end_x / 4
984 && y >= start_y / 4 && y < end_y / 4)
985 {
986 parcel_bitmap[x, y] = set_value;
987 }
988 }
989 }
990 return parcel_bitmap;
991 }
992 /// <summary>
993 /// Join the true values of 2 bitmaps together
994 /// </summary>
995 /// <param name="bitmap_base"></param>
996 /// <param name="bitmap_add"></param>
997 /// <returns></returns>
998 public static bool[,] mergeParcelBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
999 {
1000 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2)
1001 {
1002 //Throw an exception - The bitmap is not 64x64
1003 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeParcelBitmaps");
1004 }
1005 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
1006 {
1007 //Throw an exception - The bitmap is not 64x64
1008 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeParcelBitmaps");
1009
1010 }
1011
1012 int x, y;
1013 for (y = 0; y < 64; y++)
1014 {
1015 for (x = 0; x < 64; x++)
1016 {
1017 if (bitmap_add[x, y])
1018 {
1019 bitmap_base[x, y] = true;
1020 }
1021 }
1022 }
1023 return bitmap_base;
1024 }
1025 #endregion
1026
1027 #region Object Select and Object Owner Listing
1028 public void sendForceObjectSelect(int local_id, int request_type, IClientAPI remote_client)
1029 {
1030 List<uint> resultLocalIDs = new List<uint>();
1031 foreach (SceneObject obj in primsOverMe)
1032 {
1033 if (obj.rootLocalID > 0)
1034 {
1035 if (request_type == ParcelManager.PARCEL_SELECT_OBJECTS_OWNER && obj.rootPrimitive.OwnerID == this.parcelData.ownerID)
1036 {
1037 resultLocalIDs.Add(obj.rootLocalID);
1038 }
1039 else if (request_type == ParcelManager.PARCEL_SELECT_OBJECTS_GROUP && false) //TODO: change false to group support!
1040 {
1041
1042 }
1043 else if (request_type == ParcelManager.PARCEL_SELECT_OBJECTS_OTHER && obj.rootPrimitive.OwnerID != remote_client.AgentId)
1044 {
1045 resultLocalIDs.Add(obj.rootLocalID);
1046 }
1047 }
1048 }
1049
1050
1051 bool firstCall = true;
1052 int MAX_OBJECTS_PER_PACKET = 251;
1053 ForceObjectSelectPacket pack = new ForceObjectSelectPacket();
1054 ForceObjectSelectPacket.DataBlock[] data;
1055 while (resultLocalIDs.Count > 0)
1056 {
1057 if (firstCall)
1058 {
1059 pack._Header.ResetList = true;
1060 firstCall = false;
1061 }
1062 else
1063 {
1064 pack._Header.ResetList = false;
1065 }
1066
1067 if (resultLocalIDs.Count > MAX_OBJECTS_PER_PACKET)
1068 {
1069 data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET];
1070 }
1071 else
1072 {
1073 data = new ForceObjectSelectPacket.DataBlock[resultLocalIDs.Count];
1074 }
1075
1076 int i;
1077 for (i = 0; i < MAX_OBJECTS_PER_PACKET && resultLocalIDs.Count > 0; i++)
1078 {
1079 data[i] = new ForceObjectSelectPacket.DataBlock();
1080 data[i].LocalID = Convert.ToUInt32(resultLocalIDs[0]);
1081 resultLocalIDs.RemoveAt(0);
1082 }
1083 pack.Data = data;
1084 remote_client.OutPacket((Packet)pack);
1085 }
1086
1087 }
1088 public void sendParcelObjectOwners(IClientAPI remote_client)
1089 {
1090 Dictionary<LLUUID, int> ownersAndCount = new Dictionary<LLUUID,int>();
1091 foreach(SceneObject obj in primsOverMe)
1092 {
1093 if(!ownersAndCount.ContainsKey(obj.rootPrimitive.OwnerID))
1094 {
1095 ownersAndCount.Add(obj.rootPrimitive.OwnerID,0);
1096 }
1097 ownersAndCount[obj.rootPrimitive.OwnerID] += obj.primCount;
1098 }
1099 if (ownersAndCount.Count > 0)
1100 {
1101
1102 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[32];
1103
1104 if(ownersAndCount.Count < 32)
1105 {
1106 dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[ownersAndCount.Count];
1107 }
1108
1109
1110 int num = 0;
1111 foreach (LLUUID owner in ownersAndCount.Keys)
1112 {
1113 dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock();
1114 dataBlock[num].Count = ownersAndCount[owner];
1115 dataBlock[num].IsGroupOwned = false; //TODO: fix me when group support is added
1116 dataBlock[num].OnlineStatus = true; //TODO: fix me later
1117 dataBlock[num].OwnerID = owner;
1118
1119 num++;
1120 }
1121
1122 ParcelObjectOwnersReplyPacket pack = new ParcelObjectOwnersReplyPacket();
1123 pack.Data = dataBlock;
1124 remote_client.OutPacket(pack);
1125 }
1126 }
1127 #endregion
1128
1129 #region Object Returning
1130 public void returnObject(SceneObject obj)
1131 {
1132 }
1133 public void returnParcelObjects(int type, LLUUID owner)
1134 {
1135
1136 }
1137 #endregion
1138
1139 #region Object Adding/Removing from Parcel
1140 public void resetParcelPrimCounts()
1141 {
1142 parcelData.groupPrims = 0;
1143 parcelData.ownerPrims = 0;
1144 parcelData.otherPrims = 0;
1145 parcelData.selectedPrims = 0;
1146 primsOverMe.Clear();
1147 }
1148
1149 public void addPrimToCount(SceneObject obj)
1150 {
1151 LLUUID prim_owner = obj.rootPrimitive.OwnerID;
1152 int prim_count = obj.primCount;
1153
1154 if (obj.isSelected)
1155 {
1156 parcelData.selectedPrims += prim_count;
1157 }
1158 else
1159 {
1160 if (prim_owner == parcelData.ownerID)
1161 {
1162 parcelData.ownerPrims += prim_count;
1163 }
1164 else
1165 {
1166 parcelData.otherPrims += prim_count;
1167 }
1168 }
1169
1170 primsOverMe.Add(obj);
1171
1172 }
1173
1174 public void removePrimFromCount(SceneObject obj)
1175 {
1176 if (primsOverMe.Contains(obj))
1177 {
1178 LLUUID prim_owner = obj.rootPrimitive.OwnerID;
1179 int prim_count = obj.primCount;
1180
1181 if (prim_owner == parcelData.ownerID)
1182 {
1183 parcelData.ownerPrims -= prim_count;
1184 }
1185 else if (prim_owner == parcelData.groupID)
1186 {
1187 parcelData.groupPrims -= prim_count;
1188 }
1189 else
1190 {
1191 parcelData.otherPrims -= prim_count;
1192 }
1193
1194 primsOverMe.Remove(obj);
1195 }
1196 }
1197 #endregion
1198
1199 #endregion
1200
1201
1202 }
1203 #endregion
1204
1205
1206}