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