diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 253 |
1 files changed, 221 insertions, 32 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 1734ab7..f1f94a7 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -131,6 +131,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
131 | } | 131 | } |
132 | } | 132 | } |
133 | 133 | ||
134 | /// <summary> | ||
135 | /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage | ||
136 | /// (the database). | ||
137 | /// </summary> | ||
138 | /// <remarks> | ||
139 | /// Ultimately, this should be managed such that region modules can change it at the end of a set of operations | ||
140 | /// so that either all changes are preserved or none at all. However, currently, a large amount of internal | ||
141 | /// code will set this anyway when some object properties are changed. | ||
142 | /// </remarks> | ||
134 | public bool HasGroupChanged | 143 | public bool HasGroupChanged |
135 | { | 144 | { |
136 | set | 145 | set |
@@ -244,6 +253,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
244 | } | 253 | } |
245 | } | 254 | } |
246 | 255 | ||
256 | /// <summary> | ||
257 | /// If this scene object has an attachment point then indicate whether there is a point where | ||
258 | /// attachments are perceivable by avatars other than the avatar to which this object is attached. | ||
259 | /// </summary> | ||
260 | /// <remarks> | ||
261 | /// HUDs are not perceivable by other avatars. | ||
262 | /// </remarks> | ||
263 | public bool HasPrivateAttachmentPoint | ||
264 | { | ||
265 | get | ||
266 | { | ||
267 | return AttachmentPoint >= (uint)OpenMetaverse.AttachmentPoint.HUDCenter2 | ||
268 | && AttachmentPoint <= (uint)OpenMetaverse.AttachmentPoint.HUDBottomRight; | ||
269 | } | ||
270 | } | ||
271 | |||
247 | public void ClearPartAttachmentData() | 272 | public void ClearPartAttachmentData() |
248 | { | 273 | { |
249 | AttachmentPoint = 0; | 274 | AttachmentPoint = 0; |
@@ -621,6 +646,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
621 | return; | 646 | return; |
622 | } | 647 | } |
623 | } | 648 | } |
649 | |||
650 | // Restuff the new GroupPosition into each SOP of the linkset. | ||
651 | // This has the affect of resetting and tainting the physics actors. | ||
624 | SceneObjectPart[] parts = m_parts.GetArray(); | 652 | SceneObjectPart[] parts = m_parts.GetArray(); |
625 | bool triggerScriptEvent = m_rootPart.GroupPosition != val; | 653 | bool triggerScriptEvent = m_rootPart.GroupPosition != val; |
626 | if (m_dupeInProgress) | 654 | if (m_dupeInProgress) |
@@ -1649,16 +1677,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
1649 | { | 1677 | { |
1650 | return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); | 1678 | return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); |
1651 | } | 1679 | } |
1652 | |||
1653 | /// <summary> | ||
1654 | /// Added as a way for the storage provider to reset the scene, | ||
1655 | /// most likely a better way to do this sort of thing but for now... | ||
1656 | /// </summary> | ||
1657 | /// <param name="scene"></param> | ||
1658 | public void SetScene(Scene scene) | ||
1659 | { | ||
1660 | m_scene = scene; | ||
1661 | } | ||
1662 | 1680 | ||
1663 | /// <summary> | 1681 | /// <summary> |
1664 | /// Set a part to act as the root part for this scene object | 1682 | /// Set a part to act as the root part for this scene object |
@@ -1740,6 +1758,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1740 | 1758 | ||
1741 | public void ResetChildPrimPhysicsPositions() | 1759 | public void ResetChildPrimPhysicsPositions() |
1742 | { | 1760 | { |
1761 | // Setting this SOG's absolute position also loops through and sets the positions | ||
1762 | // of the SOP's in this SOG's linkset. This has the side affect of making sure | ||
1763 | // the physics world matches the simulated world. | ||
1743 | AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? | 1764 | AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? |
1744 | 1765 | ||
1745 | // teravus: AbsolutePosition is NOT a normal property! | 1766 | // teravus: AbsolutePosition is NOT a normal property! |
@@ -1816,8 +1837,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
1816 | part.ClearUpdateSchedule(); | 1837 | part.ClearUpdateSchedule(); |
1817 | if (part == m_rootPart) | 1838 | if (part == m_rootPart) |
1818 | { | 1839 | { |
1819 | if (!IsAttachment || (AttachedAvatar == avatar.ControllingClient.AgentId) || | 1840 | if (!IsAttachment |
1820 | (AttachmentPoint < 31) || (AttachmentPoint > 38)) | 1841 | || AttachedAvatar == avatar.ControllingClient.AgentId |
1842 | || !HasPrivateAttachmentPoint) | ||
1821 | avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); | 1843 | avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); |
1822 | } | 1844 | } |
1823 | } | 1845 | } |
@@ -2531,8 +2553,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2531 | } | 2553 | } |
2532 | 2554 | ||
2533 | /// <summary> | 2555 | /// <summary> |
2534 | /// Schedule a full update for this scene object | 2556 | /// Schedule a full update for this scene object to all interested viewers. |
2535 | /// </summary> | 2557 | /// </summary> |
2558 | /// <remarks> | ||
2559 | /// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations | ||
2560 | /// so that either all changes are sent at once. However, currently, a large amount of internal | ||
2561 | /// code will set this anyway when some object properties are changed. | ||
2562 | /// </remarks> | ||
2536 | public void ScheduleGroupForFullUpdate() | 2563 | public void ScheduleGroupForFullUpdate() |
2537 | { | 2564 | { |
2538 | // if (IsAttachment) | 2565 | // if (IsAttachment) |
@@ -2551,8 +2578,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2551 | } | 2578 | } |
2552 | 2579 | ||
2553 | /// <summary> | 2580 | /// <summary> |
2554 | /// Schedule a terse update for this scene object | 2581 | /// Schedule a terse update for this scene object to all interested viewers. |
2555 | /// </summary> | 2582 | /// </summary> |
2583 | /// <remarks> | ||
2584 | /// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations | ||
2585 | /// so that either all changes are sent at once. However, currently, a large amount of internal | ||
2586 | /// code will set this anyway when some object properties are changed. | ||
2587 | /// </remarks> | ||
2556 | public void ScheduleGroupForTerseUpdate() | 2588 | public void ScheduleGroupForTerseUpdate() |
2557 | { | 2589 | { |
2558 | // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); | 2590 | // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID); |
@@ -2682,12 +2714,18 @@ namespace OpenSim.Region.Framework.Scenes | |||
2682 | /// <summary> | 2714 | /// <summary> |
2683 | /// Link the prims in a given group to this group | 2715 | /// Link the prims in a given group to this group |
2684 | /// </summary> | 2716 | /// </summary> |
2717 | /// <remarks> | ||
2718 | /// Do not call this method directly - use Scene.LinkObjects() instead to avoid races between threads. | ||
2719 | /// FIXME: There are places where scripts call these methods directly without locking. This is a potential race condition. | ||
2720 | /// </remarks> | ||
2685 | /// <param name="objectGroup">The group of prims which should be linked to this group</param> | 2721 | /// <param name="objectGroup">The group of prims which should be linked to this group</param> |
2686 | public void LinkToGroup(SceneObjectGroup objectGroup) | 2722 | public void LinkToGroup(SceneObjectGroup objectGroup) |
2687 | { | 2723 | { |
2688 | LinkToGroup(objectGroup, false); | 2724 | LinkToGroup(objectGroup, false); |
2689 | } | 2725 | } |
2690 | 2726 | ||
2727 | // Link an existing group to this group. | ||
2728 | // The group being linked need not be a linkset -- it can have just one prim. | ||
2691 | public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) | 2729 | public void LinkToGroup(SceneObjectGroup objectGroup, bool insert) |
2692 | { | 2730 | { |
2693 | // m_log.DebugFormat( | 2731 | // m_log.DebugFormat( |
@@ -2698,6 +2736,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2698 | if (objectGroup == this) | 2736 | if (objectGroup == this) |
2699 | return; | 2737 | return; |
2700 | 2738 | ||
2739 | // 'linkPart' == the root of the group being linked into this group | ||
2701 | SceneObjectPart linkPart = objectGroup.m_rootPart; | 2740 | SceneObjectPart linkPart = objectGroup.m_rootPart; |
2702 | 2741 | ||
2703 | if (m_rootPart.PhysActor != null) | 2742 | if (m_rootPart.PhysActor != null) |
@@ -2709,31 +2748,44 @@ namespace OpenSim.Region.Framework.Scenes | |||
2709 | bool grpusephys = UsesPhysics; | 2748 | bool grpusephys = UsesPhysics; |
2710 | bool grptemporary = IsTemporary; | 2749 | bool grptemporary = IsTemporary; |
2711 | 2750 | ||
2751 | // Remember where the group being linked thought it was | ||
2712 | Vector3 oldGroupPosition = linkPart.GroupPosition; | 2752 | Vector3 oldGroupPosition = linkPart.GroupPosition; |
2713 | Quaternion oldRootRotation = linkPart.RotationOffset; | 2753 | Quaternion oldRootRotation = linkPart.RotationOffset; |
2714 | 2754 | ||
2715 | linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; | 2755 | // A linked SOP remembers its location and rotation relative to the root of a group. |
2756 | // Convert the root of the group being linked to be relative to the | ||
2757 | // root of the group being linked to. | ||
2758 | // Note: Some of the assignments have complex side effects. | ||
2716 | 2759 | ||
2760 | // First move the new group's root SOP's position to be relative to ours | ||
2761 | // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, | ||
2762 | // this code can be reordered to have a more logical flow.) | ||
2763 | linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; | ||
2764 | // Assign the new parent to the root of the old group | ||
2717 | linkPart.ParentID = m_rootPart.LocalId; | 2765 | linkPart.ParentID = m_rootPart.LocalId; |
2718 | 2766 | // Now that it's a child, it's group position is our root position | |
2719 | linkPart.GroupPosition = AbsolutePosition; | 2767 | linkPart.GroupPosition = AbsolutePosition; |
2720 | 2768 | ||
2721 | Vector3 axPos = linkPart.OffsetPosition; | 2769 | Vector3 axPos = linkPart.OffsetPosition; |
2770 | // Rotate the linking root SOP's position to be relative to the new root prim | ||
2722 | Quaternion parentRot = m_rootPart.RotationOffset; | 2771 | Quaternion parentRot = m_rootPart.RotationOffset; |
2723 | axPos *= Quaternion.Conjugate(parentRot); | 2772 | axPos *= Quaternion.Conjugate(parentRot); |
2724 | linkPart.OffsetPosition = axPos; | 2773 | linkPart.OffsetPosition = axPos; |
2725 | 2774 | ||
2775 | // Make the linking root SOP's rotation relative to the new root prim | ||
2726 | Quaternion oldRot = linkPart.RotationOffset; | 2776 | Quaternion oldRot = linkPart.RotationOffset; |
2727 | Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot; | 2777 | Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot; |
2728 | linkPart.RotationOffset = newRot; | 2778 | linkPart.RotationOffset = newRot; |
2729 | 2779 | ||
2730 | // linkPart.ParentID = m_rootPart.LocalId; done above | 2780 | // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. |
2731 | 2781 | // Now that we know this SOG has at least two SOPs in it, the new root | |
2782 | // SOP becomes the first in the linkset. | ||
2732 | if (m_rootPart.LinkNum == 0) | 2783 | if (m_rootPart.LinkNum == 0) |
2733 | m_rootPart.LinkNum = 1; | 2784 | m_rootPart.LinkNum = 1; |
2734 | 2785 | ||
2735 | lock (m_parts.SyncRoot) | 2786 | lock (m_parts.SyncRoot) |
2736 | { | 2787 | { |
2788 | // Calculate the new link number for the old root SOP | ||
2737 | int linkNum; | 2789 | int linkNum; |
2738 | if (insert) | 2790 | if (insert) |
2739 | { | 2791 | { |
@@ -2749,6 +2801,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2749 | linkNum = PrimCount + 1; | 2801 | linkNum = PrimCount + 1; |
2750 | } | 2802 | } |
2751 | 2803 | ||
2804 | // Add the old root SOP as a part in our group's list | ||
2752 | m_parts.Add(linkPart.UUID, linkPart); | 2805 | m_parts.Add(linkPart.UUID, linkPart); |
2753 | 2806 | ||
2754 | linkPart.SetParent(this); | 2807 | linkPart.SetParent(this); |
@@ -2756,6 +2809,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2756 | 2809 | ||
2757 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now | 2810 | // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now |
2758 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); | 2811 | linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true); |
2812 | |||
2813 | // If the added SOP is physical, also tell the physics engine about the link relationship. | ||
2759 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 2814 | if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
2760 | { | 2815 | { |
2761 | linkPart.PhysActor.link(m_rootPart.PhysActor); | 2816 | linkPart.PhysActor.link(m_rootPart.PhysActor); |
@@ -2763,21 +2818,28 @@ namespace OpenSim.Region.Framework.Scenes | |||
2763 | } | 2818 | } |
2764 | 2819 | ||
2765 | linkPart.LinkNum = linkNum++; | 2820 | linkPart.LinkNum = linkNum++; |
2821 | linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); | ||
2766 | 2822 | ||
2823 | // Get a list of the SOP's in the old group in order of their linknum's. | ||
2767 | SceneObjectPart[] ogParts = objectGroup.Parts; | 2824 | SceneObjectPart[] ogParts = objectGroup.Parts; |
2768 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) | 2825 | Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) |
2769 | { | 2826 | { |
2770 | return a.LinkNum - b.LinkNum; | 2827 | return a.LinkNum - b.LinkNum; |
2771 | }); | 2828 | }); |
2772 | 2829 | ||
2830 | // Add each of the SOP's from the old linkset to our linkset | ||
2773 | for (int i = 0; i < ogParts.Length; i++) | 2831 | for (int i = 0; i < ogParts.Length; i++) |
2774 | { | 2832 | { |
2775 | SceneObjectPart part = ogParts[i]; | 2833 | SceneObjectPart part = ogParts[i]; |
2776 | if (part.UUID != objectGroup.m_rootPart.UUID) | 2834 | if (part.UUID != objectGroup.m_rootPart.UUID) |
2777 | { | 2835 | { |
2778 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); | 2836 | LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); |
2779 | // let physics know | 2837 | |
2838 | // Update the physics flags for the newly added SOP | ||
2839 | // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) | ||
2780 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true); | 2840 | part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true); |
2841 | |||
2842 | // If the added SOP is physical, also tell the physics engine about the link relationship. | ||
2781 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) | 2843 | if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) |
2782 | { | 2844 | { |
2783 | part.PhysActor.link(m_rootPart.PhysActor); | 2845 | part.PhysActor.link(m_rootPart.PhysActor); |
@@ -2788,6 +2850,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2788 | } | 2850 | } |
2789 | } | 2851 | } |
2790 | 2852 | ||
2853 | // Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene. | ||
2791 | m_scene.UnlinkSceneObject(objectGroup, true); | 2854 | m_scene.UnlinkSceneObject(objectGroup, true); |
2792 | objectGroup.IsDeleted = true; | 2855 | objectGroup.IsDeleted = true; |
2793 | 2856 | ||
@@ -2814,6 +2877,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2814 | /// Delink the given prim from this group. The delinked prim is established as | 2877 | /// Delink the given prim from this group. The delinked prim is established as |
2815 | /// an independent SceneObjectGroup. | 2878 | /// an independent SceneObjectGroup. |
2816 | /// </summary> | 2879 | /// </summary> |
2880 | /// <remarks> | ||
2881 | /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race | ||
2882 | /// condition. But currently there is no | ||
2883 | /// alternative method that does take a lonk to delink a single prim. | ||
2884 | /// </remarks> | ||
2817 | /// <param name="partID"></param> | 2885 | /// <param name="partID"></param> |
2818 | /// <returns>The object group of the newly delinked prim. Null if part could not be found</returns> | 2886 | /// <returns>The object group of the newly delinked prim. Null if part could not be found</returns> |
2819 | public SceneObjectGroup DelinkFromGroup(uint partID) | 2887 | public SceneObjectGroup DelinkFromGroup(uint partID) |
@@ -2825,6 +2893,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2825 | /// Delink the given prim from this group. The delinked prim is established as | 2893 | /// Delink the given prim from this group. The delinked prim is established as |
2826 | /// an independent SceneObjectGroup. | 2894 | /// an independent SceneObjectGroup. |
2827 | /// </summary> | 2895 | /// </summary> |
2896 | /// <remarks> | ||
2897 | /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race | ||
2898 | /// condition. But currently there is no | ||
2899 | /// alternative method that does take a lonk to delink a single prim. | ||
2900 | /// </remarks> | ||
2828 | /// <param name="partID"></param> | 2901 | /// <param name="partID"></param> |
2829 | /// <param name="sendEvents"></param> | 2902 | /// <param name="sendEvents"></param> |
2830 | /// <returns>The object group of the newly delinked prim. Null if part could not be found</returns> | 2903 | /// <returns>The object group of the newly delinked prim. Null if part could not be found</returns> |
@@ -2850,6 +2923,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2850 | /// Delink the given prim from this group. The delinked prim is established as | 2923 | /// Delink the given prim from this group. The delinked prim is established as |
2851 | /// an independent SceneObjectGroup. | 2924 | /// an independent SceneObjectGroup. |
2852 | /// </summary> | 2925 | /// </summary> |
2926 | /// <remarks> | ||
2927 | /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race | ||
2928 | /// condition. But currently there is no | ||
2929 | /// alternative method that does take a lock to delink a single prim. | ||
2930 | /// </remarks> | ||
2853 | /// <param name="partID"></param> | 2931 | /// <param name="partID"></param> |
2854 | /// <param name="sendEvents"></param> | 2932 | /// <param name="sendEvents"></param> |
2855 | /// <returns>The object group of the newly delinked prim.</returns> | 2933 | /// <returns>The object group of the newly delinked prim.</returns> |
@@ -2864,6 +2942,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2864 | 2942 | ||
2865 | linkPart.ClearUndoState(); | 2943 | linkPart.ClearUndoState(); |
2866 | 2944 | ||
2945 | Vector3 worldPos = linkPart.GetWorldPosition(); | ||
2867 | Quaternion worldRot = linkPart.GetWorldRotation(); | 2946 | Quaternion worldRot = linkPart.GetWorldRotation(); |
2868 | 2947 | ||
2869 | // Remove the part from this object | 2948 | // Remove the part from this object |
@@ -2873,6 +2952,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2873 | 2952 | ||
2874 | SceneObjectPart[] parts = m_parts.GetArray(); | 2953 | SceneObjectPart[] parts = m_parts.GetArray(); |
2875 | 2954 | ||
2955 | // Rejigger the linknum's of the remaining SOP's to fill any gap | ||
2876 | if (parts.Length == 1 && RootPart != null) | 2956 | if (parts.Length == 1 && RootPart != null) |
2877 | { | 2957 | { |
2878 | // Single prim left | 2958 | // Single prim left |
@@ -2894,22 +2974,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
2894 | 2974 | ||
2895 | PhysicsActor linkPartPa = linkPart.PhysActor; | 2975 | PhysicsActor linkPartPa = linkPart.PhysActor; |
2896 | 2976 | ||
2977 | // Remove the SOP from the physical scene. | ||
2978 | // If the new SOG is physical, it is re-created later. | ||
2979 | // (There is a problem here in that we have not yet told the physics | ||
2980 | // engine about the delink. Someday, linksets should be made first | ||
2981 | // class objects in the physics engine interface). | ||
2897 | if (linkPartPa != null) | 2982 | if (linkPartPa != null) |
2898 | m_scene.PhysicsScene.RemovePrim(linkPartPa); | 2983 | m_scene.PhysicsScene.RemovePrim(linkPartPa); |
2899 | 2984 | ||
2900 | // We need to reset the child part's position | 2985 | // We need to reset the child part's position |
2901 | // ready for life as a separate object after being a part of another object | 2986 | // ready for life as a separate object after being a part of another object |
2902 | Quaternion parentRot = m_rootPart.RotationOffset; | ||
2903 | 2987 | ||
2988 | /* This commented out code seems to recompute what GetWorldPosition already does. | ||
2989 | * Replace with a call to GetWorldPosition (before unlinking) | ||
2990 | Quaternion parentRot = m_rootPart.RotationOffset; | ||
2904 | Vector3 axPos = linkPart.OffsetPosition; | 2991 | Vector3 axPos = linkPart.OffsetPosition; |
2905 | |||
2906 | axPos *= parentRot; | 2992 | axPos *= parentRot; |
2907 | linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); | 2993 | linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z); |
2908 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; | 2994 | linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; |
2909 | linkPart.OffsetPosition = new Vector3(0, 0, 0); | 2995 | linkPart.OffsetPosition = new Vector3(0, 0, 0); |
2910 | 2996 | */ | |
2997 | linkPart.GroupPosition = worldPos; | ||
2998 | linkPart.OffsetPosition = Vector3.Zero; | ||
2911 | linkPart.RotationOffset = worldRot; | 2999 | linkPart.RotationOffset = worldRot; |
2912 | 3000 | ||
3001 | // Create a new SOG to go around this unlinked and unattached SOP | ||
2913 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); | 3002 | SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); |
2914 | 3003 | ||
2915 | m_scene.AddNewSceneObject(objectGroup, true); | 3004 | m_scene.AddNewSceneObject(objectGroup, true); |
@@ -2947,42 +3036,58 @@ namespace OpenSim.Region.Framework.Scenes | |||
2947 | m_isBackedUp = false; | 3036 | m_isBackedUp = false; |
2948 | } | 3037 | } |
2949 | 3038 | ||
3039 | // This links an SOP from a previous linkset into my linkset. | ||
3040 | // The trick is that the SOP's position and rotation are relative to the old root SOP's | ||
3041 | // so we are passed in the position and rotation of the old linkset so this can | ||
3042 | // unjigger this SOP's position and rotation from the previous linkset and | ||
3043 | // then make them relative to my linkset root. | ||
2950 | private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) | 3044 | private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum) |
2951 | { | 3045 | { |
2952 | Quaternion parentRot = oldGroupRotation; | 3046 | Quaternion parentRot = oldGroupRotation; |
2953 | Quaternion oldRot = part.RotationOffset; | 3047 | Quaternion oldRot = part.RotationOffset; |
2954 | Quaternion worldRot = parentRot * oldRot; | ||
2955 | |||
2956 | parentRot = oldGroupRotation; | ||
2957 | 3048 | ||
3049 | // Move our position to not be relative to the old parent | ||
2958 | Vector3 axPos = part.OffsetPosition; | 3050 | Vector3 axPos = part.OffsetPosition; |
2959 | |||
2960 | axPos *= parentRot; | 3051 | axPos *= parentRot; |
2961 | part.OffsetPosition = axPos; | 3052 | part.OffsetPosition = axPos; |
2962 | Vector3 newPos = oldGroupPosition + part.OffsetPosition; | 3053 | Vector3 newPos = oldGroupPosition + part.OffsetPosition; |
2963 | part.GroupPosition = newPos; | 3054 | part.GroupPosition = newPos; |
2964 | part.OffsetPosition = Vector3.Zero; | 3055 | part.OffsetPosition = Vector3.Zero; |
3056 | |||
3057 | // Compution our rotation to be not relative to the old parent | ||
3058 | Quaternion worldRot = parentRot * oldRot; | ||
2965 | part.RotationOffset = worldRot; | 3059 | part.RotationOffset = worldRot; |
2966 | 3060 | ||
3061 | // Add this SOP to our linkset | ||
2967 | part.SetParent(this); | 3062 | part.SetParent(this); |
2968 | part.ParentID = m_rootPart.LocalId; | 3063 | part.ParentID = m_rootPart.LocalId; |
2969 | |||
2970 | m_parts.Add(part.UUID, part); | 3064 | m_parts.Add(part.UUID, part); |
2971 | 3065 | ||
2972 | part.LinkNum = linkNum; | 3066 | part.LinkNum = linkNum; |
2973 | 3067 | ||
2974 | part.OffsetPosition = newPos - AbsolutePosition; | 3068 | // Compute the new position of this SOP relative to the group position |
3069 | part.OffsetPosition = part.GroupPosition - AbsolutePosition; | ||
2975 | 3070 | ||
2976 | Quaternion rootRotation = m_rootPart.RotationOffset; | 3071 | // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. |
3072 | // It would have the affect of setting the physics engine position multiple | ||
3073 | // times. In theory, that is not necessary but I don't have a good linkset | ||
3074 | // test to know that cleaning up this code wouldn't break things.) | ||
2977 | 3075 | ||
3076 | // Rotate the relative position by the rotation of the group | ||
3077 | Quaternion rootRotation = m_rootPart.RotationOffset; | ||
2978 | Vector3 pos = part.OffsetPosition; | 3078 | Vector3 pos = part.OffsetPosition; |
2979 | pos *= Quaternion.Conjugate(rootRotation); | 3079 | pos *= Quaternion.Conjugate(rootRotation); |
2980 | part.OffsetPosition = pos; | 3080 | part.OffsetPosition = pos; |
2981 | 3081 | ||
3082 | // Compute the SOP's rotation relative to the rotation of the group. | ||
2982 | parentRot = m_rootPart.RotationOffset; | 3083 | parentRot = m_rootPart.RotationOffset; |
2983 | oldRot = part.RotationOffset; | 3084 | oldRot = part.RotationOffset; |
2984 | Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot; | 3085 | Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot; |
2985 | part.RotationOffset = newRot; | 3086 | part.RotationOffset = newRot; |
3087 | |||
3088 | // Since this SOP's state has changed, push those changes into the physics engine | ||
3089 | // and the simulator. | ||
3090 | part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false); | ||
2986 | } | 3091 | } |
2987 | 3092 | ||
2988 | /// <summary> | 3093 | /// <summary> |
@@ -3498,7 +3603,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
3498 | 3603 | ||
3499 | //we need to do a terse update even if the move wasn't allowed | 3604 | //we need to do a terse update even if the move wasn't allowed |
3500 | // so that the position is reset in the client (the object snaps back) | 3605 | // so that the position is reset in the client (the object snaps back) |
3501 | ScheduleGroupForTerseUpdate(); | 3606 | RootPart.ScheduleTerseUpdate(); |
3502 | } | 3607 | } |
3503 | 3608 | ||
3504 | /// <summary> | 3609 | /// <summary> |
@@ -3613,6 +3718,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
3613 | m_scene.PhysicsScene.AddPhysicsActorTaint(actor); | 3718 | m_scene.PhysicsScene.AddPhysicsActorTaint(actor); |
3614 | } | 3719 | } |
3615 | 3720 | ||
3721 | if (IsAttachment) | ||
3722 | { | ||
3723 | m_rootPart.AttachedPos = pos; | ||
3724 | } | ||
3725 | |||
3616 | AbsolutePosition = pos; | 3726 | AbsolutePosition = pos; |
3617 | 3727 | ||
3618 | HasGroupChanged = true; | 3728 | HasGroupChanged = true; |
@@ -4199,7 +4309,86 @@ namespace OpenSim.Region.Framework.Scenes | |||
4199 | for (int i = 0; i < parts.Length; i++) | 4309 | for (int i = 0; i < parts.Length; i++) |
4200 | parts[i].TriggerScriptChangedEvent(val); | 4310 | parts[i].TriggerScriptChangedEvent(val); |
4201 | } | 4311 | } |
4202 | 4312 | ||
4313 | /// <summary> | ||
4314 | /// Returns a count of the number of scripts in this groups parts. | ||
4315 | /// </summary> | ||
4316 | public int ScriptCount() | ||
4317 | { | ||
4318 | int count = 0; | ||
4319 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
4320 | for (int i = 0; i < parts.Length; i++) | ||
4321 | count += parts[i].Inventory.ScriptCount(); | ||
4322 | |||
4323 | return count; | ||
4324 | } | ||
4325 | |||
4326 | /// <summary> | ||
4327 | /// A float the value is a representative execution time in milliseconds of all scripts in the link set. | ||
4328 | /// </summary> | ||
4329 | public float ScriptExecutionTime() | ||
4330 | { | ||
4331 | IScriptModule[] engines = Scene.RequestModuleInterfaces<IScriptModule>(); | ||
4332 | |||
4333 | if (engines.Length == 0) // No engine at all | ||
4334 | return 0.0f; | ||
4335 | |||
4336 | float time = 0.0f; | ||
4337 | |||
4338 | // get all the scripts in all parts | ||
4339 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
4340 | List<TaskInventoryItem> scripts = new List<TaskInventoryItem>(); | ||
4341 | for (int i = 0; i < parts.Length; i++) | ||
4342 | { | ||
4343 | scripts.AddRange(parts[i].Inventory.GetInventoryItems(InventoryType.LSL)); | ||
4344 | } | ||
4345 | // extract the UUIDs | ||
4346 | List<UUID> ids = new List<UUID>(scripts.Count); | ||
4347 | foreach (TaskInventoryItem script in scripts) | ||
4348 | { | ||
4349 | if (!ids.Contains(script.ItemID)) | ||
4350 | { | ||
4351 | ids.Add(script.ItemID); | ||
4352 | } | ||
4353 | } | ||
4354 | // Offer the list of script UUIDs to each engine found and accumulate the time | ||
4355 | foreach (IScriptModule e in engines) | ||
4356 | { | ||
4357 | if (e != null) | ||
4358 | { | ||
4359 | time += e.GetScriptExecutionTime(ids); | ||
4360 | } | ||
4361 | } | ||
4362 | return time; | ||
4363 | } | ||
4364 | |||
4365 | /// <summary> | ||
4366 | /// Returns a count of the number of running scripts in this groups parts. | ||
4367 | /// </summary> | ||
4368 | public int RunningScriptCount() | ||
4369 | { | ||
4370 | int count = 0; | ||
4371 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
4372 | for (int i = 0; i < parts.Length; i++) | ||
4373 | count += parts[i].Inventory.RunningScriptCount(); | ||
4374 | |||
4375 | return count; | ||
4376 | } | ||
4377 | |||
4378 | /// <summary> | ||
4379 | /// Gets the number of sitting avatars. | ||
4380 | /// </summary> | ||
4381 | /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks> | ||
4382 | /// <returns></returns> | ||
4383 | public int GetSittingAvatarsCount() | ||
4384 | { | ||
4385 | int count = 0; | ||
4386 | |||
4387 | Array.ForEach<SceneObjectPart>(m_parts.GetArray(), p => count += p.GetSittingAvatarsCount()); | ||
4388 | |||
4389 | return count; | ||
4390 | } | ||
4391 | |||
4203 | public override string ToString() | 4392 | public override string ToString() |
4204 | { | 4393 | { |
4205 | return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); | 4394 | return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition); |