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