corrade-vassal – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 1 /*
2 * Copyright (c) 2006-2014, openmetaverse.org
3 * All rights reserved.
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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26  
27 using System;
28 using System.Collections.Generic;
29 using System.Threading;
30 using OpenMetaverse.Packets;
31 using OpenMetaverse.Http;
32 using OpenMetaverse.StructuredData;
33 using OpenMetaverse.Interfaces;
34 using OpenMetaverse.Messages.Linden;
35  
36 namespace OpenMetaverse
37 {
38 #region Enums
39  
40 /// <summary>
41 ///
42 /// </summary>
43 public enum ReportType : uint
44 {
45 /// <summary>No report</summary>
46 None = 0,
47 /// <summary>Unknown report type</summary>
48 Unknown = 1,
49 /// <summary>Bug report</summary>
50 Bug = 2,
51 /// <summary>Complaint report</summary>
52 Complaint = 3,
53 /// <summary>Customer service report</summary>
54 CustomerServiceRequest = 4
55 }
56  
57 /// <summary>
58 /// Bitflag field for ObjectUpdateCompressed data blocks, describing
59 /// which options are present for each object
60 /// </summary>
61 [Flags]
62 public enum CompressedFlags : uint
63 {
64 None = 0x00,
65 /// <summary>Unknown</summary>
66 ScratchPad = 0x01,
67 /// <summary>Whether the object has a TreeSpecies</summary>
68 Tree = 0x02,
69 /// <summary>Whether the object has floating text ala llSetText</summary>
70 HasText = 0x04,
71 /// <summary>Whether the object has an active particle system</summary>
72 HasParticles = 0x08,
73 /// <summary>Whether the object has sound attached to it</summary>
74 HasSound = 0x10,
75 /// <summary>Whether the object is attached to a root object or not</summary>
76 HasParent = 0x20,
77 /// <summary>Whether the object has texture animation settings</summary>
78 TextureAnimation = 0x40,
79 /// <summary>Whether the object has an angular velocity</summary>
80 HasAngularVelocity = 0x80,
81 /// <summary>Whether the object has a name value pairs string</summary>
82 HasNameValues = 0x100,
83 /// <summary>Whether the object has a Media URL set</summary>
84 MediaURL = 0x200
85 }
86  
87 /// <summary>
88 /// Specific Flags for MultipleObjectUpdate requests
89 /// </summary>
90 [Flags]
91 public enum UpdateType : uint
92 {
93 /// <summary>None</summary>
94 None = 0x00,
95 /// <summary>Change position of prims</summary>
96 Position = 0x01,
97 /// <summary>Change rotation of prims</summary>
98 Rotation = 0x02,
99 /// <summary>Change size of prims</summary>
100 Scale = 0x04,
101 /// <summary>Perform operation on link set</summary>
102 Linked = 0x08,
103 /// <summary>Scale prims uniformly, same as selecing ctrl+shift in the
104 /// viewer. Used in conjunction with Scale</summary>
105 Uniform = 0x10
106 }
107  
108 /// <summary>
109 /// Special values in PayPriceReply. If the price is not one of these
110 /// literal value of the price should be use
111 /// </summary>
112 public enum PayPriceType : int
113 {
114 /// <summary>
115 /// Indicates that this pay option should be hidden
116 /// </summary>
117 Hide = -1,
118  
119 /// <summary>
120 /// Indicates that this pay option should have the default value
121 /// </summary>
122 Default = -2
123 }
124  
125 #endregion Enums
126  
127 #region Structs
128  
129 /// <summary>
130 /// Contains the variables sent in an object update packet for objects.
131 /// Used to track position and movement of prims and avatars
132 /// </summary>
133 public struct ObjectMovementUpdate
134 {
135 /// <summary></summary>
136 public bool Avatar;
137 /// <summary></summary>
138 public Vector4 CollisionPlane;
139 /// <summary></summary>
140 public byte State;
141 /// <summary></summary>
142 public uint LocalID;
143 /// <summary></summary>
144 public Vector3 Position;
145 /// <summary></summary>
146 public Vector3 Velocity;
147 /// <summary></summary>
148 public Vector3 Acceleration;
149 /// <summary></summary>
150 public Quaternion Rotation;
151 /// <summary></summary>
152 public Vector3 AngularVelocity;
153 /// <summary></summary>
154 public Primitive.TextureEntry Textures;
155 }
156  
157 #endregion Structs
158  
159 /// <summary>
160 /// Handles all network traffic related to prims and avatar positions and
161 /// movement.
162 /// </summary>
163 public class ObjectManager
164 {
165 public const float HAVOK_TIMESTEP = 1.0f / 45.0f;
166  
167 #region Delegates
168  
169 #region ObjectUpdate event
170 /// <summary>The event subscribers, null of no subscribers</summary>
171 private EventHandler<PrimEventArgs> m_ObjectUpdate;
172  
173 /// <summary>Thread sync lock object</summary>
174 private readonly object m_ObjectUpdateLock = new object();
175  
176 /// <summary>Raised when the simulator sends us data containing
177 /// A <see cref="Primitive"/>, Foliage or Attachment</summary>
178 /// <seealso cref="RequestObject"/>
179 /// <seealso cref="RequestObjects"/>
180 public event EventHandler<PrimEventArgs> ObjectUpdate
181 {
182 add { lock (m_ObjectUpdateLock) { m_ObjectUpdate += value; } }
183 remove { lock (m_ObjectUpdateLock) { m_ObjectUpdate -= value; } }
184 }
185 #endregion ObjectUpdate event
186  
187 #region ObjectProperties event
188 /// <summary>The event subscribers, null of no subscribers</summary>
189 private EventHandler<ObjectPropertiesEventArgs> m_ObjectProperties;
190  
191 ///<summary>Raises the ObjectProperties Event</summary>
192 /// <param name="e">A ObjectPropertiesEventArgs object containing
193 /// the data sent from the simulator</param>
194 protected virtual void OnObjectProperties(ObjectPropertiesEventArgs e)
195 {
196 EventHandler<ObjectPropertiesEventArgs> handler = m_ObjectProperties;
197 if (handler != null)
198 handler(this, e);
199 }
200  
201 /// <summary>Thread sync lock object</summary>
202 private readonly object m_ObjectPropertiesLock = new object();
203  
204 /// <summary>Raised when the simulator sends us data containing
205 /// additional <seea cref="Primitive"/> information</summary>
206 /// <seealso cref="SelectObject"/>
207 /// <seealso cref="SelectObjects"/>
208 public event EventHandler<ObjectPropertiesEventArgs> ObjectProperties
209 {
210 add { lock (m_ObjectPropertiesLock) { m_ObjectProperties += value; } }
211 remove { lock (m_ObjectPropertiesLock) { m_ObjectProperties -= value; } }
212 }
213  
214 /// <summary>The event subscribers, null of no subscribers</summary>
215 private EventHandler<ObjectPropertiesUpdatedEventArgs> m_ObjectPropertiesUpdated;
216  
217 ///<summary>Raises the ObjectPropertiesUpdated Event</summary>
218 /// <param name="e">A ObjectPropertiesUpdatedEventArgs object containing
219 /// the data sent from the simulator</param>
220 protected virtual void OnObjectPropertiesUpdated(ObjectPropertiesUpdatedEventArgs e)
221 {
222 EventHandler<ObjectPropertiesUpdatedEventArgs> handler = m_ObjectPropertiesUpdated;
223 if (handler != null)
224 handler(this, e);
225 }
226  
227 /// <summary>Thread sync lock object</summary>
228 private readonly object m_ObjectPropertiesUpdatedLock = new object();
229  
230 /// <summary>Raised when the simulator sends us data containing
231 /// Primitive.ObjectProperties for an object we are currently tracking</summary>
232 public event EventHandler<ObjectPropertiesUpdatedEventArgs> ObjectPropertiesUpdated
233 {
234 add { lock (m_ObjectPropertiesUpdatedLock) { m_ObjectPropertiesUpdated += value; } }
235 remove { lock (m_ObjectPropertiesUpdatedLock) { m_ObjectPropertiesUpdated -= value; } }
236 }
237 #endregion ObjectProperties event
238  
239 #region ObjectPropertiesFamily event
240 /// <summary>The event subscribers, null of no subscribers</summary>
241 private EventHandler<ObjectPropertiesFamilyEventArgs> m_ObjectPropertiesFamily;
242  
243 ///<summary>Raises the ObjectPropertiesFamily Event</summary>
244 /// <param name="e">A ObjectPropertiesFamilyEventArgs object containing
245 /// the data sent from the simulator</param>
246 protected virtual void OnObjectPropertiesFamily(ObjectPropertiesFamilyEventArgs e)
247 {
248 EventHandler<ObjectPropertiesFamilyEventArgs> handler = m_ObjectPropertiesFamily;
249 if (handler != null)
250 handler(this, e);
251 }
252  
253 /// <summary>Thread sync lock object</summary>
254 private readonly object m_ObjectPropertiesFamilyLock = new object();
255  
256 /// <summary>Raised when the simulator sends us data containing
257 /// additional <seea cref="Primitive"/> and <see cref="Avatar"/> details</summary>
258 /// <seealso cref="RequestObjectPropertiesFamily"/>
259 public event EventHandler<ObjectPropertiesFamilyEventArgs> ObjectPropertiesFamily
260 {
261 add { lock (m_ObjectPropertiesFamilyLock) { m_ObjectPropertiesFamily += value; } }
262 remove { lock (m_ObjectPropertiesFamilyLock) { m_ObjectPropertiesFamily -= value; } }
263 }
264 #endregion ObjectPropertiesFamily
265  
266 #region AvatarUpdate event
267 /// <summary>The event subscribers, null of no subscribers</summary>
268 private EventHandler<AvatarUpdateEventArgs> m_AvatarUpdate;
269 private EventHandler<ParticleUpdateEventArgs> m_ParticleUpdate;
270  
271 ///<summary>Raises the AvatarUpdate Event</summary>
272 /// <param name="e">A AvatarUpdateEventArgs object containing
273 /// the data sent from the simulator</param>
274 protected virtual void OnAvatarUpdate(AvatarUpdateEventArgs e)
275 {
276 EventHandler<AvatarUpdateEventArgs> handler = m_AvatarUpdate;
277 if (handler != null)
278 handler(this, e);
279 }
280 /// <summary>
281 /// Raises the ParticleUpdate Event
282 /// </summary>
283 /// <param name="e">A ParticleUpdateEventArgs object containing
284 /// the data sent from the simulator</param>
285 protected virtual void OnParticleUpdate(ParticleUpdateEventArgs e) {
286 EventHandler<ParticleUpdateEventArgs> handler = m_ParticleUpdate;
287 if (handler != null)
288 handler(this, e);
289 }
290  
291 /// <summary>Thread sync lock object</summary>
292 private readonly object m_AvatarUpdateLock = new object();
293  
294 private readonly object m_ParticleUpdateLock = new object();
295  
296 /// <summary>Raised when the simulator sends us data containing
297 /// updated information for an <see cref="Avatar"/></summary>
298 public event EventHandler<AvatarUpdateEventArgs> AvatarUpdate
299 {
300 add { lock (m_AvatarUpdateLock) { m_AvatarUpdate += value; } }
301 remove { lock (m_AvatarUpdateLock) { m_AvatarUpdate -= value; } }
302 }
303 #endregion AvatarUpdate event
304  
305 #region TerseObjectUpdate event
306 public event EventHandler<ParticleUpdateEventArgs> ParticleUpdate {
307 add { lock (m_ParticleUpdateLock) { m_ParticleUpdate += value; } }
308 remove { lock (m_ParticleUpdateLock) { m_ParticleUpdate -= value; } }
309 }
310  
311 /// <summary>The event subscribers, null of no subscribers</summary>
312 private EventHandler<TerseObjectUpdateEventArgs> m_TerseObjectUpdate;
313  
314 /// <summary>Thread sync lock object</summary>
315 private readonly object m_TerseObjectUpdateLock = new object();
316  
317 /// <summary>Raised when the simulator sends us data containing
318 /// <see cref="Primitive"/> and <see cref="Avatar"/> movement changes</summary>
319 public event EventHandler<TerseObjectUpdateEventArgs> TerseObjectUpdate
320 {
321 add { lock (m_TerseObjectUpdateLock) { m_TerseObjectUpdate += value; } }
322 remove { lock (m_TerseObjectUpdateLock) { m_TerseObjectUpdate -= value; } }
323 }
324 #endregion TerseObjectUpdate event
325  
326 #region ObjectDataBlockUpdate event
327 /// <summary>The event subscribers, null of no subscribers</summary>
328 private EventHandler<ObjectDataBlockUpdateEventArgs> m_ObjectDataBlockUpdate;
329  
330 ///<summary>Raises the ObjectDataBlockUpdate Event</summary>
331 /// <param name="e">A ObjectDataBlockUpdateEventArgs object containing
332 /// the data sent from the simulator</param>
333 protected virtual void OnObjectDataBlockUpdate(ObjectDataBlockUpdateEventArgs e)
334 {
335 EventHandler<ObjectDataBlockUpdateEventArgs> handler = m_ObjectDataBlockUpdate;
336 if (handler != null)
337 handler(this, e);
338 }
339  
340 /// <summary>Thread sync lock object</summary>
341 private readonly object m_ObjectDataBlockUpdateLock = new object();
342  
343 /// <summary>Raised when the simulator sends us data containing
344 /// updates to an Objects DataBlock</summary>
345 public event EventHandler<ObjectDataBlockUpdateEventArgs> ObjectDataBlockUpdate
346 {
347 add { lock (m_ObjectDataBlockUpdateLock) { m_ObjectDataBlockUpdate += value; } }
348 remove { lock (m_ObjectDataBlockUpdateLock) { m_ObjectDataBlockUpdate -= value; } }
349 }
350 #endregion ObjectDataBlockUpdate event
351  
352 #region KillObject event
353 /// <summary>The event subscribers, null of no subscribers</summary>
354 private EventHandler<KillObjectEventArgs> m_KillObject;
355  
356 ///<summary>Raises the KillObject Event</summary>
357 /// <param name="e">A KillObjectEventArgs object containing
358 /// the data sent from the simulator</param>
359 protected virtual void OnKillObject(KillObjectEventArgs e)
360 {
361 EventHandler<KillObjectEventArgs> handler = m_KillObject;
362 if (handler != null)
363 handler(this, e);
364 }
365  
366 /// <summary>Thread sync lock object</summary>
367 private readonly object m_KillObjectLock = new object();
368  
369 /// <summary>Raised when the simulator informs us an <see cref="Primitive"/>
370 /// or <see cref="Avatar"/> is no longer within view</summary>
371 public event EventHandler<KillObjectEventArgs> KillObject
372 {
373 add { lock (m_KillObjectLock) { m_KillObject += value; } }
374 remove { lock (m_KillObjectLock) { m_KillObject -= value; } }
375 }
376 #endregion KillObject event
377  
378 #region KillObjects event
379 /// <summary>The event subscribers, null of no subscribers</summary>
380 private EventHandler<KillObjectsEventArgs> m_KillObjects;
381  
382 ///<summary>Raises the KillObjects Event</summary>
383 /// <param name="e">A KillObjectsEventArgs object containing
384 /// the data sent from the simulator</param>
385 protected virtual void OnKillObjects(KillObjectsEventArgs e)
386 {
387 EventHandler<KillObjectsEventArgs> handler = m_KillObjects;
388 if (handler != null)
389 handler(this, e);
390 }
391  
392 /// <summary>Thread sync lock object</summary>
393 private readonly object m_KillObjectsLock = new object();
394  
395 /// <summary>Raised when the simulator informs us when a group of <see cref="Primitive"/>
396 /// or <see cref="Avatar"/> is no longer within view</summary>
397 public event EventHandler<KillObjectsEventArgs> KillObjects
398 {
399 add { lock (m_KillObjectsLock) { m_KillObjects += value; } }
400 remove { lock (m_KillObjectsLock) { m_KillObjects -= value; } }
401 }
402 #endregion KillObjects event
403  
404 #region AvatarSitChanged event
405 /// <summary>The event subscribers, null of no subscribers</summary>
406 private EventHandler<AvatarSitChangedEventArgs> m_AvatarSitChanged;
407  
408 ///<summary>Raises the AvatarSitChanged Event</summary>
409 /// <param name="e">A AvatarSitChangedEventArgs object containing
410 /// the data sent from the simulator</param>
411 protected virtual void OnAvatarSitChanged(AvatarSitChangedEventArgs e)
412 {
413 EventHandler<AvatarSitChangedEventArgs> handler = m_AvatarSitChanged;
414 if (handler != null)
415 handler(this, e);
416 }
417  
418 /// <summary>Thread sync lock object</summary>
419 private readonly object m_AvatarSitChangedLock = new object();
420  
421 /// <summary>Raised when the simulator sends us data containing
422 /// updated sit information for our <see cref="Avatar"/></summary>
423 public event EventHandler<AvatarSitChangedEventArgs> AvatarSitChanged
424 {
425 add { lock (m_AvatarSitChangedLock) { m_AvatarSitChanged += value; } }
426 remove { lock (m_AvatarSitChangedLock) { m_AvatarSitChanged -= value; } }
427 }
428 #endregion AvatarSitChanged event
429  
430 #region PayPriceReply event
431 /// <summary>The event subscribers, null of no subscribers</summary>
432 private EventHandler<PayPriceReplyEventArgs> m_PayPriceReply;
433  
434 ///<summary>Raises the PayPriceReply Event</summary>
435 /// <param name="e">A PayPriceReplyEventArgs object containing
436 /// the data sent from the simulator</param>
437 protected virtual void OnPayPriceReply(PayPriceReplyEventArgs e)
438 {
439 EventHandler<PayPriceReplyEventArgs> handler = m_PayPriceReply;
440 if (handler != null)
441 handler(this, e);
442 }
443  
444 /// <summary>Thread sync lock object</summary>
445 private readonly object m_PayPriceReplyLock = new object();
446  
447 /// <summary>Raised when the simulator sends us data containing
448 /// purchase price information for a <see cref="Primitive"/></summary>
449 public event EventHandler<PayPriceReplyEventArgs> PayPriceReply
450 {
451 add { lock (m_PayPriceReplyLock) { m_PayPriceReply += value; } }
452 remove { lock (m_PayPriceReplyLock) { m_PayPriceReply -= value; } }
453 }
454 #endregion PayPriceReply
455  
456 #region PhysicsProperties event
457 /// <summary>
458 /// Callback for getting object media data via CAP
459 /// </summary>
460 /// <param name="success">Indicates if the operation was succesfull</param>
461 /// <param name="version">Object media version string</param>
462 /// <param name="faceMedia">Array indexed on prim face of media entry data</param>
463 public delegate void ObjectMediaCallback(bool success, string version, MediaEntry[] faceMedia);
464  
465 /// <summary>The event subscribers, null of no subscribers</summary>
466 private EventHandler<PhysicsPropertiesEventArgs> m_PhysicsProperties;
467  
468 ///<summary>Raises the PhysicsProperties Event</summary>
469 /// <param name="e">A PhysicsPropertiesEventArgs object containing
470 /// the data sent from the simulator</param>
471 protected virtual void OnPhysicsProperties(PhysicsPropertiesEventArgs e)
472 {
473 EventHandler<PhysicsPropertiesEventArgs> handler = m_PhysicsProperties;
474 if (handler != null)
475 handler(this, e);
476 }
477  
478 /// <summary>Thread sync lock object</summary>
479 private readonly object m_PhysicsPropertiesLock = new object();
480  
481 /// <summary>Raised when the simulator sends us data containing
482 /// additional <seea cref="Primitive"/> information</summary>
483 /// <seealso cref="SelectObject"/>
484 /// <seealso cref="SelectObjects"/>
485 public event EventHandler<PhysicsPropertiesEventArgs> PhysicsProperties
486 {
487 add { lock (m_PhysicsPropertiesLock) { m_PhysicsProperties += value; } }
488 remove { lock (m_PhysicsPropertiesLock) { m_PhysicsProperties -= value; } }
489 }
490 #endregion PhysicsProperties event
491  
492 #endregion Delegates
493  
494 /// <summary>Reference to the GridClient object</summary>
495 protected GridClient Client;
496 /// <summary>Does periodic dead reckoning calculation to convert
497 /// velocity and acceleration to new positions for objects</summary>
498 private Timer InterpolationTimer;
499  
500 /// <summary>
501 /// Construct a new instance of the ObjectManager class
502 /// </summary>
503 /// <param name="client">A reference to the <see cref="GridClient"/> instance</param>
504 public ObjectManager(GridClient client)
505 {
506 Client = client;
507  
508 Client.Network.RegisterCallback(PacketType.ObjectUpdate, ObjectUpdateHandler, false);
509 Client.Network.RegisterCallback(PacketType.ImprovedTerseObjectUpdate, ImprovedTerseObjectUpdateHandler, false);
510 Client.Network.RegisterCallback(PacketType.ObjectUpdateCompressed, ObjectUpdateCompressedHandler);
511 Client.Network.RegisterCallback(PacketType.ObjectUpdateCached, ObjectUpdateCachedHandler);
512 Client.Network.RegisterCallback(PacketType.KillObject, KillObjectHandler);
513 Client.Network.RegisterCallback(PacketType.ObjectPropertiesFamily, ObjectPropertiesFamilyHandler);
514 Client.Network.RegisterCallback(PacketType.ObjectProperties, ObjectPropertiesHandler);
515 Client.Network.RegisterCallback(PacketType.PayPriceReply, PayPriceReplyHandler);
516 Client.Network.RegisterEventCallback("ObjectPhysicsProperties", ObjectPhysicsPropertiesHandler);
517 }
518  
519 #region Internal event handlers
520  
521 private void Network_OnDisconnected(NetworkManager.DisconnectType reason, string message)
522 {
523 if (InterpolationTimer != null)
524 {
525 InterpolationTimer.Dispose();
526 InterpolationTimer = null;
527 }
528 }
529  
530 private void Network_OnConnected(object sender)
531 {
532 if (Client.Settings.USE_INTERPOLATION_TIMER)
533 {
534 InterpolationTimer = new Timer(InterpolationTimer_Elapsed, null, Settings.INTERPOLATION_INTERVAL, Timeout.Infinite);
535 }
536 }
537  
538 #endregion Internal event handlers
539  
540 #region Public Methods
541  
542 /// <summary>
543 /// Request information for a single object from a <see cref="Simulator"/>
544 /// you are currently connected to
545 /// </summary>
546 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
547 /// <param name="localID">The Local ID of the object</param>
548 public void RequestObject(Simulator simulator, uint localID)
549 {
550 RequestMultipleObjectsPacket request = new RequestMultipleObjectsPacket();
551 request.AgentData.AgentID = Client.Self.AgentID;
552 request.AgentData.SessionID = Client.Self.SessionID;
553 request.ObjectData = new RequestMultipleObjectsPacket.ObjectDataBlock[1];
554 request.ObjectData[0] = new RequestMultipleObjectsPacket.ObjectDataBlock();
555 request.ObjectData[0].ID = localID;
556 request.ObjectData[0].CacheMissType = 0;
557  
558 Client.Network.SendPacket(request, simulator);
559 }
560  
561 /// <summary>
562 /// Request information for multiple objects contained in
563 /// the same simulator
564 /// </summary>
565 /// <param name="simulator">The <see cref="Simulator"/> the objects are located</param>
566 /// <param name="localIDs">An array containing the Local IDs of the objects</param>
567 public void RequestObjects(Simulator simulator, List<uint> localIDs)
568 {
569 RequestMultipleObjectsPacket request = new RequestMultipleObjectsPacket();
570 request.AgentData.AgentID = Client.Self.AgentID;
571 request.AgentData.SessionID = Client.Self.SessionID;
572 request.ObjectData = new RequestMultipleObjectsPacket.ObjectDataBlock[localIDs.Count];
573  
574 for (int i = 0; i < localIDs.Count; i++)
575 {
576 request.ObjectData[i] = new RequestMultipleObjectsPacket.ObjectDataBlock();
577 request.ObjectData[i].ID = localIDs[i];
578 request.ObjectData[i].CacheMissType = 0;
579 }
580  
581 Client.Network.SendPacket(request, simulator);
582 }
583  
584 /// <summary>
585 /// Attempt to purchase an original object, a copy, or the contents of
586 /// an object
587 /// </summary>
588 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
589 /// <param name="localID">The Local ID of the object</param>
590 /// <param name="saleType">Whether the original, a copy, or the object
591 /// contents are on sale. This is used for verification, if the this
592 /// sale type is not valid for the object the purchase will fail</param>
593 /// <param name="price">Price of the object. This is used for
594 /// verification, if it does not match the actual price the purchase
595 /// will fail</param>
596 /// <param name="groupID">Group ID that will be associated with the new
597 /// purchase</param>
598 /// <param name="categoryID">Inventory folder UUID where the object or objects
599 /// purchased should be placed</param>
600 /// <example>
601 /// <code>
602 /// BuyObject(Client.Network.CurrentSim, 500, SaleType.Copy,
603 /// 100, UUID.Zero, Client.Self.InventoryRootFolderUUID);
604 /// </code>
605 ///</example>
606 public void BuyObject(Simulator simulator, uint localID, SaleType saleType, int price, UUID groupID,
607 UUID categoryID)
608 {
609 ObjectBuyPacket buy = new ObjectBuyPacket();
610  
611 buy.AgentData.AgentID = Client.Self.AgentID;
612 buy.AgentData.SessionID = Client.Self.SessionID;
613 buy.AgentData.GroupID = groupID;
614 buy.AgentData.CategoryID = categoryID;
615  
616 buy.ObjectData = new ObjectBuyPacket.ObjectDataBlock[1];
617 buy.ObjectData[0] = new ObjectBuyPacket.ObjectDataBlock();
618 buy.ObjectData[0].ObjectLocalID = localID;
619 buy.ObjectData[0].SaleType = (byte)saleType;
620 buy.ObjectData[0].SalePrice = price;
621  
622 Client.Network.SendPacket(buy, simulator);
623 }
624  
625 /// <summary>
626 /// Request prices that should be displayed in pay dialog. This will triggger the simulator
627 /// to send us back a PayPriceReply which can be handled by OnPayPriceReply event
628 /// </summary>
629 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
630 /// <param name="objectID">The ID of the object</param>
631 /// <remarks>The result is raised in the <see cref="PayPriceReply"/> event</remarks>
632 public void RequestPayPrice(Simulator simulator, UUID objectID)
633 {
634 RequestPayPricePacket payPriceRequest = new RequestPayPricePacket();
635  
636 payPriceRequest.ObjectData = new RequestPayPricePacket.ObjectDataBlock();
637 payPriceRequest.ObjectData.ObjectID = objectID;
638  
639 Client.Network.SendPacket(payPriceRequest, simulator);
640 }
641  
642 /// <summary>
643 /// Select a single object. This will cause the <see cref="Simulator"/> to send us
644 /// an <see cref="ObjectPropertiesPacket"/> which will raise the <see cref="ObjectProperties"/> event
645 /// </summary>
646 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
647 /// <param name="localID">The Local ID of the object</param>
648 /// <seealso cref="ObjectPropertiesFamilyEventArgs"/>
649 public void SelectObject(Simulator simulator, uint localID)
650 {
651 SelectObject(simulator, localID, true);
652 }
653  
654 /// <summary>
655 /// Select a single object. This will cause the <see cref="Simulator"/> to send us
656 /// an <see cref="ObjectPropertiesPacket"/> which will raise the <see cref="ObjectProperties"/> event
657 /// </summary>
658 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
659 /// <param name="localID">The Local ID of the object</param>
660 /// <param name="automaticDeselect">if true, a call to <see cref="DeselectObject"/> is
661 /// made immediately following the request</param>
662 /// <seealso cref="ObjectPropertiesFamilyEventArgs"/>
663 public void SelectObject(Simulator simulator, uint localID, bool automaticDeselect)
664 {
665 ObjectSelectPacket select = new ObjectSelectPacket();
666  
667 select.AgentData.AgentID = Client.Self.AgentID;
668 select.AgentData.SessionID = Client.Self.SessionID;
669  
670 select.ObjectData = new ObjectSelectPacket.ObjectDataBlock[1];
671 select.ObjectData[0] = new ObjectSelectPacket.ObjectDataBlock();
672 select.ObjectData[0].ObjectLocalID = localID;
673  
674 Client.Network.SendPacket(select, simulator);
675  
676 if (automaticDeselect)
677 {
678 DeselectObject(simulator, localID);
679 }
680 }
681  
682 /// <summary>
683 /// Select multiple objects. This will cause the <see cref="Simulator"/> to send us
684 /// an <see cref="ObjectPropertiesPacket"/> which will raise the <see cref="ObjectProperties"/> event
685 /// </summary>
686 /// <param name="simulator">The <see cref="Simulator"/> the objects are located</param>
687 /// <param name="localIDs">An array containing the Local IDs of the objects</param>
688 /// <param name="automaticDeselect">Should objects be deselected immediately after selection</param>
689 /// <seealso cref="ObjectPropertiesFamilyEventArgs"/>
690 public void SelectObjects(Simulator simulator, uint[] localIDs, bool automaticDeselect)
691 {
692 ObjectSelectPacket select = new ObjectSelectPacket();
693  
694 select.AgentData.AgentID = Client.Self.AgentID;
695 select.AgentData.SessionID = Client.Self.SessionID;
696  
697 select.ObjectData = new ObjectSelectPacket.ObjectDataBlock[localIDs.Length];
698  
699 for (int i = 0; i < localIDs.Length; i++)
700 {
701 select.ObjectData[i] = new ObjectSelectPacket.ObjectDataBlock();
702 select.ObjectData[i].ObjectLocalID = localIDs[i];
703 }
704  
705 Client.Network.SendPacket(select, simulator);
706  
707 if (automaticDeselect)
708 {
709 DeselectObjects(simulator, localIDs);
710 }
711 }
712  
713 /// <summary>
714 /// Select multiple objects. This will cause the <see cref="Simulator"/> to send us
715 /// an <see cref="ObjectPropertiesPacket"/> which will raise the <see cref="ObjectProperties"/> event
716 /// </summary>
717 /// <param name="simulator">The <see cref="Simulator"/> the objects are located</param>
718 /// <param name="localIDs">An array containing the Local IDs of the objects</param>
719 /// <seealso cref="ObjectPropertiesFamilyEventArgs"/>
720 public void SelectObjects(Simulator simulator, uint[] localIDs)
721 {
722 SelectObjects(simulator, localIDs, true);
723 }
724  
725 /// <summary>
726 /// Update the properties of an object
727 /// </summary>
728 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
729 /// <param name="localID">The Local ID of the object</param>
730 /// <param name="physical">true to turn the objects physical property on</param>
731 /// <param name="temporary">true to turn the objects temporary property on</param>
732 /// <param name="phantom">true to turn the objects phantom property on</param>
733 /// <param name="castsShadow">true to turn the objects cast shadows property on</param>
734 public void SetFlags(Simulator simulator, uint localID, bool physical, bool temporary, bool phantom, bool castsShadow)
735 {
736 SetFlags(simulator, localID, physical, temporary, phantom, castsShadow, PhysicsShapeType.Prim, 1000f, 0.6f, 0.5f, 1f);
737 }
738  
739 /// <summary>
740 /// Update the properties of an object
741 /// </summary>
742 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
743 /// <param name="localID">The Local ID of the object</param>
744 /// <param name="physical">true to turn the objects physical property on</param>
745 /// <param name="temporary">true to turn the objects temporary property on</param>
746 /// <param name="phantom">true to turn the objects phantom property on</param>
747 /// <param name="castsShadow">true to turn the objects cast shadows property on</param>
748 /// <param name="physicsType">Type of the represetnation prim will have in the physics engine</param>
749 /// <param name="density">Density - normal value 1000</param>
750 /// <param name="friction">Friction - normal value 0.6</param>
751 /// <param name="restitution">Restitution - standard value 0.5</param>
752 /// <param name="gravityMultiplier">Gravity multiplier - standar value 1.0</param>
753 public void SetFlags(Simulator simulator, uint localID, bool physical, bool temporary, bool phantom, bool castsShadow,
754 PhysicsShapeType physicsType, float density, float friction, float restitution, float gravityMultiplier)
755 {
756 ObjectFlagUpdatePacket flags = new ObjectFlagUpdatePacket();
757 flags.AgentData.AgentID = Client.Self.AgentID;
758 flags.AgentData.SessionID = Client.Self.SessionID;
759 flags.AgentData.ObjectLocalID = localID;
760 flags.AgentData.UsePhysics = physical;
761 flags.AgentData.IsTemporary = temporary;
762 flags.AgentData.IsPhantom = phantom;
763 flags.AgentData.CastsShadows = castsShadow;
764  
765 flags.ExtraPhysics = new ObjectFlagUpdatePacket.ExtraPhysicsBlock[1];
766 flags.ExtraPhysics[0] = new ObjectFlagUpdatePacket.ExtraPhysicsBlock();
767 flags.ExtraPhysics[0].PhysicsShapeType = (byte)physicsType;
768 flags.ExtraPhysics[0].Density = density;
769 flags.ExtraPhysics[0].Friction = friction;
770 flags.ExtraPhysics[0].Restitution = restitution;
771 flags.ExtraPhysics[0].GravityMultiplier = gravityMultiplier;
772  
773 Client.Network.SendPacket(flags, simulator);
774 }
775  
776 /// <summary>
777 /// Sets the sale properties of a single object
778 /// </summary>
779 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
780 /// <param name="localID">The Local ID of the object</param>
781 /// <param name="saleType">One of the options from the <see cref="SaleType"/> enum</param>
782 /// <param name="price">The price of the object</param>
783 public void SetSaleInfo(Simulator simulator, uint localID, SaleType saleType, int price)
784 {
785 ObjectSaleInfoPacket sale = new ObjectSaleInfoPacket();
786 sale.AgentData.AgentID = Client.Self.AgentID;
787 sale.AgentData.SessionID = Client.Self.SessionID;
788 sale.ObjectData = new ObjectSaleInfoPacket.ObjectDataBlock[1];
789 sale.ObjectData[0] = new ObjectSaleInfoPacket.ObjectDataBlock();
790 sale.ObjectData[0].LocalID = localID;
791 sale.ObjectData[0].SalePrice = price;
792 sale.ObjectData[0].SaleType = (byte)saleType;
793  
794 Client.Network.SendPacket(sale, simulator);
795 }
796  
797 /// <summary>
798 /// Sets the sale properties of multiple objects
799 /// </summary>
800 /// <param name="simulator">The <see cref="Simulator"/> the objects are located</param>
801 /// <param name="localIDs">An array containing the Local IDs of the objects</param>
802 /// <param name="saleType">One of the options from the <see cref="SaleType"/> enum</param>
803 /// <param name="price">The price of the object</param>
804 public void SetSaleInfo(Simulator simulator, List<uint> localIDs, SaleType saleType, int price)
805 {
806 ObjectSaleInfoPacket sale = new ObjectSaleInfoPacket();
807 sale.AgentData.AgentID = Client.Self.AgentID;
808 sale.AgentData.SessionID = Client.Self.SessionID;
809 sale.ObjectData = new ObjectSaleInfoPacket.ObjectDataBlock[localIDs.Count];
810  
811 for (int i = 0; i < localIDs.Count; i++)
812 {
813 sale.ObjectData[i] = new ObjectSaleInfoPacket.ObjectDataBlock();
814 sale.ObjectData[i].LocalID = localIDs[i];
815 sale.ObjectData[i].SalePrice = price;
816 sale.ObjectData[i].SaleType = (byte)saleType;
817 }
818  
819 Client.Network.SendPacket(sale, simulator);
820 }
821  
822 /// <summary>
823 /// Deselect a single object
824 /// </summary>
825 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
826 /// <param name="localID">The Local ID of the object</param>
827 public void DeselectObject(Simulator simulator, uint localID)
828 {
829 ObjectDeselectPacket deselect = new ObjectDeselectPacket();
830  
831 deselect.AgentData.AgentID = Client.Self.AgentID;
832 deselect.AgentData.SessionID = Client.Self.SessionID;
833  
834 deselect.ObjectData = new ObjectDeselectPacket.ObjectDataBlock[1];
835 deselect.ObjectData[0] = new ObjectDeselectPacket.ObjectDataBlock();
836 deselect.ObjectData[0].ObjectLocalID = localID;
837  
838 Client.Network.SendPacket(deselect, simulator);
839 }
840  
841 /// <summary>
842 /// Deselect multiple objects.
843 /// </summary>
844 /// <param name="simulator">The <see cref="Simulator"/> the objects are located</param>
845 /// <param name="localIDs">An array containing the Local IDs of the objects</param>
846 public void DeselectObjects(Simulator simulator, uint[] localIDs)
847 {
848 ObjectDeselectPacket deselect = new ObjectDeselectPacket();
849  
850 deselect.AgentData.AgentID = Client.Self.AgentID;
851 deselect.AgentData.SessionID = Client.Self.SessionID;
852  
853 deselect.ObjectData = new ObjectDeselectPacket.ObjectDataBlock[localIDs.Length];
854  
855 for (int i = 0; i < localIDs.Length; i++)
856 {
857 deselect.ObjectData[i] = new ObjectDeselectPacket.ObjectDataBlock();
858 deselect.ObjectData[i].ObjectLocalID = localIDs[i];
859 }
860  
861 Client.Network.SendPacket(deselect, simulator);
862 }
863  
864 /// <summary>
865 /// Perform a click action on an object
866 /// </summary>
867 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
868 /// <param name="localID">The Local ID of the object</param>
869 public void ClickObject(Simulator simulator, uint localID)
870 {
871 ClickObject(simulator, localID, Vector3.Zero, Vector3.Zero, 0, Vector3.Zero, Vector3.Zero, Vector3.Zero);
872 }
873  
874 /// <summary>
875 /// Perform a click action (Grab) on a single object
876 /// </summary>
877 /// <param name="simulator">The <see cref="Simulator"/> the object is located</param>
878 /// <param name="localID">The Local ID of the object</param>
879 /// <param name="uvCoord">The texture coordinates to touch</param>
880 /// <param name="stCoord">The surface coordinates to touch</param>
881 /// <param name="faceIndex">The face of the position to touch</param>
882 /// <param name="position">The region coordinates of the position to touch</param>
883 /// <param name="normal">The surface normal of the position to touch (A normal is a vector perpindicular to the surface)</param>
884 /// <param name="binormal">The surface binormal of the position to touch (A binormal is a vector tangen to the surface
885 /// pointing along the U direction of the tangent space</param>
886 public void ClickObject(Simulator simulator, uint localID, Vector3 uvCoord, Vector3 stCoord, int faceIndex, Vector3 position,
887 Vector3 normal, Vector3 binormal)
888 {
889 ObjectGrabPacket grab = new ObjectGrabPacket();
890 grab.AgentData.AgentID = Client.Self.AgentID;
891 grab.AgentData.SessionID = Client.Self.SessionID;
892 grab.ObjectData.GrabOffset = Vector3.Zero;
893 grab.ObjectData.LocalID = localID;
894 grab.SurfaceInfo = new ObjectGrabPacket.SurfaceInfoBlock[1];
895 grab.SurfaceInfo[0] = new ObjectGrabPacket.SurfaceInfoBlock();
896 grab.SurfaceInfo[0].UVCoord = uvCoord;
897 grab.SurfaceInfo[0].STCoord = stCoord;
898 grab.SurfaceInfo[0].FaceIndex = faceIndex;
899 grab.SurfaceInfo[0].Position = position;
900 grab.SurfaceInfo[0].Normal = normal;
901 grab.SurfaceInfo[0].Binormal = binormal;
902  
903 Client.Network.SendPacket(grab, simulator);
904  
905 // TODO: If these hit the server out of order the click will fail
906 // and we'll be grabbing the object
907 Thread.Sleep(50);
908  
909 ObjectDeGrabPacket degrab = new ObjectDeGrabPacket();
910 degrab.AgentData.AgentID = Client.Self.AgentID;
911 degrab.AgentData.SessionID = Client.Self.SessionID;
912 degrab.ObjectData.LocalID = localID;
913 degrab.SurfaceInfo = new ObjectDeGrabPacket.SurfaceInfoBlock[1];
914 degrab.SurfaceInfo[0] = new ObjectDeGrabPacket.SurfaceInfoBlock();
915 degrab.SurfaceInfo[0].UVCoord = uvCoord;
916 degrab.SurfaceInfo[0].STCoord = stCoord;
917 degrab.SurfaceInfo[0].FaceIndex = faceIndex;
918 degrab.SurfaceInfo[0].Position = position;
919 degrab.SurfaceInfo[0].Normal = normal;
920 degrab.SurfaceInfo[0].Binormal = binormal;
921  
922 Client.Network.SendPacket(degrab, simulator);
923 }
924  
925 /// <summary>
926 /// Create (rez) a new prim object in a simulator
927 /// </summary>
928 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object to place the object in</param>
929 /// <param name="prim">Data describing the prim object to rez</param>
930 /// <param name="groupID">Group ID that this prim will be set to, or UUID.Zero if you
931 /// do not want the object to be associated with a specific group</param>
932 /// <param name="position">An approximation of the position at which to rez the prim</param>
933 /// <param name="scale">Scale vector to size this prim</param>
934 /// <param name="rotation">Rotation quaternion to rotate this prim</param>
935 /// <remarks>Due to the way client prim rezzing is done on the server,
936 /// the requested position for an object is only close to where the prim
937 /// actually ends up. If you desire exact placement you'll need to
938 /// follow up by moving the object after it has been created. This
939 /// function will not set textures, light and flexible data, or other
940 /// extended primitive properties</remarks>
941 public void AddPrim(Simulator simulator, Primitive.ConstructionData prim, UUID groupID, Vector3 position,
942 Vector3 scale, Quaternion rotation)
943 {
944 AddPrim(simulator, prim, groupID, position, scale, rotation, PrimFlags.CreateSelected);
945 }
946  
947 /// <summary>
948 /// Create (rez) a new prim object in a simulator
949 /// </summary>
950 /// <param name="simulator">A reference to the <seealso cref="Simulator"/> object to place the object in</param>
951 /// <param name="prim">Data describing the prim object to rez</param>
952 /// <param name="groupID">Group ID that this prim will be set to, or UUID.Zero if you
953 /// do not want the object to be associated with a specific group</param>
954 /// <param name="position">An approximation of the position at which to rez the prim</param>
955 /// <param name="scale">Scale vector to size this prim</param>
956 /// <param name="rotation">Rotation quaternion to rotate this prim</param>
957 /// <param name="createFlags">Specify the <seealso cref="PrimFlags"/></param>
958 /// <remarks>Due to the way client prim rezzing is done on the server,
959 /// the requested position for an object is only close to where the prim
960 /// actually ends up. If you desire exact placement you'll need to
961 /// follow up by moving the object after it has been created. This
962 /// function will not set textures, light and flexible data, or other
963 /// extended primitive properties</remarks>
964 public void AddPrim(Simulator simulator, Primitive.ConstructionData prim, UUID groupID, Vector3 position,
965 Vector3 scale, Quaternion rotation, PrimFlags createFlags)
966 {
967 ObjectAddPacket packet = new ObjectAddPacket();
968  
969 packet.AgentData.AgentID = Client.Self.AgentID;
970 packet.AgentData.SessionID = Client.Self.SessionID;
971 packet.AgentData.GroupID = groupID;
972  
973 packet.ObjectData.State = prim.State;
974 packet.ObjectData.AddFlags = (uint)createFlags;
975 packet.ObjectData.PCode = (byte)PCode.Prim;
976  
977 packet.ObjectData.Material = (byte)prim.Material;
978 packet.ObjectData.Scale = scale;
979 packet.ObjectData.Rotation = rotation;
980  
981 packet.ObjectData.PathCurve = (byte)prim.PathCurve;
982 packet.ObjectData.PathBegin = Primitive.PackBeginCut(prim.PathBegin);
983 packet.ObjectData.PathEnd = Primitive.PackEndCut(prim.PathEnd);
984 packet.ObjectData.PathRadiusOffset = Primitive.PackPathTwist(prim.PathRadiusOffset);
985 packet.ObjectData.PathRevolutions = Primitive.PackPathRevolutions(prim.PathRevolutions);
986 packet.ObjectData.PathScaleX = Primitive.PackPathScale(prim.PathScaleX);
987 packet.ObjectData.PathScaleY = Primitive.PackPathScale(prim.PathScaleY);
988 packet.ObjectData.PathShearX = (byte)Primitive.PackPathShear(prim.PathShearX);
989 packet.ObjectData.PathShearY = (byte)Primitive.PackPathShear(prim.PathShearY);
990 packet.ObjectData.PathSkew = Primitive.PackPathTwist(prim.PathSkew);
991 packet.ObjectData.PathTaperX = Primitive.PackPathTaper(prim.PathTaperX);
992 packet.ObjectData.PathTaperY = Primitive.PackPathTaper(prim.PathTaperY);
993 packet.ObjectData.PathTwist = Primitive.PackPathTwist(prim.PathTwist);
994 packet.ObjectData.PathTwistBegin = Primitive.PackPathTwist(prim.PathTwistBegin);
995  
996 packet.ObjectData.ProfileCurve = prim.profileCurve;
997 packet.ObjectData.ProfileBegin = Primitive.PackBeginCut(prim.ProfileBegin);
998 packet.ObjectData.ProfileEnd = Primitive.PackEndCut(prim.ProfileEnd);
999 packet.ObjectData.ProfileHollow = Primitive.PackProfileHollow(prim.ProfileHollow);
1000  
1001 packet.ObjectData.RayStart = position;
1002 packet.ObjectData.RayEnd = position;
1003 packet.ObjectData.RayEndIsIntersection = 0;
1004 packet.ObjectData.RayTargetID = UUID.Zero;
1005 packet.ObjectData.BypassRaycast = 1;
1006  
1007 Client.Network.SendPacket(packet, simulator);
1008 }
1009  
1010 /// <summary>
1011 /// Rez a Linden tree
1012 /// </summary>
1013 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1014 /// <param name="scale">The size of the tree</param>
1015 /// <param name="rotation">The rotation of the tree</param>
1016 /// <param name="position">The position of the tree</param>
1017 /// <param name="treeType">The Type of tree</param>
1018 /// <param name="groupOwner">The <seealso cref="UUID"/> of the group to set the tree to,
1019 /// or UUID.Zero if no group is to be set</param>
1020 /// <param name="newTree">true to use the "new" Linden trees, false to use the old</param>
1021 public void AddTree(Simulator simulator, Vector3 scale, Quaternion rotation, Vector3 position,
1022 Tree treeType, UUID groupOwner, bool newTree)
1023 {
1024 ObjectAddPacket add = new ObjectAddPacket();
1025  
1026 add.AgentData.AgentID = Client.Self.AgentID;
1027 add.AgentData.SessionID = Client.Self.SessionID;
1028 add.AgentData.GroupID = groupOwner;
1029 add.ObjectData.BypassRaycast = 1;
1030 add.ObjectData.Material = 3;
1031 add.ObjectData.PathCurve = 16;
1032 add.ObjectData.PCode = newTree ? (byte)PCode.NewTree : (byte)PCode.Tree;
1033 add.ObjectData.RayEnd = position;
1034 add.ObjectData.RayStart = position;
1035 add.ObjectData.RayTargetID = UUID.Zero;
1036 add.ObjectData.Rotation = rotation;
1037 add.ObjectData.Scale = scale;
1038 add.ObjectData.State = (byte)treeType;
1039  
1040 Client.Network.SendPacket(add, simulator);
1041 }
1042  
1043 /// <summary>
1044 /// Rez grass and ground cover
1045 /// </summary>
1046 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1047 /// <param name="scale">The size of the grass</param>
1048 /// <param name="rotation">The rotation of the grass</param>
1049 /// <param name="position">The position of the grass</param>
1050 /// <param name="grassType">The type of grass from the <seealso cref="Grass"/> enum</param>
1051 /// <param name="groupOwner">The <seealso cref="UUID"/> of the group to set the tree to,
1052 /// or UUID.Zero if no group is to be set</param>
1053 public void AddGrass(Simulator simulator, Vector3 scale, Quaternion rotation, Vector3 position,
1054 Grass grassType, UUID groupOwner)
1055 {
1056 ObjectAddPacket add = new ObjectAddPacket();
1057  
1058 add.AgentData.AgentID = Client.Self.AgentID;
1059 add.AgentData.SessionID = Client.Self.SessionID;
1060 add.AgentData.GroupID = groupOwner;
1061 add.ObjectData.BypassRaycast = 1;
1062 add.ObjectData.Material = 3;
1063 add.ObjectData.PathCurve = 16;
1064 add.ObjectData.PCode = (byte)PCode.Grass;
1065 add.ObjectData.RayEnd = position;
1066 add.ObjectData.RayStart = position;
1067 add.ObjectData.RayTargetID = UUID.Zero;
1068 add.ObjectData.Rotation = rotation;
1069 add.ObjectData.Scale = scale;
1070 add.ObjectData.State = (byte)grassType;
1071  
1072 Client.Network.SendPacket(add, simulator);
1073 }
1074  
1075 /// <summary>
1076 /// Set the textures to apply to the faces of an object
1077 /// </summary>
1078 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1079 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1080 /// <param name="textures">The texture data to apply</param>
1081 public void SetTextures(Simulator simulator, uint localID, Primitive.TextureEntry textures)
1082 {
1083 SetTextures(simulator, localID, textures, String.Empty);
1084 }
1085  
1086 /// <summary>
1087 /// Set the textures to apply to the faces of an object
1088 /// </summary>
1089 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1090 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1091 /// <param name="textures">The texture data to apply</param>
1092 /// <param name="mediaUrl">A media URL (not used)</param>
1093 public void SetTextures(Simulator simulator, uint localID, Primitive.TextureEntry textures, string mediaUrl)
1094 {
1095 ObjectImagePacket image = new ObjectImagePacket();
1096  
1097 image.AgentData.AgentID = Client.Self.AgentID;
1098 image.AgentData.SessionID = Client.Self.SessionID;
1099 image.ObjectData = new ObjectImagePacket.ObjectDataBlock[1];
1100 image.ObjectData[0] = new ObjectImagePacket.ObjectDataBlock();
1101 image.ObjectData[0].ObjectLocalID = localID;
1102 image.ObjectData[0].TextureEntry = textures.GetBytes();
1103 image.ObjectData[0].MediaURL = Utils.StringToBytes(mediaUrl);
1104  
1105 Client.Network.SendPacket(image, simulator);
1106 }
1107  
1108 /// <summary>
1109 /// Set the Light data on an object
1110 /// </summary>
1111 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1112 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1113 /// <param name="light">A <seealso cref="Primitive.LightData"/> object containing the data to set</param>
1114 public void SetLight(Simulator simulator, uint localID, Primitive.LightData light)
1115 {
1116 ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket();
1117  
1118 extra.AgentData.AgentID = Client.Self.AgentID;
1119 extra.AgentData.SessionID = Client.Self.SessionID;
1120 extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1];
1121 extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock();
1122 extra.ObjectData[0].ObjectLocalID = localID;
1123 extra.ObjectData[0].ParamType = (byte)ExtraParamType.Light;
1124 if (light.Intensity == 0.0f)
1125 {
1126 // Disables the light if intensity is 0
1127 extra.ObjectData[0].ParamInUse = false;
1128 }
1129 else
1130 {
1131 extra.ObjectData[0].ParamInUse = true;
1132 }
1133 extra.ObjectData[0].ParamData = light.GetBytes();
1134 extra.ObjectData[0].ParamSize = (uint)extra.ObjectData[0].ParamData.Length;
1135  
1136 Client.Network.SendPacket(extra, simulator);
1137 }
1138  
1139 /// <summary>
1140 /// Set the flexible data on an object
1141 /// </summary>
1142 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1143 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1144 /// <param name="flexible">A <seealso cref="Primitive.FlexibleData"/> object containing the data to set</param>
1145 public void SetFlexible(Simulator simulator, uint localID, Primitive.FlexibleData flexible)
1146 {
1147 ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket();
1148  
1149 extra.AgentData.AgentID = Client.Self.AgentID;
1150 extra.AgentData.SessionID = Client.Self.SessionID;
1151 extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1];
1152 extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock();
1153 extra.ObjectData[0].ObjectLocalID = localID;
1154 extra.ObjectData[0].ParamType = (byte)ExtraParamType.Flexible;
1155 extra.ObjectData[0].ParamInUse = true;
1156 extra.ObjectData[0].ParamData = flexible.GetBytes();
1157 extra.ObjectData[0].ParamSize = (uint)extra.ObjectData[0].ParamData.Length;
1158  
1159 Client.Network.SendPacket(extra, simulator);
1160 }
1161  
1162 /// <summary>
1163 /// Set the sculptie texture and data on an object
1164 /// </summary>
1165 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1166 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1167 /// <param name="sculpt">A <seealso cref="Primitive.SculptData"/> object containing the data to set</param>
1168 public void SetSculpt(Simulator simulator, uint localID, Primitive.SculptData sculpt)
1169 {
1170 ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket();
1171  
1172 extra.AgentData.AgentID = Client.Self.AgentID;
1173 extra.AgentData.SessionID = Client.Self.SessionID;
1174  
1175 extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1];
1176 extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock();
1177 extra.ObjectData[0].ObjectLocalID = localID;
1178 extra.ObjectData[0].ParamType = (byte)ExtraParamType.Sculpt;
1179 extra.ObjectData[0].ParamInUse = true;
1180 extra.ObjectData[0].ParamData = sculpt.GetBytes();
1181 extra.ObjectData[0].ParamSize = (uint)extra.ObjectData[0].ParamData.Length;
1182  
1183 Client.Network.SendPacket(extra, simulator);
1184  
1185 // Not sure why, but if you don't send this the sculpted prim disappears
1186 ObjectShapePacket shape = new ObjectShapePacket();
1187  
1188 shape.AgentData.AgentID = Client.Self.AgentID;
1189 shape.AgentData.SessionID = Client.Self.SessionID;
1190  
1191 shape.ObjectData = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock[1];
1192 shape.ObjectData[0] = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock();
1193 shape.ObjectData[0].ObjectLocalID = localID;
1194 shape.ObjectData[0].PathScaleX = 100;
1195 shape.ObjectData[0].PathScaleY = 150;
1196 shape.ObjectData[0].PathCurve = 32;
1197  
1198 Client.Network.SendPacket(shape, simulator);
1199 }
1200  
1201 /// <summary>
1202 /// Unset additional primitive parameters on an object
1203 /// </summary>
1204 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1205 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1206 /// <param name="type">The extra parameters to set</param>
1207 public void SetExtraParamOff(Simulator simulator, uint localID, ExtraParamType type)
1208 {
1209 ObjectExtraParamsPacket extra = new ObjectExtraParamsPacket();
1210  
1211 extra.AgentData.AgentID = Client.Self.AgentID;
1212 extra.AgentData.SessionID = Client.Self.SessionID;
1213 extra.ObjectData = new ObjectExtraParamsPacket.ObjectDataBlock[1];
1214 extra.ObjectData[0] = new ObjectExtraParamsPacket.ObjectDataBlock();
1215 extra.ObjectData[0].ObjectLocalID = localID;
1216 extra.ObjectData[0].ParamType = (byte)type;
1217 extra.ObjectData[0].ParamInUse = false;
1218 extra.ObjectData[0].ParamData = Utils.EmptyBytes;
1219 extra.ObjectData[0].ParamSize = 0;
1220  
1221 Client.Network.SendPacket(extra, simulator);
1222 }
1223  
1224 /// <summary>
1225 /// Link multiple prims into a linkset
1226 /// </summary>
1227 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the objects reside</param>
1228 /// <param name="localIDs">An array which contains the IDs of the objects to link</param>
1229 /// <remarks>The last object in the array will be the root object of the linkset TODO: Is this true?</remarks>
1230 public void LinkPrims(Simulator simulator, List<uint> localIDs)
1231 {
1232 ObjectLinkPacket packet = new ObjectLinkPacket();
1233  
1234 packet.AgentData.AgentID = Client.Self.AgentID;
1235 packet.AgentData.SessionID = Client.Self.SessionID;
1236  
1237 packet.ObjectData = new ObjectLinkPacket.ObjectDataBlock[localIDs.Count];
1238  
1239 for (int i = 0; i < localIDs.Count; i++)
1240 {
1241 packet.ObjectData[i] = new ObjectLinkPacket.ObjectDataBlock();
1242 packet.ObjectData[i].ObjectLocalID = localIDs[i];
1243 }
1244  
1245 Client.Network.SendPacket(packet, simulator);
1246 }
1247  
1248 /// <summary>
1249 /// Delink/Unlink multiple prims from a linkset
1250 /// </summary>
1251 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the objects reside</param>
1252 /// <param name="localIDs">An array which contains the IDs of the objects to delink</param>
1253 public void DelinkPrims(Simulator simulator, List<uint> localIDs)
1254 {
1255 ObjectDelinkPacket packet = new ObjectDelinkPacket();
1256  
1257 packet.AgentData.AgentID = Client.Self.AgentID;
1258 packet.AgentData.SessionID = Client.Self.SessionID;
1259  
1260 packet.ObjectData = new ObjectDelinkPacket.ObjectDataBlock[localIDs.Count];
1261  
1262 int i = 0;
1263 foreach (uint localID in localIDs)
1264 {
1265 packet.ObjectData[i] = new ObjectDelinkPacket.ObjectDataBlock();
1266 packet.ObjectData[i].ObjectLocalID = localID;
1267  
1268 i++;
1269 }
1270  
1271 Client.Network.SendPacket(packet, simulator);
1272 }
1273  
1274 /// <summary>
1275 /// Change the rotation of an object
1276 /// </summary>
1277 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1278 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1279 /// <param name="rotation">The new rotation of the object</param>
1280 public void SetRotation(Simulator simulator, uint localID, Quaternion rotation)
1281 {
1282 ObjectRotationPacket objRotPacket = new ObjectRotationPacket();
1283 objRotPacket.AgentData.AgentID = Client.Self.AgentID;
1284 objRotPacket.AgentData.SessionID = Client.Self.SessionID;
1285  
1286 objRotPacket.ObjectData = new ObjectRotationPacket.ObjectDataBlock[1];
1287  
1288 objRotPacket.ObjectData[0] = new ObjectRotationPacket.ObjectDataBlock();
1289 objRotPacket.ObjectData[0].ObjectLocalID = localID;
1290 objRotPacket.ObjectData[0].Rotation = rotation;
1291 Client.Network.SendPacket(objRotPacket, simulator);
1292 }
1293  
1294 /// <summary>
1295 /// Set the name of an object
1296 /// </summary>
1297 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1298 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1299 /// <param name="name">A string containing the new name of the object</param>
1300 public void SetName(Simulator simulator, uint localID, string name)
1301 {
1302 SetNames(simulator, new uint[] { localID }, new string[] { name });
1303 }
1304  
1305 /// <summary>
1306 /// Set the name of multiple objects
1307 /// </summary>
1308 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the objects reside</param>
1309 /// <param name="localIDs">An array which contains the IDs of the objects to change the name of</param>
1310 /// <param name="names">An array which contains the new names of the objects</param>
1311 public void SetNames(Simulator simulator, uint[] localIDs, string[] names)
1312 {
1313 ObjectNamePacket namePacket = new ObjectNamePacket();
1314 namePacket.AgentData.AgentID = Client.Self.AgentID;
1315 namePacket.AgentData.SessionID = Client.Self.SessionID;
1316  
1317 namePacket.ObjectData = new ObjectNamePacket.ObjectDataBlock[localIDs.Length];
1318  
1319 for (int i = 0; i < localIDs.Length; ++i)
1320 {
1321 namePacket.ObjectData[i] = new ObjectNamePacket.ObjectDataBlock();
1322 namePacket.ObjectData[i].LocalID = localIDs[i];
1323 namePacket.ObjectData[i].Name = Utils.StringToBytes(names[i]);
1324 }
1325  
1326 Client.Network.SendPacket(namePacket, simulator);
1327 }
1328  
1329 /// <summary>
1330 /// Set the description of an object
1331 /// </summary>
1332 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1333 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1334 /// <param name="description">A string containing the new description of the object</param>
1335 public void SetDescription(Simulator simulator, uint localID, string description)
1336 {
1337 SetDescriptions(simulator, new uint[] { localID }, new string[] { description });
1338 }
1339  
1340 /// <summary>
1341 /// Set the descriptions of multiple objects
1342 /// </summary>
1343 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the objects reside</param>
1344 /// <param name="localIDs">An array which contains the IDs of the objects to change the description of</param>
1345 /// <param name="descriptions">An array which contains the new descriptions of the objects</param>
1346 public void SetDescriptions(Simulator simulator, uint[] localIDs, string[] descriptions)
1347 {
1348 ObjectDescriptionPacket descPacket = new ObjectDescriptionPacket();
1349 descPacket.AgentData.AgentID = Client.Self.AgentID;
1350 descPacket.AgentData.SessionID = Client.Self.SessionID;
1351  
1352 descPacket.ObjectData = new ObjectDescriptionPacket.ObjectDataBlock[localIDs.Length];
1353  
1354 for (int i = 0; i < localIDs.Length; ++i)
1355 {
1356 descPacket.ObjectData[i] = new ObjectDescriptionPacket.ObjectDataBlock();
1357 descPacket.ObjectData[i].LocalID = localIDs[i];
1358 descPacket.ObjectData[i].Description = Utils.StringToBytes(descriptions[i]);
1359 }
1360  
1361 Client.Network.SendPacket(descPacket, simulator);
1362 }
1363  
1364 /// <summary>
1365 /// Attach an object to this avatar
1366 /// </summary>
1367 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1368 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1369 /// <param name="attachPoint">The point on the avatar the object will be attached</param>
1370 /// <param name="rotation">The rotation of the attached object</param>
1371 public void AttachObject(Simulator simulator, uint localID, AttachmentPoint attachPoint, Quaternion rotation)
1372 {
1373 ObjectAttachPacket attach = new ObjectAttachPacket();
1374 attach.AgentData.AgentID = Client.Self.AgentID;
1375 attach.AgentData.SessionID = Client.Self.SessionID;
1376 attach.AgentData.AttachmentPoint = (byte)attachPoint;
1377  
1378 attach.ObjectData = new ObjectAttachPacket.ObjectDataBlock[1];
1379 attach.ObjectData[0] = new ObjectAttachPacket.ObjectDataBlock();
1380 attach.ObjectData[0].ObjectLocalID = localID;
1381 attach.ObjectData[0].Rotation = rotation;
1382  
1383 Client.Network.SendPacket(attach, simulator);
1384 }
1385  
1386 /// <summary>
1387 /// Drop an attached object from this avatar
1388 /// </summary>
1389 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/>
1390 /// object where the objects reside. This will always be the simulator the avatar is currently in
1391 /// </param>
1392 /// <param name="localID">The object's ID which is local to the simulator the object is in</param>
1393 public void DropObject(Simulator simulator, uint localID)
1394 {
1395 ObjectDropPacket dropit = new ObjectDropPacket();
1396 dropit.AgentData.AgentID = Client.Self.AgentID;
1397 dropit.AgentData.SessionID = Client.Self.SessionID;
1398 dropit.ObjectData = new ObjectDropPacket.ObjectDataBlock[1];
1399 dropit.ObjectData[0] = new ObjectDropPacket.ObjectDataBlock();
1400 dropit.ObjectData[0].ObjectLocalID = localID;
1401  
1402 Client.Network.SendPacket(dropit, simulator);
1403 }
1404  
1405 /// <summary>
1406 /// Detach an object from yourself
1407 /// </summary>
1408 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/>
1409 /// object where the objects reside
1410 ///
1411 /// This will always be the simulator the avatar is currently in
1412 /// </param>
1413 /// <param name="localIDs">An array which contains the IDs of the objects to detach</param>
1414 public void DetachObjects(Simulator simulator, List<uint> localIDs)
1415 {
1416 ObjectDetachPacket detach = new ObjectDetachPacket();
1417 detach.AgentData.AgentID = Client.Self.AgentID;
1418 detach.AgentData.SessionID = Client.Self.SessionID;
1419 detach.ObjectData = new ObjectDetachPacket.ObjectDataBlock[localIDs.Count];
1420  
1421 for (int i = 0; i < localIDs.Count; i++)
1422 {
1423 detach.ObjectData[i] = new ObjectDetachPacket.ObjectDataBlock();
1424 detach.ObjectData[i].ObjectLocalID = localIDs[i];
1425 }
1426  
1427 Client.Network.SendPacket(detach, simulator);
1428 }
1429  
1430 /// <summary>
1431 /// Change the position of an object, Will change position of entire linkset
1432 /// </summary>
1433 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1434 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1435 /// <param name="position">The new position of the object</param>
1436 public void SetPosition(Simulator simulator, uint localID, Vector3 position)
1437 {
1438 UpdateObject(simulator, localID, position, UpdateType.Position | UpdateType.Linked);
1439 }
1440  
1441 /// <summary>
1442 /// Change the position of an object
1443 /// </summary>
1444 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1445 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1446 /// <param name="position">The new position of the object</param>
1447 /// <param name="childOnly">if true, will change position of (this) child prim only, not entire linkset</param>
1448 public void SetPosition(Simulator simulator, uint localID, Vector3 position, bool childOnly)
1449 {
1450 UpdateType type = UpdateType.Position;
1451  
1452 if (!childOnly)
1453 type |= UpdateType.Linked;
1454  
1455 UpdateObject(simulator, localID, position, type);
1456 }
1457  
1458 /// <summary>
1459 /// Change the Scale (size) of an object
1460 /// </summary>
1461 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1462 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1463 /// <param name="scale">The new scale of the object</param>
1464 /// <param name="childOnly">If true, will change scale of this prim only, not entire linkset</param>
1465 /// <param name="uniform">True to resize prims uniformly</param>
1466 public void SetScale(Simulator simulator, uint localID, Vector3 scale, bool childOnly, bool uniform)
1467 {
1468 UpdateType type = UpdateType.Scale;
1469  
1470 if (!childOnly)
1471 type |= UpdateType.Linked;
1472  
1473 if (uniform)
1474 type |= UpdateType.Uniform;
1475  
1476 UpdateObject(simulator, localID, scale, type);
1477 }
1478  
1479 /// <summary>
1480 /// Change the Rotation of an object that is either a child or a whole linkset
1481 /// </summary>
1482 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1483 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1484 /// <param name="quat">The new scale of the object</param>
1485 /// <param name="childOnly">If true, will change rotation of this prim only, not entire linkset</param>
1486 public void SetRotation(Simulator simulator, uint localID, Quaternion quat, bool childOnly)
1487 {
1488 UpdateType type = UpdateType.Rotation;
1489  
1490 if (!childOnly)
1491 type |= UpdateType.Linked;
1492  
1493 MultipleObjectUpdatePacket multiObjectUpdate = new MultipleObjectUpdatePacket();
1494 multiObjectUpdate.AgentData.AgentID = Client.Self.AgentID;
1495 multiObjectUpdate.AgentData.SessionID = Client.Self.SessionID;
1496  
1497 multiObjectUpdate.ObjectData = new MultipleObjectUpdatePacket.ObjectDataBlock[1];
1498  
1499 multiObjectUpdate.ObjectData[0] = new MultipleObjectUpdatePacket.ObjectDataBlock();
1500 multiObjectUpdate.ObjectData[0].Type = (byte)type;
1501 multiObjectUpdate.ObjectData[0].ObjectLocalID = localID;
1502 multiObjectUpdate.ObjectData[0].Data = quat.GetBytes();
1503  
1504 Client.Network.SendPacket(multiObjectUpdate, simulator);
1505 }
1506  
1507 /// <summary>
1508 /// Send a Multiple Object Update packet to change the size, scale or rotation of a primitive
1509 /// </summary>
1510 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1511 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1512 /// <param name="data">The new rotation, size, or position of the target object</param>
1513 /// <param name="type">The flags from the <seealso cref="UpdateType"/> Enum</param>
1514 public void UpdateObject(Simulator simulator, uint localID, Vector3 data, UpdateType type)
1515 {
1516 MultipleObjectUpdatePacket multiObjectUpdate = new MultipleObjectUpdatePacket();
1517 multiObjectUpdate.AgentData.AgentID = Client.Self.AgentID;
1518 multiObjectUpdate.AgentData.SessionID = Client.Self.SessionID;
1519  
1520 multiObjectUpdate.ObjectData = new MultipleObjectUpdatePacket.ObjectDataBlock[1];
1521  
1522 multiObjectUpdate.ObjectData[0] = new MultipleObjectUpdatePacket.ObjectDataBlock();
1523 multiObjectUpdate.ObjectData[0].Type = (byte)type;
1524 multiObjectUpdate.ObjectData[0].ObjectLocalID = localID;
1525 multiObjectUpdate.ObjectData[0].Data = data.GetBytes();
1526  
1527 Client.Network.SendPacket(multiObjectUpdate, simulator);
1528 }
1529  
1530 /// <summary>
1531 /// Deed an object (prim) to a group, Object must be shared with group which
1532 /// can be accomplished with SetPermissions()
1533 /// </summary>
1534 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1535 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
1536 /// <param name="groupOwner">The <seealso cref="UUID"/> of the group to deed the object to</param>
1537 public void DeedObject(Simulator simulator, uint localID, UUID groupOwner)
1538 {
1539 ObjectOwnerPacket objDeedPacket = new ObjectOwnerPacket();
1540 objDeedPacket.AgentData.AgentID = Client.Self.AgentID;
1541 objDeedPacket.AgentData.SessionID = Client.Self.SessionID;
1542  
1543 // Can only be use in God mode
1544 objDeedPacket.HeaderData.Override = false;
1545 objDeedPacket.HeaderData.OwnerID = UUID.Zero;
1546 objDeedPacket.HeaderData.GroupID = groupOwner;
1547  
1548 objDeedPacket.ObjectData = new ObjectOwnerPacket.ObjectDataBlock[1];
1549 objDeedPacket.ObjectData[0] = new ObjectOwnerPacket.ObjectDataBlock();
1550  
1551 objDeedPacket.ObjectData[0].ObjectLocalID = localID;
1552  
1553 Client.Network.SendPacket(objDeedPacket, simulator);
1554 }
1555  
1556 /// <summary>
1557 /// Deed multiple objects (prims) to a group, Objects must be shared with group which
1558 /// can be accomplished with SetPermissions()
1559 /// </summary>
1560 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1561 /// <param name="localIDs">An array which contains the IDs of the objects to deed</param>
1562 /// <param name="groupOwner">The <seealso cref="UUID"/> of the group to deed the object to</param>
1563 public void DeedObjects(Simulator simulator, List<uint> localIDs, UUID groupOwner)
1564 {
1565 ObjectOwnerPacket packet = new ObjectOwnerPacket();
1566 packet.AgentData.AgentID = Client.Self.AgentID;
1567 packet.AgentData.SessionID = Client.Self.SessionID;
1568  
1569 // Can only be use in God mode
1570 packet.HeaderData.Override = false;
1571 packet.HeaderData.OwnerID = UUID.Zero;
1572 packet.HeaderData.GroupID = groupOwner;
1573  
1574 packet.ObjectData = new ObjectOwnerPacket.ObjectDataBlock[localIDs.Count];
1575  
1576 for (int i = 0; i < localIDs.Count; i++)
1577 {
1578 packet.ObjectData[i] = new ObjectOwnerPacket.ObjectDataBlock();
1579 packet.ObjectData[i].ObjectLocalID = localIDs[i];
1580 }
1581 Client.Network.SendPacket(packet, simulator);
1582 }
1583  
1584 /// <summary>
1585 /// Set the permissions on multiple objects
1586 /// </summary>
1587 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the objects reside</param>
1588 /// <param name="localIDs">An array which contains the IDs of the objects to set the permissions on</param>
1589 /// <param name="who">The new Who mask to set</param>
1590 /// <param name="permissions">Which permission to modify</param>
1591 /// <param name="set">The new state of permission</param>
1592 public void SetPermissions(Simulator simulator, List<uint> localIDs, PermissionWho who,
1593 PermissionMask permissions, bool set)
1594 {
1595 ObjectPermissionsPacket packet = new ObjectPermissionsPacket();
1596  
1597 packet.AgentData.AgentID = Client.Self.AgentID;
1598 packet.AgentData.SessionID = Client.Self.SessionID;
1599  
1600 // Override can only be used by gods
1601 packet.HeaderData.Override = false;
1602  
1603 packet.ObjectData = new ObjectPermissionsPacket.ObjectDataBlock[localIDs.Count];
1604  
1605 for (int i = 0; i < localIDs.Count; i++)
1606 {
1607 packet.ObjectData[i] = new ObjectPermissionsPacket.ObjectDataBlock();
1608  
1609 packet.ObjectData[i].ObjectLocalID = localIDs[i];
1610 packet.ObjectData[i].Field = (byte)who;
1611 packet.ObjectData[i].Mask = (uint)permissions;
1612 packet.ObjectData[i].Set = Convert.ToByte(set);
1613 }
1614  
1615 Client.Network.SendPacket(packet, simulator);
1616 }
1617  
1618 /// <summary>
1619 /// Request additional properties for an object
1620 /// </summary>
1621 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1622 /// <param name="objectID"></param>
1623 public void RequestObjectPropertiesFamily(Simulator simulator, UUID objectID)
1624 {
1625 RequestObjectPropertiesFamily(simulator, objectID, true);
1626 }
1627  
1628 /// <summary>
1629 /// Request additional properties for an object
1630 /// </summary>
1631 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
1632 /// <param name="objectID">Absolute UUID of the object</param>
1633 /// <param name="reliable">Whether to require server acknowledgement of this request</param>
1634 public void RequestObjectPropertiesFamily(Simulator simulator, UUID objectID, bool reliable)
1635 {
1636 RequestObjectPropertiesFamilyPacket properties = new RequestObjectPropertiesFamilyPacket();
1637 properties.AgentData.AgentID = Client.Self.AgentID;
1638 properties.AgentData.SessionID = Client.Self.SessionID;
1639 properties.ObjectData.ObjectID = objectID;
1640 // TODO: RequestFlags is typically only for bug report submissions, but we might be able to
1641 // use it to pass an arbitrary uint back to the callback
1642 properties.ObjectData.RequestFlags = 0;
1643  
1644 properties.Header.Reliable = reliable;
1645  
1646 Client.Network.SendPacket(properties, simulator);
1647 }
1648  
1649 /// <summary>
1650 /// Set the ownership of a list of objects to the specified group
1651 /// </summary>
1652 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the objects reside</param>
1653 /// <param name="localIds">An array which contains the IDs of the objects to set the group id on</param>
1654 /// <param name="groupID">The Groups ID</param>
1655 public void SetObjectsGroup(Simulator simulator, List<uint> localIds, UUID groupID)
1656 {
1657 ObjectGroupPacket packet = new ObjectGroupPacket();
1658 packet.AgentData.AgentID = Client.Self.AgentID;
1659 packet.AgentData.GroupID = groupID;
1660 packet.AgentData.SessionID = Client.Self.SessionID;
1661  
1662 packet.ObjectData = new ObjectGroupPacket.ObjectDataBlock[localIds.Count];
1663 for (int i = 0; i < localIds.Count; i++)
1664 {
1665 packet.ObjectData[i] = new ObjectGroupPacket.ObjectDataBlock();
1666 packet.ObjectData[i].ObjectLocalID = localIds[i];
1667 }
1668  
1669 Client.Network.SendPacket(packet, simulator);
1670 }
1671  
1672 /// <summary>
1673 /// Update current URL of the previously set prim media
1674 /// </summary>
1675 /// <param name="primID">UUID of the prim</param>
1676 /// <param name="newURL">Set current URL to this</param>
1677 /// <param name="face">Prim face number</param>
1678 /// <param name="sim">Simulator in which prim is located</param>
1679 public void NavigateObjectMedia(UUID primID, int face, string newURL, Simulator sim)
1680 {
1681 Uri url;
1682 if (sim.Caps != null && null != (url = sim.Caps.CapabilityURI("ObjectMediaNavigate")))
1683 {
1684 ObjectMediaNavigateMessage req = new ObjectMediaNavigateMessage();
1685 req.PrimID = primID;
1686 req.URL = newURL;
1687 req.Face = face;
1688  
1689 CapsClient request = new CapsClient(url);
1690 request.OnComplete += (CapsClient client, OSD result, Exception error) =>
1691 {
1692 if (error != null)
1693 {
1694 Logger.Log("ObjectMediaNavigate: " + error.Message, Helpers.LogLevel.Error, Client);
1695 }
1696 };
1697  
1698 request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
1699 }
1700 else
1701 {
1702 Logger.Log("ObjectMediaNavigate capability not available", Helpers.LogLevel.Error, Client);
1703 }
1704 }
1705  
1706 /// <summary>
1707 /// Set object media
1708 /// </summary>
1709 /// <param name="primID">UUID of the prim</param>
1710 /// <param name="faceMedia">Array the length of prims number of faces. Null on face indexes where there is
1711 /// no media, <seealso cref="MediaEntry"/> on faces which contain the media</param>
1712 /// <param name="sim">Simulatior in which prim is located</param>
1713 public void UpdateObjectMedia(UUID primID, MediaEntry[] faceMedia, Simulator sim)
1714 {
1715 Uri url;
1716 if (sim.Caps != null && null != (url = sim.Caps.CapabilityURI("ObjectMedia")))
1717 {
1718 ObjectMediaUpdate req = new ObjectMediaUpdate();
1719 req.PrimID = primID;
1720 req.FaceMedia = faceMedia;
1721 req.Verb = "UPDATE";
1722  
1723 CapsClient request = new CapsClient(url);
1724 request.OnComplete += (CapsClient client, OSD result, Exception error) =>
1725 {
1726 if (error != null)
1727 {
1728 Logger.Log("ObjectMediaUpdate: " + error.Message, Helpers.LogLevel.Error, Client);
1729 }
1730 };
1731 request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
1732 }
1733 else
1734 {
1735 Logger.Log("ObjectMedia capability not available", Helpers.LogLevel.Error, Client);
1736 }
1737 }
1738  
1739 /// <summary>
1740 /// Retrieve information about object media
1741 /// </summary>
1742 /// <param name="primID">UUID of the primitive</param>
1743 /// <param name="sim">Simulator where prim is located</param>
1744 /// <param name="callback">Call this callback when done</param>
1745 public void RequestObjectMedia(UUID primID, Simulator sim, ObjectMediaCallback callback)
1746 {
1747 Uri url;
1748 if (sim.Caps != null && null != (url = sim.Caps.CapabilityURI("ObjectMedia")))
1749 {
1750 ObjectMediaRequest req = new ObjectMediaRequest();
1751 req.PrimID = primID;
1752 req.Verb = "GET";
1753  
1754 CapsClient request = new CapsClient(url);
1755 request.OnComplete += (CapsClient client, OSD result, Exception error) =>
1756 {
1757 if (result == null)
1758 {
1759 Logger.Log("Failed retrieving ObjectMedia data", Helpers.LogLevel.Error, Client);
1760 try { callback(false, string.Empty, null); }
1761 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
1762 return;
1763 }
1764  
1765 ObjectMediaMessage msg = new ObjectMediaMessage();
1766 msg.Deserialize((OSDMap)result);
1767  
1768 if (msg.Request is ObjectMediaResponse)
1769 {
1770 ObjectMediaResponse response = (ObjectMediaResponse)msg.Request;
1771  
1772 if (Client.Settings.OBJECT_TRACKING)
1773 {
1774 Primitive prim = sim.ObjectsPrimitives.Find((Primitive p) => { return p.ID == primID; });
1775 if (prim != null)
1776 {
1777 prim.MediaVersion = response.Version;
1778 prim.FaceMedia = response.FaceMedia;
1779 }
1780 }
1781  
1782 try { callback(true, response.Version, response.FaceMedia); }
1783 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
1784 }
1785 else
1786 {
1787 try { callback(false, string.Empty, null); }
1788 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
1789 }
1790 };
1791  
1792 request.BeginGetResponse(req.Serialize(), OSDFormat.Xml, Client.Settings.CAPS_TIMEOUT);
1793 }
1794 else
1795 {
1796 Logger.Log("ObjectMedia capability not available", Helpers.LogLevel.Error, Client);
1797 try { callback(false, string.Empty, null); }
1798 catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, Client); }
1799 }
1800 }
1801 #endregion
1802  
1803 #region Packet Handlers
1804  
1805 /// <summary>Process an incoming packet and raise the appropriate events</summary>
1806 /// <param name="sender">The sender</param>
1807 /// <param name="e">The EventArgs object containing the packet data</param>
1808 protected void ObjectUpdateHandler(object sender, PacketReceivedEventArgs e)
1809 {
1810 Packet packet = e.Packet;
1811 Simulator simulator = e.Simulator;
1812  
1813 ObjectUpdatePacket update = (ObjectUpdatePacket)packet;
1814 UpdateDilation(e.Simulator, update.RegionData.TimeDilation);
1815  
1816 for (int b = 0; b < update.ObjectData.Length; b++)
1817 {
1818 ObjectUpdatePacket.ObjectDataBlock block = update.ObjectData[b];
1819  
1820 ObjectMovementUpdate objectupdate = new ObjectMovementUpdate();
1821 //Vector4 collisionPlane = Vector4.Zero;
1822 //Vector3 position;
1823 //Vector3 velocity;
1824 //Vector3 acceleration;
1825 //Quaternion rotation;
1826 //Vector3 angularVelocity;
1827 NameValue[] nameValues;
1828 bool attachment = false;
1829 PCode pcode = (PCode)block.PCode;
1830  
1831 #region Relevance check
1832  
1833 // Check if we are interested in this object
1834 if (!Client.Settings.ALWAYS_DECODE_OBJECTS)
1835 {
1836 switch (pcode)
1837 {
1838 case PCode.Grass:
1839 case PCode.Tree:
1840 case PCode.NewTree:
1841 case PCode.Prim:
1842 if (m_ObjectUpdate == null) continue;
1843 break;
1844 case PCode.Avatar:
1845 // Make an exception for updates about our own agent
1846 if (block.FullID != Client.Self.AgentID && m_AvatarUpdate == null) continue;
1847 break;
1848 case PCode.ParticleSystem:
1849 continue; // TODO: Do something with these
1850 }
1851 }
1852  
1853 #endregion Relevance check
1854  
1855 #region NameValue parsing
1856  
1857 string nameValue = Utils.BytesToString(block.NameValue);
1858 if (nameValue.Length > 0)
1859 {
1860 string[] lines = nameValue.Split('\n');
1861 nameValues = new NameValue[lines.Length];
1862  
1863 for (int i = 0; i < lines.Length; i++)
1864 {
1865 if (!String.IsNullOrEmpty(lines[i]))
1866 {
1867 NameValue nv = new NameValue(lines[i]);
1868 if (nv.Name == "AttachItemID") attachment = true;
1869 nameValues[i] = nv;
1870 }
1871 }
1872 }
1873 else
1874 {
1875 nameValues = new NameValue[0];
1876 }
1877  
1878 #endregion NameValue parsing
1879  
1880 #region Decode Object (primitive) parameters
1881 Primitive.ConstructionData data = new Primitive.ConstructionData();
1882 data.State = block.State;
1883 data.Material = (Material)block.Material;
1884 data.PathCurve = (PathCurve)block.PathCurve;
1885 data.profileCurve = block.ProfileCurve;
1886 data.PathBegin = Primitive.UnpackBeginCut(block.PathBegin);
1887 data.PathEnd = Primitive.UnpackEndCut(block.PathEnd);
1888 data.PathScaleX = Primitive.UnpackPathScale(block.PathScaleX);
1889 data.PathScaleY = Primitive.UnpackPathScale(block.PathScaleY);
1890 data.PathShearX = Primitive.UnpackPathShear((sbyte)block.PathShearX);
1891 data.PathShearY = Primitive.UnpackPathShear((sbyte)block.PathShearY);
1892 data.PathTwist = Primitive.UnpackPathTwist(block.PathTwist);
1893 data.PathTwistBegin = Primitive.UnpackPathTwist(block.PathTwistBegin);
1894 data.PathRadiusOffset = Primitive.UnpackPathTwist(block.PathRadiusOffset);
1895 data.PathTaperX = Primitive.UnpackPathTaper(block.PathTaperX);
1896 data.PathTaperY = Primitive.UnpackPathTaper(block.PathTaperY);
1897 data.PathRevolutions = Primitive.UnpackPathRevolutions(block.PathRevolutions);
1898 data.PathSkew = Primitive.UnpackPathTwist(block.PathSkew);
1899 data.ProfileBegin = Primitive.UnpackBeginCut(block.ProfileBegin);
1900 data.ProfileEnd = Primitive.UnpackEndCut(block.ProfileEnd);
1901 data.ProfileHollow = Primitive.UnpackProfileHollow(block.ProfileHollow);
1902 data.PCode = pcode;
1903 #endregion
1904  
1905 #region Decode Additional packed parameters in ObjectData
1906 int pos = 0;
1907 switch (block.ObjectData.Length)
1908 {
1909 case 76:
1910 // Collision normal for avatar
1911 objectupdate.CollisionPlane = new Vector4(block.ObjectData, pos);
1912 pos += 16;
1913  
1914 goto case 60;
1915 case 60:
1916 // Position
1917 objectupdate.Position = new Vector3(block.ObjectData, pos);
1918 pos += 12;
1919 // Velocity
1920 objectupdate.Velocity = new Vector3(block.ObjectData, pos);
1921 pos += 12;
1922 // Acceleration
1923 objectupdate.Acceleration = new Vector3(block.ObjectData, pos);
1924 pos += 12;
1925 // Rotation (theta)
1926 objectupdate.Rotation = new Quaternion(block.ObjectData, pos, true);
1927 pos += 12;
1928 // Angular velocity (omega)
1929 objectupdate.AngularVelocity = new Vector3(block.ObjectData, pos);
1930 pos += 12;
1931  
1932 break;
1933 case 48:
1934 // Collision normal for avatar
1935 objectupdate.CollisionPlane = new Vector4(block.ObjectData, pos);
1936 pos += 16;
1937  
1938 goto case 32;
1939 case 32:
1940 // The data is an array of unsigned shorts
1941  
1942 // Position
1943 objectupdate.Position = new Vector3(
1944 Utils.UInt16ToFloat(block.ObjectData, pos, -0.5f * 256.0f, 1.5f * 256.0f),
1945 Utils.UInt16ToFloat(block.ObjectData, pos + 2, -0.5f * 256.0f, 1.5f * 256.0f),
1946 Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 3.0f * 256.0f));
1947 pos += 6;
1948 // Velocity
1949 objectupdate.Velocity = new Vector3(
1950 Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
1951 Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
1952 Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
1953 pos += 6;
1954 // Acceleration
1955 objectupdate.Acceleration = new Vector3(
1956 Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
1957 Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
1958 Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
1959 pos += 6;
1960 // Rotation (theta)
1961 objectupdate.Rotation = new Quaternion(
1962 Utils.UInt16ToFloat(block.ObjectData, pos, -1.0f, 1.0f),
1963 Utils.UInt16ToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f),
1964 Utils.UInt16ToFloat(block.ObjectData, pos + 4, -1.0f, 1.0f),
1965 Utils.UInt16ToFloat(block.ObjectData, pos + 6, -1.0f, 1.0f));
1966 pos += 8;
1967 // Angular velocity (omega)
1968 objectupdate.AngularVelocity = new Vector3(
1969 Utils.UInt16ToFloat(block.ObjectData, pos, -256.0f, 256.0f),
1970 Utils.UInt16ToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f),
1971 Utils.UInt16ToFloat(block.ObjectData, pos + 4, -256.0f, 256.0f));
1972 pos += 6;
1973  
1974 break;
1975 case 16:
1976 // The data is an array of single bytes (8-bit numbers)
1977  
1978 // Position
1979 objectupdate.Position = new Vector3(
1980 Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
1981 Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
1982 Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
1983 pos += 3;
1984 // Velocity
1985 objectupdate.Velocity = new Vector3(
1986 Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
1987 Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
1988 Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
1989 pos += 3;
1990 // Accleration
1991 objectupdate.Acceleration = new Vector3(
1992 Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
1993 Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
1994 Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
1995 pos += 3;
1996 // Rotation
1997 objectupdate.Rotation = new Quaternion(
1998 Utils.ByteToFloat(block.ObjectData, pos, -1.0f, 1.0f),
1999 Utils.ByteToFloat(block.ObjectData, pos + 1, -1.0f, 1.0f),
2000 Utils.ByteToFloat(block.ObjectData, pos + 2, -1.0f, 1.0f),
2001 Utils.ByteToFloat(block.ObjectData, pos + 3, -1.0f, 1.0f));
2002 pos += 4;
2003 // Angular Velocity
2004 objectupdate.AngularVelocity = new Vector3(
2005 Utils.ByteToFloat(block.ObjectData, pos, -256.0f, 256.0f),
2006 Utils.ByteToFloat(block.ObjectData, pos + 1, -256.0f, 256.0f),
2007 Utils.ByteToFloat(block.ObjectData, pos + 2, -256.0f, 256.0f));
2008 pos += 3;
2009  
2010 break;
2011 default:
2012 Logger.Log("Got an ObjectUpdate block with ObjectUpdate field length of " +
2013 block.ObjectData.Length, Helpers.LogLevel.Warning, Client);
2014  
2015 continue;
2016 }
2017 #endregion
2018  
2019 // Determine the object type and create the appropriate class
2020 switch (pcode)
2021 {
2022 #region Prim and Foliage
2023 case PCode.Grass:
2024 case PCode.Tree:
2025 case PCode.NewTree:
2026 case PCode.Prim:
2027  
2028 bool isNewObject;
2029 lock (simulator.ObjectsPrimitives.Dictionary)
2030 isNewObject = !simulator.ObjectsPrimitives.ContainsKey(block.ID);
2031  
2032 Primitive prim = GetPrimitive(simulator, block.ID, block.FullID);
2033  
2034 // Textures
2035 objectupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 0,
2036 block.TextureEntry.Length);
2037  
2038 OnObjectDataBlockUpdate(new ObjectDataBlockUpdateEventArgs(simulator, prim, data, block, objectupdate, nameValues));
2039  
2040 #region Update Prim Info with decoded data
2041 prim.Flags = (PrimFlags)block.UpdateFlags;
2042  
2043 if ((prim.Flags & PrimFlags.ZlibCompressed) != 0)
2044 {
2045 Logger.Log("Got a ZlibCompressed ObjectUpdate, implement me!",
2046 Helpers.LogLevel.Warning, Client);
2047 continue;
2048 }
2049  
2050 // Automatically request ObjectProperties for prim if it was rezzed selected.
2051 if ((prim.Flags & PrimFlags.CreateSelected) != 0)
2052 {
2053 SelectObject(simulator, prim.LocalID);
2054 }
2055  
2056 prim.NameValues = nameValues;
2057 prim.LocalID = block.ID;
2058 prim.ID = block.FullID;
2059 prim.ParentID = block.ParentID;
2060 prim.RegionHandle = update.RegionData.RegionHandle;
2061 prim.Scale = block.Scale;
2062 prim.ClickAction = (ClickAction)block.ClickAction;
2063 prim.OwnerID = block.OwnerID;
2064 prim.MediaURL = Utils.BytesToString(block.MediaURL);
2065 prim.Text = Utils.BytesToString(block.Text);
2066 prim.TextColor = new Color4(block.TextColor, 0, false, true);
2067 prim.IsAttachment = attachment;
2068  
2069 // Sound information
2070 prim.Sound = block.Sound;
2071 prim.SoundFlags = (SoundFlags)block.Flags;
2072 prim.SoundGain = block.Gain;
2073 prim.SoundRadius = block.Radius;
2074  
2075 // Joint information
2076 prim.Joint = (JointType)block.JointType;
2077 prim.JointPivot = block.JointPivot;
2078 prim.JointAxisOrAnchor = block.JointAxisOrAnchor;
2079  
2080 // Object parameters
2081 prim.PrimData = data;
2082  
2083 // Textures, texture animations, particle system, and extra params
2084 prim.Textures = objectupdate.Textures;
2085  
2086 prim.TextureAnim = new Primitive.TextureAnimation(block.TextureAnim, 0);
2087 prim.ParticleSys = new Primitive.ParticleSystem(block.PSBlock, 0);
2088 prim.SetExtraParamsFromBytes(block.ExtraParams, 0);
2089  
2090 // PCode-specific data
2091 switch (pcode)
2092 {
2093 case PCode.Grass:
2094 case PCode.Tree:
2095 case PCode.NewTree:
2096 if (block.Data.Length == 1)
2097 prim.TreeSpecies = (Tree)block.Data[0];
2098 else
2099 Logger.Log("Got a foliage update with an invalid TreeSpecies field", Helpers.LogLevel.Warning);
2100 // prim.ScratchPad = Utils.EmptyBytes;
2101 // break;
2102 //default:
2103 // prim.ScratchPad = new byte[block.Data.Length];
2104 // if (block.Data.Length > 0)
2105 // Buffer.BlockCopy(block.Data, 0, prim.ScratchPad, 0, prim.ScratchPad.Length);
2106 break;
2107 }
2108 prim.ScratchPad = Utils.EmptyBytes;
2109  
2110 // Packed parameters
2111 prim.CollisionPlane = objectupdate.CollisionPlane;
2112 prim.Position = objectupdate.Position;
2113 prim.Velocity = objectupdate.Velocity;
2114 prim.Acceleration = objectupdate.Acceleration;
2115 prim.Rotation = objectupdate.Rotation;
2116 prim.AngularVelocity = objectupdate.AngularVelocity;
2117 #endregion
2118  
2119 EventHandler<PrimEventArgs> handler = m_ObjectUpdate;
2120 if (handler != null)
2121 {
2122 WorkPool.QueueUserWorkItem(delegate(object o)
2123 { handler(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNewObject, attachment)); });
2124 }
2125 //OnParticleUpdate handler replacing decode particles, PCode.Particle system appears to be deprecated this is a fix
2126 if (prim.ParticleSys.PartMaxAge != 0) {
2127 OnParticleUpdate(new ParticleUpdateEventArgs(simulator, prim.ParticleSys, prim));
2128 }
2129  
2130 break;
2131 #endregion Prim and Foliage
2132 #region Avatar
2133 case PCode.Avatar:
2134  
2135 bool isNewAvatar;
2136 lock (simulator.ObjectsAvatars.Dictionary)
2137 isNewAvatar = !simulator.ObjectsAvatars.ContainsKey(block.ID);
2138  
2139 // Update some internals if this is our avatar
2140 if (block.FullID == Client.Self.AgentID && simulator == Client.Network.CurrentSim)
2141 {
2142 #region Update Client.Self
2143  
2144 // We need the local ID to recognize terse updates for our agent
2145 Client.Self.localID = block.ID;
2146  
2147 // Packed parameters
2148 Client.Self.collisionPlane = objectupdate.CollisionPlane;
2149 Client.Self.relativePosition = objectupdate.Position;
2150 Client.Self.velocity = objectupdate.Velocity;
2151 Client.Self.acceleration = objectupdate.Acceleration;
2152 Client.Self.relativeRotation = objectupdate.Rotation;
2153 Client.Self.angularVelocity = objectupdate.AngularVelocity;
2154  
2155 #endregion
2156 }
2157  
2158 #region Create an Avatar from the decoded data
2159  
2160 Avatar avatar = GetAvatar(simulator, block.ID, block.FullID);
2161  
2162 objectupdate.Avatar = true;
2163 // Textures
2164 objectupdate.Textures = new Primitive.TextureEntry(block.TextureEntry, 0,
2165 block.TextureEntry.Length);
2166  
2167 OnObjectDataBlockUpdate(new ObjectDataBlockUpdateEventArgs(simulator, avatar, data, block, objectupdate, nameValues));
2168  
2169 uint oldSeatID = avatar.ParentID;
2170  
2171 avatar.ID = block.FullID;
2172 avatar.LocalID = block.ID;
2173 avatar.Scale = block.Scale;
2174 avatar.CollisionPlane = objectupdate.CollisionPlane;
2175 avatar.Position = objectupdate.Position;
2176 avatar.Velocity = objectupdate.Velocity;
2177 avatar.Acceleration = objectupdate.Acceleration;
2178 avatar.Rotation = objectupdate.Rotation;
2179 avatar.AngularVelocity = objectupdate.AngularVelocity;
2180 avatar.NameValues = nameValues;
2181 avatar.PrimData = data;
2182 if (block.Data.Length > 0)
2183 {
2184 Logger.Log("Unexpected Data field for an avatar update, length " + block.Data.Length, Helpers.LogLevel.Warning);
2185 }
2186 avatar.ParentID = block.ParentID;
2187 avatar.RegionHandle = update.RegionData.RegionHandle;
2188  
2189 SetAvatarSittingOn(simulator, avatar, block.ParentID, oldSeatID);
2190  
2191 // Textures
2192 avatar.Textures = objectupdate.Textures;
2193  
2194 #endregion Create an Avatar from the decoded data
2195  
2196 OnAvatarUpdate(new AvatarUpdateEventArgs(simulator, avatar, update.RegionData.TimeDilation, isNewAvatar));
2197  
2198 break;
2199 #endregion Avatar
2200 case PCode.ParticleSystem:
2201 DecodeParticleUpdate(block);
2202 break;
2203 default:
2204 Logger.DebugLog("Got an ObjectUpdate block with an unrecognized PCode " + pcode.ToString(), Client);
2205 break;
2206 }
2207 }
2208 }
2209  
2210 protected void DecodeParticleUpdate(ObjectUpdatePacket.ObjectDataBlock block)
2211 {
2212 // TODO: Handle ParticleSystem ObjectUpdate blocks
2213 // float bounce_b
2214 // Vector4 scale_range
2215 // Vector4 alpha_range
2216 // Vector3 vel_offset
2217 // float dist_begin_fadeout
2218 // float dist_end_fadeout
2219 // UUID image_uuid
2220 // long flags
2221 // byte createme
2222 // Vector3 diff_eq_alpha
2223 // Vector3 diff_eq_scale
2224 // byte max_particles
2225 // byte initial_particles
2226 // float kill_plane_z
2227 // Vector3 kill_plane_normal
2228 // float bounce_plane_z
2229 // Vector3 bounce_plane_normal
2230 // float spawn_range
2231 // float spawn_frequency
2232 // float spawn_frequency_range
2233 // Vector3 spawn_direction
2234 // float spawn_direction_range
2235 // float spawn_velocity
2236 // float spawn_velocity_range
2237 // float speed_limit
2238 // float wind_weight
2239 // Vector3 current_gravity
2240 // float gravity_weight
2241 // float global_lifetime
2242 // float individual_lifetime
2243 // float individual_lifetime_range
2244 // float alpha_decay
2245 // float scale_decay
2246 // float distance_death
2247 // float damp_motion_factor
2248 // Vector3 wind_diffusion_factor
2249 }
2250  
2251 /// <summary>
2252 /// A terse object update, used when a transformation matrix or
2253 /// velocity/acceleration for an object changes but nothing else
2254 /// (scale/position/rotation/acceleration/velocity)
2255 /// </summary>
2256 /// <param name="sender">The sender</param>
2257 /// <param name="e">The EventArgs object containing the packet data</param>
2258 protected void ImprovedTerseObjectUpdateHandler(object sender, PacketReceivedEventArgs e)
2259 {
2260 Packet packet = e.Packet;
2261 Simulator simulator = e.Simulator;
2262  
2263 ImprovedTerseObjectUpdatePacket terse = (ImprovedTerseObjectUpdatePacket)packet;
2264 UpdateDilation(simulator, terse.RegionData.TimeDilation);
2265  
2266 for (int i = 0; i < terse.ObjectData.Length; i++)
2267 {
2268 ImprovedTerseObjectUpdatePacket.ObjectDataBlock block = terse.ObjectData[i];
2269  
2270 try
2271 {
2272 int pos = 4;
2273 uint localid = Utils.BytesToUInt(block.Data, 0);
2274  
2275 // Check if we are interested in this update
2276 if (!Client.Settings.ALWAYS_DECODE_OBJECTS
2277 && localid != Client.Self.localID
2278 && m_TerseObjectUpdate == null)
2279 {
2280 continue;
2281 }
2282  
2283 #region Decode update data
2284  
2285 ObjectMovementUpdate update = new ObjectMovementUpdate();
2286  
2287 // LocalID
2288 update.LocalID = localid;
2289 // State
2290 update.State = block.Data[pos++];
2291 // Avatar boolean
2292 update.Avatar = (block.Data[pos++] != 0);
2293 // Collision normal for avatar
2294 if (update.Avatar)
2295 {
2296 update.CollisionPlane = new Vector4(block.Data, pos);
2297 pos += 16;
2298 }
2299 // Position
2300 update.Position = new Vector3(block.Data, pos);
2301 pos += 12;
2302 // Velocity
2303 update.Velocity = new Vector3(
2304 Utils.UInt16ToFloat(block.Data, pos, -128.0f, 128.0f),
2305 Utils.UInt16ToFloat(block.Data, pos + 2, -128.0f, 128.0f),
2306 Utils.UInt16ToFloat(block.Data, pos + 4, -128.0f, 128.0f));
2307 pos += 6;
2308 // Acceleration
2309 update.Acceleration = new Vector3(
2310 Utils.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f),
2311 Utils.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f),
2312 Utils.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f));
2313 pos += 6;
2314 // Rotation (theta)
2315 update.Rotation = new Quaternion(
2316 Utils.UInt16ToFloat(block.Data, pos, -1.0f, 1.0f),
2317 Utils.UInt16ToFloat(block.Data, pos + 2, -1.0f, 1.0f),
2318 Utils.UInt16ToFloat(block.Data, pos + 4, -1.0f, 1.0f),
2319 Utils.UInt16ToFloat(block.Data, pos + 6, -1.0f, 1.0f));
2320 pos += 8;
2321 // Angular velocity (omega)
2322 update.AngularVelocity = new Vector3(
2323 Utils.UInt16ToFloat(block.Data, pos, -64.0f, 64.0f),
2324 Utils.UInt16ToFloat(block.Data, pos + 2, -64.0f, 64.0f),
2325 Utils.UInt16ToFloat(block.Data, pos + 4, -64.0f, 64.0f));
2326 pos += 6;
2327  
2328 // Textures
2329 // FIXME: Why are we ignoring the first four bytes here?
2330 if (block.TextureEntry.Length != 0)
2331 update.Textures = new Primitive.TextureEntry(block.TextureEntry, 4, block.TextureEntry.Length - 4);
2332  
2333 #endregion Decode update data
2334  
2335 Primitive obj = !Client.Settings.OBJECT_TRACKING ? null : (update.Avatar) ?
2336 (Primitive)GetAvatar(simulator, update.LocalID, UUID.Zero) :
2337 (Primitive)GetPrimitive(simulator, update.LocalID, UUID.Zero);
2338  
2339 // Fire the pre-emptive notice (before we stomp the object)
2340 EventHandler<TerseObjectUpdateEventArgs> handler = m_TerseObjectUpdate;
2341 if (handler != null)
2342 {
2343 WorkPool.QueueUserWorkItem(delegate(object o)
2344 { handler(this, new TerseObjectUpdateEventArgs(simulator, obj, update, terse.RegionData.TimeDilation)); });
2345 }
2346  
2347 #region Update Client.Self
2348 if (update.LocalID == Client.Self.localID)
2349 {
2350 Client.Self.collisionPlane = update.CollisionPlane;
2351 Client.Self.relativePosition = update.Position;
2352 Client.Self.velocity = update.Velocity;
2353 Client.Self.acceleration = update.Acceleration;
2354 Client.Self.relativeRotation = update.Rotation;
2355 Client.Self.angularVelocity = update.AngularVelocity;
2356 }
2357 #endregion Update Client.Self
2358 if (Client.Settings.OBJECT_TRACKING && obj != null)
2359 {
2360 obj.Position = update.Position;
2361 obj.Rotation = update.Rotation;
2362 obj.Velocity = update.Velocity;
2363 obj.CollisionPlane = update.CollisionPlane;
2364 obj.Acceleration = update.Acceleration;
2365 obj.AngularVelocity = update.AngularVelocity;
2366 obj.PrimData.State = update.State;
2367 if (update.Textures != null)
2368 obj.Textures = update.Textures;
2369 }
2370  
2371 }
2372 catch (Exception ex)
2373 {
2374 Logger.Log(ex.Message, Helpers.LogLevel.Warning, Client, ex);
2375 }
2376 }
2377 }
2378  
2379 /// <summary>Process an incoming packet and raise the appropriate events</summary>
2380 /// <param name="sender">The sender</param>
2381 /// <param name="e">The EventArgs object containing the packet data</param>
2382 protected void ObjectUpdateCompressedHandler(object sender, PacketReceivedEventArgs e)
2383 {
2384 Packet packet = e.Packet;
2385 Simulator simulator = e.Simulator;
2386  
2387 ObjectUpdateCompressedPacket update = (ObjectUpdateCompressedPacket)packet;
2388  
2389 for (int b = 0; b < update.ObjectData.Length; b++)
2390 {
2391 ObjectUpdateCompressedPacket.ObjectDataBlock block = update.ObjectData[b];
2392 int i = 0;
2393  
2394 try
2395 {
2396 // UUID
2397 UUID FullID = new UUID(block.Data, 0);
2398 i += 16;
2399 // Local ID
2400 uint LocalID = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
2401 (block.Data[i++] << 16) + (block.Data[i++] << 24));
2402 // PCode
2403 PCode pcode = (PCode)block.Data[i++];
2404  
2405 #region Relevance check
2406  
2407 if (!Client.Settings.ALWAYS_DECODE_OBJECTS)
2408 {
2409 switch (pcode)
2410 {
2411 case PCode.Grass:
2412 case PCode.Tree:
2413 case PCode.NewTree:
2414 case PCode.Prim:
2415 if (m_ObjectUpdate == null) continue;
2416 break;
2417 }
2418 }
2419  
2420 #endregion Relevance check
2421  
2422 bool isNew;
2423 lock (simulator.ObjectsPrimitives.Dictionary)
2424 isNew = !simulator.ObjectsPrimitives.ContainsKey(LocalID);
2425  
2426 Primitive prim = GetPrimitive(simulator, LocalID, FullID);
2427  
2428 prim.LocalID = LocalID;
2429 prim.ID = FullID;
2430 prim.Flags = (PrimFlags)block.UpdateFlags;
2431 prim.PrimData.PCode = pcode;
2432  
2433 #region Decode block and update Prim
2434  
2435 // State
2436 prim.PrimData.State = block.Data[i++];
2437 // CRC
2438 i += 4;
2439 // Material
2440 prim.PrimData.Material = (Material)block.Data[i++];
2441 // Click action
2442 prim.ClickAction = (ClickAction)block.Data[i++];
2443 // Scale
2444 prim.Scale = new Vector3(block.Data, i);
2445 i += 12;
2446 // Position
2447 prim.Position = new Vector3(block.Data, i);
2448 i += 12;
2449 // Rotation
2450 prim.Rotation = new Quaternion(block.Data, i, true);
2451 i += 12;
2452 // Compressed flags
2453 CompressedFlags flags = (CompressedFlags)Utils.BytesToUInt(block.Data, i);
2454 i += 4;
2455  
2456 prim.OwnerID = new UUID(block.Data, i);
2457 i += 16;
2458  
2459 // Angular velocity
2460 if ((flags & CompressedFlags.HasAngularVelocity) != 0)
2461 {
2462 prim.AngularVelocity = new Vector3(block.Data, i);
2463 i += 12;
2464 }
2465  
2466 // Parent ID
2467 if ((flags & CompressedFlags.HasParent) != 0)
2468 {
2469 prim.ParentID = (uint)(block.Data[i++] + (block.Data[i++] << 8) +
2470 (block.Data[i++] << 16) + (block.Data[i++] << 24));
2471 }
2472 else
2473 {
2474 prim.ParentID = 0;
2475 }
2476  
2477 // Tree data
2478 if ((flags & CompressedFlags.Tree) != 0)
2479 {
2480 prim.TreeSpecies = (Tree)block.Data[i++];
2481 //prim.ScratchPad = Utils.EmptyBytes;
2482 }
2483 // Scratch pad
2484 else if ((flags & CompressedFlags.ScratchPad) != 0)
2485 {
2486 prim.TreeSpecies = (Tree)0;
2487  
2488 int size = block.Data[i++];
2489 //prim.ScratchPad = new byte[size];
2490 //Buffer.BlockCopy(block.Data, i, prim.ScratchPad, 0, size);
2491 i += size;
2492 }
2493 prim.ScratchPad = Utils.EmptyBytes;
2494  
2495 // Floating text
2496 if ((flags & CompressedFlags.HasText) != 0)
2497 {
2498 string text = String.Empty;
2499 while (block.Data[i] != 0)
2500 {
2501 text += (char)block.Data[i];
2502 i++;
2503 }
2504 i++;
2505  
2506 // Floating text
2507 prim.Text = text;
2508  
2509 // Text color
2510 prim.TextColor = new Color4(block.Data, i, false);
2511 i += 4;
2512 }
2513 else
2514 {
2515 prim.Text = String.Empty;
2516 }
2517  
2518 // Media URL
2519 if ((flags & CompressedFlags.MediaURL) != 0)
2520 {
2521 string text = String.Empty;
2522 while (block.Data[i] != 0)
2523 {
2524 text += (char)block.Data[i];
2525 i++;
2526 }
2527 i++;
2528  
2529 prim.MediaURL = text;
2530 }
2531  
2532 // Particle system
2533 if ((flags & CompressedFlags.HasParticles) != 0)
2534 {
2535 prim.ParticleSys = new Primitive.ParticleSystem(block.Data, i);
2536 i += 86;
2537 }
2538  
2539 // Extra parameters
2540 i += prim.SetExtraParamsFromBytes(block.Data, i);
2541  
2542 //Sound data
2543 if ((flags & CompressedFlags.HasSound) != 0)
2544 {
2545 prim.Sound = new UUID(block.Data, i);
2546 i += 16;
2547  
2548 prim.SoundGain = Utils.BytesToFloat(block.Data, i);
2549 i += 4;
2550 prim.SoundFlags = (SoundFlags)block.Data[i++];
2551 prim.SoundRadius = Utils.BytesToFloat(block.Data, i);
2552 i += 4;
2553 }
2554  
2555 // Name values
2556 if ((flags & CompressedFlags.HasNameValues) != 0)
2557 {
2558 string text = String.Empty;
2559 while (block.Data[i] != 0)
2560 {
2561 text += (char)block.Data[i];
2562 i++;
2563 }
2564 i++;
2565  
2566 // Parse the name values
2567 if (text.Length > 0)
2568 {
2569 string[] lines = text.Split('\n');
2570 prim.NameValues = new NameValue[lines.Length];
2571  
2572 for (int j = 0; j < lines.Length; j++)
2573 {
2574 if (!String.IsNullOrEmpty(lines[j]))
2575 {
2576 NameValue nv = new NameValue(lines[j]);
2577 prim.NameValues[j] = nv;
2578 }
2579 }
2580 }
2581 }
2582  
2583 prim.PrimData.PathCurve = (PathCurve)block.Data[i++];
2584 ushort pathBegin = Utils.BytesToUInt16(block.Data, i); i += 2;
2585 prim.PrimData.PathBegin = Primitive.UnpackBeginCut(pathBegin);
2586 ushort pathEnd = Utils.BytesToUInt16(block.Data, i); i += 2;
2587 prim.PrimData.PathEnd = Primitive.UnpackEndCut(pathEnd);
2588 prim.PrimData.PathScaleX = Primitive.UnpackPathScale(block.Data[i++]);
2589 prim.PrimData.PathScaleY = Primitive.UnpackPathScale(block.Data[i++]);
2590 prim.PrimData.PathShearX = Primitive.UnpackPathShear((sbyte)block.Data[i++]);
2591 prim.PrimData.PathShearY = Primitive.UnpackPathShear((sbyte)block.Data[i++]);
2592 prim.PrimData.PathTwist = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);
2593 prim.PrimData.PathTwistBegin = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);
2594 prim.PrimData.PathRadiusOffset = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);
2595 prim.PrimData.PathTaperX = Primitive.UnpackPathTaper((sbyte)block.Data[i++]);
2596 prim.PrimData.PathTaperY = Primitive.UnpackPathTaper((sbyte)block.Data[i++]);
2597 prim.PrimData.PathRevolutions = Primitive.UnpackPathRevolutions(block.Data[i++]);
2598 prim.PrimData.PathSkew = Primitive.UnpackPathTwist((sbyte)block.Data[i++]);
2599  
2600 prim.PrimData.profileCurve = block.Data[i++];
2601 ushort profileBegin = Utils.BytesToUInt16(block.Data, i); i += 2;
2602 prim.PrimData.ProfileBegin = Primitive.UnpackBeginCut(profileBegin);
2603 ushort profileEnd = Utils.BytesToUInt16(block.Data, i); i += 2;
2604 prim.PrimData.ProfileEnd = Primitive.UnpackEndCut(profileEnd);
2605 ushort profileHollow = Utils.BytesToUInt16(block.Data, i); i += 2;
2606 prim.PrimData.ProfileHollow = Primitive.UnpackProfileHollow(profileHollow);
2607  
2608 // TextureEntry
2609 int textureEntryLength = (int)Utils.BytesToUInt(block.Data, i);
2610 i += 4;
2611 prim.Textures = new Primitive.TextureEntry(block.Data, i, textureEntryLength);
2612 i += textureEntryLength;
2613  
2614 // Texture animation
2615 if ((flags & CompressedFlags.TextureAnimation) != 0)
2616 {
2617 //int textureAnimLength = (int)Utils.BytesToUIntBig(block.Data, i);
2618 i += 4;
2619 prim.TextureAnim = new Primitive.TextureAnimation(block.Data, i);
2620 }
2621  
2622 #endregion
2623  
2624 prim.IsAttachment = (flags & CompressedFlags.HasNameValues) != 0 && prim.ParentID != 0;
2625  
2626 #region Raise Events
2627  
2628 EventHandler<PrimEventArgs> handler = m_ObjectUpdate;
2629 if (handler != null)
2630 handler(this, new PrimEventArgs(simulator, prim, update.RegionData.TimeDilation, isNew, prim.IsAttachment));
2631  
2632 #endregion
2633 }
2634 catch (IndexOutOfRangeException ex)
2635 {
2636 Logger.Log("Error decoding an ObjectUpdateCompressed packet", Helpers.LogLevel.Warning, Client, ex);
2637 Logger.Log(block, Helpers.LogLevel.Warning);
2638 }
2639 }
2640 }
2641  
2642 /// <summary>Process an incoming packet and raise the appropriate events</summary>
2643 /// <param name="sender">The sender</param>
2644 /// <param name="e">The EventArgs object containing the packet data</param>
2645 protected void ObjectUpdateCachedHandler(object sender, PacketReceivedEventArgs e)
2646 {
2647 if (Client.Settings.ALWAYS_REQUEST_OBJECTS)
2648 {
2649 bool cachedPrimitives = Client.Settings.CACHE_PRIMITIVES;
2650 Packet packet = e.Packet;
2651 Simulator simulator = e.Simulator;
2652  
2653 ObjectUpdateCachedPacket update = (ObjectUpdateCachedPacket)packet;
2654 List<uint> ids = new List<uint>(update.ObjectData.Length);
2655  
2656 // Object caching is implemented when Client.Settings.PRIMITIVES_FACTORY is True, otherwise request updates for all of these objects
2657 for (int i = 0; i < update.ObjectData.Length; i++)
2658 {
2659 uint localID = update.ObjectData[i].ID;
2660  
2661 if (cachedPrimitives)
2662 {
2663 if (!simulator.DataPool.NeedsRequest(localID))
2664 {
2665 continue;
2666 }
2667 }
2668 ids.Add(localID);
2669 }
2670 RequestObjects(simulator, ids);
2671 }
2672 }
2673  
2674 /// <summary>Process an incoming packet and raise the appropriate events</summary>
2675 /// <param name="sender">The sender</param>
2676 /// <param name="e">The EventArgs object containing the packet data</param>
2677 protected void KillObjectHandler(object sender, PacketReceivedEventArgs e)
2678 {
2679 Packet packet = e.Packet;
2680 Simulator simulator = e.Simulator;
2681  
2682 KillObjectPacket kill = (KillObjectPacket)packet;
2683  
2684 // Notify first, so that handler has a chance to get a
2685 // reference from the ObjectTracker to the object being killed
2686 uint[] killed = new uint[kill.ObjectData.Length];
2687 for (int i = 0; i < kill.ObjectData.Length; i++)
2688 {
2689 OnKillObject(new KillObjectEventArgs(simulator, kill.ObjectData[i].ID));
2690 killed[i] = kill.ObjectData[i].ID;
2691 }
2692 OnKillObjects(new KillObjectsEventArgs(e.Simulator, killed));
2693  
2694  
2695 lock (simulator.ObjectsPrimitives.Dictionary)
2696 {
2697 List<uint> removeAvatars = new List<uint>();
2698 List<uint> removePrims = new List<uint>();
2699  
2700 if (Client.Settings.OBJECT_TRACKING)
2701 {
2702 uint localID;
2703 for (int i = 0; i < kill.ObjectData.Length; i++)
2704 {
2705 localID = kill.ObjectData[i].ID;
2706  
2707 if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(localID))
2708 removePrims.Add(localID);
2709  
2710 foreach (KeyValuePair<uint, Primitive> prim in simulator.ObjectsPrimitives.Dictionary)
2711 {
2712 if (prim.Value.ParentID == localID)
2713 {
2714 OnKillObject(new KillObjectEventArgs(simulator, prim.Key));
2715 removePrims.Add(prim.Key);
2716 }
2717 }
2718 }
2719 }
2720  
2721 if (Client.Settings.AVATAR_TRACKING)
2722 {
2723 lock (simulator.ObjectsAvatars.Dictionary)
2724 {
2725 uint localID;
2726 for (int i = 0; i < kill.ObjectData.Length; i++)
2727 {
2728 localID = kill.ObjectData[i].ID;
2729  
2730 if (simulator.ObjectsAvatars.Dictionary.ContainsKey(localID))
2731 removeAvatars.Add(localID);
2732  
2733 List<uint> rootPrims = new List<uint>();
2734  
2735 foreach (KeyValuePair<uint, Primitive> prim in simulator.ObjectsPrimitives.Dictionary)
2736 {
2737 if (prim.Value.ParentID == localID)
2738 {
2739 OnKillObject(new KillObjectEventArgs(simulator, prim.Key));
2740 removePrims.Add(prim.Key);
2741 rootPrims.Add(prim.Key);
2742 }
2743 }
2744  
2745 foreach (KeyValuePair<uint, Primitive> prim in simulator.ObjectsPrimitives.Dictionary)
2746 {
2747 if (rootPrims.Contains(prim.Value.ParentID))
2748 {
2749 OnKillObject(new KillObjectEventArgs(simulator, prim.Key));
2750 removePrims.Add(prim.Key);
2751 }
2752 }
2753 }
2754  
2755 //Do the actual removing outside of the loops but still inside the lock.
2756 //This safely prevents the collection from being modified during a loop.
2757 foreach (uint removeID in removeAvatars)
2758 simulator.ObjectsAvatars.Dictionary.Remove(removeID);
2759 }
2760 }
2761  
2762 if (Client.Settings.CACHE_PRIMITIVES)
2763 {
2764 simulator.DataPool.ReleasePrims(removePrims);
2765 }
2766 foreach (uint removeID in removePrims)
2767 simulator.ObjectsPrimitives.Dictionary.Remove(removeID);
2768 }
2769 }
2770  
2771 /// <summary>Process an incoming packet and raise the appropriate events</summary>
2772 /// <param name="sender">The sender</param>
2773 /// <param name="e">The EventArgs object containing the packet data</param>
2774 protected void ObjectPropertiesHandler(object sender, PacketReceivedEventArgs e)
2775 {
2776 Packet packet = e.Packet;
2777 Simulator simulator = e.Simulator;
2778  
2779 ObjectPropertiesPacket op = (ObjectPropertiesPacket)packet;
2780 ObjectPropertiesPacket.ObjectDataBlock[] datablocks = op.ObjectData;
2781  
2782 for (int i = 0; i < datablocks.Length; ++i)
2783 {
2784 ObjectPropertiesPacket.ObjectDataBlock objectData = datablocks[i];
2785 Primitive.ObjectProperties props = new Primitive.ObjectProperties();
2786  
2787 props.ObjectID = objectData.ObjectID;
2788 props.AggregatePerms = objectData.AggregatePerms;
2789 props.AggregatePermTextures = objectData.AggregatePermTextures;
2790 props.AggregatePermTexturesOwner = objectData.AggregatePermTexturesOwner;
2791 props.Permissions = new Permissions(objectData.BaseMask, objectData.EveryoneMask, objectData.GroupMask,
2792 objectData.NextOwnerMask, objectData.OwnerMask);
2793 props.Category = (ObjectCategory)objectData.Category;
2794 props.CreationDate = Utils.UnixTimeToDateTime((uint)objectData.CreationDate);
2795 props.CreatorID = objectData.CreatorID;
2796 props.Description = Utils.BytesToString(objectData.Description);
2797 props.FolderID = objectData.FolderID;
2798 props.FromTaskID = objectData.FromTaskID;
2799 props.GroupID = objectData.GroupID;
2800 props.InventorySerial = objectData.InventorySerial;
2801 props.ItemID = objectData.ItemID;
2802 props.LastOwnerID = objectData.LastOwnerID;
2803 props.Name = Utils.BytesToString(objectData.Name);
2804 props.OwnerID = objectData.OwnerID;
2805 props.OwnershipCost = objectData.OwnershipCost;
2806 props.SalePrice = objectData.SalePrice;
2807 props.SaleType = (SaleType)objectData.SaleType;
2808 props.SitName = Utils.BytesToString(objectData.SitName);
2809 props.TouchName = Utils.BytesToString(objectData.TouchName);
2810  
2811 int numTextures = objectData.TextureID.Length / 16;
2812 props.TextureIDs = new UUID[numTextures];
2813 for (int j = 0; j < numTextures; ++j)
2814 props.TextureIDs[j] = new UUID(objectData.TextureID, j * 16);
2815  
2816 if (Client.Settings.OBJECT_TRACKING)
2817 {
2818 Primitive findPrim = simulator.ObjectsPrimitives.Find(
2819 delegate(Primitive prim) { return prim.ID == props.ObjectID; });
2820  
2821 if (findPrim != null)
2822 {
2823 OnObjectPropertiesUpdated(new ObjectPropertiesUpdatedEventArgs(simulator, findPrim, props));
2824  
2825 lock (simulator.ObjectsPrimitives.Dictionary)
2826 {
2827 if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(findPrim.LocalID))
2828 simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties = props;
2829 }
2830 }
2831 }
2832  
2833 OnObjectProperties(new ObjectPropertiesEventArgs(simulator, props));
2834 }
2835 }
2836  
2837 /// <summary>Process an incoming packet and raise the appropriate events</summary>
2838 /// <param name="sender">The sender</param>
2839 /// <param name="e">The EventArgs object containing the packet data</param>
2840 protected void ObjectPropertiesFamilyHandler(object sender, PacketReceivedEventArgs e)
2841 {
2842 Packet packet = e.Packet;
2843 Simulator simulator = e.Simulator;
2844  
2845 ObjectPropertiesFamilyPacket op = (ObjectPropertiesFamilyPacket)packet;
2846 Primitive.ObjectProperties props = new Primitive.ObjectProperties();
2847  
2848 ReportType requestType = (ReportType)op.ObjectData.RequestFlags;
2849  
2850 props.ObjectID = op.ObjectData.ObjectID;
2851 props.Category = (ObjectCategory)op.ObjectData.Category;
2852 props.Description = Utils.BytesToString(op.ObjectData.Description);
2853 props.GroupID = op.ObjectData.GroupID;
2854 props.LastOwnerID = op.ObjectData.LastOwnerID;
2855 props.Name = Utils.BytesToString(op.ObjectData.Name);
2856 props.OwnerID = op.ObjectData.OwnerID;
2857 props.OwnershipCost = op.ObjectData.OwnershipCost;
2858 props.SalePrice = op.ObjectData.SalePrice;
2859 props.SaleType = (SaleType)op.ObjectData.SaleType;
2860 props.Permissions.BaseMask = (PermissionMask)op.ObjectData.BaseMask;
2861 props.Permissions.EveryoneMask = (PermissionMask)op.ObjectData.EveryoneMask;
2862 props.Permissions.GroupMask = (PermissionMask)op.ObjectData.GroupMask;
2863 props.Permissions.NextOwnerMask = (PermissionMask)op.ObjectData.NextOwnerMask;
2864 props.Permissions.OwnerMask = (PermissionMask)op.ObjectData.OwnerMask;
2865  
2866 if (Client.Settings.OBJECT_TRACKING)
2867 {
2868 Primitive findPrim = simulator.ObjectsPrimitives.Find(
2869 delegate(Primitive prim) { return prim.ID == op.ObjectData.ObjectID; });
2870  
2871 if (findPrim != null)
2872 {
2873 lock (simulator.ObjectsPrimitives.Dictionary)
2874 {
2875 if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(findPrim.LocalID))
2876 {
2877 if (simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties == null)
2878 simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties = new Primitive.ObjectProperties();
2879 simulator.ObjectsPrimitives.Dictionary[findPrim.LocalID].Properties.SetFamilyProperties(props);
2880 }
2881 }
2882 }
2883 }
2884  
2885 OnObjectPropertiesFamily(new ObjectPropertiesFamilyEventArgs(simulator, props, requestType));
2886 }
2887  
2888 /// <summary>Process an incoming packet and raise the appropriate events</summary>
2889 /// <param name="sender">The sender</param>
2890 /// <param name="e">The EventArgs object containing the packet data</param>
2891 protected void PayPriceReplyHandler(object sender, PacketReceivedEventArgs e)
2892 {
2893 if (m_PayPriceReply != null)
2894 {
2895 Packet packet = e.Packet;
2896 Simulator simulator = e.Simulator;
2897  
2898 PayPriceReplyPacket p = (PayPriceReplyPacket)packet;
2899 UUID objectID = p.ObjectData.ObjectID;
2900 int defaultPrice = p.ObjectData.DefaultPayPrice;
2901 int[] buttonPrices = new int[p.ButtonData.Length];
2902  
2903 for (int i = 0; i < p.ButtonData.Length; i++)
2904 {
2905 buttonPrices[i] = p.ButtonData[i].PayButton;
2906 }
2907  
2908 OnPayPriceReply(new PayPriceReplyEventArgs(simulator, objectID, defaultPrice, buttonPrices));
2909 }
2910 }
2911  
2912 /// <summary>
2913 ///
2914 /// </summary>
2915 /// <param name="capsKey"></param>
2916 /// <param name="message"></param>
2917 /// <param name="simulator"></param>
2918 protected void ObjectPhysicsPropertiesHandler(string capsKey, IMessage message, Simulator simulator)
2919 {
2920 ObjectPhysicsPropertiesMessage msg = (ObjectPhysicsPropertiesMessage)message;
2921  
2922 if (Client.Settings.OBJECT_TRACKING)
2923 {
2924 for (int i = 0; i < msg.ObjectPhysicsProperties.Length; i++)
2925 {
2926 lock (simulator.ObjectsPrimitives.Dictionary)
2927 {
2928 if (simulator.ObjectsPrimitives.Dictionary.ContainsKey(msg.ObjectPhysicsProperties[i].LocalID))
2929 {
2930 simulator.ObjectsPrimitives.Dictionary[msg.ObjectPhysicsProperties[i].LocalID].PhysicsProps = msg.ObjectPhysicsProperties[i];
2931 }
2932 }
2933 }
2934 }
2935  
2936 if (m_PhysicsProperties != null)
2937 {
2938 for (int i = 0; i < msg.ObjectPhysicsProperties.Length; i++)
2939 {
2940 OnPhysicsProperties(new PhysicsPropertiesEventArgs(simulator, msg.ObjectPhysicsProperties[i]));
2941 }
2942 }
2943 }
2944  
2945 #endregion Packet Handlers
2946  
2947 #region Utility Functions
2948  
2949 /// <summary>
2950 /// Setup construction data for a basic primitive shape
2951 /// </summary>
2952 /// <param name="type">Primitive shape to construct</param>
2953 /// <returns>Construction data that can be plugged into a <seealso cref="Primitive"/></returns>
2954 public static Primitive.ConstructionData BuildBasicShape(PrimType type)
2955 {
2956 Primitive.ConstructionData prim = new Primitive.ConstructionData();
2957 prim.PCode = PCode.Prim;
2958 prim.Material = Material.Wood;
2959  
2960 switch (type)
2961 {
2962 case PrimType.Box:
2963 prim.ProfileCurve = ProfileCurve.Square;
2964 prim.PathCurve = PathCurve.Line;
2965 prim.ProfileEnd = 1f;
2966 prim.PathEnd = 1f;
2967 prim.PathScaleX = 1f;
2968 prim.PathScaleY = 1f;
2969 prim.PathRevolutions = 1f;
2970 break;
2971 case PrimType.Cylinder:
2972 prim.ProfileCurve = ProfileCurve.Circle;
2973 prim.PathCurve = PathCurve.Line;
2974 prim.ProfileEnd = 1f;
2975 prim.PathEnd = 1f;
2976 prim.PathScaleX = 1f;
2977 prim.PathScaleY = 1f;
2978 prim.PathRevolutions = 1f;
2979 break;
2980 case PrimType.Prism:
2981 prim.ProfileCurve = ProfileCurve.EqualTriangle;
2982 prim.PathCurve = PathCurve.Line;
2983 prim.ProfileEnd = 1f;
2984 prim.PathEnd = 1f;
2985 prim.PathScaleX = 0f;
2986 prim.PathScaleY = 0f;
2987 prim.PathRevolutions = 1f;
2988 break;
2989 case PrimType.Ring:
2990 prim.ProfileCurve = ProfileCurve.EqualTriangle;
2991 prim.PathCurve = PathCurve.Circle;
2992 prim.ProfileEnd = 1f;
2993 prim.PathEnd = 1f;
2994 prim.PathScaleX = 1f;
2995 prim.PathScaleY = 0.25f;
2996 prim.PathRevolutions = 1f;
2997 break;
2998 case PrimType.Sphere:
2999 prim.ProfileCurve = ProfileCurve.HalfCircle;
3000 prim.PathCurve = PathCurve.Circle;
3001 prim.ProfileEnd = 1f;
3002 prim.PathEnd = 1f;
3003 prim.PathScaleX = 1f;
3004 prim.PathScaleY = 1f;
3005 prim.PathRevolutions = 1f;
3006 break;
3007 case PrimType.Torus:
3008 prim.ProfileCurve = ProfileCurve.Circle;
3009 prim.PathCurve = PathCurve.Circle;
3010 prim.ProfileEnd = 1f;
3011 prim.PathEnd = 1f;
3012 prim.PathScaleX = 1f;
3013 prim.PathScaleY = 0.25f;
3014 prim.PathRevolutions = 1f;
3015 break;
3016 case PrimType.Tube:
3017 prim.ProfileCurve = ProfileCurve.Square;
3018 prim.PathCurve = PathCurve.Circle;
3019 prim.ProfileEnd = 1f;
3020 prim.PathEnd = 1f;
3021 prim.PathScaleX = 1f;
3022 prim.PathScaleY = 0.25f;
3023 prim.PathRevolutions = 1f;
3024 break;
3025 case PrimType.Sculpt:
3026 prim.ProfileCurve = ProfileCurve.Circle;
3027 prim.PathCurve = PathCurve.Circle;
3028 prim.ProfileEnd = 1f;
3029 prim.PathEnd = 1f;
3030 prim.PathScaleX = 1f;
3031 prim.PathScaleY = 0.5f;
3032 prim.PathRevolutions = 1f;
3033 break;
3034 default:
3035 throw new NotSupportedException("Unsupported shape: " + type.ToString());
3036 }
3037  
3038 return prim;
3039 }
3040  
3041 /// <summary>
3042 ///
3043 /// </summary>
3044 /// <param name="sim"></param>
3045 /// <param name="av"></param>
3046 /// <param name="localid"></param>
3047 /// <param name="oldSeatID"></param>
3048 protected void SetAvatarSittingOn(Simulator sim, Avatar av, uint localid, uint oldSeatID)
3049 {
3050 if (Client.Network.CurrentSim == sim && av.LocalID == Client.Self.localID)
3051 {
3052 Client.Self.sittingOn = localid;
3053 }
3054  
3055 av.ParentID = localid;
3056  
3057  
3058 if (m_AvatarSitChanged != null && oldSeatID != localid)
3059 {
3060 OnAvatarSitChanged(new AvatarSitChangedEventArgs(sim, av, localid, oldSeatID));
3061 }
3062 }
3063  
3064 /// <summary>
3065 ///
3066 /// </summary>
3067 /// <param name="s"></param>
3068 /// <param name="dilation"></param>
3069 protected void UpdateDilation(Simulator s, uint dilation)
3070 {
3071 s.Stats.Dilation = (float)dilation / 65535.0f;
3072 }
3073  
3074  
3075 /// <summary>
3076 /// Set the Shape data of an object
3077 /// </summary>
3078 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
3079 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
3080 /// <param name="prim">Data describing the prim shape</param>
3081 public void SetShape(Simulator simulator, uint localID, Primitive.ConstructionData prim)
3082 {
3083 ObjectShapePacket shape = new ObjectShapePacket();
3084  
3085 shape.AgentData.AgentID = Client.Self.AgentID;
3086 shape.AgentData.SessionID = Client.Self.SessionID;
3087  
3088 shape.ObjectData = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock[1];
3089 shape.ObjectData[0] = new OpenMetaverse.Packets.ObjectShapePacket.ObjectDataBlock();
3090  
3091 shape.ObjectData[0].ObjectLocalID = localID;
3092  
3093 shape.ObjectData[0].PathCurve = (byte)prim.PathCurve;
3094 shape.ObjectData[0].PathBegin = Primitive.PackBeginCut(prim.PathBegin);
3095 shape.ObjectData[0].PathEnd = Primitive.PackEndCut(prim.PathEnd);
3096 shape.ObjectData[0].PathScaleX = Primitive.PackPathScale(prim.PathScaleX);
3097 shape.ObjectData[0].PathScaleY = Primitive.PackPathScale(prim.PathScaleY);
3098 shape.ObjectData[0].PathShearX = (byte)Primitive.PackPathShear(prim.PathShearX);
3099 shape.ObjectData[0].PathShearY = (byte)Primitive.PackPathShear(prim.PathShearY);
3100 shape.ObjectData[0].PathTwist = Primitive.PackPathTwist(prim.PathTwist);
3101 shape.ObjectData[0].PathTwistBegin = Primitive.PackPathTwist(prim.PathTwistBegin);
3102 shape.ObjectData[0].PathRadiusOffset = Primitive.PackPathTwist(prim.PathRadiusOffset);
3103 shape.ObjectData[0].PathTaperX = Primitive.PackPathTaper(prim.PathTaperX);
3104 shape.ObjectData[0].PathTaperY = Primitive.PackPathTaper(prim.PathTaperY);
3105 shape.ObjectData[0].PathRevolutions = Primitive.PackPathRevolutions(prim.PathRevolutions);
3106 shape.ObjectData[0].PathSkew = Primitive.PackPathTwist(prim.PathSkew);
3107  
3108 shape.ObjectData[0].ProfileCurve = prim.profileCurve;
3109 shape.ObjectData[0].ProfileBegin = Primitive.PackBeginCut(prim.ProfileBegin);
3110 shape.ObjectData[0].ProfileEnd = Primitive.PackEndCut(prim.ProfileEnd);
3111 shape.ObjectData[0].ProfileHollow = Primitive.PackProfileHollow(prim.ProfileHollow);
3112  
3113 Client.Network.SendPacket(shape, simulator);
3114 }
3115  
3116 /// <summary>
3117 /// Set the Material data of an object
3118 /// </summary>
3119 /// <param name="simulator">A reference to the <seealso cref="OpenMetaverse.Simulator"/> object where the object resides</param>
3120 /// <param name="localID">The objects ID which is local to the simulator the object is in</param>
3121 /// <param name="material">The new material of the object</param>
3122 public void SetMaterial(Simulator simulator, uint localID, Material material)
3123 {
3124 ObjectMaterialPacket matPacket = new ObjectMaterialPacket();
3125  
3126 matPacket.AgentData.AgentID = Client.Self.AgentID;
3127 matPacket.AgentData.SessionID = Client.Self.SessionID;
3128  
3129 matPacket.ObjectData = new ObjectMaterialPacket.ObjectDataBlock[1];
3130 matPacket.ObjectData[0] = new ObjectMaterialPacket.ObjectDataBlock();
3131  
3132 matPacket.ObjectData[0].ObjectLocalID = localID;
3133 matPacket.ObjectData[0].Material = (byte)material;
3134  
3135 Client.Network.SendPacket(matPacket, simulator);
3136 }
3137  
3138  
3139 #endregion Utility Functions
3140  
3141 #region Object Tracking Link
3142  
3143 /// <summary>
3144 ///
3145 /// </summary>
3146 /// <param name="simulator"></param>
3147 /// <param name="localID"></param>
3148 /// <param name="fullID"></param>
3149 /// <returns></returns>
3150 protected Primitive GetPrimitive(Simulator simulator, uint localID, UUID fullID)
3151 {
3152 return GetPrimitive(simulator, localID, fullID, true);
3153 }
3154 /// <summary>
3155 ///
3156 /// </summary>
3157 /// <param name="simulator"></param>
3158 /// <param name="localID"></param>
3159 /// <param name="fullID"></param>
3160 /// <param name="createIfMissing"></param>
3161 /// <returns></returns>
3162 public Primitive GetPrimitive(Simulator simulator, uint localID, UUID fullID, bool createIfMissing)
3163 {
3164 if (Client.Settings.OBJECT_TRACKING)
3165 {
3166 lock (simulator.ObjectsPrimitives.Dictionary)
3167 {
3168  
3169 Primitive prim;
3170  
3171 if (simulator.ObjectsPrimitives.Dictionary.TryGetValue(localID, out prim))
3172 {
3173 return prim;
3174 }
3175 else
3176 {
3177 if (!createIfMissing) return null;
3178 if (Client.Settings.CACHE_PRIMITIVES)
3179 {
3180 prim = simulator.DataPool.MakePrimitive(localID);
3181 }
3182 else
3183 {
3184 prim = new Primitive();
3185 prim.LocalID = localID;
3186 prim.RegionHandle = simulator.Handle;
3187 }
3188 prim.ActiveClients++;
3189 prim.ID = fullID;
3190  
3191 simulator.ObjectsPrimitives.Dictionary[localID] = prim;
3192  
3193 return prim;
3194 }
3195 }
3196 }
3197 else
3198 {
3199 return new Primitive();
3200 }
3201 }
3202  
3203 /// <summary>
3204 ///
3205 /// </summary>
3206 /// <param name="simulator"></param>
3207 /// <param name="localID"></param>
3208 /// <param name="fullID"></param>
3209 /// <returns></returns>
3210 protected Avatar GetAvatar(Simulator simulator, uint localID, UUID fullID)
3211 {
3212 if (Client.Settings.AVATAR_TRACKING)
3213 {
3214 lock (simulator.ObjectsAvatars.Dictionary)
3215 {
3216  
3217 Avatar avatar;
3218  
3219 if (simulator.ObjectsAvatars.Dictionary.TryGetValue(localID, out avatar))
3220 {
3221 return avatar;
3222 }
3223 else
3224 {
3225 avatar = new Avatar();
3226 avatar.LocalID = localID;
3227 avatar.ID = fullID;
3228 avatar.RegionHandle = simulator.Handle;
3229  
3230 simulator.ObjectsAvatars.Dictionary[localID] = avatar;
3231  
3232 return avatar;
3233 }
3234 }
3235 }
3236 else
3237 {
3238 return new Avatar();
3239 }
3240 }
3241  
3242 #endregion Object Tracking Link
3243  
3244 protected void InterpolationTimer_Elapsed(object obj)
3245 {
3246 int elapsed = 0;
3247  
3248 if (Client.Network.Connected)
3249 {
3250 int start = Environment.TickCount;
3251  
3252 int interval = Environment.TickCount - Client.Self.lastInterpolation;
3253 float seconds = (float)interval / 1000f;
3254  
3255 // Iterate through all of the simulators
3256 Simulator[] sims = Client.Network.Simulators.ToArray();
3257 for (int i = 0; i < sims.Length; i++)
3258 {
3259 Simulator sim = sims[i];
3260  
3261 float adjSeconds = seconds * sim.Stats.Dilation;
3262  
3263 // Iterate through all of this sims avatars
3264 sim.ObjectsAvatars.ForEach(
3265 delegate(Avatar avatar)
3266 {
3267 #region Linear Motion
3268 // Only do movement interpolation (extrapolation) when there is a non-zero velocity but
3269 // no acceleration
3270 if (avatar.Acceleration != Vector3.Zero && avatar.Velocity == Vector3.Zero)
3271 {
3272 avatar.Position += (avatar.Velocity + avatar.Acceleration *
3273 (0.5f * (adjSeconds - HAVOK_TIMESTEP))) * adjSeconds;
3274 avatar.Velocity += avatar.Acceleration * adjSeconds;
3275 }
3276 #endregion Linear Motion
3277 }
3278 );
3279  
3280 // Iterate through all of this sims primitives
3281 sim.ObjectsPrimitives.ForEach(
3282 delegate(Primitive prim)
3283 {
3284 if (prim.Joint == JointType.Invalid)
3285 {
3286 #region Angular Velocity
3287 Vector3 angVel = prim.AngularVelocity;
3288 float omega = angVel.LengthSquared();
3289  
3290 if (omega > 0.00001f)
3291 {
3292 omega = (float)Math.Sqrt(omega);
3293 float angle = omega * adjSeconds;
3294 angVel *= 1.0f / omega;
3295 Quaternion dQ = Quaternion.CreateFromAxisAngle(angVel, angle);
3296  
3297 prim.Rotation *= dQ;
3298 }
3299 #endregion Angular Velocity
3300  
3301 #region Linear Motion
3302 // Only do movement interpolation (extrapolation) when there is a non-zero velocity but
3303 // no acceleration
3304 if (prim.Acceleration != Vector3.Zero && prim.Velocity == Vector3.Zero)
3305 {
3306 prim.Position += (prim.Velocity + prim.Acceleration *
3307 (0.5f * (adjSeconds - HAVOK_TIMESTEP))) * adjSeconds;
3308 prim.Velocity += prim.Acceleration * adjSeconds;
3309 }
3310 #endregion Linear Motion
3311 }
3312 else if (prim.Joint == JointType.Hinge)
3313 {
3314 //FIXME: Hinge movement extrapolation
3315 }
3316 else if (prim.Joint == JointType.Point)
3317 {
3318 //FIXME: Point movement extrapolation
3319 }
3320 else
3321 {
3322 Logger.Log("Unhandled joint type " + prim.Joint, Helpers.LogLevel.Warning, Client);
3323 }
3324 }
3325 );
3326 }
3327  
3328 // Make sure the last interpolated time is always updated
3329 Client.Self.lastInterpolation = Environment.TickCount;
3330  
3331 elapsed = Client.Self.lastInterpolation - start;
3332 }
3333  
3334 // Start the timer again. Use a minimum of a 50ms pause in between calculations
3335 int delay = Math.Max(50, Settings.INTERPOLATION_INTERVAL - elapsed);
3336 if (InterpolationTimer != null)
3337 {
3338 InterpolationTimer.Change(delay, Timeout.Infinite);
3339 }
3340  
3341 }
3342 }
3343 #region EventArgs classes
3344  
3345 /// <summary>Provides data for the <see cref="ObjectManager.ObjectUpdate"/> event</summary>
3346 /// <remarks><para>The <see cref="ObjectManager.ObjectUpdate"/> event occurs when the simulator sends
3347 /// an <see cref="ObjectUpdatePacket"/> containing a Primitive, Foliage or Attachment data</para>
3348 /// <para>Note 1: The <see cref="ObjectManager.ObjectUpdate"/> event will not be raised when the object is an Avatar</para>
3349 /// <para>Note 2: It is possible for the <see cref="ObjectManager.ObjectUpdate"/> to be
3350 /// raised twice for the same object if for example the primitive moved to a new simulator, then returned to the current simulator or
3351 /// if an Avatar crosses the border into a new simulator and returns to the current simulator</para>
3352 /// </remarks>
3353 /// <example>
3354 /// The following code example uses the <see cref="PrimEventArgs.Prim"/>, <see cref="PrimEventArgs.Simulator"/>, and <see cref="PrimEventArgs.IsAttachment"/>
3355 /// properties to display new Primitives and Attachments on the <see cref="Console"/> window.
3356 /// <code>
3357 /// // Subscribe to the event that gives us prim and foliage information
3358 /// Client.Objects.ObjectUpdate += Objects_ObjectUpdate;
3359 ///
3360 ///
3361 /// private void Objects_ObjectUpdate(object sender, PrimEventArgs e)
3362 /// {
3363 /// Console.WriteLine("Primitive {0} {1} in {2} is an attachment {3}", e.Prim.ID, e.Prim.LocalID, e.Simulator.Name, e.IsAttachment);
3364 /// }
3365 /// </code>
3366 /// </example>
3367 /// <seealso cref="ObjectManager.ObjectUpdate"/>
3368 /// <seealso cref="ObjectManager.AvatarUpdate"/>
3369 /// <seealso cref="AvatarUpdateEventArgs"/>
3370 public class PrimEventArgs : EventArgs
3371 {
3372 private readonly Simulator m_Simulator;
3373 private readonly bool m_IsNew;
3374 private readonly bool m_IsAttachment;
3375 private readonly Primitive m_Prim;
3376 private readonly ushort m_TimeDilation;
3377  
3378 /// <summary>Get the simulator the <see cref="Primitive"/> originated from</summary>
3379 public Simulator Simulator { get { return m_Simulator; } }
3380 /// <summary>Get the <see cref="Primitive"/> details</summary>
3381 public Primitive Prim { get { return m_Prim; } }
3382 /// <summary>true if the <see cref="Primitive"/> did not exist in the dictionary before this update (always true if object tracking has been disabled)</summary>
3383 public bool IsNew { get { return m_IsNew; } }
3384 /// <summary>true if the <see cref="Primitive"/> is attached to an <see cref="Avatar"/></summary>
3385 public bool IsAttachment { get { return m_IsAttachment; } }
3386 /// <summary>Get the simulator Time Dilation</summary>
3387 public ushort TimeDilation { get { return m_TimeDilation; } }
3388  
3389 /// <summary>
3390 /// Construct a new instance of the PrimEventArgs class
3391 /// </summary>
3392 /// <param name="simulator">The simulator the object originated from</param>
3393 /// <param name="prim">The Primitive</param>
3394 /// <param name="timeDilation">The simulator time dilation</param>
3395 /// <param name="isNew">The prim was not in the dictionary before this update</param>
3396 /// <param name="isAttachment">true if the primitive represents an attachment to an agent</param>
3397 public PrimEventArgs(Simulator simulator, Primitive prim, ushort timeDilation, bool isNew, bool isAttachment)
3398 {
3399 this.m_Simulator = simulator;
3400 this.m_IsNew = isNew;
3401 this.m_IsAttachment = isAttachment;
3402 this.m_Prim = prim;
3403 this.m_TimeDilation = timeDilation;
3404 }
3405 }
3406  
3407 /// <summary>Provides data for the <see cref="ObjectManager.AvatarUpdate"/> event</summary>
3408 /// <remarks><para>The <see cref="ObjectManager.AvatarUpdate"/> event occurs when the simulator sends
3409 /// an <see cref="ObjectUpdatePacket"/> containing Avatar data</para>
3410 /// <para>Note 1: The <see cref="ObjectManager.AvatarUpdate"/> event will not be raised when the object is an Avatar</para>
3411 /// <para>Note 2: It is possible for the <see cref="ObjectManager.AvatarUpdate"/> to be
3412 /// raised twice for the same avatar if for example the avatar moved to a new simulator, then returned to the current simulator</para>
3413 /// </remarks>
3414 /// <example>
3415 /// The following code example uses the <see cref="AvatarUpdateEventArgs.Avatar"/> property to make a request for the top picks
3416 /// using the <see cref="AvatarManager.RequestAvatarPicks"/> method in the <see cref="AvatarManager"/> class to display the names
3417 /// of our own agents picks listings on the <see cref="Console"/> window.
3418 /// <code>
3419 /// // subscribe to the AvatarUpdate event to get our information
3420 /// Client.Objects.AvatarUpdate += Objects_AvatarUpdate;
3421 /// Client.Avatars.AvatarPicksReply += Avatars_AvatarPicksReply;
3422 ///
3423 /// private void Objects_AvatarUpdate(object sender, AvatarUpdateEventArgs e)
3424 /// {
3425 /// // we only want our own data
3426 /// if (e.Avatar.LocalID == Client.Self.LocalID)
3427 /// {
3428 /// // Unsubscribe from the avatar update event to prevent a loop
3429 /// // where we continually request the picks every time we get an update for ourselves
3430 /// Client.Objects.AvatarUpdate -= Objects_AvatarUpdate;
3431 /// // make the top picks request through AvatarManager
3432 /// Client.Avatars.RequestAvatarPicks(e.Avatar.ID);
3433 /// }
3434 /// }
3435 ///
3436 /// private void Avatars_AvatarPicksReply(object sender, AvatarPicksReplyEventArgs e)
3437 /// {
3438 /// // we'll unsubscribe from the AvatarPicksReply event since we now have the data
3439 /// // we were looking for
3440 /// Client.Avatars.AvatarPicksReply -= Avatars_AvatarPicksReply;
3441 /// // loop through the dictionary and extract the names of the top picks from our profile
3442 /// foreach (var pickName in e.Picks.Values)
3443 /// {
3444 /// Console.WriteLine(pickName);
3445 /// }
3446 /// }
3447 /// </code>
3448 /// </example>
3449 /// <seealso cref="ObjectManager.ObjectUpdate"/>
3450 /// <seealso cref="PrimEventArgs"/>
3451 public class AvatarUpdateEventArgs : EventArgs
3452 {
3453 private readonly Simulator m_Simulator;
3454 private readonly Avatar m_Avatar;
3455 private readonly ushort m_TimeDilation;
3456 private readonly bool m_IsNew;
3457  
3458 /// <summary>Get the simulator the object originated from</summary>
3459 public Simulator Simulator { get { return m_Simulator; } }
3460 /// <summary>Get the <see cref="Avatar"/> data</summary>
3461 public Avatar Avatar { get { return m_Avatar; } }
3462 /// <summary>Get the simulator time dilation</summary>
3463 public ushort TimeDilation { get { return m_TimeDilation; } }
3464 /// <summary>true if the <see cref="Avatar"/> did not exist in the dictionary before this update (always true if avatar tracking has been disabled)</summary>
3465 public bool IsNew { get { return m_IsNew; } }
3466  
3467 /// <summary>
3468 /// Construct a new instance of the AvatarUpdateEventArgs class
3469 /// </summary>
3470 /// <param name="simulator">The simulator the packet originated from</param>
3471 /// <param name="avatar">The <see cref="Avatar"/> data</param>
3472 /// <param name="timeDilation">The simulator time dilation</param>
3473 /// <param name="isNew">The avatar was not in the dictionary before this update</param>
3474 public AvatarUpdateEventArgs(Simulator simulator, Avatar avatar, ushort timeDilation, bool isNew)
3475 {
3476 this.m_Simulator = simulator;
3477 this.m_Avatar = avatar;
3478 this.m_TimeDilation = timeDilation;
3479 this.m_IsNew = isNew;
3480 }
3481 }
3482  
3483 public class ParticleUpdateEventArgs : EventArgs {
3484 private readonly Simulator m_Simulator;
3485 private readonly Primitive.ParticleSystem m_ParticleSystem;
3486 private readonly Primitive m_Source;
3487  
3488 /// <summary>Get the simulator the object originated from</summary>
3489 public Simulator Simulator { get { return m_Simulator; } }
3490 /// <summary>Get the <see cref="ParticleSystem"/> data</summary>
3491 public Primitive.ParticleSystem ParticleSystem { get { return m_ParticleSystem; } }
3492 /// <summary>Get <see cref="Primitive"/> source</summary>
3493 public Primitive Source { get { return m_Source; } }
3494  
3495 /// <summary>
3496 /// Construct a new instance of the ParticleUpdateEventArgs class
3497 /// </summary>
3498 /// <param name="simulator">The simulator the packet originated from</param>
3499 /// <param name="particlesystem">The ParticleSystem data</param>
3500 /// <param name="source">The Primitive source</param>
3501 public ParticleUpdateEventArgs(Simulator simulator, Primitive.ParticleSystem particlesystem, Primitive source) {
3502 this.m_Simulator = simulator;
3503 this.m_ParticleSystem = particlesystem;
3504 this.m_Source = source;
3505 }
3506 }
3507  
3508 /// <summary>Provides additional primitive data for the <see cref="ObjectManager.ObjectProperties"/> event</summary>
3509 /// <remarks><para>The <see cref="ObjectManager.ObjectProperties"/> event occurs when the simulator sends
3510 /// an <see cref="ObjectPropertiesPacket"/> containing additional details for a Primitive, Foliage data or Attachment data</para>
3511 /// <para>The <see cref="ObjectManager.ObjectProperties"/> event is also raised when a <see cref="ObjectManager.SelectObject"/> request is
3512 /// made.</para>
3513 /// </remarks>
3514 /// <example>
3515 /// The following code example uses the <see cref="PrimEventArgs.Prim"/>, <see cref="PrimEventArgs.Simulator"/> and
3516 /// <see cref="ObjectPropertiesEventArgs.Properties"/>
3517 /// properties to display new attachments and send a request for additional properties containing the name of the
3518 /// attachment then display it on the <see cref="Console"/> window.
3519 /// <code>
3520 /// // Subscribe to the event that provides additional primitive details
3521 /// Client.Objects.ObjectProperties += Objects_ObjectProperties;
3522 ///
3523 /// // handle the properties data that arrives
3524 /// private void Objects_ObjectProperties(object sender, ObjectPropertiesEventArgs e)
3525 /// {
3526 /// Console.WriteLine("Primitive Properties: {0} Name is {1}", e.Properties.ObjectID, e.Properties.Name);
3527 /// }
3528 /// </code>
3529 /// </example>
3530 public class ObjectPropertiesEventArgs : EventArgs
3531 {
3532 protected readonly Simulator m_Simulator;
3533 protected readonly Primitive.ObjectProperties m_Properties;
3534  
3535 /// <summary>Get the simulator the object is located</summary>
3536 public Simulator Simulator { get { return m_Simulator; } }
3537 /// <summary>Get the primitive properties</summary>
3538 public Primitive.ObjectProperties Properties { get { return m_Properties; } }
3539  
3540 /// <summary>
3541 /// Construct a new instance of the ObjectPropertiesEventArgs class
3542 /// </summary>
3543 /// <param name="simulator">The simulator the object is located</param>
3544 /// <param name="props">The primitive Properties</param>
3545 public ObjectPropertiesEventArgs(Simulator simulator, Primitive.ObjectProperties props)
3546 {
3547 this.m_Simulator = simulator;
3548 this.m_Properties = props;
3549 }
3550 }
3551  
3552 /// <summary>Provides additional primitive data for the <see cref="ObjectManager.ObjectPropertiesUpdated"/> event</summary>
3553 /// <remarks><para>The <see cref="ObjectManager.ObjectPropertiesUpdated"/> event occurs when the simulator sends
3554 /// an <see cref="ObjectPropertiesPacket"/> containing additional details for a Primitive or Foliage data that is currently
3555 /// being tracked in the <see cref="Simulator.ObjectsPrimitives"/> dictionary</para>
3556 /// <para>The <see cref="ObjectManager.ObjectPropertiesUpdated"/> event is also raised when a <see cref="ObjectManager.SelectObject"/> request is
3557 /// made and <see cref="Settings.OBJECT_TRACKING"/> is enabled</para>
3558 /// </remarks>
3559 public class ObjectPropertiesUpdatedEventArgs : ObjectPropertiesEventArgs
3560 {
3561  
3562 private readonly Primitive m_Prim;
3563  
3564 /// <summary>Get the primitive details</summary>
3565 public Primitive Prim { get { return m_Prim; } }
3566  
3567 /// <summary>
3568 /// Construct a new instance of the ObjectPropertiesUpdatedEvenrArgs class
3569 /// </summary>
3570 /// <param name="simulator">The simulator the object is located</param>
3571 /// <param name="prim">The Primitive</param>
3572 /// <param name="props">The primitive Properties</param>
3573 public ObjectPropertiesUpdatedEventArgs(Simulator simulator, Primitive prim, Primitive.ObjectProperties props) : base(simulator, props)
3574 {
3575 this.m_Prim = prim;
3576 }
3577 }
3578  
3579 /// <summary>Provides additional primitive data, permissions and sale info for the <see cref="ObjectManager.ObjectPropertiesFamily"/> event</summary>
3580 /// <remarks><para>The <see cref="ObjectManager.ObjectPropertiesFamily"/> event occurs when the simulator sends
3581 /// an <see cref="ObjectPropertiesPacket"/> containing additional details for a Primitive, Foliage data or Attachment. This includes
3582 /// Permissions, Sale info, and other basic details on an object</para>
3583 /// <para>The <see cref="ObjectManager.ObjectProperties"/> event is also raised when a <see cref="ObjectManager.RequestObjectPropertiesFamily"/> request is
3584 /// made, the viewer equivalent is hovering the mouse cursor over an object</para>
3585 /// </remarks>
3586 public class ObjectPropertiesFamilyEventArgs : EventArgs
3587 {
3588 private readonly Simulator m_Simulator;
3589 private readonly Primitive.ObjectProperties m_Properties;
3590 private readonly ReportType m_Type;
3591  
3592 /// <summary>Get the simulator the object is located</summary>
3593 public Simulator Simulator { get { return m_Simulator; } }
3594 /// <summary></summary>
3595 public Primitive.ObjectProperties Properties { get { return m_Properties; } }
3596 /// <summary></summary>
3597 public ReportType Type { get { return m_Type; } }
3598  
3599 public ObjectPropertiesFamilyEventArgs(Simulator simulator, Primitive.ObjectProperties props, ReportType type)
3600 {
3601 this.m_Simulator = simulator;
3602 this.m_Properties = props;
3603 this.m_Type = type;
3604 }
3605 }
3606  
3607 /// <summary>Provides primitive data containing updated location, velocity, rotation, textures for the <see cref="ObjectManager.TerseObjectUpdate"/> event</summary>
3608 /// <remarks><para>The <see cref="ObjectManager.TerseObjectUpdate"/> event occurs when the simulator sends updated location, velocity, rotation, etc</para>
3609 /// </remarks>
3610 public class TerseObjectUpdateEventArgs : EventArgs
3611 {
3612 private readonly Simulator m_Simulator;
3613 private readonly Primitive m_Prim;
3614 private readonly ObjectMovementUpdate m_Update;
3615 private readonly ushort m_TimeDilation;
3616  
3617 /// <summary>Get the simulator the object is located</summary>
3618 public Simulator Simulator { get { return m_Simulator; } }
3619 /// <summary>Get the primitive details</summary>
3620 public Primitive Prim { get { return m_Prim; } }
3621 /// <summary></summary>
3622 public ObjectMovementUpdate Update { get { return m_Update; } }
3623 /// <summary></summary>
3624 public ushort TimeDilation { get { return m_TimeDilation; } }
3625  
3626 public TerseObjectUpdateEventArgs(Simulator simulator, Primitive prim, ObjectMovementUpdate update, ushort timeDilation)
3627 {
3628 this.m_Simulator = simulator;
3629 this.m_Prim = prim;
3630 this.m_Update = update;
3631 this.m_TimeDilation = timeDilation;
3632 }
3633 }
3634  
3635 /// <summary>
3636 ///
3637 /// </summary>
3638 public class ObjectDataBlockUpdateEventArgs : EventArgs
3639 {
3640 private readonly Simulator m_Simulator;
3641 private readonly Primitive m_Prim;
3642 private readonly Primitive.ConstructionData m_ConstructionData;
3643 private readonly ObjectUpdatePacket.ObjectDataBlock m_Block;
3644 private readonly ObjectMovementUpdate m_Update;
3645 private readonly NameValue[] m_NameValues;
3646  
3647 /// <summary>Get the simulator the object is located</summary>
3648 public Simulator Simulator { get { return m_Simulator; } }
3649 /// <summary>Get the primitive details</summary>
3650 public Primitive Prim { get { return m_Prim; } }
3651 /// <summary></summary>
3652 public Primitive.ConstructionData ConstructionData { get { return m_ConstructionData; } }
3653 /// <summary></summary>
3654 public ObjectUpdatePacket.ObjectDataBlock Block { get { return m_Block; } }
3655 /// <summary></summary>
3656 public ObjectMovementUpdate Update { get { return m_Update; } }
3657 /// <summary></summary>
3658 public NameValue[] NameValues { get { return m_NameValues; } }
3659  
3660 public ObjectDataBlockUpdateEventArgs(Simulator simulator, Primitive prim, Primitive.ConstructionData constructionData,
3661 ObjectUpdatePacket.ObjectDataBlock block, ObjectMovementUpdate objectupdate, NameValue[] nameValues)
3662 {
3663 this.m_Simulator = simulator;
3664 this.m_Prim = prim;
3665 this.m_ConstructionData = constructionData;
3666 this.m_Block = block;
3667 this.m_Update = objectupdate;
3668 this.m_NameValues = nameValues;
3669 }
3670 }
3671  
3672 /// <summary>Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the
3673 /// <see cref="ObjectManager.KillObject"/> event</summary>
3674 public class KillObjectEventArgs : EventArgs
3675 {
3676 private readonly Simulator m_Simulator;
3677 private readonly uint m_ObjectLocalID;
3678  
3679 /// <summary>Get the simulator the object is located</summary>
3680 public Simulator Simulator { get { return m_Simulator; } }
3681 /// <summary>The LocalID of the object</summary>
3682 public uint ObjectLocalID { get { return m_ObjectLocalID; } }
3683  
3684 public KillObjectEventArgs(Simulator simulator, uint objectID)
3685 {
3686 this.m_Simulator = simulator;
3687 this.m_ObjectLocalID = objectID;
3688 }
3689 }
3690  
3691 /// <summary>Provides notification when an Avatar, Object or Attachment is DeRezzed or moves out of the avatars view for the
3692 /// <see cref="ObjectManager.KillObjects"/> event</summary>
3693 public class KillObjectsEventArgs : EventArgs
3694 {
3695 private readonly Simulator m_Simulator;
3696 private readonly uint[] m_ObjectLocalIDs;
3697  
3698 /// <summary>Get the simulator the object is located</summary>
3699 public Simulator Simulator { get { return m_Simulator; } }
3700 /// <summary>The LocalID of the object</summary>
3701 public uint[] ObjectLocalIDs { get { return m_ObjectLocalIDs; } }
3702  
3703 public KillObjectsEventArgs(Simulator simulator, uint[] objectIDs)
3704 {
3705 this.m_Simulator = simulator;
3706 this.m_ObjectLocalIDs = objectIDs;
3707 }
3708 }
3709  
3710 /// <summary>
3711 /// Provides updates sit position data
3712 /// </summary>
3713 public class AvatarSitChangedEventArgs : EventArgs
3714 {
3715 private readonly Simulator m_Simulator;
3716 private readonly Avatar m_Avatar;
3717 private readonly uint m_SittingOn;
3718 private readonly uint m_OldSeat;
3719  
3720 /// <summary>Get the simulator the object is located</summary>
3721 public Simulator Simulator { get { return m_Simulator; } }
3722 /// <summary></summary>
3723 public Avatar Avatar { get { return m_Avatar; } }
3724 /// <summary></summary>
3725 public uint SittingOn { get { return m_SittingOn; } }
3726 /// <summary></summary>
3727 public uint OldSeat { get { return m_OldSeat; } }
3728  
3729 public AvatarSitChangedEventArgs(Simulator simulator, Avatar avatar, uint sittingOn, uint oldSeat)
3730 {
3731 this.m_Simulator = simulator;
3732 this.m_Avatar = avatar;
3733 this.m_SittingOn = sittingOn;
3734 this.m_OldSeat = oldSeat;
3735 }
3736 }
3737  
3738 /// <summary>
3739 ///
3740 /// </summary>
3741 public class PayPriceReplyEventArgs : EventArgs
3742 {
3743 private readonly Simulator m_Simulator;
3744 private readonly UUID m_ObjectID;
3745 private readonly int m_DefaultPrice;
3746 private readonly int[] m_ButtonPrices;
3747  
3748 /// <summary>Get the simulator the object is located</summary>
3749 public Simulator Simulator { get { return m_Simulator; } }
3750 /// <summary></summary>
3751 public UUID ObjectID { get { return m_ObjectID; } }
3752 /// <summary></summary>
3753 public int DefaultPrice { get { return m_DefaultPrice; } }
3754 /// <summary></summary>
3755 public int[] ButtonPrices { get { return m_ButtonPrices; } }
3756  
3757 public PayPriceReplyEventArgs(Simulator simulator, UUID objectID, int defaultPrice, int[] buttonPrices)
3758 {
3759 this.m_Simulator = simulator;
3760 this.m_ObjectID = objectID;
3761 this.m_DefaultPrice = defaultPrice;
3762 this.m_ButtonPrices = buttonPrices;
3763 }
3764 }
3765  
3766 public class ObjectMediaEventArgs : EventArgs
3767 {
3768 /// <summary>
3769 /// Indicates if the operation was successful
3770 /// </summary>
3771 public bool Success { get; set; }
3772  
3773 /// <summary>
3774 /// Media version string
3775 /// </summary>
3776 public string Version { get; set; }
3777  
3778 /// <summary>
3779 /// Array of media entries indexed by face number
3780 /// </summary>
3781 public MediaEntry[] FaceMedia { get; set; }
3782  
3783 public ObjectMediaEventArgs(bool success, string version, MediaEntry[] faceMedia)
3784 {
3785 this.Success = success;
3786 this.Version = version;
3787 this.FaceMedia = faceMedia;
3788 }
3789 }
3790  
3791 /// <summary>
3792 /// Set when simulator sends us infomation on primitive's physical properties
3793 /// </summary>
3794 public class PhysicsPropertiesEventArgs : EventArgs
3795 {
3796 /// <summary>Simulator where the message originated</summary>
3797 public Simulator Simulator;
3798 /// <summary>Updated physical properties</summary>
3799 public Primitive.PhysicsProperties PhysicsProperties;
3800  
3801 /// <summary>
3802 /// Constructor
3803 /// </summary>
3804 /// <param name="sim">Simulator where the message originated</param>
3805 /// <param name="props">Updated physical properties</param>
3806 public PhysicsPropertiesEventArgs(Simulator sim, Primitive.PhysicsProperties props)
3807 {
3808 Simulator = sim;
3809 PhysicsProperties = props;
3810 }
3811 }
3812  
3813 #endregion
3814 }