aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/OpenSim.World/ParcelManager.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/OpenSim.World/ParcelManager.cs832
1 files changed, 832 insertions, 0 deletions
diff --git a/OpenSim/OpenSim.World/ParcelManager.cs b/OpenSim/OpenSim.World/ParcelManager.cs
new file mode 100644
index 0000000..d571150
--- /dev/null
+++ b/OpenSim/OpenSim.World/ParcelManager.cs
@@ -0,0 +1,832 @@
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 System.Text;
31using libsecondlife;
32using libsecondlife.Packets;
33using OpenSim.Framework.Interfaces;
34using OpenSim.Framework.Types;
35
36namespace OpenSim.world
37{
38
39
40 #region ParcelManager Class
41 /// <summary>
42 /// Handles Parcel objects and operations requiring information from other Parcel objects (divide, join, etc)
43 /// </summary>
44 public class ParcelManager : OpenSim.Framework.Interfaces.ILocalStorageParcelReceiver
45 {
46
47 #region Constants
48 //Parcel types set with flags in ParcelOverlay.
49 //Only one of these can be used.
50 public const byte PARCEL_TYPE_PUBLIC = (byte)0; //Equals 00000000
51 public const byte PARCEL_TYPE_OWNED_BY_OTHER = (byte)1; //Equals 00000001
52 public const byte PARCEL_TYPE_OWNED_BY_GROUP = (byte)2; //Equals 00000010
53 public const byte PARCEL_TYPE_OWNED_BY_REQUESTER = (byte)3; //Equals 00000011
54 public const byte PARCEL_TYPE_IS_FOR_SALE = (byte)4; //Equals 00000100
55 public const byte PARCEL_TYPE_IS_BEING_AUCTIONED = (byte)5; //Equals 00000101
56
57
58 //Flags that when set, a border on the given side will be placed
59 //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)
60 //This took forever to figure out -- jeesh. /blame LL for even having to send these
61 public const byte PARCEL_FLAG_PROPERTY_BORDER_WEST = (byte)64; //Equals 01000000
62 public const byte PARCEL_FLAG_PROPERTY_BORDER_SOUTH = (byte)128; //Equals 10000000
63
64 //RequestResults (I think these are right, they seem to work):
65 public const int PARCEL_RESULT_ONE_PARCEL = 0; // The request they made contained only one parcel
66 public const int PARCEL_RESULT_MULTIPLE_PARCELS = 1; // The request they made contained more than one parcel
67
68 //These are other constants. Yay!
69 public const int START_PARCEL_LOCAL_ID = 1;
70 #endregion
71
72 #region Member Variables
73 public Dictionary<int, Parcel> parcelList = new Dictionary<int, Parcel>();
74 private int lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
75 private int[,] parcelIDList = new int[64, 64];
76
77 private static World m_world;
78 #endregion
79
80 #region Constructors
81 public ParcelManager(World world)
82 {
83
84 m_world = world;
85 parcelIDList.Initialize();
86
87 }
88 #endregion
89
90 #region Member Functions
91
92 #region Parcel From Storage Functions
93 public void ParcelFromStorage(ParcelData data)
94 {
95 Parcel new_parcel = new Parcel(data.ownerID, data.isGroupOwned, m_world);
96 new_parcel.parcelData = data.Copy();
97 new_parcel.setParcelBitmapFromByteArray();
98 addParcel(new_parcel);
99
100 }
101
102 public void NoParcelDataFromStorage()
103 {
104 resetSimParcels();
105 }
106 #endregion
107
108 #region Parcel Add/Remove/Get/Create
109 /// <summary>
110 /// Creates a basic Parcel object without an owner (a zeroed key)
111 /// </summary>
112 /// <returns></returns>
113 public Parcel createBaseParcel()
114 {
115 return new Parcel(new LLUUID(), false, m_world);
116 }
117
118 /// <summary>
119 /// Adds a parcel to the stored list and adds them to the parcelIDList to what they own
120 /// </summary>
121 /// <param name="new_parcel">The parcel being added</param>
122 public void addParcel(Parcel new_parcel)
123 {
124 lastParcelLocalID++;
125 new_parcel.parcelData.localID = lastParcelLocalID;
126 parcelList.Add(lastParcelLocalID, new_parcel.Copy());
127
128
129 bool[,] parcelBitmap = new_parcel.getParcelBitmap();
130 int x, y;
131 for (x = 0; x < 64; x++)
132 {
133 for (y = 0; y < 64; y++)
134 {
135 if (parcelBitmap[x, y])
136 {
137 parcelIDList[x, y] = lastParcelLocalID;
138 }
139 }
140 }
141 parcelList[lastParcelLocalID].forceUpdateParcelInfo();
142
143
144 }
145 /// <summary>
146 /// Removes a parcel from the list. Will not remove if local_id is still owning an area in parcelIDList
147 /// </summary>
148 /// <param name="local_id">Parcel.localID of the parcel to remove.</param>
149 public void removeParcel(int local_id)
150 {
151 int x, y;
152 for (x = 0; x < 64; x++)
153 {
154 for (y = 0; y < 64; y++)
155 {
156 if (parcelIDList[x, y] == local_id)
157 {
158 throw new Exception("Could not remove parcel. Still being used at " + x + ", " + y);
159 }
160 }
161 }
162 m_world.localStorage.RemoveParcel(parcelList[local_id].parcelData);
163 parcelList.Remove(local_id);
164 }
165
166 public void performFinalParcelJoin(Parcel master, Parcel slave)
167 {
168 int x, y;
169 bool[,] parcelBitmapSlave = slave.getParcelBitmap();
170 for (x = 0; x < 64; x++)
171 {
172 for (y = 0; y < 64; y++)
173 {
174 if (parcelBitmapSlave[x, y])
175 {
176 parcelIDList[x, y] = master.parcelData.localID;
177 }
178 }
179 }
180 removeParcel(slave.parcelData.localID);
181 }
182 /// <summary>
183 /// Get the parcel at the specified point
184 /// </summary>
185 /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
186 /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
187 /// <returns>Parcel at the point supplied</returns>
188 public Parcel getParcel(int x, int y)
189 {
190 if (x > 256 || y > 256 || x < 0 || y < 0)
191 {
192 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
193 }
194 else
195 {
196 return parcelList[parcelIDList[x / 4, y / 4]];
197 }
198
199 }
200 #endregion
201
202 #region Parcel Modification
203 /// <summary>
204 /// Subdivides a parcel
205 /// </summary>
206 /// <param name="start_x">West Point</param>
207 /// <param name="start_y">South Point</param>
208 /// <param name="end_x">East Point</param>
209 /// <param name="end_y">North Point</param>
210 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
211 /// <returns>Returns true if successful</returns>
212 public bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
213 {
214 //First, lets loop through the points and make sure they are all in the same parcel
215 //Get the parcel at start
216 Parcel startParcel = getParcel(start_x, start_y);
217 if (startParcel == null) return false; //No such parcel at the beginning
218
219 //Loop through the points
220 try
221 {
222 int totalX = end_x - start_x;
223 int totalY = end_y - start_y;
224 int x, y;
225 for (y = 0; y < totalY; y++)
226 {
227 for (x = 0; x < totalX; x++)
228 {
229 Parcel tempParcel = getParcel(start_x + x, start_y + y);
230 if (tempParcel == null) return false; //No such parcel at that point
231 if (tempParcel != startParcel) return false; //Subdividing over 2 parcels; no-no
232 }
233 }
234 }
235 catch (Exception e)
236 {
237 return false; //Exception. For now, lets skip subdivision
238 }
239
240 //If we are still here, then they are subdividing within one parcel
241 //Check owner
242 if (startParcel.parcelData.ownerID != attempting_user_id)
243 {
244 return false; //They cant do this!
245 }
246
247 //Lets create a new parcel with bitmap activated at that point (keeping the old parcels info)
248 Parcel newParcel = startParcel.Copy();
249 newParcel.parcelData.parcelName = "Subdivision of " + newParcel.parcelData.parcelName;
250 newParcel.parcelData.globalID = LLUUID.Random();
251
252 newParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(start_x, start_y, end_x, end_y));
253
254 //Now, lets set the subdivision area of the original to false
255 int startParcelIndex = startParcel.parcelData.localID;
256 parcelList[startParcelIndex].setParcelBitmap(Parcel.modifyParcelBitmapSquare(startParcel.getParcelBitmap(), start_x, start_y, end_x, end_y, false));
257 parcelList[startParcelIndex].forceUpdateParcelInfo();
258
259
260 //Now add the new parcel
261 addParcel(newParcel);
262
263
264
265
266
267 return true;
268 }
269 /// <summary>
270 /// Join 2 parcels together
271 /// </summary>
272 /// <param name="start_x">x value in first parcel</param>
273 /// <param name="start_y">y value in first parcel</param>
274 /// <param name="end_x">x value in second parcel</param>
275 /// <param name="end_y">y value in second parcel</param>
276 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the parcels</param>
277 /// <returns>Returns true if successful</returns>
278 public bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
279 {
280 end_x -= 4;
281 end_y -= 4;
282
283 //NOTE: The following only connects the parcels in each corner and not all the parcels that are within the selection box!
284 //This should be fixed later -- somewhat "incomplete code" --Ming
285 Parcel startParcel, endParcel;
286
287 try
288 {
289 startParcel = getParcel(start_x, start_y);
290 endParcel = getParcel(end_x, end_y);
291 }
292 catch (Exception e)
293 {
294 return false; //Error occured when trying to get the start and end parcels
295 }
296 if (startParcel == endParcel)
297 {
298 return false; //Subdivision of the same parcel is not allowed
299 }
300
301 //Check the parcel owners:
302 if (startParcel.parcelData.ownerID != endParcel.parcelData.ownerID)
303 {
304 return false;
305 }
306 if (startParcel.parcelData.ownerID != attempting_user_id)
307 {
308 //TODO: Group editing stuff. Avatar owner support for now
309 return false;
310 }
311
312 //Same owners! Lets join them
313 //Merge them to startParcel
314 parcelList[startParcel.parcelData.localID].setParcelBitmap(Parcel.mergeParcelBitmaps(startParcel.getParcelBitmap(), endParcel.getParcelBitmap()));
315 performFinalParcelJoin(startParcel, endParcel);
316
317 return true;
318
319
320
321 }
322 #endregion
323
324 #region Parcel Updating
325 /// <summary>
326 /// Where we send the ParcelOverlay packet to the client
327 /// </summary>
328 /// <param name="remote_client">The object representing the client</param>
329 public void sendParcelOverlay(IClientAPI remote_client)
330 {
331 const int PARCEL_BLOCKS_PER_PACKET = 1024;
332 int x, y = 0;
333 byte[] byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
334 int byteArrayCount = 0;
335 int sequenceID = 0;
336 ParcelOverlayPacket packet;
337
338 for (y = 0; y < 64; y++)
339 {
340 for (x = 0; x < 64; x++)
341 {
342 byte tempByte = (byte)0; //This represents the byte for the current 4x4
343 Parcel currentParcelBlock = getParcel(x * 4, y * 4);
344
345 if (currentParcelBlock.parcelData.ownerID == remote_client.AgentId)
346 {
347 //Owner Flag
348 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_REQUESTER);
349 }
350 else if (currentParcelBlock.parcelData.salePrice > 0 && (currentParcelBlock.parcelData.authBuyerID == LLUUID.Zero || currentParcelBlock.parcelData.authBuyerID == remote_client.AgentId))
351 {
352 //Sale Flag
353 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_IS_FOR_SALE);
354 }
355 else if (currentParcelBlock.parcelData.ownerID == LLUUID.Zero)
356 {
357 //Public Flag
358 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_PUBLIC);
359 }
360 else
361 {
362 //Other Flag
363 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_OTHER);
364 }
365
366
367 //Now for border control
368 if (x == 0)
369 {
370 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
371 }
372 else if (getParcel((x - 1) * 4, y * 4) != currentParcelBlock)
373 {
374 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
375 }
376
377 if (y == 0)
378 {
379 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
380 }
381 else if (getParcel(x * 4, (y - 1) * 4) != currentParcelBlock)
382 {
383 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
384 }
385
386 byteArray[byteArrayCount] = tempByte;
387 byteArrayCount++;
388 if (byteArrayCount >= PARCEL_BLOCKS_PER_PACKET)
389 {
390 byteArrayCount = 0;
391 packet = new ParcelOverlayPacket();
392 packet.ParcelData.Data = byteArray;
393 packet.ParcelData.SequenceID = sequenceID;
394 remote_client.OutPacket((Packet)packet);
395 sequenceID++;
396 byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
397 }
398 }
399 }
400
401 packet = new ParcelOverlayPacket();
402 packet.ParcelData.Data = byteArray;
403 packet.ParcelData.SequenceID = sequenceID; //Eh?
404 remote_client.OutPacket((Packet)packet);
405 }
406 #endregion
407
408 /// <summary>
409 /// Resets the sim to the default parcel (full sim parcel owned by the default user)
410 /// </summary>
411 public void resetSimParcels()
412 {
413 //Remove all the parcels in the sim and add a blank, full sim parcel set to public
414 parcelList.Clear();
415 lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
416 parcelIDList.Initialize();
417
418 Parcel fullSimParcel = new Parcel(LLUUID.Zero, false, m_world);
419
420 fullSimParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(0, 0, 256, 256));
421 fullSimParcel.parcelData.parcelName = "Your Sim Parcel";
422 fullSimParcel.parcelData.parcelDesc = "";
423
424 fullSimParcel.parcelData.ownerID = m_world.m_regInfo.MasterAvatarAssignedUUID;
425 fullSimParcel.parcelData.salePrice = 1;
426 fullSimParcel.parcelData.parcelFlags = libsecondlife.Parcel.ParcelFlags.ForSale;
427 fullSimParcel.parcelData.parcelStatus = libsecondlife.Parcel.ParcelStatus.Leased;
428
429 addParcel(fullSimParcel);
430
431 }
432 #endregion
433 }
434 #endregion
435
436
437 #region Parcel Class
438 /// <summary>
439 /// Keeps track of a specific parcel's information
440 /// </summary>
441 public class Parcel
442 {
443 #region Member Variables
444 public ParcelData parcelData = new ParcelData();
445 public World m_world;
446
447 private bool[,] parcelBitmap = new bool[64, 64];
448
449 #endregion
450
451
452 #region Constructors
453 public Parcel(LLUUID owner_id, bool is_group_owned, World world)
454 {
455 m_world = world;
456 parcelData.ownerID = owner_id;
457 parcelData.isGroupOwned = is_group_owned;
458
459 }
460 #endregion
461
462
463 #region Member Functions
464
465 #region General Functions
466 /// <summary>
467 /// Checks to see if this parcel contains a point
468 /// </summary>
469 /// <param name="x"></param>
470 /// <param name="y"></param>
471 /// <returns>Returns true if the parcel contains the specified point</returns>
472 public bool containsPoint(int x, int y)
473 {
474 if (x >= 0 && y >= 0 && x <= 256 && x <= 256)
475 {
476 return (parcelBitmap[x / 4, y / 4] == true);
477 }
478 else
479 {
480 return false;
481 }
482 }
483
484 public Parcel Copy()
485 {
486 Parcel newParcel = new Parcel(this.parcelData.ownerID, this.parcelData.isGroupOwned, m_world);
487
488 //Place all new variables here!
489 newParcel.parcelBitmap = (bool[,])(this.parcelBitmap.Clone());
490 newParcel.parcelData = parcelData.Copy();
491
492 return newParcel;
493 }
494
495 #endregion
496
497
498 #region Packet Request Handling
499 /// <summary>
500 /// Sends parcel properties as requested
501 /// </summary>
502 /// <param name="sequence_id">ID sent by client for them to keep track of</param>
503 /// <param name="snap_selection">Bool sent by client for them to use</param>
504 /// <param name="remote_client">Object representing the client</param>
505 public void sendParcelProperties(int sequence_id, bool snap_selection, int request_result, IClientAPI remote_client)
506 {
507
508 ParcelPropertiesPacket updatePacket = new ParcelPropertiesPacket();
509 updatePacket.ParcelData.AABBMax = parcelData.AABBMax;
510 updatePacket.ParcelData.AABBMin = parcelData.AABBMin;
511 updatePacket.ParcelData.Area = parcelData.area;
512 updatePacket.ParcelData.AuctionID = parcelData.auctionID;
513 updatePacket.ParcelData.AuthBuyerID =parcelData.authBuyerID; //unemplemented
514
515 updatePacket.ParcelData.Bitmap = parcelData.parcelBitmapByteArray;
516
517 updatePacket.ParcelData.Desc = libsecondlife.Helpers.StringToField(parcelData.parcelDesc);
518 updatePacket.ParcelData.Category = (byte)parcelData.category;
519 updatePacket.ParcelData.ClaimDate = parcelData.claimDate;
520 updatePacket.ParcelData.ClaimPrice = parcelData.claimPrice;
521 updatePacket.ParcelData.GroupID = parcelData.groupID;
522 updatePacket.ParcelData.GroupPrims = parcelData.groupPrims;
523 updatePacket.ParcelData.IsGroupOwned = parcelData.isGroupOwned;
524 updatePacket.ParcelData.LandingType = (byte)parcelData.landingType;
525 updatePacket.ParcelData.LocalID = parcelData.localID;
526 updatePacket.ParcelData.MaxPrims = 1000; //unemplemented
527 updatePacket.ParcelData.MediaAutoScale = parcelData.mediaAutoScale;
528 updatePacket.ParcelData.MediaID = parcelData.mediaID;
529 updatePacket.ParcelData.MediaURL = Helpers.StringToField(parcelData.mediaURL);
530 updatePacket.ParcelData.MusicURL = Helpers.StringToField(parcelData.musicURL);
531 updatePacket.ParcelData.Name = Helpers.StringToField(parcelData.parcelName);
532 updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
533 updatePacket.ParcelData.OtherCount = 0; //unemplemented
534 updatePacket.ParcelData.OtherPrims = 0; //unemplented
535 updatePacket.ParcelData.OwnerID = parcelData.ownerID;
536 updatePacket.ParcelData.OwnerPrims = 0; //unemplemented
537 updatePacket.ParcelData.ParcelFlags = (uint)parcelData.parcelFlags; //unemplemented
538 updatePacket.ParcelData.ParcelPrimBonus = (float)1.0; //unemplemented
539 updatePacket.ParcelData.PassHours = parcelData.passHours;
540 updatePacket.ParcelData.PassPrice = parcelData.passPrice;
541 updatePacket.ParcelData.PublicCount = 0; //unemplemented
542 updatePacket.ParcelData.RegionDenyAnonymous = false; //unemplemented
543 updatePacket.ParcelData.RegionDenyIdentified = false; //unemplemented
544 updatePacket.ParcelData.RegionDenyTransacted = false; //unemplemented
545 updatePacket.ParcelData.RegionPushOverride = true; //unemplemented
546 updatePacket.ParcelData.RentPrice = 0; //??
547 updatePacket.ParcelData.RequestResult = request_result;
548 updatePacket.ParcelData.SalePrice = parcelData.salePrice; //unemplemented
549 updatePacket.ParcelData.SelectedPrims = 0; //unemeplemented
550 updatePacket.ParcelData.SelfCount = 0;//unemplemented
551 updatePacket.ParcelData.SequenceID = sequence_id;
552 updatePacket.ParcelData.SimWideMaxPrims = 15000; //unemplemented
553 updatePacket.ParcelData.SimWideTotalPrims = 0; //unemplemented
554 updatePacket.ParcelData.SnapSelection = snap_selection;
555 updatePacket.ParcelData.SnapshotID = parcelData.snapshotID;
556 updatePacket.ParcelData.Status = (byte)parcelData.parcelStatus;
557 updatePacket.ParcelData.TotalPrims = 0; //unemplemented
558 updatePacket.ParcelData.UserLocation = parcelData.userLocation;
559 updatePacket.ParcelData.UserLookAt = parcelData.userLookAt;
560 remote_client.OutPacket((Packet)updatePacket);
561 }
562
563 public void updateParcelProperties(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
564 {
565 if (remote_client.AgentId == parcelData.ownerID)
566 {
567 //Needs later group support
568 parcelData.authBuyerID = packet.ParcelData.AuthBuyerID;
569 parcelData.category = (libsecondlife.Parcel.ParcelCategory)packet.ParcelData.Category;
570 parcelData.parcelDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc);
571 parcelData.groupID = packet.ParcelData.GroupID;
572 parcelData.landingType = packet.ParcelData.LandingType;
573 parcelData.mediaAutoScale = packet.ParcelData.MediaAutoScale;
574 parcelData.mediaID = packet.ParcelData.MediaID;
575 parcelData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL);
576 parcelData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL);
577 parcelData.parcelName = libsecondlife.Helpers.FieldToUTF8String(packet.ParcelData.Name);
578 parcelData.parcelFlags = (libsecondlife.Parcel.ParcelFlags)packet.ParcelData.ParcelFlags;
579 parcelData.passHours = packet.ParcelData.PassHours;
580 parcelData.passPrice = packet.ParcelData.PassPrice;
581 parcelData.salePrice = packet.ParcelData.SalePrice;
582 parcelData.snapshotID = packet.ParcelData.SnapshotID;
583 parcelData.userLocation = packet.ParcelData.UserLocation;
584 parcelData.userLookAt = packet.ParcelData.UserLookAt;
585
586 foreach (Avatar av in m_world.Avatars.Values)
587 {
588 Parcel over = m_world.parcelManager.getParcel((int)Math.Round(av.Pos.X), (int)Math.Round(av.Pos.Y));
589 if (over == this)
590 {
591 sendParcelProperties(0, false, 0, av.ControllingClient);
592 }
593 }
594 }
595 }
596 #endregion
597
598
599 #region Update Functions
600 /// <summary>
601 /// Updates the AABBMin and AABBMax values after area/shape modification of parcel
602 /// </summary>
603 private void updateAABBAndAreaValues()
604 {
605 int min_x = 64;
606 int min_y = 64;
607 int max_x = 0;
608 int max_y = 0;
609 int tempArea = 0;
610 int x, y;
611 for (x = 0; x < 64; x++)
612 {
613 for (y = 0; y < 64; y++)
614 {
615 if (parcelBitmap[x, y] == true)
616 {
617 if (min_x > x) min_x = x;
618 if (min_y > y) min_y = y;
619 if (max_x < x) max_x = x;
620 if (max_y < y) max_y = y;
621 tempArea += 16; //16sqm parcel
622 }
623 }
624 }
625 parcelData.AABBMin = new LLVector3((float)(min_x * 4), (float)(min_y * 4), m_world.Terrain[(min_x * 4), (min_y * 4)]);
626 parcelData.AABBMax = new LLVector3((float)(max_x * 4), (float)(max_y * 4), m_world.Terrain[(max_x * 4), (max_y * 4)]);
627 parcelData.area = tempArea;
628 }
629
630 public void updateParcelBitmapByteArray()
631 {
632 parcelData.parcelBitmapByteArray = convertParcelBitmapToBytes();
633 }
634
635 /// <summary>
636 /// Update all settings in parcel such as area, bitmap byte array, etc
637 /// </summary>
638 public void forceUpdateParcelInfo()
639 {
640 this.updateAABBAndAreaValues();
641 this.updateParcelBitmapByteArray();
642 }
643
644 public void setParcelBitmapFromByteArray()
645 {
646 parcelBitmap = convertBytesToParcelBitmap();
647 }
648 #endregion
649
650
651 #region Parcel Bitmap Functions
652 /// <summary>
653 /// Sets the parcel's bitmap manually
654 /// </summary>
655 /// <param name="bitmap">64x64 block representing where this parcel is on a map</param>
656 public void setParcelBitmap(bool[,] bitmap)
657 {
658 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
659 {
660 //Throw an exception - The bitmap is not 64x64
661 throw new Exception("Error: Invalid Parcel Bitmap");
662 }
663 else
664 {
665 //Valid: Lets set it
666 parcelBitmap = bitmap;
667 forceUpdateParcelInfo();
668
669 }
670 }
671 /// <summary>
672 /// Gets the parcels bitmap manually
673 /// </summary>
674 /// <returns></returns>
675 public bool[,] getParcelBitmap()
676 {
677 return parcelBitmap;
678 }
679 /// <summary>
680 /// Converts the parcel bitmap to a packet friendly byte array
681 /// </summary>
682 /// <returns></returns>
683 private byte[] convertParcelBitmapToBytes()
684 {
685 byte[] tempConvertArr = new byte[512];
686 byte tempByte = 0;
687 int x, y, i, byteNum = 0;
688 i = 0;
689 for (y = 0; y < 64; y++)
690 {
691 for (x = 0; x < 64; x++)
692 {
693 tempByte = Convert.ToByte(tempByte | Convert.ToByte(parcelBitmap[x, y]) << (i++ % 8));
694 if (i % 8 == 0)
695 {
696 tempConvertArr[byteNum] = tempByte;
697 tempByte = (byte)0;
698 i = 0;
699 byteNum++;
700 }
701 }
702 }
703 return tempConvertArr;
704 }
705
706 private bool[,] convertBytesToParcelBitmap()
707 {
708 bool[,] tempConvertMap = new bool[64, 64];
709 tempConvertMap.Initialize();
710 byte tempByte = 0;
711 int x = 0, y = 0, i = 0, bitNum = 0;
712 for(i = 0; i < 512; i++)
713 {
714 tempByte = parcelData.parcelBitmapByteArray[i];
715 for(bitNum = 0; bitNum < 8; bitNum++)
716 {
717 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte)1);
718 tempConvertMap[x, y] = bit;
719 x++;
720 if(x > 63)
721 {
722 x = 0;
723 y++;
724 }
725
726 }
727
728 }
729 return tempConvertMap;
730 }
731 /// <summary>
732 /// Full sim parcel creation
733 /// </summary>
734 /// <returns></returns>
735 public static bool[,] basicFullRegionParcelBitmap()
736 {
737 return getSquareParcelBitmap(0, 0, 256, 256);
738 }
739
740 /// <summary>
741 /// Used to modify the bitmap between the x and y points. Points use 64 scale
742 /// </summary>
743 /// <param name="start_x"></param>
744 /// <param name="start_y"></param>
745 /// <param name="end_x"></param>
746 /// <param name="end_y"></param>
747 /// <returns></returns>
748 public static bool[,] getSquareParcelBitmap(int start_x, int start_y, int end_x, int end_y)
749 {
750
751 bool[,] tempBitmap = new bool[64, 64];
752 tempBitmap.Initialize();
753
754 tempBitmap = modifyParcelBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
755 return tempBitmap;
756 }
757
758 /// <summary>
759 /// Change a parcel's bitmap at within a square and set those points to a specific value
760 /// </summary>
761 /// <param name="parcel_bitmap"></param>
762 /// <param name="start_x"></param>
763 /// <param name="start_y"></param>
764 /// <param name="end_x"></param>
765 /// <param name="end_y"></param>
766 /// <param name="set_value"></param>
767 /// <returns></returns>
768 public static bool[,] modifyParcelBitmapSquare(bool[,] parcel_bitmap, int start_x, int start_y, int end_x, int end_y, bool set_value)
769 {
770 if (parcel_bitmap.GetLength(0) != 64 || parcel_bitmap.GetLength(1) != 64 || parcel_bitmap.Rank != 2)
771 {
772 //Throw an exception - The bitmap is not 64x64
773 throw new Exception("Error: Invalid Parcel Bitmap in modifyParcelBitmapSquare()");
774 }
775
776 int x, y;
777 for (y = 0; y < 64; y++)
778 {
779 for (x = 0; x < 64; x++)
780 {
781 if (x >= start_x / 4 && x < end_x / 4
782 && y >= start_y / 4 && y < end_y / 4)
783 {
784 parcel_bitmap[x, y] = set_value;
785 }
786 }
787 }
788 return parcel_bitmap;
789 }
790 /// <summary>
791 /// Join the true values of 2 bitmaps together
792 /// </summary>
793 /// <param name="bitmap_base"></param>
794 /// <param name="bitmap_add"></param>
795 /// <returns></returns>
796 public static bool[,] mergeParcelBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
797 {
798 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2)
799 {
800 //Throw an exception - The bitmap is not 64x64
801 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeParcelBitmaps");
802 }
803 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
804 {
805 //Throw an exception - The bitmap is not 64x64
806 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeParcelBitmaps");
807
808 }
809
810 int x, y;
811 for (y = 0; y < 64; y++)
812 {
813 for (x = 0; x < 64; x++)
814 {
815 if (bitmap_add[x, y])
816 {
817 bitmap_base[x, y] = true;
818 }
819 }
820 }
821 return bitmap_base;
822 }
823 #endregion
824
825 #endregion
826
827
828 }
829 #endregion
830
831
832}