diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectPart.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | 3826 |
1 files changed, 3826 insertions, 0 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs new file mode 100644 index 0000000..dfa9318 --- /dev/null +++ b/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs | |||
@@ -0,0 +1,3826 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Drawing; | ||
31 | using System.Reflection; | ||
32 | using System.Runtime.Serialization; | ||
33 | using System.Security.Permissions; | ||
34 | using System.Xml; | ||
35 | using System.Xml.Serialization; | ||
36 | using log4net; | ||
37 | using OpenMetaverse; | ||
38 | using OpenMetaverse.Packets; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Region.Framework.Interfaces; | ||
41 | using OpenSim.Region.Framework.Scenes.Scripting; | ||
42 | using OpenSim.Region.Physics.Manager; | ||
43 | |||
44 | namespace OpenSim.Region.Framework.Scenes | ||
45 | { | ||
46 | #region Enumerations | ||
47 | |||
48 | [Flags] | ||
49 | public enum Changed : uint | ||
50 | { | ||
51 | INVENTORY = 1, | ||
52 | COLOR = 2, | ||
53 | SHAPE = 4, | ||
54 | SCALE = 8, | ||
55 | TEXTURE = 16, | ||
56 | LINK = 32, | ||
57 | ALLOWED_DROP = 64, | ||
58 | OWNER = 128, | ||
59 | REGION_RESTART = 256, | ||
60 | REGION = 512, | ||
61 | TELEPORT = 1024 | ||
62 | } | ||
63 | |||
64 | // I don't really know where to put this except here. | ||
65 | // Can't access the OpenSim.Region.ScriptEngine.Common.LSL_BaseClass.Changed constants | ||
66 | [Flags] | ||
67 | public enum ExtraParamType | ||
68 | { | ||
69 | Something1 = 1, | ||
70 | Something2 = 2, | ||
71 | Something3 = 4, | ||
72 | Something4 = 8, | ||
73 | Flexible = 16, | ||
74 | Light = 32, | ||
75 | Sculpt = 48, | ||
76 | Something5 = 64, | ||
77 | Something6 = 128 | ||
78 | } | ||
79 | |||
80 | [Flags] | ||
81 | public enum TextureAnimFlags : byte | ||
82 | { | ||
83 | NONE = 0x00, | ||
84 | ANIM_ON = 0x01, | ||
85 | LOOP = 0x02, | ||
86 | REVERSE = 0x04, | ||
87 | PING_PONG = 0x08, | ||
88 | SMOOTH = 0x10, | ||
89 | ROTATE = 0x20, | ||
90 | SCALE = 0x40 | ||
91 | } | ||
92 | |||
93 | #endregion Enumerations | ||
94 | |||
95 | [Serializable] | ||
96 | public class SceneObjectPart : IScriptHost, ISerializable | ||
97 | { | ||
98 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
99 | |||
100 | // use only one serializer to give the runtime a chance to optimize it (it won't do that if you | ||
101 | // use a new instance every time) | ||
102 | private static XmlSerializer serializer = new XmlSerializer(typeof (SceneObjectPart)); | ||
103 | |||
104 | #region Fields | ||
105 | |||
106 | [XmlIgnore] | ||
107 | public bool AllowedDrop = false; | ||
108 | |||
109 | [XmlIgnore] | ||
110 | public bool DIE_AT_EDGE = false; | ||
111 | |||
112 | // TODO: This needs to be persisted in next XML version update! | ||
113 | [XmlIgnore] | ||
114 | public int[] PayPrice = {-2,-2,-2,-2,-2}; | ||
115 | [XmlIgnore] | ||
116 | public PhysicsActor PhysActor = null; | ||
117 | |||
118 | //Xantor 20080528 Sound stuff: | ||
119 | // Note: This isn't persisted in the database right now, as the fields for that aren't just there yet. | ||
120 | // Not a big problem as long as the script that sets it remains in the prim on startup. | ||
121 | // for SL compatibility it should be persisted though (set sound / displaytext / particlesystem, kill script) | ||
122 | [XmlIgnore] | ||
123 | public UUID Sound; | ||
124 | |||
125 | [XmlIgnore] | ||
126 | public byte SoundFlags; | ||
127 | |||
128 | [XmlIgnore] | ||
129 | public double SoundGain; | ||
130 | |||
131 | [XmlIgnore] | ||
132 | public double SoundRadius; | ||
133 | |||
134 | [XmlIgnore] | ||
135 | public uint TimeStampFull = 0; | ||
136 | |||
137 | [XmlIgnore] | ||
138 | public uint TimeStampLastActivity = 0; // Will be used for AutoReturn | ||
139 | |||
140 | [XmlIgnore] | ||
141 | public uint TimeStampTerse = 0; | ||
142 | |||
143 | [XmlIgnore] | ||
144 | public UUID FromAssetID = UUID.Zero; | ||
145 | |||
146 | /// <value> | ||
147 | /// The UUID of the user inventory item from which this object was rezzed if this is a root part. | ||
148 | /// If UUID.Zero then either this is not a root part or there is no connection with a user inventory item. | ||
149 | /// </value> | ||
150 | private UUID m_fromUserInventoryItemID = UUID.Zero; | ||
151 | |||
152 | [XmlIgnore] | ||
153 | public UUID FromUserInventoryItemID | ||
154 | { | ||
155 | get { return m_fromUserInventoryItemID; } | ||
156 | } | ||
157 | |||
158 | [XmlIgnore] | ||
159 | public bool IsAttachment = false; | ||
160 | |||
161 | [XmlIgnore] | ||
162 | public scriptEvents AggregateScriptEvents = 0; | ||
163 | |||
164 | [XmlIgnore] | ||
165 | public UUID AttachedAvatar = UUID.Zero; | ||
166 | |||
167 | [XmlIgnore] | ||
168 | public Vector3 AttachedPos = Vector3.Zero; | ||
169 | |||
170 | [XmlIgnore] | ||
171 | public uint AttachmentPoint = (byte)0; | ||
172 | |||
173 | [XmlIgnore] | ||
174 | public PhysicsVector RotationAxis = new PhysicsVector(1f,1f,1f); | ||
175 | |||
176 | [XmlIgnore] | ||
177 | public bool VolumeDetectActive = false; // XmlIgnore set to avoid problems with persistance until I come to care for this | ||
178 | // Certainly this must be a persistant setting finally | ||
179 | |||
180 | /// <summary> | ||
181 | /// This part's inventory | ||
182 | /// </summary> | ||
183 | [XmlIgnore] | ||
184 | public IEntityInventory Inventory | ||
185 | { | ||
186 | get { return m_inventory; } | ||
187 | } | ||
188 | protected SceneObjectPartInventory m_inventory; | ||
189 | |||
190 | [XmlIgnore] | ||
191 | public bool Undoing = false; | ||
192 | |||
193 | [XmlIgnore] | ||
194 | private PrimFlags LocalFlags = 0; | ||
195 | private byte[] m_TextureAnimation; | ||
196 | private byte m_clickAction = 0; | ||
197 | private Color m_color = Color.Black; | ||
198 | private string m_description = String.Empty; | ||
199 | private readonly List<uint> m_lastColliders = new List<uint>(); | ||
200 | // private PhysicsVector m_lastRotationalVelocity = PhysicsVector.Zero; | ||
201 | private int m_linkNum = 0; | ||
202 | [XmlIgnore] | ||
203 | private int m_scriptAccessPin = 0; | ||
204 | [XmlIgnore] | ||
205 | private readonly Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); | ||
206 | private string m_sitName = String.Empty; | ||
207 | private Quaternion m_sitTargetOrientation = Quaternion.Identity; | ||
208 | private Vector3 m_sitTargetPosition = Vector3.Zero; | ||
209 | private string m_sitAnimation = "SIT"; | ||
210 | private string m_text = String.Empty; | ||
211 | private string m_touchName = String.Empty; | ||
212 | private readonly UndoStack<UndoState> m_undo = new UndoStack<UndoState>(5); | ||
213 | private UUID _creatorID; | ||
214 | |||
215 | /// <summary> | ||
216 | /// Only used internally to schedule client updates. | ||
217 | /// 0 - no update is scheduled | ||
218 | /// 1 - terse update scheduled | ||
219 | /// 2 - full update scheduled | ||
220 | /// | ||
221 | /// TODO - This should be an enumeration | ||
222 | /// </summary> | ||
223 | private byte m_updateFlag; | ||
224 | |||
225 | protected Vector3 m_acceleration; | ||
226 | protected Vector3 m_angularVelocity; | ||
227 | |||
228 | //unkown if this will be kept, added as a way of removing the group position from the group class | ||
229 | protected Vector3 m_groupPosition; | ||
230 | protected uint m_localId; | ||
231 | protected Material m_material = (Material)3; // Wood | ||
232 | protected string m_name; | ||
233 | protected Vector3 m_offsetPosition; | ||
234 | |||
235 | // FIXME, TODO, ERROR: 'ParentGroup' can't be in here, move it out. | ||
236 | protected SceneObjectGroup m_parentGroup; | ||
237 | protected byte[] m_particleSystem = new byte[0]; | ||
238 | protected ulong m_regionHandle; | ||
239 | protected Quaternion m_rotationOffset; | ||
240 | protected PrimitiveBaseShape m_shape = null; | ||
241 | protected UUID m_uuid; | ||
242 | protected Vector3 m_velocity; | ||
243 | |||
244 | // TODO: Those have to be changed into persistent properties at some later point, | ||
245 | // or sit-camera on vehicles will break on sim-crossing. | ||
246 | private Vector3 m_cameraEyeOffset = new Vector3(0.0f, 0.0f, 0.0f); | ||
247 | private Vector3 m_cameraAtOffset = new Vector3(0.0f, 0.0f, 0.0f); | ||
248 | private bool m_forceMouselook = false; | ||
249 | |||
250 | // TODO: Collision sound should have default. | ||
251 | private UUID m_collisionSound = UUID.Zero; | ||
252 | private float m_collisionSoundVolume = 0.0f; | ||
253 | |||
254 | #endregion Fields | ||
255 | |||
256 | #region Constructors | ||
257 | |||
258 | /// <summary> | ||
259 | /// No arg constructor called by region restore db code | ||
260 | /// </summary> | ||
261 | public SceneObjectPart() | ||
262 | { | ||
263 | // It's not necessary to persist this | ||
264 | m_TextureAnimation = new byte[0]; | ||
265 | m_particleSystem = new byte[0]; | ||
266 | Rezzed = DateTime.Now; | ||
267 | |||
268 | m_inventory = new SceneObjectPartInventory(this); | ||
269 | } | ||
270 | |||
271 | /// <summary> | ||
272 | /// Create a completely new SceneObjectPart (prim). This will need to be added separately to a SceneObjectGroup | ||
273 | /// </summary> | ||
274 | /// <param name="ownerID"></param> | ||
275 | /// <param name="shape"></param> | ||
276 | /// <param name="position"></param> | ||
277 | /// <param name="rotationOffset"></param> | ||
278 | /// <param name="offsetPosition"></param> | ||
279 | public SceneObjectPart( | ||
280 | UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition, | ||
281 | Quaternion rotationOffset, Vector3 offsetPosition) | ||
282 | { | ||
283 | m_name = "Primitive"; | ||
284 | |||
285 | Rezzed = DateTime.Now; | ||
286 | _creationDate = (Int32) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; | ||
287 | _ownerID = ownerID; | ||
288 | _creatorID = _ownerID; | ||
289 | _lastOwnerID = UUID.Zero; | ||
290 | UUID = UUID.Random(); | ||
291 | Shape = shape; | ||
292 | // Todo: Add More Object Parameter from above! | ||
293 | _ownershipCost = 0; | ||
294 | _objectSaleType = (byte) 0; | ||
295 | _salePrice = 0; | ||
296 | _category = (uint) 0; | ||
297 | _lastOwnerID = _creatorID; | ||
298 | // End Todo: /// | ||
299 | GroupPosition = groupPosition; | ||
300 | OffsetPosition = offsetPosition; | ||
301 | RotationOffset = rotationOffset; | ||
302 | Velocity = new Vector3(0, 0, 0); | ||
303 | AngularVelocity = new Vector3(0, 0, 0); | ||
304 | Acceleration = new Vector3(0, 0, 0); | ||
305 | m_TextureAnimation = new byte[0]; | ||
306 | m_particleSystem = new byte[0]; | ||
307 | |||
308 | // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol, | ||
309 | // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from | ||
310 | // the prim into an agent inventory (Linden client reports that the "Object not found for drop" in its log | ||
311 | |||
312 | _flags = 0; | ||
313 | _flags |= PrimFlags.CreateSelected; | ||
314 | |||
315 | TrimPermissions(); | ||
316 | //m_undo = new UndoStack<UndoState>(ParentGroup.GetSceneMaxUndo()); | ||
317 | |||
318 | m_inventory = new SceneObjectPartInventory(this); | ||
319 | } | ||
320 | |||
321 | protected SceneObjectPart(SerializationInfo info, StreamingContext context) | ||
322 | { | ||
323 | //System.Console.WriteLine("SceneObjectPart Deserialize BGN"); | ||
324 | m_TextureAnimation = new byte[0]; | ||
325 | m_particleSystem = new byte[0]; | ||
326 | if (info == null) | ||
327 | { | ||
328 | throw new ArgumentNullException("info"); | ||
329 | } | ||
330 | |||
331 | /* | ||
332 | m_queue = (Queue<SceneObjectPart>)info.GetValue("m_queue", typeof(Queue<SceneObjectPart>)); | ||
333 | m_ids = (List<UUID>)info.GetValue("m_ids", typeof(List<UUID>)); | ||
334 | */ | ||
335 | |||
336 | //System.Console.WriteLine("SceneObjectPart Deserialize END"); | ||
337 | Rezzed = DateTime.Now; | ||
338 | |||
339 | m_inventory = new SceneObjectPartInventory(this); | ||
340 | } | ||
341 | |||
342 | #endregion Constructors | ||
343 | |||
344 | #region XML Schema | ||
345 | |||
346 | private UUID _lastOwnerID; | ||
347 | private UUID _ownerID; | ||
348 | private UUID _groupID; | ||
349 | private int _ownershipCost; | ||
350 | private byte _objectSaleType; | ||
351 | private int _salePrice; | ||
352 | private uint _category; | ||
353 | private Int32 _creationDate; | ||
354 | private uint _parentID = 0; | ||
355 | private UUID m_sitTargetAvatar = UUID.Zero; | ||
356 | private uint _baseMask = (uint)PermissionMask.All; | ||
357 | private uint _ownerMask = (uint)PermissionMask.All; | ||
358 | private uint _groupMask = (uint)PermissionMask.None; | ||
359 | private uint _everyoneMask = (uint)PermissionMask.None; | ||
360 | private uint _nextOwnerMask = (uint)PermissionMask.All; | ||
361 | private PrimFlags _flags = 0; | ||
362 | private DateTime m_expires; | ||
363 | private DateTime m_rezzed; | ||
364 | |||
365 | public UUID CreatorID | ||
366 | { | ||
367 | get | ||
368 | { | ||
369 | return _creatorID; | ||
370 | } | ||
371 | set | ||
372 | { | ||
373 | _creatorID = value; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | /// <summary> | ||
378 | /// Exposing this is not particularly good, but it's one of the least evils at the moment to see | ||
379 | /// folder id from prim inventory item data, since it's not (yet) actually stored with the prim. | ||
380 | /// </summary> | ||
381 | public UUID FolderID | ||
382 | { | ||
383 | get { return UUID; } | ||
384 | set { } // Don't allow assignment, or legacy prims wil b0rk | ||
385 | } | ||
386 | |||
387 | /// <value> | ||
388 | /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes | ||
389 | /// </value> | ||
390 | public uint InventorySerial | ||
391 | { | ||
392 | get { return m_inventory.Serial; } | ||
393 | set { m_inventory.Serial = value; } | ||
394 | } | ||
395 | |||
396 | /// <value> | ||
397 | /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes | ||
398 | /// </value> | ||
399 | public TaskInventoryDictionary TaskInventory | ||
400 | { | ||
401 | get { return m_inventory.Items; } | ||
402 | set { m_inventory.Items = value; } | ||
403 | } | ||
404 | |||
405 | public uint ObjectFlags | ||
406 | { | ||
407 | get { return (uint)_flags; } | ||
408 | set { _flags = (PrimFlags)value; } | ||
409 | } | ||
410 | |||
411 | public UUID UUID | ||
412 | { | ||
413 | get { return m_uuid; } | ||
414 | set { m_uuid = value; } | ||
415 | } | ||
416 | |||
417 | public uint LocalId | ||
418 | { | ||
419 | get { return m_localId; } | ||
420 | set { m_localId = value; } | ||
421 | } | ||
422 | |||
423 | public virtual string Name | ||
424 | { | ||
425 | get { return m_name; } | ||
426 | set | ||
427 | { | ||
428 | m_name = value; | ||
429 | if (PhysActor != null) | ||
430 | { | ||
431 | PhysActor.SOPName = value; | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | |||
436 | public byte Material | ||
437 | { | ||
438 | get { return (byte) m_material; } | ||
439 | set { m_material = (Material)value; } | ||
440 | } | ||
441 | |||
442 | public ulong RegionHandle | ||
443 | { | ||
444 | get { return m_regionHandle; } | ||
445 | set { m_regionHandle = value; } | ||
446 | } | ||
447 | |||
448 | public int ScriptAccessPin | ||
449 | { | ||
450 | get { return m_scriptAccessPin; } | ||
451 | set { m_scriptAccessPin = (int)value; } | ||
452 | } | ||
453 | |||
454 | [XmlIgnore] | ||
455 | public Byte[] TextureAnimation | ||
456 | { | ||
457 | get { return m_TextureAnimation; } | ||
458 | set { m_TextureAnimation = value; } | ||
459 | } | ||
460 | |||
461 | [XmlIgnore] | ||
462 | public Byte[] ParticleSystem | ||
463 | { | ||
464 | get { return m_particleSystem; } | ||
465 | set { m_particleSystem = value; } | ||
466 | } | ||
467 | |||
468 | [XmlIgnore] | ||
469 | public DateTime Expires | ||
470 | { | ||
471 | get { return m_expires; } | ||
472 | set { m_expires = value; } | ||
473 | } | ||
474 | |||
475 | [XmlIgnore] | ||
476 | public DateTime Rezzed | ||
477 | { | ||
478 | get { return m_rezzed; } | ||
479 | set { m_rezzed = value; } | ||
480 | } | ||
481 | |||
482 | /// <summary> | ||
483 | /// The position of the entire group that this prim belongs to. | ||
484 | /// </summary> | ||
485 | public Vector3 GroupPosition | ||
486 | { | ||
487 | get | ||
488 | { | ||
489 | // If this is a linkset, we don't want the physics engine mucking up our group position here. | ||
490 | if (PhysActor != null && _parentID == 0) | ||
491 | { | ||
492 | m_groupPosition.X = PhysActor.Position.X; | ||
493 | m_groupPosition.Y = PhysActor.Position.Y; | ||
494 | m_groupPosition.Z = PhysActor.Position.Z; | ||
495 | } | ||
496 | |||
497 | if (IsAttachment) | ||
498 | { | ||
499 | ScenePresence sp = m_parentGroup.Scene.GetScenePresence(AttachedAvatar); | ||
500 | if (sp != null) | ||
501 | { | ||
502 | return sp.AbsolutePosition; | ||
503 | } | ||
504 | } | ||
505 | |||
506 | return m_groupPosition; | ||
507 | } | ||
508 | set | ||
509 | { | ||
510 | StoreUndoState(); | ||
511 | |||
512 | m_groupPosition = value; | ||
513 | |||
514 | if (PhysActor != null) | ||
515 | { | ||
516 | try | ||
517 | { | ||
518 | // Root prim actually goes at Position | ||
519 | if (_parentID == 0) | ||
520 | { | ||
521 | PhysActor.Position = new PhysicsVector(value.X, value.Y, value.Z); | ||
522 | } | ||
523 | else | ||
524 | { | ||
525 | // To move the child prim in respect to the group position and rotation we have to calculate | ||
526 | Vector3 resultingposition = GetWorldPosition(); | ||
527 | PhysActor.Position = new PhysicsVector(resultingposition.X, resultingposition.Y, resultingposition.Z); | ||
528 | Quaternion resultingrot = GetWorldRotation(); | ||
529 | PhysActor.Orientation = resultingrot; | ||
530 | } | ||
531 | |||
532 | // Tell the physics engines that this prim changed. | ||
533 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
534 | } | ||
535 | catch (Exception e) | ||
536 | { | ||
537 | Console.WriteLine("[SCENEOBJECTPART]: GROUP POSITION. " + e.Message); | ||
538 | } | ||
539 | } | ||
540 | |||
541 | // TODO if we decide to do sitting in a more SL compatible way (multiple avatars per prim), this has to be fixed, too | ||
542 | if (m_sitTargetAvatar != UUID.Zero) | ||
543 | { | ||
544 | if (m_parentGroup != null) // TODO can there be a SOP without a SOG? | ||
545 | { | ||
546 | ScenePresence avatar; | ||
547 | if (m_parentGroup.Scene.TryGetAvatar(m_sitTargetAvatar, out avatar)) | ||
548 | { | ||
549 | avatar.ParentPosition = GetWorldPosition(); | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | } | ||
554 | } | ||
555 | |||
556 | public Vector3 OffsetPosition | ||
557 | { | ||
558 | get { return m_offsetPosition; } | ||
559 | set | ||
560 | { | ||
561 | StoreUndoState(); | ||
562 | m_offsetPosition = value; | ||
563 | |||
564 | if (ParentGroup != null && !ParentGroup.IsDeleted) | ||
565 | { | ||
566 | if (_parentID != 0 && PhysActor != null) | ||
567 | { | ||
568 | Vector3 resultingposition = GetWorldPosition(); | ||
569 | PhysActor.Position = new PhysicsVector(resultingposition.X, resultingposition.Y, resultingposition.Z); | ||
570 | Quaternion resultingrot = GetWorldRotation(); | ||
571 | PhysActor.Orientation = resultingrot; | ||
572 | |||
573 | // Tell the physics engines that this prim changed. | ||
574 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
575 | } | ||
576 | } | ||
577 | } | ||
578 | } | ||
579 | |||
580 | public Quaternion RotationOffset | ||
581 | { | ||
582 | get | ||
583 | { | ||
584 | // We don't want the physics engine mucking up the rotations in a linkset | ||
585 | if ((_parentID == 0) && (Shape.PCode != 9 || Shape.State == 0) && (PhysActor != null)) | ||
586 | { | ||
587 | if (PhysActor.Orientation.X != 0 || PhysActor.Orientation.Y != 0 | ||
588 | || PhysActor.Orientation.Z != 0 || PhysActor.Orientation.W != 0) | ||
589 | { | ||
590 | m_rotationOffset = PhysActor.Orientation; | ||
591 | } | ||
592 | } | ||
593 | return m_rotationOffset; | ||
594 | } | ||
595 | set | ||
596 | { | ||
597 | StoreUndoState(); | ||
598 | m_rotationOffset = value; | ||
599 | |||
600 | if (PhysActor != null) | ||
601 | { | ||
602 | try | ||
603 | { | ||
604 | // Root prim gets value directly | ||
605 | if (_parentID == 0) | ||
606 | { | ||
607 | PhysActor.Orientation = value; | ||
608 | //m_log.Info("[PART]: RO1:" + PhysActor.Orientation.ToString()); | ||
609 | } | ||
610 | else | ||
611 | { | ||
612 | // Child prim we have to calculate it's world rotationwel | ||
613 | Quaternion resultingrotation = GetWorldRotation(); | ||
614 | PhysActor.Orientation = resultingrotation; | ||
615 | //m_log.Info("[PART]: RO2:" + PhysActor.Orientation.ToString()); | ||
616 | } | ||
617 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
618 | //} | ||
619 | } | ||
620 | catch (Exception ex) | ||
621 | { | ||
622 | Console.WriteLine("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message); | ||
623 | } | ||
624 | } | ||
625 | |||
626 | } | ||
627 | } | ||
628 | |||
629 | /// <summary></summary> | ||
630 | public Vector3 Velocity | ||
631 | { | ||
632 | get | ||
633 | { | ||
634 | //if (PhysActor.Velocity.X != 0 || PhysActor.Velocity.Y != 0 | ||
635 | //|| PhysActor.Velocity.Z != 0) | ||
636 | //{ | ||
637 | if (PhysActor != null) | ||
638 | { | ||
639 | if (PhysActor.IsPhysical) | ||
640 | { | ||
641 | m_velocity.X = PhysActor.Velocity.X; | ||
642 | m_velocity.Y = PhysActor.Velocity.Y; | ||
643 | m_velocity.Z = PhysActor.Velocity.Z; | ||
644 | } | ||
645 | } | ||
646 | |||
647 | return m_velocity; | ||
648 | } | ||
649 | |||
650 | set | ||
651 | { | ||
652 | m_velocity = value; | ||
653 | if (PhysActor != null) | ||
654 | { | ||
655 | if (PhysActor.IsPhysical) | ||
656 | { | ||
657 | PhysActor.Velocity = new PhysicsVector(value.X, value.Y, value.Z); | ||
658 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
659 | } | ||
660 | } | ||
661 | } | ||
662 | } | ||
663 | |||
664 | public Vector3 RotationalVelocity | ||
665 | { | ||
666 | get { return AngularVelocity; } | ||
667 | set { AngularVelocity = value; } | ||
668 | } | ||
669 | |||
670 | /// <summary></summary> | ||
671 | public Vector3 AngularVelocity | ||
672 | { | ||
673 | get | ||
674 | { | ||
675 | if ((PhysActor != null) && PhysActor.IsPhysical) | ||
676 | { | ||
677 | m_angularVelocity.FromBytes(PhysActor.RotationalVelocity.GetBytes(), 0); | ||
678 | } | ||
679 | return m_angularVelocity; | ||
680 | } | ||
681 | set { m_angularVelocity = value; } | ||
682 | } | ||
683 | |||
684 | /// <summary></summary> | ||
685 | public Vector3 Acceleration | ||
686 | { | ||
687 | get { return m_acceleration; } | ||
688 | set { m_acceleration = value; } | ||
689 | } | ||
690 | |||
691 | public string Description | ||
692 | { | ||
693 | get { return m_description; } | ||
694 | set | ||
695 | { | ||
696 | m_description = value; | ||
697 | if (PhysActor != null) | ||
698 | { | ||
699 | PhysActor.SOPDescription = value; | ||
700 | } | ||
701 | } | ||
702 | } | ||
703 | |||
704 | public Color Color | ||
705 | { | ||
706 | get { return m_color; } | ||
707 | set | ||
708 | { | ||
709 | m_color = value; | ||
710 | TriggerScriptChangedEvent(Changed.COLOR); | ||
711 | |||
712 | /* ScheduleFullUpdate() need not be called b/c after | ||
713 | * setting the color, the text will be set, so then | ||
714 | * ScheduleFullUpdate() will be called. */ | ||
715 | //ScheduleFullUpdate(); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | public string Text | ||
720 | { | ||
721 | get | ||
722 | { | ||
723 | string returnstr = m_text; | ||
724 | if (returnstr.Length > 255) | ||
725 | { | ||
726 | returnstr = returnstr.Substring(0, 254); | ||
727 | } | ||
728 | return returnstr; | ||
729 | } | ||
730 | set | ||
731 | { | ||
732 | m_text = value; | ||
733 | } | ||
734 | } | ||
735 | |||
736 | |||
737 | public string SitName | ||
738 | { | ||
739 | get { return m_sitName; } | ||
740 | set { m_sitName = value; } | ||
741 | } | ||
742 | |||
743 | public string TouchName | ||
744 | { | ||
745 | get { return m_touchName; } | ||
746 | set { m_touchName = value; } | ||
747 | } | ||
748 | |||
749 | public int LinkNum | ||
750 | { | ||
751 | get { return m_linkNum; } | ||
752 | set { m_linkNum = value; } | ||
753 | } | ||
754 | |||
755 | public byte ClickAction | ||
756 | { | ||
757 | get { return m_clickAction; } | ||
758 | set | ||
759 | { | ||
760 | m_clickAction = value; | ||
761 | } | ||
762 | } | ||
763 | |||
764 | public PrimitiveBaseShape Shape | ||
765 | { | ||
766 | get { return m_shape; } | ||
767 | set | ||
768 | { | ||
769 | bool shape_changed = false; | ||
770 | // TODO: this should really be restricted to the right | ||
771 | // set of attributes on shape change. For instance, | ||
772 | // changing the lighting on a shape shouldn't cause | ||
773 | // this. | ||
774 | if (m_shape != null) | ||
775 | shape_changed = true; | ||
776 | |||
777 | m_shape = value; | ||
778 | |||
779 | if (shape_changed) | ||
780 | TriggerScriptChangedEvent(Changed.SHAPE); | ||
781 | } | ||
782 | } | ||
783 | |||
784 | public Vector3 Scale | ||
785 | { | ||
786 | get { return m_shape.Scale; } | ||
787 | set | ||
788 | { | ||
789 | StoreUndoState(); | ||
790 | if (m_shape != null) { | ||
791 | m_shape.Scale = value; | ||
792 | |||
793 | if (PhysActor != null && m_parentGroup != null) | ||
794 | { | ||
795 | if (m_parentGroup.Scene != null) | ||
796 | { | ||
797 | if (m_parentGroup.Scene.PhysicsScene != null) | ||
798 | { | ||
799 | PhysActor.Size = new PhysicsVector(m_shape.Scale.X, m_shape.Scale.Y, m_shape.Scale.Z); | ||
800 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
801 | } | ||
802 | } | ||
803 | } | ||
804 | } | ||
805 | TriggerScriptChangedEvent(Changed.SCALE); | ||
806 | } | ||
807 | } | ||
808 | public byte UpdateFlag | ||
809 | { | ||
810 | get { return m_updateFlag; } | ||
811 | set { m_updateFlag = value; } | ||
812 | } | ||
813 | |||
814 | #endregion | ||
815 | |||
816 | //--------------- | ||
817 | #region Public Properties with only Get | ||
818 | |||
819 | public Vector3 AbsolutePosition | ||
820 | { | ||
821 | get { | ||
822 | if (IsAttachment) | ||
823 | return GroupPosition; | ||
824 | |||
825 | return m_offsetPosition + m_groupPosition; } | ||
826 | } | ||
827 | |||
828 | public UUID ObjectCreator | ||
829 | { | ||
830 | get { return _creatorID; } | ||
831 | } | ||
832 | |||
833 | public UUID ObjectOwner | ||
834 | { | ||
835 | get { return _ownerID; } | ||
836 | } | ||
837 | |||
838 | public SceneObjectGroup ParentGroup | ||
839 | { | ||
840 | get { return m_parentGroup; } | ||
841 | } | ||
842 | |||
843 | public scriptEvents ScriptEvents | ||
844 | { | ||
845 | get { return AggregateScriptEvents; } | ||
846 | } | ||
847 | |||
848 | |||
849 | public Quaternion SitTargetOrientation | ||
850 | { | ||
851 | get { return m_sitTargetOrientation; } | ||
852 | set { m_sitTargetOrientation = value; } | ||
853 | } | ||
854 | |||
855 | |||
856 | public Vector3 SitTargetPosition | ||
857 | { | ||
858 | get { return m_sitTargetPosition; } | ||
859 | set { m_sitTargetPosition = value; } | ||
860 | } | ||
861 | |||
862 | // This sort of sucks, but I'm adding these in to make some of | ||
863 | // the mappings more consistant. | ||
864 | public Vector3 SitTargetPositionLL | ||
865 | { | ||
866 | get { return new Vector3(m_sitTargetPosition.X, m_sitTargetPosition.Y,m_sitTargetPosition.Z); } | ||
867 | set { m_sitTargetPosition = value; } | ||
868 | } | ||
869 | |||
870 | public Quaternion SitTargetOrientationLL | ||
871 | { | ||
872 | get | ||
873 | { | ||
874 | return new Quaternion( | ||
875 | m_sitTargetOrientation.X, | ||
876 | m_sitTargetOrientation.Y, | ||
877 | m_sitTargetOrientation.Z, | ||
878 | m_sitTargetOrientation.W | ||
879 | ); | ||
880 | } | ||
881 | |||
882 | set { m_sitTargetOrientation = new Quaternion(value.X, value.Y, value.Z, value.W); } | ||
883 | } | ||
884 | |||
885 | public bool Stopped | ||
886 | { | ||
887 | get { | ||
888 | double threshold = 0.02; | ||
889 | return (Math.Abs(Velocity.X) < threshold && | ||
890 | Math.Abs(Velocity.Y) < threshold && | ||
891 | Math.Abs(Velocity.Z) < threshold && | ||
892 | Math.Abs(AngularVelocity.X) < threshold && | ||
893 | Math.Abs(AngularVelocity.Y) < threshold && | ||
894 | Math.Abs(AngularVelocity.Z) < threshold); | ||
895 | } | ||
896 | } | ||
897 | |||
898 | public uint ParentID | ||
899 | { | ||
900 | get { return _parentID; } | ||
901 | set { _parentID = value; } | ||
902 | } | ||
903 | |||
904 | public int CreationDate | ||
905 | { | ||
906 | get { return _creationDate; } | ||
907 | set { _creationDate = value; } | ||
908 | } | ||
909 | |||
910 | public uint Category | ||
911 | { | ||
912 | get { return _category; } | ||
913 | set { _category = value; } | ||
914 | } | ||
915 | |||
916 | public int SalePrice | ||
917 | { | ||
918 | get { return _salePrice; } | ||
919 | set { _salePrice = value; } | ||
920 | } | ||
921 | |||
922 | public byte ObjectSaleType | ||
923 | { | ||
924 | get { return _objectSaleType; } | ||
925 | set { _objectSaleType = value; } | ||
926 | } | ||
927 | |||
928 | public int OwnershipCost | ||
929 | { | ||
930 | get { return _ownershipCost; } | ||
931 | set { _ownershipCost = value; } | ||
932 | } | ||
933 | |||
934 | public UUID GroupID | ||
935 | { | ||
936 | get { return _groupID; } | ||
937 | set { _groupID = value; } | ||
938 | } | ||
939 | |||
940 | public UUID OwnerID | ||
941 | { | ||
942 | get { return _ownerID; } | ||
943 | set { _ownerID = value; } | ||
944 | } | ||
945 | |||
946 | public UUID LastOwnerID | ||
947 | { | ||
948 | get { return _lastOwnerID; } | ||
949 | set { _lastOwnerID = value; } | ||
950 | } | ||
951 | |||
952 | public uint BaseMask | ||
953 | { | ||
954 | get { return _baseMask; } | ||
955 | set { _baseMask = value; } | ||
956 | } | ||
957 | |||
958 | public uint OwnerMask | ||
959 | { | ||
960 | get { return _ownerMask; } | ||
961 | set { _ownerMask = value; } | ||
962 | } | ||
963 | |||
964 | public uint GroupMask | ||
965 | { | ||
966 | get { return _groupMask; } | ||
967 | set { _groupMask = value; } | ||
968 | } | ||
969 | |||
970 | public uint EveryoneMask | ||
971 | { | ||
972 | get { return _everyoneMask; } | ||
973 | set { _everyoneMask = value; } | ||
974 | } | ||
975 | |||
976 | public uint NextOwnerMask | ||
977 | { | ||
978 | get { return _nextOwnerMask; } | ||
979 | set { _nextOwnerMask = value; } | ||
980 | } | ||
981 | |||
982 | public PrimFlags Flags | ||
983 | { | ||
984 | get { return _flags; } | ||
985 | set { _flags = value; } | ||
986 | } | ||
987 | |||
988 | [XmlIgnore] | ||
989 | public UUID SitTargetAvatar | ||
990 | { | ||
991 | get { return m_sitTargetAvatar; } | ||
992 | set { m_sitTargetAvatar = value; } | ||
993 | } | ||
994 | |||
995 | [XmlIgnore] | ||
996 | public virtual UUID RegionID | ||
997 | { | ||
998 | get | ||
999 | { | ||
1000 | if (ParentGroup != null && ParentGroup.Scene != null) | ||
1001 | return ParentGroup.Scene.RegionInfo.RegionID; | ||
1002 | else | ||
1003 | return UUID.Zero; | ||
1004 | } | ||
1005 | set {} // read only | ||
1006 | } | ||
1007 | |||
1008 | private UUID _parentUUID = UUID.Zero; | ||
1009 | [XmlIgnore] | ||
1010 | public UUID ParentUUID | ||
1011 | { | ||
1012 | get | ||
1013 | { | ||
1014 | if (ParentGroup != null) | ||
1015 | { | ||
1016 | _parentUUID = ParentGroup.UUID; | ||
1017 | } | ||
1018 | return _parentUUID; | ||
1019 | } | ||
1020 | set { _parentUUID = value; } | ||
1021 | } | ||
1022 | |||
1023 | [XmlIgnore] | ||
1024 | public string SitAnimation | ||
1025 | { | ||
1026 | get { return m_sitAnimation; } | ||
1027 | set { m_sitAnimation = value; } | ||
1028 | } | ||
1029 | |||
1030 | public UUID CollisionSound | ||
1031 | { | ||
1032 | get { return m_collisionSound; } | ||
1033 | set | ||
1034 | { | ||
1035 | m_collisionSound = value; | ||
1036 | aggregateScriptEvents(); | ||
1037 | } | ||
1038 | } | ||
1039 | |||
1040 | public float CollisionSoundVolume | ||
1041 | { | ||
1042 | get { return m_collisionSoundVolume; } | ||
1043 | set { m_collisionSoundVolume = value; } | ||
1044 | } | ||
1045 | |||
1046 | #endregion Public Properties with only Get | ||
1047 | |||
1048 | |||
1049 | |||
1050 | #region Private Methods | ||
1051 | |||
1052 | private uint ApplyMask(uint val, bool set, uint mask) | ||
1053 | { | ||
1054 | if (set) | ||
1055 | { | ||
1056 | return val |= mask; | ||
1057 | } | ||
1058 | else | ||
1059 | { | ||
1060 | return val &= ~mask; | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | /// <summary> | ||
1065 | /// Clear all pending updates of parts to clients | ||
1066 | /// </summary> | ||
1067 | private void ClearUpdateSchedule() | ||
1068 | { | ||
1069 | m_updateFlag = 0; | ||
1070 | } | ||
1071 | |||
1072 | private void SendObjectPropertiesToClient(UUID AgentID) | ||
1073 | { | ||
1074 | List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); | ||
1075 | for (int i = 0; i < avatars.Count; i++) | ||
1076 | { | ||
1077 | // Ugly reference :( | ||
1078 | if (avatars[i].UUID == AgentID) | ||
1079 | { | ||
1080 | m_parentGroup.GetProperties(avatars[i].ControllingClient); | ||
1081 | } | ||
1082 | } | ||
1083 | } | ||
1084 | |||
1085 | private void handleTimerAccounting(uint localID, double interval) | ||
1086 | { | ||
1087 | if (localID == LocalId) | ||
1088 | { | ||
1089 | |||
1090 | float sec = (float)interval; | ||
1091 | if (m_parentGroup != null) | ||
1092 | { | ||
1093 | if (sec == 0) | ||
1094 | { | ||
1095 | if (m_parentGroup.scriptScore + 0.001f >= float.MaxValue - 0.001) | ||
1096 | m_parentGroup.scriptScore = 0; | ||
1097 | |||
1098 | m_parentGroup.scriptScore += 0.001f; | ||
1099 | return; | ||
1100 | } | ||
1101 | |||
1102 | if (m_parentGroup.scriptScore + (0.001f / sec) >= float.MaxValue - (0.001f / sec)) | ||
1103 | m_parentGroup.scriptScore = 0; | ||
1104 | m_parentGroup.scriptScore += (0.001f / sec); | ||
1105 | } | ||
1106 | |||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | #endregion Private Methods | ||
1111 | |||
1112 | #region Public Methods | ||
1113 | |||
1114 | public void ResetExpire() | ||
1115 | { | ||
1116 | Expires = DateTime.Now + new TimeSpan(600000000); | ||
1117 | } | ||
1118 | |||
1119 | public void AddFlag(PrimFlags flag) | ||
1120 | { | ||
1121 | // PrimFlags prevflag = Flags; | ||
1122 | if ((ObjectFlags & (uint) flag) == 0) | ||
1123 | { | ||
1124 | //Console.WriteLine("Adding flag: " + ((PrimFlags) flag).ToString()); | ||
1125 | _flags |= flag; | ||
1126 | |||
1127 | if (flag == PrimFlags.TemporaryOnRez) | ||
1128 | ResetExpire(); | ||
1129 | } | ||
1130 | // System.Console.WriteLine("Aprev: " + prevflag.ToString() + " curr: " + Flags.ToString()); | ||
1131 | } | ||
1132 | |||
1133 | /// <summary> | ||
1134 | /// Tell all scene presences that they should send updates for this part to their clients | ||
1135 | /// </summary> | ||
1136 | public void AddFullUpdateToAllAvatars() | ||
1137 | { | ||
1138 | List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); | ||
1139 | for (int i = 0; i < avatars.Count; i++) | ||
1140 | { | ||
1141 | avatars[i].QueuePartForUpdate(this); | ||
1142 | } | ||
1143 | } | ||
1144 | |||
1145 | public void AddFullUpdateToAvatar(ScenePresence presence) | ||
1146 | { | ||
1147 | presence.QueuePartForUpdate(this); | ||
1148 | } | ||
1149 | |||
1150 | public void AddNewParticleSystem(Primitive.ParticleSystem pSystem) | ||
1151 | { | ||
1152 | m_particleSystem = pSystem.GetBytes(); | ||
1153 | } | ||
1154 | |||
1155 | public void RemoveParticleSystem() | ||
1156 | { | ||
1157 | m_particleSystem = new byte[0]; | ||
1158 | } | ||
1159 | |||
1160 | /// Terse updates | ||
1161 | public void AddTerseUpdateToAllAvatars() | ||
1162 | { | ||
1163 | List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); | ||
1164 | for (int i = 0; i < avatars.Count; i++) | ||
1165 | { | ||
1166 | avatars[i].QueuePartForUpdate(this); | ||
1167 | } | ||
1168 | } | ||
1169 | |||
1170 | public void AddTerseUpdateToAvatar(ScenePresence presence) | ||
1171 | { | ||
1172 | presence.QueuePartForUpdate(this); | ||
1173 | } | ||
1174 | |||
1175 | public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim) | ||
1176 | { | ||
1177 | byte[] data = new byte[16]; | ||
1178 | int pos = 0; | ||
1179 | |||
1180 | // The flags don't like conversion from uint to byte, so we have to do | ||
1181 | // it the crappy way. See the above function :( | ||
1182 | |||
1183 | data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++; | ||
1184 | data[pos] = (byte)pTexAnim.Face; pos++; | ||
1185 | data[pos] = (byte)pTexAnim.SizeX; pos++; | ||
1186 | data[pos] = (byte)pTexAnim.SizeY; pos++; | ||
1187 | |||
1188 | Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos); | ||
1189 | Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4); | ||
1190 | Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8); | ||
1191 | |||
1192 | m_TextureAnimation = data; | ||
1193 | } | ||
1194 | |||
1195 | public void AdjustSoundGain(double volume) | ||
1196 | { | ||
1197 | if (volume > 1) | ||
1198 | volume = 1; | ||
1199 | if (volume < 0) | ||
1200 | volume = 0; | ||
1201 | |||
1202 | List<ScenePresence> avatarts = m_parentGroup.Scene.GetAvatars(); | ||
1203 | foreach (ScenePresence p in avatarts) | ||
1204 | { | ||
1205 | p.ControllingClient.SendAttachedSoundGainChange(UUID, (float)volume); | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | /// <summary> | ||
1210 | /// hook to the physics scene to apply impulse | ||
1211 | /// This is sent up to the group, which then finds the root prim | ||
1212 | /// and applies the force on the root prim of the group | ||
1213 | /// </summary> | ||
1214 | /// <param name="impulsei">Vector force</param> | ||
1215 | /// <param name="localGlobalTF">true for the local frame, false for the global frame</param> | ||
1216 | public void ApplyImpulse(Vector3 impulsei, bool localGlobalTF) | ||
1217 | { | ||
1218 | PhysicsVector impulse = new PhysicsVector(impulsei.X, impulsei.Y, impulsei.Z); | ||
1219 | |||
1220 | if (localGlobalTF) | ||
1221 | { | ||
1222 | Quaternion grot = GetWorldRotation(); | ||
1223 | Quaternion AXgrot = grot; | ||
1224 | Vector3 AXimpulsei = impulsei; | ||
1225 | Vector3 newimpulse = AXimpulsei * AXgrot; | ||
1226 | impulse = new PhysicsVector(newimpulse.X, newimpulse.Y, newimpulse.Z); | ||
1227 | } | ||
1228 | |||
1229 | if (m_parentGroup != null) | ||
1230 | { | ||
1231 | m_parentGroup.applyImpulse(impulse); | ||
1232 | } | ||
1233 | } | ||
1234 | |||
1235 | |||
1236 | /// <summary> | ||
1237 | /// hook to the physics scene to apply angular impulse | ||
1238 | /// This is sent up to the group, which then finds the root prim | ||
1239 | /// and applies the force on the root prim of the group | ||
1240 | /// </summary> | ||
1241 | /// <param name="impulsei">Vector force</param> | ||
1242 | /// <param name="localGlobalTF">true for the local frame, false for the global frame</param> | ||
1243 | public void ApplyAngularImpulse(Vector3 impulsei, bool localGlobalTF) | ||
1244 | { | ||
1245 | PhysicsVector impulse = new PhysicsVector(impulsei.X, impulsei.Y, impulsei.Z); | ||
1246 | |||
1247 | if (localGlobalTF) | ||
1248 | { | ||
1249 | Quaternion grot = GetWorldRotation(); | ||
1250 | Quaternion AXgrot = grot; | ||
1251 | Vector3 AXimpulsei = impulsei; | ||
1252 | Vector3 newimpulse = AXimpulsei * AXgrot; | ||
1253 | impulse = new PhysicsVector(newimpulse.X, newimpulse.Y, newimpulse.Z); | ||
1254 | } | ||
1255 | |||
1256 | if (m_parentGroup != null) | ||
1257 | { | ||
1258 | m_parentGroup.applyAngularImpulse(impulse); | ||
1259 | } | ||
1260 | } | ||
1261 | |||
1262 | /// <summary> | ||
1263 | /// hook to the physics scene to apply angular impulse | ||
1264 | /// This is sent up to the group, which then finds the root prim | ||
1265 | /// and applies the force on the root prim of the group | ||
1266 | /// </summary> | ||
1267 | /// <param name="impulsei">Vector force</param> | ||
1268 | /// <param name="localGlobalTF">true for the local frame, false for the global frame</param> | ||
1269 | public void SetAngularImpulse(Vector3 impulsei, bool localGlobalTF) | ||
1270 | { | ||
1271 | PhysicsVector impulse = new PhysicsVector(impulsei.X, impulsei.Y, impulsei.Z); | ||
1272 | |||
1273 | if (localGlobalTF) | ||
1274 | { | ||
1275 | Quaternion grot = GetWorldRotation(); | ||
1276 | Quaternion AXgrot = grot; | ||
1277 | Vector3 AXimpulsei = impulsei; | ||
1278 | Vector3 newimpulse = AXimpulsei * AXgrot; | ||
1279 | impulse = new PhysicsVector(newimpulse.X, newimpulse.Y, newimpulse.Z); | ||
1280 | } | ||
1281 | |||
1282 | if (m_parentGroup != null) | ||
1283 | { | ||
1284 | m_parentGroup.setAngularImpulse(impulse); | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1288 | public Vector3 GetTorque() | ||
1289 | { | ||
1290 | if (m_parentGroup != null) | ||
1291 | { | ||
1292 | m_parentGroup.GetTorque(); | ||
1293 | } | ||
1294 | return Vector3.Zero; | ||
1295 | } | ||
1296 | |||
1297 | /// <summary> | ||
1298 | /// Apply physics to this part. | ||
1299 | /// </summary> | ||
1300 | /// <param name="rootObjectFlags"></param> | ||
1301 | /// <param name="m_physicalPrim"></param> | ||
1302 | public void ApplyPhysics(uint rootObjectFlags, bool VolumeDetectActive, bool m_physicalPrim) | ||
1303 | { | ||
1304 | bool isPhysical = (((rootObjectFlags & (uint) PrimFlags.Physics) != 0) && m_physicalPrim); | ||
1305 | bool isPhantom = ((rootObjectFlags & (uint) PrimFlags.Phantom) != 0); | ||
1306 | |||
1307 | if (IsJoint()) | ||
1308 | { | ||
1309 | DoPhysicsPropertyUpdate(isPhysical, true); | ||
1310 | } | ||
1311 | else | ||
1312 | { | ||
1313 | // Special case for VolumeDetection: If VolumeDetection is set, the phantom flag is locally ignored | ||
1314 | if (VolumeDetectActive) | ||
1315 | isPhantom = false; | ||
1316 | |||
1317 | // Added clarification.. since A rigid body is an object that you can kick around, etc. | ||
1318 | bool RigidBody = isPhysical && !isPhantom; | ||
1319 | |||
1320 | // The only time the physics scene shouldn't know about the prim is if it's phantom or an attachment, which is phantom by definition | ||
1321 | if (!isPhantom && !IsAttachment) | ||
1322 | { | ||
1323 | PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( | ||
1324 | Name, | ||
1325 | Shape, | ||
1326 | new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z), | ||
1327 | new PhysicsVector(Scale.X, Scale.Y, Scale.Z), | ||
1328 | RotationOffset, | ||
1329 | RigidBody); | ||
1330 | |||
1331 | // Basic Physics returns null.. joy joy joy. | ||
1332 | if (PhysActor != null) | ||
1333 | { | ||
1334 | PhysActor.SOPName = this.Name; // save object name and desc into the PhysActor so ODE internals know the joint/body info | ||
1335 | PhysActor.SOPDescription = this.Description; | ||
1336 | PhysActor.LocalID = LocalId; | ||
1337 | DoPhysicsPropertyUpdate(RigidBody, true); | ||
1338 | PhysActor.SetVolumeDetect(VolumeDetectActive ? 1 : 0); | ||
1339 | } | ||
1340 | } | ||
1341 | } | ||
1342 | } | ||
1343 | |||
1344 | public void ClearUndoState() | ||
1345 | { | ||
1346 | lock (m_undo) | ||
1347 | { | ||
1348 | m_undo.Clear(); | ||
1349 | } | ||
1350 | StoreUndoState(); | ||
1351 | } | ||
1352 | |||
1353 | public byte ConvertScriptUintToByte(uint indata) | ||
1354 | { | ||
1355 | byte outdata = (byte)TextureAnimFlags.NONE; | ||
1356 | if ((indata & 1) != 0) outdata |= (byte)TextureAnimFlags.ANIM_ON; | ||
1357 | if ((indata & 2) != 0) outdata |= (byte)TextureAnimFlags.LOOP; | ||
1358 | if ((indata & 4) != 0) outdata |= (byte)TextureAnimFlags.REVERSE; | ||
1359 | if ((indata & 8) != 0) outdata |= (byte)TextureAnimFlags.PING_PONG; | ||
1360 | if ((indata & 16) != 0) outdata |= (byte)TextureAnimFlags.SMOOTH; | ||
1361 | if ((indata & 32) != 0) outdata |= (byte)TextureAnimFlags.ROTATE; | ||
1362 | if ((indata & 64) != 0) outdata |= (byte)TextureAnimFlags.SCALE; | ||
1363 | return outdata; | ||
1364 | } | ||
1365 | |||
1366 | /// <summary> | ||
1367 | /// Duplicates this part. | ||
1368 | /// </summary> | ||
1369 | /// <returns></returns> | ||
1370 | public SceneObjectPart Copy(uint localID, UUID AgentID, UUID GroupID, int linkNum, bool userExposed) | ||
1371 | { | ||
1372 | SceneObjectPart dupe = (SceneObjectPart) MemberwiseClone(); | ||
1373 | dupe.m_shape = m_shape.Copy(); | ||
1374 | dupe.m_regionHandle = m_regionHandle; | ||
1375 | if (userExposed) | ||
1376 | dupe.UUID = UUID.Random(); | ||
1377 | |||
1378 | //memberwiseclone means it also clones the physics actor reference | ||
1379 | // This will make physical prim 'bounce' if not set to null. | ||
1380 | if (!userExposed) | ||
1381 | dupe.PhysActor = null; | ||
1382 | |||
1383 | dupe._ownerID = AgentID; | ||
1384 | dupe._groupID = GroupID; | ||
1385 | dupe.GroupPosition = GroupPosition; | ||
1386 | dupe.OffsetPosition = OffsetPosition; | ||
1387 | dupe.RotationOffset = RotationOffset; | ||
1388 | dupe.Velocity = new Vector3(0, 0, 0); | ||
1389 | dupe.Acceleration = new Vector3(0, 0, 0); | ||
1390 | dupe.AngularVelocity = new Vector3(0, 0, 0); | ||
1391 | dupe.ObjectFlags = ObjectFlags; | ||
1392 | |||
1393 | dupe._ownershipCost = _ownershipCost; | ||
1394 | dupe._objectSaleType = _objectSaleType; | ||
1395 | dupe._salePrice = _salePrice; | ||
1396 | dupe._category = _category; | ||
1397 | dupe.m_rezzed = m_rezzed; | ||
1398 | |||
1399 | dupe.m_inventory = new SceneObjectPartInventory(dupe); | ||
1400 | dupe.m_inventory.Items = (TaskInventoryDictionary)m_inventory.Items.Clone(); | ||
1401 | |||
1402 | if (userExposed) | ||
1403 | { | ||
1404 | dupe.ResetIDs(linkNum); | ||
1405 | dupe.m_inventory.HasInventoryChanged = true; | ||
1406 | } | ||
1407 | else | ||
1408 | { | ||
1409 | dupe.m_inventory.HasInventoryChanged = m_inventory.HasInventoryChanged; | ||
1410 | } | ||
1411 | |||
1412 | // Move afterwards ResetIDs as it clears the localID | ||
1413 | dupe.LocalId = localID; | ||
1414 | // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated. | ||
1415 | dupe._lastOwnerID = ObjectOwner; | ||
1416 | |||
1417 | byte[] extraP = new byte[Shape.ExtraParams.Length]; | ||
1418 | Array.Copy(Shape.ExtraParams, extraP, extraP.Length); | ||
1419 | dupe.Shape.ExtraParams = extraP; | ||
1420 | |||
1421 | if (userExposed) | ||
1422 | { | ||
1423 | if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero) | ||
1424 | { | ||
1425 | m_parentGroup.Scene.AssetCache.GetAsset(dupe.m_shape.SculptTexture, dupe.SculptTextureCallback, true); | ||
1426 | } | ||
1427 | bool UsePhysics = ((dupe.ObjectFlags & (uint)PrimFlags.Physics) != 0); | ||
1428 | dupe.DoPhysicsPropertyUpdate(UsePhysics, true); | ||
1429 | } | ||
1430 | |||
1431 | return dupe; | ||
1432 | } | ||
1433 | |||
1434 | public static SceneObjectPart Create() | ||
1435 | { | ||
1436 | SceneObjectPart part = new SceneObjectPart(); | ||
1437 | part.UUID = UUID.Random(); | ||
1438 | |||
1439 | PrimitiveBaseShape shape = PrimitiveBaseShape.Create(); | ||
1440 | part.Shape = shape; | ||
1441 | |||
1442 | part.Name = "Primitive"; | ||
1443 | part._ownerID = UUID.Random(); | ||
1444 | |||
1445 | return part; | ||
1446 | } | ||
1447 | |||
1448 | public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew) | ||
1449 | { | ||
1450 | if (IsJoint()) | ||
1451 | { | ||
1452 | if (UsePhysics) | ||
1453 | { | ||
1454 | // by turning a joint proxy object physical, we cause creation of a joint in the ODE scene. | ||
1455 | // note that, as a special case, joints have no bodies or geoms in the physics scene, even though they are physical. | ||
1456 | |||
1457 | PhysicsJointType jointType; | ||
1458 | if (IsHingeJoint()) | ||
1459 | { | ||
1460 | jointType = PhysicsJointType.Hinge; | ||
1461 | } | ||
1462 | else if (IsBallJoint()) | ||
1463 | { | ||
1464 | jointType = PhysicsJointType.Ball; | ||
1465 | } | ||
1466 | else | ||
1467 | { | ||
1468 | jointType = PhysicsJointType.Ball; | ||
1469 | } | ||
1470 | |||
1471 | List<string> bodyNames = new List<string>(); | ||
1472 | string RawParams = Description; | ||
1473 | string[] jointParams = RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries); | ||
1474 | string trackedBodyName = null; | ||
1475 | if (jointParams.Length >= 2) | ||
1476 | { | ||
1477 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | ||
1478 | { | ||
1479 | string bodyName = jointParams[iBodyName]; | ||
1480 | bodyNames.Add(bodyName); | ||
1481 | if (bodyName != "NULL") | ||
1482 | { | ||
1483 | if (trackedBodyName == null) | ||
1484 | { | ||
1485 | trackedBodyName = bodyName; | ||
1486 | } | ||
1487 | } | ||
1488 | } | ||
1489 | } | ||
1490 | |||
1491 | SceneObjectPart trackedBody = m_parentGroup.Scene.GetSceneObjectPart(trackedBodyName); // FIXME: causes a sequential lookup | ||
1492 | Quaternion localRotation = Quaternion.Identity; | ||
1493 | if (trackedBody != null) | ||
1494 | { | ||
1495 | localRotation = Quaternion.Inverse(trackedBody.RotationOffset) * this.RotationOffset; | ||
1496 | } | ||
1497 | else | ||
1498 | { | ||
1499 | // error, output it below | ||
1500 | } | ||
1501 | |||
1502 | PhysicsJoint joint; | ||
1503 | |||
1504 | joint = m_parentGroup.Scene.PhysicsScene.RequestJointCreation(Name, jointType, | ||
1505 | new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z), | ||
1506 | this.RotationOffset, | ||
1507 | Description, | ||
1508 | bodyNames, | ||
1509 | trackedBodyName, | ||
1510 | localRotation); | ||
1511 | |||
1512 | if (trackedBody == null) | ||
1513 | { | ||
1514 | ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name); | ||
1515 | } | ||
1516 | |||
1517 | } | ||
1518 | else | ||
1519 | { | ||
1520 | if (isNew) | ||
1521 | { | ||
1522 | // if the joint proxy is new, and it is not physical, do nothing. There is no joint in ODE to | ||
1523 | // delete, and if we try to delete it, due to asynchronous processing, the deletion request | ||
1524 | // will get processed later at an indeterminate time, which could cancel a later-arriving | ||
1525 | // joint creation request. | ||
1526 | } | ||
1527 | else | ||
1528 | { | ||
1529 | // here we turn off the joint object, so remove the joint from the physics scene | ||
1530 | m_parentGroup.Scene.PhysicsScene.RequestJointDeletion(Name); // FIXME: what if the name changed? | ||
1531 | |||
1532 | // make sure client isn't interpolating the joint proxy object | ||
1533 | Velocity = new Vector3(0, 0, 0); | ||
1534 | RotationalVelocity = new Vector3(0, 0, 0); | ||
1535 | Acceleration = new Vector3(0, 0, 0); | ||
1536 | } | ||
1537 | } | ||
1538 | } | ||
1539 | else | ||
1540 | { | ||
1541 | if (PhysActor != null) | ||
1542 | { | ||
1543 | if (UsePhysics != PhysActor.IsPhysical || isNew) | ||
1544 | { | ||
1545 | if (PhysActor.IsPhysical) // implies UsePhysics==false for this block | ||
1546 | { | ||
1547 | if (!isNew) | ||
1548 | ParentGroup.Scene.RemovePhysicalPrim(1); | ||
1549 | |||
1550 | PhysActor.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate; | ||
1551 | PhysActor.OnOutOfBounds -= PhysicsOutOfBounds; | ||
1552 | PhysActor.delink(); | ||
1553 | |||
1554 | if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints && (!isNew)) | ||
1555 | { | ||
1556 | // destroy all joints connected to this now deactivated body | ||
1557 | m_parentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(PhysActor); | ||
1558 | } | ||
1559 | |||
1560 | // stop client-side interpolation of all joint proxy objects that have just been deleted | ||
1561 | // this is done because RemoveAllJointsConnectedToActor invokes the OnJointDeactivated callback, | ||
1562 | // which stops client-side interpolation of deactivated joint proxy objects. | ||
1563 | } | ||
1564 | |||
1565 | if (!UsePhysics && !isNew) | ||
1566 | { | ||
1567 | // reset velocity to 0 on physics switch-off. Without that, the client thinks the | ||
1568 | // prim still has velocity and continues to interpolate its position along the old | ||
1569 | // velocity-vector. | ||
1570 | Velocity = new Vector3(0, 0, 0); | ||
1571 | Acceleration = new Vector3(0, 0, 0); | ||
1572 | AngularVelocity = new Vector3(0, 0, 0); | ||
1573 | //RotationalVelocity = new Vector3(0, 0, 0); | ||
1574 | } | ||
1575 | |||
1576 | PhysActor.IsPhysical = UsePhysics; | ||
1577 | |||
1578 | |||
1579 | // If we're not what we're supposed to be in the physics scene, recreate ourselves. | ||
1580 | //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); | ||
1581 | /// that's not wholesome. Had to make Scene public | ||
1582 | //PhysActor = null; | ||
1583 | |||
1584 | if ((ObjectFlags & (uint)PrimFlags.Phantom) == 0) | ||
1585 | { | ||
1586 | if (UsePhysics) | ||
1587 | { | ||
1588 | ParentGroup.Scene.AddPhysicalPrim(1); | ||
1589 | |||
1590 | PhysActor.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; | ||
1591 | PhysActor.OnOutOfBounds += PhysicsOutOfBounds; | ||
1592 | if (_parentID != 0 && _parentID != LocalId) | ||
1593 | { | ||
1594 | if (ParentGroup.RootPart.PhysActor != null) | ||
1595 | { | ||
1596 | PhysActor.link(ParentGroup.RootPart.PhysActor); | ||
1597 | } | ||
1598 | } | ||
1599 | } | ||
1600 | } | ||
1601 | } | ||
1602 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
1603 | } | ||
1604 | } | ||
1605 | } | ||
1606 | |||
1607 | /// <summary> | ||
1608 | /// Restore this part from the serialized xml representation. | ||
1609 | /// </summary> | ||
1610 | /// <param name="xmlReader"></param> | ||
1611 | /// <returns></returns> | ||
1612 | public static SceneObjectPart FromXml(XmlReader xmlReader) | ||
1613 | { | ||
1614 | return FromXml(UUID.Zero, xmlReader); | ||
1615 | } | ||
1616 | |||
1617 | /// <summary> | ||
1618 | /// Restore this part from the serialized xml representation. | ||
1619 | /// </summary> | ||
1620 | /// <param name="fromUserInventoryItemId">The inventory id from which this part came, if applicable</param> | ||
1621 | /// <param name="xmlReader"></param> | ||
1622 | /// <returns></returns> | ||
1623 | public static SceneObjectPart FromXml(UUID fromUserInventoryItemId, XmlReader xmlReader) | ||
1624 | { | ||
1625 | SceneObjectPart part = (SceneObjectPart)serializer.Deserialize(xmlReader); | ||
1626 | part.m_fromUserInventoryItemID = fromUserInventoryItemId; | ||
1627 | |||
1628 | // for tempOnRez objects, we have to fix the Expire date. | ||
1629 | if ((part.Flags & PrimFlags.TemporaryOnRez) != 0) part.ResetExpire(); | ||
1630 | |||
1631 | return part; | ||
1632 | } | ||
1633 | |||
1634 | public UUID GetAvatarOnSitTarget() | ||
1635 | { | ||
1636 | return m_sitTargetAvatar; | ||
1637 | } | ||
1638 | |||
1639 | public bool GetDieAtEdge() | ||
1640 | { | ||
1641 | if (m_parentGroup == null) | ||
1642 | return false; | ||
1643 | if (m_parentGroup.IsDeleted) | ||
1644 | return false; | ||
1645 | |||
1646 | return m_parentGroup.RootPart.DIE_AT_EDGE; | ||
1647 | } | ||
1648 | |||
1649 | public double GetDistanceTo(Vector3 a, Vector3 b) | ||
1650 | { | ||
1651 | float dx = a.X - b.X; | ||
1652 | float dy = a.Y - b.Y; | ||
1653 | float dz = a.Z - b.Z; | ||
1654 | return Math.Sqrt(dx * dx + dy * dy + dz * dz); | ||
1655 | } | ||
1656 | |||
1657 | public uint GetEffectiveObjectFlags() | ||
1658 | { | ||
1659 | PrimFlags f = _flags; | ||
1660 | if (m_parentGroup == null || m_parentGroup.RootPart == this) | ||
1661 | f &= ~(PrimFlags.Touch | PrimFlags.Money); | ||
1662 | |||
1663 | return (uint)_flags | (uint)LocalFlags; | ||
1664 | } | ||
1665 | |||
1666 | public Vector3 GetGeometricCenter() | ||
1667 | { | ||
1668 | if (PhysActor != null) | ||
1669 | { | ||
1670 | return new Vector3(PhysActor.CenterOfMass.X, PhysActor.CenterOfMass.Y, PhysActor.CenterOfMass.Z); | ||
1671 | } | ||
1672 | else | ||
1673 | { | ||
1674 | return new Vector3(0, 0, 0); | ||
1675 | } | ||
1676 | } | ||
1677 | |||
1678 | public float GetMass() | ||
1679 | { | ||
1680 | if (PhysActor != null) | ||
1681 | { | ||
1682 | return PhysActor.Mass; | ||
1683 | } | ||
1684 | else | ||
1685 | { | ||
1686 | return 0; | ||
1687 | } | ||
1688 | } | ||
1689 | |||
1690 | public PhysicsVector GetForce() | ||
1691 | { | ||
1692 | if (PhysActor != null) | ||
1693 | return PhysActor.Force; | ||
1694 | else | ||
1695 | return new PhysicsVector(); | ||
1696 | } | ||
1697 | |||
1698 | [SecurityPermission(SecurityAction.LinkDemand, | ||
1699 | Flags = SecurityPermissionFlag.SerializationFormatter)] | ||
1700 | public virtual void GetObjectData( | ||
1701 | SerializationInfo info, StreamingContext context) | ||
1702 | { | ||
1703 | if (info == null) | ||
1704 | { | ||
1705 | throw new ArgumentNullException("info"); | ||
1706 | } | ||
1707 | |||
1708 | info.AddValue("m_inventoryFileName", Inventory.GetInventoryFileName()); | ||
1709 | info.AddValue("m_folderID", UUID); | ||
1710 | info.AddValue("PhysActor", PhysActor); | ||
1711 | |||
1712 | Dictionary<Guid, TaskInventoryItem> TaskInventory_work = new Dictionary<Guid, TaskInventoryItem>(); | ||
1713 | |||
1714 | foreach (UUID id in TaskInventory.Keys) | ||
1715 | { | ||
1716 | TaskInventory_work.Add(id.Guid, TaskInventory[id]); | ||
1717 | } | ||
1718 | |||
1719 | info.AddValue("TaskInventory", TaskInventory_work); | ||
1720 | |||
1721 | info.AddValue("LastOwnerID", _lastOwnerID.Guid); | ||
1722 | info.AddValue("OwnerID", _ownerID.Guid); | ||
1723 | info.AddValue("GroupID", _groupID.Guid); | ||
1724 | |||
1725 | info.AddValue("OwnershipCost", _ownershipCost); | ||
1726 | info.AddValue("ObjectSaleType", _objectSaleType); | ||
1727 | info.AddValue("SalePrice", _salePrice); | ||
1728 | info.AddValue("Category", _category); | ||
1729 | |||
1730 | info.AddValue("CreationDate", _creationDate); | ||
1731 | info.AddValue("ParentID", _parentID); | ||
1732 | |||
1733 | info.AddValue("OwnerMask", _ownerMask); | ||
1734 | info.AddValue("NextOwnerMask", _nextOwnerMask); | ||
1735 | info.AddValue("GroupMask", _groupMask); | ||
1736 | info.AddValue("EveryoneMask", _everyoneMask); | ||
1737 | info.AddValue("BaseMask", _baseMask); | ||
1738 | |||
1739 | info.AddValue("m_particleSystem", m_particleSystem); | ||
1740 | |||
1741 | info.AddValue("TimeStampFull", TimeStampFull); | ||
1742 | info.AddValue("TimeStampTerse", TimeStampTerse); | ||
1743 | info.AddValue("TimeStampLastActivity", TimeStampLastActivity); | ||
1744 | |||
1745 | info.AddValue("m_updateFlag", m_updateFlag); | ||
1746 | info.AddValue("CreatorID", _creatorID.Guid); | ||
1747 | |||
1748 | info.AddValue("m_inventorySerial", m_inventory.Serial); | ||
1749 | info.AddValue("m_uuid", m_uuid.Guid); | ||
1750 | info.AddValue("m_localID", m_localId); | ||
1751 | info.AddValue("m_name", m_name); | ||
1752 | info.AddValue("m_flags", _flags); | ||
1753 | info.AddValue("m_material", m_material); | ||
1754 | info.AddValue("m_regionHandle", m_regionHandle); | ||
1755 | |||
1756 | info.AddValue("m_groupPosition.X", m_groupPosition.X); | ||
1757 | info.AddValue("m_groupPosition.Y", m_groupPosition.Y); | ||
1758 | info.AddValue("m_groupPosition.Z", m_groupPosition.Z); | ||
1759 | |||
1760 | info.AddValue("m_offsetPosition.X", m_offsetPosition.X); | ||
1761 | info.AddValue("m_offsetPosition.Y", m_offsetPosition.Y); | ||
1762 | info.AddValue("m_offsetPosition.Z", m_offsetPosition.Z); | ||
1763 | |||
1764 | info.AddValue("m_rotationOffset.W", m_rotationOffset.W); | ||
1765 | info.AddValue("m_rotationOffset.X", m_rotationOffset.X); | ||
1766 | info.AddValue("m_rotationOffset.Y", m_rotationOffset.Y); | ||
1767 | info.AddValue("m_rotationOffset.Z", m_rotationOffset.Z); | ||
1768 | |||
1769 | info.AddValue("m_velocity.X", m_velocity.X); | ||
1770 | info.AddValue("m_velocity.Y", m_velocity.Y); | ||
1771 | info.AddValue("m_velocity.Z", m_velocity.Z); | ||
1772 | |||
1773 | info.AddValue("m_rotationalvelocity.X", RotationalVelocity.X); | ||
1774 | info.AddValue("m_rotationalvelocity.Y", RotationalVelocity.Y); | ||
1775 | info.AddValue("m_rotationalvelocity.Z", RotationalVelocity.Z); | ||
1776 | |||
1777 | info.AddValue("m_angularVelocity.X", m_angularVelocity.X); | ||
1778 | info.AddValue("m_angularVelocity.Y", m_angularVelocity.Y); | ||
1779 | info.AddValue("m_angularVelocity.Z", m_angularVelocity.Z); | ||
1780 | |||
1781 | info.AddValue("m_acceleration.X", m_acceleration.X); | ||
1782 | info.AddValue("m_acceleration.Y", m_acceleration.Y); | ||
1783 | info.AddValue("m_acceleration.Z", m_acceleration.Z); | ||
1784 | |||
1785 | info.AddValue("m_description", m_description); | ||
1786 | info.AddValue("m_color", m_color); | ||
1787 | info.AddValue("m_text", m_text); | ||
1788 | info.AddValue("m_sitName", m_sitName); | ||
1789 | info.AddValue("m_touchName", m_touchName); | ||
1790 | info.AddValue("m_clickAction", m_clickAction); | ||
1791 | info.AddValue("m_shape", m_shape); | ||
1792 | info.AddValue("m_parentGroup", m_parentGroup); | ||
1793 | info.AddValue("PayPrice", PayPrice); | ||
1794 | } | ||
1795 | |||
1796 | public void GetProperties(IClientAPI client) | ||
1797 | { | ||
1798 | client.SendObjectPropertiesReply( | ||
1799 | m_fromUserInventoryItemID, (ulong)_creationDate, _creatorID, UUID.Zero, UUID.Zero, | ||
1800 | _groupID, (short)InventorySerial, _lastOwnerID, UUID, _ownerID, | ||
1801 | ParentGroup.RootPart.TouchName, new byte[0], ParentGroup.RootPart.SitName, Name, Description, | ||
1802 | ParentGroup.RootPart._ownerMask, ParentGroup.RootPart._nextOwnerMask, ParentGroup.RootPart._groupMask, ParentGroup.RootPart._everyoneMask, | ||
1803 | ParentGroup.RootPart._baseMask, | ||
1804 | ParentGroup.RootPart.ObjectSaleType, | ||
1805 | ParentGroup.RootPart.SalePrice); | ||
1806 | } | ||
1807 | |||
1808 | public UUID GetRootPartUUID() | ||
1809 | { | ||
1810 | if (m_parentGroup != null) | ||
1811 | { | ||
1812 | return m_parentGroup.UUID; | ||
1813 | } | ||
1814 | return UUID.Zero; | ||
1815 | } | ||
1816 | |||
1817 | /// <summary> | ||
1818 | /// Method for a prim to get it's world position from the group. | ||
1819 | /// Remember, the Group Position simply gives the position of the group itself | ||
1820 | /// </summary> | ||
1821 | /// <returns>A Linked Child Prim objects position in world</returns> | ||
1822 | public Vector3 GetWorldPosition() | ||
1823 | { | ||
1824 | Quaternion parentRot = ParentGroup.RootPart.RotationOffset; | ||
1825 | |||
1826 | Vector3 axPos = OffsetPosition; | ||
1827 | |||
1828 | axPos *= parentRot; | ||
1829 | Vector3 translationOffsetPosition = axPos; | ||
1830 | return GroupPosition + translationOffsetPosition; | ||
1831 | } | ||
1832 | |||
1833 | /// <summary> | ||
1834 | /// Gets the rotation of this prim offset by the group rotation | ||
1835 | /// </summary> | ||
1836 | /// <returns></returns> | ||
1837 | public Quaternion GetWorldRotation() | ||
1838 | { | ||
1839 | Quaternion newRot; | ||
1840 | |||
1841 | if (this.LinkNum == 0) | ||
1842 | { | ||
1843 | newRot = RotationOffset; | ||
1844 | } | ||
1845 | else | ||
1846 | { | ||
1847 | Quaternion parentRot = ParentGroup.RootPart.RotationOffset; | ||
1848 | Quaternion oldRot = RotationOffset; | ||
1849 | newRot = parentRot * oldRot; | ||
1850 | } | ||
1851 | |||
1852 | return newRot; | ||
1853 | } | ||
1854 | |||
1855 | public void MoveToTarget(Vector3 target, float tau) | ||
1856 | { | ||
1857 | if (tau > 0) | ||
1858 | { | ||
1859 | m_parentGroup.moveToTarget(target, tau); | ||
1860 | } | ||
1861 | else | ||
1862 | { | ||
1863 | StopMoveToTarget(); | ||
1864 | } | ||
1865 | } | ||
1866 | |||
1867 | public virtual void OnGrab(Vector3 offsetPos, IClientAPI remoteClient) | ||
1868 | { | ||
1869 | } | ||
1870 | |||
1871 | public void PhysicsCollision(EventArgs e) | ||
1872 | { | ||
1873 | // single threaded here | ||
1874 | if (e == null) | ||
1875 | { | ||
1876 | return; | ||
1877 | } | ||
1878 | |||
1879 | CollisionEventUpdate a = (CollisionEventUpdate)e; | ||
1880 | Dictionary<uint, float> collissionswith = a.m_objCollisionList; | ||
1881 | List<uint> thisHitColliders = new List<uint>(); | ||
1882 | List<uint> endedColliders = new List<uint>(); | ||
1883 | List<uint> startedColliders = new List<uint>(); | ||
1884 | |||
1885 | // calculate things that started colliding this time | ||
1886 | // and build up list of colliders this time | ||
1887 | foreach (uint localid in collissionswith.Keys) | ||
1888 | { | ||
1889 | if (localid != 0) | ||
1890 | { | ||
1891 | thisHitColliders.Add(localid); | ||
1892 | if (!m_lastColliders.Contains(localid)) | ||
1893 | { | ||
1894 | startedColliders.Add(localid); | ||
1895 | } | ||
1896 | |||
1897 | //m_log.Debug("[OBJECT]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString()); | ||
1898 | } | ||
1899 | } | ||
1900 | |||
1901 | // calculate things that ended colliding | ||
1902 | foreach (uint localID in m_lastColliders) | ||
1903 | { | ||
1904 | if (!thisHitColliders.Contains(localID)) | ||
1905 | { | ||
1906 | endedColliders.Add(localID); | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | //add the items that started colliding this time to the last colliders list. | ||
1911 | foreach (uint localID in startedColliders) | ||
1912 | { | ||
1913 | m_lastColliders.Add(localID); | ||
1914 | } | ||
1915 | // remove things that ended colliding from the last colliders list | ||
1916 | foreach (uint localID in endedColliders) | ||
1917 | { | ||
1918 | m_lastColliders.Remove(localID); | ||
1919 | } | ||
1920 | if (m_parentGroup == null) | ||
1921 | return; | ||
1922 | if (m_parentGroup.IsDeleted) | ||
1923 | return; | ||
1924 | |||
1925 | // play the sound. | ||
1926 | if (startedColliders.Count > 0 && CollisionSound != UUID.Zero && CollisionSoundVolume > 0.0f) | ||
1927 | { | ||
1928 | SendSound(CollisionSound.ToString(), CollisionSoundVolume, true, (byte)0); | ||
1929 | } | ||
1930 | |||
1931 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision_start) != 0) | ||
1932 | { | ||
1933 | // do event notification | ||
1934 | if (startedColliders.Count > 0) | ||
1935 | { | ||
1936 | ColliderArgs StartCollidingMessage = new ColliderArgs(); | ||
1937 | List<DetectedObject> colliding = new List<DetectedObject>(); | ||
1938 | foreach (uint localId in startedColliders) | ||
1939 | { | ||
1940 | // always running this check because if the user deletes the object it would return a null reference. | ||
1941 | if (m_parentGroup == null) | ||
1942 | return; | ||
1943 | if (m_parentGroup.Scene == null) | ||
1944 | return; | ||
1945 | SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); | ||
1946 | if (obj != null) | ||
1947 | { | ||
1948 | DetectedObject detobj = new DetectedObject(); | ||
1949 | detobj.keyUUID = obj.UUID; | ||
1950 | detobj.nameStr = obj.Name; | ||
1951 | detobj.ownerUUID = obj._ownerID; | ||
1952 | detobj.posVector = obj.AbsolutePosition; | ||
1953 | detobj.rotQuat = obj.GetWorldRotation(); | ||
1954 | detobj.velVector = obj.Velocity; | ||
1955 | detobj.colliderType = 0; | ||
1956 | detobj.groupUUID = obj._groupID; | ||
1957 | colliding.Add(detobj); | ||
1958 | } | ||
1959 | else | ||
1960 | { | ||
1961 | List<ScenePresence> avlist = m_parentGroup.Scene.GetScenePresences(); | ||
1962 | if (avlist != null) | ||
1963 | { | ||
1964 | foreach (ScenePresence av in avlist) | ||
1965 | { | ||
1966 | if (av.LocalId == localId) | ||
1967 | { | ||
1968 | DetectedObject detobj = new DetectedObject(); | ||
1969 | detobj.keyUUID = av.UUID; | ||
1970 | detobj.nameStr = av.ControllingClient.Name; | ||
1971 | detobj.ownerUUID = av.UUID; | ||
1972 | detobj.posVector = av.AbsolutePosition; | ||
1973 | detobj.rotQuat = av.Rotation; | ||
1974 | detobj.velVector = av.Velocity; | ||
1975 | detobj.colliderType = 0; | ||
1976 | detobj.groupUUID = av.ControllingClient.ActiveGroupId; | ||
1977 | colliding.Add(detobj); | ||
1978 | } | ||
1979 | } | ||
1980 | } | ||
1981 | } | ||
1982 | } | ||
1983 | if (colliding.Count > 0) | ||
1984 | { | ||
1985 | StartCollidingMessage.Colliders = colliding; | ||
1986 | // always running this check because if the user deletes the object it would return a null reference. | ||
1987 | if (m_parentGroup == null) | ||
1988 | return; | ||
1989 | if (m_parentGroup.Scene == null) | ||
1990 | return; | ||
1991 | m_parentGroup.Scene.EventManager.TriggerScriptCollidingStart(LocalId, StartCollidingMessage); | ||
1992 | } | ||
1993 | } | ||
1994 | } | ||
1995 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision) != 0) | ||
1996 | { | ||
1997 | if (m_lastColliders.Count > 0) | ||
1998 | { | ||
1999 | ColliderArgs CollidingMessage = new ColliderArgs(); | ||
2000 | List<DetectedObject> colliding = new List<DetectedObject>(); | ||
2001 | foreach (uint localId in m_lastColliders) | ||
2002 | { | ||
2003 | // always running this check because if the user deletes the object it would return a null reference. | ||
2004 | if (localId == 0) | ||
2005 | continue; | ||
2006 | |||
2007 | if (m_parentGroup == null) | ||
2008 | return; | ||
2009 | if (m_parentGroup.Scene == null) | ||
2010 | return; | ||
2011 | SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); | ||
2012 | if (obj != null) | ||
2013 | { | ||
2014 | DetectedObject detobj = new DetectedObject(); | ||
2015 | detobj.keyUUID = obj.UUID; | ||
2016 | detobj.nameStr = obj.Name; | ||
2017 | detobj.ownerUUID = obj._ownerID; | ||
2018 | detobj.posVector = obj.AbsolutePosition; | ||
2019 | detobj.rotQuat = obj.GetWorldRotation(); | ||
2020 | detobj.velVector = obj.Velocity; | ||
2021 | detobj.colliderType = 0; | ||
2022 | detobj.groupUUID = obj._groupID; | ||
2023 | colliding.Add(detobj); | ||
2024 | } | ||
2025 | else | ||
2026 | { | ||
2027 | List<ScenePresence> avlist = m_parentGroup.Scene.GetScenePresences(); | ||
2028 | if (avlist != null) | ||
2029 | { | ||
2030 | foreach (ScenePresence av in avlist) | ||
2031 | { | ||
2032 | if (av.LocalId == localId) | ||
2033 | { | ||
2034 | DetectedObject detobj = new DetectedObject(); | ||
2035 | detobj.keyUUID = av.UUID; | ||
2036 | detobj.nameStr = av.Name; | ||
2037 | detobj.ownerUUID = av.UUID; | ||
2038 | detobj.posVector = av.AbsolutePosition; | ||
2039 | detobj.rotQuat = av.Rotation; | ||
2040 | detobj.velVector = av.Velocity; | ||
2041 | detobj.colliderType = 0; | ||
2042 | detobj.groupUUID = av.ControllingClient.ActiveGroupId; | ||
2043 | colliding.Add(detobj); | ||
2044 | } | ||
2045 | } | ||
2046 | |||
2047 | } | ||
2048 | } | ||
2049 | } | ||
2050 | if (colliding.Count > 0) | ||
2051 | { | ||
2052 | CollidingMessage.Colliders = colliding; | ||
2053 | // always running this check because if the user deletes the object it would return a null reference. | ||
2054 | if (m_parentGroup == null) | ||
2055 | return; | ||
2056 | if (m_parentGroup.Scene == null) | ||
2057 | return; | ||
2058 | m_parentGroup.Scene.EventManager.TriggerScriptColliding(LocalId, CollidingMessage); | ||
2059 | } | ||
2060 | |||
2061 | } | ||
2062 | } | ||
2063 | if ((m_parentGroup.RootPart.ScriptEvents & scriptEvents.collision_end) != 0) | ||
2064 | { | ||
2065 | if (endedColliders.Count > 0) | ||
2066 | { | ||
2067 | ColliderArgs EndCollidingMessage = new ColliderArgs(); | ||
2068 | List<DetectedObject> colliding = new List<DetectedObject>(); | ||
2069 | foreach (uint localId in endedColliders) | ||
2070 | { | ||
2071 | if (localId == 0) | ||
2072 | continue; | ||
2073 | |||
2074 | // always running this check because if the user deletes the object it would return a null reference. | ||
2075 | if (m_parentGroup == null) | ||
2076 | return; | ||
2077 | if (m_parentGroup.Scene == null) | ||
2078 | return; | ||
2079 | SceneObjectPart obj = m_parentGroup.Scene.GetSceneObjectPart(localId); | ||
2080 | if (obj != null) | ||
2081 | { | ||
2082 | DetectedObject detobj = new DetectedObject(); | ||
2083 | detobj.keyUUID = obj.UUID; | ||
2084 | detobj.nameStr = obj.Name; | ||
2085 | detobj.ownerUUID = obj._ownerID; | ||
2086 | detobj.posVector = obj.AbsolutePosition; | ||
2087 | detobj.rotQuat = obj.GetWorldRotation(); | ||
2088 | detobj.velVector = obj.Velocity; | ||
2089 | detobj.colliderType = 0; | ||
2090 | detobj.groupUUID = obj._groupID; | ||
2091 | colliding.Add(detobj); | ||
2092 | } | ||
2093 | else | ||
2094 | { | ||
2095 | List<ScenePresence> avlist = m_parentGroup.Scene.GetScenePresences(); | ||
2096 | if (avlist != null) | ||
2097 | { | ||
2098 | foreach (ScenePresence av in avlist) | ||
2099 | { | ||
2100 | if (av.LocalId == localId) | ||
2101 | { | ||
2102 | DetectedObject detobj = new DetectedObject(); | ||
2103 | detobj.keyUUID = av.UUID; | ||
2104 | detobj.nameStr = av.Name; | ||
2105 | detobj.ownerUUID = av.UUID; | ||
2106 | detobj.posVector = av.AbsolutePosition; | ||
2107 | detobj.rotQuat = av.Rotation; | ||
2108 | detobj.velVector = av.Velocity; | ||
2109 | detobj.colliderType = 0; | ||
2110 | detobj.groupUUID = av.ControllingClient.ActiveGroupId; | ||
2111 | colliding.Add(detobj); | ||
2112 | } | ||
2113 | } | ||
2114 | |||
2115 | } | ||
2116 | } | ||
2117 | } | ||
2118 | if (colliding.Count > 0) | ||
2119 | { | ||
2120 | EndCollidingMessage.Colliders = colliding; | ||
2121 | // always running this check because if the user deletes the object it would return a null reference. | ||
2122 | if (m_parentGroup == null) | ||
2123 | return; | ||
2124 | if (m_parentGroup.Scene == null) | ||
2125 | return; | ||
2126 | m_parentGroup.Scene.EventManager.TriggerScriptCollidingEnd(LocalId, EndCollidingMessage); | ||
2127 | } | ||
2128 | |||
2129 | } | ||
2130 | } | ||
2131 | } | ||
2132 | |||
2133 | public void PhysicsOutOfBounds(PhysicsVector pos) | ||
2134 | { | ||
2135 | m_log.Info("[PHYSICS]: Physical Object went out of bounds."); | ||
2136 | RemFlag(PrimFlags.Physics); | ||
2137 | DoPhysicsPropertyUpdate(false, true); | ||
2138 | //m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
2139 | } | ||
2140 | |||
2141 | public void PhysicsRequestingTerseUpdate() | ||
2142 | { | ||
2143 | if (PhysActor != null) | ||
2144 | { | ||
2145 | Vector3 newpos = new Vector3(PhysActor.Position.GetBytes(), 0); | ||
2146 | if (newpos.X > 257f || newpos.X < -1f || newpos.Y > 257f || newpos.Y < -1f) | ||
2147 | { | ||
2148 | m_parentGroup.AbsolutePosition = newpos; | ||
2149 | return; | ||
2150 | } | ||
2151 | } | ||
2152 | ScheduleTerseUpdate(); | ||
2153 | |||
2154 | //SendTerseUpdateToAllClients(); | ||
2155 | } | ||
2156 | |||
2157 | public void PreloadSound(string sound) | ||
2158 | { | ||
2159 | // UUID ownerID = OwnerID; | ||
2160 | UUID objectID = UUID; | ||
2161 | UUID soundID = UUID.Zero; | ||
2162 | |||
2163 | if (!UUID.TryParse(sound, out soundID)) | ||
2164 | { | ||
2165 | //Trys to fetch sound id from prim's inventory. | ||
2166 | //Prim's inventory doesn't support non script items yet | ||
2167 | SceneObjectPart op = this; | ||
2168 | foreach (KeyValuePair<UUID, TaskInventoryItem> item in op.TaskInventory) | ||
2169 | { | ||
2170 | if (item.Value.Name == sound) | ||
2171 | { | ||
2172 | soundID = item.Value.ItemID; | ||
2173 | break; | ||
2174 | } | ||
2175 | } | ||
2176 | } | ||
2177 | |||
2178 | List<ScenePresence> avatarts = m_parentGroup.Scene.GetAvatars(); | ||
2179 | foreach (ScenePresence p in avatarts) | ||
2180 | { | ||
2181 | // TODO: some filtering by distance of avatar | ||
2182 | |||
2183 | p.ControllingClient.SendPreLoadSound(objectID, objectID, soundID); | ||
2184 | } | ||
2185 | } | ||
2186 | |||
2187 | public void RemFlag(PrimFlags flag) | ||
2188 | { | ||
2189 | // PrimFlags prevflag = Flags; | ||
2190 | if ((ObjectFlags & (uint) flag) != 0) | ||
2191 | { | ||
2192 | //Console.WriteLine("Removing flag: " + ((PrimFlags)flag).ToString()); | ||
2193 | _flags &= ~flag; | ||
2194 | } | ||
2195 | //System.Console.WriteLine("prev: " + prevflag.ToString() + " curr: " + Flags.ToString()); | ||
2196 | //ScheduleFullUpdate(); | ||
2197 | } | ||
2198 | |||
2199 | public void RemoveScriptEvents(UUID scriptid) | ||
2200 | { | ||
2201 | lock (m_scriptEvents) | ||
2202 | { | ||
2203 | if (m_scriptEvents.ContainsKey(scriptid)) | ||
2204 | { | ||
2205 | scriptEvents oldparts = scriptEvents.None; | ||
2206 | oldparts = (scriptEvents) m_scriptEvents[scriptid]; | ||
2207 | |||
2208 | // remove values from aggregated script events | ||
2209 | AggregateScriptEvents &= ~oldparts; | ||
2210 | m_scriptEvents.Remove(scriptid); | ||
2211 | aggregateScriptEvents(); | ||
2212 | } | ||
2213 | } | ||
2214 | } | ||
2215 | |||
2216 | /// <summary> | ||
2217 | /// Reset UUIDs for this part. This involves generate this part's own UUID and | ||
2218 | /// generating new UUIDs for all the items in the inventory. | ||
2219 | /// </summary> | ||
2220 | /// <param name="linkNum">Link number for the part</param> | ||
2221 | public void ResetIDs(int linkNum) | ||
2222 | { | ||
2223 | UUID = UUID.Random(); | ||
2224 | LinkNum = linkNum; | ||
2225 | LocalId = 0; | ||
2226 | Inventory.ResetInventoryIDs(); | ||
2227 | } | ||
2228 | |||
2229 | /// <summary> | ||
2230 | /// Resize this part. | ||
2231 | /// </summary> | ||
2232 | /// <param name="scale"></param> | ||
2233 | public void Resize(Vector3 scale) | ||
2234 | { | ||
2235 | StoreUndoState(); | ||
2236 | m_shape.Scale = scale; | ||
2237 | |||
2238 | ParentGroup.HasGroupChanged = true; | ||
2239 | ScheduleFullUpdate(); | ||
2240 | } | ||
2241 | |||
2242 | /// <summary> | ||
2243 | /// Schedules this prim for a full update | ||
2244 | /// </summary> | ||
2245 | public void ScheduleFullUpdate() | ||
2246 | { | ||
2247 | if (m_parentGroup != null) | ||
2248 | { | ||
2249 | m_parentGroup.QueueForUpdateCheck(); | ||
2250 | } | ||
2251 | |||
2252 | int timeNow = Util.UnixTimeSinceEpoch(); | ||
2253 | |||
2254 | // If multiple updates are scheduled on the same second, we still need to perform all of them | ||
2255 | // So we'll force the issue by bumping up the timestamp so that later processing sees these need | ||
2256 | // to be performed. | ||
2257 | if (timeNow <= TimeStampFull) | ||
2258 | { | ||
2259 | TimeStampFull += 1; | ||
2260 | } | ||
2261 | else | ||
2262 | { | ||
2263 | TimeStampFull = (uint)timeNow; | ||
2264 | } | ||
2265 | |||
2266 | m_updateFlag = 2; | ||
2267 | |||
2268 | // m_log.DebugFormat( | ||
2269 | // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}", | ||
2270 | // UUID, Name, TimeStampFull); | ||
2271 | } | ||
2272 | |||
2273 | /// <summary> | ||
2274 | /// Schedule a terse update for this prim. Terse updates only send position, | ||
2275 | /// rotation, velocity, rotational velocity and shape information. | ||
2276 | /// </summary> | ||
2277 | public void ScheduleTerseUpdate() | ||
2278 | { | ||
2279 | if (m_updateFlag < 1) | ||
2280 | { | ||
2281 | if (m_parentGroup != null) | ||
2282 | { | ||
2283 | m_parentGroup.HasGroupChanged = true; | ||
2284 | m_parentGroup.QueueForUpdateCheck(); | ||
2285 | } | ||
2286 | TimeStampTerse = (uint) Util.UnixTimeSinceEpoch(); | ||
2287 | m_updateFlag = 1; | ||
2288 | |||
2289 | // m_log.DebugFormat( | ||
2290 | // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}", | ||
2291 | // UUID, Name, TimeStampTerse); | ||
2292 | } | ||
2293 | } | ||
2294 | |||
2295 | public void ScriptSetPhantomStatus(bool Phantom) | ||
2296 | { | ||
2297 | if (m_parentGroup != null) | ||
2298 | { | ||
2299 | m_parentGroup.ScriptSetPhantomStatus(Phantom); | ||
2300 | } | ||
2301 | } | ||
2302 | |||
2303 | public void ScriptSetTemporaryStatus(bool Temporary) | ||
2304 | { | ||
2305 | if (m_parentGroup != null) | ||
2306 | { | ||
2307 | m_parentGroup.ScriptSetTemporaryStatus(Temporary); | ||
2308 | } | ||
2309 | } | ||
2310 | |||
2311 | public void ScriptSetPhysicsStatus(bool UsePhysics) | ||
2312 | { | ||
2313 | if (m_parentGroup == null) | ||
2314 | DoPhysicsPropertyUpdate(UsePhysics, false); | ||
2315 | else | ||
2316 | m_parentGroup.ScriptSetPhysicsStatus(UsePhysics); | ||
2317 | } | ||
2318 | |||
2319 | public void ScriptSetVolumeDetect(bool SetVD) | ||
2320 | { | ||
2321 | |||
2322 | if (m_parentGroup != null) | ||
2323 | { | ||
2324 | m_parentGroup.ScriptSetVolumeDetect(SetVD); | ||
2325 | } | ||
2326 | } | ||
2327 | |||
2328 | |||
2329 | public void SculptTextureCallback(UUID textureID, AssetBase texture) | ||
2330 | { | ||
2331 | if (m_shape.SculptEntry) | ||
2332 | { | ||
2333 | if (texture != null) | ||
2334 | { | ||
2335 | m_shape.SculptData = texture.Data; | ||
2336 | if (PhysActor != null) | ||
2337 | { | ||
2338 | // Tricks physics engine into thinking we've changed the part shape. | ||
2339 | PrimitiveBaseShape m_newshape = m_shape.Copy(); | ||
2340 | PhysActor.Shape = m_newshape; | ||
2341 | m_shape = m_newshape; | ||
2342 | |||
2343 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
2344 | } | ||
2345 | } | ||
2346 | } | ||
2347 | } | ||
2348 | |||
2349 | /// <summary> | ||
2350 | /// | ||
2351 | /// </summary> | ||
2352 | /// <param name="remoteClient"></param> | ||
2353 | public void SendFullUpdate(IClientAPI remoteClient, uint clientFlags) | ||
2354 | { | ||
2355 | m_parentGroup.SendPartFullUpdate(remoteClient, this, clientFlags); | ||
2356 | } | ||
2357 | |||
2358 | /// <summary> | ||
2359 | /// | ||
2360 | /// </summary> | ||
2361 | public void SendFullUpdateToAllClients() | ||
2362 | { | ||
2363 | List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); | ||
2364 | for (int i = 0; i < avatars.Count; i++) | ||
2365 | { | ||
2366 | // Ugly reference :( | ||
2367 | m_parentGroup.SendPartFullUpdate(avatars[i].ControllingClient, this, | ||
2368 | avatars[i].GenerateClientFlags(UUID)); | ||
2369 | } | ||
2370 | } | ||
2371 | |||
2372 | public void SendFullUpdateToAllClientsExcept(UUID agentID) | ||
2373 | { | ||
2374 | List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); | ||
2375 | for (int i = 0; i < avatars.Count; i++) | ||
2376 | { | ||
2377 | // Ugly reference :( | ||
2378 | if (avatars[i].UUID != agentID) | ||
2379 | { | ||
2380 | m_parentGroup.SendPartFullUpdate(avatars[i].ControllingClient, this, | ||
2381 | avatars[i].GenerateClientFlags(UUID)); | ||
2382 | } | ||
2383 | } | ||
2384 | } | ||
2385 | |||
2386 | /// <summary> | ||
2387 | /// Sends a full update to the client | ||
2388 | /// </summary> | ||
2389 | /// <param name="remoteClient"></param> | ||
2390 | /// <param name="clientFlags"></param> | ||
2391 | public void SendFullUpdateToClient(IClientAPI remoteClient, uint clientflags) | ||
2392 | { | ||
2393 | Vector3 lPos; | ||
2394 | lPos = OffsetPosition; | ||
2395 | SendFullUpdateToClient(remoteClient, lPos, clientflags); | ||
2396 | } | ||
2397 | |||
2398 | /// <summary> | ||
2399 | /// Sends a full update to the client | ||
2400 | /// </summary> | ||
2401 | /// <param name="remoteClient"></param> | ||
2402 | /// <param name="lPos"></param> | ||
2403 | /// <param name="clientFlags"></param> | ||
2404 | public void SendFullUpdateToClient(IClientAPI remoteClient, Vector3 lPos, uint clientFlags) | ||
2405 | { | ||
2406 | // Suppress full updates during attachment editing | ||
2407 | // | ||
2408 | if (ParentGroup.IsSelected && IsAttachment) | ||
2409 | return; | ||
2410 | |||
2411 | if (ParentGroup.IsDeleted) | ||
2412 | return; | ||
2413 | |||
2414 | clientFlags &= ~(uint) PrimFlags.CreateSelected; | ||
2415 | |||
2416 | if (remoteClient.AgentId == _ownerID) | ||
2417 | { | ||
2418 | if ((uint) (_flags & PrimFlags.CreateSelected) != 0) | ||
2419 | { | ||
2420 | clientFlags |= (uint) PrimFlags.CreateSelected; | ||
2421 | _flags &= ~PrimFlags.CreateSelected; | ||
2422 | } | ||
2423 | } | ||
2424 | //bool isattachment = IsAttachment; | ||
2425 | //if (LocalId != ParentGroup.RootPart.LocalId) | ||
2426 | //isattachment = ParentGroup.RootPart.IsAttachment; | ||
2427 | |||
2428 | byte[] color = new byte[] {m_color.R, m_color.G, m_color.B, m_color.A}; | ||
2429 | remoteClient.SendPrimitiveToClient(m_regionHandle, (ushort)(m_parentGroup.GetTimeDilation() * (float)ushort.MaxValue), LocalId, m_shape, | ||
2430 | lPos, Velocity, Acceleration, RotationOffset, RotationalVelocity, clientFlags, m_uuid, _ownerID, | ||
2431 | m_text, color, _parentID, m_particleSystem, m_clickAction, (byte)m_material, m_TextureAnimation, IsAttachment, | ||
2432 | AttachmentPoint,FromAssetID, Sound, SoundGain, SoundFlags, SoundRadius); | ||
2433 | } | ||
2434 | |||
2435 | /// <summary> | ||
2436 | /// Tell all the prims which have had updates scheduled | ||
2437 | /// </summary> | ||
2438 | public void SendScheduledUpdates() | ||
2439 | { | ||
2440 | if (m_updateFlag == 1) //some change has been made so update the clients | ||
2441 | { | ||
2442 | AddTerseUpdateToAllAvatars(); | ||
2443 | ClearUpdateSchedule(); | ||
2444 | |||
2445 | // This causes the Scene to 'poll' physical objects every couple of frames | ||
2446 | // bad, so it's been replaced by an event driven method. | ||
2447 | //if ((ObjectFlags & (uint)PrimFlags.Physics) != 0) | ||
2448 | //{ | ||
2449 | // Only send the constant terse updates on physical objects! | ||
2450 | //ScheduleTerseUpdate(); | ||
2451 | //} | ||
2452 | } | ||
2453 | else | ||
2454 | { | ||
2455 | if (m_updateFlag == 2) // is a new prim, just created/reloaded or has major changes | ||
2456 | { | ||
2457 | AddFullUpdateToAllAvatars(); | ||
2458 | ClearUpdateSchedule(); | ||
2459 | } | ||
2460 | } | ||
2461 | } | ||
2462 | |||
2463 | /// <summary> | ||
2464 | /// Trigger or play an attached sound in this part's inventory. | ||
2465 | /// </summary> | ||
2466 | /// <param name="sound"></param> | ||
2467 | /// <param name="volume"></param> | ||
2468 | /// <param name="triggered"></param> | ||
2469 | /// <param name="flags"></param> | ||
2470 | public void SendSound(string sound, double volume, bool triggered, byte flags) | ||
2471 | { | ||
2472 | if (volume > 1) | ||
2473 | volume = 1; | ||
2474 | if (volume < 0) | ||
2475 | volume = 0; | ||
2476 | |||
2477 | UUID ownerID = _ownerID; | ||
2478 | UUID objectID = UUID; | ||
2479 | UUID parentID = GetRootPartUUID(); | ||
2480 | UUID soundID = UUID.Zero; | ||
2481 | Vector3 position = AbsolutePosition; // region local | ||
2482 | ulong regionHandle = m_parentGroup.Scene.RegionInfo.RegionHandle; | ||
2483 | |||
2484 | if (!UUID.TryParse(sound, out soundID)) | ||
2485 | { | ||
2486 | // search sound file from inventory | ||
2487 | SceneObjectPart op = this; | ||
2488 | foreach (KeyValuePair<UUID, TaskInventoryItem> item in op.TaskInventory) | ||
2489 | { | ||
2490 | if (item.Value.Name == sound && item.Value.Type == (int)AssetType.Sound) | ||
2491 | { | ||
2492 | soundID = item.Value.ItemID; | ||
2493 | break; | ||
2494 | } | ||
2495 | } | ||
2496 | } | ||
2497 | |||
2498 | if (soundID == UUID.Zero) | ||
2499 | return; | ||
2500 | |||
2501 | ISoundModule soundModule = m_parentGroup.Scene.RequestModuleInterface<ISoundModule>(); | ||
2502 | if (soundModule != null) | ||
2503 | { | ||
2504 | if (triggered) | ||
2505 | soundModule.TriggerSound(soundID, ownerID, objectID, parentID, volume, position, regionHandle); | ||
2506 | else | ||
2507 | soundModule.PlayAttachedSound(soundID, ownerID, objectID, volume, position, flags); | ||
2508 | } | ||
2509 | } | ||
2510 | |||
2511 | /// <summary> | ||
2512 | /// Send a terse update to all clients | ||
2513 | /// </summary> | ||
2514 | public void SendTerseUpdateToAllClients() | ||
2515 | { | ||
2516 | List<ScenePresence> avatars = m_parentGroup.Scene.GetScenePresences(); | ||
2517 | for (int i = 0; i < avatars.Count; i++) | ||
2518 | { | ||
2519 | SendTerseUpdateToClient(avatars[i].ControllingClient); | ||
2520 | } | ||
2521 | } | ||
2522 | |||
2523 | public void SetAttachmentPoint(uint AttachmentPoint) | ||
2524 | { | ||
2525 | this.AttachmentPoint = AttachmentPoint; | ||
2526 | |||
2527 | if (AttachmentPoint != 0) | ||
2528 | { | ||
2529 | IsAttachment = true; | ||
2530 | } | ||
2531 | else | ||
2532 | { | ||
2533 | IsAttachment = false; | ||
2534 | } | ||
2535 | |||
2536 | // save the attachment point. | ||
2537 | //if (AttachmentPoint != 0) | ||
2538 | //{ | ||
2539 | m_shape.State = (byte)AttachmentPoint; | ||
2540 | //} | ||
2541 | } | ||
2542 | |||
2543 | public void SetAvatarOnSitTarget(UUID avatarID) | ||
2544 | { | ||
2545 | m_sitTargetAvatar = avatarID; | ||
2546 | if (ParentGroup != null) | ||
2547 | ParentGroup.TriggerScriptChangedEvent(Changed.LINK); | ||
2548 | } | ||
2549 | |||
2550 | public void SetAxisRotation(int axis, int rotate) | ||
2551 | { | ||
2552 | if (m_parentGroup != null) | ||
2553 | { | ||
2554 | m_parentGroup.SetAxisRotation(axis, rotate); | ||
2555 | } | ||
2556 | } | ||
2557 | |||
2558 | public void SetBuoyancy(float fvalue) | ||
2559 | { | ||
2560 | if (PhysActor != null) | ||
2561 | { | ||
2562 | PhysActor.Buoyancy = fvalue; | ||
2563 | } | ||
2564 | } | ||
2565 | |||
2566 | public void SetDieAtEdge(bool p) | ||
2567 | { | ||
2568 | if (m_parentGroup == null) | ||
2569 | return; | ||
2570 | if (m_parentGroup.IsDeleted) | ||
2571 | return; | ||
2572 | |||
2573 | m_parentGroup.RootPart.DIE_AT_EDGE = p; | ||
2574 | } | ||
2575 | |||
2576 | public void SetFloatOnWater(int floatYN) | ||
2577 | { | ||
2578 | if (PhysActor != null) | ||
2579 | { | ||
2580 | if (floatYN == 1) | ||
2581 | { | ||
2582 | PhysActor.FloatOnWater = true; | ||
2583 | } | ||
2584 | else | ||
2585 | { | ||
2586 | PhysActor.FloatOnWater = false; | ||
2587 | } | ||
2588 | } | ||
2589 | } | ||
2590 | |||
2591 | public void SetForce(PhysicsVector force) | ||
2592 | { | ||
2593 | if (PhysActor != null) | ||
2594 | { | ||
2595 | PhysActor.Force = force; | ||
2596 | } | ||
2597 | } | ||
2598 | |||
2599 | public void SetVehicleType(int type) | ||
2600 | { | ||
2601 | if (PhysActor != null) | ||
2602 | { | ||
2603 | PhysActor.VehicleType = type; | ||
2604 | } | ||
2605 | } | ||
2606 | |||
2607 | public void SetVehicleFloatParam(int param, float value) | ||
2608 | { | ||
2609 | if (PhysActor != null) | ||
2610 | { | ||
2611 | PhysActor.VehicleFloatParam(param, value); | ||
2612 | } | ||
2613 | } | ||
2614 | |||
2615 | public void SetVehicleVectorParam(int param, PhysicsVector value) | ||
2616 | { | ||
2617 | if (PhysActor != null) | ||
2618 | { | ||
2619 | PhysActor.VehicleVectorParam(param, value); | ||
2620 | } | ||
2621 | } | ||
2622 | |||
2623 | public void SetVehicleRotationParam(int param, Quaternion rotation) | ||
2624 | { | ||
2625 | if (PhysActor != null) | ||
2626 | { | ||
2627 | PhysActor.VehicleRotationParam(param, rotation); | ||
2628 | } | ||
2629 | } | ||
2630 | |||
2631 | public void SetGroup(UUID groupID, IClientAPI client) | ||
2632 | { | ||
2633 | _groupID = groupID; | ||
2634 | if (client != null) | ||
2635 | GetProperties(client); | ||
2636 | m_updateFlag = 2; | ||
2637 | } | ||
2638 | |||
2639 | /// <summary> | ||
2640 | /// | ||
2641 | /// </summary> | ||
2642 | public void SetParent(SceneObjectGroup parent) | ||
2643 | { | ||
2644 | m_parentGroup = parent; | ||
2645 | } | ||
2646 | |||
2647 | // Use this for attachments! LocalID should be avatar's localid | ||
2648 | public void SetParentLocalId(uint localID) | ||
2649 | { | ||
2650 | _parentID = localID; | ||
2651 | } | ||
2652 | |||
2653 | public void SetPhysicsAxisRotation() | ||
2654 | { | ||
2655 | if (PhysActor != null) | ||
2656 | { | ||
2657 | PhysActor.LockAngularMotion(RotationAxis); | ||
2658 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
2659 | } | ||
2660 | } | ||
2661 | |||
2662 | public void SetScriptEvents(UUID scriptid, int events) | ||
2663 | { | ||
2664 | // scriptEvents oldparts; | ||
2665 | lock (m_scriptEvents) | ||
2666 | { | ||
2667 | if (m_scriptEvents.ContainsKey(scriptid)) | ||
2668 | { | ||
2669 | // oldparts = m_scriptEvents[scriptid]; | ||
2670 | |||
2671 | // remove values from aggregated script events | ||
2672 | if (m_scriptEvents[scriptid] == (scriptEvents) events) | ||
2673 | return; | ||
2674 | m_scriptEvents[scriptid] = (scriptEvents) events; | ||
2675 | } | ||
2676 | else | ||
2677 | { | ||
2678 | m_scriptEvents.Add(scriptid, (scriptEvents) events); | ||
2679 | } | ||
2680 | } | ||
2681 | aggregateScriptEvents(); | ||
2682 | } | ||
2683 | |||
2684 | /// <summary> | ||
2685 | /// Set the text displayed for this part. | ||
2686 | /// </summary> | ||
2687 | /// <param name="text"></param> | ||
2688 | public void SetText(string text) | ||
2689 | { | ||
2690 | Text = text; | ||
2691 | |||
2692 | ParentGroup.HasGroupChanged = true; | ||
2693 | ScheduleFullUpdate(); | ||
2694 | } | ||
2695 | |||
2696 | /// <summary> | ||
2697 | /// Set the text displayed for this part. | ||
2698 | /// </summary> | ||
2699 | /// <param name="text"></param> | ||
2700 | /// <param name="color"></param> | ||
2701 | /// <param name="alpha"></param> | ||
2702 | public void SetText(string text, Vector3 color, double alpha) | ||
2703 | { | ||
2704 | Color = Color.FromArgb(0xff - (int) (alpha*0xff), | ||
2705 | (int) (color.X*0xff), | ||
2706 | (int) (color.Y*0xff), | ||
2707 | (int) (color.Z*0xff)); | ||
2708 | SetText(text); | ||
2709 | } | ||
2710 | |||
2711 | public void StopMoveToTarget() | ||
2712 | { | ||
2713 | m_parentGroup.stopMoveToTarget(); | ||
2714 | |||
2715 | m_parentGroup.ScheduleGroupForTerseUpdate(); | ||
2716 | //m_parentGroup.ScheduleGroupForFullUpdate(); | ||
2717 | } | ||
2718 | |||
2719 | public void StoreUndoState() | ||
2720 | { | ||
2721 | if (!Undoing) | ||
2722 | { | ||
2723 | if (m_parentGroup != null) | ||
2724 | { | ||
2725 | lock (m_undo) | ||
2726 | { | ||
2727 | if (m_undo.Count > 0) | ||
2728 | { | ||
2729 | UndoState last = m_undo.Peek(); | ||
2730 | if (last != null) | ||
2731 | { | ||
2732 | if (last.Compare(this)) | ||
2733 | return; | ||
2734 | } | ||
2735 | } | ||
2736 | |||
2737 | if (m_parentGroup.GetSceneMaxUndo() > 0) | ||
2738 | { | ||
2739 | UndoState nUndo = new UndoState(this); | ||
2740 | |||
2741 | m_undo.Push(nUndo); | ||
2742 | } | ||
2743 | |||
2744 | } | ||
2745 | } | ||
2746 | } | ||
2747 | } | ||
2748 | |||
2749 | public EntityIntersection TestIntersection(Ray iray, Quaternion parentrot) | ||
2750 | { | ||
2751 | // In this case we're using a sphere with a radius of the largest dimention of the prim | ||
2752 | // TODO: Change to take shape into account | ||
2753 | |||
2754 | |||
2755 | EntityIntersection returnresult = new EntityIntersection(); | ||
2756 | Vector3 vAbsolutePosition = AbsolutePosition; | ||
2757 | Vector3 vScale = Scale; | ||
2758 | Vector3 rOrigin = iray.Origin; | ||
2759 | Vector3 rDirection = iray.Direction; | ||
2760 | |||
2761 | //rDirection = rDirection.Normalize(); | ||
2762 | // Buidling the first part of the Quadratic equation | ||
2763 | Vector3 r2ndDirection = rDirection*rDirection; | ||
2764 | float itestPart1 = r2ndDirection.X + r2ndDirection.Y + r2ndDirection.Z; | ||
2765 | |||
2766 | // Buidling the second part of the Quadratic equation | ||
2767 | Vector3 tmVal2 = rOrigin - vAbsolutePosition; | ||
2768 | Vector3 r2Direction = rDirection*2.0f; | ||
2769 | Vector3 tmVal3 = r2Direction*tmVal2; | ||
2770 | |||
2771 | float itestPart2 = tmVal3.X + tmVal3.Y + tmVal3.Z; | ||
2772 | |||
2773 | // Buidling the third part of the Quadratic equation | ||
2774 | Vector3 tmVal4 = rOrigin*rOrigin; | ||
2775 | Vector3 tmVal5 = vAbsolutePosition*vAbsolutePosition; | ||
2776 | |||
2777 | Vector3 tmVal6 = vAbsolutePosition*rOrigin; | ||
2778 | |||
2779 | |||
2780 | // Set Radius to the largest dimention of the prim | ||
2781 | float radius = 0f; | ||
2782 | if (vScale.X > radius) | ||
2783 | radius = vScale.X; | ||
2784 | if (vScale.Y > radius) | ||
2785 | radius = vScale.Y; | ||
2786 | if (vScale.Z > radius) | ||
2787 | radius = vScale.Z; | ||
2788 | |||
2789 | // the second part of this is the default prim size | ||
2790 | // once we factor in the aabb of the prim we're adding we can | ||
2791 | // change this to; | ||
2792 | // radius = (radius / 2) - 0.01f; | ||
2793 | // | ||
2794 | radius = (radius / 2) + (0.5f / 2) - 0.1f; | ||
2795 | |||
2796 | //radius = radius; | ||
2797 | |||
2798 | float itestPart3 = tmVal4.X + tmVal4.Y + tmVal4.Z + tmVal5.X + tmVal5.Y + tmVal5.Z - | ||
2799 | (2.0f*(tmVal6.X + tmVal6.Y + tmVal6.Z + (radius*radius))); | ||
2800 | |||
2801 | // Yuk Quadradrics.. Solve first | ||
2802 | float rootsqr = (itestPart2*itestPart2) - (4.0f*itestPart1*itestPart3); | ||
2803 | if (rootsqr < 0.0f) | ||
2804 | { | ||
2805 | // No intersection | ||
2806 | return returnresult; | ||
2807 | } | ||
2808 | float root = ((-itestPart2) - (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f); | ||
2809 | |||
2810 | if (root < 0.0f) | ||
2811 | { | ||
2812 | // perform second quadratic root solution | ||
2813 | root = ((-itestPart2) + (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f); | ||
2814 | |||
2815 | // is there any intersection? | ||
2816 | if (root < 0.0f) | ||
2817 | { | ||
2818 | // nope, no intersection | ||
2819 | return returnresult; | ||
2820 | } | ||
2821 | } | ||
2822 | |||
2823 | // We got an intersection. putting together an EntityIntersection object with the | ||
2824 | // intersection information | ||
2825 | Vector3 ipoint = | ||
2826 | new Vector3(iray.Origin.X + (iray.Direction.X*root), iray.Origin.Y + (iray.Direction.Y*root), | ||
2827 | iray.Origin.Z + (iray.Direction.Z*root)); | ||
2828 | |||
2829 | returnresult.HitTF = true; | ||
2830 | returnresult.ipoint = ipoint; | ||
2831 | |||
2832 | // Normal is calculated by the difference and then normalizing the result | ||
2833 | Vector3 normalpart = ipoint - vAbsolutePosition; | ||
2834 | returnresult.normal = normalpart / normalpart.Length(); | ||
2835 | |||
2836 | // It's funny how the Vector3 object has a Distance function, but the Axiom.Math object doesn't. | ||
2837 | // I can write a function to do it.. but I like the fact that this one is Static. | ||
2838 | |||
2839 | Vector3 distanceConvert1 = new Vector3(iray.Origin.X, iray.Origin.Y, iray.Origin.Z); | ||
2840 | Vector3 distanceConvert2 = new Vector3(ipoint.X, ipoint.Y, ipoint.Z); | ||
2841 | float distance = (float) Util.GetDistanceTo(distanceConvert1, distanceConvert2); | ||
2842 | |||
2843 | returnresult.distance = distance; | ||
2844 | |||
2845 | return returnresult; | ||
2846 | } | ||
2847 | |||
2848 | public EntityIntersection TestIntersectionOBB(Ray iray, Quaternion parentrot, bool frontFacesOnly, bool faceCenters) | ||
2849 | { | ||
2850 | // In this case we're using a rectangular prism, which has 6 faces and therefore 6 planes | ||
2851 | // This breaks down into the ray---> plane equation. | ||
2852 | // TODO: Change to take shape into account | ||
2853 | Vector3[] vertexes = new Vector3[8]; | ||
2854 | |||
2855 | // float[] distance = new float[6]; | ||
2856 | Vector3[] FaceA = new Vector3[6]; // vertex A for Facei | ||
2857 | Vector3[] FaceB = new Vector3[6]; // vertex B for Facei | ||
2858 | Vector3[] FaceC = new Vector3[6]; // vertex C for Facei | ||
2859 | Vector3[] FaceD = new Vector3[6]; // vertex D for Facei | ||
2860 | |||
2861 | Vector3[] normals = new Vector3[6]; // Normal for Facei | ||
2862 | Vector3[] AAfacenormals = new Vector3[6]; // Axis Aligned face normals | ||
2863 | |||
2864 | AAfacenormals[0] = new Vector3(1, 0, 0); | ||
2865 | AAfacenormals[1] = new Vector3(0, 1, 0); | ||
2866 | AAfacenormals[2] = new Vector3(-1, 0, 0); | ||
2867 | AAfacenormals[3] = new Vector3(0, -1, 0); | ||
2868 | AAfacenormals[4] = new Vector3(0, 0, 1); | ||
2869 | AAfacenormals[5] = new Vector3(0, 0, -1); | ||
2870 | |||
2871 | Vector3 AmBa = new Vector3(0, 0, 0); // Vertex A - Vertex B | ||
2872 | Vector3 AmBb = new Vector3(0, 0, 0); // Vertex B - Vertex C | ||
2873 | Vector3 cross = new Vector3(); | ||
2874 | |||
2875 | Vector3 pos = GetWorldPosition(); | ||
2876 | Quaternion rot = GetWorldRotation(); | ||
2877 | |||
2878 | // Variables prefixed with AX are Axiom.Math copies of the LL variety. | ||
2879 | |||
2880 | Quaternion AXrot = rot; | ||
2881 | AXrot.Normalize(); | ||
2882 | |||
2883 | Vector3 AXpos = pos; | ||
2884 | |||
2885 | // tScale is the offset to derive the vertex based on the scale. | ||
2886 | // it's different for each vertex because we've got to rotate it | ||
2887 | // to get the world position of the vertex to produce the Oriented Bounding Box | ||
2888 | |||
2889 | Vector3 tScale = Vector3.Zero; | ||
2890 | |||
2891 | Vector3 AXscale = new Vector3(m_shape.Scale.X * 0.5f, m_shape.Scale.Y * 0.5f, m_shape.Scale.Z * 0.5f); | ||
2892 | |||
2893 | //Vector3 pScale = (AXscale) - (AXrot.Inverse() * (AXscale)); | ||
2894 | //Vector3 nScale = (AXscale * -1) - (AXrot.Inverse() * (AXscale * -1)); | ||
2895 | |||
2896 | // rScale is the rotated offset to find a vertex based on the scale and the world rotation. | ||
2897 | Vector3 rScale = new Vector3(); | ||
2898 | |||
2899 | // Get Vertexes for Faces Stick them into ABCD for each Face | ||
2900 | // Form: Face<vertex>[face] that corresponds to the below diagram | ||
2901 | #region ABCD Face Vertex Map Comment Diagram | ||
2902 | // A _________ B | ||
2903 | // | | | ||
2904 | // | 4 top | | ||
2905 | // |_________| | ||
2906 | // C D | ||
2907 | |||
2908 | // A _________ B | ||
2909 | // | Back | | ||
2910 | // | 3 | | ||
2911 | // |_________| | ||
2912 | // C D | ||
2913 | |||
2914 | // A _________ B B _________ A | ||
2915 | // | Left | | Right | | ||
2916 | // | 0 | | 2 | | ||
2917 | // |_________| |_________| | ||
2918 | // C D D C | ||
2919 | |||
2920 | // A _________ B | ||
2921 | // | Front | | ||
2922 | // | 1 | | ||
2923 | // |_________| | ||
2924 | // C D | ||
2925 | |||
2926 | // C _________ D | ||
2927 | // | | | ||
2928 | // | 5 bot | | ||
2929 | // |_________| | ||
2930 | // A B | ||
2931 | #endregion | ||
2932 | |||
2933 | #region Plane Decomposition of Oriented Bounding Box | ||
2934 | tScale = new Vector3(AXscale.X, -AXscale.Y, AXscale.Z); | ||
2935 | rScale = tScale * AXrot; | ||
2936 | vertexes[0] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
2937 | // vertexes[0].X = pos.X + vertexes[0].X; | ||
2938 | //vertexes[0].Y = pos.Y + vertexes[0].Y; | ||
2939 | //vertexes[0].Z = pos.Z + vertexes[0].Z; | ||
2940 | |||
2941 | FaceA[0] = vertexes[0]; | ||
2942 | FaceB[3] = vertexes[0]; | ||
2943 | FaceA[4] = vertexes[0]; | ||
2944 | |||
2945 | tScale = AXscale; | ||
2946 | rScale = tScale * AXrot; | ||
2947 | vertexes[1] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
2948 | |||
2949 | // vertexes[1].X = pos.X + vertexes[1].X; | ||
2950 | // vertexes[1].Y = pos.Y + vertexes[1].Y; | ||
2951 | //vertexes[1].Z = pos.Z + vertexes[1].Z; | ||
2952 | |||
2953 | FaceB[0] = vertexes[1]; | ||
2954 | FaceA[1] = vertexes[1]; | ||
2955 | FaceC[4] = vertexes[1]; | ||
2956 | |||
2957 | tScale = new Vector3(AXscale.X, -AXscale.Y, -AXscale.Z); | ||
2958 | rScale = tScale * AXrot; | ||
2959 | |||
2960 | vertexes[2] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
2961 | |||
2962 | //vertexes[2].X = pos.X + vertexes[2].X; | ||
2963 | //vertexes[2].Y = pos.Y + vertexes[2].Y; | ||
2964 | //vertexes[2].Z = pos.Z + vertexes[2].Z; | ||
2965 | |||
2966 | FaceC[0] = vertexes[2]; | ||
2967 | FaceD[3] = vertexes[2]; | ||
2968 | FaceC[5] = vertexes[2]; | ||
2969 | |||
2970 | tScale = new Vector3(AXscale.X, AXscale.Y, -AXscale.Z); | ||
2971 | rScale = tScale * AXrot; | ||
2972 | vertexes[3] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
2973 | |||
2974 | //vertexes[3].X = pos.X + vertexes[3].X; | ||
2975 | // vertexes[3].Y = pos.Y + vertexes[3].Y; | ||
2976 | // vertexes[3].Z = pos.Z + vertexes[3].Z; | ||
2977 | |||
2978 | FaceD[0] = vertexes[3]; | ||
2979 | FaceC[1] = vertexes[3]; | ||
2980 | FaceA[5] = vertexes[3]; | ||
2981 | |||
2982 | tScale = new Vector3(-AXscale.X, AXscale.Y, AXscale.Z); | ||
2983 | rScale = tScale * AXrot; | ||
2984 | vertexes[4] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
2985 | |||
2986 | // vertexes[4].X = pos.X + vertexes[4].X; | ||
2987 | // vertexes[4].Y = pos.Y + vertexes[4].Y; | ||
2988 | // vertexes[4].Z = pos.Z + vertexes[4].Z; | ||
2989 | |||
2990 | FaceB[1] = vertexes[4]; | ||
2991 | FaceA[2] = vertexes[4]; | ||
2992 | FaceD[4] = vertexes[4]; | ||
2993 | |||
2994 | tScale = new Vector3(-AXscale.X, AXscale.Y, -AXscale.Z); | ||
2995 | rScale = tScale * AXrot; | ||
2996 | vertexes[5] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
2997 | |||
2998 | // vertexes[5].X = pos.X + vertexes[5].X; | ||
2999 | // vertexes[5].Y = pos.Y + vertexes[5].Y; | ||
3000 | // vertexes[5].Z = pos.Z + vertexes[5].Z; | ||
3001 | |||
3002 | FaceD[1] = vertexes[5]; | ||
3003 | FaceC[2] = vertexes[5]; | ||
3004 | FaceB[5] = vertexes[5]; | ||
3005 | |||
3006 | tScale = new Vector3(-AXscale.X, -AXscale.Y, AXscale.Z); | ||
3007 | rScale = tScale * AXrot; | ||
3008 | vertexes[6] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
3009 | |||
3010 | // vertexes[6].X = pos.X + vertexes[6].X; | ||
3011 | // vertexes[6].Y = pos.Y + vertexes[6].Y; | ||
3012 | // vertexes[6].Z = pos.Z + vertexes[6].Z; | ||
3013 | |||
3014 | FaceB[2] = vertexes[6]; | ||
3015 | FaceA[3] = vertexes[6]; | ||
3016 | FaceB[4] = vertexes[6]; | ||
3017 | |||
3018 | tScale = new Vector3(-AXscale.X, -AXscale.Y, -AXscale.Z); | ||
3019 | rScale = tScale * AXrot; | ||
3020 | vertexes[7] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z))); | ||
3021 | |||
3022 | // vertexes[7].X = pos.X + vertexes[7].X; | ||
3023 | // vertexes[7].Y = pos.Y + vertexes[7].Y; | ||
3024 | // vertexes[7].Z = pos.Z + vertexes[7].Z; | ||
3025 | |||
3026 | FaceD[2] = vertexes[7]; | ||
3027 | FaceC[3] = vertexes[7]; | ||
3028 | FaceD[5] = vertexes[7]; | ||
3029 | #endregion | ||
3030 | |||
3031 | // Get our plane normals | ||
3032 | for (int i = 0; i < 6; i++) | ||
3033 | { | ||
3034 | //m_log.Info("[FACECALCULATION]: FaceA[" + i + "]=" + FaceA[i] + " FaceB[" + i + "]=" + FaceB[i] + " FaceC[" + i + "]=" + FaceC[i] + " FaceD[" + i + "]=" + FaceD[i]); | ||
3035 | |||
3036 | // Our Plane direction | ||
3037 | AmBa = FaceA[i] - FaceB[i]; | ||
3038 | AmBb = FaceB[i] - FaceC[i]; | ||
3039 | |||
3040 | cross = Vector3.Cross(AmBb, AmBa); | ||
3041 | |||
3042 | // normalize the cross product to get the normal. | ||
3043 | normals[i] = cross / cross.Length(); | ||
3044 | |||
3045 | //m_log.Info("[NORMALS]: normals[ " + i + "]" + normals[i].ToString()); | ||
3046 | //distance[i] = (normals[i].X * AmBa.X + normals[i].Y * AmBa.Y + normals[i].Z * AmBa.Z) * -1; | ||
3047 | } | ||
3048 | |||
3049 | EntityIntersection returnresult = new EntityIntersection(); | ||
3050 | |||
3051 | returnresult.distance = 1024; | ||
3052 | float c = 0; | ||
3053 | float a = 0; | ||
3054 | float d = 0; | ||
3055 | Vector3 q = new Vector3(); | ||
3056 | |||
3057 | #region OBB Version 2 Experiment | ||
3058 | //float fmin = 999999; | ||
3059 | //float fmax = -999999; | ||
3060 | //float s = 0; | ||
3061 | |||
3062 | //for (int i=0;i<6;i++) | ||
3063 | //{ | ||
3064 | //s = iray.Direction.Dot(normals[i]); | ||
3065 | //d = normals[i].Dot(FaceB[i]); | ||
3066 | |||
3067 | //if (s == 0) | ||
3068 | //{ | ||
3069 | //if (iray.Origin.Dot(normals[i]) > d) | ||
3070 | //{ | ||
3071 | //return returnresult; | ||
3072 | //} | ||
3073 | // else | ||
3074 | //{ | ||
3075 | //continue; | ||
3076 | //} | ||
3077 | //} | ||
3078 | //a = (d - iray.Origin.Dot(normals[i])) / s; | ||
3079 | //if (iray.Direction.Dot(normals[i]) < 0) | ||
3080 | //{ | ||
3081 | //if (a > fmax) | ||
3082 | //{ | ||
3083 | //if (a > fmin) | ||
3084 | //{ | ||
3085 | //return returnresult; | ||
3086 | //} | ||
3087 | //fmax = a; | ||
3088 | //} | ||
3089 | |||
3090 | //} | ||
3091 | //else | ||
3092 | //{ | ||
3093 | //if (a < fmin) | ||
3094 | //{ | ||
3095 | //if (a < 0 || a < fmax) | ||
3096 | //{ | ||
3097 | //return returnresult; | ||
3098 | //} | ||
3099 | //fmin = a; | ||
3100 | //} | ||
3101 | //} | ||
3102 | //} | ||
3103 | //if (fmax > 0) | ||
3104 | // a= fmax; | ||
3105 | //else | ||
3106 | // a=fmin; | ||
3107 | |||
3108 | //q = iray.Origin + a * iray.Direction; | ||
3109 | #endregion | ||
3110 | |||
3111 | // Loop over faces (6 of them) | ||
3112 | for (int i = 0; i < 6; i++) | ||
3113 | { | ||
3114 | AmBa = FaceA[i] - FaceB[i]; | ||
3115 | AmBb = FaceB[i] - FaceC[i]; | ||
3116 | d = Vector3.Dot(normals[i], FaceB[i]); | ||
3117 | |||
3118 | //if (faceCenters) | ||
3119 | //{ | ||
3120 | // c = normals[i].Dot(normals[i]); | ||
3121 | //} | ||
3122 | //else | ||
3123 | //{ | ||
3124 | c = Vector3.Dot(iray.Direction, normals[i]); | ||
3125 | //} | ||
3126 | if (c == 0) | ||
3127 | continue; | ||
3128 | |||
3129 | a = (d - Vector3.Dot(iray.Origin, normals[i])) / c; | ||
3130 | |||
3131 | if (a < 0) | ||
3132 | continue; | ||
3133 | |||
3134 | // If the normal is pointing outside the object | ||
3135 | if (Vector3.Dot(iray.Direction, normals[i]) < 0 || !frontFacesOnly) | ||
3136 | { | ||
3137 | //if (faceCenters) | ||
3138 | //{ //(FaceA[i] + FaceB[i] + FaceC[1] + FaceD[i]) / 4f; | ||
3139 | // q = iray.Origin + a * normals[i]; | ||
3140 | //} | ||
3141 | //else | ||
3142 | //{ | ||
3143 | q = iray.Origin + iray.Direction * a; | ||
3144 | //} | ||
3145 | |||
3146 | float distance2 = (float)GetDistanceTo(q, AXpos); | ||
3147 | // Is this the closest hit to the object's origin? | ||
3148 | //if (faceCenters) | ||
3149 | //{ | ||
3150 | // distance2 = (float)GetDistanceTo(q, iray.Origin); | ||
3151 | //} | ||
3152 | |||
3153 | if (distance2 < returnresult.distance) | ||
3154 | { | ||
3155 | returnresult.distance = distance2; | ||
3156 | returnresult.HitTF = true; | ||
3157 | returnresult.ipoint = q; | ||
3158 | //m_log.Info("[FACE]:" + i.ToString()); | ||
3159 | //m_log.Info("[POINT]: " + q.ToString()); | ||
3160 | //m_log.Info("[DIST]: " + distance2.ToString()); | ||
3161 | if (faceCenters) | ||
3162 | { | ||
3163 | returnresult.normal = AAfacenormals[i] * AXrot; | ||
3164 | |||
3165 | Vector3 scaleComponent = AAfacenormals[i]; | ||
3166 | float ScaleOffset = 0.5f; | ||
3167 | if (scaleComponent.X != 0) ScaleOffset = AXscale.X; | ||
3168 | if (scaleComponent.Y != 0) ScaleOffset = AXscale.Y; | ||
3169 | if (scaleComponent.Z != 0) ScaleOffset = AXscale.Z; | ||
3170 | ScaleOffset = Math.Abs(ScaleOffset); | ||
3171 | Vector3 offset = returnresult.normal * ScaleOffset; | ||
3172 | returnresult.ipoint = AXpos + offset; | ||
3173 | |||
3174 | ///pos = (intersectionpoint + offset); | ||
3175 | } | ||
3176 | else | ||
3177 | { | ||
3178 | returnresult.normal = normals[i]; | ||
3179 | } | ||
3180 | returnresult.AAfaceNormal = AAfacenormals[i]; | ||
3181 | } | ||
3182 | } | ||
3183 | } | ||
3184 | return returnresult; | ||
3185 | } | ||
3186 | |||
3187 | /// <summary> | ||
3188 | /// Serialize this part to xml. | ||
3189 | /// </summary> | ||
3190 | /// <param name="xmlWriter"></param> | ||
3191 | public void ToXml(XmlWriter xmlWriter) | ||
3192 | { | ||
3193 | serializer.Serialize(xmlWriter, this); | ||
3194 | } | ||
3195 | |||
3196 | public void TriggerScriptChangedEvent(Changed val) | ||
3197 | { | ||
3198 | if (m_parentGroup != null) | ||
3199 | { | ||
3200 | if (m_parentGroup.Scene != null) | ||
3201 | m_parentGroup.Scene.TriggerObjectChanged(LocalId, (uint)val); | ||
3202 | } | ||
3203 | } | ||
3204 | |||
3205 | public void TrimPermissions() | ||
3206 | { | ||
3207 | _baseMask &= (uint)PermissionMask.All; | ||
3208 | _ownerMask &= (uint)PermissionMask.All; | ||
3209 | _groupMask &= (uint)PermissionMask.All; | ||
3210 | _everyoneMask &= (uint)PermissionMask.All; | ||
3211 | _nextOwnerMask &= (uint)PermissionMask.All; | ||
3212 | } | ||
3213 | |||
3214 | public void Undo() | ||
3215 | { | ||
3216 | lock (m_undo) | ||
3217 | { | ||
3218 | if (m_undo.Count > 0) | ||
3219 | { | ||
3220 | UndoState goback = m_undo.Pop(); | ||
3221 | if (goback != null) | ||
3222 | goback.PlaybackState(this); | ||
3223 | } | ||
3224 | } | ||
3225 | } | ||
3226 | |||
3227 | public void UpdateExtraParam(ushort type, bool inUse, byte[] data) | ||
3228 | { | ||
3229 | m_shape.ReadInUpdateExtraParam(type, inUse, data); | ||
3230 | |||
3231 | if (type == 0x30) | ||
3232 | { | ||
3233 | if (m_shape.SculptEntry && m_shape.SculptTexture != UUID.Zero) | ||
3234 | { | ||
3235 | //AssetBase tx = m_parentGroup.Scene.getase | ||
3236 | m_parentGroup.Scene.AssetCache.GetAsset(m_shape.SculptTexture, SculptTextureCallback, true); | ||
3237 | } | ||
3238 | } | ||
3239 | |||
3240 | ParentGroup.HasGroupChanged = true; | ||
3241 | ScheduleFullUpdate(); | ||
3242 | } | ||
3243 | |||
3244 | public void UpdateGroupPosition(Vector3 pos) | ||
3245 | { | ||
3246 | if ((pos.X != GroupPosition.X) || | ||
3247 | (pos.Y != GroupPosition.Y) || | ||
3248 | (pos.Z != GroupPosition.Z)) | ||
3249 | { | ||
3250 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | ||
3251 | GroupPosition = newPos; | ||
3252 | ScheduleTerseUpdate(); | ||
3253 | } | ||
3254 | } | ||
3255 | |||
3256 | public virtual void UpdateMovement() | ||
3257 | { | ||
3258 | } | ||
3259 | |||
3260 | /// <summary> | ||
3261 | /// | ||
3262 | /// </summary> | ||
3263 | /// <param name="pos"></param> | ||
3264 | public void UpdateOffSet(Vector3 pos) | ||
3265 | { | ||
3266 | if ((pos.X != OffsetPosition.X) || | ||
3267 | (pos.Y != OffsetPosition.Y) || | ||
3268 | (pos.Z != OffsetPosition.Z)) | ||
3269 | { | ||
3270 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | ||
3271 | OffsetPosition = newPos; | ||
3272 | ScheduleTerseUpdate(); | ||
3273 | } | ||
3274 | } | ||
3275 | |||
3276 | public void UpdatePermissions(UUID AgentID, byte field, uint localID, uint mask, byte addRemTF) | ||
3277 | { | ||
3278 | bool set = addRemTF == 1; | ||
3279 | bool god = m_parentGroup.Scene.Permissions.IsGod(AgentID); | ||
3280 | |||
3281 | uint baseMask = _baseMask; | ||
3282 | if (god) | ||
3283 | baseMask = 0x7ffffff0; | ||
3284 | |||
3285 | // Are we the owner? | ||
3286 | if ((AgentID == _ownerID) || god) | ||
3287 | { | ||
3288 | switch (field) | ||
3289 | { | ||
3290 | case 1: | ||
3291 | if (god) | ||
3292 | { | ||
3293 | _baseMask = ApplyMask(_baseMask, set, mask); | ||
3294 | Inventory.ApplyGodPermissions(_baseMask); | ||
3295 | } | ||
3296 | |||
3297 | break; | ||
3298 | case 2: | ||
3299 | _ownerMask = ApplyMask(_ownerMask, set, mask) & | ||
3300 | baseMask; | ||
3301 | break; | ||
3302 | case 4: | ||
3303 | _groupMask = ApplyMask(_groupMask, set, mask) & | ||
3304 | baseMask; | ||
3305 | break; | ||
3306 | case 8: | ||
3307 | _everyoneMask = ApplyMask(_everyoneMask, set, mask) & | ||
3308 | baseMask; | ||
3309 | break; | ||
3310 | case 16: | ||
3311 | _nextOwnerMask = ApplyMask(_nextOwnerMask, set, mask) & | ||
3312 | baseMask; | ||
3313 | break; | ||
3314 | } | ||
3315 | SendFullUpdateToAllClients(); | ||
3316 | |||
3317 | SendObjectPropertiesToClient(AgentID); | ||
3318 | |||
3319 | } | ||
3320 | } | ||
3321 | |||
3322 | public bool IsHingeJoint() | ||
3323 | { | ||
3324 | // For now, we use the NINJA naming scheme for identifying joints. | ||
3325 | // In the future, we can support other joint specification schemes such as a | ||
3326 | // custom checkbox in the viewer GUI. | ||
3327 | if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints) | ||
3328 | { | ||
3329 | string hingeString = "hingejoint"; | ||
3330 | return (Name.Length >= hingeString.Length && Name.Substring(0, hingeString.Length) == hingeString); | ||
3331 | } | ||
3332 | else | ||
3333 | { | ||
3334 | return false; | ||
3335 | } | ||
3336 | } | ||
3337 | |||
3338 | public bool IsBallJoint() | ||
3339 | { | ||
3340 | // For now, we use the NINJA naming scheme for identifying joints. | ||
3341 | // In the future, we can support other joint specification schemes such as a | ||
3342 | // custom checkbox in the viewer GUI. | ||
3343 | if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints) | ||
3344 | { | ||
3345 | string ballString = "balljoint"; | ||
3346 | return (Name.Length >= ballString.Length && Name.Substring(0, ballString.Length) == ballString); | ||
3347 | } | ||
3348 | else | ||
3349 | { | ||
3350 | return false; | ||
3351 | } | ||
3352 | } | ||
3353 | |||
3354 | public bool IsJoint() | ||
3355 | { | ||
3356 | // For now, we use the NINJA naming scheme for identifying joints. | ||
3357 | // In the future, we can support other joint specification schemes such as a | ||
3358 | // custom checkbox in the viewer GUI. | ||
3359 | if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints) | ||
3360 | { | ||
3361 | return IsHingeJoint() || IsBallJoint(); | ||
3362 | } | ||
3363 | else | ||
3364 | { | ||
3365 | return false; | ||
3366 | } | ||
3367 | } | ||
3368 | |||
3369 | public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVD) | ||
3370 | { | ||
3371 | bool wasUsingPhysics = ((ObjectFlags & (uint) PrimFlags.Physics) != 0); | ||
3372 | bool wasTemporary = ((ObjectFlags & (uint)PrimFlags.TemporaryOnRez) != 0); | ||
3373 | bool wasPhantom = ((ObjectFlags & (uint)PrimFlags.Phantom) != 0); | ||
3374 | bool wasVD = VolumeDetectActive; | ||
3375 | |||
3376 | if ((UsePhysics == wasUsingPhysics) && (wasTemporary == IsTemporary) && (wasPhantom == IsPhantom) && (IsVD==wasVD) ) | ||
3377 | { | ||
3378 | return; | ||
3379 | } | ||
3380 | |||
3381 | // Special cases for VD. VD can only be called from a script | ||
3382 | // and can't be combined with changes to other states. So we can rely | ||
3383 | // that... | ||
3384 | // ... if VD is changed, all others are not. | ||
3385 | // ... if one of the others is changed, VD is not. | ||
3386 | if (IsVD) // VD is active, special logic applies | ||
3387 | { | ||
3388 | // State machine logic for VolumeDetect | ||
3389 | // More logic below | ||
3390 | bool phanReset = (IsPhantom != wasPhantom) && !IsPhantom; | ||
3391 | |||
3392 | if (phanReset) // Phantom changes from on to off switch VD off too | ||
3393 | { | ||
3394 | IsVD = false; // Switch it of for the course of this routine | ||
3395 | VolumeDetectActive = false; // and also permanently | ||
3396 | if (PhysActor != null) | ||
3397 | PhysActor.SetVolumeDetect(0); // Let physics know about it too | ||
3398 | } | ||
3399 | else | ||
3400 | { | ||
3401 | IsPhantom = false; | ||
3402 | // If volumedetect is active we don't want phantom to be applied. | ||
3403 | // If this is a new call to VD out of the state "phantom" | ||
3404 | // this will also cause the prim to be visible to physics | ||
3405 | } | ||
3406 | |||
3407 | } | ||
3408 | |||
3409 | if (UsePhysics && IsJoint()) | ||
3410 | { | ||
3411 | IsPhantom = true; | ||
3412 | } | ||
3413 | |||
3414 | if (UsePhysics) | ||
3415 | { | ||
3416 | AddFlag(PrimFlags.Physics); | ||
3417 | if (!wasUsingPhysics) | ||
3418 | { | ||
3419 | DoPhysicsPropertyUpdate(UsePhysics, false); | ||
3420 | if (m_parentGroup != null) | ||
3421 | { | ||
3422 | if (!m_parentGroup.IsDeleted) | ||
3423 | { | ||
3424 | if (LocalId == m_parentGroup.RootPart.LocalId) | ||
3425 | { | ||
3426 | m_parentGroup.CheckSculptAndLoad(); | ||
3427 | } | ||
3428 | } | ||
3429 | } | ||
3430 | } | ||
3431 | } | ||
3432 | else | ||
3433 | { | ||
3434 | RemFlag(PrimFlags.Physics); | ||
3435 | if (wasUsingPhysics) | ||
3436 | { | ||
3437 | DoPhysicsPropertyUpdate(UsePhysics, false); | ||
3438 | } | ||
3439 | } | ||
3440 | |||
3441 | |||
3442 | if (IsPhantom || IsAttachment) // note: this may have been changed above in the case of joints | ||
3443 | { | ||
3444 | AddFlag(PrimFlags.Phantom); | ||
3445 | if (PhysActor != null) | ||
3446 | { | ||
3447 | m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); | ||
3448 | /// that's not wholesome. Had to make Scene public | ||
3449 | PhysActor = null; | ||
3450 | } | ||
3451 | } | ||
3452 | else // Not phantom | ||
3453 | { | ||
3454 | RemFlag(PrimFlags.Phantom); | ||
3455 | |||
3456 | if (PhysActor == null) | ||
3457 | { | ||
3458 | // It's not phantom anymore. So make sure the physics engine get's knowledge of it | ||
3459 | PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( | ||
3460 | Name, | ||
3461 | Shape, | ||
3462 | new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z), | ||
3463 | new PhysicsVector(Scale.X, Scale.Y, Scale.Z), | ||
3464 | RotationOffset, | ||
3465 | UsePhysics); | ||
3466 | |||
3467 | if (PhysActor != null) | ||
3468 | { | ||
3469 | PhysActor.LocalID = LocalId; | ||
3470 | DoPhysicsPropertyUpdate(UsePhysics, true); | ||
3471 | if (m_parentGroup != null) | ||
3472 | { | ||
3473 | if (!m_parentGroup.IsDeleted) | ||
3474 | { | ||
3475 | if (LocalId == m_parentGroup.RootPart.LocalId) | ||
3476 | { | ||
3477 | m_parentGroup.CheckSculptAndLoad(); | ||
3478 | } | ||
3479 | } | ||
3480 | } | ||
3481 | if ( | ||
3482 | ((AggregateScriptEvents & scriptEvents.collision) != 0) || | ||
3483 | ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || | ||
3484 | ((AggregateScriptEvents & scriptEvents.collision_start) != 0) || | ||
3485 | (CollisionSound != UUID.Zero) | ||
3486 | ) | ||
3487 | { | ||
3488 | PhysActor.OnCollisionUpdate += PhysicsCollision; | ||
3489 | PhysActor.SubscribeEvents(1000); | ||
3490 | } | ||
3491 | } | ||
3492 | } | ||
3493 | else // it already has a physical representation | ||
3494 | { | ||
3495 | PhysActor.IsPhysical = UsePhysics; | ||
3496 | |||
3497 | DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim | ||
3498 | if (m_parentGroup != null) | ||
3499 | { | ||
3500 | if (!m_parentGroup.IsDeleted) | ||
3501 | { | ||
3502 | if (LocalId == m_parentGroup.RootPart.LocalId) | ||
3503 | { | ||
3504 | m_parentGroup.CheckSculptAndLoad(); | ||
3505 | } | ||
3506 | } | ||
3507 | } | ||
3508 | } | ||
3509 | } | ||
3510 | |||
3511 | if (IsVD) | ||
3512 | { | ||
3513 | // If the above logic worked (this is urgent candidate to unit tests!) | ||
3514 | // we now have a physicsactor. | ||
3515 | // Defensive programming calls for a check here. | ||
3516 | // Better would be throwing an exception that could be catched by a unit test as the internal | ||
3517 | // logic should make sure, this Physactor is always here. | ||
3518 | if (this.PhysActor != null) | ||
3519 | { | ||
3520 | PhysActor.SetVolumeDetect(1); | ||
3521 | AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active | ||
3522 | this.VolumeDetectActive = true; | ||
3523 | } | ||
3524 | |||
3525 | } | ||
3526 | else | ||
3527 | { // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like | ||
3528 | // (mumbles, well, at least if you have infinte CPU powers :-) ) | ||
3529 | if (this.PhysActor != null) | ||
3530 | { | ||
3531 | PhysActor.SetVolumeDetect(0); | ||
3532 | } | ||
3533 | this.VolumeDetectActive = false; | ||
3534 | } | ||
3535 | |||
3536 | |||
3537 | if (IsTemporary) | ||
3538 | { | ||
3539 | AddFlag(PrimFlags.TemporaryOnRez); | ||
3540 | } | ||
3541 | else | ||
3542 | { | ||
3543 | RemFlag(PrimFlags.TemporaryOnRez); | ||
3544 | } | ||
3545 | // System.Console.WriteLine("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString()); | ||
3546 | |||
3547 | ParentGroup.HasGroupChanged = true; | ||
3548 | ScheduleFullUpdate(); | ||
3549 | } | ||
3550 | |||
3551 | public void UpdateRotation(Quaternion rot) | ||
3552 | { | ||
3553 | if ((rot.X != RotationOffset.X) || | ||
3554 | (rot.Y != RotationOffset.Y) || | ||
3555 | (rot.Z != RotationOffset.Z) || | ||
3556 | (rot.W != RotationOffset.W)) | ||
3557 | { | ||
3558 | //StoreUndoState(); | ||
3559 | RotationOffset = rot; | ||
3560 | ParentGroup.HasGroupChanged = true; | ||
3561 | ScheduleTerseUpdate(); | ||
3562 | } | ||
3563 | } | ||
3564 | |||
3565 | /// <summary> | ||
3566 | /// Update the shape of this part. | ||
3567 | /// </summary> | ||
3568 | /// <param name="shapeBlock"></param> | ||
3569 | public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock) | ||
3570 | { | ||
3571 | m_shape.PathBegin = shapeBlock.PathBegin; | ||
3572 | m_shape.PathEnd = shapeBlock.PathEnd; | ||
3573 | m_shape.PathScaleX = shapeBlock.PathScaleX; | ||
3574 | m_shape.PathScaleY = shapeBlock.PathScaleY; | ||
3575 | m_shape.PathShearX = shapeBlock.PathShearX; | ||
3576 | m_shape.PathShearY = shapeBlock.PathShearY; | ||
3577 | m_shape.PathSkew = shapeBlock.PathSkew; | ||
3578 | m_shape.ProfileBegin = shapeBlock.ProfileBegin; | ||
3579 | m_shape.ProfileEnd = shapeBlock.ProfileEnd; | ||
3580 | m_shape.PathCurve = shapeBlock.PathCurve; | ||
3581 | m_shape.ProfileCurve = shapeBlock.ProfileCurve; | ||
3582 | m_shape.ProfileHollow = shapeBlock.ProfileHollow; | ||
3583 | m_shape.PathRadiusOffset = shapeBlock.PathRadiusOffset; | ||
3584 | m_shape.PathRevolutions = shapeBlock.PathRevolutions; | ||
3585 | m_shape.PathTaperX = shapeBlock.PathTaperX; | ||
3586 | m_shape.PathTaperY = shapeBlock.PathTaperY; | ||
3587 | m_shape.PathTwist = shapeBlock.PathTwist; | ||
3588 | m_shape.PathTwistBegin = shapeBlock.PathTwistBegin; | ||
3589 | if (PhysActor != null) | ||
3590 | { | ||
3591 | PhysActor.Shape = m_shape; | ||
3592 | } | ||
3593 | |||
3594 | // This is what makes vehicle trailers work | ||
3595 | // A script in a child prim re-issues | ||
3596 | // llSetPrimitiveParams(PRIM_TYPE) every few seconds. That | ||
3597 | // prevents autoreturn. This is not well known. It also works | ||
3598 | // in SL. | ||
3599 | // | ||
3600 | if (ParentGroup.RootPart != this) | ||
3601 | ParentGroup.RootPart.Rezzed = DateTime.Now; | ||
3602 | |||
3603 | ParentGroup.HasGroupChanged = true; | ||
3604 | ScheduleFullUpdate(); | ||
3605 | } | ||
3606 | |||
3607 | // Added to handle bug in libsecondlife's TextureEntry.ToBytes() | ||
3608 | // not handling RGBA properly. Cycles through, and "fixes" the color | ||
3609 | // info | ||
3610 | public void UpdateTexture(Primitive.TextureEntry tex) | ||
3611 | { | ||
3612 | //Color4 tmpcolor; | ||
3613 | //for (uint i = 0; i < 32; i++) | ||
3614 | //{ | ||
3615 | // if (tex.FaceTextures[i] != null) | ||
3616 | // { | ||
3617 | // tmpcolor = tex.GetFace((uint) i).RGBA; | ||
3618 | // tmpcolor.A = tmpcolor.A*255; | ||
3619 | // tmpcolor.R = tmpcolor.R*255; | ||
3620 | // tmpcolor.G = tmpcolor.G*255; | ||
3621 | // tmpcolor.B = tmpcolor.B*255; | ||
3622 | // tex.FaceTextures[i].RGBA = tmpcolor; | ||
3623 | // } | ||
3624 | //} | ||
3625 | //tmpcolor = tex.DefaultTexture.RGBA; | ||
3626 | //tmpcolor.A = tmpcolor.A*255; | ||
3627 | //tmpcolor.R = tmpcolor.R*255; | ||
3628 | //tmpcolor.G = tmpcolor.G*255; | ||
3629 | //tmpcolor.B = tmpcolor.B*255; | ||
3630 | //tex.DefaultTexture.RGBA = tmpcolor; | ||
3631 | UpdateTextureEntry(tex.ToBytes()); | ||
3632 | } | ||
3633 | |||
3634 | /// <summary> | ||
3635 | /// Update the texture entry for this part. | ||
3636 | /// </summary> | ||
3637 | /// <param name="textureEntry"></param> | ||
3638 | public void UpdateTextureEntry(byte[] textureEntry) | ||
3639 | { | ||
3640 | m_shape.TextureEntry = textureEntry; | ||
3641 | TriggerScriptChangedEvent(Changed.TEXTURE); | ||
3642 | |||
3643 | ParentGroup.HasGroupChanged = true; | ||
3644 | ParentGroup.ScheduleGroupForFullUpdate(); | ||
3645 | } | ||
3646 | |||
3647 | public void aggregateScriptEvents() | ||
3648 | { | ||
3649 | AggregateScriptEvents = 0; | ||
3650 | |||
3651 | // Aggregate script events | ||
3652 | lock (m_scriptEvents) | ||
3653 | { | ||
3654 | foreach (scriptEvents s in m_scriptEvents.Values) | ||
3655 | { | ||
3656 | AggregateScriptEvents |= s; | ||
3657 | } | ||
3658 | } | ||
3659 | |||
3660 | uint objectflagupdate = 0; | ||
3661 | |||
3662 | if ( | ||
3663 | ((AggregateScriptEvents & scriptEvents.touch) != 0) || | ||
3664 | ((AggregateScriptEvents & scriptEvents.touch_end) != 0) || | ||
3665 | ((AggregateScriptEvents & scriptEvents.touch_start) != 0) | ||
3666 | ) | ||
3667 | { | ||
3668 | objectflagupdate |= (uint) PrimFlags.Touch; | ||
3669 | } | ||
3670 | |||
3671 | if ((AggregateScriptEvents & scriptEvents.money) != 0) | ||
3672 | { | ||
3673 | objectflagupdate |= (uint) PrimFlags.Money; | ||
3674 | } | ||
3675 | |||
3676 | if (AllowedDrop) | ||
3677 | { | ||
3678 | objectflagupdate |= (uint) PrimFlags.AllowInventoryDrop; | ||
3679 | } | ||
3680 | |||
3681 | if ( | ||
3682 | ((AggregateScriptEvents & scriptEvents.collision) != 0) || | ||
3683 | ((AggregateScriptEvents & scriptEvents.collision_end) != 0) || | ||
3684 | ((AggregateScriptEvents & scriptEvents.collision_start) != 0) || | ||
3685 | (CollisionSound != UUID.Zero) | ||
3686 | ) | ||
3687 | { | ||
3688 | // subscribe to physics updates. | ||
3689 | if (PhysActor != null) | ||
3690 | { | ||
3691 | PhysActor.OnCollisionUpdate += PhysicsCollision; | ||
3692 | PhysActor.SubscribeEvents(1000); | ||
3693 | |||
3694 | } | ||
3695 | } | ||
3696 | else | ||
3697 | { | ||
3698 | if (PhysActor != null) | ||
3699 | { | ||
3700 | PhysActor.UnSubscribeEvents(); | ||
3701 | PhysActor.OnCollisionUpdate -= PhysicsCollision; | ||
3702 | } | ||
3703 | } | ||
3704 | |||
3705 | if (m_parentGroup == null) | ||
3706 | { | ||
3707 | ScheduleFullUpdate(); | ||
3708 | return; | ||
3709 | } | ||
3710 | |||
3711 | if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) | ||
3712 | { | ||
3713 | m_parentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting; | ||
3714 | } | ||
3715 | else | ||
3716 | { | ||
3717 | m_parentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting; | ||
3718 | } | ||
3719 | |||
3720 | LocalFlags=(PrimFlags)objectflagupdate; | ||
3721 | |||
3722 | if (m_parentGroup != null && m_parentGroup.RootPart == this) | ||
3723 | m_parentGroup.aggregateScriptEvents(); | ||
3724 | else | ||
3725 | ScheduleFullUpdate(); | ||
3726 | } | ||
3727 | |||
3728 | public int registerTargetWaypoint(Vector3 target, float tolerance) | ||
3729 | { | ||
3730 | if (m_parentGroup != null) | ||
3731 | { | ||
3732 | return m_parentGroup.registerTargetWaypoint(target, tolerance); | ||
3733 | } | ||
3734 | return 0; | ||
3735 | } | ||
3736 | |||
3737 | public void unregisterTargetWaypoint(int handle) | ||
3738 | { | ||
3739 | if (m_parentGroup != null) | ||
3740 | { | ||
3741 | m_parentGroup.unregisterTargetWaypoint(handle); | ||
3742 | } | ||
3743 | } | ||
3744 | |||
3745 | public void SetCameraAtOffset(Vector3 v) | ||
3746 | { | ||
3747 | m_cameraAtOffset = v; | ||
3748 | } | ||
3749 | |||
3750 | public void SetCameraEyeOffset(Vector3 v) | ||
3751 | { | ||
3752 | m_cameraEyeOffset = v; | ||
3753 | } | ||
3754 | |||
3755 | public void SetForceMouselook(bool force) | ||
3756 | { | ||
3757 | m_forceMouselook = force; | ||
3758 | } | ||
3759 | |||
3760 | public Vector3 GetCameraAtOffset() | ||
3761 | { | ||
3762 | return m_cameraAtOffset; | ||
3763 | } | ||
3764 | |||
3765 | public Vector3 GetCameraEyeOffset() | ||
3766 | { | ||
3767 | return m_cameraEyeOffset; | ||
3768 | } | ||
3769 | |||
3770 | public bool GetForceMouselook() | ||
3771 | { | ||
3772 | return m_forceMouselook; | ||
3773 | } | ||
3774 | |||
3775 | public override string ToString() | ||
3776 | { | ||
3777 | return String.Format("{0} {1} (parent {2}))", Name, UUID, ParentGroup); | ||
3778 | } | ||
3779 | |||
3780 | #endregion Public Methods | ||
3781 | |||
3782 | public void SendTerseUpdateToClient(IClientAPI remoteClient) | ||
3783 | { | ||
3784 | if (ParentGroup == null || ParentGroup.IsDeleted) | ||
3785 | return; | ||
3786 | |||
3787 | Vector3 lPos = OffsetPosition; | ||
3788 | |||
3789 | byte state = Shape.State; | ||
3790 | if (IsAttachment) | ||
3791 | { | ||
3792 | if (ParentGroup.RootPart != this) | ||
3793 | return; | ||
3794 | |||
3795 | lPos = ParentGroup.RootPart.AttachedPos; | ||
3796 | state = (byte)AttachmentPoint; | ||
3797 | } | ||
3798 | else | ||
3799 | { | ||
3800 | if (ParentGroup.RootPart == this) | ||
3801 | lPos = AbsolutePosition; | ||
3802 | } | ||
3803 | |||
3804 | remoteClient.SendPrimTerseUpdate(m_regionHandle, | ||
3805 | (ushort)(m_parentGroup.GetTimeDilation() * | ||
3806 | (float)ushort.MaxValue), LocalId, lPos, | ||
3807 | RotationOffset, Velocity, | ||
3808 | RotationalVelocity, state, FromAssetID, | ||
3809 | OwnerID, (int)AttachmentPoint); | ||
3810 | } | ||
3811 | |||
3812 | public void AddScriptLPS(int count) | ||
3813 | { | ||
3814 | m_parentGroup.AddScriptLPS(count); | ||
3815 | } | ||
3816 | |||
3817 | public void ApplyNextOwnerPermissions() | ||
3818 | { | ||
3819 | _baseMask &= _nextOwnerMask; | ||
3820 | _ownerMask &= _nextOwnerMask; | ||
3821 | _everyoneMask &= _nextOwnerMask; | ||
3822 | |||
3823 | Inventory.ApplyNextOwnerPermissions(); | ||
3824 | } | ||
3825 | } | ||
3826 | } | ||