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