opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Collections.Generic;
30 using System.Drawing;
31 using System.IO;
32 using System.Reflection;
33 using System.Runtime.Serialization;
34 using System.Security.Permissions;
35 using System.Xml;
36 using System.Xml.Serialization;
37 using log4net;
38 using OpenMetaverse;
39 using OpenMetaverse.Packets;
40 using OpenMetaverse.StructuredData;
41 using OpenSim.Framework;
42 using OpenSim.Region.Framework.Interfaces;
43 using OpenSim.Region.Framework.Scenes.Scripting;
44 using OpenSim.Region.Framework.Scenes.Serialization;
45 using OpenSim.Region.Physics.Manager;
46 using PermissionMask = OpenSim.Framework.PermissionMask;
47  
48 namespace OpenSim.Region.Framework.Scenes
49 {
50 #region Enumerations
51  
52 [Flags]
53 public enum Changed : uint
54 {
55 INVENTORY = 1,
56 COLOR = 2,
57 SHAPE = 4,
58 SCALE = 8,
59 TEXTURE = 16,
60 LINK = 32,
61 ALLOWED_DROP = 64,
62 OWNER = 128,
63 REGION = 256,
64 TELEPORT = 512,
65 REGION_RESTART = 1024,
66 MEDIA = 2048,
67 ANIMATION = 16384
68 }
69  
70 // I don't really know where to put this except here.
71 // Can't access the OpenSim.Region.ScriptEngine.Common.LSL_BaseClass.Changed constants
72 [Flags]
73 public enum ExtraParamType
74 {
75 Something1 = 1,
76 Something2 = 2,
77 Something3 = 4,
78 Something4 = 8,
79 Flexible = 16,
80 Light = 32,
81 Sculpt = 48,
82 Something5 = 64,
83 Something6 = 128
84 }
85  
86 [Flags]
87 public enum TextureAnimFlags : byte
88 {
89 NONE = 0x00,
90 ANIM_ON = 0x01,
91 LOOP = 0x02,
92 REVERSE = 0x04,
93 PING_PONG = 0x08,
94 SMOOTH = 0x10,
95 ROTATE = 0x20,
96 SCALE = 0x40
97 }
98  
99 public enum PrimType : int
100 {
101 BOX = 0,
102 CYLINDER = 1,
103 PRISM = 2,
104 SPHERE = 3,
105 TORUS = 4,
106 TUBE = 5,
107 RING = 6,
108 SCULPT = 7
109 }
110  
111 public enum UpdateRequired : byte
112 {
113 NONE = 0,
114 TERSE = 1,
115 FULL = 2
116 }
117  
118 #endregion Enumerations
119  
120 public class SceneObjectPart : ISceneEntity
121 {
122 /// <value>
123 /// Denote all sides of the prim
124 /// </value>
125 public const int ALL_SIDES = -1;
126  
127 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
128  
129 /// <summary>
130 /// Dynamic attributes can be created and deleted as required.
131 /// </summary>
132 public DAMap DynAttrs { get; set; }
133  
134 private DOMap m_dynObjs;
135  
136 /// <summary>
137 /// Dynamic objects that can be created and deleted as required.
138 /// </summary>
139 public DOMap DynObjs
140 {
141 get
142 {
143 if (m_dynObjs == null)
144 m_dynObjs = new DOMap();
145  
146 return m_dynObjs;
147 }
148  
149 set
150 {
151 m_dynObjs = value;
152 }
153 }
154  
155 /// <value>
156 /// Is this a root part?
157 /// </value>
158 /// <remarks>
159 /// This will return true even if the whole object is attached to an avatar.
160 /// </remarks>
161 public bool IsRoot
162 {
163 get { return ParentGroup.RootPart == this; }
164 }
165  
166 /// <summary>
167 /// Is an explicit sit target set for this part?
168 /// </summary>
169 public bool IsSitTargetSet
170 {
171 get
172 {
173 return
174 !(SitTargetPosition == Vector3.Zero
175 && (SitTargetOrientation == Quaternion.Identity // Valid Zero Rotation quaternion
176 || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 1f && SitTargetOrientation.W == 0f // W-Z Mapping was invalid at one point
177 || SitTargetOrientation.X == 0f && SitTargetOrientation.Y == 0f && SitTargetOrientation.Z == 0f && SitTargetOrientation.W == 0f)); // Invalid Quaternion
178 }
179 }
180  
181 #region Fields
182  
183 public bool AllowedDrop;
184  
185 public bool DIE_AT_EDGE;
186  
187 public bool RETURN_AT_EDGE;
188  
189 public bool BlockGrab;
190  
191 public bool StatusSandbox;
192  
193 public Vector3 StatusSandboxPos;
194  
195 [XmlIgnore]
196 public int[] PayPrice = {-2,-2,-2,-2,-2};
197  
198 [XmlIgnore]
199 /// <summary>
200 /// The representation of this part in the physics scene.
201 /// </summary>
202 /// <remarks>
203 /// If you use this property more than once in a section of code then you must take a reference and use that.
204 /// If another thread is simultaneously turning physics off on this part then this refernece could become
205 /// null at any time.
206 /// </remarks>
207 public PhysicsActor PhysActor { get; set; }
208  
209 //Xantor 20080528 Sound stuff:
210 // Note: This isn't persisted in the database right now, as the fields for that aren't just there yet.
211 // Not a big problem as long as the script that sets it remains in the prim on startup.
212 // for SL compatibility it should be persisted though (set sound / displaytext / particlesystem, kill script)
213  
214 public UUID Sound;
215  
216 public byte SoundFlags;
217  
218 public double SoundGain;
219  
220 public double SoundRadius;
221  
222 /// <summary>
223 /// Should sounds played from this prim be queued?
224 /// </summary>
225 /// <remarks>
226 /// This should only be changed by sound modules. It is up to sound modules as to how they interpret this setting.
227 /// </remarks>
228 public bool SoundQueueing { get; set; }
229  
230 public uint TimeStampFull;
231  
232 public uint TimeStampLastActivity; // Will be used for AutoReturn
233  
234 public uint TimeStampTerse;
235  
236 public int STATUS_ROTATE_X;
237  
238 public int STATUS_ROTATE_Y;
239  
240 public int STATUS_ROTATE_Z;
241  
242 private Dictionary<int, string> m_CollisionFilter = new Dictionary<int, string>();
243  
244 /// <value>
245 /// The UUID of the user inventory item from which this object was rezzed if this is a root part.
246 /// If UUID.Zero then either this is not a root part or there is no connection with a user inventory item.
247 /// </value>
248 private UUID m_fromUserInventoryItemID;
249  
250 public UUID FromUserInventoryItemID
251 {
252 get { return m_fromUserInventoryItemID; }
253 set { m_fromUserInventoryItemID = value; }
254 }
255  
256 public scriptEvents AggregateScriptEvents;
257  
258 public Vector3 AttachedPos;
259  
260 public Vector3 RotationAxis = Vector3.One;
261  
262 public bool VolumeDetectActive; // XmlIgnore set to avoid problems with persistance until I come to care for this
263 // Certainly this must be a persistant setting finally
264  
265 public bool IsWaitingForFirstSpinUpdatePacket;
266  
267 public Quaternion SpinOldOrientation = Quaternion.Identity;
268  
269 protected int m_APIDIterations = 0;
270 protected Quaternion m_APIDTarget = Quaternion.Identity;
271 protected float m_APIDDamp = 0;
272 protected float m_APIDStrength = 0;
273  
274 /// <summary>
275 /// This part's inventory
276 /// </summary>
277 public IEntityInventory Inventory
278 {
279 get { return m_inventory; }
280 }
281 protected SceneObjectPartInventory m_inventory;
282  
283 public bool Undoing;
284  
285 public bool IgnoreUndoUpdate = false;
286  
287 public PrimFlags LocalFlags;
288  
289 private float m_damage = -1.0f;
290 private byte[] m_TextureAnimation;
291 private byte m_clickAction;
292 private Color m_color = Color.Black;
293 private readonly List<uint> m_lastColliders = new List<uint>();
294 private int m_linkNum;
295  
296 private int m_scriptAccessPin;
297  
298 private readonly Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
299 private string m_sitName = String.Empty;
300 private Quaternion m_sitTargetOrientation = Quaternion.Identity;
301 private Vector3 m_sitTargetPosition;
302 private string m_sitAnimation = "SIT";
303 private string m_text = String.Empty;
304 private string m_touchName = String.Empty;
305 private readonly List<UndoState> m_undo = new List<UndoState>(5);
306 private readonly List<UndoState> m_redo = new List<UndoState>(5);
307  
308 private bool m_passTouches = false;
309 private bool m_passCollisions = false;
310  
311 protected Vector3 m_acceleration;
312 protected Vector3 m_angularVelocity;
313  
314 //unkown if this will be kept, added as a way of removing the group position from the group class
315 protected Vector3 m_groupPosition;
316 protected uint m_localId;
317 protected Material m_material = OpenMetaverse.Material.Wood;
318 protected string m_name;
319 protected Vector3 m_offsetPosition;
320  
321 protected SceneObjectGroup m_parentGroup;
322 protected byte[] m_particleSystem = Utils.EmptyBytes;
323 protected ulong m_regionHandle;
324 protected Quaternion m_rotationOffset = Quaternion.Identity;
325 protected PrimitiveBaseShape m_shape;
326 protected UUID m_uuid;
327 protected Vector3 m_velocity;
328  
329 protected Vector3 m_lastPosition;
330 protected Quaternion m_lastRotation;
331 protected Vector3 m_lastVelocity;
332 protected Vector3 m_lastAcceleration;
333 protected Vector3 m_lastAngularVelocity;
334 protected int m_lastTerseSent;
335  
336 protected byte m_physicsShapeType = (byte)PhysShapeType.prim;
337 protected float m_density = 1000.0f; // in kg/m^3
338 protected float m_gravitymod = 1.0f;
339 protected float m_friction = 0.6f; // wood
340 protected float m_bounce = 0.5f; // wood
341  
342 /// <summary>
343 /// Stores media texture data
344 /// </summary>
345 protected string m_mediaUrl;
346  
347 // TODO: Those have to be changed into persistent properties at some later point,
348 // or sit-camera on vehicles will break on sim-crossing.
349 private Vector3 m_cameraEyeOffset;
350 private Vector3 m_cameraAtOffset;
351 private bool m_forceMouselook;
352  
353 // TODO: Collision sound should have default.
354 private UUID m_collisionSound;
355 private float m_collisionSoundVolume;
356  
357 public KeyframeMotion KeyframeMotion
358 {
359 get; set;
360 }
361  
362 #endregion Fields
363  
364 // ~SceneObjectPart()
365 // {
366 // Console.WriteLine(
367 // "[SCENE OBJECT PART]: Destructor called for {0}, local id {1}, parent {2} {3}",
368 // Name, LocalId, ParentGroup.Name, ParentGroup.LocalId);
369 // m_log.DebugFormat(
370 // "[SCENE OBJECT PART]: Destructor called for {0}, local id {1}, parent {2} {3}",
371 // Name, LocalId, ParentGroup.Name, ParentGroup.LocalId);
372 // }
373  
374 #region Constructors
375  
376 /// <summary>
377 /// No arg constructor called by region restore db code
378 /// </summary>
379 public SceneObjectPart()
380 {
381 m_TextureAnimation = Utils.EmptyBytes;
382 m_particleSystem = Utils.EmptyBytes;
383 Rezzed = DateTime.UtcNow;
384 Description = String.Empty;
385 DynAttrs = new DAMap();
386  
387 // Prims currently only contain a single folder (Contents). From looking at the Second Life protocol,
388 // this appears to have the same UUID (!) as the prim. If this isn't the case, one can't drag items from
389 // the prim into an agent inventory (Linden client reports that the "Object not found for drop" in its log
390 m_inventory = new SceneObjectPartInventory(this);
391 }
392  
393 /// <summary>
394 /// Create a completely new SceneObjectPart (prim). This will need to be added separately to a SceneObjectGroup
395 /// </summary>
396 /// <param name="ownerID"></param>
397 /// <param name="shape"></param>
398 /// <param name="position"></param>
399 /// <param name="rotationOffset"></param>
400 /// <param name="offsetPosition"></param>
401 public SceneObjectPart(
402 UUID ownerID, PrimitiveBaseShape shape, Vector3 groupPosition,
403 Quaternion rotationOffset, Vector3 offsetPosition) : this()
404 {
405 m_name = "Primitive";
406  
407 CreationDate = (int)Utils.DateTimeToUnixTime(Rezzed);
408 LastOwnerID = CreatorID = OwnerID = ownerID;
409 UUID = UUID.Random();
410 Shape = shape;
411 OwnershipCost = 0;
412 ObjectSaleType = 0;
413 SalePrice = 0;
414 Category = 0;
415 GroupPosition = groupPosition;
416 OffsetPosition = offsetPosition;
417 RotationOffset = rotationOffset;
418 Velocity = Vector3.Zero;
419 AngularVelocity = Vector3.Zero;
420 Acceleration = Vector3.Zero;
421 Flags = 0;
422 CreateSelected = true;
423  
424 TrimPermissions();
425 }
426  
427 #endregion Constructors
428  
429 #region XML Schema
430  
431 private UUID _lastOwnerID;
432 private UUID _ownerID;
433 private UUID _groupID;
434 private int _ownershipCost;
435 private byte _objectSaleType;
436 private int _salePrice;
437 private uint _category;
438 private Int32 _creationDate;
439 private uint _parentID = 0;
440 private uint _baseMask = (uint)(PermissionMask.All | PermissionMask.Export);
441 private uint _ownerMask = (uint)(PermissionMask.All | PermissionMask.Export);
442 private uint _groupMask = (uint)PermissionMask.None;
443 private uint _everyoneMask = (uint)PermissionMask.None;
444 private uint _nextOwnerMask = (uint)PermissionMask.All;
445 private PrimFlags _flags = PrimFlags.None;
446 private DateTime m_expires;
447 private DateTime m_rezzed;
448 private bool m_createSelected = false;
449  
450 private UUID _creatorID;
451 public UUID CreatorID
452 {
453 get { return _creatorID; }
454 set { _creatorID = value; }
455 }
456  
457 private string m_creatorData = string.Empty;
458 /// <summary>
459 /// Data about the creator in the form home_url;name
460 /// </summary>
461 public string CreatorData
462 {
463 get { return m_creatorData; }
464 set { m_creatorData = value; }
465 }
466  
467 /// <summary>
468 /// Used by the DB layer to retrieve / store the entire user identification.
469 /// The identification can either be a simple UUID or a string of the form
470 /// uuid[;home_url[;name]]
471 /// </summary>
472 public string CreatorIdentification
473 {
474 get
475 {
476 if (!string.IsNullOrEmpty(CreatorData))
477 return CreatorID.ToString() + ';' + CreatorData;
478 else
479 return CreatorID.ToString();
480 }
481 set
482 {
483 if ((value == null) || (value != null && value == string.Empty))
484 {
485 CreatorData = string.Empty;
486 return;
487 }
488  
489 if (!value.Contains(";")) // plain UUID
490 {
491 UUID uuid = UUID.Zero;
492 UUID.TryParse(value, out uuid);
493 CreatorID = uuid;
494 }
495 else // <uuid>[;<endpoint>[;name]]
496 {
497 string name = "Unknown User";
498 string[] parts = value.Split(';');
499 if (parts.Length >= 1)
500 {
501 UUID uuid = UUID.Zero;
502 UUID.TryParse(parts[0], out uuid);
503 CreatorID = uuid;
504 }
505 if (parts.Length >= 2)
506 {
507 CreatorData = parts[1];
508 if (!CreatorData.EndsWith("/"))
509 CreatorData += "/";
510 }
511 if (parts.Length >= 3)
512 name = parts[2];
513  
514 CreatorData += ';' + name;
515  
516 }
517 }
518 }
519  
520 /// <summary>
521 /// A relic from when we we thought that prims contained folder objects. In
522 /// reality, prim == folder
523 /// Exposing this is not particularly good, but it's one of the least evils at the moment to see
524 /// folder id from prim inventory item data, since it's not (yet) actually stored with the prim.
525 /// </summary>
526 public UUID FolderID
527 {
528 get { return UUID; }
529 set { } // Don't allow assignment, or legacy prims wil b0rk - but we need the setter for legacy serialization.
530 }
531  
532 /// <value>
533 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes
534 /// </value>
535 public uint InventorySerial
536 {
537 get { return m_inventory.Serial; }
538 set { m_inventory.Serial = value; }
539 }
540  
541 /// <value>
542 /// Access should be via Inventory directly - this property temporarily remains for xml serialization purposes
543 /// </value>
544 public TaskInventoryDictionary TaskInventory
545 {
546 get { return m_inventory.Items; }
547 set { m_inventory.Items = value; }
548 }
549  
550 /// <summary>
551 /// This is idential to the Flags property, except that the returned value is uint rather than PrimFlags
552 /// </summary>
553 [Obsolete("Use Flags property instead")]
554 public uint ObjectFlags
555 {
556 get { return (uint)Flags; }
557 set { Flags = (PrimFlags)value; }
558 }
559  
560 public UUID UUID
561 {
562 get { return m_uuid; }
563 set
564 {
565 m_uuid = value;
566  
567 // This is necessary so that TaskInventoryItem parent ids correctly reference the new uuid of this part
568 if (Inventory != null)
569 Inventory.ResetObjectID();
570 }
571 }
572  
573 public uint LocalId
574 {
575 get { return m_localId; }
576 set
577 {
578 m_localId = value;
579 // m_log.DebugFormat("[SCENE OBJECT PART]: Set part {0} to local id {1}", Name, m_localId);
580 }
581 }
582  
583 public virtual string Name
584 {
585 get { return m_name; }
586 set
587 {
588 m_name = value;
589  
590 PhysicsActor pa = PhysActor;
591  
592 if (pa != null)
593 pa.SOPName = value;
594 }
595 }
596  
597 public byte Material
598 {
599 get { return (byte) m_material; }
600 set
601 {
602 m_material = (Material)value;
603  
604 PhysicsActor pa = PhysActor;
605  
606 if (pa != null)
607 pa.SetMaterial((int)value);
608 }
609 }
610  
611 [XmlIgnore]
612 public bool PassTouches
613 {
614 get { return m_passTouches; }
615 set
616 {
617 m_passTouches = value;
618  
619 if (ParentGroup != null)
620 ParentGroup.HasGroupChanged = true;
621 }
622 }
623  
624 public bool PassCollisions
625 {
626 get { return m_passCollisions; }
627 set
628 {
629 m_passCollisions = value;
630  
631 if (ParentGroup != null)
632 ParentGroup.HasGroupChanged = true;
633 }
634 }
635  
636 public Dictionary<int, string> CollisionFilter
637 {
638 get { return m_CollisionFilter; }
639 set
640 {
641 m_CollisionFilter = value;
642 }
643 }
644  
645 protected Quaternion APIDTarget
646 {
647 get { return m_APIDTarget; }
648 set { m_APIDTarget = value; }
649 }
650  
651  
652 protected float APIDDamp
653 {
654 get { return m_APIDDamp; }
655 set { m_APIDDamp = value; }
656 }
657  
658  
659 protected float APIDStrength
660 {
661 get { return m_APIDStrength; }
662 set { m_APIDStrength = value; }
663 }
664  
665 public ulong RegionHandle
666 {
667 get { return m_regionHandle; }
668 set { m_regionHandle = value; }
669 }
670  
671 public int ScriptAccessPin
672 {
673 get { return m_scriptAccessPin; }
674 set { m_scriptAccessPin = (int)value; }
675 }
676 private SceneObjectPart m_PlaySoundMasterPrim = null;
677 public SceneObjectPart PlaySoundMasterPrim
678 {
679 get { return m_PlaySoundMasterPrim; }
680 set { m_PlaySoundMasterPrim = value; }
681 }
682  
683 private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>();
684 public List<SceneObjectPart> PlaySoundSlavePrims
685 {
686 get { return m_PlaySoundSlavePrims; }
687 set { m_PlaySoundSlavePrims = value; }
688 }
689  
690 private SceneObjectPart m_LoopSoundMasterPrim = null;
691 public SceneObjectPart LoopSoundMasterPrim
692 {
693 get { return m_LoopSoundMasterPrim; }
694 set { m_LoopSoundMasterPrim = value; }
695 }
696  
697 private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>();
698 public List<SceneObjectPart> LoopSoundSlavePrims
699 {
700 get { return m_LoopSoundSlavePrims; }
701 set { m_LoopSoundSlavePrims = value; }
702 }
703  
704  
705 public Byte[] TextureAnimation
706 {
707 get { return m_TextureAnimation; }
708 set { m_TextureAnimation = value; }
709 }
710  
711  
712 public Byte[] ParticleSystem
713 {
714 get { return m_particleSystem; }
715 set { m_particleSystem = value; }
716 }
717  
718  
719 public DateTime Expires
720 {
721 get { return m_expires; }
722 set { m_expires = value; }
723 }
724  
725  
726 public DateTime Rezzed
727 {
728 get { return m_rezzed; }
729 set { m_rezzed = value; }
730 }
731  
732  
733 public float Damage
734 {
735 get { return m_damage; }
736 set { m_damage = value; }
737 }
738  
739 /// <summary>
740 /// The position of the entire group that this prim belongs to.
741 /// </summary>
742 public Vector3 GroupPosition
743 {
744 get
745 {
746 // If this is a linkset, we don't want the physics engine mucking up our group position here.
747 PhysicsActor actor = PhysActor;
748 // If physical and the root prim of a linkset, the position of the group is what physics thinks.
749 if (actor != null && ParentID == 0)
750 m_groupPosition = actor.Position;
751  
752 // If I'm an attachment, my position is reported as the position of who I'm attached to
753 if (ParentGroup.IsAttachment)
754 {
755 ScenePresence sp = ParentGroup.Scene.GetScenePresence(ParentGroup.AttachedAvatar);
756 if (sp != null)
757 return sp.AbsolutePosition;
758 }
759  
760 return m_groupPosition;
761 }
762 set
763 {
764 m_groupPosition = value;
765  
766 PhysicsActor actor = PhysActor;
767 if (actor != null)
768 {
769 try
770 {
771 // Root prim actually goes at Position
772 if (ParentID == 0)
773 {
774 actor.Position = value;
775 }
776 else
777 {
778 // The physics engine always sees all objects (root or linked) in world coordinates.
779 actor.Position = GetWorldPosition();
780 actor.Orientation = GetWorldRotation();
781 }
782  
783 // Tell the physics engines that this prim changed.
784 if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null)
785 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
786 }
787 catch (Exception e)
788 {
789 m_log.ErrorFormat("[SCENEOBJECTPART]: GROUP POSITION. {0}", e);
790 }
791 }
792 }
793 }
794  
795 public Vector3 OffsetPosition
796 {
797 get { return m_offsetPosition; }
798 set
799 {
800 // StoreUndoState();
801 m_offsetPosition = value;
802  
803 if (ParentGroup != null && !ParentGroup.IsDeleted)
804 {
805 PhysicsActor actor = PhysActor;
806 if (ParentID != 0 && actor != null)
807 {
808 actor.Position = GetWorldPosition();
809 actor.Orientation = GetWorldRotation();
810  
811 // Tell the physics engines that this prim changed.
812 if (ParentGroup.Scene != null)
813 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
814 }
815 }
816 }
817 }
818  
819 public Vector3 RelativePosition
820 {
821 get
822 {
823 if (IsRoot)
824 {
825 if (ParentGroup.IsAttachment)
826 return AttachedPos;
827 else
828 return AbsolutePosition;
829 }
830 else
831 {
832 return OffsetPosition;
833 }
834 }
835 }
836  
837 public Quaternion RotationOffset
838 {
839 get
840 {
841 // We don't want the physics engine mucking up the rotations in a linkset
842 PhysicsActor actor = PhysActor;
843 // If this is a root of a linkset, the real rotation is what the physics engine thinks.
844 // If not a root prim, the offset rotation is computed by SOG and is relative to the root.
845 if (ParentID == 0 && (Shape.PCode != 9 || Shape.State == 0) && actor != null)
846 {
847 if (actor.Orientation.X != 0f || actor.Orientation.Y != 0f
848 || actor.Orientation.Z != 0f || actor.Orientation.W != 0f)
849 {
850 m_rotationOffset = actor.Orientation;
851 }
852 }
853  
854 // float roll, pitch, yaw = 0;
855 // m_rotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
856 //
857 // m_log.DebugFormat(
858 // "[SCENE OBJECT PART]: Got euler {0} for RotationOffset on {1} {2}",
859 // new Vector3(roll, pitch, yaw), Name, LocalId);
860  
861 return m_rotationOffset;
862 }
863  
864 set
865 {
866 StoreUndoState();
867 m_rotationOffset = value;
868  
869 PhysicsActor actor = PhysActor;
870 if (actor != null)
871 {
872 try
873 {
874 // Root prim gets value directly
875 if (ParentID == 0)
876 {
877 actor.Orientation = value;
878 //m_log.Info("[PART]: RO1:" + actor.Orientation.ToString());
879 }
880 else
881 {
882 // Child prim we have to calculate it's world rotationwel
883 Quaternion resultingrotation = GetWorldRotation();
884 actor.Orientation = resultingrotation;
885 //m_log.Info("[PART]: RO2:" + actor.Orientation.ToString());
886 }
887  
888 if (ParentGroup != null && ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null)
889 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
890 //}
891 }
892 catch (Exception ex)
893 {
894 m_log.Error("[SCENEOBJECTPART]: ROTATIONOFFSET" + ex.Message);
895 }
896 }
897  
898 // float roll, pitch, yaw = 0;
899 // m_rotationOffset.GetEulerAngles(out roll, out pitch, out yaw);
900 //
901 // m_log.DebugFormat(
902 // "[SCENE OBJECT PART]: Set euler {0} for RotationOffset on {1} {2}",
903 // new Vector3(roll, pitch, yaw), Name, LocalId);
904 }
905 }
906  
907 /// <summary></summary>
908 public Vector3 Velocity
909 {
910 get
911 {
912 PhysicsActor actor = PhysActor;
913 if (actor != null)
914 {
915 if (actor.IsPhysical)
916 {
917 m_velocity = actor.Velocity;
918 }
919 }
920  
921 return m_velocity;
922 }
923  
924 set
925 {
926 m_velocity = value;
927  
928 PhysicsActor actor = PhysActor;
929 if (actor != null)
930 {
931 if (actor.IsPhysical)
932 {
933 actor.Velocity = value;
934 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
935 }
936 }
937 }
938 }
939  
940 /// <summary>Update angular velocity and schedule terse update.</summary>
941 public void UpdateAngularVelocity(Vector3 avel)
942 {
943 AngularVelocity = avel;
944 ScheduleTerseUpdate();
945 ParentGroup.HasGroupChanged = true;
946 }
947  
948 /// <summary>Get or set angular velocity. Does not schedule update.</summary>
949 public Vector3 AngularVelocity
950 {
951 get
952 {
953 PhysicsActor actor = PhysActor;
954 if ((actor != null) && actor.IsPhysical)
955 {
956 m_angularVelocity = actor.RotationalVelocity;
957 }
958 return m_angularVelocity;
959 }
960 set { m_angularVelocity = value; }
961 }
962  
963 /// <summary></summary>
964 public Vector3 Acceleration
965 {
966 get { return m_acceleration; }
967 set { m_acceleration = value; }
968 }
969  
970 public string Description { get; set; }
971  
972 /// <value>
973 /// Text color.
974 /// </value>
975 public Color Color
976 {
977 get { return m_color; }
978 set { m_color = value; }
979 }
980  
981 public string Text
982 {
983 get
984 {
985 if (m_text.Length > 255)
986 return m_text.Substring(0, 254);
987 return m_text;
988 }
989 set { m_text = value; }
990 }
991  
992  
993 public string SitName
994 {
995 get { return m_sitName; }
996 set { m_sitName = value; }
997 }
998  
999 public string TouchName
1000 {
1001 get { return m_touchName; }
1002 set { m_touchName = value; }
1003 }
1004  
1005 public int LinkNum
1006 {
1007 get { return m_linkNum; }
1008 set
1009 {
1010 // if (ParentGroup != null)
1011 // {
1012 // m_log.DebugFormat(
1013 // "[SCENE OBJECT PART]: Setting linknum of {0}@{1} to {2} from {3}",
1014 // Name, AbsolutePosition, value, m_linkNum);
1015 // Util.PrintCallStack();
1016 // }
1017  
1018 m_linkNum = value;
1019 }
1020 }
1021  
1022 public byte ClickAction
1023 {
1024 get { return m_clickAction; }
1025 set
1026 {
1027 m_clickAction = value;
1028 }
1029 }
1030  
1031 public PrimitiveBaseShape Shape
1032 {
1033 get { return m_shape; }
1034 set { m_shape = value;}
1035 }
1036  
1037 /// <summary>
1038 /// Change the scale of this part.
1039 /// </summary>
1040 public Vector3 Scale
1041 {
1042 get { return m_shape.Scale; }
1043 set
1044 {
1045 if (m_shape != null)
1046 {
1047 StoreUndoState();
1048  
1049 m_shape.Scale = value;
1050  
1051 PhysicsActor actor = PhysActor;
1052 if (actor != null)
1053 {
1054 if (ParentGroup.Scene != null)
1055 {
1056 if (ParentGroup.Scene.PhysicsScene != null)
1057 {
1058 actor.Size = m_shape.Scale;
1059  
1060 // if (Shape.SculptEntry)
1061 // CheckSculptAndLoad();
1062 // else
1063 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(actor);
1064 }
1065 }
1066 }
1067 }
1068  
1069 TriggerScriptChangedEvent(Changed.SCALE);
1070 }
1071 }
1072  
1073 public UpdateRequired UpdateFlag { get; set; }
1074 public bool UpdatePhysRequired { get; set; }
1075  
1076 /// <summary>
1077 /// Used for media on a prim.
1078 /// </summary>
1079 /// Do not change this value directly - always do it through an IMoapModule.
1080 public string MediaUrl
1081 {
1082 get
1083 {
1084 return m_mediaUrl;
1085 }
1086  
1087 set
1088 {
1089 m_mediaUrl = value;
1090  
1091 if (ParentGroup != null)
1092 ParentGroup.HasGroupChanged = true;
1093 }
1094 }
1095  
1096 public bool CreateSelected
1097 {
1098 get { return m_createSelected; }
1099 set
1100 {
1101 // m_log.DebugFormat("[SOP]: Setting CreateSelected to {0} for {1} {2}", value, Name, UUID);
1102 m_createSelected = value;
1103 }
1104 }
1105  
1106 #endregion
1107  
1108 //---------------
1109 #region Public Properties with only Get
1110  
1111 public Vector3 AbsolutePosition
1112 {
1113 get
1114 {
1115 if (ParentGroup.IsAttachment)
1116 return GroupPosition;
1117  
1118 return m_offsetPosition + m_groupPosition;
1119 }
1120 }
1121  
1122 public SceneObjectGroup ParentGroup
1123 {
1124 get { return m_parentGroup; }
1125 private set { m_parentGroup = value; }
1126 }
1127  
1128 public scriptEvents ScriptEvents
1129 {
1130 get { return AggregateScriptEvents; }
1131 }
1132  
1133 public Quaternion SitTargetOrientation
1134 {
1135 get { return m_sitTargetOrientation; }
1136 set
1137 {
1138 m_sitTargetOrientation = value;
1139 // m_log.DebugFormat("[SCENE OBJECT PART]: Set sit target orientation {0} for {1} {2}", m_sitTargetOrientation, Name, LocalId);
1140 }
1141 }
1142  
1143 public Vector3 SitTargetPosition
1144 {
1145 get { return m_sitTargetPosition; }
1146 set
1147 {
1148 m_sitTargetPosition = value;
1149 // m_log.DebugFormat("[SCENE OBJECT PART]: Set sit target position to {0} for {1} {2}", m_sitTargetPosition, Name, LocalId);
1150 }
1151 }
1152  
1153 // This sort of sucks, but I'm adding these in to make some of
1154 // the mappings more consistant.
1155 public Vector3 SitTargetPositionLL
1156 {
1157 get { return m_sitTargetPosition; }
1158 set { m_sitTargetPosition = value; }
1159 }
1160  
1161 public Quaternion SitTargetOrientationLL
1162 {
1163 get { return m_sitTargetOrientation; }
1164 set { m_sitTargetOrientation = value; }
1165 }
1166  
1167 public bool Stopped
1168 {
1169 get {
1170 double threshold = 0.02;
1171 return (Math.Abs(Velocity.X) < threshold &&
1172 Math.Abs(Velocity.Y) < threshold &&
1173 Math.Abs(Velocity.Z) < threshold &&
1174 Math.Abs(AngularVelocity.X) < threshold &&
1175 Math.Abs(AngularVelocity.Y) < threshold &&
1176 Math.Abs(AngularVelocity.Z) < threshold);
1177 }
1178 }
1179  
1180 /// <summary>
1181 /// The parent ID of this part.
1182 /// </summary>
1183 /// <remarks>
1184 /// If this is a root part which is not attached to an avatar then the value will be 0.
1185 /// If this is a root part which is attached to an avatar then the value is the local id of that avatar.
1186 /// If this is a child part then the value is the local ID of the root part.
1187 /// </remarks>
1188 public uint ParentID
1189 {
1190 get { return _parentID; }
1191 set { _parentID = value; }
1192 }
1193  
1194 public int CreationDate
1195 {
1196 get { return _creationDate; }
1197 set { _creationDate = value; }
1198 }
1199  
1200 public uint Category
1201 {
1202 get { return _category; }
1203 set { _category = value; }
1204 }
1205  
1206 public int SalePrice
1207 {
1208 get { return _salePrice; }
1209 set { _salePrice = value; }
1210 }
1211  
1212 public byte ObjectSaleType
1213 {
1214 get { return _objectSaleType; }
1215 set { _objectSaleType = value; }
1216 }
1217  
1218 public int OwnershipCost
1219 {
1220 get { return _ownershipCost; }
1221 set { _ownershipCost = value; }
1222 }
1223  
1224 public UUID GroupID
1225 {
1226 get { return _groupID; }
1227 set { _groupID = value; }
1228 }
1229  
1230 public UUID OwnerID
1231 {
1232 get { return _ownerID; }
1233 set { _ownerID = value; }
1234 }
1235  
1236 public UUID LastOwnerID
1237 {
1238 get { return _lastOwnerID; }
1239 set { _lastOwnerID = value; }
1240 }
1241  
1242 public uint BaseMask
1243 {
1244 get { return _baseMask; }
1245 set { _baseMask = value; }
1246 }
1247  
1248 public uint OwnerMask
1249 {
1250 get { return _ownerMask; }
1251 set { _ownerMask = value; }
1252 }
1253  
1254 public uint GroupMask
1255 {
1256 get { return _groupMask; }
1257 set { _groupMask = value; }
1258 }
1259  
1260 public uint EveryoneMask
1261 {
1262 get { return _everyoneMask; }
1263 set { _everyoneMask = value; }
1264 }
1265  
1266 public uint NextOwnerMask
1267 {
1268 get { return _nextOwnerMask; }
1269 set { _nextOwnerMask = value; }
1270 }
1271  
1272 /// <summary>
1273 /// Property flags. See OpenMetaverse.PrimFlags
1274 /// </summary>
1275 /// <remarks>
1276 /// Example properties are PrimFlags.Phantom and PrimFlags.DieAtEdge
1277 /// </remarks>
1278 public PrimFlags Flags
1279 {
1280 get { return _flags; }
1281 set
1282 {
1283 // m_log.DebugFormat("[SOP]: Setting flags for {0} {1} to {2}", UUID, Name, value);
1284 _flags = value;
1285 }
1286 }
1287  
1288 /// <summary>
1289 /// ID of the avatar that is sat on us if we have a sit target. If there is no such avatar then is UUID.Zero
1290 /// </summary>
1291 public UUID SitTargetAvatar { get; set; }
1292  
1293 /// <summary>
1294 /// IDs of all avatars sat on this part.
1295 /// </summary>
1296 /// <remarks>
1297 /// We need to track this so that we can stop sat upon prims from being attached.
1298 /// </remarks>
1299 /// <value>
1300 /// null if there are no sitting avatars. This is to save us create a hashset for every prim in a scene.
1301 /// </value>
1302 private HashSet<UUID> m_sittingAvatars;
1303  
1304 public virtual UUID RegionID
1305 {
1306 get
1307 {
1308 if (ParentGroup.Scene != null)
1309 return ParentGroup.Scene.RegionInfo.RegionID;
1310 else
1311 return UUID.Zero;
1312 }
1313 set {} // read only
1314 }
1315  
1316 private UUID _parentUUID = UUID.Zero;
1317  
1318 public UUID ParentUUID
1319 {
1320 get
1321 {
1322 if (ParentGroup != null)
1323 _parentUUID = ParentGroup.UUID;
1324  
1325 return _parentUUID;
1326 }
1327  
1328 set { _parentUUID = value; }
1329 }
1330  
1331 public string SitAnimation
1332 {
1333 get { return m_sitAnimation; }
1334 set { m_sitAnimation = value; }
1335 }
1336  
1337 public UUID CollisionSound
1338 {
1339 get { return m_collisionSound; }
1340 set
1341 {
1342 m_collisionSound = value;
1343 aggregateScriptEvents();
1344 }
1345 }
1346  
1347 public float CollisionSoundVolume
1348 {
1349 get { return m_collisionSoundVolume; }
1350 set { m_collisionSoundVolume = value; }
1351 }
1352  
1353 public byte DefaultPhysicsShapeType()
1354 {
1355 byte type;
1356  
1357 if (Shape != null && (Shape.SculptType == (byte)SculptType.Mesh))
1358 type = (byte)PhysShapeType.convex;
1359 else
1360 type = (byte)PhysShapeType.prim;
1361  
1362 return type;
1363 }
1364  
1365 public byte PhysicsShapeType
1366 {
1367 get { return m_physicsShapeType; }
1368 set
1369 {
1370 byte oldv = m_physicsShapeType;
1371  
1372 if (value >= 0 && value <= (byte)PhysShapeType.convex)
1373 {
1374 if (value == (byte)PhysShapeType.none && ParentGroup != null && ParentGroup.RootPart == this)
1375 m_physicsShapeType = DefaultPhysicsShapeType();
1376 else
1377 m_physicsShapeType = value;
1378 }
1379 else
1380 m_physicsShapeType = DefaultPhysicsShapeType();
1381  
1382 if (m_physicsShapeType != oldv && ParentGroup != null)
1383 {
1384 if (m_physicsShapeType == (byte)PhysShapeType.none)
1385 {
1386 if (PhysActor != null)
1387 {
1388 Velocity = new Vector3(0, 0, 0);
1389 Acceleration = new Vector3(0, 0, 0);
1390 if (ParentGroup.RootPart == this)
1391 AngularVelocity = new Vector3(0, 0, 0);
1392 ParentGroup.Scene.RemovePhysicalPrim(1);
1393 RemoveFromPhysics();
1394 }
1395 }
1396 else if (PhysActor == null)
1397 {
1398 ApplyPhysics((uint)Flags, VolumeDetectActive);
1399 }
1400 else
1401 {
1402 PhysActor.PhysicsShapeType = m_physicsShapeType;
1403 }
1404  
1405 if (ParentGroup != null)
1406 ParentGroup.HasGroupChanged = true;
1407 }
1408  
1409 if (m_physicsShapeType != value)
1410 {
1411 UpdatePhysRequired = true;
1412 }
1413 }
1414 }
1415  
1416 public float Density // in kg/m^3
1417 {
1418 get { return m_density; }
1419 set
1420 {
1421 if (value >=1 && value <= 22587.0)
1422 {
1423 m_density = value;
1424 UpdatePhysRequired = true;
1425 }
1426  
1427 ScheduleFullUpdateIfNone();
1428  
1429 if (ParentGroup != null)
1430 ParentGroup.HasGroupChanged = true;
1431  
1432 PhysicsActor pa = PhysActor;
1433 if (pa != null)
1434 pa.Density = Density;
1435 }
1436 }
1437  
1438 public float GravityModifier
1439 {
1440 get { return m_gravitymod; }
1441 set
1442 {
1443 if( value >= -1 && value <=28.0f)
1444 {
1445 m_gravitymod = value;
1446 UpdatePhysRequired = true;
1447 }
1448  
1449 ScheduleFullUpdateIfNone();
1450  
1451 if (ParentGroup != null)
1452 ParentGroup.HasGroupChanged = true;
1453  
1454 PhysicsActor pa = PhysActor;
1455 if (pa != null)
1456 pa.GravModifier = GravityModifier;
1457 }
1458 }
1459  
1460 public float Friction
1461 {
1462 get { return m_friction; }
1463 set
1464 {
1465 if (value >= 0 && value <= 255.0f)
1466 {
1467 m_friction = value;
1468 UpdatePhysRequired = true;
1469 }
1470  
1471 ScheduleFullUpdateIfNone();
1472  
1473 if (ParentGroup != null)
1474 ParentGroup.HasGroupChanged = true;
1475  
1476 PhysicsActor pa = PhysActor;
1477 if (pa != null)
1478 pa.Friction = Friction;
1479 }
1480 }
1481  
1482 public float Restitution
1483 {
1484 get { return m_bounce; }
1485 set
1486 {
1487 if (value >= 0 && value <= 1.0f)
1488 {
1489 m_bounce = value;
1490 UpdatePhysRequired = true;
1491 }
1492  
1493 ScheduleFullUpdateIfNone();
1494  
1495 if (ParentGroup != null)
1496 ParentGroup.HasGroupChanged = true;
1497  
1498 PhysicsActor pa = PhysActor;
1499 if (pa != null)
1500 pa.Restitution = Restitution;
1501 }
1502 }
1503  
1504 #endregion Public Properties with only Get
1505  
1506 private uint ApplyMask(uint val, bool set, uint mask)
1507 {
1508 if (set)
1509 {
1510 return val |= mask;
1511 }
1512 else
1513 {
1514 return val &= ~mask;
1515 }
1516 }
1517  
1518 /// <summary>
1519 /// Clear all pending updates of parts to clients
1520 /// </summary>
1521 public void ClearUpdateSchedule()
1522 {
1523 UpdateFlag = UpdateRequired.NONE;
1524 }
1525  
1526 /// <summary>
1527 /// Send this part's properties (name, description, inventory serial, base mask, etc.) to a client
1528 /// </summary>
1529 /// <param name="client"></param>
1530 public void SendPropertiesToClient(IClientAPI client)
1531 {
1532 client.SendObjectPropertiesReply(this);
1533 }
1534  
1535 // TODO: unused:
1536 // private void handleTimerAccounting(uint localID, double interval)
1537 // {
1538 // if (localID == LocalId)
1539 // {
1540 // float sec = (float)interval;
1541 // if (m_parentGroup != null)
1542 // {
1543 // if (sec == 0)
1544 // {
1545 // if (m_parentGroup.scriptScore + 0.001f >= float.MaxValue - 0.001)
1546 // m_parentGroup.scriptScore = 0;
1547 //
1548 // m_parentGroup.scriptScore += 0.001f;
1549 // return;
1550 // }
1551 //
1552 // if (m_parentGroup.scriptScore + (0.001f / sec) >= float.MaxValue - (0.001f / sec))
1553 // m_parentGroup.scriptScore = 0;
1554 // m_parentGroup.scriptScore += (0.001f / sec);
1555 // }
1556 // }
1557 // }
1558  
1559 #region Public Methods
1560  
1561 public void ResetExpire()
1562 {
1563 Expires = DateTime.Now + new TimeSpan(600000000);
1564 }
1565  
1566 public void AddFlag(PrimFlags flag)
1567 {
1568 // PrimFlags prevflag = Flags;
1569 if ((Flags & flag) == 0)
1570 {
1571 //m_log.Debug("Adding flag: " + ((PrimFlags) flag).ToString());
1572 Flags |= flag;
1573  
1574 if (flag == PrimFlags.TemporaryOnRez)
1575 ResetExpire();
1576 }
1577 // m_log.Debug("Aprev: " + prevflag.ToString() + " curr: " + Flags.ToString());
1578 }
1579  
1580 public void AddNewParticleSystem(Primitive.ParticleSystem pSystem)
1581 {
1582 m_particleSystem = pSystem.GetBytes();
1583 }
1584  
1585 public void RemoveParticleSystem()
1586 {
1587 m_particleSystem = new byte[0];
1588 }
1589  
1590 public void AddTextureAnimation(Primitive.TextureAnimation pTexAnim)
1591 {
1592 byte[] data = new byte[16];
1593 int pos = 0;
1594  
1595 // The flags don't like conversion from uint to byte, so we have to do
1596 // it the crappy way. See the above function :(
1597  
1598 data[pos] = ConvertScriptUintToByte((uint)pTexAnim.Flags); pos++;
1599 data[pos] = (byte)pTexAnim.Face; pos++;
1600 data[pos] = (byte)pTexAnim.SizeX; pos++;
1601 data[pos] = (byte)pTexAnim.SizeY; pos++;
1602  
1603 Utils.FloatToBytes(pTexAnim.Start).CopyTo(data, pos);
1604 Utils.FloatToBytes(pTexAnim.Length).CopyTo(data, pos + 4);
1605 Utils.FloatToBytes(pTexAnim.Rate).CopyTo(data, pos + 8);
1606  
1607 m_TextureAnimation = data;
1608 }
1609  
1610 public void AdjustSoundGain(double volume)
1611 {
1612 if (volume > 1)
1613 volume = 1;
1614 if (volume < 0)
1615 volume = 0;
1616  
1617 ParentGroup.Scene.ForEachRootClient(delegate(IClientAPI client)
1618 {
1619 client.SendAttachedSoundGainChange(UUID, (float)volume);
1620 });
1621 }
1622  
1623 /// <summary>
1624 /// hook to the physics scene to apply impulse
1625 /// This is sent up to the group, which then finds the root prim
1626 /// and applies the force on the root prim of the group
1627 /// </summary>
1628 /// <param name="impulsei">Vector force</param>
1629 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param>
1630 public void ApplyImpulse(Vector3 impulsei, bool localGlobalTF)
1631 {
1632 Vector3 impulse = impulsei;
1633  
1634 if (localGlobalTF)
1635 {
1636 Quaternion grot = GetWorldRotation();
1637 Quaternion AXgrot = grot;
1638 Vector3 AXimpulsei = impulsei;
1639 Vector3 newimpulse = AXimpulsei * AXgrot;
1640 impulse = newimpulse;
1641 }
1642  
1643 if (ParentGroup != null)
1644 {
1645 ParentGroup.applyImpulse(impulse);
1646 }
1647 }
1648  
1649 /// <summary>
1650 /// hook to the physics scene to apply angular impulse
1651 /// This is sent up to the group, which then finds the root prim
1652 /// and applies the force on the root prim of the group
1653 /// </summary>
1654 /// <param name="impulsei">Vector force</param>
1655 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param>
1656 public void ApplyAngularImpulse(Vector3 impulsei, bool localGlobalTF)
1657 {
1658 Vector3 impulse = impulsei;
1659  
1660 if (localGlobalTF)
1661 {
1662 Quaternion grot = GetWorldRotation();
1663 Quaternion AXgrot = grot;
1664 Vector3 AXimpulsei = impulsei;
1665 Vector3 newimpulse = AXimpulsei * AXgrot;
1666 impulse = newimpulse;
1667 }
1668  
1669 ParentGroup.applyAngularImpulse(impulse);
1670 }
1671  
1672 /// <summary>
1673 /// hook to the physics scene to apply angular impulse
1674 /// This is sent up to the group, which then finds the root prim
1675 /// and applies the force on the root prim of the group
1676 /// </summary>
1677 /// <param name="impulsei">Vector force</param>
1678 /// <param name="localGlobalTF">true for the local frame, false for the global frame</param>
1679 public void SetAngularImpulse(Vector3 impulsei, bool localGlobalTF)
1680 {
1681 Vector3 impulse = impulsei;
1682  
1683 if (localGlobalTF)
1684 {
1685 Quaternion grot = GetWorldRotation();
1686 Quaternion AXgrot = grot;
1687 Vector3 AXimpulsei = impulsei;
1688 Vector3 newimpulse = AXimpulsei * AXgrot;
1689 impulse = newimpulse;
1690 }
1691  
1692 ParentGroup.setAngularImpulse(impulse);
1693 }
1694  
1695 /// <summary>
1696 /// Apply physics to this part.
1697 /// </summary>
1698 /// <param name="rootObjectFlags"></param>
1699 /// <param name="VolumeDetectActive"></param>
1700 public void ApplyPhysics(uint rootObjectFlags, bool _VolumeDetectActive)
1701 {
1702 VolumeDetectActive = _VolumeDetectActive;
1703  
1704 if (!ParentGroup.Scene.CollidablePrims)
1705 return;
1706  
1707 if (PhysicsShapeType == (byte)PhysShapeType.none)
1708 return;
1709  
1710 bool isPhysical = (rootObjectFlags & (uint) PrimFlags.Physics) != 0;
1711 bool isPhantom = (rootObjectFlags & (uint) PrimFlags.Phantom) != 0;
1712  
1713 if (_VolumeDetectActive)
1714 isPhantom = true;
1715  
1716 if (IsJoint())
1717 {
1718 DoPhysicsPropertyUpdate(isPhysical, true);
1719 }
1720 else
1721 {
1722 if ((!isPhantom || isPhysical || _VolumeDetectActive) && !ParentGroup.IsAttachment
1723 && !(Shape.PathCurve == (byte)Extrusion.Flexible))
1724 {
1725 AddToPhysics(isPhysical, isPhantom, isPhysical);
1726 }
1727 else
1728 PhysActor = null; // just to be sure
1729 }
1730 }
1731  
1732 public byte ConvertScriptUintToByte(uint indata)
1733 {
1734 byte outdata = (byte)TextureAnimFlags.NONE;
1735 if ((indata & 1) != 0) outdata |= (byte)TextureAnimFlags.ANIM_ON;
1736 if ((indata & 2) != 0) outdata |= (byte)TextureAnimFlags.LOOP;
1737 if ((indata & 4) != 0) outdata |= (byte)TextureAnimFlags.REVERSE;
1738 if ((indata & 8) != 0) outdata |= (byte)TextureAnimFlags.PING_PONG;
1739 if ((indata & 16) != 0) outdata |= (byte)TextureAnimFlags.SMOOTH;
1740 if ((indata & 32) != 0) outdata |= (byte)TextureAnimFlags.ROTATE;
1741 if ((indata & 64) != 0) outdata |= (byte)TextureAnimFlags.SCALE;
1742 return outdata;
1743 }
1744  
1745 /// <summary>
1746 /// Duplicates this part.
1747 /// </summary>
1748 /// <param name="localID"></param>
1749 /// <param name="AgentID"></param>
1750 /// <param name="GroupID"></param>
1751 /// <param name="linkNum"></param>
1752 /// <param name="userExposed">True if the duplicate will immediately be in the scene, false otherwise</param>
1753 /// <returns></returns>
1754 public SceneObjectPart Copy(uint localID, UUID AgentID, UUID GroupID, int linkNum, bool userExposed)
1755 {
1756 SceneObjectPart dupe = (SceneObjectPart)MemberwiseClone();
1757 dupe.m_shape = m_shape.Copy();
1758 dupe.m_regionHandle = m_regionHandle;
1759 if (userExposed)
1760 dupe.UUID = UUID.Random();
1761  
1762 dupe.PhysActor = null;
1763  
1764 dupe.OwnerID = AgentID;
1765 dupe.GroupID = GroupID;
1766 dupe.GroupPosition = GroupPosition;
1767 dupe.OffsetPosition = OffsetPosition;
1768 dupe.RotationOffset = RotationOffset;
1769 dupe.Velocity = Velocity;
1770 dupe.Acceleration = Acceleration;
1771 dupe.AngularVelocity = AngularVelocity;
1772 dupe.Flags = Flags;
1773  
1774 dupe.OwnershipCost = OwnershipCost;
1775 dupe.ObjectSaleType = ObjectSaleType;
1776 dupe.SalePrice = SalePrice;
1777 dupe.Category = Category;
1778 dupe.m_rezzed = m_rezzed;
1779  
1780 dupe.m_inventory = new SceneObjectPartInventory(dupe);
1781 dupe.m_inventory.Items = (TaskInventoryDictionary)m_inventory.Items.Clone();
1782  
1783 if (userExposed)
1784 {
1785 dupe.ResetIDs(linkNum);
1786 dupe.m_inventory.HasInventoryChanged = true;
1787 }
1788 else
1789 {
1790 dupe.m_inventory.HasInventoryChanged = m_inventory.HasInventoryChanged;
1791 }
1792  
1793 // Move afterwards ResetIDs as it clears the localID
1794 dupe.LocalId = localID;
1795 // This may be wrong... it might have to be applied in SceneObjectGroup to the object that's being duplicated.
1796 dupe.LastOwnerID = OwnerID;
1797  
1798 byte[] extraP = new byte[Shape.ExtraParams.Length];
1799 Array.Copy(Shape.ExtraParams, extraP, extraP.Length);
1800 dupe.Shape.ExtraParams = extraP;
1801  
1802 // safeguard actual copy is done in sog.copy
1803 dupe.KeyframeMotion = null;
1804 dupe.PayPrice = (int[])PayPrice.Clone();
1805  
1806 dupe.DynAttrs.CopyFrom(DynAttrs);
1807  
1808 if (userExposed)
1809 {
1810 /*
1811 if (dupe.m_shape.SculptEntry && dupe.m_shape.SculptTexture != UUID.Zero)
1812 {
1813 ParentGroup.Scene.AssetService.Get(
1814 dupe.m_shape.SculptTexture.ToString(), dupe, dupe.AssetReceived);
1815 }
1816 */
1817 bool UsePhysics = ((dupe.Flags & PrimFlags.Physics) != 0);
1818 dupe.DoPhysicsPropertyUpdate(UsePhysics, true);
1819 }
1820  
1821 ParentGroup.Scene.EventManager.TriggerOnSceneObjectPartCopy(dupe, this, userExposed);
1822  
1823 // m_log.DebugFormat("[SCENE OBJECT PART]: Clone of {0} {1} finished", Name, UUID);
1824  
1825 return dupe;
1826 }
1827  
1828 /// <summary>
1829 /// Called back by asynchronous asset fetch.
1830 /// </summary>
1831 /// <param name="id">ID of asset received</param>
1832 /// <param name="sender">Register</param>
1833 /// <param name="asset"></param>
1834 /*
1835 protected void AssetReceived(string id, Object sender, AssetBase asset)
1836 {
1837 if (asset != null)
1838 SculptTextureCallback(asset);
1839 else
1840 m_log.WarnFormat(
1841 "[SCENE OBJECT PART]: Part {0} {1} requested mesh/sculpt data for asset id {2} from asset service but received no data",
1842 Name, UUID, id);
1843 }
1844 */
1845 /// <summary>
1846 /// Do a physics property update for a NINJA joint.
1847 /// </summary>
1848 /// <param name="UsePhysics"></param>
1849 /// <param name="isNew"></param>
1850 protected void DoPhysicsPropertyUpdateForNinjaJoint(bool UsePhysics, bool isNew)
1851 {
1852 if (UsePhysics)
1853 {
1854 // by turning a joint proxy object physical, we cause creation of a joint in the ODE scene.
1855 // note that, as a special case, joints have no bodies or geoms in the physics scene, even though they are physical.
1856  
1857 PhysicsJointType jointType;
1858 if (IsHingeJoint())
1859 {
1860 jointType = PhysicsJointType.Hinge;
1861 }
1862 else if (IsBallJoint())
1863 {
1864 jointType = PhysicsJointType.Ball;
1865 }
1866 else
1867 {
1868 jointType = PhysicsJointType.Ball;
1869 }
1870  
1871 List<string> bodyNames = new List<string>();
1872 string RawParams = Description;
1873 string[] jointParams = RawParams.Split(" ".ToCharArray(), System.StringSplitOptions.RemoveEmptyEntries);
1874 string trackedBodyName = null;
1875 if (jointParams.Length >= 2)
1876 {
1877 for (int iBodyName = 0; iBodyName < 2; iBodyName++)
1878 {
1879 string bodyName = jointParams[iBodyName];
1880 bodyNames.Add(bodyName);
1881 if (bodyName != "NULL")
1882 {
1883 if (trackedBodyName == null)
1884 {
1885 trackedBodyName = bodyName;
1886 }
1887 }
1888 }
1889 }
1890  
1891 SceneObjectPart trackedBody = ParentGroup.Scene.GetSceneObjectPart(trackedBodyName); // FIXME: causes a sequential lookup
1892 Quaternion localRotation = Quaternion.Identity;
1893 if (trackedBody != null)
1894 {
1895 localRotation = Quaternion.Inverse(trackedBody.RotationOffset) * this.RotationOffset;
1896 }
1897 else
1898 {
1899 // error, output it below
1900 }
1901  
1902 PhysicsJoint joint;
1903  
1904 joint = ParentGroup.Scene.PhysicsScene.RequestJointCreation(Name, jointType,
1905 AbsolutePosition,
1906 this.RotationOffset,
1907 Description,
1908 bodyNames,
1909 trackedBodyName,
1910 localRotation);
1911  
1912 if (trackedBody == null)
1913 {
1914 ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name);
1915 }
1916 }
1917 else
1918 {
1919 if (isNew)
1920 {
1921 // if the joint proxy is new, and it is not physical, do nothing. There is no joint in ODE to
1922 // delete, and if we try to delete it, due to asynchronous processing, the deletion request
1923 // will get processed later at an indeterminate time, which could cancel a later-arriving
1924 // joint creation request.
1925 }
1926 else
1927 {
1928 // here we turn off the joint object, so remove the joint from the physics scene
1929 ParentGroup.Scene.PhysicsScene.RequestJointDeletion(Name); // FIXME: what if the name changed?
1930  
1931 // make sure client isn't interpolating the joint proxy object
1932 Velocity = Vector3.Zero;
1933 AngularVelocity = Vector3.Zero;
1934 Acceleration = Vector3.Zero;
1935 }
1936 }
1937 }
1938  
1939 /// <summary>
1940 /// Do a physics propery update for this part.
1941 /// </summary>
1942 /// <param name="UsePhysics"></param>
1943 /// <param name="isNew"></param>
1944 public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew)
1945 {
1946 if (ParentGroup.Scene == null)
1947 return;
1948  
1949 if (!ParentGroup.Scene.PhysicalPrims && UsePhysics)
1950 return;
1951  
1952 if (IsJoint())
1953 {
1954 DoPhysicsPropertyUpdateForNinjaJoint(UsePhysics, isNew);
1955 }
1956 else
1957 {
1958 PhysicsActor pa = PhysActor;
1959  
1960 if (pa != null)
1961 {
1962 if (UsePhysics != pa.IsPhysical || isNew)
1963 {
1964 if (pa.IsPhysical) // implies UsePhysics==false for this block
1965 {
1966 if (!isNew)
1967 ParentGroup.Scene.RemovePhysicalPrim(1);
1968  
1969 pa.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate;
1970 pa.OnOutOfBounds -= PhysicsOutOfBounds;
1971 pa.delink();
1972  
1973 if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints && (!isNew))
1974 {
1975 // destroy all joints connected to this now deactivated body
1976 ParentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(pa);
1977 }
1978  
1979 // stop client-side interpolation of all joint proxy objects that have just been deleted
1980 // this is done because RemoveAllJointsConnectedToActor invokes the OnJointDeactivated callback,
1981 // which stops client-side interpolation of deactivated joint proxy objects.
1982 }
1983  
1984 if (!UsePhysics && !isNew)
1985 {
1986 // reset velocity to 0 on physics switch-off. Without that, the client thinks the
1987 // prim still has velocity and continues to interpolate its position along the old
1988 // velocity-vector.
1989 Velocity = new Vector3(0, 0, 0);
1990 Acceleration = new Vector3(0, 0, 0);
1991 AngularVelocity = new Vector3(0, 0, 0);
1992 //RotationalVelocity = new Vector3(0, 0, 0);
1993 }
1994  
1995 pa.IsPhysical = UsePhysics;
1996  
1997 // If we're not what we're supposed to be in the physics scene, recreate ourselves.
1998 //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
1999 /// that's not wholesome. Had to make Scene public
2000 //PhysActor = null;
2001  
2002 if ((Flags & PrimFlags.Phantom) == 0)
2003 {
2004 if (UsePhysics)
2005 {
2006 if (ParentGroup.RootPart.KeyframeMotion != null)
2007 ParentGroup.RootPart.KeyframeMotion.Stop();
2008 ParentGroup.RootPart.KeyframeMotion = null;
2009 ParentGroup.Scene.AddPhysicalPrim(1);
2010  
2011 pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate;
2012 pa.OnOutOfBounds += PhysicsOutOfBounds;
2013 if (ParentID != 0 && ParentID != LocalId)
2014 {
2015 PhysicsActor parentPa = ParentGroup.RootPart.PhysActor;
2016  
2017 if (parentPa != null)
2018 {
2019 pa.link(parentPa);
2020 }
2021 }
2022 }
2023 }
2024 }
2025  
2026 // If this part is a sculpt then delay the physics update until we've asynchronously loaded the
2027 // mesh data.
2028 // if (Shape.SculptEntry)
2029 // CheckSculptAndLoad();
2030 // else
2031 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
2032 }
2033 }
2034 }
2035  
2036 /// <summary>
2037 /// Restore this part from the serialized xml representation.
2038 /// </summary>
2039 /// <param name="xmlReader"></param>
2040 /// <returns></returns>
2041 public static SceneObjectPart FromXml(XmlTextReader xmlReader)
2042 {
2043 SceneObjectPart part = SceneObjectSerializer.Xml2ToSOP(xmlReader);
2044  
2045 // for tempOnRez objects, we have to fix the Expire date.
2046 if ((part.Flags & PrimFlags.TemporaryOnRez) != 0)
2047 part.ResetExpire();
2048  
2049 return part;
2050 }
2051  
2052 public bool GetDieAtEdge()
2053 {
2054 if (ParentGroup.IsDeleted)
2055 return false;
2056  
2057 return ParentGroup.RootPart.DIE_AT_EDGE;
2058 }
2059  
2060 public bool GetReturnAtEdge()
2061 {
2062 if (ParentGroup.IsDeleted)
2063 return false;
2064  
2065 return ParentGroup.RootPart.RETURN_AT_EDGE;
2066 }
2067  
2068 public void SetReturnAtEdge(bool p)
2069 {
2070 if (ParentGroup.IsDeleted)
2071 return;
2072  
2073 ParentGroup.RootPart.RETURN_AT_EDGE = p;
2074 }
2075  
2076 public bool GetBlockGrab()
2077 {
2078 if (ParentGroup.IsDeleted)
2079 return false;
2080  
2081 return ParentGroup.RootPart.BlockGrab;
2082 }
2083  
2084 public void SetBlockGrab(bool p)
2085 {
2086 if (ParentGroup.IsDeleted)
2087 return;
2088  
2089 ParentGroup.RootPart.BlockGrab = p;
2090 }
2091  
2092 public void SetStatusSandbox(bool p)
2093 {
2094 if (ParentGroup.IsDeleted)
2095 return;
2096 StatusSandboxPos = ParentGroup.RootPart.AbsolutePosition;
2097 ParentGroup.RootPart.StatusSandbox = p;
2098 }
2099  
2100 public bool GetStatusSandbox()
2101 {
2102 if (ParentGroup.IsDeleted)
2103 return false;
2104  
2105 return ParentGroup.RootPart.StatusSandbox;
2106 }
2107  
2108 public int GetAxisRotation(int axis)
2109 {
2110 //Cannot use ScriptBaseClass constants as no referance to it currently.
2111 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X)
2112 return STATUS_ROTATE_X;
2113 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y)
2114 return STATUS_ROTATE_Y;
2115 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z)
2116 return STATUS_ROTATE_Z;
2117  
2118 return 0;
2119 }
2120  
2121 public double GetDistanceTo(Vector3 a, Vector3 b)
2122 {
2123 float dx = a.X - b.X;
2124 float dy = a.Y - b.Y;
2125 float dz = a.Z - b.Z;
2126 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
2127 }
2128  
2129 public uint GetEffectiveObjectFlags()
2130 {
2131 // Commenting this section of code out since it doesn't actually do anything, as enums are handled by
2132 // value rather than reference
2133 // PrimFlags f = _flags;
2134 // if (m_parentGroup == null || m_parentGroup.RootPart == this)
2135 // f &= ~(PrimFlags.Touch | PrimFlags.Money);
2136  
2137 return (uint)Flags | (uint)LocalFlags;
2138 }
2139  
2140 public Vector3 GetGeometricCenter()
2141 {
2142 PhysicsActor pa = PhysActor;
2143  
2144 if (pa != null)
2145 return pa.GeometricCenter;
2146 else
2147 return Vector3.Zero;
2148 }
2149  
2150 public Vector3 GetCenterOfMass()
2151 {
2152 PhysicsActor pa = PhysActor;
2153  
2154 if (pa != null)
2155 return pa.CenterOfMass;
2156 else
2157 return Vector3.Zero;
2158 }
2159  
2160 public float GetMass()
2161 {
2162 PhysicsActor pa = PhysActor;
2163  
2164 if (pa != null)
2165 return pa.Mass;
2166 else
2167 return 0;
2168 }
2169  
2170 public Vector3 GetForce()
2171 {
2172 PhysicsActor pa = PhysActor;
2173  
2174 if (pa != null)
2175 return pa.Force;
2176 else
2177 return Vector3.Zero;
2178 }
2179  
2180 /// <summary>
2181 /// Method for a prim to get it's world position from the group.
2182 /// </summary>
2183 /// <remarks>
2184 /// Remember, the Group Position simply gives the position of the group itself
2185 /// </remarks>
2186 /// <returns>A Linked Child Prim objects position in world</returns>
2187 public Vector3 GetWorldPosition()
2188 {
2189 Vector3 ret;
2190 if (_parentID == 0)
2191 // if a root SOP, my position is what it is
2192 ret = GroupPosition;
2193 else
2194 {
2195 // If a child SOP, my position is relative to the root SOP so take
2196 // my info and add the root's position and rotation to
2197 // get my world position.
2198 Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
2199 Vector3 translationOffsetPosition = OffsetPosition * parentRot;
2200 ret = ParentGroup.AbsolutePosition + translationOffsetPosition;
2201 }
2202 return ret;
2203 }
2204  
2205 /// <summary>
2206 /// Gets the rotation of this prim offset by the group rotation
2207 /// </summary>
2208 /// <returns></returns>
2209 public Quaternion GetWorldRotation()
2210 {
2211 Quaternion newRot;
2212  
2213 if (this.LinkNum == 0 || this.LinkNum == 1)
2214 {
2215 newRot = RotationOffset;
2216 }
2217 else
2218 {
2219 // A child SOP's rotation is relative to the root SOP's rotation.
2220 // Combine them to get my absolute rotation.
2221 Quaternion parentRot = ParentGroup.RootPart.RotationOffset;
2222 Quaternion oldRot = RotationOffset;
2223 newRot = parentRot * oldRot;
2224 }
2225  
2226 return newRot;
2227 }
2228  
2229 public void MoveToTarget(Vector3 target, float tau)
2230 {
2231 if (tau > 0)
2232 {
2233 ParentGroup.moveToTarget(target, tau);
2234 }
2235 else
2236 {
2237 StopMoveToTarget();
2238 }
2239 }
2240  
2241 /// <summary>
2242 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
2243 /// </summary>
2244 /// <param name="height">Height to hover. Height of zero disables hover.</param>
2245 /// <param name="hoverType">Determines what the height is relative to </param>
2246 /// <param name="tau">Number of seconds over which to reach target</param>
2247 public void SetHoverHeight(float height, PIDHoverType hoverType, float tau)
2248 {
2249 ParentGroup.SetHoverHeight(height, hoverType, tau);
2250 }
2251  
2252 public void StopHover()
2253 {
2254 ParentGroup.SetHoverHeight(0f, PIDHoverType.Ground, 0f);
2255 }
2256  
2257 public virtual void OnGrab(Vector3 offsetPos, IClientAPI remoteClient)
2258 {
2259 }
2260  
2261 public bool CollisionFilteredOut(UUID objectID, string objectName)
2262 {
2263 if(CollisionFilter.Count == 0)
2264 return false;
2265  
2266 if (CollisionFilter.ContainsValue(objectID.ToString()) ||
2267 CollisionFilter.ContainsValue(objectID.ToString() + objectName) ||
2268 CollisionFilter.ContainsValue(UUID.Zero.ToString() + objectName))
2269 {
2270 if (CollisionFilter.ContainsKey(1))
2271 return false;
2272 return true;
2273 }
2274  
2275 if (CollisionFilter.ContainsKey(1))
2276 return true;
2277  
2278 return false;
2279 }
2280  
2281 private DetectedObject CreateDetObject(SceneObjectPart obj)
2282 {
2283 DetectedObject detobj = new DetectedObject();
2284 detobj.keyUUID = obj.UUID;
2285 detobj.nameStr = obj.Name;
2286 detobj.ownerUUID = obj.OwnerID;
2287 detobj.posVector = obj.AbsolutePosition;
2288 detobj.rotQuat = obj.GetWorldRotation();
2289 detobj.velVector = obj.Velocity;
2290 detobj.colliderType = 0;
2291 detobj.groupUUID = obj.GroupID;
2292  
2293 return detobj;
2294 }
2295  
2296 private DetectedObject CreateDetObject(ScenePresence av)
2297 {
2298 DetectedObject detobj = new DetectedObject();
2299 detobj.keyUUID = av.UUID;
2300 detobj.nameStr = av.ControllingClient.Name;
2301 detobj.ownerUUID = av.UUID;
2302 detobj.posVector = av.AbsolutePosition;
2303 detobj.rotQuat = av.Rotation;
2304 detobj.velVector = av.Velocity;
2305 detobj.colliderType = 0;
2306 detobj.groupUUID = av.ControllingClient.ActiveGroupId;
2307  
2308 return detobj;
2309 }
2310  
2311 private DetectedObject CreateDetObjectForGround()
2312 {
2313 DetectedObject detobj = new DetectedObject();
2314 detobj.keyUUID = UUID.Zero;
2315 detobj.nameStr = "";
2316 detobj.ownerUUID = UUID.Zero;
2317 detobj.posVector = ParentGroup.RootPart.AbsolutePosition;
2318 detobj.rotQuat = Quaternion.Identity;
2319 detobj.velVector = Vector3.Zero;
2320 detobj.colliderType = 0;
2321 detobj.groupUUID = UUID.Zero;
2322  
2323 return detobj;
2324 }
2325  
2326 private ColliderArgs CreateColliderArgs(SceneObjectPart dest, List<uint> colliders)
2327 {
2328 ColliderArgs colliderArgs = new ColliderArgs();
2329 List<DetectedObject> colliding = new List<DetectedObject>();
2330 foreach (uint localId in colliders)
2331 {
2332 if (localId == 0)
2333 continue;
2334  
2335 SceneObjectPart obj = ParentGroup.Scene.GetSceneObjectPart(localId);
2336 if (obj != null)
2337 {
2338 if (!dest.CollisionFilteredOut(obj.UUID, obj.Name))
2339 colliding.Add(CreateDetObject(obj));
2340 }
2341 else
2342 {
2343 ScenePresence av = ParentGroup.Scene.GetScenePresence(localId);
2344 if (av != null && (!av.IsChildAgent))
2345 {
2346 if (!dest.CollisionFilteredOut(av.UUID, av.Name))
2347 colliding.Add(CreateDetObject(av));
2348 }
2349 }
2350 }
2351  
2352 colliderArgs.Colliders = colliding;
2353  
2354 return colliderArgs;
2355 }
2356  
2357 private delegate void ScriptCollidingNotification(uint localID, ColliderArgs message);
2358  
2359 private void SendCollisionEvent(scriptEvents ev, List<uint> colliders, ScriptCollidingNotification notify)
2360 {
2361 bool sendToRoot = false;
2362 ColliderArgs CollidingMessage;
2363  
2364 if (colliders.Count > 0)
2365 {
2366 if ((ScriptEvents & ev) != 0)
2367 {
2368 CollidingMessage = CreateColliderArgs(this, colliders);
2369  
2370 if (CollidingMessage.Colliders.Count > 0)
2371 notify(LocalId, CollidingMessage);
2372  
2373 if (PassCollisions)
2374 sendToRoot = true;
2375 }
2376 else
2377 {
2378 if ((ParentGroup.RootPart.ScriptEvents & ev) != 0)
2379 sendToRoot = true;
2380 }
2381 if (sendToRoot && ParentGroup.RootPart != this)
2382 {
2383 CollidingMessage = CreateColliderArgs(ParentGroup.RootPart, colliders);
2384 if (CollidingMessage.Colliders.Count > 0)
2385 notify(ParentGroup.RootPart.LocalId, CollidingMessage);
2386 }
2387 }
2388 }
2389  
2390 private void SendLandCollisionEvent(scriptEvents ev, ScriptCollidingNotification notify)
2391 {
2392 if ((ParentGroup.RootPart.ScriptEvents & ev) != 0)
2393 {
2394 ColliderArgs LandCollidingMessage = new ColliderArgs();
2395 List<DetectedObject> colliding = new List<DetectedObject>();
2396  
2397 colliding.Add(CreateDetObjectForGround());
2398 LandCollidingMessage.Colliders = colliding;
2399  
2400 notify(LocalId, LandCollidingMessage);
2401 }
2402 }
2403  
2404 public void PhysicsCollision(EventArgs e)
2405 {
2406 if (ParentGroup.Scene == null || ParentGroup.IsDeleted)
2407 return;
2408  
2409 // single threaded here
2410 CollisionEventUpdate a = (CollisionEventUpdate)e;
2411 Dictionary<uint, ContactPoint> collissionswith = a.m_objCollisionList;
2412 List<uint> thisHitColliders = new List<uint>();
2413 List<uint> endedColliders = new List<uint>();
2414 List<uint> startedColliders = new List<uint>();
2415  
2416 // calculate things that started colliding this time
2417 // and build up list of colliders this time
2418 foreach (uint localid in collissionswith.Keys)
2419 {
2420 thisHitColliders.Add(localid);
2421 if (!m_lastColliders.Contains(localid))
2422 startedColliders.Add(localid);
2423 }
2424  
2425 // calculate things that ended colliding
2426 foreach (uint localID in m_lastColliders)
2427 {
2428 if (!thisHitColliders.Contains(localID))
2429 endedColliders.Add(localID);
2430 }
2431  
2432 //add the items that started colliding this time to the last colliders list.
2433 foreach (uint localID in startedColliders)
2434 m_lastColliders.Add(localID);
2435  
2436 // remove things that ended colliding from the last colliders list
2437 foreach (uint localID in endedColliders)
2438 m_lastColliders.Remove(localID);
2439  
2440 // play the sound.
2441 if (startedColliders.Count > 0 && CollisionSound != UUID.Zero && CollisionSoundVolume > 0.0f)
2442 {
2443 ISoundModule soundModule = ParentGroup.Scene.RequestModuleInterface<ISoundModule>();
2444 if (soundModule != null)
2445 {
2446 soundModule.SendSound(UUID, CollisionSound,
2447 CollisionSoundVolume, true, 0, 0, false,
2448 false);
2449 }
2450 }
2451  
2452 SendCollisionEvent(scriptEvents.collision_start, startedColliders, ParentGroup.Scene.EventManager.TriggerScriptCollidingStart);
2453 SendCollisionEvent(scriptEvents.collision , m_lastColliders , ParentGroup.Scene.EventManager.TriggerScriptColliding);
2454 SendCollisionEvent(scriptEvents.collision_end , endedColliders , ParentGroup.Scene.EventManager.TriggerScriptCollidingEnd);
2455  
2456 if (startedColliders.Contains(0))
2457 SendLandCollisionEvent(scriptEvents.land_collision_start, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingStart);
2458 if (m_lastColliders.Contains(0))
2459 SendLandCollisionEvent(scriptEvents.land_collision, ParentGroup.Scene.EventManager.TriggerScriptLandColliding);
2460 if (endedColliders.Contains(0))
2461 SendLandCollisionEvent(scriptEvents.land_collision_end, ParentGroup.Scene.EventManager.TriggerScriptLandCollidingEnd);
2462 }
2463  
2464 public void PhysicsOutOfBounds(Vector3 pos)
2465 {
2466 // Note: This is only being called on the root prim at this time.
2467  
2468 m_log.ErrorFormat(
2469 "[SCENE OBJECT PART]: Physical object {0}, localID {1} went out of bounds at {2} in {3}. Stopping at {4} and making non-physical.",
2470 Name, LocalId, pos, ParentGroup.Scene.Name, AbsolutePosition);
2471  
2472 RemFlag(PrimFlags.Physics);
2473 DoPhysicsPropertyUpdate(false, true);
2474 }
2475  
2476 public void PhysicsRequestingTerseUpdate()
2477 {
2478 PhysicsActor pa = PhysActor;
2479  
2480 if (pa != null)
2481 {
2482 Vector3 newpos = new Vector3(pa.Position.GetBytes(), 0);
2483  
2484 if (ParentGroup.Scene.TestBorderCross(newpos, Cardinals.N)
2485 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.S)
2486 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.E)
2487 | ParentGroup.Scene.TestBorderCross(newpos, Cardinals.W))
2488 {
2489 ParentGroup.AbsolutePosition = newpos;
2490 return;
2491 }
2492 //ParentGroup.RootPart.m_groupPosition = newpos;
2493 }
2494  
2495 if (pa != null && ParentID != 0 && ParentGroup != null)
2496 {
2497 // Special case where a child object is requesting property updates.
2498 // This happens when linksets are modified to use flexible links rather than
2499 // the default links.
2500 // The simulator code presumes that child parts are only modified by scripts
2501 // so the logic for changing position/rotation/etc does not take into
2502 // account the physical object actually moving.
2503 // This code updates the offset position and rotation of the child and then
2504 // lets the update code push the update to the viewer.
2505 // Since physics engines do not normally generate this event for linkset children,
2506 // this code will not be active unless you have a specially configured
2507 // physics engine.
2508 Quaternion invRootRotation = Quaternion.Normalize(Quaternion.Inverse(ParentGroup.RootPart.RotationOffset));
2509 m_offsetPosition = pa.Position - m_groupPosition;
2510 RotationOffset = pa.Orientation * invRootRotation;
2511 // m_log.DebugFormat("{0} PhysicsRequestingTerseUpdate child: pos={1}, rot={2}, offPos={3}, offRot={4}",
2512 // "[SCENE OBJECT PART]", pa.Position, pa.Orientation, m_offsetPosition, RotationOffset);
2513 }
2514  
2515 ScheduleTerseUpdate();
2516 }
2517  
2518 public void RemFlag(PrimFlags flag)
2519 {
2520 // PrimFlags prevflag = Flags;
2521 if ((Flags & flag) != 0)
2522 {
2523 //m_log.Debug("Removing flag: " + ((PrimFlags)flag).ToString());
2524 Flags &= ~flag;
2525 }
2526 //m_log.Debug("prev: " + prevflag.ToString() + " curr: " + Flags.ToString());
2527 //ScheduleFullUpdate();
2528 }
2529  
2530 public void RemoveScriptEvents(UUID scriptid)
2531 {
2532 lock (m_scriptEvents)
2533 {
2534 if (m_scriptEvents.ContainsKey(scriptid))
2535 {
2536 scriptEvents oldparts = scriptEvents.None;
2537 oldparts = (scriptEvents) m_scriptEvents[scriptid];
2538  
2539 // remove values from aggregated script events
2540 AggregateScriptEvents &= ~oldparts;
2541 m_scriptEvents.Remove(scriptid);
2542 aggregateScriptEvents();
2543 }
2544 }
2545 }
2546  
2547 /// <summary>
2548 /// Reset UUIDs for this part. This involves generate this part's own UUID and
2549 /// generating new UUIDs for all the items in the inventory.
2550 /// </summary>
2551 /// <param name="linkNum">Link number for the part</param>
2552 public void ResetIDs(int linkNum)
2553 {
2554 UUID = UUID.Random();
2555 LinkNum = linkNum;
2556 LocalId = 0;
2557 Inventory.ResetInventoryIDs();
2558 }
2559  
2560 /// <summary>
2561 /// Set the scale of this part.
2562 /// </summary>
2563 /// <remarks>
2564 /// Unlike the scale property, this checks the new size against scene limits and schedules a full property
2565 /// update to viewers.
2566 /// </remarks>
2567 /// <param name="scale"></param>
2568 public void Resize(Vector3 scale)
2569 {
2570 PhysicsActor pa = PhysActor;
2571  
2572 if (ParentGroup.Scene != null)
2573 {
2574 scale.X = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.X));
2575 scale.Y = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Y));
2576 scale.Z = Math.Max(ParentGroup.Scene.m_minNonphys, Math.Min(ParentGroup.Scene.m_maxNonphys, scale.Z));
2577  
2578 if (pa != null && pa.IsPhysical)
2579 {
2580 scale.X = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.X));
2581 scale.Y = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Y));
2582 scale.Z = Math.Max(ParentGroup.Scene.m_minPhys, Math.Min(ParentGroup.Scene.m_maxPhys, scale.Z));
2583 }
2584 }
2585  
2586 // m_log.DebugFormat("[SCENE OBJECT PART]: Resizing {0} {1} to {2}", Name, LocalId, scale);
2587  
2588 Scale = scale;
2589  
2590 ParentGroup.HasGroupChanged = true;
2591 ScheduleFullUpdate();
2592 }
2593  
2594 public void RotLookAt(Quaternion target, float strength, float damping)
2595 {
2596 if (ParentGroup.IsAttachment)
2597 {
2598 /*
2599 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2600 if (avatar != null)
2601 {
2602 Rotate the Av?
2603 } */
2604 }
2605 else
2606 {
2607 APIDDamp = damping;
2608 APIDStrength = strength;
2609 APIDTarget = target;
2610  
2611 if (APIDStrength <= 0)
2612 {
2613 m_log.WarnFormat("[SceneObjectPart] Invalid rotation strength {0}",APIDStrength);
2614 return;
2615 }
2616  
2617 m_APIDIterations = 1 + (int)(Math.PI * APIDStrength);
2618 }
2619  
2620 // Necessary to get the lookat deltas applied
2621 ParentGroup.QueueForUpdateCheck();
2622 }
2623  
2624 public void StartLookAt(Quaternion target, float strength, float damping)
2625 {
2626 RotLookAt(target,strength,damping);
2627 }
2628  
2629 public void StopLookAt()
2630 {
2631 APIDTarget = Quaternion.Identity;
2632 }
2633  
2634  
2635  
2636 public void ScheduleFullUpdateIfNone()
2637 {
2638 if (ParentGroup == null)
2639 return;
2640  
2641 // ??? ParentGroup.HasGroupChanged = true;
2642  
2643 if (UpdateFlag != UpdateRequired.FULL)
2644 ScheduleFullUpdate();
2645 }
2646  
2647 /// <summary>
2648 /// Schedules this prim for a full update
2649 /// </summary>
2650 public void ScheduleFullUpdate()
2651 {
2652 // m_log.DebugFormat("[SCENE OBJECT PART]: Scheduling full update for {0} {1}", Name, LocalId);
2653  
2654 if (ParentGroup == null)
2655 return;
2656  
2657 ParentGroup.QueueForUpdateCheck();
2658  
2659 int timeNow = Util.UnixTimeSinceEpoch();
2660  
2661 // If multiple updates are scheduled on the same second, we still need to perform all of them
2662 // So we'll force the issue by bumping up the timestamp so that later processing sees these need
2663 // to be performed.
2664 if (timeNow <= TimeStampFull)
2665 {
2666 TimeStampFull += 1;
2667 }
2668 else
2669 {
2670 TimeStampFull = (uint)timeNow;
2671 }
2672  
2673 UpdateFlag = UpdateRequired.FULL;
2674  
2675 // m_log.DebugFormat(
2676 // "[SCENE OBJECT PART]: Scheduling full update for {0}, {1} at {2}",
2677 // UUID, Name, TimeStampFull);
2678  
2679 if (ParentGroup.Scene != null)
2680 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, true);
2681 }
2682  
2683 /// <summary>
2684 /// Schedule a terse update for this prim. Terse updates only send position,
2685 /// rotation, velocity and rotational velocity information.
2686 /// </summary>
2687 public void ScheduleTerseUpdate()
2688 {
2689 if (ParentGroup == null)
2690 return;
2691  
2692 // This was pulled from SceneViewer. Attachments always receive full updates.
2693 // This is needed because otherwise if only the root prim changes position, then
2694 // it looks as if the entire object has moved (including the other prims).
2695 if (ParentGroup.IsAttachment)
2696 {
2697 ScheduleFullUpdate();
2698 return;
2699 }
2700  
2701 if (UpdateFlag == UpdateRequired.NONE)
2702 {
2703 ParentGroup.HasGroupChanged = true;
2704 ParentGroup.QueueForUpdateCheck();
2705  
2706 TimeStampTerse = (uint) Util.UnixTimeSinceEpoch();
2707 UpdateFlag = UpdateRequired.TERSE;
2708  
2709 // m_log.DebugFormat(
2710 // "[SCENE OBJECT PART]: Scheduling terse update for {0}, {1} at {2}",
2711 // UUID, Name, TimeStampTerse);
2712 }
2713  
2714 if (ParentGroup.Scene != null)
2715 ParentGroup.Scene.EventManager.TriggerSceneObjectPartUpdated(this, false);
2716 }
2717  
2718 public void ScriptSetPhysicsStatus(bool UsePhysics)
2719 {
2720 ParentGroup.ScriptSetPhysicsStatus(UsePhysics);
2721 }
2722  
2723 /// <summary>
2724 /// Set sculpt and mesh data, and tell the physics engine to process the change.
2725 /// </summary>
2726 /// <param name="texture">The mesh itself.</param>
2727 /*
2728 public void SculptTextureCallback(AssetBase texture)
2729 {
2730 if (m_shape.SculptEntry)
2731 {
2732 // commented out for sculpt map caching test - null could mean a cached sculpt map has been found
2733 //if (texture != null)
2734 {
2735 if (texture != null)
2736 {
2737 // m_log.DebugFormat(
2738 // "[SCENE OBJECT PART]: Setting sculpt data for {0} on SculptTextureCallback()", Name);
2739  
2740 m_shape.SculptData = texture.Data;
2741 }
2742  
2743 PhysicsActor pa = PhysActor;
2744  
2745 if (pa != null)
2746 {
2747 // Update the physics actor with the new loaded sculpt data and set the taint signal.
2748 pa.Shape = m_shape;
2749  
2750 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
2751 }
2752 }
2753 }
2754 }
2755 */
2756 /// <summary>
2757 /// Send a full update to the client for the given part
2758 /// </summary>
2759 /// <param name="remoteClient"></param>
2760 protected internal void SendFullUpdate(IClientAPI remoteClient)
2761 {
2762 if (ParentGroup == null)
2763 return;
2764  
2765 // m_log.DebugFormat(
2766 // "[SOG]: Sendinging part full update to {0} for {1} {2}", remoteClient.Name, part.Name, part.LocalId);
2767  
2768 if (IsRoot)
2769 {
2770 if (ParentGroup.IsAttachment)
2771 {
2772 SendFullUpdateToClient(remoteClient, AttachedPos);
2773 }
2774 else
2775 {
2776 SendFullUpdateToClient(remoteClient, AbsolutePosition);
2777 }
2778 }
2779 else
2780 {
2781 SendFullUpdateToClient(remoteClient);
2782 }
2783 }
2784  
2785 /// <summary>
2786 /// Send a full update for this part to all clients.
2787 /// </summary>
2788 public void SendFullUpdateToAllClients()
2789 {
2790 if (ParentGroup == null)
2791 return;
2792  
2793 ParentGroup.Scene.ForEachScenePresence(delegate(ScenePresence avatar)
2794 {
2795 SendFullUpdate(avatar.ControllingClient);
2796 });
2797 }
2798  
2799 /// <summary>
2800 /// Sends a full update to the client
2801 /// </summary>
2802 /// <param name="remoteClient"></param>
2803 public void SendFullUpdateToClient(IClientAPI remoteClient)
2804 {
2805 SendFullUpdateToClient(remoteClient, OffsetPosition);
2806 }
2807  
2808 /// <summary>
2809 /// Sends a full update to the client
2810 /// </summary>
2811 /// <param name="remoteClient"></param>
2812 /// <param name="lPos"></param>
2813 public void SendFullUpdateToClient(IClientAPI remoteClient, Vector3 lPos)
2814 {
2815 if (ParentGroup == null)
2816 return;
2817  
2818 // Suppress full updates during attachment editing
2819 //
2820 if (ParentGroup.IsSelected && ParentGroup.IsAttachment)
2821 return;
2822  
2823 if (ParentGroup.IsDeleted)
2824 return;
2825  
2826 if (ParentGroup.IsAttachment
2827 && ParentGroup.AttachedAvatar != remoteClient.AgentId
2828 && ParentGroup.HasPrivateAttachmentPoint)
2829 return;
2830  
2831 if (remoteClient.AgentId == OwnerID)
2832 {
2833 if ((Flags & PrimFlags.CreateSelected) != 0)
2834 Flags &= ~PrimFlags.CreateSelected;
2835 }
2836 //bool isattachment = IsAttachment;
2837 //if (LocalId != ParentGroup.RootPart.LocalId)
2838 //isattachment = ParentGroup.RootPart.IsAttachment;
2839  
2840 remoteClient.SendEntityUpdate(this, PrimUpdateFlags.FullUpdate);
2841 ParentGroup.Scene.StatsReporter.AddObjectUpdates(1);
2842 }
2843  
2844 /// <summary>
2845 /// Tell all the prims which have had updates scheduled
2846 /// </summary>
2847 public void SendScheduledUpdates()
2848 {
2849 const float ROTATION_TOLERANCE = 0.01f;
2850 const float VELOCITY_TOLERANCE = 0.001f;
2851 const float POSITION_TOLERANCE = 0.05f;
2852 const int TIME_MS_TOLERANCE = 3000;
2853  
2854 switch (UpdateFlag)
2855 {
2856 case UpdateRequired.TERSE:
2857 {
2858 ClearUpdateSchedule();
2859 // Throw away duplicate or insignificant updates
2860 if (!RotationOffset.ApproxEquals(m_lastRotation, ROTATION_TOLERANCE) ||
2861 !Acceleration.Equals(m_lastAcceleration) ||
2862 !Velocity.ApproxEquals(m_lastVelocity, VELOCITY_TOLERANCE) ||
2863 Velocity.ApproxEquals(Vector3.Zero, VELOCITY_TOLERANCE) ||
2864 !AngularVelocity.ApproxEquals(m_lastAngularVelocity, VELOCITY_TOLERANCE) ||
2865 !OffsetPosition.ApproxEquals(m_lastPosition, POSITION_TOLERANCE) ||
2866 Environment.TickCount - m_lastTerseSent > TIME_MS_TOLERANCE)
2867 {
2868 SendTerseUpdateToAllClients();
2869  
2870 // Update the "last" values
2871 m_lastPosition = OffsetPosition;
2872 m_lastRotation = RotationOffset;
2873 m_lastVelocity = Velocity;
2874 m_lastAcceleration = Acceleration;
2875 m_lastAngularVelocity = AngularVelocity;
2876 m_lastTerseSent = Environment.TickCount;
2877 }
2878 break;
2879 }
2880 case UpdateRequired.FULL:
2881 {
2882 ClearUpdateSchedule();
2883 SendFullUpdateToAllClients();
2884 break;
2885 }
2886 }
2887 }
2888  
2889 /// <summary>
2890 /// Send a terse update to all clients
2891 /// </summary>
2892 public void SendTerseUpdateToAllClients()
2893 {
2894 ParentGroup.Scene.ForEachClient(delegate(IClientAPI client)
2895 {
2896 SendTerseUpdateToClient(client);
2897 });
2898 }
2899  
2900 public void SetAxisRotation(int axis, int rotate)
2901 {
2902 ParentGroup.SetAxisRotation(axis, rotate);
2903  
2904 //Cannot use ScriptBaseClass constants as no referance to it currently.
2905 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0)
2906 STATUS_ROTATE_X = rotate;
2907  
2908 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0)
2909 STATUS_ROTATE_Y = rotate;
2910  
2911 if ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0)
2912 STATUS_ROTATE_Z = rotate;
2913 }
2914  
2915 public void SetBuoyancy(float fvalue)
2916 {
2917 PhysicsActor pa = PhysActor;
2918  
2919 if (pa != null)
2920 pa.Buoyancy = fvalue;
2921 }
2922  
2923 public void SetDieAtEdge(bool p)
2924 {
2925 if (ParentGroup.IsDeleted)
2926 return;
2927  
2928 ParentGroup.RootPart.DIE_AT_EDGE = p;
2929 }
2930  
2931 public void SetFloatOnWater(int floatYN)
2932 {
2933 PhysicsActor pa = PhysActor;
2934  
2935 if (pa != null)
2936 pa.FloatOnWater = floatYN == 1;
2937 }
2938  
2939 public void SetForce(Vector3 force)
2940 {
2941 PhysicsActor pa = PhysActor;
2942  
2943 if (pa != null)
2944 pa.Force = force;
2945 }
2946  
2947 public void SetVehicleType(int type)
2948 {
2949 PhysicsActor pa = PhysActor;
2950  
2951 if (pa != null)
2952 pa.VehicleType = type;
2953 }
2954  
2955 public void SetVehicleFloatParam(int param, float value)
2956 {
2957 PhysicsActor pa = PhysActor;
2958  
2959 if (pa != null)
2960 pa.VehicleFloatParam(param, value);
2961 }
2962  
2963 public void SetVehicleVectorParam(int param, Vector3 value)
2964 {
2965 PhysicsActor pa = PhysActor;
2966  
2967 if (pa != null)
2968 pa.VehicleVectorParam(param, value);
2969 }
2970  
2971 public void SetVehicleRotationParam(int param, Quaternion rotation)
2972 {
2973 PhysicsActor pa = PhysActor;
2974  
2975 if (pa != null)
2976 pa.VehicleRotationParam(param, rotation);
2977 }
2978  
2979 /// <summary>
2980 /// Set the color & alpha of prim faces
2981 /// </summary>
2982 /// <param name="face"></param>
2983 /// <param name="color"></param>
2984 /// <param name="alpha"></param>
2985 public void SetFaceColorAlpha(int face, Vector3 color, double ?alpha)
2986 {
2987 Vector3 clippedColor = Util.Clip(color, 0.0f, 1.0f);
2988 float clippedAlpha = alpha.HasValue ?
2989 Util.Clip((float)alpha.Value, 0.0f, 1.0f) : 0;
2990  
2991 // The only way to get a deep copy/ If we don't do this, we can
2992 // never detect color changes further down.
2993 Byte[] buf = Shape.Textures.GetBytes();
2994 Primitive.TextureEntry tex = new Primitive.TextureEntry(buf, 0, buf.Length);
2995 Color4 texcolor;
2996 if (face >= 0 && face < GetNumberOfSides())
2997 {
2998 texcolor = tex.CreateFace((uint)face).RGBA;
2999 texcolor.R = clippedColor.X;
3000 texcolor.G = clippedColor.Y;
3001 texcolor.B = clippedColor.Z;
3002 if (alpha.HasValue)
3003 {
3004 texcolor.A = clippedAlpha;
3005 }
3006 tex.FaceTextures[face].RGBA = texcolor;
3007 UpdateTextureEntry(tex.GetBytes());
3008 return;
3009 }
3010 else if (face == ALL_SIDES)
3011 {
3012 for (uint i = 0; i < GetNumberOfSides(); i++)
3013 {
3014 if (tex.FaceTextures[i] != null)
3015 {
3016 texcolor = tex.FaceTextures[i].RGBA;
3017 texcolor.R = clippedColor.X;
3018 texcolor.G = clippedColor.Y;
3019 texcolor.B = clippedColor.Z;
3020 if (alpha.HasValue)
3021 {
3022 texcolor.A = clippedAlpha;
3023 }
3024 tex.FaceTextures[i].RGBA = texcolor;
3025 }
3026 texcolor = tex.DefaultTexture.RGBA;
3027 texcolor.R = clippedColor.X;
3028 texcolor.G = clippedColor.Y;
3029 texcolor.B = clippedColor.Z;
3030 if (alpha.HasValue)
3031 {
3032 texcolor.A = clippedAlpha;
3033 }
3034 tex.DefaultTexture.RGBA = texcolor;
3035 }
3036 UpdateTextureEntry(tex.GetBytes());
3037 return;
3038 }
3039 }
3040  
3041 /// <summary>
3042 /// Get the number of sides that this part has.
3043 /// </summary>
3044 /// <returns></returns>
3045 public int GetNumberOfSides()
3046 {
3047 int ret = 0;
3048 bool hasCut;
3049 bool hasHollow;
3050 bool hasDimple;
3051 bool hasProfileCut;
3052  
3053 PrimType primType = GetPrimType();
3054 HasCutHollowDimpleProfileCut(primType, Shape, out hasCut, out hasHollow, out hasDimple, out hasProfileCut);
3055  
3056 switch (primType)
3057 {
3058 case PrimType.BOX:
3059 ret = 6;
3060 if (hasCut) ret += 2;
3061 if (hasHollow) ret += 1;
3062 break;
3063 case PrimType.CYLINDER:
3064 ret = 3;
3065 if (hasCut) ret += 2;
3066 if (hasHollow) ret += 1;
3067 break;
3068 case PrimType.PRISM:
3069 ret = 5;
3070 if (hasCut) ret += 2;
3071 if (hasHollow) ret += 1;
3072 break;
3073 case PrimType.SPHERE:
3074 ret = 1;
3075 if (hasCut) ret += 2;
3076 if (hasDimple) ret += 2;
3077 if (hasHollow) ret += 1;
3078 break;
3079 case PrimType.TORUS:
3080 ret = 1;
3081 if (hasCut) ret += 2;
3082 if (hasProfileCut) ret += 2;
3083 if (hasHollow) ret += 1;
3084 break;
3085 case PrimType.TUBE:
3086 ret = 4;
3087 if (hasCut) ret += 2;
3088 if (hasProfileCut) ret += 2;
3089 if (hasHollow) ret += 1;
3090 break;
3091 case PrimType.RING:
3092 ret = 3;
3093 if (hasCut) ret += 2;
3094 if (hasProfileCut) ret += 2;
3095 if (hasHollow) ret += 1;
3096 break;
3097 case PrimType.SCULPT:
3098 // Special mesh handling
3099 if (Shape.SculptType == (byte)SculptType.Mesh)
3100 ret = 8; // if it's a mesh then max 8 faces
3101 else
3102 ret = 1; // if it's a sculpt then max 1 face
3103 break;
3104 }
3105  
3106 return ret;
3107 }
3108  
3109 /// <summary>
3110 /// Tell us what type this prim is
3111 /// </summary>
3112 /// <param name="primShape"></param>
3113 /// <returns></returns>
3114 public PrimType GetPrimType()
3115 {
3116 if (Shape.SculptEntry)
3117 return PrimType.SCULPT;
3118  
3119 if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.Square)
3120 {
3121 if (Shape.PathCurve == (byte)Extrusion.Straight)
3122 return PrimType.BOX;
3123 else if (Shape.PathCurve == (byte)Extrusion.Curve1)
3124 return PrimType.TUBE;
3125 }
3126 else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.Circle)
3127 {
3128 if (Shape.PathCurve == (byte)Extrusion.Straight)
3129 return PrimType.CYLINDER;
3130 // ProfileCurve seems to combine hole shape and profile curve so we need to only compare against the lower 3 bits
3131 else if (Shape.PathCurve == (byte)Extrusion.Curve1)
3132 return PrimType.TORUS;
3133 }
3134 else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.HalfCircle)
3135 {
3136 if (Shape.PathCurve == (byte)Extrusion.Curve1 || Shape.PathCurve == (byte)Extrusion.Curve2)
3137 return PrimType.SPHERE;
3138 }
3139 else if ((Shape.ProfileCurve & 0x07) == (byte)ProfileShape.EquilateralTriangle)
3140 {
3141 if (Shape.PathCurve == (byte)Extrusion.Straight)
3142 return PrimType.PRISM;
3143 else if (Shape.PathCurve == (byte)Extrusion.Curve1)
3144 return PrimType.RING;
3145 }
3146  
3147 return PrimType.BOX;
3148 }
3149  
3150 /// <summary>
3151 /// Tell us if this object has cut, hollow, dimple, and other factors affecting the number of faces
3152 /// </summary>
3153 /// <param name="primType"></param>
3154 /// <param name="shape"></param>
3155 /// <param name="hasCut"></param>
3156 /// <param name="hasHollow"></param>
3157 /// <param name="hasDimple"></param>
3158 /// <param name="hasProfileCut"></param>
3159 protected static void HasCutHollowDimpleProfileCut(PrimType primType, PrimitiveBaseShape shape, out bool hasCut, out bool hasHollow,
3160 out bool hasDimple, out bool hasProfileCut)
3161 {
3162 if (primType == PrimType.BOX
3163 ||
3164 primType == PrimType.CYLINDER
3165 ||
3166 primType == PrimType.PRISM)
3167  
3168 hasCut = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0);
3169 else
3170 hasCut = (shape.PathBegin > 0) || (shape.PathEnd > 0);
3171  
3172 hasHollow = shape.ProfileHollow > 0;
3173 hasDimple = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); // taken from llSetPrimitiveParms
3174 hasProfileCut = hasDimple; // is it the same thing?
3175 }
3176  
3177 public void SetVehicleFlags(int param, bool remove)
3178 {
3179 PhysicsActor pa = PhysActor;
3180  
3181 if (pa != null)
3182 pa.VehicleFlags(param, remove);
3183 }
3184  
3185 public void SetGroup(UUID groupID, IClientAPI client)
3186 {
3187 // Scene.AddNewPrims() calls with client == null so can't use this.
3188 // m_log.DebugFormat(
3189 // "[SCENE OBJECT PART]: Setting group for {0} to {1} for {2}",
3190 // Name, groupID, OwnerID);
3191  
3192 GroupID = groupID;
3193 if (client != null)
3194 SendPropertiesToClient(client);
3195 UpdateFlag = UpdateRequired.FULL;
3196 }
3197  
3198 /// <summary>
3199 /// Set the parent group of this prim.
3200 /// </summary>
3201 public void SetParent(SceneObjectGroup parent)
3202 {
3203 ParentGroup = parent;
3204 }
3205  
3206 // Use this for attachments! LocalID should be avatar's localid
3207 public void SetParentLocalId(uint localID)
3208 {
3209 ParentID = localID;
3210 }
3211  
3212 public void SetPhysicsAxisRotation()
3213 {
3214 PhysicsActor pa = PhysActor;
3215  
3216 if (pa != null)
3217 {
3218 pa.LockAngularMotion(RotationAxis);
3219 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
3220 }
3221 }
3222  
3223 /// <summary>
3224 /// Set the events that this part will pass on to listeners.
3225 /// </summary>
3226 /// <param name="scriptid"></param>
3227 /// <param name="events"></param>
3228 public void SetScriptEvents(UUID scriptid, int events)
3229 {
3230 // m_log.DebugFormat(
3231 // "[SCENE OBJECT PART]: Set script events for script with id {0} on {1}/{2} to {3} in {4}",
3232 // scriptid, Name, ParentGroup.Name, events, ParentGroup.Scene.Name);
3233  
3234 // scriptEvents oldparts;
3235 lock (m_scriptEvents)
3236 {
3237 if (m_scriptEvents.ContainsKey(scriptid))
3238 {
3239 // oldparts = m_scriptEvents[scriptid];
3240  
3241 // remove values from aggregated script events
3242 if (m_scriptEvents[scriptid] == (scriptEvents) events)
3243 return;
3244 m_scriptEvents[scriptid] = (scriptEvents) events;
3245 }
3246 else
3247 {
3248 m_scriptEvents.Add(scriptid, (scriptEvents) events);
3249 }
3250 }
3251 aggregateScriptEvents();
3252 }
3253  
3254 /// <summary>
3255 /// Set the text displayed for this part.
3256 /// </summary>
3257 /// <param name="text"></param>
3258 public void SetText(string text)
3259 {
3260 Text = text;
3261  
3262 if (ParentGroup != null)
3263 {
3264 ParentGroup.HasGroupChanged = true;
3265 ScheduleFullUpdate();
3266 }
3267 }
3268  
3269 /// <summary>
3270 /// Set the text displayed for this part.
3271 /// </summary>
3272 /// <param name="text"></param>
3273 /// <param name="color"></param>
3274 /// <param name="alpha"></param>
3275 public void SetText(string text, Vector3 color, double alpha)
3276 {
3277 Color = Color.FromArgb((int) (alpha*0xff),
3278 (int) (color.X*0xff),
3279 (int) (color.Y*0xff),
3280 (int) (color.Z*0xff));
3281 SetText(text);
3282 }
3283  
3284 public void StopMoveToTarget()
3285 {
3286 ParentGroup.stopMoveToTarget();
3287  
3288 ParentGroup.ScheduleGroupForTerseUpdate();
3289 //ParentGroup.ScheduleGroupForFullUpdate();
3290 }
3291  
3292 public void StoreUndoState()
3293 {
3294 StoreUndoState(false);
3295 }
3296  
3297 public void StoreUndoState(bool forGroup)
3298 {
3299 if (ParentGroup == null || ParentGroup.Scene == null)
3300 return;
3301  
3302 if (Undoing)
3303 {
3304 // m_log.DebugFormat(
3305 // "[SCENE OBJECT PART]: Ignoring undo store for {0} {1} since already undoing", Name, LocalId);
3306 return;
3307 }
3308  
3309 if (IgnoreUndoUpdate)
3310 {
3311 // m_log.DebugFormat("[SCENE OBJECT PART]: Ignoring undo store for {0} {1}", Name, LocalId);
3312 return;
3313 }
3314  
3315 lock (m_undo)
3316 {
3317 if (m_undo.Count > 0)
3318 {
3319 UndoState last = m_undo[m_undo.Count - 1];
3320 if (last != null)
3321 {
3322 // TODO: May need to fix for group comparison
3323 if (last.Compare(this))
3324 {
3325 // m_log.DebugFormat(
3326 // "[SCENE OBJECT PART]: Not storing undo for {0} {1} since current state is same as last undo state, initial stack size {2}",
3327 // Name, LocalId, m_undo.Count);
3328  
3329 return;
3330 }
3331 }
3332 }
3333  
3334 // m_log.DebugFormat(
3335 // "[SCENE OBJECT PART]: Storing undo state for {0} {1}, forGroup {2}, initial stack size {3}",
3336 // Name, LocalId, forGroup, m_undo.Count);
3337  
3338 if (ParentGroup.Scene.MaxUndoCount > 0)
3339 {
3340 UndoState nUndo = new UndoState(this, forGroup);
3341  
3342 m_undo.Add(nUndo);
3343  
3344 if (m_undo.Count > ParentGroup.Scene.MaxUndoCount)
3345 m_undo.RemoveAt(0);
3346  
3347 if (m_redo.Count > 0)
3348 m_redo.Clear();
3349  
3350 // m_log.DebugFormat(
3351 // "[SCENE OBJECT PART]: Stored undo state for {0} {1}, forGroup {2}, stack size now {3}",
3352 // Name, LocalId, forGroup, m_undo.Count);
3353 }
3354 }
3355 }
3356  
3357 /// <summary>
3358 /// Return number of undos on the stack. Here temporarily pending a refactor.
3359 /// </summary>
3360 public int UndoCount
3361 {
3362 get
3363 {
3364 lock (m_undo)
3365 return m_undo.Count;
3366 }
3367 }
3368  
3369 public void Undo()
3370 {
3371 lock (m_undo)
3372 {
3373 // m_log.DebugFormat(
3374 // "[SCENE OBJECT PART]: Handling undo request for {0} {1}, stack size {2}",
3375 // Name, LocalId, m_undo.Count);
3376  
3377 if (m_undo.Count > 0)
3378 {
3379 UndoState goback = m_undo[m_undo.Count - 1];
3380 m_undo.RemoveAt(m_undo.Count - 1);
3381  
3382 UndoState nUndo = null;
3383  
3384 if (ParentGroup.Scene.MaxUndoCount > 0)
3385 {
3386 nUndo = new UndoState(this, goback.ForGroup);
3387 }
3388  
3389 goback.PlaybackState(this);
3390  
3391 if (nUndo != null)
3392 {
3393 m_redo.Add(nUndo);
3394  
3395 if (m_redo.Count > ParentGroup.Scene.MaxUndoCount)
3396 m_redo.RemoveAt(0);
3397 }
3398 }
3399  
3400 // m_log.DebugFormat(
3401 // "[SCENE OBJECT PART]: Handled undo request for {0} {1}, stack size now {2}",
3402 // Name, LocalId, m_undo.Count);
3403 }
3404 }
3405  
3406 public void Redo()
3407 {
3408 lock (m_undo)
3409 {
3410 // m_log.DebugFormat(
3411 // "[SCENE OBJECT PART]: Handling redo request for {0} {1}, stack size {2}",
3412 // Name, LocalId, m_redo.Count);
3413  
3414 if (m_redo.Count > 0)
3415 {
3416 UndoState gofwd = m_redo[m_redo.Count - 1];
3417 m_redo.RemoveAt(m_redo.Count - 1);
3418  
3419 if (ParentGroup.Scene.MaxUndoCount > 0)
3420 {
3421 UndoState nUndo = new UndoState(this, gofwd.ForGroup);
3422  
3423 m_undo.Add(nUndo);
3424  
3425 if (m_undo.Count > ParentGroup.Scene.MaxUndoCount)
3426 m_undo.RemoveAt(0);
3427 }
3428  
3429 gofwd.PlayfwdState(this);
3430  
3431 // m_log.DebugFormat(
3432 // "[SCENE OBJECT PART]: Handled redo request for {0} {1}, stack size now {2}",
3433 // Name, LocalId, m_redo.Count);
3434 }
3435 }
3436 }
3437  
3438 public void ClearUndoState()
3439 {
3440 // m_log.DebugFormat("[SCENE OBJECT PART]: Clearing undo and redo stacks in {0} {1}", Name, LocalId);
3441  
3442 lock (m_undo)
3443 {
3444 m_undo.Clear();
3445 m_redo.Clear();
3446 }
3447 }
3448  
3449 public EntityIntersection TestIntersection(Ray iray, Quaternion parentrot)
3450 {
3451 // In this case we're using a sphere with a radius of the largest dimension of the prim
3452 // TODO: Change to take shape into account
3453  
3454 EntityIntersection result = new EntityIntersection();
3455 Vector3 vAbsolutePosition = AbsolutePosition;
3456 Vector3 vScale = Scale;
3457 Vector3 rOrigin = iray.Origin;
3458 Vector3 rDirection = iray.Direction;
3459  
3460 //rDirection = rDirection.Normalize();
3461 // Buidling the first part of the Quadratic equation
3462 Vector3 r2ndDirection = rDirection*rDirection;
3463 float itestPart1 = r2ndDirection.X + r2ndDirection.Y + r2ndDirection.Z;
3464  
3465 // Buidling the second part of the Quadratic equation
3466 Vector3 tmVal2 = rOrigin - vAbsolutePosition;
3467 Vector3 r2Direction = rDirection*2.0f;
3468 Vector3 tmVal3 = r2Direction*tmVal2;
3469  
3470 float itestPart2 = tmVal3.X + tmVal3.Y + tmVal3.Z;
3471  
3472 // Buidling the third part of the Quadratic equation
3473 Vector3 tmVal4 = rOrigin*rOrigin;
3474 Vector3 tmVal5 = vAbsolutePosition*vAbsolutePosition;
3475  
3476 Vector3 tmVal6 = vAbsolutePosition*rOrigin;
3477  
3478 // Set Radius to the largest dimension of the prim
3479 float radius = 0f;
3480 if (vScale.X > radius)
3481 radius = vScale.X;
3482 if (vScale.Y > radius)
3483 radius = vScale.Y;
3484 if (vScale.Z > radius)
3485 radius = vScale.Z;
3486  
3487 // the second part of this is the default prim size
3488 // once we factor in the aabb of the prim we're adding we can
3489 // change this to;
3490 // radius = (radius / 2) - 0.01f;
3491 //
3492 radius = (radius / 2) + (0.5f / 2) - 0.1f;
3493  
3494 //radius = radius;
3495  
3496 float itestPart3 = tmVal4.X + tmVal4.Y + tmVal4.Z + tmVal5.X + tmVal5.Y + tmVal5.Z -
3497 (2.0f*(tmVal6.X + tmVal6.Y + tmVal6.Z + (radius*radius)));
3498  
3499 // Yuk Quadradrics.. Solve first
3500 float rootsqr = (itestPart2*itestPart2) - (4.0f*itestPart1*itestPart3);
3501 if (rootsqr < 0.0f)
3502 {
3503 // No intersection
3504 return result;
3505 }
3506 float root = ((-itestPart2) - (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f);
3507  
3508 if (root < 0.0f)
3509 {
3510 // perform second quadratic root solution
3511 root = ((-itestPart2) + (float) Math.Sqrt((double) rootsqr))/(itestPart1*2.0f);
3512  
3513 // is there any intersection?
3514 if (root < 0.0f)
3515 {
3516 // nope, no intersection
3517 return result;
3518 }
3519 }
3520  
3521 // We got an intersection. putting together an EntityIntersection object with the
3522 // intersection information
3523 Vector3 ipoint =
3524 new Vector3(iray.Origin.X + (iray.Direction.X*root), iray.Origin.Y + (iray.Direction.Y*root),
3525 iray.Origin.Z + (iray.Direction.Z*root));
3526  
3527 result.HitTF = true;
3528 result.ipoint = ipoint;
3529  
3530 // Normal is calculated by the difference and then normalizing the result
3531 Vector3 normalpart = ipoint - vAbsolutePosition;
3532 result.normal = normalpart / normalpart.Length();
3533  
3534 // It's funny how the Vector3 object has a Distance function, but the Axiom.Math object doesn't.
3535 // I can write a function to do it.. but I like the fact that this one is Static.
3536  
3537 Vector3 distanceConvert1 = new Vector3(iray.Origin.X, iray.Origin.Y, iray.Origin.Z);
3538 Vector3 distanceConvert2 = new Vector3(ipoint.X, ipoint.Y, ipoint.Z);
3539 float distance = (float) Util.GetDistanceTo(distanceConvert1, distanceConvert2);
3540  
3541 result.distance = distance;
3542  
3543 return result;
3544 }
3545  
3546 public EntityIntersection TestIntersectionOBB(Ray iray, Quaternion parentrot, bool frontFacesOnly, bool faceCenters)
3547 {
3548 // In this case we're using a rectangular prism, which has 6 faces and therefore 6 planes
3549 // This breaks down into the ray---> plane equation.
3550 // TODO: Change to take shape into account
3551 Vector3[] vertexes = new Vector3[8];
3552  
3553 // float[] distance = new float[6];
3554 Vector3[] FaceA = new Vector3[6]; // vertex A for Facei
3555 Vector3[] FaceB = new Vector3[6]; // vertex B for Facei
3556 Vector3[] FaceC = new Vector3[6]; // vertex C for Facei
3557 Vector3[] FaceD = new Vector3[6]; // vertex D for Facei
3558  
3559 Vector3[] normals = new Vector3[6]; // Normal for Facei
3560 Vector3[] AAfacenormals = new Vector3[6]; // Axis Aligned face normals
3561  
3562 AAfacenormals[0] = new Vector3(1, 0, 0);
3563 AAfacenormals[1] = new Vector3(0, 1, 0);
3564 AAfacenormals[2] = new Vector3(-1, 0, 0);
3565 AAfacenormals[3] = new Vector3(0, -1, 0);
3566 AAfacenormals[4] = new Vector3(0, 0, 1);
3567 AAfacenormals[5] = new Vector3(0, 0, -1);
3568  
3569 Vector3 AmBa = new Vector3(0, 0, 0); // Vertex A - Vertex B
3570 Vector3 AmBb = new Vector3(0, 0, 0); // Vertex B - Vertex C
3571 Vector3 cross = new Vector3();
3572  
3573 Vector3 pos = GetWorldPosition();
3574 Quaternion rot = GetWorldRotation();
3575  
3576 // Variables prefixed with AX are Axiom.Math copies of the LL variety.
3577  
3578 Quaternion AXrot = rot;
3579 AXrot.Normalize();
3580  
3581 Vector3 AXpos = pos;
3582  
3583 // tScale is the offset to derive the vertex based on the scale.
3584 // it's different for each vertex because we've got to rotate it
3585 // to get the world position of the vertex to produce the Oriented Bounding Box
3586  
3587 Vector3 tScale = Vector3.Zero;
3588  
3589 Vector3 AXscale = new Vector3(m_shape.Scale.X * 0.5f, m_shape.Scale.Y * 0.5f, m_shape.Scale.Z * 0.5f);
3590  
3591 //Vector3 pScale = (AXscale) - (AXrot.Inverse() * (AXscale));
3592 //Vector3 nScale = (AXscale * -1) - (AXrot.Inverse() * (AXscale * -1));
3593  
3594 // rScale is the rotated offset to find a vertex based on the scale and the world rotation.
3595 Vector3 rScale = new Vector3();
3596  
3597 // Get Vertexes for Faces Stick them into ABCD for each Face
3598 // Form: Face<vertex>[face] that corresponds to the below diagram
3599 #region ABCD Face Vertex Map Comment Diagram
3600 // A _________ B
3601 // | |
3602 // | 4 top |
3603 // |_________|
3604 // C D
3605  
3606 // A _________ B
3607 // | Back |
3608 // | 3 |
3609 // |_________|
3610 // C D
3611  
3612 // A _________ B B _________ A
3613 // | Left | | Right |
3614 // | 0 | | 2 |
3615 // |_________| |_________|
3616 // C D D C
3617  
3618 // A _________ B
3619 // | Front |
3620 // | 1 |
3621 // |_________|
3622 // C D
3623  
3624 // C _________ D
3625 // | |
3626 // | 5 bot |
3627 // |_________|
3628 // A B
3629 #endregion
3630  
3631 #region Plane Decomposition of Oriented Bounding Box
3632 tScale = new Vector3(AXscale.X, -AXscale.Y, AXscale.Z);
3633 rScale = tScale * AXrot;
3634 vertexes[0] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3635 // vertexes[0].X = pos.X + vertexes[0].X;
3636 //vertexes[0].Y = pos.Y + vertexes[0].Y;
3637 //vertexes[0].Z = pos.Z + vertexes[0].Z;
3638  
3639 FaceA[0] = vertexes[0];
3640 FaceB[3] = vertexes[0];
3641 FaceA[4] = vertexes[0];
3642  
3643 tScale = AXscale;
3644 rScale = tScale * AXrot;
3645 vertexes[1] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3646  
3647 // vertexes[1].X = pos.X + vertexes[1].X;
3648 // vertexes[1].Y = pos.Y + vertexes[1].Y;
3649 //vertexes[1].Z = pos.Z + vertexes[1].Z;
3650  
3651 FaceB[0] = vertexes[1];
3652 FaceA[1] = vertexes[1];
3653 FaceC[4] = vertexes[1];
3654  
3655 tScale = new Vector3(AXscale.X, -AXscale.Y, -AXscale.Z);
3656 rScale = tScale * AXrot;
3657  
3658 vertexes[2] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3659  
3660 //vertexes[2].X = pos.X + vertexes[2].X;
3661 //vertexes[2].Y = pos.Y + vertexes[2].Y;
3662 //vertexes[2].Z = pos.Z + vertexes[2].Z;
3663  
3664 FaceC[0] = vertexes[2];
3665 FaceD[3] = vertexes[2];
3666 FaceC[5] = vertexes[2];
3667  
3668 tScale = new Vector3(AXscale.X, AXscale.Y, -AXscale.Z);
3669 rScale = tScale * AXrot;
3670 vertexes[3] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3671  
3672 //vertexes[3].X = pos.X + vertexes[3].X;
3673 // vertexes[3].Y = pos.Y + vertexes[3].Y;
3674 // vertexes[3].Z = pos.Z + vertexes[3].Z;
3675  
3676 FaceD[0] = vertexes[3];
3677 FaceC[1] = vertexes[3];
3678 FaceA[5] = vertexes[3];
3679  
3680 tScale = new Vector3(-AXscale.X, AXscale.Y, AXscale.Z);
3681 rScale = tScale * AXrot;
3682 vertexes[4] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3683  
3684 // vertexes[4].X = pos.X + vertexes[4].X;
3685 // vertexes[4].Y = pos.Y + vertexes[4].Y;
3686 // vertexes[4].Z = pos.Z + vertexes[4].Z;
3687  
3688 FaceB[1] = vertexes[4];
3689 FaceA[2] = vertexes[4];
3690 FaceD[4] = vertexes[4];
3691  
3692 tScale = new Vector3(-AXscale.X, AXscale.Y, -AXscale.Z);
3693 rScale = tScale * AXrot;
3694 vertexes[5] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3695  
3696 // vertexes[5].X = pos.X + vertexes[5].X;
3697 // vertexes[5].Y = pos.Y + vertexes[5].Y;
3698 // vertexes[5].Z = pos.Z + vertexes[5].Z;
3699  
3700 FaceD[1] = vertexes[5];
3701 FaceC[2] = vertexes[5];
3702 FaceB[5] = vertexes[5];
3703  
3704 tScale = new Vector3(-AXscale.X, -AXscale.Y, AXscale.Z);
3705 rScale = tScale * AXrot;
3706 vertexes[6] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3707  
3708 // vertexes[6].X = pos.X + vertexes[6].X;
3709 // vertexes[6].Y = pos.Y + vertexes[6].Y;
3710 // vertexes[6].Z = pos.Z + vertexes[6].Z;
3711  
3712 FaceB[2] = vertexes[6];
3713 FaceA[3] = vertexes[6];
3714 FaceB[4] = vertexes[6];
3715  
3716 tScale = new Vector3(-AXscale.X, -AXscale.Y, -AXscale.Z);
3717 rScale = tScale * AXrot;
3718 vertexes[7] = (new Vector3((pos.X + rScale.X), (pos.Y + rScale.Y), (pos.Z + rScale.Z)));
3719  
3720 // vertexes[7].X = pos.X + vertexes[7].X;
3721 // vertexes[7].Y = pos.Y + vertexes[7].Y;
3722 // vertexes[7].Z = pos.Z + vertexes[7].Z;
3723  
3724 FaceD[2] = vertexes[7];
3725 FaceC[3] = vertexes[7];
3726 FaceD[5] = vertexes[7];
3727 #endregion
3728  
3729 // Get our plane normals
3730 for (int i = 0; i < 6; i++)
3731 {
3732 //m_log.Info("[FACECALCULATION]: FaceA[" + i + "]=" + FaceA[i] + " FaceB[" + i + "]=" + FaceB[i] + " FaceC[" + i + "]=" + FaceC[i] + " FaceD[" + i + "]=" + FaceD[i]);
3733  
3734 // Our Plane direction
3735 AmBa = FaceA[i] - FaceB[i];
3736 AmBb = FaceB[i] - FaceC[i];
3737  
3738 cross = Vector3.Cross(AmBb, AmBa);
3739  
3740 // normalize the cross product to get the normal.
3741 normals[i] = cross / cross.Length();
3742  
3743 //m_log.Info("[NORMALS]: normals[ " + i + "]" + normals[i].ToString());
3744 //distance[i] = (normals[i].X * AmBa.X + normals[i].Y * AmBa.Y + normals[i].Z * AmBa.Z) * -1;
3745 }
3746  
3747 EntityIntersection result = new EntityIntersection();
3748  
3749 result.distance = 1024;
3750 float c = 0;
3751 float a = 0;
3752 float d = 0;
3753 Vector3 q = new Vector3();
3754  
3755 #region OBB Version 2 Experiment
3756 //float fmin = 999999;
3757 //float fmax = -999999;
3758 //float s = 0;
3759  
3760 //for (int i=0;i<6;i++)
3761 //{
3762 //s = iray.Direction.Dot(normals[i]);
3763 //d = normals[i].Dot(FaceB[i]);
3764  
3765 //if (s == 0)
3766 //{
3767 //if (iray.Origin.Dot(normals[i]) > d)
3768 //{
3769 //return result;
3770 //}
3771 // else
3772 //{
3773 //continue;
3774 //}
3775 //}
3776 //a = (d - iray.Origin.Dot(normals[i])) / s;
3777 //if (iray.Direction.Dot(normals[i]) < 0)
3778 //{
3779 //if (a > fmax)
3780 //{
3781 //if (a > fmin)
3782 //{
3783 //return result;
3784 //}
3785 //fmax = a;
3786 //}
3787  
3788 //}
3789 //else
3790 //{
3791 //if (a < fmin)
3792 //{
3793 //if (a < 0 || a < fmax)
3794 //{
3795 //return result;
3796 //}
3797 //fmin = a;
3798 //}
3799 //}
3800 //}
3801 //if (fmax > 0)
3802 // a= fmax;
3803 //else
3804 // a=fmin;
3805  
3806 //q = iray.Origin + a * iray.Direction;
3807 #endregion
3808  
3809 // Loop over faces (6 of them)
3810 for (int i = 0; i < 6; i++)
3811 {
3812 AmBa = FaceA[i] - FaceB[i];
3813 AmBb = FaceB[i] - FaceC[i];
3814 d = Vector3.Dot(normals[i], FaceB[i]);
3815  
3816 //if (faceCenters)
3817 //{
3818 // c = normals[i].Dot(normals[i]);
3819 //}
3820 //else
3821 //{
3822 c = Vector3.Dot(iray.Direction, normals[i]);
3823 //}
3824 if (c == 0)
3825 continue;
3826  
3827 a = (d - Vector3.Dot(iray.Origin, normals[i])) / c;
3828  
3829 if (a < 0)
3830 continue;
3831  
3832 // If the normal is pointing outside the object
3833 if (Vector3.Dot(iray.Direction, normals[i]) < 0 || !frontFacesOnly)
3834 {
3835 //if (faceCenters)
3836 //{ //(FaceA[i] + FaceB[i] + FaceC[1] + FaceD[i]) / 4f;
3837 // q = iray.Origin + a * normals[i];
3838 //}
3839 //else
3840 //{
3841 q = iray.Origin + iray.Direction * a;
3842 //}
3843  
3844 float distance2 = (float)GetDistanceTo(q, AXpos);
3845 // Is this the closest hit to the object's origin?
3846 //if (faceCenters)
3847 //{
3848 // distance2 = (float)GetDistanceTo(q, iray.Origin);
3849 //}
3850  
3851 if (distance2 < result.distance)
3852 {
3853 result.distance = distance2;
3854 result.HitTF = true;
3855 result.ipoint = q;
3856 result.face = i;
3857 //m_log.Info("[FACE]:" + i.ToString());
3858 //m_log.Info("[POINT]: " + q.ToString());
3859 //m_log.Info("[DIST]: " + distance2.ToString());
3860 if (faceCenters)
3861 {
3862 result.normal = AAfacenormals[i] * AXrot;
3863  
3864 Vector3 scaleComponent = AAfacenormals[i];
3865 float ScaleOffset = 0.5f;
3866 if (scaleComponent.X != 0) ScaleOffset = AXscale.X;
3867 if (scaleComponent.Y != 0) ScaleOffset = AXscale.Y;
3868 if (scaleComponent.Z != 0) ScaleOffset = AXscale.Z;
3869 ScaleOffset = Math.Abs(ScaleOffset);
3870 Vector3 offset = result.normal * ScaleOffset;
3871 result.ipoint = AXpos + offset;
3872  
3873 ///pos = (intersectionpoint + offset);
3874 }
3875 else
3876 {
3877 result.normal = normals[i];
3878 }
3879 result.AAfaceNormal = AAfacenormals[i];
3880 }
3881 }
3882 }
3883 return result;
3884 }
3885  
3886 /// <summary>
3887 /// Serialize this part to xml.
3888 /// </summary>
3889 /// <param name="xmlWriter"></param>
3890 public void ToXml(XmlTextWriter xmlWriter)
3891 {
3892 SceneObjectSerializer.SOPToXml2(xmlWriter, this, new Dictionary<string, object>());
3893 }
3894  
3895 public void TriggerScriptChangedEvent(Changed val)
3896 {
3897 if (ParentGroup != null && ParentGroup.Scene != null)
3898 ParentGroup.Scene.EventManager.TriggerOnScriptChangedEvent(LocalId, (uint)val);
3899 }
3900  
3901 public void TrimPermissions()
3902 {
3903 BaseMask &= (uint)(PermissionMask.All | PermissionMask.Export);
3904 OwnerMask &= (uint)(PermissionMask.All | PermissionMask.Export);
3905 GroupMask &= (uint)PermissionMask.All;
3906 EveryoneMask &= (uint)(PermissionMask.All | PermissionMask.Export);
3907 NextOwnerMask &= (uint)PermissionMask.All;
3908 }
3909  
3910 public void UpdateExtraParam(ushort type, bool inUse, byte[] data)
3911 {
3912 m_shape.ReadInUpdateExtraParam(type, inUse, data);
3913 /*
3914 if (type == 0x30)
3915 {
3916 if (m_shape.SculptEntry && m_shape.SculptTexture != UUID.Zero)
3917 {
3918 ParentGroup.Scene.AssetService.Get(m_shape.SculptTexture.ToString(), this, AssetReceived);
3919 }
3920 }
3921 */
3922 if (ParentGroup != null)
3923 {
3924 ParentGroup.HasGroupChanged = true;
3925 ScheduleFullUpdate();
3926 }
3927 }
3928  
3929 public void UpdateGroupPosition(Vector3 newPos)
3930 {
3931 Vector3 oldPos = GroupPosition;
3932  
3933 if ((newPos.X != oldPos.X) ||
3934 (newPos.Y != oldPos.Y) ||
3935 (newPos.Z != oldPos.Z))
3936 {
3937 GroupPosition = newPos;
3938 ScheduleTerseUpdate();
3939 }
3940 }
3941  
3942 /// <summary>
3943 /// Update this part's offset position.
3944 /// </summary>
3945 /// <param name="pos"></param>
3946 public void UpdateOffSet(Vector3 newPos)
3947 {
3948 Vector3 oldPos = OffsetPosition;
3949  
3950 if ((newPos.X != oldPos.X) ||
3951 (newPos.Y != oldPos.Y) ||
3952 (newPos.Z != oldPos.Z))
3953 {
3954 if (ParentGroup.RootPart.GetStatusSandbox())
3955 {
3956 if (Util.GetDistanceTo(ParentGroup.RootPart.StatusSandboxPos, newPos) > 10)
3957 {
3958 ParentGroup.RootPart.ScriptSetPhysicsStatus(false);
3959 newPos = OffsetPosition;
3960 ParentGroup.Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
3961 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, ParentGroup.RootPart.AbsolutePosition, Name, UUID, false);
3962 }
3963 }
3964  
3965 OffsetPosition = newPos;
3966 ScheduleTerseUpdate();
3967 }
3968 }
3969  
3970 /// <summary>
3971 /// Update permissions on the SOP. Should only be called from SOG.UpdatePermissions because the SOG
3972 /// will handle the client notifications once all of its parts are updated.
3973 /// </summary>
3974 /// <param name="AgentID"></param>
3975 /// <param name="field"></param>
3976 /// <param name="localID"></param>
3977 /// <param name="mask"></param>
3978 /// <param name="addRemTF"></param>
3979 public void UpdatePermissions(UUID AgentID, byte field, uint localID, uint mask, byte addRemTF)
3980 {
3981 bool set = addRemTF == 1;
3982 bool god = ParentGroup.Scene.Permissions.IsGod(AgentID);
3983  
3984 uint baseMask = BaseMask;
3985 if (god)
3986 baseMask = 0x7ffffff0;
3987  
3988 // Are we the owner?
3989 if ((AgentID == OwnerID) || god)
3990 {
3991 switch (field)
3992 {
3993 case 1:
3994 if (god)
3995 {
3996 BaseMask = ApplyMask(BaseMask, set, mask);
3997 Inventory.ApplyGodPermissions(_baseMask);
3998 }
3999  
4000 break;
4001 case 2:
4002 OwnerMask = ApplyMask(OwnerMask, set, mask) &
4003 baseMask;
4004 break;
4005 case 4:
4006 GroupMask = ApplyMask(GroupMask, set, mask) &
4007 baseMask;
4008 break;
4009 case 8:
4010 // Trying to set export permissions - extra checks
4011 if (set && (mask & (uint)PermissionMask.Export) != 0)
4012 {
4013 if ((OwnerMask & (uint)PermissionMask.Export) == 0 || (BaseMask & (uint)PermissionMask.Export) == 0 || (NextOwnerMask & (uint)PermissionMask.All) != (uint)PermissionMask.All)
4014 mask &= ~(uint)PermissionMask.Export;
4015 }
4016 EveryoneMask = ApplyMask(EveryoneMask, set, mask) &
4017 baseMask;
4018 break;
4019 case 16:
4020 // Force full perm if export
4021 if ((EveryoneMask & (uint)PermissionMask.Export) != 0)
4022 {
4023 NextOwnerMask = (uint)PermissionMask.All;
4024 break;
4025 }
4026 NextOwnerMask = ApplyMask(NextOwnerMask, set, mask) &
4027 baseMask;
4028 // Prevent the client from creating no mod, no copy
4029 // objects
4030 if ((NextOwnerMask & (uint)PermissionMask.Copy) == 0)
4031 NextOwnerMask |= (uint)PermissionMask.Transfer;
4032  
4033 NextOwnerMask |= (uint)PermissionMask.Move;
4034  
4035 break;
4036 }
4037  
4038 SendFullUpdateToAllClients();
4039 }
4040 }
4041  
4042 public void ClonePermissions(SceneObjectPart source)
4043 {
4044 bool update = false;
4045  
4046 if (BaseMask != source.BaseMask ||
4047 OwnerMask != source.OwnerMask ||
4048 GroupMask != source.GroupMask ||
4049 EveryoneMask != source.EveryoneMask ||
4050 NextOwnerMask != source.NextOwnerMask)
4051 update = true;
4052  
4053 BaseMask = source.BaseMask;
4054 OwnerMask = source.OwnerMask;
4055 GroupMask = source.GroupMask;
4056 EveryoneMask = source.EveryoneMask;
4057 NextOwnerMask = source.NextOwnerMask;
4058  
4059 if (update)
4060 SendFullUpdateToAllClients();
4061 }
4062  
4063 public bool IsHingeJoint()
4064 {
4065 // For now, we use the NINJA naming scheme for identifying joints.
4066 // In the future, we can support other joint specification schemes such as a
4067 // custom checkbox in the viewer GUI.
4068 if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
4069 {
4070 string hingeString = "hingejoint";
4071 return (Name.Length >= hingeString.Length && Name.Substring(0, hingeString.Length) == hingeString);
4072 }
4073 else
4074 {
4075 return false;
4076 }
4077 }
4078  
4079 public bool IsBallJoint()
4080 {
4081 // For now, we use the NINJA naming scheme for identifying joints.
4082 // In the future, we can support other joint specification schemes such as a
4083 // custom checkbox in the viewer GUI.
4084 if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
4085 {
4086 string ballString = "balljoint";
4087 return (Name.Length >= ballString.Length && Name.Substring(0, ballString.Length) == ballString);
4088 }
4089 else
4090 {
4091 return false;
4092 }
4093 }
4094  
4095 public bool IsJoint()
4096 {
4097 // For now, we use the NINJA naming scheme for identifying joints.
4098 // In the future, we can support other joint specification schemes such as a
4099 // custom checkbox in the viewer GUI.
4100 if (ParentGroup.Scene != null && ParentGroup.Scene.PhysicsScene != null && ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints)
4101 {
4102 return IsHingeJoint() || IsBallJoint();
4103 }
4104 else
4105 {
4106 return false;
4107 }
4108 }
4109  
4110 public void UpdateExtraPhysics(ExtraPhysicsData physdata)
4111 {
4112 if (physdata.PhysShapeType == PhysShapeType.invalid || ParentGroup == null)
4113 return;
4114  
4115 if (PhysicsShapeType != (byte)physdata.PhysShapeType)
4116 {
4117 PhysicsShapeType = (byte)physdata.PhysShapeType;
4118  
4119 }
4120  
4121 if(Density != physdata.Density)
4122 Density = physdata.Density;
4123 if(GravityModifier != physdata.GravitationModifier)
4124 GravityModifier = physdata.GravitationModifier;
4125 if(Friction != physdata.Friction)
4126 Friction = physdata.Friction;
4127 if(Restitution != physdata.Bounce)
4128 Restitution = physdata.Bounce;
4129 }
4130 /// <summary>
4131 /// Update the flags on this prim. This covers properties such as phantom, physics and temporary.
4132 /// </summary>
4133 /// <param name="UsePhysics"></param>
4134 /// <param name="SetTemporary"></param>
4135 /// <param name="SetPhantom"></param>
4136 /// <param name="SetVD"></param>
4137 public void UpdatePrimFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVD)
4138 {
4139 bool wasUsingPhysics = ((Flags & PrimFlags.Physics) != 0);
4140 bool wasTemporary = ((Flags & PrimFlags.TemporaryOnRez) != 0);
4141 bool wasPhantom = ((Flags & PrimFlags.Phantom) != 0);
4142 bool wasVD = VolumeDetectActive;
4143  
4144 if ((UsePhysics == wasUsingPhysics) && (wasTemporary == SetTemporary) && (wasPhantom == SetPhantom) && (SetVD == wasVD))
4145 return;
4146  
4147 PhysicsActor pa = PhysActor;
4148  
4149 // Special cases for VD. VD can only be called from a script
4150 // and can't be combined with changes to other states. So we can rely
4151 // that...
4152 // ... if VD is changed, all others are not.
4153 // ... if one of the others is changed, VD is not.
4154 if (SetVD) // VD is active, special logic applies
4155 {
4156 // State machine logic for VolumeDetect
4157 // More logic below
4158 bool phanReset = (SetPhantom != wasPhantom) && !SetPhantom;
4159  
4160 if (phanReset) // Phantom changes from on to off switch VD off too
4161 {
4162 SetVD = false; // Switch it of for the course of this routine
4163 VolumeDetectActive = false; // and also permanently
4164  
4165 if (pa != null)
4166 pa.SetVolumeDetect(0); // Let physics know about it too
4167 }
4168 else
4169 {
4170 // If volumedetect is active we don't want phantom to be applied.
4171 // If this is a new call to VD out of the state "phantom"
4172 // this will also cause the prim to be visible to physics
4173 SetPhantom = false;
4174 }
4175 }
4176  
4177 if (UsePhysics && IsJoint())
4178 {
4179 SetPhantom = true;
4180 }
4181  
4182 if (UsePhysics)
4183 {
4184 AddFlag(PrimFlags.Physics);
4185 if (!wasUsingPhysics)
4186 {
4187 DoPhysicsPropertyUpdate(UsePhysics, false);
4188 }
4189 }
4190 else
4191 {
4192 RemFlag(PrimFlags.Physics);
4193 if (wasUsingPhysics)
4194 {
4195 DoPhysicsPropertyUpdate(UsePhysics, false);
4196 }
4197 }
4198  
4199 if (SetPhantom
4200 || ParentGroup.IsAttachment
4201 || PhysicsShapeType == (byte)PhysShapeType.none
4202 || (Shape.PathCurve == (byte)Extrusion.Flexible)) // note: this may have been changed above in the case of joints
4203 {
4204 AddFlag(PrimFlags.Phantom);
4205  
4206 if (PhysActor != null)
4207 {
4208 RemoveFromPhysics();
4209 pa = null;
4210 }
4211 }
4212 else // Not phantom
4213 {
4214 RemFlag(PrimFlags.Phantom);
4215  
4216 if (ParentGroup.Scene == null)
4217 return;
4218  
4219 if (ParentGroup.Scene.CollidablePrims && pa == null)
4220 {
4221 AddToPhysics(UsePhysics, SetPhantom, false);
4222 pa = PhysActor;
4223  
4224 if (pa != null)
4225 {
4226 pa.SetMaterial(Material);
4227 DoPhysicsPropertyUpdate(UsePhysics, true);
4228  
4229 SubscribeForCollisionEvents();
4230 }
4231 }
4232 else // it already has a physical representation
4233 {
4234 DoPhysicsPropertyUpdate(UsePhysics, false); // Update physical status. If it's phantom this will remove the prim
4235 }
4236 }
4237  
4238 if (SetVD)
4239 {
4240 // If the above logic worked (this is urgent candidate to unit tests!)
4241 // we now have a physicsactor.
4242 // Defensive programming calls for a check here.
4243 // Better would be throwing an exception that could be catched by a unit test as the internal
4244 // logic should make sure, this Physactor is always here.
4245 if (pa != null)
4246 {
4247 pa.SetVolumeDetect(1);
4248 AddFlag(PrimFlags.Phantom); // We set this flag also if VD is active
4249 VolumeDetectActive = true;
4250 }
4251 }
4252 else if (SetVD != wasVD)
4253 {
4254 // Remove VolumeDetect in any case. Note, it's safe to call SetVolumeDetect as often as you like
4255 // (mumbles, well, at least if you have infinte CPU powers :-))
4256 if (pa != null)
4257 pa.SetVolumeDetect(0);
4258  
4259 RemFlag(PrimFlags.Phantom);
4260 VolumeDetectActive = false;
4261 }
4262  
4263 if (SetTemporary)
4264 {
4265 AddFlag(PrimFlags.TemporaryOnRez);
4266 }
4267 else
4268 {
4269 RemFlag(PrimFlags.TemporaryOnRez);
4270 }
4271  
4272 // m_log.Debug("Update: PHY:" + UsePhysics.ToString() + ", T:" + IsTemporary.ToString() + ", PHA:" + IsPhantom.ToString() + " S:" + CastsShadows.ToString());
4273  
4274 if (ParentGroup != null)
4275 {
4276 ParentGroup.HasGroupChanged = true;
4277 ScheduleFullUpdate();
4278 }
4279  
4280 // m_log.DebugFormat("[SCENE OBJECT PART]: Updated PrimFlags on {0} {1} to {2}", Name, LocalId, Flags);
4281 }
4282  
4283 /// <summary>
4284 /// Subscribe for physics collision events if needed for scripts and sounds
4285 /// </summary>
4286 public void SubscribeForCollisionEvents()
4287 {
4288 PhysicsActor pa = PhysActor;
4289  
4290 if (pa != null)
4291 {
4292 if (
4293 ((AggregateScriptEvents & scriptEvents.collision) != 0) ||
4294 ((AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4295 ((AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4296 ((AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4297 ((AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4298 ((AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4299 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision) != 0) ||
4300 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_end) != 0) ||
4301 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.collision_start) != 0) ||
4302 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_start) != 0) ||
4303 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision) != 0) ||
4304 ((ParentGroup.RootPart.AggregateScriptEvents & scriptEvents.land_collision_end) != 0) ||
4305 (CollisionSound != UUID.Zero)
4306 )
4307 {
4308 if (!pa.SubscribedEvents())
4309 {
4310 // If not already subscribed for event, set up for a collision event.
4311 pa.OnCollisionUpdate += PhysicsCollision;
4312 pa.SubscribeEvents(1000);
4313 }
4314 }
4315 else
4316 {
4317 // There is no need to be subscribed to collisions so, if subscribed, remove subscription
4318 if (pa.SubscribedEvents())
4319 {
4320 pa.OnCollisionUpdate -= PhysicsCollision;
4321 pa.UnSubscribeEvents();
4322 }
4323 }
4324 }
4325 }
4326  
4327 /// <summary>
4328 /// Adds this part to the physics scene.
4329 /// </summary>
4330 /// <remarks>This method also sets the PhysActor property.</remarks>
4331 /// <param name="rigidBody">Add this prim with a rigid body.</param>
4332 /// <returns>
4333 /// The physics actor. null if there was a failure.
4334 /// </returns>
4335 private void AddToPhysics(bool isPhysical, bool isPhantom, bool applyDynamics)
4336 {
4337 PhysicsActor pa;
4338  
4339 Vector3 velocity = Velocity;
4340 Vector3 rotationalVelocity = AngularVelocity;;
4341  
4342 try
4343 {
4344 pa = ParentGroup.Scene.PhysicsScene.AddPrimShape(
4345 string.Format("{0}/{1}", Name, UUID),
4346 Shape,
4347 AbsolutePosition,
4348 Scale,
4349 GetWorldRotation(),
4350 isPhysical,
4351 isPhantom,
4352 PhysicsShapeType,
4353 m_localId);
4354 }
4355 catch (Exception e)
4356 {
4357 m_log.ErrorFormat("[SCENE]: caught exception meshing object {0}. Object set to phantom. e={1}", m_uuid, e);
4358 pa = null;
4359 }
4360  
4361 if (pa != null)
4362 {
4363 pa.SOPName = this.Name; // save object into the PhysActor so ODE internals know the joint/body info
4364 pa.SetMaterial(Material);
4365  
4366 pa.Density = Density;
4367 pa.GravModifier = GravityModifier;
4368 pa.Friction = Friction;
4369 pa.Restitution = Restitution;
4370  
4371 if (VolumeDetectActive) // change if not the default only
4372 pa.SetVolumeDetect(1);
4373 // we are going to tell rest of code about physics so better have this here
4374 PhysActor = pa;
4375  
4376 if (isPhysical)
4377 {
4378 if (ParentGroup.RootPart.KeyframeMotion != null)
4379 ParentGroup.RootPart.KeyframeMotion.Stop();
4380 ParentGroup.RootPart.KeyframeMotion = null;
4381 ParentGroup.Scene.AddPhysicalPrim(1);
4382  
4383 pa.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate;
4384 pa.OnOutOfBounds += PhysicsOutOfBounds;
4385  
4386 if (ParentID != 0 && ParentID != LocalId)
4387 {
4388 PhysicsActor parentPa = ParentGroup.RootPart.PhysActor;
4389  
4390 if (parentPa != null)
4391 {
4392 pa.link(parentPa);
4393 }
4394 }
4395 }
4396  
4397 if (applyDynamics)
4398 // do independent of isphysical so parameters get setted (at least some)
4399 {
4400 Velocity = velocity;
4401 AngularVelocity = rotationalVelocity;
4402 // pa.Velocity = velocity;
4403 pa.RotationalVelocity = rotationalVelocity;
4404 }
4405  
4406 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
4407 }
4408  
4409 PhysActor = pa;
4410 ParentGroup.Scene.EventManager.TriggerObjectAddedToPhysicalScene(this);
4411 }
4412  
4413 /// <summary>
4414 /// This removes the part from the physics scene.
4415 /// </summary>
4416 /// <remarks>
4417 /// This isn't the same as turning off physical, since even without being physical the prim has a physics
4418 /// representation for collision detection. Rather, this would be used in situations such as making a prim
4419 /// phantom.
4420 /// </remarks>
4421 public void RemoveFromPhysics()
4422 {
4423 ParentGroup.Scene.EventManager.TriggerObjectRemovedFromPhysicalScene(this);
4424 if (ParentGroup.Scene.PhysicsScene != null)
4425 ParentGroup.Scene.PhysicsScene.RemovePrim(PhysActor);
4426 PhysActor = null;
4427 }
4428  
4429 /// <summary>
4430 /// This updates the part's rotation and sends out an update to clients if necessary.
4431 /// </summary>
4432 /// <param name="rot"></param>
4433 public void UpdateRotation(Quaternion rot)
4434 {
4435 if (rot != RotationOffset)
4436 {
4437 RotationOffset = rot;
4438  
4439 if (ParentGroup != null)
4440 {
4441 ParentGroup.HasGroupChanged = true;
4442 ScheduleTerseUpdate();
4443 }
4444 }
4445 }
4446  
4447 /// <summary>
4448 /// Update the shape of this part.
4449 /// </summary>
4450 /// <param name="shapeBlock"></param>
4451 public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock)
4452 {
4453 m_shape.PathBegin = shapeBlock.PathBegin;
4454 m_shape.PathEnd = shapeBlock.PathEnd;
4455 m_shape.PathScaleX = shapeBlock.PathScaleX;
4456 m_shape.PathScaleY = shapeBlock.PathScaleY;
4457 m_shape.PathShearX = shapeBlock.PathShearX;
4458 m_shape.PathShearY = shapeBlock.PathShearY;
4459 m_shape.PathSkew = shapeBlock.PathSkew;
4460 m_shape.ProfileBegin = shapeBlock.ProfileBegin;
4461 m_shape.ProfileEnd = shapeBlock.ProfileEnd;
4462 m_shape.PathCurve = shapeBlock.PathCurve;
4463 m_shape.ProfileCurve = shapeBlock.ProfileCurve;
4464 m_shape.ProfileHollow = shapeBlock.ProfileHollow;
4465 m_shape.PathRadiusOffset = shapeBlock.PathRadiusOffset;
4466 m_shape.PathRevolutions = shapeBlock.PathRevolutions;
4467 m_shape.PathTaperX = shapeBlock.PathTaperX;
4468 m_shape.PathTaperY = shapeBlock.PathTaperY;
4469 m_shape.PathTwist = shapeBlock.PathTwist;
4470 m_shape.PathTwistBegin = shapeBlock.PathTwistBegin;
4471  
4472 PhysicsActor pa = PhysActor;
4473  
4474 if (pa != null)
4475 {
4476 pa.Shape = m_shape;
4477 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(pa);
4478 }
4479  
4480 // This is what makes vehicle trailers work
4481 // A script in a child prim re-issues
4482 // llSetPrimitiveParams(PRIM_TYPE) every few seconds. That
4483 // prevents autoreturn. This is not well known. It also works
4484 // in SL.
4485 //
4486 if (ParentGroup.RootPart != this)
4487 ParentGroup.RootPart.Rezzed = DateTime.UtcNow;
4488  
4489 ParentGroup.HasGroupChanged = true;
4490 TriggerScriptChangedEvent(Changed.SHAPE);
4491 ScheduleFullUpdate();
4492 }
4493  
4494 public void UpdateSlice(float begin, float end)
4495 {
4496 if (end < begin)
4497 {
4498 float temp = begin;
4499 begin = end;
4500 end = temp;
4501 }
4502 end = Math.Min(1f, Math.Max(0f, end));
4503 begin = Math.Min(Math.Min(1f, Math.Max(0f, begin)), end - 0.02f);
4504 if (begin < 0.02f && end < 0.02f)
4505 {
4506 begin = 0f;
4507 end = 0.02f;
4508 }
4509  
4510 ushort uBegin = (ushort)(50000.0 * begin);
4511 ushort uEnd = (ushort)(50000.0 * (1f - end));
4512 bool updatePossiblyNeeded = false;
4513 PrimType primType = GetPrimType();
4514 if (primType == PrimType.SPHERE || primType == PrimType.TORUS || primType == PrimType.TUBE || primType == PrimType.RING)
4515 {
4516 if (m_shape.ProfileBegin != uBegin || m_shape.ProfileEnd != uEnd)
4517 {
4518 m_shape.ProfileBegin = uBegin;
4519 m_shape.ProfileEnd = uEnd;
4520 updatePossiblyNeeded = true;
4521 }
4522 }
4523 else if (m_shape.PathBegin != uBegin || m_shape.PathEnd != uEnd)
4524 {
4525 m_shape.PathBegin = uBegin;
4526 m_shape.PathEnd = uEnd;
4527 updatePossiblyNeeded = true;
4528 }
4529  
4530 if (updatePossiblyNeeded && ParentGroup != null)
4531 {
4532 ParentGroup.HasGroupChanged = true;
4533 }
4534 if (updatePossiblyNeeded && PhysActor != null)
4535 {
4536 PhysActor.Shape = m_shape;
4537 ParentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor);
4538 }
4539 if (updatePossiblyNeeded)
4540 {
4541 ScheduleFullUpdate();
4542 }
4543 }
4544  
4545 /// <summary>
4546 /// If the part is a sculpt/mesh, retrieve the mesh data and reinsert it into the shape so that the physics
4547 /// engine can use it.
4548 /// </summary>
4549 /// <remarks>
4550 /// When the physics engine has finished with it, the sculpt data is discarded to save memory.
4551 /// </remarks>
4552 /*
4553 public void CheckSculptAndLoad()
4554 {
4555 // m_log.DebugFormat("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
4556  
4557 if (ParentGroup.IsDeleted)
4558 return;
4559  
4560 if ((ParentGroup.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
4561 return;
4562  
4563 if (Shape.SculptEntry && Shape.SculptTexture != UUID.Zero)
4564 {
4565 // check if a previously decoded sculpt map has been cached
4566 // We don't read the file here - the meshmerizer will do that later.
4567 // TODO: Could we simplify the meshmerizer code by reading and setting the data here?
4568 if (File.Exists(System.IO.Path.Combine("j2kDecodeCache", "smap_" + Shape.SculptTexture.ToString())))
4569 {
4570 SculptTextureCallback(null);
4571 }
4572 else
4573 {
4574 ParentGroup.Scene.AssetService.Get(Shape.SculptTexture.ToString(), this, AssetReceived);
4575 }
4576 }
4577 }
4578 */
4579 /// <summary>
4580 /// Update the texture entry for this part.
4581 /// </summary>
4582 /// <param name="serializedTextureEntry"></param>
4583 public void UpdateTextureEntry(byte[] serializedTextureEntry)
4584 {
4585 UpdateTextureEntry(new Primitive.TextureEntry(serializedTextureEntry, 0, serializedTextureEntry.Length));
4586 }
4587  
4588 /// <summary>
4589 /// Update the texture entry for this part.
4590 /// </summary>
4591 /// <param name="newTex"></param>
4592 public void UpdateTextureEntry(Primitive.TextureEntry newTex)
4593 {
4594 Primitive.TextureEntry oldTex = Shape.Textures;
4595  
4596 Changed changeFlags = 0;
4597  
4598 Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture;
4599 Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture;
4600  
4601 // On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all
4602 // other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point.
4603 if (fallbackNewFace == null)
4604 {
4605 fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
4606 newTex.DefaultTexture = fallbackNewFace;
4607 }
4608 if (fallbackOldFace == null)
4609 {
4610 fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
4611 oldTex.DefaultTexture = fallbackOldFace;
4612 }
4613  
4614 // Materials capable viewers can send a ObjectImage packet
4615 // when nothing in TE has changed. MaterialID should be updated
4616 // by the RenderMaterials CAP handler, so updating it here may cause a
4617 // race condtion. Therefore, if no non-materials TE fields have changed,
4618 // we should ignore any changes and not update Shape.TextureEntry
4619  
4620 bool otherFieldsChanged = false;
4621  
4622 for (int i = 0 ; i < GetNumberOfSides(); i++)
4623 {
4624  
4625 Primitive.TextureEntryFace newFace = newTex.DefaultTexture;
4626 Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;
4627  
4628 if (oldTex.FaceTextures[i] != null)
4629 oldFace = oldTex.FaceTextures[i];
4630 if (newTex.FaceTextures[i] != null)
4631 newFace = newTex.FaceTextures[i];
4632  
4633 Color4 oldRGBA = oldFace.RGBA;
4634 Color4 newRGBA = newFace.RGBA;
4635  
4636 if (oldRGBA.R != newRGBA.R ||
4637 oldRGBA.G != newRGBA.G ||
4638 oldRGBA.B != newRGBA.B ||
4639 oldRGBA.A != newRGBA.A)
4640 changeFlags |= Changed.COLOR;
4641  
4642 if (oldFace.TextureID != newFace.TextureID)
4643 changeFlags |= Changed.TEXTURE;
4644  
4645 // Max change, skip the rest of testing
4646 if (changeFlags == (Changed.TEXTURE | Changed.COLOR))
4647 break;
4648  
4649 if (!otherFieldsChanged)
4650 {
4651 if (oldFace.Bump != newFace.Bump) otherFieldsChanged = true;
4652 if (oldFace.Fullbright != newFace.Fullbright) otherFieldsChanged = true;
4653 if (oldFace.Glow != newFace.Glow) otherFieldsChanged = true;
4654 if (oldFace.MediaFlags != newFace.MediaFlags) otherFieldsChanged = true;
4655 if (oldFace.OffsetU != newFace.OffsetU) otherFieldsChanged = true;
4656 if (oldFace.OffsetV != newFace.OffsetV) otherFieldsChanged = true;
4657 if (oldFace.RepeatU != newFace.RepeatU) otherFieldsChanged = true;
4658 if (oldFace.RepeatV != newFace.RepeatV) otherFieldsChanged = true;
4659 if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true;
4660 if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true;
4661 if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true;
4662 }
4663 }
4664  
4665 if (changeFlags != 0 || otherFieldsChanged)
4666 {
4667 m_shape.TextureEntry = newTex.GetBytes();
4668 if (changeFlags != 0)
4669 TriggerScriptChangedEvent(changeFlags);
4670 UpdateFlag = UpdateRequired.FULL;
4671 ParentGroup.HasGroupChanged = true;
4672  
4673 //This is madness..
4674 //ParentGroup.ScheduleGroupForFullUpdate();
4675 //This is sparta
4676 ScheduleFullUpdate();
4677 }
4678 }
4679  
4680 public void aggregateScriptEvents()
4681 {
4682 if (ParentGroup == null || ParentGroup.RootPart == null)
4683 return;
4684  
4685 AggregateScriptEvents = 0;
4686  
4687 // Aggregate script events
4688 lock (m_scriptEvents)
4689 {
4690 foreach (scriptEvents s in m_scriptEvents.Values)
4691 {
4692 AggregateScriptEvents |= s;
4693 }
4694 }
4695  
4696 uint objectflagupdate = 0;
4697  
4698 if (
4699 ((AggregateScriptEvents & scriptEvents.touch) != 0) ||
4700 ((AggregateScriptEvents & scriptEvents.touch_end) != 0) ||
4701 ((AggregateScriptEvents & scriptEvents.touch_start) != 0)
4702 )
4703 {
4704 objectflagupdate |= (uint) PrimFlags.Touch;
4705 }
4706  
4707 if ((AggregateScriptEvents & scriptEvents.money) != 0)
4708 {
4709 objectflagupdate |= (uint) PrimFlags.Money;
4710 }
4711  
4712 if (AllowedDrop)
4713 {
4714 objectflagupdate |= (uint) PrimFlags.AllowInventoryDrop;
4715 }
4716  
4717 SubscribeForCollisionEvents();
4718  
4719 //if ((GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0)
4720 //{
4721 // ParentGroup.Scene.EventManager.OnScriptTimerEvent += handleTimerAccounting;
4722 //}
4723 //else
4724 //{
4725 // ParentGroup.Scene.EventManager.OnScriptTimerEvent -= handleTimerAccounting;
4726 //}
4727  
4728 LocalFlags = (PrimFlags)objectflagupdate;
4729  
4730 if (ParentGroup != null && ParentGroup.RootPart == this)
4731 {
4732 ParentGroup.aggregateScriptEvents();
4733 }
4734 else
4735 {
4736 // m_log.DebugFormat(
4737 // "[SCENE OBJECT PART]: Scheduling part {0} {1} for full update in aggregateScriptEvents()", Name, LocalId);
4738 ScheduleFullUpdate();
4739 }
4740 }
4741  
4742 public void SetCameraAtOffset(Vector3 v)
4743 {
4744 m_cameraAtOffset = v;
4745 }
4746  
4747 public void SetCameraEyeOffset(Vector3 v)
4748 {
4749 m_cameraEyeOffset = v;
4750 }
4751  
4752 public void SetForceMouselook(bool force)
4753 {
4754 m_forceMouselook = force;
4755 }
4756  
4757 public Vector3 GetCameraAtOffset()
4758 {
4759 return m_cameraAtOffset;
4760 }
4761  
4762 public Vector3 GetCameraEyeOffset()
4763 {
4764 return m_cameraEyeOffset;
4765 }
4766  
4767 public bool GetForceMouselook()
4768 {
4769 return m_forceMouselook;
4770 }
4771  
4772 public override string ToString()
4773 {
4774 return String.Format("{0} {1} (parent {2}))", Name, UUID, ParentGroup);
4775 }
4776  
4777 #endregion Public Methods
4778  
4779 public void SendTerseUpdateToClient(IClientAPI remoteClient)
4780 {
4781 if (ParentGroup.IsDeleted)
4782 return;
4783  
4784 if (ParentGroup.IsAttachment
4785 && (ParentGroup.RootPart != this
4786 || ParentGroup.AttachedAvatar != remoteClient.AgentId && ParentGroup.HasPrivateAttachmentPoint))
4787 return;
4788  
4789 // Causes this thread to dig into the Client Thread Data.
4790 // Remember your locking here!
4791 remoteClient.SendEntityUpdate(
4792 this,
4793 PrimUpdateFlags.Position | PrimUpdateFlags.Rotation | PrimUpdateFlags.Velocity
4794 | PrimUpdateFlags.Acceleration | PrimUpdateFlags.AngularVelocity);
4795  
4796 ParentGroup.Scene.StatsReporter.AddObjectUpdates(1);
4797 }
4798  
4799 public void AddScriptLPS(int count)
4800 {
4801 ParentGroup.AddScriptLPS(count);
4802 }
4803  
4804 /// <summary>
4805 /// Sets a prim's owner and permissions when it's rezzed.
4806 /// </summary>
4807 /// <param name="item">The inventory item from which the item was rezzed</param>
4808 /// <param name="userInventory">True: the item is being rezzed from the user's inventory. False: from a prim's inventory.</param>
4809 /// <param name="scene">The scene the prim is being rezzed into</param>
4810 public void ApplyPermissionsOnRez(InventoryItemBase item, bool userInventory, Scene scene)
4811 {
4812 if ((OwnerID != item.Owner) || ((item.CurrentPermissions & SceneObjectGroup.SLAM) != 0) || ((item.Flags & (uint)InventoryItemFlags.ObjectSlamPerm) != 0))
4813 {
4814 if (scene.Permissions.PropagatePermissions())
4815 {
4816 if ((item.Flags & (uint)InventoryItemFlags.ObjectHasMultipleItems) == 0)
4817 {
4818 // Apply the item's permissions to the object
4819 //LogPermissions("Before applying item permissions");
4820 if (userInventory)
4821 {
4822 EveryoneMask = item.EveryOnePermissions;
4823 NextOwnerMask = item.NextPermissions;
4824 }
4825 else
4826 {
4827 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteEveryone) != 0)
4828 EveryoneMask = item.EveryOnePermissions;
4829 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteNextOwner) != 0)
4830 NextOwnerMask = item.NextPermissions;
4831 if ((item.Flags & (uint)InventoryItemFlags.ObjectOverwriteGroup) != 0)
4832 GroupMask = item.GroupPermissions;
4833 }
4834 //LogPermissions("After applying item permissions");
4835 }
4836 }
4837  
4838 GroupMask = 0; // DO NOT propagate here
4839 }
4840  
4841 if (OwnerID != item.Owner)
4842 {
4843 //LogPermissions("Before ApplyNextOwnerPermissions");
4844 ApplyNextOwnerPermissions();
4845 //LogPermissions("After ApplyNextOwnerPermissions");
4846  
4847 LastOwnerID = OwnerID;
4848 OwnerID = item.Owner;
4849 Inventory.ChangeInventoryOwner(item.Owner);
4850 }
4851 }
4852  
4853 /// <summary>
4854 /// Logs the prim's permissions. Useful when debugging permission problems.
4855 /// </summary>
4856 /// <param name="message"></param>
4857 private void LogPermissions(String message)
4858 {
4859 PermissionsUtil.LogPermissions(Name, message, BaseMask, OwnerMask, NextOwnerMask);
4860 }
4861  
4862 public void ApplyNextOwnerPermissions()
4863 {
4864 // Export needs to be preserved in the base and everyone
4865 // mask, but removed in the owner mask as a next owner
4866 // can never change the export status
4867 BaseMask &= NextOwnerMask | (uint)PermissionMask.Export;
4868 OwnerMask &= NextOwnerMask;
4869 EveryoneMask &= NextOwnerMask | (uint)PermissionMask.Export;
4870  
4871 Inventory.ApplyNextOwnerPermissions();
4872 }
4873  
4874 public void UpdateLookAt()
4875 {
4876 try
4877 {
4878 if (APIDTarget != Quaternion.Identity)
4879 {
4880 if (m_APIDIterations <= 1)
4881 {
4882 UpdateRotation(APIDTarget);
4883 APIDTarget = Quaternion.Identity;
4884 return;
4885 }
4886  
4887 Quaternion rot = Quaternion.Slerp(RotationOffset,APIDTarget,1.0f/(float)m_APIDIterations);
4888 rot.Normalize();
4889 UpdateRotation(rot);
4890  
4891 m_APIDIterations--;
4892  
4893 // This ensures that we'll check this object on the next iteration
4894 ParentGroup.QueueForUpdateCheck();
4895 }
4896 }
4897 catch (Exception ex)
4898 {
4899 m_log.Error("[Physics] " + ex);
4900 }
4901 }
4902  
4903 public Color4 GetTextColor()
4904 {
4905 Color color = Color;
4906 return new Color4(color.R, color.G, color.B, (byte)(0xFF - color.A));
4907 }
4908  
4909 /// <summary>
4910 /// Record an avatar sitting on this part.
4911 /// </summary>
4912 /// <remarks>This is called for all the sitting avatars whether there is a sit target set or not.</remarks>
4913 /// <returns>
4914 /// true if the avatar was not already recorded, false otherwise.
4915 /// </returns>
4916 /// <param name='avatarId'></param>
4917 protected internal bool AddSittingAvatar(UUID avatarId)
4918 {
4919 lock (ParentGroup.m_sittingAvatars)
4920 {
4921 if (IsSitTargetSet && SitTargetAvatar == UUID.Zero)
4922 SitTargetAvatar = avatarId;
4923  
4924 if (m_sittingAvatars == null)
4925 m_sittingAvatars = new HashSet<UUID>();
4926  
4927 if (m_sittingAvatars.Add(avatarId))
4928 {
4929 ParentGroup.m_sittingAvatars.Add(avatarId);
4930  
4931 return true;
4932 }
4933  
4934 return false;
4935 }
4936 }
4937  
4938 /// <summary>
4939 /// Remove an avatar recorded as sitting on this part.
4940 /// </summary>
4941 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
4942 /// <returns>
4943 /// true if the avatar was present and removed, false if it was not present.
4944 /// </returns>
4945 /// <param name='avatarId'></param>
4946 protected internal bool RemoveSittingAvatar(UUID avatarId)
4947 {
4948 lock (ParentGroup.m_sittingAvatars)
4949 {
4950 if (SitTargetAvatar == avatarId)
4951 SitTargetAvatar = UUID.Zero;
4952  
4953 if (m_sittingAvatars == null)
4954 return false;
4955  
4956 if (m_sittingAvatars.Remove(avatarId))
4957 {
4958 if (m_sittingAvatars.Count == 0)
4959 m_sittingAvatars = null;
4960  
4961 ParentGroup.m_sittingAvatars.Remove(avatarId);
4962  
4963 return true;
4964 }
4965  
4966 return false;
4967 }
4968 }
4969  
4970 /// <summary>
4971 /// Get a copy of the list of sitting avatars.
4972 /// </summary>
4973 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
4974 /// <returns>A hashset of the sitting avatars. Returns null if there are no sitting avatars.</returns>
4975 public HashSet<UUID> GetSittingAvatars()
4976 {
4977 lock (ParentGroup.m_sittingAvatars)
4978 {
4979 if (m_sittingAvatars == null)
4980 return null;
4981 else
4982 return new HashSet<UUID>(m_sittingAvatars);
4983 }
4984 }
4985  
4986 /// <summary>
4987 /// Gets the number of sitting avatars.
4988 /// </summary>
4989 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
4990 /// <returns></returns>
4991 public int GetSittingAvatarsCount()
4992 {
4993 lock (ParentGroup.m_sittingAvatars)
4994 {
4995 if (m_sittingAvatars == null)
4996 return 0;
4997 else
4998 return m_sittingAvatars.Count;
4999 }
5000 }
5001 }
5002 }