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