aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/LandManagement
diff options
context:
space:
mode:
authormingchen2008-03-22 23:10:22 +0000
committermingchen2008-03-22 23:10:22 +0000
commit71ca162821ac0e5aae5f91c433b91549ae6d5419 (patch)
treefa2f13c2541075aba6807fcf95364466a785bd51 /OpenSim/Region/Environment/LandManagement
parentImplements llLoopSound(), llStopSound(), and llAdjustSoundVolume(). (diff)
downloadopensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.zip
opensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.tar.gz
opensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.tar.bz2
opensim-SC_OLD-71ca162821ac0e5aae5f91c433b91549ae6d5419.tar.xz
*Moved LandManagement into its own region module (spiffy!)
Diffstat (limited to 'OpenSim/Region/Environment/LandManagement')
-rw-r--r--OpenSim/Region/Environment/LandManagement/Land.cs842
-rw-r--r--OpenSim/Region/Environment/LandManagement/LandManager.cs942
2 files changed, 0 insertions, 1784 deletions
diff --git a/OpenSim/Region/Environment/LandManagement/Land.cs b/OpenSim/Region/Environment/LandManagement/Land.cs
deleted file mode 100644
index 5b84103..0000000
--- a/OpenSim/Region/Environment/LandManagement/Land.cs
+++ /dev/null
@@ -1,842 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.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;
33using OpenSim.Framework.Console;
34using OpenSim.Region.Environment.Scenes;
35using OpenSim.Region.Environment.Interfaces;
36
37namespace OpenSim.Region.Environment.LandManagement
38{
39
40 #region Parcel Class
41
42 /// <summary>
43 /// Keeps track of a specific piece of land's information
44 /// </summary>
45 public class Land
46 {
47 #region Member Variables
48
49 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50
51 public LandData landData = new LandData();
52 public List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>();
53 public Scene m_scene;
54
55 private bool[,] landBitmap = new bool[64,64];
56
57 #endregion
58
59 #region Constructors
60
61 public Land(LLUUID owner_id, bool is_group_owned, Scene scene)
62 {
63 m_scene = scene;
64 landData.ownerID = owner_id;
65 landData.isGroupOwned = is_group_owned;
66 }
67
68 #endregion
69
70 #region Member Functions
71
72 #region General Functions
73
74 /// <summary>
75 /// Checks to see if this land object contains a point
76 /// </summary>
77 /// <param name="x"></param>
78 /// <param name="y"></param>
79 /// <returns>Returns true if the piece of land contains the specified point</returns>
80 public bool containsPoint(int x, int y)
81 {
82 if (x >= 0 && y >= 0 && x <= Constants.RegionSize && x <= Constants.RegionSize)
83 {
84 return (landBitmap[x/4, y/4] == true);
85 }
86 else
87 {
88 return false;
89 }
90 }
91
92 public Land Copy()
93 {
94 Land newLand = new Land(landData.ownerID, landData.isGroupOwned, m_scene);
95
96 //Place all new variables here!
97 newLand.landBitmap = (bool[,]) (landBitmap.Clone());
98 newLand.landData = landData.Copy();
99
100 return newLand;
101 }
102
103 #endregion
104
105 #region Packet Request Handling
106
107 /// <summary>
108 /// Sends land properties as requested
109 /// </summary>
110 /// <param name="sequence_id">ID sent by client for them to keep track of</param>
111 /// <param name="snap_selection">Bool sent by client for them to use</param>
112 /// <param name="remote_client">Object representing the client</param>
113 public void sendLandProperties(int sequence_id, bool snap_selection, int request_result,
114 IClientAPI remote_client)
115 {
116 ParcelPropertiesPacket updatePacket = (ParcelPropertiesPacket) PacketPool.Instance.GetPacket(PacketType.ParcelProperties);
117 // TODO: don't create new blocks if recycling an old packet
118
119 updatePacket.ParcelData.AABBMax = landData.AABBMax;
120 updatePacket.ParcelData.AABBMin = landData.AABBMin;
121 updatePacket.ParcelData.Area = landData.area;
122 updatePacket.ParcelData.AuctionID = landData.auctionID;
123 updatePacket.ParcelData.AuthBuyerID = landData.authBuyerID; //unemplemented
124
125 updatePacket.ParcelData.Bitmap = landData.landBitmapByteArray;
126
127 updatePacket.ParcelData.Desc = Helpers.StringToField(landData.landDesc);
128 updatePacket.ParcelData.Category = (byte) landData.category;
129 updatePacket.ParcelData.ClaimDate = landData.claimDate;
130 updatePacket.ParcelData.ClaimPrice = landData.claimPrice;
131 updatePacket.ParcelData.GroupID = landData.groupID;
132 updatePacket.ParcelData.GroupPrims = landData.groupPrims;
133 updatePacket.ParcelData.IsGroupOwned = landData.isGroupOwned;
134 updatePacket.ParcelData.LandingType = (byte) landData.landingType;
135 updatePacket.ParcelData.LocalID = landData.localID;
136 if (landData.area > 0)
137 {
138 updatePacket.ParcelData.MaxPrims =
139 Convert.ToInt32(
140 Math.Round((Convert.ToDecimal(landData.area)/Convert.ToDecimal(65536))*15000*
141 Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor)));
142 }
143 else
144 {
145 updatePacket.ParcelData.MaxPrims = 0;
146 }
147 updatePacket.ParcelData.MediaAutoScale = landData.mediaAutoScale;
148 updatePacket.ParcelData.MediaID = landData.mediaID;
149 updatePacket.ParcelData.MediaURL = Helpers.StringToField(landData.mediaURL);
150 updatePacket.ParcelData.MusicURL = Helpers.StringToField(landData.musicURL);
151 updatePacket.ParcelData.Name = Helpers.StringToField(landData.landName);
152 updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented
153 updatePacket.ParcelData.OtherCount = 0; //unemplemented
154 updatePacket.ParcelData.OtherPrims = landData.otherPrims;
155 updatePacket.ParcelData.OwnerID = landData.ownerID;
156 updatePacket.ParcelData.OwnerPrims = landData.ownerPrims;
157 updatePacket.ParcelData.ParcelFlags = landData.landFlags;
158 updatePacket.ParcelData.ParcelPrimBonus = m_scene.RegionInfo.EstateSettings.objectBonusFactor;
159 updatePacket.ParcelData.PassHours = landData.passHours;
160 updatePacket.ParcelData.PassPrice = landData.passPrice;
161 updatePacket.ParcelData.PublicCount = 0; //unemplemented
162
163 uint regionFlags = (uint) m_scene.RegionInfo.EstateSettings.regionFlags;
164 updatePacket.ParcelData.RegionDenyAnonymous = ((regionFlags & (uint) Simulator.RegionFlags.DenyAnonymous) >
165 0);
166 updatePacket.ParcelData.RegionDenyIdentified = ((regionFlags & (uint) Simulator.RegionFlags.DenyIdentified) >
167 0);
168 updatePacket.ParcelData.RegionDenyTransacted = ((regionFlags & (uint) Simulator.RegionFlags.DenyTransacted) >
169 0);
170 updatePacket.ParcelData.RegionPushOverride = ((regionFlags & (uint) Simulator.RegionFlags.RestrictPushObject) >
171 0);
172
173 updatePacket.ParcelData.RentPrice = 0;
174 updatePacket.ParcelData.RequestResult = request_result;
175 updatePacket.ParcelData.SalePrice = landData.salePrice;
176 updatePacket.ParcelData.SelectedPrims = landData.selectedPrims;
177 updatePacket.ParcelData.SelfCount = 0; //unemplemented
178 updatePacket.ParcelData.SequenceID = sequence_id;
179 if (landData.simwideArea > 0)
180 {
181 updatePacket.ParcelData.SimWideMaxPrims =
182 Convert.ToInt32(
183 Math.Round((Convert.ToDecimal(landData.simwideArea)/Convert.ToDecimal(65536))*15000*
184 Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor)));
185 }
186 else
187 {
188 updatePacket.ParcelData.SimWideMaxPrims = 0;
189 }
190 updatePacket.ParcelData.SimWideTotalPrims = landData.simwidePrims;
191 updatePacket.ParcelData.SnapSelection = snap_selection;
192 updatePacket.ParcelData.SnapshotID = landData.snapshotID;
193 updatePacket.ParcelData.Status = (byte) landData.landStatus;
194 updatePacket.ParcelData.TotalPrims = landData.ownerPrims + landData.groupPrims + landData.otherPrims +
195 landData.selectedPrims;
196 updatePacket.ParcelData.UserLocation = landData.userLocation;
197 updatePacket.ParcelData.UserLookAt = landData.userLookAt;
198 remote_client.OutPacket((Packet) updatePacket, ThrottleOutPacketType.Task);
199 }
200
201 public void updateLandProperties(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
202 {
203 if (remote_client.AgentId == landData.ownerID)
204 {
205 //Needs later group support
206 LandData newData = landData.Copy();
207 newData.authBuyerID = packet.ParcelData.AuthBuyerID;
208 newData.category = (Parcel.ParcelCategory) packet.ParcelData.Category;
209 newData.landDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc);
210 newData.groupID = packet.ParcelData.GroupID;
211 newData.landingType = packet.ParcelData.LandingType;
212 newData.mediaAutoScale = packet.ParcelData.MediaAutoScale;
213 newData.mediaID = packet.ParcelData.MediaID;
214 newData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL);
215 newData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL);
216 newData.landName = Helpers.FieldToUTF8String(packet.ParcelData.Name);
217 newData.landFlags = packet.ParcelData.ParcelFlags;
218 newData.passHours = packet.ParcelData.PassHours;
219 newData.passPrice = packet.ParcelData.PassPrice;
220 newData.salePrice = packet.ParcelData.SalePrice;
221 newData.snapshotID = packet.ParcelData.SnapshotID;
222 newData.userLocation = packet.ParcelData.UserLocation;
223 newData.userLookAt = packet.ParcelData.UserLookAt;
224
225 m_scene.LandManager.updateLandObject(landData.localID, newData);
226
227 sendLandUpdateToAvatarsOverMe();
228 }
229 }
230
231 public bool isEitherBannedOrRestricted(LLUUID avatar)
232 {
233 if (isBannedFromLand(avatar))
234 {
235 return true;
236 }
237 else if (isRestrictedFromLand(avatar))
238 {
239 return true;
240 }
241 return false;
242 }
243
244 public bool isBannedFromLand(LLUUID avatar)
245 {
246 if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseBanList) > 0)
247 {
248 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
249 entry.AgentID = avatar;
250 entry.Flags = ParcelManager.AccessList.Ban;
251 entry.Time = new DateTime();
252 if (landData.parcelAccessList.Contains(entry))
253 {
254 //They are banned, so lets send them a notice about this parcel
255 return true;
256 }
257 }
258 return false;
259 }
260
261 public bool isRestrictedFromLand(LLUUID avatar)
262 {
263 if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseAccessList) > 0)
264 {
265 ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry();
266 entry.AgentID = avatar;
267 entry.Flags = ParcelManager.AccessList.Access;
268 entry.Time = new DateTime();
269 if (!landData.parcelAccessList.Contains(entry))
270 {
271 //They are not allowed in this parcel, but not banned, so lets send them a notice about this parcel
272 return true;
273 }
274 }
275 return false;
276 }
277
278 public void sendLandUpdateToClient(IClientAPI remote_client)
279 {
280 sendLandProperties(0, false, 0, remote_client);
281 }
282
283 public void sendLandUpdateToAvatarsOverMe()
284 {
285 List<ScenePresence> avatars = m_scene.GetAvatars();
286 Land over = null;
287 for (int i = 0; i < avatars.Count; i++)
288 {
289 try
290 {
291 over =
292 m_scene.LandManager.getLandObject((int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.X))),
293 (int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.Y))));
294 }
295 catch (Exception)
296 {
297 m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatars[i].AbsolutePosition.X) + " y: " + Math.Round(avatars[i].AbsolutePosition.Y));
298 }
299
300 if (over != null)
301 {
302 if (over.landData.localID == landData.localID)
303 {
304 sendLandUpdateToClient(avatars[i].ControllingClient);
305 }
306 }
307 }
308 }
309
310 #endregion
311
312 #region AccessList Functions
313
314 public ParcelAccessListReplyPacket.ListBlock[] createAccessListArrayByFlag(ParcelManager.AccessList flag)
315 {
316 List<ParcelAccessListReplyPacket.ListBlock> list = new List<ParcelAccessListReplyPacket.ListBlock>();
317 foreach (ParcelManager.ParcelAccessEntry entry in landData.parcelAccessList)
318 {
319 if (entry.Flags == flag)
320 {
321 ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock();
322
323 listBlock.Flags = (uint) 0;
324 listBlock.ID = entry.AgentID;
325 listBlock.Time = 0;
326
327 list.Add(listBlock);
328 }
329 }
330
331 if (list.Count == 0)
332 {
333 ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock();
334
335 listBlock.Flags = (uint) 0;
336 listBlock.ID = LLUUID.Zero;
337 listBlock.Time = 0;
338
339 list.Add(listBlock);
340 }
341 return list.ToArray();
342 }
343
344 public void sendAccessList(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID,
345 IClientAPI remote_client)
346 {
347 ParcelAccessListReplyPacket replyPacket;
348
349 if (flags == (uint) ParcelManager.AccessList.Access || flags == (uint) ParcelManager.AccessList.Both)
350 {
351 replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
352 replyPacket.Data.AgentID = agentID;
353 replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Access;
354 replyPacket.Data.LocalID = landData.localID;
355 replyPacket.Data.SequenceID = 0;
356
357 replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Access);
358 remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task);
359 }
360
361 if (flags == (uint) ParcelManager.AccessList.Ban || flags == (uint) ParcelManager.AccessList.Both)
362 {
363 replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply);
364 replyPacket.Data.AgentID = agentID;
365 replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Ban;
366 replyPacket.Data.LocalID = landData.localID;
367 replyPacket.Data.SequenceID = 0;
368
369 replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Ban);
370 remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task);
371 }
372 }
373
374 public void updateAccessList(uint flags, List<ParcelManager.ParcelAccessEntry> entries, IClientAPI remote_client)
375 {
376 LandData newData = landData.Copy();
377
378 if (entries.Count == 1 && entries[0].AgentID == LLUUID.Zero)
379 {
380 entries.Clear();
381 }
382
383 List<ParcelManager.ParcelAccessEntry> toRemove = new List<ParcelManager.ParcelAccessEntry>();
384 foreach (ParcelManager.ParcelAccessEntry entry in newData.parcelAccessList)
385 {
386 if (entry.Flags == (ParcelManager.AccessList) flags)
387 {
388 toRemove.Add(entry);
389 }
390 }
391
392 foreach (ParcelManager.ParcelAccessEntry entry in toRemove)
393 {
394 newData.parcelAccessList.Remove(entry);
395 }
396 foreach (ParcelManager.ParcelAccessEntry entry in entries)
397 {
398 ParcelManager.ParcelAccessEntry temp = new ParcelManager.ParcelAccessEntry();
399 temp.AgentID = entry.AgentID;
400 temp.Time = new DateTime(); //Pointless? Yes.
401 temp.Flags = (ParcelManager.AccessList) flags;
402
403 if (!newData.parcelAccessList.Contains(temp))
404 {
405 newData.parcelAccessList.Add(temp);
406 }
407 }
408
409 m_scene.LandManager.updateLandObject(landData.localID, newData);
410 }
411
412 #endregion
413
414 #region Update Functions
415
416 /// <summary>
417 /// Updates the AABBMin and AABBMax values after area/shape modification of the land object
418 /// </summary>
419 private void updateAABBAndAreaValues()
420 {
421 int min_x = 64;
422 int min_y = 64;
423 int max_x = 0;
424 int max_y = 0;
425 int tempArea = 0;
426 int x, y;
427 for (x = 0; x < 64; x++)
428 {
429 for (y = 0; y < 64; y++)
430 {
431 if (landBitmap[x, y] == true)
432 {
433 if (min_x > x) min_x = x;
434 if (min_y > y) min_y = y;
435 if (max_x < x) max_x = x;
436 if (max_y < y) max_y = y;
437 tempArea += 16; //16sqm peice of land
438 }
439 }
440 }
441 int tx = min_x * 4;
442 if (tx > 255)
443 tx = 255;
444 int ty = min_y * 4;
445 if (ty > 255)
446 ty = 255;
447 landData.AABBMin =
448 new LLVector3((float)(min_x * 4), (float)(min_y * 4),
449 (float)m_scene.Heightmap[tx, ty]);
450
451 tx = max_x * 4;
452 if (tx > 255)
453 tx = 255;
454 ty = max_y * 4;
455 if (ty > 255)
456 ty = 255;
457 landData.AABBMax =
458 new LLVector3((float)(max_x * 4), (float)(max_y * 4),
459 (float)m_scene.Heightmap[tx, ty]);
460 landData.area = tempArea;
461 }
462
463 public void updateLandBitmapByteArray()
464 {
465 landData.landBitmapByteArray = convertLandBitmapToBytes();
466 }
467
468 /// <summary>
469 /// Update all settings in land such as area, bitmap byte array, etc
470 /// </summary>
471 public void forceUpdateLandInfo()
472 {
473 updateAABBAndAreaValues();
474 updateLandBitmapByteArray();
475 }
476
477 public void setLandBitmapFromByteArray()
478 {
479 landBitmap = convertBytesToLandBitmap();
480 }
481
482 #endregion
483
484 #region Land Bitmap Functions
485
486 /// <summary>
487 /// Sets the land's bitmap manually
488 /// </summary>
489 /// <param name="bitmap">64x64 block representing where this land is on a map</param>
490 public void setLandBitmap(bool[,] bitmap)
491 {
492 if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2)
493 {
494 //Throw an exception - The bitmap is not 64x64
495 //throw new Exception("Error: Invalid Parcel Bitmap");
496 }
497 else
498 {
499 //Valid: Lets set it
500 landBitmap = bitmap;
501 forceUpdateLandInfo();
502 }
503 }
504
505 /// <summary>
506 /// Gets the land's bitmap manually
507 /// </summary>
508 /// <returns></returns>
509 public bool[,] getLandBitmap()
510 {
511 return landBitmap;
512 }
513
514 /// <summary>
515 /// Converts the land bitmap to a packet friendly byte array
516 /// </summary>
517 /// <returns></returns>
518 private byte[] convertLandBitmapToBytes()
519 {
520 byte[] tempConvertArr = new byte[512];
521 byte tempByte = 0;
522 int x, y, i, byteNum = 0;
523 i = 0;
524 for (y = 0; y < 64; y++)
525 {
526 for (x = 0; x < 64; x++)
527 {
528 tempByte = Convert.ToByte(tempByte | Convert.ToByte(landBitmap[x, y]) << (i++%8));
529 if (i%8 == 0)
530 {
531 tempConvertArr[byteNum] = tempByte;
532 tempByte = (byte) 0;
533 i = 0;
534 byteNum++;
535 }
536 }
537 }
538 return tempConvertArr;
539 }
540
541 private bool[,] convertBytesToLandBitmap()
542 {
543 bool[,] tempConvertMap = new bool[64,64];
544 tempConvertMap.Initialize();
545 byte tempByte = 0;
546 int x = 0, y = 0, i = 0, bitNum = 0;
547 for (i = 0; i < 512; i++)
548 {
549 tempByte = landData.landBitmapByteArray[i];
550 for (bitNum = 0; bitNum < 8; bitNum++)
551 {
552 bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1);
553 tempConvertMap[x, y] = bit;
554 x++;
555 if (x > 63)
556 {
557 x = 0;
558 y++;
559 }
560 }
561 }
562 return tempConvertMap;
563 }
564
565 /// <summary>
566 /// Full sim land object creation
567 /// </summary>
568 /// <returns></returns>
569 public static bool[,] basicFullRegionLandBitmap()
570 {
571 return getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize);
572 }
573
574 /// <summary>
575 /// Used to modify the bitmap between the x and y points. Points use 64 scale
576 /// </summary>
577 /// <param name="start_x"></param>
578 /// <param name="start_y"></param>
579 /// <param name="end_x"></param>
580 /// <param name="end_y"></param>
581 /// <returns></returns>
582 public static bool[,] getSquareLandBitmap(int start_x, int start_y, int end_x, int end_y)
583 {
584 bool[,] tempBitmap = new bool[64,64];
585 tempBitmap.Initialize();
586
587 tempBitmap = modifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true);
588 return tempBitmap;
589 }
590
591 /// <summary>
592 /// Change a land bitmap at within a square and set those points to a specific value
593 /// </summary>
594 /// <param name="land_bitmap"></param>
595 /// <param name="start_x"></param>
596 /// <param name="start_y"></param>
597 /// <param name="end_x"></param>
598 /// <param name="end_y"></param>
599 /// <param name="set_value"></param>
600 /// <returns></returns>
601 public static bool[,] modifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y,
602 bool set_value)
603 {
604 if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2)
605 {
606 //Throw an exception - The bitmap is not 64x64
607 //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()");
608 }
609
610 int x, y;
611 for (y = 0; y < 64; y++)
612 {
613 for (x = 0; x < 64; x++)
614 {
615 if (x >= start_x/4 && x < end_x/4
616 && y >= start_y/4 && y < end_y/4)
617 {
618 land_bitmap[x, y] = set_value;
619 }
620 }
621 }
622 return land_bitmap;
623 }
624
625 /// <summary>
626 /// Join the true values of 2 bitmaps together
627 /// </summary>
628 /// <param name="bitmap_base"></param>
629 /// <param name="bitmap_add"></param>
630 /// <returns></returns>
631 public static bool[,] mergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add)
632 {
633 if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2)
634 {
635 //Throw an exception - The bitmap is not 64x64
636 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps");
637 }
638 if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2)
639 {
640 //Throw an exception - The bitmap is not 64x64
641 throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps");
642 }
643
644 int x, y;
645 for (y = 0; y < 64; y++)
646 {
647 for (x = 0; x < 64; x++)
648 {
649 if (bitmap_add[x, y])
650 {
651 bitmap_base[x, y] = true;
652 }
653 }
654 }
655 return bitmap_base;
656 }
657
658 #endregion
659
660 #region Object Select and Object Owner Listing
661
662 public void sendForceObjectSelect(int local_id, int request_type, IClientAPI remote_client)
663 {
664 List<uint> resultLocalIDs = new List<uint>();
665 foreach (SceneObjectGroup obj in primsOverMe)
666 {
667 if (obj.LocalId > 0)
668 {
669 if (request_type == LandManager.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == landData.ownerID)
670 {
671 resultLocalIDs.Add(obj.LocalId);
672 }
673 // else if (request_type == LandManager.LAND_SELECT_OBJECTS_GROUP && ...) // TODO: group support
674 // {
675 // }
676 else if (request_type == LandManager.LAND_SELECT_OBJECTS_OTHER &&
677 obj.OwnerID != remote_client.AgentId)
678 {
679 resultLocalIDs.Add(obj.LocalId);
680 }
681 }
682 }
683
684
685 bool firstCall = true;
686 int MAX_OBJECTS_PER_PACKET = 251;
687 ForceObjectSelectPacket pack = (ForceObjectSelectPacket) PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect);
688 // TODO: don't create new blocks if recycling an old packet
689 ForceObjectSelectPacket.DataBlock[] data;
690 while (resultLocalIDs.Count > 0)
691 {
692 if (firstCall)
693 {
694 pack._Header.ResetList = true;
695 firstCall = false;
696 }
697 else
698 {
699 pack._Header.ResetList = false;
700 }
701
702 if (resultLocalIDs.Count > MAX_OBJECTS_PER_PACKET)
703 {
704 data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET];
705 }
706 else
707 {
708 data = new ForceObjectSelectPacket.DataBlock[resultLocalIDs.Count];
709 }
710
711 int i;
712 for (i = 0; i < MAX_OBJECTS_PER_PACKET && resultLocalIDs.Count > 0; i++)
713 {
714 data[i] = new ForceObjectSelectPacket.DataBlock();
715 data[i].LocalID = Convert.ToUInt32(resultLocalIDs[0]);
716 resultLocalIDs.RemoveAt(0);
717 }
718 pack.Data = data;
719 remote_client.OutPacket((Packet) pack, ThrottleOutPacketType.Task);
720 }
721 }
722
723 public void sendLandObjectOwners(IClientAPI remote_client)
724 {
725 Dictionary<LLUUID, int> ownersAndCount = new Dictionary<LLUUID, int>();
726 ParcelObjectOwnersReplyPacket pack = (ParcelObjectOwnersReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply);
727 // TODO: don't create new blocks if recycling an old packet
728
729 foreach (SceneObjectGroup obj in primsOverMe)
730 {
731 if (!ownersAndCount.ContainsKey(obj.OwnerID))
732 {
733 ownersAndCount.Add(obj.OwnerID, 0);
734 }
735 ownersAndCount[obj.OwnerID] += obj.PrimCount;
736 }
737 if (ownersAndCount.Count > 0)
738 {
739 ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[32];
740
741 if (ownersAndCount.Count < 32)
742 {
743 dataBlock = new ParcelObjectOwnersReplyPacket.DataBlock[ownersAndCount.Count];
744 }
745
746
747 int num = 0;
748 foreach (LLUUID owner in ownersAndCount.Keys)
749 {
750 dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock();
751 dataBlock[num].Count = ownersAndCount[owner];
752 dataBlock[num].IsGroupOwned = false; //TODO: fix me when group support is added
753 dataBlock[num].OnlineStatus = true; //TODO: fix me later
754 dataBlock[num].OwnerID = owner;
755
756 num++;
757 }
758 pack.Data = dataBlock;
759 }
760 remote_client.OutPacket(pack, ThrottleOutPacketType.Task);
761 }
762
763 #endregion
764
765 #region Object Returning
766
767 public void returnObject(SceneObjectGroup obj)
768 {
769 }
770
771 public void returnLandObjects(int type, LLUUID owner)
772 {
773 }
774
775 #endregion
776
777 #region Object Adding/Removing from Parcel
778
779 public void resetLandPrimCounts()
780 {
781 landData.groupPrims = 0;
782 landData.ownerPrims = 0;
783 landData.otherPrims = 0;
784 landData.selectedPrims = 0;
785 primsOverMe.Clear();
786 }
787
788 public void addPrimToCount(SceneObjectGroup obj)
789 {
790 LLUUID prim_owner = obj.OwnerID;
791 int prim_count = obj.PrimCount;
792
793 if (obj.IsSelected)
794 {
795 landData.selectedPrims += prim_count;
796 }
797 else
798 {
799 if (prim_owner == landData.ownerID)
800 {
801 landData.ownerPrims += prim_count;
802 }
803 else
804 {
805 landData.otherPrims += prim_count;
806 }
807 }
808
809 primsOverMe.Add(obj);
810 }
811
812 public void removePrimFromCount(SceneObjectGroup obj)
813 {
814 if (primsOverMe.Contains(obj))
815 {
816 LLUUID prim_owner = obj.OwnerID;
817 int prim_count = obj.PrimCount;
818
819 if (prim_owner == landData.ownerID)
820 {
821 landData.ownerPrims -= prim_count;
822 }
823 else if (prim_owner == landData.groupID)
824 {
825 landData.groupPrims -= prim_count;
826 }
827 else
828 {
829 landData.otherPrims -= prim_count;
830 }
831
832 primsOverMe.Remove(obj);
833 }
834 }
835
836 #endregion
837
838 #endregion
839 }
840
841 #endregion
842}
diff --git a/OpenSim/Region/Environment/LandManagement/LandManager.cs b/OpenSim/Region/Environment/LandManagement/LandManager.cs
deleted file mode 100644
index 0b3c5de..0000000
--- a/OpenSim/Region/Environment/LandManagement/LandManager.cs
+++ /dev/null
@@ -1,942 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.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 Axiom.Math;
31using libsecondlife;
32using libsecondlife.Packets;
33using OpenSim.Framework;
34using OpenSim.Framework.Console;
35using OpenSim.Region.Environment.Scenes;
36using OpenSim.Region.Environment.Interfaces;
37using OpenSim.Region.Physics.Manager;
38
39namespace OpenSim.Region.Environment.LandManagement
40{
41 #region LandManager Class
42
43 /// <summary>
44 /// Handles Land objects and operations requiring information from other Land objects (divide, join, etc)
45 /// </summary>
46 public class LandManager
47 {
48 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
49
50 #region Constants
51
52 //Land types set with flags in ParcelOverlay.
53 //Only one of these can be used.
54 public const byte LAND_TYPE_PUBLIC = (byte) 0; //Equals 00000000
55 public const byte LAND_TYPE_OWNED_BY_OTHER = (byte) 1; //Equals 00000001
56 public const byte LAND_TYPE_OWNED_BY_GROUP = (byte) 2; //Equals 00000010
57 public const byte LAND_TYPE_OWNED_BY_REQUESTER = (byte) 3; //Equals 00000011
58 public const byte LAND_TYPE_IS_FOR_SALE = (byte) 4; //Equals 00000100
59 public const byte LAND_TYPE_IS_BEING_AUCTIONED = (byte) 5; //Equals 00000101
60
61 //Flags that when set, a border on the given side will be placed
62 //NOTE: North and East is assumable by the west and south sides (if land to east has a west border, then I have an east border; etc)
63 //This took forever to figure out -- jeesh. /blame LL for even having to send these
64 public const byte LAND_FLAG_PROPERTY_BORDER_WEST = (byte) 64; //Equals 01000000
65 public const byte LAND_FLAG_PROPERTY_BORDER_SOUTH = (byte) 128; //Equals 10000000
66
67 //RequestResults (I think these are right, they seem to work):
68 public const int LAND_RESULT_SINGLE = 0; // The request they made contained only a single piece of land
69 public const int LAND_RESULT_MULTIPLE = 1; // The request they made contained more than a single peice of land
70
71 //ParcelSelectObjects
72 public const int LAND_SELECT_OBJECTS_OWNER = 2;
73 public const int LAND_SELECT_OBJECTS_GROUP = 4;
74 public const int LAND_SELECT_OBJECTS_OTHER = 8;
75
76 //These are other constants. Yay!
77 public const int START_LAND_LOCAL_ID = 1;
78
79 public const float BAN_LINE_SAFETY_HIEGHT = 100;
80
81 #endregion
82
83 #region Member Variables
84
85 public Dictionary<int, Land> landList = new Dictionary<int, Land>();
86 private int lastLandLocalID = START_LAND_LOCAL_ID - 1;
87 private int[,] landIDList = new int[64,64];
88
89 /// <summary>
90 /// Set to true when a prim is moved, created, added. Performs a prim count update
91 /// </summary>
92 public bool landPrimCountTainted = false;
93
94 private readonly Scene m_scene;
95 private readonly RegionInfo m_regInfo;
96
97 public bool allowedForcefulBans = true;
98
99 #endregion
100
101 #region Constructors
102
103 public LandManager(Scene scene, RegionInfo reginfo)
104 {
105 m_scene = scene;
106 m_regInfo = reginfo;
107 landIDList.Initialize();
108 scene.EventManager.OnAvatarEnteringNewParcel +=
109 new EventManager.AvatarEnteringNewParcel(handleAvatarChangingParcel);
110 scene.EventManager.OnClientMovement += new EventManager.ClientMovement(handleAnyClientMovement);
111 }
112
113 #endregion
114
115 #region Member Functions
116
117 #region Land Object From Storage Functions
118
119 public void IncomingLandObjectsFromStorage(List<LandData> data)
120 {
121 for (int i = 0; i < data.Count; i++)
122 {
123 //try
124 //{
125 IncomingLandObjectFromStorage(data[i]);
126 //}
127 //catch (Exception ex)
128 //{
129 //m_log.Error("[LandManager]: IncomingLandObjectsFromStorage: Exception: " + ex.ToString());
130 //throw ex;
131 //}
132 }
133 //foreach (LandData parcel in data)
134 //{
135 // IncomingLandObjectFromStorage(parcel);
136 //}
137 }
138
139 public void IncomingLandObjectFromStorage(LandData data)
140 {
141 Land new_land = new Land(data.ownerID, data.isGroupOwned, m_scene);
142 new_land.landData = data.Copy();
143 new_land.setLandBitmapFromByteArray();
144 addLandObject(new_land);
145 }
146
147 public void NoLandDataFromStorage()
148 {
149 Console.WriteLine("No LandData in storage! Loading a single, flat parcel instead");
150 resetSimLandObjects();
151 }
152
153 #endregion
154
155 #region Parcel Add/Remove/Get/Create
156
157 /// <summary>
158 /// Creates a basic Parcel object without an owner (a zeroed key)
159 /// </summary>
160 /// <returns></returns>
161 public Land createBaseLand()
162 {
163 return new Land(LLUUID.Zero, false, m_scene);
164 }
165
166 /// <summary>
167 /// Adds a land object to the stored list and adds them to the landIDList to what they own
168 /// </summary>
169 /// <param name="new_land">The land object being added</param>
170 public Land addLandObject(Land new_land)
171 {
172 lastLandLocalID++;
173 new_land.landData.localID = lastLandLocalID;
174 landList.Add(lastLandLocalID, new_land.Copy());
175
176
177 bool[,] landBitmap = new_land.getLandBitmap();
178 int x, y;
179 for (x = 0; x < 64; x++)
180 {
181 for (y = 0; y < 64; y++)
182 {
183 if (landBitmap[x, y])
184 {
185 landIDList[x, y] = lastLandLocalID;
186 }
187 }
188 }
189 landList[lastLandLocalID].forceUpdateLandInfo();
190 m_scene.EventManager.TriggerLandObjectAdded(new_land, m_scene.RegionInfo.RegionID);
191 return new_land;
192 }
193
194 /// <summary>
195 /// Removes a land object from the list. Will not remove if local_id is still owning an area in landIDList
196 /// </summary>
197 /// <param name="local_id">Land.localID of the peice of land to remove.</param>
198 public void removeLandObject(int local_id)
199 {
200 int x, y;
201 for (x = 0; x < 64; x++)
202 {
203 for (y = 0; y < 64; y++)
204 {
205 if (landIDList[x, y] == local_id)
206 {
207 return;
208 //throw new Exception("Could not remove land object. Still being used at " + x + ", " + y);
209 }
210 }
211 }
212
213 m_scene.EventManager.TriggerLandObjectRemoved(landList[local_id].landData.globalID);
214 landList.Remove(local_id);
215 }
216
217 public void updateLandObject(int local_id, LandData newData)
218 {
219 if (landList.ContainsKey(local_id))
220 {
221 landList[local_id].landData = newData.Copy();
222 m_scene.EventManager.TriggerLandObjectUpdated((uint) local_id, landList[local_id]);
223 }
224 else
225 {
226 //throw new Exception("Could not update land object. Local ID '" + local_id + "' does not exist");
227 }
228 }
229
230 private void performFinalLandJoin(Land master, Land slave)
231 {
232 int x, y;
233 bool[,] landBitmapSlave = slave.getLandBitmap();
234 for (x = 0; x < 64; x++)
235 {
236 for (y = 0; y < 64; y++)
237 {
238 if (landBitmapSlave[x, y])
239 {
240 landIDList[x, y] = master.landData.localID;
241 }
242 }
243 }
244
245 removeLandObject(slave.landData.localID);
246 updateLandObject(master.landData.localID, master.landData);
247 }
248
249 /// <summary>
250 /// Get the land object at the specified point
251 /// </summary>
252 /// <param name="x">Value between 0 - 256 on the x axis of the point</param>
253 /// <param name="y">Value between 0 - 256 on the y axis of the point</param>
254 /// <returns>Land object at the point supplied</returns>
255 public Land getLandObject(float x_float, float y_float)
256 {
257 int x;
258 int y;
259
260 try
261 {
262 x = Convert.ToInt32(Math.Floor(Convert.ToDouble(x_float) / Convert.ToDouble(4.0)));
263 y = Convert.ToInt32(Math.Floor(Convert.ToDouble(y_float) / Convert.ToDouble(4.0)));
264 }
265 catch (System.OverflowException)
266 {
267 return null;
268 }
269
270 if (x >= 64 || y >= 64 || x < 0 || y < 0)
271 {
272 return null;
273 }
274 else
275 {
276 // Console.WriteLine("Point (" + x + ", " + y + ") determined from point (" + x_float + ", " + y_float + ")");
277 return landList[landIDList[x, y]];
278 }
279 }
280
281 public Land getLandObject(int x, int y)
282 {
283 if (x >= Convert.ToInt32(Constants.RegionSize) || y >= Convert.ToInt32(Constants.RegionSize) || x < 0 || y < 0)
284 {
285 // These exceptions here will cause a lot of complaints from the users specifically because
286 // they happen every time at border crossings
287 throw new Exception("Error: Parcel not found at point " + x + ", " + y);
288 }
289 else
290 {
291 return landList[landIDList[x/4, y/4]];
292 }
293 }
294
295 #endregion
296
297 #region Parcel Modification
298
299 /// <summary>
300 /// Subdivides a piece of land
301 /// </summary>
302 /// <param name="start_x">West Point</param>
303 /// <param name="start_y">South Point</param>
304 /// <param name="end_x">East Point</param>
305 /// <param name="end_y">North Point</param>
306 /// <param name="attempting_user_id">LLUUID of user who is trying to subdivide</param>
307 /// <returns>Returns true if successful</returns>
308 private bool subdivide(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
309 {
310 //First, lets loop through the points and make sure they are all in the same peice of land
311 //Get the land object at start
312 Land startLandObject = null;
313 try
314 {
315 startLandObject = getLandObject(start_x, start_y);
316 }
317 catch (Exception)
318 {
319 m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + start_x + " y:" + start_y);
320 }
321 if (startLandObject == null) return false; //No such land object at the beginning
322
323 //Loop through the points
324 try
325 {
326 int totalX = end_x - start_x;
327 int totalY = end_y - start_y;
328 int x, y;
329 for (y = 0; y < totalY; y++)
330 {
331 for (x = 0; x < totalX; x++)
332 {
333 Land tempLandObject = getLandObject(start_x + x, start_y + y);
334 if (tempLandObject == null) return false; //No such land object at that point
335 if (tempLandObject != startLandObject) return false; //Subdividing over 2 land objects; no-no
336 }
337 }
338 }
339 catch (Exception)
340 {
341 return false; //Exception. For now, lets skip subdivision
342 }
343
344 //If we are still here, then they are subdividing within one piece of land
345 //Check owner
346 if (startLandObject.landData.ownerID != attempting_user_id)
347 {
348 return false; //They cant do this!
349 }
350
351 //Lets create a new land object with bitmap activated at that point (keeping the old land objects info)
352 Land newLand = startLandObject.Copy();
353 newLand.landData.landName = "Subdivision of " + newLand.landData.landName;
354 newLand.landData.globalID = LLUUID.Random();
355
356 newLand.setLandBitmap(Land.getSquareLandBitmap(start_x, start_y, end_x, end_y));
357
358 //Now, lets set the subdivision area of the original to false
359 int startLandObjectIndex = startLandObject.landData.localID;
360 landList[startLandObjectIndex].setLandBitmap(
361 Land.modifyLandBitmapSquare(startLandObject.getLandBitmap(), start_x, start_y, end_x, end_y, false));
362 landList[startLandObjectIndex].forceUpdateLandInfo();
363
364 setPrimsTainted();
365
366 //Now add the new land object
367 Land result = addLandObject(newLand);
368 updateLandObject(startLandObject.landData.localID, startLandObject.landData);
369 result.sendLandUpdateToAvatarsOverMe();
370
371
372 return true;
373 }
374
375 /// <summary>
376 /// Join 2 land objects together
377 /// </summary>
378 /// <param name="start_x">x value in first piece of land</param>
379 /// <param name="start_y">y value in first piece of land</param>
380 /// <param name="end_x">x value in second peice of land</param>
381 /// <param name="end_y">y value in second peice of land</param>
382 /// <param name="attempting_user_id">LLUUID of the avatar trying to join the land objects</param>
383 /// <returns>Returns true if successful</returns>
384 private bool join(int start_x, int start_y, int end_x, int end_y, LLUUID attempting_user_id)
385 {
386 end_x -= 4;
387 end_y -= 4;
388
389 List<Land> selectedLandObjects = new List<Land>();
390 int stepXSelected = 0;
391 int stepYSelected = 0;
392 for (stepYSelected = start_y; stepYSelected <= end_y; stepYSelected += 4)
393 {
394 for (stepXSelected = start_x; stepXSelected <= end_x; stepXSelected += 4)
395 {
396 Land p = null;
397 try
398 {
399 p = getLandObject(stepXSelected, stepYSelected);
400 }
401 catch (Exception)
402 {
403 m_log.Error("[LAND]: " + "Unable to get land object for subdivision at x: " + stepXSelected + " y:" + stepYSelected);
404 }
405 if (p != null)
406 {
407 if (!selectedLandObjects.Contains(p))
408 {
409 selectedLandObjects.Add(p);
410 }
411 }
412 }
413 }
414 Land masterLandObject = selectedLandObjects[0];
415 selectedLandObjects.RemoveAt(0);
416
417
418 if (selectedLandObjects.Count < 1)
419 {
420 return false; //Only one piece of land selected
421 }
422 if (masterLandObject.landData.ownerID != attempting_user_id)
423 {
424 return false; //Not the same owner
425 }
426 foreach (Land p in selectedLandObjects)
427 {
428 if (p.landData.ownerID != masterLandObject.landData.ownerID)
429 {
430 return false; //Over multiple users. TODO: make this just ignore this piece of land?
431 }
432 }
433 foreach (Land slaveLandObject in selectedLandObjects)
434 {
435 landList[masterLandObject.landData.localID].setLandBitmap(
436 Land.mergeLandBitmaps(masterLandObject.getLandBitmap(), slaveLandObject.getLandBitmap()));
437 performFinalLandJoin(masterLandObject, slaveLandObject);
438 }
439
440
441 setPrimsTainted();
442
443 masterLandObject.sendLandUpdateToAvatarsOverMe();
444
445 return true;
446 }
447
448 #endregion
449
450 #region Parcel Updating
451
452 /// <summary>
453 /// Where we send the ParcelOverlay packet to the client
454 /// </summary>
455 /// <param name="remote_client">The object representing the client</param>
456 public void sendParcelOverlay(IClientAPI remote_client)
457 {
458 const int LAND_BLOCKS_PER_PACKET = 1024;
459 int x, y = 0;
460 byte[] byteArray = new byte[LAND_BLOCKS_PER_PACKET];
461 int byteArrayCount = 0;
462 int sequenceID = 0;
463 ParcelOverlayPacket packet;
464
465 for (y = 0; y < 64; y++)
466 {
467 for (x = 0; x < 64; x++)
468 {
469 byte tempByte = (byte) 0; //This represents the byte for the current 4x4
470 Land currentParcelBlock = null;
471
472 try
473 {
474 currentParcelBlock = getLandObject(x * 4, y * 4);
475 }
476 catch (Exception)
477 {
478 m_log.Warn("[LAND]: " + "unable to get land at x: " + (x * 4) + " y: " + (y * 4));
479 }
480
481
482 if (currentParcelBlock != null)
483 {
484 if (currentParcelBlock.landData.ownerID == remote_client.AgentId)
485 {
486 //Owner Flag
487 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_REQUESTER);
488 }
489 else if (currentParcelBlock.landData.salePrice > 0 &&
490 (currentParcelBlock.landData.authBuyerID == LLUUID.Zero ||
491 currentParcelBlock.landData.authBuyerID == remote_client.AgentId))
492 {
493 //Sale Flag
494 tempByte = Convert.ToByte(tempByte | LAND_TYPE_IS_FOR_SALE);
495 }
496 else if (currentParcelBlock.landData.ownerID == LLUUID.Zero)
497 {
498 //Public Flag
499 tempByte = Convert.ToByte(tempByte | LAND_TYPE_PUBLIC);
500 }
501 else
502 {
503 //Other Flag
504 tempByte = Convert.ToByte(tempByte | LAND_TYPE_OWNED_BY_OTHER);
505 }
506
507
508 //Now for border control
509 try
510 {
511 Land westParcel = null;
512 Land southParcel = null;
513 if (x > 0)
514 {
515 westParcel = getLandObject((x - 1)*4, y*4);
516 }
517 if (y > 0)
518 {
519 southParcel = getLandObject(x*4, (y - 1)*4);
520 }
521
522 if (x == 0)
523 {
524 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
525 }
526 else if (westParcel != null && westParcel != currentParcelBlock)
527 {
528 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_WEST);
529 }
530
531 if (y == 0)
532 {
533 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
534 }
535 else if (southParcel != null && southParcel != currentParcelBlock)
536 {
537 tempByte = Convert.ToByte(tempByte | LAND_FLAG_PROPERTY_BORDER_SOUTH);
538 }
539
540 byteArray[byteArrayCount] = tempByte;
541 byteArrayCount++;
542 if (byteArrayCount >= LAND_BLOCKS_PER_PACKET)
543 {
544 byteArrayCount = 0;
545 packet = (ParcelOverlayPacket) PacketPool.Instance.GetPacket(PacketType.ParcelOverlay);
546 packet.ParcelData.Data = byteArray;
547 packet.ParcelData.SequenceID = sequenceID;
548 remote_client.OutPacket((Packet) packet, ThrottleOutPacketType.Task);
549 sequenceID++;
550 byteArray = new byte[LAND_BLOCKS_PER_PACKET];
551 }
552 }
553 catch (Exception e)
554 {
555 m_log.Debug("[LAND]: Skipped Land checks because avatar is out of bounds: " + e.Message);
556 }
557 }
558 }
559 }
560 }
561
562 public void handleParcelPropertiesRequest(int start_x, int start_y, int end_x, int end_y, int sequence_id,
563 bool snap_selection, IClientAPI remote_client)
564 {
565 //Get the land objects within the bounds
566 List<Land> temp = new List<Land>();
567 int x, y, i;
568 int inc_x = end_x - start_x;
569 int inc_y = end_y - start_y;
570 for (x = 0; x < inc_x; x++)
571 {
572 for (y = 0; y < inc_y; y++)
573 {
574
575 Land currentParcel = null;
576 try
577 {
578 currentParcel = getLandObject(start_x + x, start_y + y);
579 }
580 catch (Exception)
581 {
582 m_log.Warn("[LAND]: " + "unable to get land at x: " + (start_x + x) + " y: " + (start_y + y));
583 }
584 if (currentParcel != null)
585 {
586 if (!temp.Contains(currentParcel))
587 {
588 currentParcel.forceUpdateLandInfo();
589 temp.Add(currentParcel);
590 }
591 }
592 }
593 }
594
595 int requestResult = LAND_RESULT_SINGLE;
596 if (temp.Count > 1)
597 {
598 requestResult = LAND_RESULT_MULTIPLE;
599 }
600
601 for (i = 0; i < temp.Count; i++)
602 {
603 temp[i].sendLandProperties(sequence_id, snap_selection, requestResult, remote_client);
604 }
605
606
607 sendParcelOverlay(remote_client);
608 }
609
610 public void handleParcelPropertiesUpdateRequest(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client)
611 {
612 if (landList.ContainsKey(packet.ParcelData.LocalID))
613 {
614 landList[packet.ParcelData.LocalID].updateLandProperties(packet, remote_client);
615 }
616 }
617
618 public void handleParcelDivideRequest(int west, int south, int east, int north, IClientAPI remote_client)
619 {
620 subdivide(west, south, east, north, remote_client.AgentId);
621 }
622
623 public void handleParcelJoinRequest(int west, int south, int east, int north, IClientAPI remote_client)
624 {
625 join(west, south, east, north, remote_client.AgentId);
626 }
627
628 public void handleParcelSelectObjectsRequest(int local_id, int request_type, IClientAPI remote_client)
629 {
630 landList[local_id].sendForceObjectSelect(local_id, request_type, remote_client);
631 }
632
633 public void handleParcelObjectOwnersRequest(int local_id, IClientAPI remote_client)
634 {
635 landList[local_id].sendLandObjectOwners(remote_client);
636 }
637
638 #endregion
639
640 /// <summary>
641 /// Resets the sim to the default land object (full sim piece of land owned by the default user)
642 /// </summary>
643 public void resetSimLandObjects()
644 {
645 //Remove all the land objects in the sim and add a blank, full sim land object set to public
646 landList.Clear();
647 lastLandLocalID = START_LAND_LOCAL_ID - 1;
648 landIDList.Initialize();
649
650 Land fullSimParcel = new Land(LLUUID.Zero, false, m_scene);
651
652 fullSimParcel.setLandBitmap(Land.getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize));
653 fullSimParcel.landData.ownerID = m_regInfo.MasterAvatarAssignedUUID;
654
655 addLandObject(fullSimParcel);
656 }
657
658 public List<Land> parcelsNearPoint(LLVector3 position)
659 {
660 List<Land> parcelsNear = new List<Land>();
661 int x, y;
662 for (x = -4; x <= 4; x += 4)
663 {
664 for (y = -4; y <= 4; y += 4)
665 {
666 Land check = getLandObject(position.X + x, position.Y + y);
667 if (check != null)
668 {
669 if (!parcelsNear.Contains(check))
670 {
671 parcelsNear.Add(check);
672 }
673 }
674 }
675 }
676
677 return parcelsNear;
678 }
679
680 public void sendYouAreBannedNotice(ScenePresence avatar)
681 {
682 if (allowedForcefulBans)
683 {
684 avatar.ControllingClient.SendAlertMessage(
685 "You are not allowed on this parcel because you are banned. Please go away. <3 OpenSim Developers");
686
687 avatar.PhysicsActor.Position =
688 new PhysicsVector(avatar.lastKnownAllowedPosition.x, avatar.lastKnownAllowedPosition.y,
689 avatar.lastKnownAllowedPosition.z);
690 avatar.PhysicsActor.Velocity = new PhysicsVector(0, 0, 0);
691 }
692 else
693 {
694 avatar.ControllingClient.SendAlertMessage(
695 "You are not allowed on this parcel because you are banned; however, the grid administrator has disabled ban lines globally. Please obey the land owner's requests or you can be banned from the entire sim! <3 OpenSim Developers");
696 }
697 }
698
699 public void handleAvatarChangingParcel(ScenePresence avatar, int localLandID, LLUUID regionID)
700 {
701 if (m_scene.RegionInfo.RegionID == regionID)
702 {
703 if (landList[localLandID] != null)
704 {
705 Land parcelAvatarIsEntering = landList[localLandID];
706 if (avatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT)
707 {
708 if (parcelAvatarIsEntering.isBannedFromLand(avatar.UUID))
709 {
710 sendYouAreBannedNotice(avatar);
711 }
712 else if (parcelAvatarIsEntering.isRestrictedFromLand(avatar.UUID))
713 {
714 avatar.ControllingClient.SendAlertMessage(
715 "You are not allowed on this parcel because the land owner has restricted access. For now, you can enter, but please respect the land owner's decisions (or he can ban you!). <3 OpenSim Developers");
716 }
717 else
718 {
719 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
720 }
721 }
722 else
723 {
724 avatar.sentMessageAboutRestrictedParcelFlyingDown = true;
725 }
726 }
727 }
728 }
729
730 public void sendOutNearestBanLine(IClientAPI avatar)
731 {
732 List<ScenePresence> avatars = m_scene.GetAvatars();
733 foreach (ScenePresence presence in avatars)
734 {
735 if (presence.UUID == avatar.AgentId)
736 {
737
738 List<Land> checkLandParcels = parcelsNearPoint(presence.AbsolutePosition);
739 foreach (Land checkBan in checkLandParcels)
740 {
741 if (checkBan.isBannedFromLand(avatar.AgentId))
742 {
743 checkBan.sendLandProperties(-30000, false, (int) ParcelManager.ParcelResult.Single, avatar);
744 return; //Only send one
745 }
746 else if (checkBan.isRestrictedFromLand(avatar.AgentId))
747 {
748 checkBan.sendLandProperties(-40000, false, (int) ParcelManager.ParcelResult.Single, avatar);
749 return; //Only send one
750 }
751 }
752 return;
753 }
754 }
755 }
756
757 public void sendLandUpdate(ScenePresence avatar, bool force)
758 {
759 Land over = null;
760 try
761 {
762 over = getLandObject((int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.X))),
763 (int)Math.Min(255, Math.Max(0, Math.Round(avatar.AbsolutePosition.Y))));
764 }
765 catch (Exception)
766 {
767 m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatar.AbsolutePosition.X) + " y: " + Math.Round(avatar.AbsolutePosition.Y));
768 }
769
770 if (over != null)
771 {
772 if (force)
773 {
774 if (!avatar.IsChildAgent)
775 {
776 over.sendLandUpdateToClient(avatar.ControllingClient);
777 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
778 m_scene.RegionInfo.RegionID);
779 }
780 }
781
782 if (avatar.currentParcelUUID != over.landData.globalID)
783 {
784 if (!avatar.IsChildAgent)
785 {
786 over.sendLandUpdateToClient(avatar.ControllingClient);
787 avatar.currentParcelUUID = over.landData.globalID;
788 m_scene.EventManager.TriggerAvatarEnteringNewParcel(avatar, over.landData.localID,
789 m_scene.RegionInfo.RegionID);
790 }
791 }
792 }
793 }
794 public void sendLandUpdate(ScenePresence avatar)
795 {
796 sendLandUpdate(avatar, false);
797
798 }
799 public void handleSignificantClientMovement(IClientAPI remote_client)
800 {
801 ScenePresence clientAvatar = m_scene.GetScenePresence(remote_client.AgentId);
802
803 if (clientAvatar != null)
804 {
805 sendLandUpdate(clientAvatar);
806 sendOutNearestBanLine(remote_client);
807 Land parcel = getLandObject(clientAvatar.AbsolutePosition.X, clientAvatar.AbsolutePosition.Y);
808 if (parcel != null)
809 {
810 if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
811 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown)
812 {
813 handleAvatarChangingParcel(clientAvatar, parcel.landData.localID, m_scene.RegionInfo.RegionID);
814 //They are going below the safety line!
815 if (!parcel.isBannedFromLand(clientAvatar.UUID))
816 {
817 clientAvatar.sentMessageAboutRestrictedParcelFlyingDown = false;
818 }
819 }
820 else if (clientAvatar.AbsolutePosition.Z < BAN_LINE_SAFETY_HIEGHT &&
821 parcel.isBannedFromLand(clientAvatar.UUID))
822 {
823 sendYouAreBannedNotice(clientAvatar);
824 }
825 }
826 }
827 }
828
829 public void handleAnyClientMovement(ScenePresence avatar)
830 //Like handleSignificantClientMovement, but called with an AgentUpdate regardless of distance.
831 {
832 Land over = getLandObject(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y);
833 if (over != null)
834 {
835 if (!over.isBannedFromLand(avatar.UUID) || avatar.AbsolutePosition.Z >= BAN_LINE_SAFETY_HIEGHT)
836 {
837 avatar.lastKnownAllowedPosition =
838 new Vector3(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z);
839 }
840 }
841 }
842
843
844 public void handleParcelAccessRequest(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID,
845 int landLocalID, IClientAPI remote_client)
846 {
847 if (landList.ContainsKey(landLocalID))
848 {
849 landList[landLocalID].sendAccessList(agentID, sessionID, flags, sequenceID, remote_client);
850 }
851 }
852
853 public void handleParcelAccessUpdateRequest(LLUUID agentID, LLUUID sessionID, uint flags, int landLocalID,
854 List<ParcelManager.ParcelAccessEntry> entries,
855 IClientAPI remote_client)
856 {
857 if (landList.ContainsKey(landLocalID))
858 {
859 if (agentID == landList[landLocalID].landData.ownerID)
860 {
861 landList[landLocalID].updateAccessList(flags, entries, remote_client);
862 }
863 }
864 else
865 {
866 Console.WriteLine("INVALID LOCAL LAND ID");
867 }
868 }
869
870 public void resetAllLandPrimCounts()
871 {
872 foreach (Land p in landList.Values)
873 {
874 p.resetLandPrimCounts();
875 }
876 }
877
878 public void setPrimsTainted()
879 {
880 landPrimCountTainted = true;
881 }
882
883 public void addPrimToLandPrimCounts(SceneObjectGroup obj)
884 {
885 LLVector3 position = obj.AbsolutePosition;
886 Land landUnderPrim = getLandObject(position.X, position.Y);
887 if (landUnderPrim != null)
888 {
889 landUnderPrim.addPrimToCount(obj);
890 }
891 }
892
893 public void removePrimFromLandPrimCounts(SceneObjectGroup obj)
894 {
895 foreach (Land p in landList.Values)
896 {
897 p.removePrimFromCount(obj);
898 }
899 }
900
901 public void finalizeLandPrimCountUpdate()
902 {
903 //Get Simwide prim count for owner
904 Dictionary<LLUUID, List<Land>> landOwnersAndParcels = new Dictionary<LLUUID, List<Land>>();
905 foreach (Land p in landList.Values)
906 {
907 if (!landOwnersAndParcels.ContainsKey(p.landData.ownerID))
908 {
909 List<Land> tempList = new List<Land>();
910 tempList.Add(p);
911 landOwnersAndParcels.Add(p.landData.ownerID, tempList);
912 }
913 else
914 {
915 landOwnersAndParcels[p.landData.ownerID].Add(p);
916 }
917 }
918
919 foreach (LLUUID owner in landOwnersAndParcels.Keys)
920 {
921 int simArea = 0;
922 int simPrims = 0;
923 foreach (Land p in landOwnersAndParcels[owner])
924 {
925 simArea += p.landData.area;
926 simPrims += p.landData.ownerPrims + p.landData.otherPrims + p.landData.groupPrims +
927 p.landData.selectedPrims;
928 }
929
930 foreach (Land p in landOwnersAndParcels[owner])
931 {
932 p.landData.simwideArea = simArea;
933 p.landData.simwidePrims = simPrims;
934 }
935 }
936 }
937
938 #endregion
939 }
940
941 #endregion
942}