corrade-vassal – Blame information for rev 1
?pathlinks?
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 | } |