diff options
Diffstat (limited to 'OpenSim/Region/Environment/Modules/World/Land/LandObject.cs')
-rw-r--r-- | OpenSim/Region/Environment/Modules/World/Land/LandObject.cs | 943 |
1 files changed, 943 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs b/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs new file mode 100644 index 0000000..693c55d --- /dev/null +++ b/OpenSim/Region/Environment/Modules/World/Land/LandObject.cs | |||
@@ -0,0 +1,943 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using libsecondlife; | ||
32 | using libsecondlife.Packets; | ||
33 | using log4net; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Region.Environment.Interfaces; | ||
36 | using OpenSim.Region.Environment.Modules.World.Land; | ||
37 | using OpenSim.Region.Environment.Scenes; | ||
38 | |||
39 | namespace OpenSim.Region.Environment.Modules.World.Land | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// Keeps track of a specific piece of land's information | ||
43 | /// </summary> | ||
44 | public class LandObject : ILandObject | ||
45 | { | ||
46 | #region Member Variables | ||
47 | |||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | protected LandData m_landData = new LandData(); | ||
51 | protected List<SceneObjectGroup> primsOverMe = new List<SceneObjectGroup>(); | ||
52 | protected Scene m_scene; | ||
53 | |||
54 | private bool[,] m_landBitmap = new bool[64,64]; | ||
55 | |||
56 | public bool[,] landBitmap | ||
57 | { | ||
58 | get | ||
59 | { | ||
60 | return m_landBitmap; | ||
61 | } | ||
62 | set | ||
63 | { | ||
64 | m_landBitmap = value; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | #endregion | ||
69 | |||
70 | #region ILandObject Members | ||
71 | |||
72 | public LandData landData | ||
73 | { | ||
74 | get | ||
75 | { | ||
76 | return m_landData; | ||
77 | } | ||
78 | |||
79 | set | ||
80 | { | ||
81 | m_landData = value; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | public LLUUID regionUUID | ||
86 | { | ||
87 | get { return m_scene.RegionInfo.RegionID; } | ||
88 | } | ||
89 | |||
90 | #endregion | ||
91 | |||
92 | |||
93 | #region Constructors | ||
94 | |||
95 | public LandObject(LLUUID owner_id, bool is_group_owned, Scene scene) | ||
96 | { | ||
97 | m_scene = scene; | ||
98 | landData.ownerID = owner_id; | ||
99 | landData.isGroupOwned = is_group_owned; | ||
100 | } | ||
101 | |||
102 | #endregion | ||
103 | |||
104 | #region Member Functions | ||
105 | |||
106 | #region General Functions | ||
107 | |||
108 | /// <summary> | ||
109 | /// Checks to see if this land object contains a point | ||
110 | /// </summary> | ||
111 | /// <param name="x"></param> | ||
112 | /// <param name="y"></param> | ||
113 | /// <returns>Returns true if the piece of land contains the specified point</returns> | ||
114 | public bool containsPoint(int x, int y) | ||
115 | { | ||
116 | if (x >= 0 && y >= 0 && x <= Constants.RegionSize && x <= Constants.RegionSize) | ||
117 | { | ||
118 | return (landBitmap[x/4, y/4] == true); | ||
119 | } | ||
120 | else | ||
121 | { | ||
122 | return false; | ||
123 | } | ||
124 | } | ||
125 | |||
126 | public ILandObject Copy() | ||
127 | { | ||
128 | ILandObject newLand = new LandObject(landData.ownerID, landData.isGroupOwned, m_scene); | ||
129 | |||
130 | //Place all new variables here! | ||
131 | newLand.landBitmap = (bool[,]) (landBitmap.Clone()); | ||
132 | newLand.landData = landData.Copy(); | ||
133 | |||
134 | return newLand; | ||
135 | } | ||
136 | |||
137 | #endregion | ||
138 | |||
139 | #region Packet Request Handling | ||
140 | |||
141 | /// <summary> | ||
142 | /// Sends land properties as requested | ||
143 | /// </summary> | ||
144 | /// <param name="sequence_id">ID sent by client for them to keep track of</param> | ||
145 | /// <param name="snap_selection">Bool sent by client for them to use</param> | ||
146 | /// <param name="remote_client">Object representing the client</param> | ||
147 | public void sendLandProperties(int sequence_id, bool snap_selection, int request_result, | ||
148 | IClientAPI remote_client) | ||
149 | { | ||
150 | ParcelPropertiesPacket updatePacket = (ParcelPropertiesPacket) PacketPool.Instance.GetPacket(PacketType.ParcelProperties); | ||
151 | // TODO: don't create new blocks if recycling an old packet | ||
152 | |||
153 | updatePacket.ParcelData.AABBMax = landData.AABBMax; | ||
154 | updatePacket.ParcelData.AABBMin = landData.AABBMin; | ||
155 | updatePacket.ParcelData.Area = landData.area; | ||
156 | updatePacket.ParcelData.AuctionID = landData.auctionID; | ||
157 | updatePacket.ParcelData.AuthBuyerID = landData.authBuyerID; //unemplemented | ||
158 | |||
159 | updatePacket.ParcelData.Bitmap = landData.landBitmapByteArray; | ||
160 | |||
161 | updatePacket.ParcelData.Desc = Helpers.StringToField(landData.landDesc); | ||
162 | updatePacket.ParcelData.Category = (byte) landData.category; | ||
163 | updatePacket.ParcelData.ClaimDate = landData.claimDate; | ||
164 | updatePacket.ParcelData.ClaimPrice = landData.claimPrice; | ||
165 | updatePacket.ParcelData.GroupID = landData.groupID; | ||
166 | updatePacket.ParcelData.GroupPrims = landData.groupPrims; | ||
167 | updatePacket.ParcelData.IsGroupOwned = landData.isGroupOwned; | ||
168 | updatePacket.ParcelData.LandingType = (byte) landData.landingType; | ||
169 | updatePacket.ParcelData.LocalID = landData.localID; | ||
170 | if (landData.area > 0) | ||
171 | { | ||
172 | updatePacket.ParcelData.MaxPrims = | ||
173 | Convert.ToInt32( | ||
174 | Math.Round((Convert.ToDecimal(landData.area)/Convert.ToDecimal(65536))*m_scene.objectCapacity* | ||
175 | Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor))); | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | updatePacket.ParcelData.MaxPrims = 0; | ||
180 | } | ||
181 | updatePacket.ParcelData.MediaAutoScale = landData.mediaAutoScale; | ||
182 | updatePacket.ParcelData.MediaID = landData.mediaID; | ||
183 | updatePacket.ParcelData.MediaURL = Helpers.StringToField(landData.mediaURL); | ||
184 | updatePacket.ParcelData.MusicURL = Helpers.StringToField(landData.musicURL); | ||
185 | updatePacket.ParcelData.Name = Helpers.StringToField(landData.landName); | ||
186 | updatePacket.ParcelData.OtherCleanTime = 0; //unemplemented | ||
187 | updatePacket.ParcelData.OtherCount = 0; //unemplemented | ||
188 | updatePacket.ParcelData.OtherPrims = landData.otherPrims; | ||
189 | updatePacket.ParcelData.OwnerID = landData.ownerID; | ||
190 | updatePacket.ParcelData.OwnerPrims = landData.ownerPrims; | ||
191 | updatePacket.ParcelData.ParcelFlags = landData.landFlags; | ||
192 | updatePacket.ParcelData.ParcelPrimBonus = m_scene.RegionInfo.EstateSettings.objectBonusFactor; | ||
193 | updatePacket.ParcelData.PassHours = landData.passHours; | ||
194 | updatePacket.ParcelData.PassPrice = landData.passPrice; | ||
195 | updatePacket.ParcelData.PublicCount = 0; //unemplemented | ||
196 | |||
197 | uint regionFlags = (uint) m_scene.RegionInfo.EstateSettings.regionFlags; | ||
198 | updatePacket.ParcelData.RegionDenyAnonymous = ((regionFlags & (uint) Simulator.RegionFlags.DenyAnonymous) > | ||
199 | 0); | ||
200 | updatePacket.ParcelData.RegionDenyIdentified = ((regionFlags & (uint) Simulator.RegionFlags.DenyIdentified) > | ||
201 | 0); | ||
202 | updatePacket.ParcelData.RegionDenyTransacted = ((regionFlags & (uint) Simulator.RegionFlags.DenyTransacted) > | ||
203 | 0); | ||
204 | updatePacket.ParcelData.RegionPushOverride = ((regionFlags & (uint) Simulator.RegionFlags.RestrictPushObject) > | ||
205 | 0); | ||
206 | |||
207 | updatePacket.ParcelData.RentPrice = 0; | ||
208 | updatePacket.ParcelData.RequestResult = request_result; | ||
209 | updatePacket.ParcelData.SalePrice = landData.salePrice; | ||
210 | updatePacket.ParcelData.SelectedPrims = landData.selectedPrims; | ||
211 | updatePacket.ParcelData.SelfCount = 0; //unemplemented | ||
212 | updatePacket.ParcelData.SequenceID = sequence_id; | ||
213 | if (landData.simwideArea > 0) | ||
214 | { | ||
215 | updatePacket.ParcelData.SimWideMaxPrims = | ||
216 | Convert.ToInt32( | ||
217 | Math.Round((Convert.ToDecimal(landData.simwideArea) / Convert.ToDecimal(65536)) * m_scene.objectCapacity * | ||
218 | Convert.ToDecimal(m_scene.RegionInfo.EstateSettings.objectBonusFactor))); | ||
219 | } | ||
220 | else | ||
221 | { | ||
222 | updatePacket.ParcelData.SimWideMaxPrims = 0; | ||
223 | } | ||
224 | updatePacket.ParcelData.SimWideTotalPrims = landData.simwidePrims; | ||
225 | updatePacket.ParcelData.SnapSelection = snap_selection; | ||
226 | updatePacket.ParcelData.SnapshotID = landData.snapshotID; | ||
227 | updatePacket.ParcelData.Status = (byte) landData.landStatus; | ||
228 | updatePacket.ParcelData.TotalPrims = landData.ownerPrims + landData.groupPrims + landData.otherPrims + | ||
229 | landData.selectedPrims; | ||
230 | updatePacket.ParcelData.UserLocation = landData.userLocation; | ||
231 | updatePacket.ParcelData.UserLookAt = landData.userLookAt; | ||
232 | remote_client.OutPacket((Packet) updatePacket, ThrottleOutPacketType.Task); | ||
233 | } | ||
234 | |||
235 | public void updateLandProperties(ParcelPropertiesUpdatePacket packet, IClientAPI remote_client) | ||
236 | { | ||
237 | if (remote_client.AgentId == landData.ownerID) | ||
238 | { | ||
239 | //Needs later group support | ||
240 | LandData newData = landData.Copy(); | ||
241 | newData.authBuyerID = packet.ParcelData.AuthBuyerID; | ||
242 | newData.category = (Parcel.ParcelCategory) packet.ParcelData.Category; | ||
243 | newData.landDesc = Helpers.FieldToUTF8String(packet.ParcelData.Desc); | ||
244 | newData.groupID = packet.ParcelData.GroupID; | ||
245 | newData.landingType = packet.ParcelData.LandingType; | ||
246 | newData.mediaAutoScale = packet.ParcelData.MediaAutoScale; | ||
247 | newData.mediaID = packet.ParcelData.MediaID; | ||
248 | newData.mediaURL = Helpers.FieldToUTF8String(packet.ParcelData.MediaURL); | ||
249 | newData.musicURL = Helpers.FieldToUTF8String(packet.ParcelData.MusicURL); | ||
250 | newData.landName = Helpers.FieldToUTF8String(packet.ParcelData.Name); | ||
251 | newData.landFlags = packet.ParcelData.ParcelFlags; | ||
252 | newData.passHours = packet.ParcelData.PassHours; | ||
253 | newData.passPrice = packet.ParcelData.PassPrice; | ||
254 | newData.salePrice = packet.ParcelData.SalePrice; | ||
255 | newData.snapshotID = packet.ParcelData.SnapshotID; | ||
256 | newData.userLocation = packet.ParcelData.UserLocation; | ||
257 | newData.userLookAt = packet.ParcelData.UserLookAt; | ||
258 | |||
259 | m_scene.LandChannel.updateLandObject(landData.localID, newData); | ||
260 | |||
261 | sendLandUpdateToAvatarsOverMe(); | ||
262 | } | ||
263 | } | ||
264 | public void updateLandSold(LLUUID avatarID, LLUUID groupID, bool groupOwned, uint AuctionID, int claimprice, int area) | ||
265 | { | ||
266 | LandData newData = landData.Copy(); | ||
267 | newData.ownerID = avatarID; | ||
268 | newData.groupID = groupID; | ||
269 | newData.isGroupOwned = groupOwned; | ||
270 | //newData.auctionID = AuctionID; | ||
271 | newData.claimDate = Util.UnixTimeSinceEpoch(); | ||
272 | newData.claimPrice = claimprice; | ||
273 | newData.salePrice = 0; | ||
274 | newData.authBuyerID = LLUUID.Zero; | ||
275 | newData.landFlags &= ~(uint)(Parcel.ParcelFlags.ForSale | Parcel.ParcelFlags.ForSaleObjects | Parcel.ParcelFlags.SellParcelObjects); | ||
276 | m_scene.LandChannel.updateLandObject(landData.localID, newData); | ||
277 | |||
278 | sendLandUpdateToAvatarsOverMe(); | ||
279 | } | ||
280 | |||
281 | public bool isEitherBannedOrRestricted(LLUUID avatar) | ||
282 | { | ||
283 | if (isBannedFromLand(avatar)) | ||
284 | { | ||
285 | return true; | ||
286 | } | ||
287 | else if (isRestrictedFromLand(avatar)) | ||
288 | { | ||
289 | return true; | ||
290 | } | ||
291 | return false; | ||
292 | } | ||
293 | |||
294 | public bool isBannedFromLand(LLUUID avatar) | ||
295 | { | ||
296 | if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseBanList) > 0) | ||
297 | { | ||
298 | ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); | ||
299 | entry.AgentID = avatar; | ||
300 | entry.Flags = ParcelManager.AccessList.Ban; | ||
301 | entry.Time = new DateTime(); | ||
302 | if (landData.parcelAccessList.Contains(entry)) | ||
303 | { | ||
304 | //They are banned, so lets send them a notice about this parcel | ||
305 | return true; | ||
306 | } | ||
307 | } | ||
308 | return false; | ||
309 | } | ||
310 | |||
311 | public bool isRestrictedFromLand(LLUUID avatar) | ||
312 | { | ||
313 | if ((landData.landFlags & (uint) Parcel.ParcelFlags.UseAccessList) > 0) | ||
314 | { | ||
315 | ParcelManager.ParcelAccessEntry entry = new ParcelManager.ParcelAccessEntry(); | ||
316 | entry.AgentID = avatar; | ||
317 | entry.Flags = ParcelManager.AccessList.Access; | ||
318 | entry.Time = new DateTime(); | ||
319 | if (!landData.parcelAccessList.Contains(entry)) | ||
320 | { | ||
321 | //They are not allowed in this parcel, but not banned, so lets send them a notice about this parcel | ||
322 | return true; | ||
323 | } | ||
324 | } | ||
325 | return false; | ||
326 | } | ||
327 | |||
328 | public void sendLandUpdateToClient(IClientAPI remote_client) | ||
329 | { | ||
330 | sendLandProperties(0, false, 0, remote_client); | ||
331 | } | ||
332 | |||
333 | public void sendLandUpdateToAvatarsOverMe() | ||
334 | { | ||
335 | List<ScenePresence> avatars = m_scene.GetAvatars(); | ||
336 | ILandObject over = null; | ||
337 | for (int i = 0; i < avatars.Count; i++) | ||
338 | { | ||
339 | try | ||
340 | { | ||
341 | over = | ||
342 | m_scene.LandChannel.getLandObject((int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.X))), | ||
343 | (int)Math.Max(255,Math.Min(0,Math.Round(avatars[i].AbsolutePosition.Y)))); | ||
344 | } | ||
345 | catch (Exception) | ||
346 | { | ||
347 | m_log.Warn("[LAND]: " + "unable to get land at x: " + Math.Round(avatars[i].AbsolutePosition.X) + " y: " + Math.Round(avatars[i].AbsolutePosition.Y)); | ||
348 | } | ||
349 | |||
350 | if (over != null) | ||
351 | { | ||
352 | if (over.landData.localID == landData.localID) | ||
353 | { | ||
354 | sendLandUpdateToClient(avatars[i].ControllingClient); | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | |||
360 | #endregion | ||
361 | |||
362 | #region AccessList Functions | ||
363 | |||
364 | public ParcelAccessListReplyPacket.ListBlock[] createAccessListArrayByFlag(ParcelManager.AccessList flag) | ||
365 | { | ||
366 | List<ParcelAccessListReplyPacket.ListBlock> list = new List<ParcelAccessListReplyPacket.ListBlock>(); | ||
367 | foreach (ParcelManager.ParcelAccessEntry entry in landData.parcelAccessList) | ||
368 | { | ||
369 | if (entry.Flags == flag) | ||
370 | { | ||
371 | ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock(); | ||
372 | |||
373 | listBlock.Flags = (uint) 0; | ||
374 | listBlock.ID = entry.AgentID; | ||
375 | listBlock.Time = 0; | ||
376 | |||
377 | list.Add(listBlock); | ||
378 | } | ||
379 | } | ||
380 | |||
381 | if (list.Count == 0) | ||
382 | { | ||
383 | ParcelAccessListReplyPacket.ListBlock listBlock = new ParcelAccessListReplyPacket.ListBlock(); | ||
384 | |||
385 | listBlock.Flags = (uint) 0; | ||
386 | listBlock.ID = LLUUID.Zero; | ||
387 | listBlock.Time = 0; | ||
388 | |||
389 | list.Add(listBlock); | ||
390 | } | ||
391 | return list.ToArray(); | ||
392 | } | ||
393 | |||
394 | public void sendAccessList(LLUUID agentID, LLUUID sessionID, uint flags, int sequenceID, | ||
395 | IClientAPI remote_client) | ||
396 | { | ||
397 | ParcelAccessListReplyPacket replyPacket; | ||
398 | |||
399 | if (flags == (uint) ParcelManager.AccessList.Access || flags == (uint) ParcelManager.AccessList.Both) | ||
400 | { | ||
401 | replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply); | ||
402 | replyPacket.Data.AgentID = agentID; | ||
403 | replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Access; | ||
404 | replyPacket.Data.LocalID = landData.localID; | ||
405 | replyPacket.Data.SequenceID = 0; | ||
406 | |||
407 | replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Access); | ||
408 | remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task); | ||
409 | } | ||
410 | |||
411 | if (flags == (uint) ParcelManager.AccessList.Ban || flags == (uint) ParcelManager.AccessList.Both) | ||
412 | { | ||
413 | replyPacket = (ParcelAccessListReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelAccessListReply); | ||
414 | replyPacket.Data.AgentID = agentID; | ||
415 | replyPacket.Data.Flags = (uint) ParcelManager.AccessList.Ban; | ||
416 | replyPacket.Data.LocalID = landData.localID; | ||
417 | replyPacket.Data.SequenceID = 0; | ||
418 | |||
419 | replyPacket.List = createAccessListArrayByFlag(ParcelManager.AccessList.Ban); | ||
420 | remote_client.OutPacket((Packet) replyPacket, ThrottleOutPacketType.Task); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | public void updateAccessList(uint flags, List<ParcelManager.ParcelAccessEntry> entries, IClientAPI remote_client) | ||
425 | { | ||
426 | LandData newData = landData.Copy(); | ||
427 | |||
428 | if (entries.Count == 1 && entries[0].AgentID == LLUUID.Zero) | ||
429 | { | ||
430 | entries.Clear(); | ||
431 | } | ||
432 | |||
433 | List<ParcelManager.ParcelAccessEntry> toRemove = new List<ParcelManager.ParcelAccessEntry>(); | ||
434 | foreach (ParcelManager.ParcelAccessEntry entry in newData.parcelAccessList) | ||
435 | { | ||
436 | if (entry.Flags == (ParcelManager.AccessList) flags) | ||
437 | { | ||
438 | toRemove.Add(entry); | ||
439 | } | ||
440 | } | ||
441 | |||
442 | foreach (ParcelManager.ParcelAccessEntry entry in toRemove) | ||
443 | { | ||
444 | newData.parcelAccessList.Remove(entry); | ||
445 | } | ||
446 | foreach (ParcelManager.ParcelAccessEntry entry in entries) | ||
447 | { | ||
448 | ParcelManager.ParcelAccessEntry temp = new ParcelManager.ParcelAccessEntry(); | ||
449 | temp.AgentID = entry.AgentID; | ||
450 | temp.Time = new DateTime(); //Pointless? Yes. | ||
451 | temp.Flags = (ParcelManager.AccessList) flags; | ||
452 | |||
453 | if (!newData.parcelAccessList.Contains(temp)) | ||
454 | { | ||
455 | newData.parcelAccessList.Add(temp); | ||
456 | } | ||
457 | } | ||
458 | |||
459 | m_scene.LandChannel.updateLandObject(landData.localID, newData); | ||
460 | } | ||
461 | |||
462 | #endregion | ||
463 | |||
464 | #region Update Functions | ||
465 | |||
466 | /// <summary> | ||
467 | /// Updates the AABBMin and AABBMax values after area/shape modification of the land object | ||
468 | /// </summary> | ||
469 | private void updateAABBAndAreaValues() | ||
470 | { | ||
471 | int min_x = 64; | ||
472 | int min_y = 64; | ||
473 | int max_x = 0; | ||
474 | int max_y = 0; | ||
475 | int tempArea = 0; | ||
476 | int x, y; | ||
477 | for (x = 0; x < 64; x++) | ||
478 | { | ||
479 | for (y = 0; y < 64; y++) | ||
480 | { | ||
481 | if (landBitmap[x, y] == true) | ||
482 | { | ||
483 | if (min_x > x) min_x = x; | ||
484 | if (min_y > y) min_y = y; | ||
485 | if (max_x < x) max_x = x; | ||
486 | if (max_y < y) max_y = y; | ||
487 | tempArea += 16; //16sqm peice of land | ||
488 | } | ||
489 | } | ||
490 | } | ||
491 | int tx = min_x * 4; | ||
492 | if (tx > 255) | ||
493 | tx = 255; | ||
494 | int ty = min_y * 4; | ||
495 | if (ty > 255) | ||
496 | ty = 255; | ||
497 | landData.AABBMin = | ||
498 | new LLVector3((float)(min_x * 4), (float)(min_y * 4), | ||
499 | (float)m_scene.Heightmap[tx, ty]); | ||
500 | |||
501 | tx = max_x * 4; | ||
502 | if (tx > 255) | ||
503 | tx = 255; | ||
504 | ty = max_y * 4; | ||
505 | if (ty > 255) | ||
506 | ty = 255; | ||
507 | landData.AABBMax = | ||
508 | new LLVector3((float)(max_x * 4), (float)(max_y * 4), | ||
509 | (float)m_scene.Heightmap[tx, ty]); | ||
510 | landData.area = tempArea; | ||
511 | } | ||
512 | |||
513 | public void updateLandBitmapByteArray() | ||
514 | { | ||
515 | landData.landBitmapByteArray = convertLandBitmapToBytes(); | ||
516 | } | ||
517 | |||
518 | /// <summary> | ||
519 | /// Update all settings in land such as area, bitmap byte array, etc | ||
520 | /// </summary> | ||
521 | public void forceUpdateLandInfo() | ||
522 | { | ||
523 | updateAABBAndAreaValues(); | ||
524 | updateLandBitmapByteArray(); | ||
525 | } | ||
526 | |||
527 | public void setLandBitmapFromByteArray() | ||
528 | { | ||
529 | landBitmap = convertBytesToLandBitmap(); | ||
530 | } | ||
531 | |||
532 | #endregion | ||
533 | |||
534 | #region Land Bitmap Functions | ||
535 | |||
536 | /// <summary> | ||
537 | /// Sets the land's bitmap manually | ||
538 | /// </summary> | ||
539 | /// <param name="bitmap">64x64 block representing where this land is on a map</param> | ||
540 | public void setLandBitmap(bool[,] bitmap) | ||
541 | { | ||
542 | if (bitmap.GetLength(0) != 64 || bitmap.GetLength(1) != 64 || bitmap.Rank != 2) | ||
543 | { | ||
544 | //Throw an exception - The bitmap is not 64x64 | ||
545 | //throw new Exception("Error: Invalid Parcel Bitmap"); | ||
546 | } | ||
547 | else | ||
548 | { | ||
549 | //Valid: Lets set it | ||
550 | landBitmap = bitmap; | ||
551 | forceUpdateLandInfo(); | ||
552 | } | ||
553 | } | ||
554 | |||
555 | /// <summary> | ||
556 | /// Gets the land's bitmap manually | ||
557 | /// </summary> | ||
558 | /// <returns></returns> | ||
559 | public bool[,] getLandBitmap() | ||
560 | { | ||
561 | return landBitmap; | ||
562 | } | ||
563 | |||
564 | /// <summary> | ||
565 | /// Converts the land bitmap to a packet friendly byte array | ||
566 | /// </summary> | ||
567 | /// <returns></returns> | ||
568 | private byte[] convertLandBitmapToBytes() | ||
569 | { | ||
570 | byte[] tempConvertArr = new byte[512]; | ||
571 | byte tempByte = 0; | ||
572 | int x, y, i, byteNum = 0; | ||
573 | i = 0; | ||
574 | for (y = 0; y < 64; y++) | ||
575 | { | ||
576 | for (x = 0; x < 64; x++) | ||
577 | { | ||
578 | tempByte = Convert.ToByte(tempByte | Convert.ToByte(landBitmap[x, y]) << (i++%8)); | ||
579 | if (i%8 == 0) | ||
580 | { | ||
581 | tempConvertArr[byteNum] = tempByte; | ||
582 | tempByte = (byte) 0; | ||
583 | i = 0; | ||
584 | byteNum++; | ||
585 | } | ||
586 | } | ||
587 | } | ||
588 | return tempConvertArr; | ||
589 | } | ||
590 | |||
591 | private bool[,] convertBytesToLandBitmap() | ||
592 | { | ||
593 | bool[,] tempConvertMap = new bool[64,64]; | ||
594 | tempConvertMap.Initialize(); | ||
595 | byte tempByte = 0; | ||
596 | int x = 0, y = 0, i = 0, bitNum = 0; | ||
597 | for (i = 0; i < 512; i++) | ||
598 | { | ||
599 | tempByte = landData.landBitmapByteArray[i]; | ||
600 | for (bitNum = 0; bitNum < 8; bitNum++) | ||
601 | { | ||
602 | bool bit = Convert.ToBoolean(Convert.ToByte(tempByte >> bitNum) & (byte) 1); | ||
603 | tempConvertMap[x, y] = bit; | ||
604 | x++; | ||
605 | if (x > 63) | ||
606 | { | ||
607 | x = 0; | ||
608 | y++; | ||
609 | } | ||
610 | } | ||
611 | } | ||
612 | return tempConvertMap; | ||
613 | } | ||
614 | |||
615 | /// <summary> | ||
616 | /// Full sim land object creation | ||
617 | /// </summary> | ||
618 | /// <returns></returns> | ||
619 | public bool[,] basicFullRegionLandBitmap() | ||
620 | { | ||
621 | return getSquareLandBitmap(0, 0, (int)Constants.RegionSize, (int)Constants.RegionSize); | ||
622 | } | ||
623 | |||
624 | /// <summary> | ||
625 | /// Used to modify the bitmap between the x and y points. Points use 64 scale | ||
626 | /// </summary> | ||
627 | /// <param name="start_x"></param> | ||
628 | /// <param name="start_y"></param> | ||
629 | /// <param name="end_x"></param> | ||
630 | /// <param name="end_y"></param> | ||
631 | /// <returns></returns> | ||
632 | public bool[,] getSquareLandBitmap(int start_x, int start_y, int end_x, int end_y) | ||
633 | { | ||
634 | bool[,] tempBitmap = new bool[64,64]; | ||
635 | tempBitmap.Initialize(); | ||
636 | |||
637 | tempBitmap = modifyLandBitmapSquare(tempBitmap, start_x, start_y, end_x, end_y, true); | ||
638 | return tempBitmap; | ||
639 | } | ||
640 | |||
641 | /// <summary> | ||
642 | /// Change a land bitmap at within a square and set those points to a specific value | ||
643 | /// </summary> | ||
644 | /// <param name="land_bitmap"></param> | ||
645 | /// <param name="start_x"></param> | ||
646 | /// <param name="start_y"></param> | ||
647 | /// <param name="end_x"></param> | ||
648 | /// <param name="end_y"></param> | ||
649 | /// <param name="set_value"></param> | ||
650 | /// <returns></returns> | ||
651 | public bool[,] modifyLandBitmapSquare(bool[,] land_bitmap, int start_x, int start_y, int end_x, int end_y, | ||
652 | bool set_value) | ||
653 | { | ||
654 | if (land_bitmap.GetLength(0) != 64 || land_bitmap.GetLength(1) != 64 || land_bitmap.Rank != 2) | ||
655 | { | ||
656 | //Throw an exception - The bitmap is not 64x64 | ||
657 | //throw new Exception("Error: Invalid Parcel Bitmap in modifyLandBitmapSquare()"); | ||
658 | } | ||
659 | |||
660 | int x, y; | ||
661 | for (y = 0; y < 64; y++) | ||
662 | { | ||
663 | for (x = 0; x < 64; x++) | ||
664 | { | ||
665 | if (x >= start_x/4 && x < end_x/4 | ||
666 | && y >= start_y/4 && y < end_y/4) | ||
667 | { | ||
668 | land_bitmap[x, y] = set_value; | ||
669 | } | ||
670 | } | ||
671 | } | ||
672 | return land_bitmap; | ||
673 | } | ||
674 | |||
675 | /// <summary> | ||
676 | /// Join the true values of 2 bitmaps together | ||
677 | /// </summary> | ||
678 | /// <param name="bitmap_base"></param> | ||
679 | /// <param name="bitmap_add"></param> | ||
680 | /// <returns></returns> | ||
681 | public bool[,] mergeLandBitmaps(bool[,] bitmap_base, bool[,] bitmap_add) | ||
682 | { | ||
683 | if (bitmap_base.GetLength(0) != 64 || bitmap_base.GetLength(1) != 64 || bitmap_base.Rank != 2) | ||
684 | { | ||
685 | //Throw an exception - The bitmap is not 64x64 | ||
686 | throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_base in mergeLandBitmaps"); | ||
687 | } | ||
688 | if (bitmap_add.GetLength(0) != 64 || bitmap_add.GetLength(1) != 64 || bitmap_add.Rank != 2) | ||
689 | { | ||
690 | //Throw an exception - The bitmap is not 64x64 | ||
691 | throw new Exception("Error: Invalid Parcel Bitmap - Bitmap_add in mergeLandBitmaps"); | ||
692 | } | ||
693 | |||
694 | int x, y; | ||
695 | for (y = 0; y < 64; y++) | ||
696 | { | ||
697 | for (x = 0; x < 64; x++) | ||
698 | { | ||
699 | if (bitmap_add[x, y]) | ||
700 | { | ||
701 | bitmap_base[x, y] = true; | ||
702 | } | ||
703 | } | ||
704 | } | ||
705 | return bitmap_base; | ||
706 | } | ||
707 | |||
708 | #endregion | ||
709 | |||
710 | #region Object Select and Object Owner Listing | ||
711 | |||
712 | public void sendForceObjectSelect(int local_id, int request_type, IClientAPI remote_client) | ||
713 | { | ||
714 | List<uint> resultLocalIDs = new List<uint>(); | ||
715 | foreach (SceneObjectGroup obj in primsOverMe) | ||
716 | { | ||
717 | if (obj.LocalId > 0) | ||
718 | { | ||
719 | if (request_type == LandChannel.LAND_SELECT_OBJECTS_OWNER && obj.OwnerID == landData.ownerID) | ||
720 | { | ||
721 | resultLocalIDs.Add(obj.LocalId); | ||
722 | } | ||
723 | // else if (request_type == LandManager.LAND_SELECT_OBJECTS_GROUP && ...) // TODO: group support | ||
724 | // { | ||
725 | // } | ||
726 | else if (request_type == LandChannel.LAND_SELECT_OBJECTS_OTHER && | ||
727 | obj.OwnerID != remote_client.AgentId) | ||
728 | { | ||
729 | resultLocalIDs.Add(obj.LocalId); | ||
730 | } | ||
731 | } | ||
732 | } | ||
733 | |||
734 | |||
735 | bool firstCall = true; | ||
736 | int MAX_OBJECTS_PER_PACKET = 251; | ||
737 | ForceObjectSelectPacket pack = (ForceObjectSelectPacket) PacketPool.Instance.GetPacket(PacketType.ForceObjectSelect); | ||
738 | // TODO: don't create new blocks if recycling an old packet | ||
739 | ForceObjectSelectPacket.DataBlock[] data; | ||
740 | while (resultLocalIDs.Count > 0) | ||
741 | { | ||
742 | if (firstCall) | ||
743 | { | ||
744 | pack._Header.ResetList = true; | ||
745 | firstCall = false; | ||
746 | } | ||
747 | else | ||
748 | { | ||
749 | pack._Header.ResetList = false; | ||
750 | } | ||
751 | |||
752 | if (resultLocalIDs.Count > MAX_OBJECTS_PER_PACKET) | ||
753 | { | ||
754 | data = new ForceObjectSelectPacket.DataBlock[MAX_OBJECTS_PER_PACKET]; | ||
755 | } | ||
756 | else | ||
757 | { | ||
758 | data = new ForceObjectSelectPacket.DataBlock[resultLocalIDs.Count]; | ||
759 | } | ||
760 | |||
761 | int i; | ||
762 | for (i = 0; i < MAX_OBJECTS_PER_PACKET && resultLocalIDs.Count > 0; i++) | ||
763 | { | ||
764 | data[i] = new ForceObjectSelectPacket.DataBlock(); | ||
765 | data[i].LocalID = Convert.ToUInt32(resultLocalIDs[0]); | ||
766 | resultLocalIDs.RemoveAt(0); | ||
767 | } | ||
768 | pack.Data = data; | ||
769 | remote_client.OutPacket((Packet) pack, ThrottleOutPacketType.Task); | ||
770 | } | ||
771 | } | ||
772 | |||
773 | /// <summary> | ||
774 | /// Notify the parcel owner each avatar that owns prims situated on their land. This notification includes | ||
775 | /// aggreagete details such as the number of prims. | ||
776 | /// | ||
777 | /// </summary> | ||
778 | /// <param name="remote_client"> | ||
779 | /// A <see cref="IClientAPI"/> | ||
780 | /// </param> | ||
781 | public void sendLandObjectOwners(IClientAPI remote_client) | ||
782 | { | ||
783 | Dictionary<LLUUID, int> primCount = new Dictionary<LLUUID, int>(); | ||
784 | ParcelObjectOwnersReplyPacket pack | ||
785 | = (ParcelObjectOwnersReplyPacket) PacketPool.Instance.GetPacket(PacketType.ParcelObjectOwnersReply); | ||
786 | // TODO: don't create new blocks if recycling an old packet | ||
787 | |||
788 | foreach (SceneObjectGroup obj in primsOverMe) | ||
789 | { | ||
790 | try | ||
791 | { | ||
792 | if (!primCount.ContainsKey(obj.OwnerID)) | ||
793 | { | ||
794 | primCount.Add(obj.OwnerID, 0); | ||
795 | } | ||
796 | } | ||
797 | catch (NullReferenceException) | ||
798 | { | ||
799 | m_log.Info("[LAND]: " + "Got Null Reference when searching land owners from the parcel panel"); | ||
800 | } | ||
801 | try | ||
802 | { | ||
803 | primCount[obj.OwnerID] += obj.PrimCount; | ||
804 | } | ||
805 | catch (KeyNotFoundException) | ||
806 | { | ||
807 | m_log.Error("[LAND]: Unable to match a prim with it's owner."); | ||
808 | } | ||
809 | } | ||
810 | |||
811 | int notifyCount = primCount.Count; | ||
812 | |||
813 | if (notifyCount > 0) | ||
814 | { | ||
815 | if (notifyCount > 32) | ||
816 | { | ||
817 | m_log.InfoFormat( | ||
818 | "[LAND]: More than {0} avatars own prims on this parcel. Only sending back details of first {0}" | ||
819 | + " - a developer might want to investigate whether this is a hard limit", 32); | ||
820 | |||
821 | notifyCount = 32; | ||
822 | } | ||
823 | |||
824 | ParcelObjectOwnersReplyPacket.DataBlock[] dataBlock | ||
825 | = new ParcelObjectOwnersReplyPacket.DataBlock[notifyCount]; | ||
826 | |||
827 | int num = 0; | ||
828 | foreach (LLUUID owner in primCount.Keys) | ||
829 | { | ||
830 | dataBlock[num] = new ParcelObjectOwnersReplyPacket.DataBlock(); | ||
831 | dataBlock[num].Count = primCount[owner]; | ||
832 | dataBlock[num].IsGroupOwned = false; //TODO: fix me when group support is added | ||
833 | dataBlock[num].OnlineStatus = true; //TODO: fix me later | ||
834 | dataBlock[num].OwnerID = owner; | ||
835 | |||
836 | num++; | ||
837 | |||
838 | if (num >= notifyCount) | ||
839 | { | ||
840 | break; | ||
841 | } | ||
842 | } | ||
843 | |||
844 | pack.Data = dataBlock; | ||
845 | } | ||
846 | |||
847 | remote_client.OutPacket(pack, ThrottleOutPacketType.Task); | ||
848 | } | ||
849 | |||
850 | public Dictionary<LLUUID, int> getLandObjectOwners() | ||
851 | { | ||
852 | Dictionary<LLUUID, int> ownersAndCount = new Dictionary<LLUUID, int>(); | ||
853 | foreach (SceneObjectGroup obj in primsOverMe) | ||
854 | { | ||
855 | if (!ownersAndCount.ContainsKey(obj.OwnerID)) | ||
856 | { | ||
857 | ownersAndCount.Add(obj.OwnerID, 0); | ||
858 | } | ||
859 | ownersAndCount[obj.OwnerID] += obj.PrimCount; | ||
860 | } | ||
861 | return ownersAndCount; | ||
862 | } | ||
863 | |||
864 | #endregion | ||
865 | |||
866 | #region Object Returning | ||
867 | |||
868 | public void returnObject(SceneObjectGroup obj) | ||
869 | { | ||
870 | } | ||
871 | |||
872 | public void returnLandObjects(int type, LLUUID owner) | ||
873 | { | ||
874 | } | ||
875 | |||
876 | #endregion | ||
877 | |||
878 | #region Object Adding/Removing from Parcel | ||
879 | |||
880 | public void resetLandPrimCounts() | ||
881 | { | ||
882 | landData.groupPrims = 0; | ||
883 | landData.ownerPrims = 0; | ||
884 | landData.otherPrims = 0; | ||
885 | landData.selectedPrims = 0; | ||
886 | primsOverMe.Clear(); | ||
887 | } | ||
888 | |||
889 | public void addPrimToCount(SceneObjectGroup obj) | ||
890 | { | ||
891 | LLUUID prim_owner = obj.OwnerID; | ||
892 | int prim_count = obj.PrimCount; | ||
893 | |||
894 | if (obj.IsSelected) | ||
895 | { | ||
896 | landData.selectedPrims += prim_count; | ||
897 | } | ||
898 | else | ||
899 | { | ||
900 | if (prim_owner == landData.ownerID) | ||
901 | { | ||
902 | landData.ownerPrims += prim_count; | ||
903 | } | ||
904 | else | ||
905 | { | ||
906 | landData.otherPrims += prim_count; | ||
907 | } | ||
908 | } | ||
909 | |||
910 | primsOverMe.Add(obj); | ||
911 | } | ||
912 | |||
913 | public void removePrimFromCount(SceneObjectGroup obj) | ||
914 | { | ||
915 | if (primsOverMe.Contains(obj)) | ||
916 | { | ||
917 | LLUUID prim_owner = obj.OwnerID; | ||
918 | int prim_count = obj.PrimCount; | ||
919 | |||
920 | if (prim_owner == landData.ownerID) | ||
921 | { | ||
922 | landData.ownerPrims -= prim_count; | ||
923 | } | ||
924 | else if (prim_owner == landData.groupID) | ||
925 | { | ||
926 | landData.groupPrims -= prim_count; | ||
927 | } | ||
928 | else | ||
929 | { | ||
930 | landData.otherPrims -= prim_count; | ||
931 | } | ||
932 | |||
933 | primsOverMe.Remove(obj); | ||
934 | } | ||
935 | } | ||
936 | |||
937 | #endregion | ||
938 | |||
939 | #endregion | ||
940 | |||
941 | |||
942 | } | ||
943 | } \ No newline at end of file | ||