aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectPart.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectPart.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectPart.cs3826
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
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.Reflection;
32using System.Runtime.Serialization;
33using System.Security.Permissions;
34using System.Xml;
35using System.Xml.Serialization;
36using log4net;
37using OpenMetaverse;
38using OpenMetaverse.Packets;
39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Framework.Scenes.Scripting;
42using OpenSim.Region.Physics.Manager;
43
44namespace 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();
790if (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}