aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/OpenSim.RegionServer/Simulator/ParcelManager.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/OpenSim.RegionServer/Simulator/ParcelManager.cs')
-rw-r--r--OpenSim/OpenSim.RegionServer/Simulator/ParcelManager.cs832
1 files changed, 832 insertions, 0 deletions
diff --git a/OpenSim/OpenSim.RegionServer/Simulator/ParcelManager.cs b/OpenSim/OpenSim.RegionServer/Simulator/ParcelManager.cs
new file mode 100644
index 0000000..a9d4eea
--- /dev/null
+++ b/OpenSim/OpenSim.RegionServer/Simulator/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.RegionServer.Simulator;
34using OpenSim.Framework.Interfaces;
35using OpenSim.Framework.Types;
36using OpenSim.RegionServer.Client;
37
38namespace OpenSim.RegionServer.Simulator
39{
40 public delegate void ParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id, bool snap_selection, ClientView remote_client);
41 public delegate void ParcelDivideRequest(int west, int south, int east, int north, ClientView remote_client);
42 public delegate void ParcelJoinRequest(int west, int south, int east, int north, ClientView remote_client);
43 public delegate void ParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, ClientView remote_client);
44
45 #region ParcelManager Class
46 /// <summary>
47 /// Handles Parcel objects and operations requiring information from other Parcel objects (divide, join, etc)
48 /// </summary>
49 public class ParcelManager : OpenSim.Framework.Interfaces.ILocalStorageParcelReceiver
50 {
51
52 #region Constants
53 //Parcel types set with flags in ParcelOverlay.
54 //Only one of these can be used.
55 public const byte PARCEL_TYPE_PUBLIC = (byte)0; //Equals 00000000
56 public const byte PARCEL_TYPE_OWNED_BY_OTHER = (byte)1; //Equals 00000001
57 public const byte PARCEL_TYPE_OWNED_BY_GROUP = (byte)2; //Equals 00000010
58 public const byte PARCEL_TYPE_OWNED_BY_REQUESTER = (byte)3; //Equals 00000011
59 public const byte PARCEL_TYPE_IS_FOR_SALE = (byte)4; //Equals 00000100
60 public const byte PARCEL_TYPE_IS_BEING_AUCTIONED = (byte)5; //Equals 00000101
61
62
63 //Flags that when set, a border on the given side will be placed
64 //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)
65 //This took forever to figure out -- jeesh. /blame LL for even having to send these
66 public const byte PARCEL_FLAG_PROPERTY_BORDER_WEST = (byte)64; //Equals 01000000
67 public const byte PARCEL_FLAG_PROPERTY_BORDER_SOUTH = (byte)128; //Equals 10000000
68
69 //RequestResults (I think these are right, they seem to work):
70 public const int PARCEL_RESULT_ONE_PARCEL = 0; // The request they made contained only one parcel
71 public const int PARCEL_RESULT_MULTIPLE_PARCELS = 1; // The request they made contained more than one parcel
72
73 //These are other constants. Yay!
74 public const int START_PARCEL_LOCAL_ID = 1;
75 #endregion
76
77 #region Member Variables
78 public Dictionary<int, Parcel> parcelList = new Dictionary<int, Parcel>();
79 private int lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
80 private int[,] parcelIDList = new int[64, 64];
81
82 private static World m_world;
83 #endregion
84
85 #region Constructors
86 public ParcelManager(World world)
87 {
88
89 m_world = world;
90 parcelIDList.Initialize();
91
92 }
93 #endregion
94
95 #region Member Functions
96
97 #region Parcel From Storage Functions
98 public void ParcelFromStorage(ParcelData data)
99 {
100 Parcel new_parcel = new Parcel(data.ownerID, data.isGroupOwned, m_world);
101 new_parcel.parcelData = data.Copy();
102 new_parcel.setParcelBitmapFromByteArray();
103 addParcel(new_parcel);
104
105 }
106
107 public void NoParcelDataFromStorage()
108 {
109 resetSimParcels();
110 }
111 #endregion
112
113 #region Parcel Add/Remove/Get/Create
114 /// <summary>
115 /// Creates a basic Parcel object without an owner (a zeroed key)
116 /// </summary>
117 /// <returns></returns>
118 public Parcel createBaseParcel()
119 {
120 return new Parcel(new LLUUID(), false, m_world);
121 }
122
123 /// <summary>
124 /// Adds a parcel to the stored list and adds them to the parcelIDList to what they own
125 /// </summary>
126 /// <param name="new_parcel">The parcel being added</param>
127 public void addParcel(Parcel new_parcel)
128 {
129 lastParcelLocalID++;
130 new_parcel.parcelData.localID = lastParcelLocalID;
131 parcelList.Add(lastParcelLocalID, new_parcel.Copy());
132
133
134 bool[,] parcelBitmap = new_parcel.getParcelBitmap();
135 int x, y;
136 for (x = 0; x < 64; x++)
137 {
138 for (y = 0; y < 64; y++)
139 {
140 if (parcelBitmap[x, y])
141 {
142 parcelIDList[x, y] = lastParcelLocalID;
143 }
144 }
145 }
146 parcelList[lastParcelLocalID].forceUpdateParcelInfo();
147
148
149 }
150 /// <summary>
151 /// Removes a parcel from the list. Will not remove if local_id is still owning an area in parcelIDList
152 /// </summary>
153 /// <param name="local_id">Parcel.localID of the parcel to remove.</param>
154 public void removeParcel(int local_id)
155 {
156 int x, y;
157 for (x = 0; x < 64; x++)
158 {
159 for (y = 0; y < 64; y++)
160 {
161 if (parcelIDList[x, y] == local_id)
162 {
163 throw new Exception("Could not remove parcel. Still being used at " + x + ", " + y);
164 }
165 }
166 }
167 m_world.localStorage.RemoveParcel(parcelList[local_id].parcelData);
168 parcelList.Remove(local_id);
169 }
170
171 public void performFinalParcelJoin(Parcel master, Parcel slave)
172 {
173 int x, y;
174 bool[,] parcelBitmapSlave = slave.getParcelBitmap();
175 for (x = 0; x < 64; x++)
176 {
177 for (y = 0; y < 64; y++)
178 {
179 if (parcelBitmapSlave[x, y])
180 {
181 parcelIDList[x, y] = master.parcelData.localID;
182 }
183 }
184 }
185 removeParcel(slave.parcelData.localID);
186 }
187 /// <summary>
188 /// Get the parcel at the specified point
189 /// </summary>
190 /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
191 /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
192 /// <returns>Parcel at the point supplied</returns>
193 public Parcel getParcel(int x, int y)
194 {
195 if (x > 256 || y > 256 || x < 0 || y < 0)
196 {
197 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
198 }
199 else
200 {
201 return parcelList[parcelIDList[x / 4, y / 4]];
202 }
203
204 }
205 #endregion
206
207 #region Parcel Modification
208 /// <summary>
209 /// Subdivides a parcel
210 /// </summary>
211 /// <param name="start_x">West Point</param>
212 /// <param name="start_y">South Point</param>
213 /// <param name="end_x">East Point</param>
214 /// <param name="end_y">North Point</param>
215 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
216 /// <returns>Returns true if successful</returns>
217 public bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
218 {
219 //First, lets loop through the points and make sure they are all in the same parcel
220 //Get the parcel at start
221 Parcel startParcel = getParcel(start_x, start_y);
222 if (startParcel == null) return false; //No such parcel at the beginning
223
224 //Loop through the points
225 try
226 {
227 int totalX = end_x - start_x;
228 int totalY = end_y - start_y;
229 int x, y;
230 for (y = 0; y < totalY; y++)
231 {
232 for (x = 0; x < totalX; x++)
233 {
234 Parcel tempParcel = getParcel(start_x + x, start_y + y);
235 if (tempParcel == null) return false; //No such parcel at that point
236 if (tempParcel != startParcel) return false; //Subdividing over 2 parcels; no-no
237 }
238 }
239 }
240 catch (Exception e)
241 {
242 return false; //Exception. For now, lets skip subdivision
243 }
244
245 //If we are still here, then they are subdividing within one parcel
246 //Check owner
247 if (startParcel.parcelData.ownerID != attempting_user_id)
248 {
249 return false; //They cant do this!
250 }
251
252 //Lets create a new parcel with bitmap activated at that point (keeping the old parcels info)
253 Parcel newParcel = startParcel.Copy();
254 newParcel.parcelData.parcelName = "Subdivision of " + newParcel.parcelData.parcelName;
255 newParcel.parcelData.globalID = LLUUID.Random();
256
257 newParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(start_x, start_y, end_x, end_y));
258
259 //Now, lets set the subdivision area of the original to false
260 int startParcelIndex = startParcel.parcelData.localID;
261 parcelList[startParcelIndex].setParcelBitmap(Parcel.modifyParcelBitmapSquare(startParcel.getParcelBitmap(), start_x, start_y, end_x, end_y, false));
262 parcelList[startParcelIndex].forceUpdateParcelInfo();
263
264
265 //Now add the new parcel
266 addParcel(newParcel);
267
268
269
270
271
272 return true;
273 }
274 /// <summary>
275 /// Join 2 parcels together
276 /// </summary>
277 /// <param name="start_x">x value in first parcel</param>
278 /// <param name="start_y">y value in first parcel</param>
279 /// <param name="end_x">x value in second parcel</param>
280 /// <param name="end_y">y value in second parcel</param>
281 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the parcels</param>
282 /// <returns>Returns true if successful</returns>
283 public bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
284 {
285 end_x -= 4;
286 end_y -= 4;
287 Console.WriteLine("Joining Parcels between (" + start_x + ", " + start_y + ") and (" + end_x + ", " + end_y + ")");
288
289 //NOTE: The following only connects the parcels in each corner and not all the parcels that are within the selection box!
290 //This should be fixed later -- somewhat "incomplete code" --Ming
291 Parcel startParcel, endParcel;
292
293 try
294 {
295 startParcel = getParcel(start_x, start_y);
296 endParcel = getParcel(end_x, end_y);
297 }
298 catch (Exception e)
299 {
300 return false; //Error occured when trying to get the start and end parcels
301 }
302 if (startParcel == endParcel)
303 {
304 return false; //Subdivision of the same parcel is not allowed
305 }
306
307 //Check the parcel owners:
308 if (startParcel.parcelData.ownerID != endParcel.parcelData.ownerID)
309 {
310 return false;
311 }
312 if (startParcel.parcelData.ownerID != attempting_user_id)
313 {
314 //TODO: Group editing stuff. Avatar owner support for now
315 return false;
316 }
317
318 Console.WriteLine("Performing Join on parcel: " + startParcel.parcelData.parcelName + " - " + startParcel.parcelData.area + "sqm and " + endParcel.parcelData.parcelName + " - " + endParcel.parcelData.area + "sqm");
319 //Same owners! Lets join them
320 //Merge them to startParcel
321 parcelList[startParcel.parcelData.localID].setParcelBitmap(Parcel.mergeParcelBitmaps(startParcel.getParcelBitmap(), endParcel.getParcelBitmap()));
322 performFinalParcelJoin(startParcel, endParcel);
323
324 return true;
325
326
327
328 }
329 #endregion
330
331 #region Parcel Updating
332 /// <summary>
333 /// Where we send the ParcelOverlay packet to the client
334 /// </summary>
335 /// <param name="remote_client">The object representing the client</param>
336 public void sendParcelOverlay(ClientView remote_client)
337 {
338 const int PARCEL_BLOCKS_PER_PACKET = 1024;
339 int x, y = 0;
340 byte[] byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
341 int byteArrayCount = 0;
342 int sequenceID = 0;
343 ParcelOverlayPacket packet;
344
345 for (y = 0; y < 64; y++)
346 {
347 for (x = 0; x < 64; x++)
348 {
349 byte tempByte = (byte)0; //This represents the byte for the current 4x4
350 Parcel currentParcelBlock = getParcel(x * 4, y * 4);
351
352 if (currentParcelBlock.parcelData.ownerID == remote_client.AgentID)
353 {
354 //Owner Flag
355 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_REQUESTER);
356 }
357 else if (currentParcelBlock.parcelData.salePrice > 0 && (currentParcelBlock.parcelData.authBuyerID == LLUUID.Zero || currentParcelBlock.parcelData.authBuyerID == remote_client.AgentID))
358 {
359 //Sale Flag
360 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_IS_FOR_SALE);
361 }
362 else if (currentParcelBlock.parcelData.ownerID == LLUUID.Zero)
363 {
364 //Public Flag
365 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_PUBLIC);
366 }
367 else
368 {
369 //Other Flag
370 tempByte = Convert.ToByte(tempByte | PARCEL_TYPE_OWNED_BY_OTHER);
371 }
372
373
374 //Now for border control
375 if (x == 0)
376 {
377 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
378 }
379 else if (getParcel((x - 1) * 4, y * 4) != currentParcelBlock)
380 {
381 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_WEST);
382 }
383
384 if (y == 0)
385 {
386 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
387 }
388 else if (getParcel(x * 4, (y - 1) * 4) != currentParcelBlock)
389 {
390 tempByte = Convert.ToByte(tempByte | PARCEL_FLAG_PROPERTY_BORDER_SOUTH);
391 }
392
393 byteArray[byteArrayCount] = tempByte;
394 byteArrayCount++;
395 if (byteArrayCount >= PARCEL_BLOCKS_PER_PACKET)
396 {
397 byteArrayCount = 0;
398 packet = new ParcelOverlayPacket();
399 packet.ParcelData.Data = byteArray;
400 packet.ParcelData.SequenceID = sequenceID;
401 remote_client.OutPacket((Packet)packet);
402 sequenceID++;
403 byteArray = new byte[PARCEL_BLOCKS_PER_PACKET];
404 }
405 }
406 }
407
408 packet = new ParcelOverlayPacket();
409 packet.ParcelData.Data = byteArray;
410 packet.ParcelData.SequenceID = sequenceID; //Eh?
411 remote_client.OutPacket((Packet)packet);
412 }
413 #endregion
414
415 /// <summary>
416 /// Resets the sim to the default parcel (full sim parcel owned by the default user)
417 /// </summary>
418 public void resetSimParcels()
419 {
420 //Remove all the parcels in the sim and add a blank, full sim parcel set to public
421 parcelList.Clear();
422 lastParcelLocalID = START_PARCEL_LOCAL_ID - 1;
423 parcelIDList.Initialize();
424
425 Parcel fullSimParcel = new Parcel(LLUUID.Zero, false, m_world);
426
427 fullSimParcel.setParcelBitmap(Parcel.getSquareParcelBitmap(0, 0, 256, 256));
428 fullSimParcel.parcelData.parcelName = "Your Sim Parcel";
429 fullSimParcel.parcelData.parcelDesc = "";
430
431 fullSimParcel.parcelData.ownerID = m_world.m_regInfo.MasterAvatarAssignedUUID;
432 fullSimParcel.parcelData.salePrice = 1;
433 fullSimParcel.parcelData.parcelFlags = libsecondlife.Parcel.ParcelFlags.ForSale;
434 fullSimParcel.parcelData.parcelStatus = libsecondlife.Parcel.ParcelStatus.Leased;
435
436 addParcel(fullSimParcel);
437
438 }
439 #endregion
440 }
441 #endregion
442
443
444 #region Parcel Class
445 /// <summary>
446 /// Keeps track of a specific parcel's information
447 /// </summary>
448 public class Parcel
449 {
450 #region Member Variables
451 public ParcelData parcelData = new ParcelData();
452 public World m_world;
453
454 private bool[,] parcelBitmap = new bool[64, 64];
455
456 #endregion
457
458
459 #region Constructors
460 public Parcel(LLUUID owner_id, bool is_group_owned, World world)
461 {
462 m_world = world;
463 parcelData.ownerID = owner_id;
464 parcelData.isGroupOwned = is_group_owned;
465
466 }
467 #endregion
468
469
470 #region Member Functions
471
472 #region General Functions
473 /// <summary>
474 /// Checks to see if this parcel contains a point
475 /// </summary>
476 /// <param name="x"></param>
477 /// <param name="y"></param>
478 /// <returns>Returns true if the parcel contains the specified point</returns>
479 public bool containsPoint(int x, int y)
480 {
481 if (x >= 0 && y >= 0 && x <= 256 && x <= 256)
482 {
483 return (parcelBitmap[x / 4, y / 4] == true);
484 }
485 else
486 {
487 return false;
488 }
489 }
490
491 public Parcel Copy()
492 {
493 Parcel newParcel = new Parcel(this.parcelData.ownerID, this.parcelData.isGroupOwned, m_world);
494
495 //Place all new variables here!
496 newParcel.parcelBitmap = (bool[,])(this.parcelBitmap.Clone());
497 newParcel.parcelData = parcelData.Copy();
498
499 return newParcel;
500 }
501
502 #endregion
503
504
505 #region Packet Request Handling
506 /// <summary>
507 /// Sends parcel properties as requested
508 /// </summary>
509 /// <param name="sequence_id">ID sent by client for them to keep track of</param>
510 /// <param name="snap_selection">Bool sent by client for them to use</param>
511 /// <param name="remote_client">Object representing the client</param>
512 public void sendParcelProperties(int sequence_id, bool snap_selection, int request_result, ClientView remote_client)
513 {
514
515 ParcelPropertiesPacket updatePacket = new ParcelPropertiesPacket();
516 updatePacket.ParcelData.AABBMax = parcelData.AABBMax;
517 updatePacket.ParcelData.AABBMin = parcelData.AABBMin;
518 updatePacket.ParcelData.Area = parcelData.area;
519 updatePacket.ParcelData.AuctionID = parcelData.auctionID;
520 updatePacket.ParcelData.AuthBuyerID =parcelData.authBuyerID; //unemplemented
521
522 updatePacket.ParcelData.Bitmap = parcelData.parcelBitmapByteArray;
523
524 updatePacket.ParcelData.Desc = libsecondlife.Helpers.StringToField(parcelData.parcelDesc);
525 updatePacket.ParcelData.Category = (byte)parcelData.category;
526 updatePacket.ParcelData.ClaimDate = parcelData.claimDate;
527 updatePacket.ParcelData.ClaimPrice = parcelData.claimPrice;
528 updatePacket.ParcelData.GroupID = parcelData.groupID;
529 updatePacket.ParcelData.GroupPrims = parcelData.groupPrims;
530 updatePacket.ParcelData.IsGroupOwned = parcelData.isGroupOwned;
531 updatePacket.ParcelData.LandingType = (byte)parcelData.landingType;
532 updatePacket.ParcelData.LocalID = parcelData.localID;
533 updatePacket.ParcelData.MaxPrims = 1000; //unemplemented
534 updatePacket.ParcelData.MediaAutoScale = parcelData.mediaAutoScale;
535 updatePacket.ParcelData.MediaID = parcelData.mediaID;
536 updatePacket.ParcelData.MediaURL = Helpers.StringToField(parcelData.mediaURL);
537 updatePacket.ParcelData.MusicURL = Helpers.StringToField(parcelData.musicURL);
538 updatePacket.ParcelData.Name = Helpers.StringToField(parcelData.parcelName);
539 updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
540 updatePacket.ParcelData.OtherCount = 0; //unemplemented
541 updatePacket.ParcelData.OtherPrims = 0; //unemplented
542 updatePacket.ParcelData.OwnerID = parcelData.ownerID;
543 updatePacket.ParcelData.OwnerPrims = 0; //unemplemented
544 updatePacket.ParcelData.ParcelFlags = (uint)parcelData.parcelFlags; //unemplemented
545 updatePacket.ParcelData.ParcelPrimBonus = (float)1.0; //unemplemented
546 updatePacket.ParcelData.PassHours = parcelData.passHours;
547 updatePacket.ParcelData.PassPrice = parcelData.passPrice;
548 updatePacket.ParcelData.PublicCount = 0; //unemplemented
549 updatePacket.ParcelData.RegionDenyAnonymous = false; //unemplemented
550 updatePacket.ParcelData.RegionDenyIdentified = false; //unemplemented
551 updatePacket.ParcelData.RegionDenyTransacted = false; //unemplemented
552 updatePacket.ParcelData.RegionPushOverride = true; //unemplemented
553 updatePacket.ParcelData.RentPrice = 0; //??
554 updatePacket.ParcelData.RequestResult = request_result;
555 updatePacket.ParcelData.SalePrice = parcelData.salePrice; //unemplemented
556 updatePacket.ParcelData.SelectedPrims = 0; //unemeplemented
557 updatePacket.ParcelData.SelfCount = 0;//unemplemented
558 updatePacket.ParcelData.SequenceID = sequence_id;
559 updatePacket.ParcelData.SimWideMaxPrims = 15000; //unemplemented
560 updatePacket.ParcelData.SimWideTotalPrims = 0; //unemplemented
561 updatePacket.ParcelData.SnapSelection = snap_selection;
562 updatePacket.ParcelData.SnapshotID = parcelData.snapshotID;
563 updatePacket.ParcelData.Status = (byte)parcelData.parcelStatus;
564 updatePacket.ParcelData.TotalPrims = 0; //unemplemented
565 updatePacket.ParcelData.UserLocation = parcelData.userLocation;
566 updatePacket.ParcelData.UserLookAt = parcelData.userLookAt;
567
568 remote_client.OutPacket((Packet)updatePacket);
569 }
570
571 public void updateParcelProperties(ParcelPropertiesUpdatePacket packet, ClientView remote_client)
572 {
573 if (remote_client.AgentID == parcelData.ownerID)
574 {
575 //Needs later group support
576 Console.WriteLine("Request for update - parcel #" + parcelData.localID);
577 parcelData.authBuyerID = packet.ParcelData.AuthBuyerID;
578 parcelData.category = (libsecondlife.Parcel.ParcelCategory)packet.ParcelData.Category;
579 parcelData.parcelDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc);
580 parcelData.groupID = packet.ParcelData.GroupID;
581 parcelData.landingType = packet.ParcelData.LandingType;
582 parcelData.mediaAutoScale = packet.ParcelData.MediaAutoScale;
583 parcelData.mediaID = packet.ParcelData.MediaID;
584 parcelData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL);
585 parcelData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL);
586 parcelData.parcelName = libsecondlife.Helpers.FieldToUTF8String(packet.ParcelData.Name);
587 parcelData.parcelFlags = (libsecondlife.Parcel.ParcelFlags)packet.ParcelData.ParcelFlags;
588 parcelData.passHours = packet.ParcelData.PassHours;
589 parcelData.passPrice = packet.ParcelData.PassPrice;
590 parcelData.salePrice = packet.ParcelData.SalePrice;
591 parcelData.snapshotID = packet.ParcelData.SnapshotID;
592 parcelData.userLocation = packet.ParcelData.UserLocation;
593 parcelData.userLookAt = packet.ParcelData.UserLookAt;
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}