diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 708 |
1 files changed, 552 insertions, 156 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 42ac9aa..482597d 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Drawing; | 30 | using System.Drawing; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Diagnostics; | ||
32 | using System.Linq; | 33 | using System.Linq; |
33 | using System.Threading; | 34 | using System.Threading; |
34 | using System.Xml; | 35 | using System.Xml; |
@@ -105,8 +106,29 @@ namespace OpenSim.Region.Framework.Scenes | |||
105 | /// since the group's last persistent backup | 106 | /// since the group's last persistent backup |
106 | /// </summary> | 107 | /// </summary> |
107 | private bool m_hasGroupChanged = false; | 108 | private bool m_hasGroupChanged = false; |
108 | private long timeFirstChanged; | 109 | private long timeFirstChanged = 0; |
109 | private long timeLastChanged; | 110 | private long timeLastChanged = 0; |
111 | private long m_maxPersistTime = 0; | ||
112 | private long m_minPersistTime = 0; | ||
113 | private Random m_rand; | ||
114 | private bool m_suspendUpdates; | ||
115 | private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>(); | ||
116 | |||
117 | public bool areUpdatesSuspended | ||
118 | { | ||
119 | get | ||
120 | { | ||
121 | return m_suspendUpdates; | ||
122 | } | ||
123 | set | ||
124 | { | ||
125 | m_suspendUpdates = value; | ||
126 | if (!value) | ||
127 | { | ||
128 | QueueForUpdateCheck(); | ||
129 | } | ||
130 | } | ||
131 | } | ||
110 | 132 | ||
111 | public bool HasGroupChanged | 133 | public bool HasGroupChanged |
112 | { | 134 | { |
@@ -114,9 +136,39 @@ namespace OpenSim.Region.Framework.Scenes | |||
114 | { | 136 | { |
115 | if (value) | 137 | if (value) |
116 | { | 138 | { |
139 | if (m_isBackedUp) | ||
140 | { | ||
141 | m_scene.SceneGraph.FireChangeBackup(this); | ||
142 | } | ||
117 | timeLastChanged = DateTime.Now.Ticks; | 143 | timeLastChanged = DateTime.Now.Ticks; |
118 | if (!m_hasGroupChanged) | 144 | if (!m_hasGroupChanged) |
119 | timeFirstChanged = DateTime.Now.Ticks; | 145 | timeFirstChanged = DateTime.Now.Ticks; |
146 | if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null) | ||
147 | { | ||
148 | if (m_rand == null) | ||
149 | { | ||
150 | byte[] val = new byte[16]; | ||
151 | m_rootPart.UUID.ToBytes(val, 0); | ||
152 | m_rand = new Random(BitConverter.ToInt32(val, 0)); | ||
153 | } | ||
154 | |||
155 | if (m_scene.GetRootAgentCount() == 0) | ||
156 | { | ||
157 | //If the region is empty, this change has been made by an automated process | ||
158 | //and thus we delay the persist time by a random amount between 1.5 and 2.5. | ||
159 | |||
160 | float factor = 1.5f + (float)(m_rand.NextDouble()); | ||
161 | m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor); | ||
162 | m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor); | ||
163 | } | ||
164 | else | ||
165 | { | ||
166 | //If the region is not empty, we want to obey the minimum and maximum persist times | ||
167 | //but add a random factor so we stagger the object persistance a little | ||
168 | m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5 | ||
169 | m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0 | ||
170 | } | ||
171 | } | ||
120 | } | 172 | } |
121 | m_hasGroupChanged = value; | 173 | m_hasGroupChanged = value; |
122 | 174 | ||
@@ -131,7 +183,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
131 | /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since | 183 | /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since |
132 | /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. | 184 | /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. |
133 | /// </summary> | 185 | /// </summary> |
134 | public bool HasGroupChangedDueToDelink { get; private set; } | 186 | public bool HasGroupChangedDueToDelink { get; set; } |
135 | 187 | ||
136 | private bool isTimeToPersist() | 188 | private bool isTimeToPersist() |
137 | { | 189 | { |
@@ -141,8 +193,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
141 | return false; | 193 | return false; |
142 | if (m_scene.ShuttingDown) | 194 | if (m_scene.ShuttingDown) |
143 | return true; | 195 | return true; |
196 | |||
197 | if (m_minPersistTime == 0 || m_maxPersistTime == 0) | ||
198 | { | ||
199 | m_maxPersistTime = m_scene.m_persistAfter; | ||
200 | m_minPersistTime = m_scene.m_dontPersistBefore; | ||
201 | } | ||
202 | |||
144 | long currentTime = DateTime.Now.Ticks; | 203 | long currentTime = DateTime.Now.Ticks; |
145 | if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) | 204 | |
205 | if (timeLastChanged == 0) timeLastChanged = currentTime; | ||
206 | if (timeFirstChanged == 0) timeFirstChanged = currentTime; | ||
207 | |||
208 | if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime) | ||
146 | return true; | 209 | return true; |
147 | return false; | 210 | return false; |
148 | } | 211 | } |
@@ -185,10 +248,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
185 | 248 | ||
186 | private bool m_scriptListens_atTarget; | 249 | private bool m_scriptListens_atTarget; |
187 | private bool m_scriptListens_notAtTarget; | 250 | private bool m_scriptListens_notAtTarget; |
188 | |||
189 | private bool m_scriptListens_atRotTarget; | 251 | private bool m_scriptListens_atRotTarget; |
190 | private bool m_scriptListens_notAtRotTarget; | 252 | private bool m_scriptListens_notAtRotTarget; |
191 | 253 | ||
254 | public bool m_dupeInProgress = false; | ||
192 | internal Dictionary<UUID, string> m_savedScriptState; | 255 | internal Dictionary<UUID, string> m_savedScriptState; |
193 | 256 | ||
194 | #region Properties | 257 | #region Properties |
@@ -228,7 +291,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
228 | public virtual Quaternion Rotation | 291 | public virtual Quaternion Rotation |
229 | { | 292 | { |
230 | get { return m_rotation; } | 293 | get { return m_rotation; } |
231 | set { m_rotation = value; } | 294 | set { |
295 | foreach(SceneObjectPart p in m_parts.GetArray()) | ||
296 | { | ||
297 | p.StoreUndoState(UndoType.STATE_GROUP_ROTATION); | ||
298 | } | ||
299 | m_rotation = value; | ||
300 | } | ||
232 | } | 301 | } |
233 | 302 | ||
234 | public Quaternion GroupRotation | 303 | public Quaternion GroupRotation |
@@ -305,7 +374,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
305 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); | 374 | m_scene.CrossPrimGroupIntoNewRegion(val, this, true); |
306 | } | 375 | } |
307 | } | 376 | } |
308 | 377 | ||
378 | foreach (SceneObjectPart part in m_parts.GetArray()) | ||
379 | { | ||
380 | part.IgnoreUndoUpdate = true; | ||
381 | } | ||
309 | if (RootPart.GetStatusSandbox()) | 382 | if (RootPart.GetStatusSandbox()) |
310 | { | 383 | { |
311 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) | 384 | if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) |
@@ -319,10 +392,31 @@ namespace OpenSim.Region.Framework.Scenes | |||
319 | return; | 392 | return; |
320 | } | 393 | } |
321 | } | 394 | } |
322 | |||
323 | SceneObjectPart[] parts = m_parts.GetArray(); | 395 | SceneObjectPart[] parts = m_parts.GetArray(); |
324 | for (int i = 0; i < parts.Length; i++) | 396 | foreach (SceneObjectPart part in parts) |
325 | parts[i].GroupPosition = val; | 397 | { |
398 | part.IgnoreUndoUpdate = false; | ||
399 | part.StoreUndoState(UndoType.STATE_GROUP_POSITION); | ||
400 | part.GroupPosition = val; | ||
401 | if (!m_dupeInProgress) | ||
402 | { | ||
403 | part.TriggerScriptChangedEvent(Changed.POSITION); | ||
404 | } | ||
405 | } | ||
406 | if (!m_dupeInProgress) | ||
407 | { | ||
408 | foreach (ScenePresence av in m_linkedAvatars) | ||
409 | { | ||
410 | SceneObjectPart p; | ||
411 | if (m_parts.TryGetValue(av.LinkedPrim, out p)) | ||
412 | { | ||
413 | Vector3 offset = p.GetWorldPosition() - av.ParentPosition; | ||
414 | av.AbsolutePosition += offset; | ||
415 | av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition | ||
416 | av.SendAvatarDataToAllAgents(); | ||
417 | } | ||
418 | } | ||
419 | } | ||
326 | 420 | ||
327 | //if (m_rootPart.PhysActor != null) | 421 | //if (m_rootPart.PhysActor != null) |
328 | //{ | 422 | //{ |
@@ -481,6 +575,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
481 | /// </summary> | 575 | /// </summary> |
482 | public SceneObjectGroup() | 576 | public SceneObjectGroup() |
483 | { | 577 | { |
578 | |||
484 | } | 579 | } |
485 | 580 | ||
486 | /// <summary> | 581 | /// <summary> |
@@ -497,7 +592,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
497 | /// Constructor. This object is added to the scene later via AttachToScene() | 592 | /// Constructor. This object is added to the scene later via AttachToScene() |
498 | /// </summary> | 593 | /// </summary> |
499 | public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) | 594 | public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) |
500 | { | 595 | { |
501 | SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); | 596 | SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); |
502 | } | 597 | } |
503 | 598 | ||
@@ -545,6 +640,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
545 | /// </summary> | 640 | /// </summary> |
546 | public virtual void AttachToBackup() | 641 | public virtual void AttachToBackup() |
547 | { | 642 | { |
643 | if (IsAttachment) return; | ||
644 | m_scene.SceneGraph.FireAttachToBackup(this); | ||
645 | |||
548 | if (InSceneBackup) | 646 | if (InSceneBackup) |
549 | { | 647 | { |
550 | //m_log.DebugFormat( | 648 | //m_log.DebugFormat( |
@@ -587,6 +685,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
587 | 685 | ||
588 | ApplyPhysics(m_scene.m_physicalPrim); | 686 | ApplyPhysics(m_scene.m_physicalPrim); |
589 | 687 | ||
688 | if (RootPart.PhysActor != null) | ||
689 | RootPart.Buoyancy = RootPart.Buoyancy; | ||
690 | |||
590 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled | 691 | // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled |
591 | // for the same object with very different properties. The caller must schedule the update. | 692 | // for the same object with very different properties. The caller must schedule the update. |
592 | //ScheduleGroupForFullUpdate(); | 693 | //ScheduleGroupForFullUpdate(); |
@@ -660,9 +761,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
660 | result.normal = inter.normal; | 761 | result.normal = inter.normal; |
661 | result.distance = inter.distance; | 762 | result.distance = inter.distance; |
662 | } | 763 | } |
764 | |||
663 | } | 765 | } |
664 | } | 766 | } |
665 | |||
666 | return result; | 767 | return result; |
667 | } | 768 | } |
668 | 769 | ||
@@ -682,17 +783,19 @@ namespace OpenSim.Region.Framework.Scenes | |||
682 | minZ = 8192f; | 783 | minZ = 8192f; |
683 | 784 | ||
684 | SceneObjectPart[] parts = m_parts.GetArray(); | 785 | SceneObjectPart[] parts = m_parts.GetArray(); |
685 | for (int i = 0; i < parts.Length; i++) | 786 | foreach (SceneObjectPart part in parts) |
686 | { | 787 | { |
687 | SceneObjectPart part = parts[i]; | ||
688 | |||
689 | Vector3 worldPos = part.GetWorldPosition(); | 788 | Vector3 worldPos = part.GetWorldPosition(); |
690 | Vector3 offset = worldPos - AbsolutePosition; | 789 | Vector3 offset = worldPos - AbsolutePosition; |
691 | Quaternion worldRot; | 790 | Quaternion worldRot; |
692 | if (part.ParentID == 0) | 791 | if (part.ParentID == 0) |
792 | { | ||
693 | worldRot = part.RotationOffset; | 793 | worldRot = part.RotationOffset; |
794 | } | ||
694 | else | 795 | else |
796 | { | ||
695 | worldRot = part.GetWorldRotation(); | 797 | worldRot = part.GetWorldRotation(); |
798 | } | ||
696 | 799 | ||
697 | Vector3 frontTopLeft; | 800 | Vector3 frontTopLeft; |
698 | Vector3 frontTopRight; | 801 | Vector3 frontTopRight; |
@@ -704,6 +807,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
704 | Vector3 backBottomLeft; | 807 | Vector3 backBottomLeft; |
705 | Vector3 backBottomRight; | 808 | Vector3 backBottomRight; |
706 | 809 | ||
810 | // Vector3[] corners = new Vector3[8]; | ||
811 | |||
707 | Vector3 orig = Vector3.Zero; | 812 | Vector3 orig = Vector3.Zero; |
708 | 813 | ||
709 | frontTopLeft.X = orig.X - (part.Scale.X / 2); | 814 | frontTopLeft.X = orig.X - (part.Scale.X / 2); |
@@ -738,6 +843,38 @@ namespace OpenSim.Region.Framework.Scenes | |||
738 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); | 843 | backBottomRight.Y = orig.Y + (part.Scale.Y / 2); |
739 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); | 844 | backBottomRight.Z = orig.Z - (part.Scale.Z / 2); |
740 | 845 | ||
846 | |||
847 | |||
848 | //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | ||
849 | //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | ||
850 | //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | ||
851 | //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); | ||
852 | //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); | ||
853 | //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); | ||
854 | //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); | ||
855 | //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); | ||
856 | |||
857 | //for (int i = 0; i < 8; i++) | ||
858 | //{ | ||
859 | // corners[i] = corners[i] * worldRot; | ||
860 | // corners[i] += offset; | ||
861 | |||
862 | // if (corners[i].X > maxX) | ||
863 | // maxX = corners[i].X; | ||
864 | // if (corners[i].X < minX) | ||
865 | // minX = corners[i].X; | ||
866 | |||
867 | // if (corners[i].Y > maxY) | ||
868 | // maxY = corners[i].Y; | ||
869 | // if (corners[i].Y < minY) | ||
870 | // minY = corners[i].Y; | ||
871 | |||
872 | // if (corners[i].Z > maxZ) | ||
873 | // maxZ = corners[i].Y; | ||
874 | // if (corners[i].Z < minZ) | ||
875 | // minZ = corners[i].Z; | ||
876 | //} | ||
877 | |||
741 | frontTopLeft = frontTopLeft * worldRot; | 878 | frontTopLeft = frontTopLeft * worldRot; |
742 | frontTopRight = frontTopRight * worldRot; | 879 | frontTopRight = frontTopRight * worldRot; |
743 | frontBottomLeft = frontBottomLeft * worldRot; | 880 | frontBottomLeft = frontBottomLeft * worldRot; |
@@ -759,6 +896,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
759 | backTopLeft += offset; | 896 | backTopLeft += offset; |
760 | backTopRight += offset; | 897 | backTopRight += offset; |
761 | 898 | ||
899 | //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z); | ||
900 | //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z); | ||
901 | //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z); | ||
902 | //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z); | ||
903 | //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z); | ||
904 | //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z); | ||
905 | //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z); | ||
906 | //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z); | ||
907 | |||
762 | if (frontTopRight.X > maxX) | 908 | if (frontTopRight.X > maxX) |
763 | maxX = frontTopRight.X; | 909 | maxX = frontTopRight.X; |
764 | if (frontTopLeft.X > maxX) | 910 | if (frontTopLeft.X > maxX) |
@@ -904,15 +1050,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
904 | 1050 | ||
905 | public void SaveScriptedState(XmlTextWriter writer) | 1051 | public void SaveScriptedState(XmlTextWriter writer) |
906 | { | 1052 | { |
1053 | SaveScriptedState(writer, false); | ||
1054 | } | ||
1055 | |||
1056 | public void SaveScriptedState(XmlTextWriter writer, bool oldIDs) | ||
1057 | { | ||
907 | XmlDocument doc = new XmlDocument(); | 1058 | XmlDocument doc = new XmlDocument(); |
908 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); | 1059 | Dictionary<UUID,string> states = new Dictionary<UUID,string>(); |
909 | 1060 | ||
910 | SceneObjectPart[] parts = m_parts.GetArray(); | 1061 | SceneObjectPart[] parts = m_parts.GetArray(); |
911 | for (int i = 0; i < parts.Length; i++) | 1062 | for (int i = 0; i < parts.Length; i++) |
912 | { | 1063 | { |
913 | Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); | 1064 | Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs); |
914 | foreach (KeyValuePair<UUID, string> kvp in pstates) | 1065 | foreach (KeyValuePair<UUID, string> kvp in pstates) |
915 | states.Add(kvp.Key, kvp.Value); | 1066 | states[kvp.Key] = kvp.Value; |
916 | } | 1067 | } |
917 | 1068 | ||
918 | if (states.Count > 0) | 1069 | if (states.Count > 0) |
@@ -931,6 +1082,118 @@ namespace OpenSim.Region.Framework.Scenes | |||
931 | } | 1082 | } |
932 | } | 1083 | } |
933 | 1084 | ||
1085 | /// <summary> | ||
1086 | /// Add the avatar to this linkset (avatar is sat). | ||
1087 | /// </summary> | ||
1088 | /// <param name="agentID"></param> | ||
1089 | public void AddAvatar(UUID agentID) | ||
1090 | { | ||
1091 | ScenePresence presence; | ||
1092 | if (m_scene.TryGetScenePresence(agentID, out presence)) | ||
1093 | { | ||
1094 | if (!m_linkedAvatars.Contains(presence)) | ||
1095 | { | ||
1096 | m_linkedAvatars.Add(presence); | ||
1097 | } | ||
1098 | } | ||
1099 | } | ||
1100 | |||
1101 | /// <summary> | ||
1102 | /// Delete the avatar from this linkset (avatar is unsat). | ||
1103 | /// </summary> | ||
1104 | /// <param name="agentID"></param> | ||
1105 | public void DeleteAvatar(UUID agentID) | ||
1106 | { | ||
1107 | ScenePresence presence; | ||
1108 | if (m_scene.TryGetScenePresence(agentID, out presence)) | ||
1109 | { | ||
1110 | if (m_linkedAvatars.Contains(presence)) | ||
1111 | { | ||
1112 | m_linkedAvatars.Remove(presence); | ||
1113 | } | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1117 | /// <summary> | ||
1118 | /// Returns the list of linked presences (avatars sat on this group) | ||
1119 | /// </summary> | ||
1120 | /// <param name="agentID"></param> | ||
1121 | public List<ScenePresence> GetLinkedAvatars() | ||
1122 | { | ||
1123 | return m_linkedAvatars; | ||
1124 | } | ||
1125 | |||
1126 | /// <summary> | ||
1127 | /// Attach this scene object to the given avatar. | ||
1128 | /// </summary> | ||
1129 | /// <param name="agentID"></param> | ||
1130 | /// <param name="attachmentpoint"></param> | ||
1131 | /// <param name="AttachOffset"></param> | ||
1132 | public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent) | ||
1133 | { | ||
1134 | ScenePresence avatar = m_scene.GetScenePresence(agentID); | ||
1135 | if (avatar != null) | ||
1136 | { | ||
1137 | // don't attach attachments to child agents | ||
1138 | if (avatar.IsChildAgent) return; | ||
1139 | |||
1140 | // m_log.DebugFormat("[SOG]: Adding attachment {0} to avatar {1}", Name, avatar.Name); | ||
1141 | |||
1142 | DetachFromBackup(); | ||
1143 | |||
1144 | // Remove from database and parcel prim count | ||
1145 | m_scene.DeleteFromStorage(UUID); | ||
1146 | m_scene.EventManager.TriggerParcelPrimCountTainted(); | ||
1147 | |||
1148 | m_rootPart.AttachedAvatar = agentID; | ||
1149 | |||
1150 | //Anakin Lohner bug #3839 | ||
1151 | lock (m_parts) | ||
1152 | { | ||
1153 | foreach (SceneObjectPart p in m_parts.GetArray()) | ||
1154 | { | ||
1155 | p.AttachedAvatar = agentID; | ||
1156 | } | ||
1157 | } | ||
1158 | |||
1159 | if (m_rootPart.PhysActor != null) | ||
1160 | { | ||
1161 | m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor); | ||
1162 | m_rootPart.PhysActor = null; | ||
1163 | } | ||
1164 | |||
1165 | AbsolutePosition = AttachOffset; | ||
1166 | m_rootPart.AttachedPos = AttachOffset; | ||
1167 | m_rootPart.IsAttachment = true; | ||
1168 | |||
1169 | m_rootPart.SetParentLocalId(avatar.LocalId); | ||
1170 | SetAttachmentPoint(Convert.ToByte(attachmentpoint)); | ||
1171 | |||
1172 | avatar.AddAttachment(this); | ||
1173 | |||
1174 | if (!silent) | ||
1175 | { | ||
1176 | // Killing it here will cause the client to deselect it | ||
1177 | // It then reappears on the avatar, deselected | ||
1178 | // through the full update below | ||
1179 | // | ||
1180 | if (IsSelected) | ||
1181 | { | ||
1182 | m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId }); | ||
1183 | } | ||
1184 | |||
1185 | IsSelected = false; // fudge.... | ||
1186 | ScheduleGroupForFullUpdate(); | ||
1187 | } | ||
1188 | } | ||
1189 | else | ||
1190 | { | ||
1191 | m_log.WarnFormat( | ||
1192 | "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present", | ||
1193 | UUID, agentID, Scene.RegionInfo.RegionName); | ||
1194 | } | ||
1195 | } | ||
1196 | |||
934 | public byte GetAttachmentPoint() | 1197 | public byte GetAttachmentPoint() |
935 | { | 1198 | { |
936 | return m_rootPart.Shape.State; | 1199 | return m_rootPart.Shape.State; |
@@ -1057,7 +1320,10 @@ namespace OpenSim.Region.Framework.Scenes | |||
1057 | public void AddPart(SceneObjectPart part) | 1320 | public void AddPart(SceneObjectPart part) |
1058 | { | 1321 | { |
1059 | part.SetParent(this); | 1322 | part.SetParent(this); |
1060 | part.LinkNum = m_parts.Add(part.UUID, part); | 1323 | m_parts.Add(part.UUID, part); |
1324 | |||
1325 | part.LinkNum = m_parts.Count; | ||
1326 | |||
1061 | if (part.LinkNum == 2 && RootPart != null) | 1327 | if (part.LinkNum == 2 && RootPart != null) |
1062 | RootPart.LinkNum = 1; | 1328 | RootPart.LinkNum = 1; |
1063 | } | 1329 | } |
@@ -1141,7 +1407,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1141 | 1407 | ||
1142 | public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) | 1408 | public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient) |
1143 | { | 1409 | { |
1144 | part.StoreUndoState(); | 1410 | part.StoreUndoState(UndoType.STATE_PRIM_ALL); |
1145 | part.OnGrab(offsetPos, remoteClient); | 1411 | part.OnGrab(offsetPos, remoteClient); |
1146 | } | 1412 | } |
1147 | 1413 | ||
@@ -1161,6 +1427,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1161 | /// <param name="silent">If true then deletion is not broadcast to clients</param> | 1427 | /// <param name="silent">If true then deletion is not broadcast to clients</param> |
1162 | public void DeleteGroupFromScene(bool silent) | 1428 | public void DeleteGroupFromScene(bool silent) |
1163 | { | 1429 | { |
1430 | // We need to keep track of this state in case this group is still queued for backup. | ||
1431 | m_isDeleted = true; | ||
1432 | |||
1433 | DetachFromBackup(); | ||
1434 | |||
1164 | SceneObjectPart[] parts = m_parts.GetArray(); | 1435 | SceneObjectPart[] parts = m_parts.GetArray(); |
1165 | for (int i = 0; i < parts.Length; i++) | 1436 | for (int i = 0; i < parts.Length; i++) |
1166 | { | 1437 | { |
@@ -1172,13 +1443,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1172 | avatar.StandUp(); | 1443 | avatar.StandUp(); |
1173 | 1444 | ||
1174 | if (!silent) | 1445 | if (!silent) |
1175 | { | ||
1176 | part.UpdateFlag = 0; | 1446 | part.UpdateFlag = 0; |
1177 | if (part == m_rootPart) | ||
1178 | avatar.ControllingClient.SendKillObject(m_regionHandle, part.LocalId); | ||
1179 | } | ||
1180 | }); | 1447 | }); |
1181 | } | 1448 | } |
1449 | |||
1450 | |||
1182 | } | 1451 | } |
1183 | 1452 | ||
1184 | public void AddScriptLPS(int count) | 1453 | public void AddScriptLPS(int count) |
@@ -1275,7 +1544,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
1275 | 1544 | ||
1276 | public void SetOwnerId(UUID userId) | 1545 | public void SetOwnerId(UUID userId) |
1277 | { | 1546 | { |
1278 | ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); | 1547 | ForEachPart(delegate(SceneObjectPart part) |
1548 | { | ||
1549 | |||
1550 | part.OwnerID = userId; | ||
1551 | |||
1552 | }); | ||
1279 | } | 1553 | } |
1280 | 1554 | ||
1281 | public void ForEachPart(Action<SceneObjectPart> whatToDo) | 1555 | public void ForEachPart(Action<SceneObjectPart> whatToDo) |
@@ -1307,11 +1581,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
1307 | return; | 1581 | return; |
1308 | } | 1582 | } |
1309 | 1583 | ||
1584 | if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0) | ||
1585 | return; | ||
1586 | |||
1310 | // Since this is the top of the section of call stack for backing up a particular scene object, don't let | 1587 | // Since this is the top of the section of call stack for backing up a particular scene object, don't let |
1311 | // any exception propogate upwards. | 1588 | // any exception propogate upwards. |
1312 | try | 1589 | try |
1313 | { | 1590 | { |
1314 | if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart | 1591 | if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart |
1592 | m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things | ||
1593 | m_scene.LoadingPrims) // Land may not be valid yet | ||
1594 | |||
1315 | { | 1595 | { |
1316 | ILandObject parcel = m_scene.LandChannel.GetLandObject( | 1596 | ILandObject parcel = m_scene.LandChannel.GetLandObject( |
1317 | m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); | 1597 | m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); |
@@ -1338,6 +1618,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1338 | } | 1618 | } |
1339 | } | 1619 | } |
1340 | } | 1620 | } |
1621 | |||
1341 | } | 1622 | } |
1342 | 1623 | ||
1343 | if (m_scene.UseBackup && HasGroupChanged) | 1624 | if (m_scene.UseBackup && HasGroupChanged) |
@@ -1345,6 +1626,20 @@ namespace OpenSim.Region.Framework.Scenes | |||
1345 | // don't backup while it's selected or you're asking for changes mid stream. | 1626 | // don't backup while it's selected or you're asking for changes mid stream. |
1346 | if (isTimeToPersist() || forcedBackup) | 1627 | if (isTimeToPersist() || forcedBackup) |
1347 | { | 1628 | { |
1629 | if (m_rootPart.PhysActor != null && | ||
1630 | (!m_rootPart.PhysActor.IsPhysical)) | ||
1631 | { | ||
1632 | // Possible ghost prim | ||
1633 | if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition) | ||
1634 | { | ||
1635 | foreach (SceneObjectPart part in m_parts.GetArray()) | ||
1636 | { | ||
1637 | // Re-set physics actor positions and | ||
1638 | // orientations | ||
1639 | part.GroupPosition = m_rootPart.GroupPosition; | ||
1640 | } | ||
1641 | } | ||
1642 | } | ||
1348 | // m_log.DebugFormat( | 1643 | // m_log.DebugFormat( |
1349 | // "[SCENE]: Storing {0}, {1} in {2}", | 1644 | // "[SCENE]: Storing {0}, {1} in {2}", |
1350 | // Name, UUID, m_scene.RegionInfo.RegionName); | 1645 | // Name, UUID, m_scene.RegionInfo.RegionName); |
@@ -1408,86 +1703,90 @@ namespace OpenSim.Region.Framework.Scenes | |||
1408 | /// <returns></returns> | 1703 | /// <returns></returns> |
1409 | public SceneObjectGroup Copy(bool userExposed) | 1704 | public SceneObjectGroup Copy(bool userExposed) |
1410 | { | 1705 | { |
1411 | SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); | 1706 | SceneObjectGroup dupe; |
1412 | dupe.m_isBackedUp = false; | 1707 | try |
1413 | dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); | 1708 | { |
1414 | 1709 | m_dupeInProgress = true; | |
1415 | // Warning, The following code related to previousAttachmentStatus is needed so that clones of | 1710 | dupe = (SceneObjectGroup)MemberwiseClone(); |
1416 | // attachments do not bordercross while they're being duplicated. This is hacktastic! | 1711 | dupe.m_isBackedUp = false; |
1417 | // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! | 1712 | dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); |
1418 | // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state | ||
1419 | // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, | ||
1420 | // then restore it's attachment state | ||
1421 | |||
1422 | // This is only necessary when userExposed is false! | ||
1423 | 1713 | ||
1424 | bool previousAttachmentStatus = dupe.RootPart.IsAttachment; | 1714 | // Warning, The following code related to previousAttachmentStatus is needed so that clones of |
1425 | 1715 | // attachments do not bordercross while they're being duplicated. This is hacktastic! | |
1426 | if (!userExposed) | 1716 | // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! |
1427 | dupe.RootPart.IsAttachment = true; | 1717 | // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state |
1718 | // (which should be false anyway) set it as an Attachment and then set it's Absolute Position, | ||
1719 | // then restore it's attachment state | ||
1428 | 1720 | ||
1429 | dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); | 1721 | // This is only necessary when userExposed is false! |
1430 | 1722 | ||
1431 | if (!userExposed) | 1723 | bool previousAttachmentStatus = dupe.RootPart.IsAttachment; |
1432 | { | ||
1433 | dupe.RootPart.IsAttachment = previousAttachmentStatus; | ||
1434 | } | ||
1435 | 1724 | ||
1436 | dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); | 1725 | if (!userExposed) |
1437 | dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; | 1726 | dupe.RootPart.IsAttachment = true; |
1438 | 1727 | ||
1439 | if (userExposed) | 1728 | dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z); |
1440 | dupe.m_rootPart.TrimPermissions(); | ||
1441 | 1729 | ||
1442 | List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); | 1730 | if (!userExposed) |
1443 | |||
1444 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) | ||
1445 | { | 1731 | { |
1446 | return p1.LinkNum.CompareTo(p2.LinkNum); | 1732 | dupe.RootPart.IsAttachment = previousAttachmentStatus; |
1447 | } | 1733 | } |
1448 | ); | ||
1449 | 1734 | ||
1450 | foreach (SceneObjectPart part in partList) | 1735 | dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); |
1451 | { | 1736 | dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; |
1452 | SceneObjectPart newPart; | 1737 | |
1453 | if (part.UUID != m_rootPart.UUID) | 1738 | if (userExposed) |
1739 | dupe.m_rootPart.TrimPermissions(); | ||
1740 | |||
1741 | List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); | ||
1742 | |||
1743 | partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) | ||
1744 | { | ||
1745 | return p1.LinkNum.CompareTo(p2.LinkNum); | ||
1746 | } | ||
1747 | ); | ||
1748 | |||
1749 | foreach (SceneObjectPart part in partList) | ||
1454 | { | 1750 | { |
1455 | newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); | 1751 | if (part.UUID != m_rootPart.UUID) |
1456 | newPart.LinkNum = part.LinkNum; | 1752 | { |
1753 | SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); | ||
1754 | |||
1755 | newPart.LinkNum = part.LinkNum; | ||
1756 | } | ||
1757 | |||
1758 | // Need to duplicate the physics actor as well | ||
1759 | if (part.PhysActor != null && userExposed) | ||
1760 | { | ||
1761 | PrimitiveBaseShape pbs = part.Shape; | ||
1762 | |||
1763 | part.PhysActor | ||
1764 | = m_scene.PhysicsScene.AddPrimShape( | ||
1765 | string.Format("{0}/{1}", part.Name, part.UUID), | ||
1766 | pbs, | ||
1767 | part.AbsolutePosition, | ||
1768 | part.Scale, | ||
1769 | part.RotationOffset, | ||
1770 | part.PhysActor.IsPhysical); | ||
1771 | part.PhysActor.SetMaterial((int)part.Material); | ||
1772 | |||
1773 | part.PhysActor.LocalID = part.LocalId; | ||
1774 | part.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); | ||
1775 | } | ||
1457 | } | 1776 | } |
1458 | else | 1777 | if (userExposed) |
1459 | { | 1778 | { |
1460 | newPart = dupe.m_rootPart; | 1779 | dupe.UpdateParentIDs(); |
1461 | } | 1780 | dupe.HasGroupChanged = true; |
1781 | dupe.AttachToBackup(); | ||
1462 | 1782 | ||
1463 | // Need to duplicate the physics actor as well | 1783 | ScheduleGroupForFullUpdate(); |
1464 | if (part.PhysActor != null && userExposed) | ||
1465 | { | ||
1466 | PrimitiveBaseShape pbs = part.Shape; | ||
1467 | |||
1468 | newPart.PhysActor | ||
1469 | = m_scene.PhysicsScene.AddPrimShape( | ||
1470 | part.LocalId, | ||
1471 | string.Format("{0}/{1}", part.Name, part.UUID), | ||
1472 | pbs, | ||
1473 | part.AbsolutePosition, | ||
1474 | part.Scale, | ||
1475 | part.RotationOffset, | ||
1476 | part.PhysActor.IsPhysical); | ||
1477 | |||
1478 | newPart.DoPhysicsPropertyUpdate(part.PhysActor.IsPhysical, true); | ||
1479 | } | 1784 | } |
1480 | } | 1785 | } |
1481 | 1786 | finally | |
1482 | if (userExposed) | ||
1483 | { | 1787 | { |
1484 | dupe.UpdateParentIDs(); | 1788 | m_dupeInProgress = false; |
1485 | dupe.HasGroupChanged = true; | ||
1486 | dupe.AttachToBackup(); | ||
1487 | |||
1488 | ScheduleGroupForFullUpdate(); | ||
1489 | } | 1789 | } |
1490 | |||
1491 | return dupe; | 1790 | return dupe; |
1492 | } | 1791 | } |
1493 | 1792 | ||
@@ -1632,6 +1931,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
1632 | return Vector3.Zero; | 1931 | return Vector3.Zero; |
1633 | } | 1932 | } |
1634 | 1933 | ||
1934 | // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object | ||
1635 | public void moveToTarget(Vector3 target, float tau) | 1935 | public void moveToTarget(Vector3 target, float tau) |
1636 | { | 1936 | { |
1637 | SceneObjectPart rootpart = m_rootPart; | 1937 | SceneObjectPart rootpart = m_rootPart; |
@@ -1671,20 +1971,55 @@ namespace OpenSim.Region.Framework.Scenes | |||
1671 | SceneObjectPart rootpart = m_rootPart; | 1971 | SceneObjectPart rootpart = m_rootPart; |
1672 | if (rootpart != null) | 1972 | if (rootpart != null) |
1673 | { | 1973 | { |
1674 | if (rootpart.PhysActor != null) | 1974 | if (IsAttachment) |
1675 | { | 1975 | { |
1676 | rootpart.PhysActor.PIDActive = false; | 1976 | ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar); |
1977 | if (avatar != null) avatar.StopMoveToPosition(); | ||
1978 | } | ||
1979 | else | ||
1980 | { | ||
1981 | if (rootpart.PhysActor != null) | ||
1982 | { | ||
1983 | rootpart.PhysActor.PIDActive = false; | ||
1984 | } | ||
1677 | } | 1985 | } |
1678 | } | 1986 | } |
1679 | } | 1987 | } |
1680 | 1988 | ||
1989 | public void rotLookAt(Quaternion target, float strength, float damping) | ||
1990 | { | ||
1991 | SceneObjectPart rootpart = m_rootPart; | ||
1992 | if (rootpart != null) | ||
1993 | { | ||
1994 | if (IsAttachment) | ||
1995 | { | ||
1996 | /* | ||
1997 | ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar); | ||
1998 | if (avatar != null) | ||
1999 | { | ||
2000 | Rotate the Av? | ||
2001 | } */ | ||
2002 | } | ||
2003 | else | ||
2004 | { | ||
2005 | if (rootpart.PhysActor != null) | ||
2006 | { // APID must be implemented in your physics system for this to function. | ||
2007 | rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W); | ||
2008 | rootpart.PhysActor.APIDStrength = strength; | ||
2009 | rootpart.PhysActor.APIDDamping = damping; | ||
2010 | rootpart.PhysActor.APIDActive = true; | ||
2011 | } | ||
2012 | } | ||
2013 | } | ||
2014 | } | ||
2015 | |||
1681 | public void stopLookAt() | 2016 | public void stopLookAt() |
1682 | { | 2017 | { |
1683 | SceneObjectPart rootpart = m_rootPart; | 2018 | SceneObjectPart rootpart = m_rootPart; |
1684 | if (rootpart != null) | 2019 | if (rootpart != null) |
1685 | { | 2020 | { |
1686 | if (rootpart.PhysActor != null) | 2021 | if (rootpart.PhysActor != null) |
1687 | { | 2022 | { // APID must be implemented in your physics system for this to function. |
1688 | rootpart.PhysActor.APIDActive = false; | 2023 | rootpart.PhysActor.APIDActive = false; |
1689 | } | 2024 | } |
1690 | } | 2025 | } |
@@ -1750,6 +2085,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
1750 | public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) | 2085 | public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) |
1751 | { | 2086 | { |
1752 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); | 2087 | SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); |
2088 | newPart.SetParent(this); | ||
2089 | |||
1753 | AddPart(newPart); | 2090 | AddPart(newPart); |
1754 | 2091 | ||
1755 | SetPartAsNonRoot(newPart); | 2092 | SetPartAsNonRoot(newPart); |
@@ -1898,11 +2235,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
1898 | /// Immediately send a full update for this scene object. | 2235 | /// Immediately send a full update for this scene object. |
1899 | /// </summary> | 2236 | /// </summary> |
1900 | public void SendGroupFullUpdate() | 2237 | public void SendGroupFullUpdate() |
1901 | { | 2238 | { |
1902 | if (IsDeleted) | 2239 | if (IsDeleted) |
1903 | return; | 2240 | return; |
1904 | 2241 | ||
1905 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); | 2242 | // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); |
1906 | 2243 | ||
1907 | RootPart.SendFullUpdateToAllClients(); | 2244 | RootPart.SendFullUpdateToAllClients(); |
1908 | 2245 | ||
@@ -2091,12 +2428,15 @@ namespace OpenSim.Region.Framework.Scenes | |||
2091 | part.LinkNum += objectGroup.PrimCount; | 2428 | part.LinkNum += objectGroup.PrimCount; |
2092 | } | 2429 | } |
2093 | } | 2430 | } |
2431 | } | ||
2094 | 2432 | ||
2095 | linkPart.LinkNum = 2; | 2433 | linkPart.LinkNum = 2; |
2096 | 2434 | ||
2097 | linkPart.SetParent(this); | 2435 | linkPart.SetParent(this); |
2098 | linkPart.CreateSelected = true; | 2436 | linkPart.CreateSelected = true; |
2099 | 2437 | ||
2438 | lock (m_parts.SyncRoot) | ||
2439 | { | ||
2100 | //if (linkPart.PhysActor != null) | 2440 | //if (linkPart.PhysActor != null) |
2101 | //{ | 2441 | //{ |
2102 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); | 2442 | // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor); |
@@ -2254,6 +2594,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2254 | /// <param name="objectGroup"></param> | 2594 | /// <param name="objectGroup"></param> |
2255 | public virtual void DetachFromBackup() | 2595 | public virtual void DetachFromBackup() |
2256 | { | 2596 | { |
2597 | m_scene.SceneGraph.FireDetachFromBackup(this); | ||
2598 | |||
2257 | if (m_isBackedUp) | 2599 | if (m_isBackedUp) |
2258 | m_scene.EventManager.OnBackup -= ProcessBackup; | 2600 | m_scene.EventManager.OnBackup -= ProcessBackup; |
2259 | 2601 | ||
@@ -2272,7 +2614,8 @@ namespace OpenSim.Region.Framework.Scenes | |||
2272 | 2614 | ||
2273 | axPos *= parentRot; | 2615 | axPos *= parentRot; |
2274 | part.OffsetPosition = axPos; | 2616 | part.OffsetPosition = axPos; |
2275 | part.GroupPosition = oldGroupPosition + part.OffsetPosition; | 2617 | Vector3 newPos = oldGroupPosition + part.OffsetPosition; |
2618 | part.GroupPosition = newPos; | ||
2276 | part.OffsetPosition = Vector3.Zero; | 2619 | part.OffsetPosition = Vector3.Zero; |
2277 | part.RotationOffset = worldRot; | 2620 | part.RotationOffset = worldRot; |
2278 | 2621 | ||
@@ -2283,7 +2626,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2283 | 2626 | ||
2284 | part.LinkNum = linkNum; | 2627 | part.LinkNum = linkNum; |
2285 | 2628 | ||
2286 | part.OffsetPosition = part.GroupPosition - AbsolutePosition; | 2629 | part.OffsetPosition = newPos - AbsolutePosition; |
2287 | 2630 | ||
2288 | Quaternion rootRotation = m_rootPart.RotationOffset; | 2631 | Quaternion rootRotation = m_rootPart.RotationOffset; |
2289 | 2632 | ||
@@ -2293,7 +2636,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2293 | 2636 | ||
2294 | parentRot = m_rootPart.RotationOffset; | 2637 | parentRot = m_rootPart.RotationOffset; |
2295 | oldRot = part.RotationOffset; | 2638 | oldRot = part.RotationOffset; |
2296 | Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; | 2639 | Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot; |
2297 | part.RotationOffset = newRot; | 2640 | part.RotationOffset = newRot; |
2298 | } | 2641 | } |
2299 | 2642 | ||
@@ -2544,8 +2887,12 @@ namespace OpenSim.Region.Framework.Scenes | |||
2544 | } | 2887 | } |
2545 | } | 2888 | } |
2546 | 2889 | ||
2890 | RootPart.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | ||
2547 | for (int i = 0; i < parts.Length; i++) | 2891 | for (int i = 0; i < parts.Length; i++) |
2548 | parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | 2892 | { |
2893 | if (parts[i] != RootPart) | ||
2894 | parts[i].UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect); | ||
2895 | } | ||
2549 | } | 2896 | } |
2550 | } | 2897 | } |
2551 | 2898 | ||
@@ -2558,6 +2905,17 @@ namespace OpenSim.Region.Framework.Scenes | |||
2558 | } | 2905 | } |
2559 | } | 2906 | } |
2560 | 2907 | ||
2908 | |||
2909 | |||
2910 | /// <summary> | ||
2911 | /// Gets the number of parts | ||
2912 | /// </summary> | ||
2913 | /// <returns></returns> | ||
2914 | public int GetPartCount() | ||
2915 | { | ||
2916 | return Parts.Count(); | ||
2917 | } | ||
2918 | |||
2561 | /// <summary> | 2919 | /// <summary> |
2562 | /// Update the texture entry for this part | 2920 | /// Update the texture entry for this part |
2563 | /// </summary> | 2921 | /// </summary> |
@@ -2619,11 +2977,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2619 | scale.Y = m_scene.m_maxNonphys; | 2977 | scale.Y = m_scene.m_maxNonphys; |
2620 | if (scale.Z > m_scene.m_maxNonphys) | 2978 | if (scale.Z > m_scene.m_maxNonphys) |
2621 | scale.Z = m_scene.m_maxNonphys; | 2979 | scale.Z = m_scene.m_maxNonphys; |
2622 | |||
2623 | SceneObjectPart part = GetChildPart(localID); | 2980 | SceneObjectPart part = GetChildPart(localID); |
2624 | if (part != null) | 2981 | if (part != null) |
2625 | { | 2982 | { |
2626 | part.Resize(scale); | ||
2627 | if (part.PhysActor != null) | 2983 | if (part.PhysActor != null) |
2628 | { | 2984 | { |
2629 | if (part.PhysActor.IsPhysical) | 2985 | if (part.PhysActor.IsPhysical) |
@@ -2638,7 +2994,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2638 | part.PhysActor.Size = scale; | 2994 | part.PhysActor.Size = scale; |
2639 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); | 2995 | m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor); |
2640 | } | 2996 | } |
2641 | //if (part.UUID != m_rootPart.UUID) | 2997 | part.Resize(scale); |
2642 | 2998 | ||
2643 | HasGroupChanged = true; | 2999 | HasGroupChanged = true; |
2644 | part.TriggerScriptChangedEvent(Changed.SCALE); | 3000 | part.TriggerScriptChangedEvent(Changed.SCALE); |
@@ -2661,7 +3017,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2661 | SceneObjectPart part = GetChildPart(localID); | 3017 | SceneObjectPart part = GetChildPart(localID); |
2662 | if (part != null) | 3018 | if (part != null) |
2663 | { | 3019 | { |
2664 | part.IgnoreUndoUpdate = true; | ||
2665 | if (scale.X > m_scene.m_maxNonphys) | 3020 | if (scale.X > m_scene.m_maxNonphys) |
2666 | scale.X = m_scene.m_maxNonphys; | 3021 | scale.X = m_scene.m_maxNonphys; |
2667 | if (scale.Y > m_scene.m_maxNonphys) | 3022 | if (scale.Y > m_scene.m_maxNonphys) |
@@ -2698,7 +3053,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2698 | 3053 | ||
2699 | if (part.PhysActor != null && part.PhysActor.IsPhysical) | 3054 | if (part.PhysActor != null && part.PhysActor.IsPhysical) |
2700 | { | 3055 | { |
2701 | if (oldSize.X * x > m_scene.m_maxPhys) | 3056 | if (oldSize.X*x > m_scene.m_maxPhys) |
2702 | { | 3057 | { |
2703 | f = m_scene.m_maxPhys / oldSize.X; | 3058 | f = m_scene.m_maxPhys / oldSize.X; |
2704 | a = f / x; | 3059 | a = f / x; |
@@ -2706,7 +3061,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2706 | y *= a; | 3061 | y *= a; |
2707 | z *= a; | 3062 | z *= a; |
2708 | } | 3063 | } |
2709 | if (oldSize.Y * y > m_scene.m_maxPhys) | 3064 | if (oldSize.Y*y > m_scene.m_maxPhys) |
2710 | { | 3065 | { |
2711 | f = m_scene.m_maxPhys / oldSize.Y; | 3066 | f = m_scene.m_maxPhys / oldSize.Y; |
2712 | a = f / y; | 3067 | a = f / y; |
@@ -2714,7 +3069,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2714 | y *= a; | 3069 | y *= a; |
2715 | z *= a; | 3070 | z *= a; |
2716 | } | 3071 | } |
2717 | if (oldSize.Z * z > m_scene.m_maxPhys) | 3072 | if (oldSize.Z*z > m_scene.m_maxPhys) |
2718 | { | 3073 | { |
2719 | f = m_scene.m_maxPhys / oldSize.Z; | 3074 | f = m_scene.m_maxPhys / oldSize.Z; |
2720 | a = f / z; | 3075 | a = f / z; |
@@ -2725,7 +3080,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2725 | } | 3080 | } |
2726 | else | 3081 | else |
2727 | { | 3082 | { |
2728 | if (oldSize.X * x > m_scene.m_maxNonphys) | 3083 | if (oldSize.X*x > m_scene.m_maxNonphys) |
2729 | { | 3084 | { |
2730 | f = m_scene.m_maxNonphys / oldSize.X; | 3085 | f = m_scene.m_maxNonphys / oldSize.X; |
2731 | a = f / x; | 3086 | a = f / x; |
@@ -2733,7 +3088,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2733 | y *= a; | 3088 | y *= a; |
2734 | z *= a; | 3089 | z *= a; |
2735 | } | 3090 | } |
2736 | if (oldSize.Y * y > m_scene.m_maxNonphys) | 3091 | if (oldSize.Y*y > m_scene.m_maxNonphys) |
2737 | { | 3092 | { |
2738 | f = m_scene.m_maxNonphys / oldSize.Y; | 3093 | f = m_scene.m_maxNonphys / oldSize.Y; |
2739 | a = f / y; | 3094 | a = f / y; |
@@ -2741,7 +3096,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2741 | y *= a; | 3096 | y *= a; |
2742 | z *= a; | 3097 | z *= a; |
2743 | } | 3098 | } |
2744 | if (oldSize.Z * z > m_scene.m_maxNonphys) | 3099 | if (oldSize.Z*z > m_scene.m_maxNonphys) |
2745 | { | 3100 | { |
2746 | f = m_scene.m_maxNonphys / oldSize.Z; | 3101 | f = m_scene.m_maxNonphys / oldSize.Z; |
2747 | a = f / z; | 3102 | a = f / z; |
@@ -2751,7 +3106,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2751 | } | 3106 | } |
2752 | } | 3107 | } |
2753 | obPart.IgnoreUndoUpdate = false; | 3108 | obPart.IgnoreUndoUpdate = false; |
2754 | obPart.StoreUndoState(); | ||
2755 | } | 3109 | } |
2756 | } | 3110 | } |
2757 | } | 3111 | } |
@@ -2759,8 +3113,13 @@ namespace OpenSim.Region.Framework.Scenes | |||
2759 | Vector3 prevScale = part.Scale; | 3113 | Vector3 prevScale = part.Scale; |
2760 | prevScale.X *= x; | 3114 | prevScale.X *= x; |
2761 | prevScale.Y *= y; | 3115 | prevScale.Y *= y; |
2762 | prevScale.Z *= z; | 3116 | prevScale.Z *= z;; |
3117 | |||
3118 | part.IgnoreUndoUpdate = false; | ||
3119 | part.StoreUndoState(UndoType.STATE_GROUP_SCALE); | ||
3120 | part.IgnoreUndoUpdate = true; | ||
2763 | part.Resize(prevScale); | 3121 | part.Resize(prevScale); |
3122 | part.IgnoreUndoUpdate = false; | ||
2764 | 3123 | ||
2765 | parts = m_parts.GetArray(); | 3124 | parts = m_parts.GetArray(); |
2766 | for (int i = 0; i < parts.Length; i++) | 3125 | for (int i = 0; i < parts.Length; i++) |
@@ -2769,19 +3128,26 @@ namespace OpenSim.Region.Framework.Scenes | |||
2769 | obPart.IgnoreUndoUpdate = true; | 3128 | obPart.IgnoreUndoUpdate = true; |
2770 | if (obPart.UUID != m_rootPart.UUID) | 3129 | if (obPart.UUID != m_rootPart.UUID) |
2771 | { | 3130 | { |
2772 | Vector3 currentpos = new Vector3(obPart.OffsetPosition); | 3131 | if (obPart.UUID != m_rootPart.UUID) |
2773 | currentpos.X *= x; | 3132 | { |
2774 | currentpos.Y *= y; | 3133 | obPart.IgnoreUndoUpdate = false; |
2775 | currentpos.Z *= z; | 3134 | obPart.StoreUndoState(UndoType.STATE_GROUP_SCALE); |
2776 | Vector3 newSize = new Vector3(obPart.Scale); | 3135 | obPart.IgnoreUndoUpdate = true; |
2777 | newSize.X *= x; | 3136 | |
2778 | newSize.Y *= y; | 3137 | Vector3 currentpos = new Vector3(obPart.OffsetPosition); |
2779 | newSize.Z *= z; | 3138 | currentpos.X *= x; |
2780 | obPart.Resize(newSize); | 3139 | currentpos.Y *= y; |
2781 | obPart.UpdateOffSet(currentpos); | 3140 | currentpos.Z *= z; |
3141 | Vector3 newSize = new Vector3(obPart.Scale); | ||
3142 | newSize.X *= x; | ||
3143 | newSize.Y *= y; | ||
3144 | newSize.Z *= z; | ||
3145 | obPart.Resize(newSize); | ||
3146 | obPart.UpdateOffSet(currentpos); | ||
3147 | } | ||
3148 | obPart.IgnoreUndoUpdate = false; | ||
2782 | } | 3149 | } |
2783 | obPart.IgnoreUndoUpdate = false; | 3150 | obPart.IgnoreUndoUpdate = false; |
2784 | obPart.StoreUndoState(); | ||
2785 | } | 3151 | } |
2786 | 3152 | ||
2787 | if (part.PhysActor != null) | 3153 | if (part.PhysActor != null) |
@@ -2791,7 +3157,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
2791 | } | 3157 | } |
2792 | 3158 | ||
2793 | part.IgnoreUndoUpdate = false; | 3159 | part.IgnoreUndoUpdate = false; |
2794 | part.StoreUndoState(); | ||
2795 | HasGroupChanged = true; | 3160 | HasGroupChanged = true; |
2796 | m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); | 3161 | m_rootPart.TriggerScriptChangedEvent(Changed.SCALE); |
2797 | ScheduleGroupForTerseUpdate(); | 3162 | ScheduleGroupForTerseUpdate(); |
@@ -2808,14 +3173,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
2808 | /// <param name="pos"></param> | 3173 | /// <param name="pos"></param> |
2809 | public void UpdateGroupPosition(Vector3 pos) | 3174 | public void UpdateGroupPosition(Vector3 pos) |
2810 | { | 3175 | { |
2811 | SceneObjectPart[] parts = m_parts.GetArray(); | ||
2812 | for (int i = 0; i < parts.Length; i++) | ||
2813 | parts[i].StoreUndoState(); | ||
2814 | |||
2815 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) | 3176 | if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) |
2816 | { | 3177 | { |
2817 | if (IsAttachment) | 3178 | if (IsAttachment) |
2818 | { | 3179 | { |
3180 | m_rootPart.StoreUndoState(UndoType.STATE_GROUP_POSITION); | ||
2819 | m_rootPart.AttachedPos = pos; | 3181 | m_rootPart.AttachedPos = pos; |
2820 | } | 3182 | } |
2821 | if (RootPart.GetStatusSandbox()) | 3183 | if (RootPart.GetStatusSandbox()) |
@@ -2849,7 +3211,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2849 | 3211 | ||
2850 | SceneObjectPart[] parts = m_parts.GetArray(); | 3212 | SceneObjectPart[] parts = m_parts.GetArray(); |
2851 | for (int i = 0; i < parts.Length; i++) | 3213 | for (int i = 0; i < parts.Length; i++) |
2852 | parts[i].StoreUndoState(); | 3214 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); |
2853 | 3215 | ||
2854 | if (part != null) | 3216 | if (part != null) |
2855 | { | 3217 | { |
@@ -2874,7 +3236,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2874 | { | 3236 | { |
2875 | SceneObjectPart[] parts = m_parts.GetArray(); | 3237 | SceneObjectPart[] parts = m_parts.GetArray(); |
2876 | for (int i = 0; i < parts.Length; i++) | 3238 | for (int i = 0; i < parts.Length; i++) |
2877 | parts[i].StoreUndoState(); | 3239 | parts[i].StoreUndoState(UndoType.STATE_PRIM_POSITION); |
2878 | 3240 | ||
2879 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); | 3241 | Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); |
2880 | Vector3 oldPos = | 3242 | Vector3 oldPos = |
@@ -2895,10 +3257,27 @@ namespace OpenSim.Region.Framework.Scenes | |||
2895 | obPart.OffsetPosition = obPart.OffsetPosition + diff; | 3257 | obPart.OffsetPosition = obPart.OffsetPosition + diff; |
2896 | } | 3258 | } |
2897 | 3259 | ||
2898 | AbsolutePosition = newPos; | 3260 | //We have to set undoing here because otherwise an undo state will be saved |
3261 | if (!m_rootPart.Undoing) | ||
3262 | { | ||
3263 | m_rootPart.Undoing = true; | ||
3264 | AbsolutePosition = newPos; | ||
3265 | m_rootPart.Undoing = false; | ||
3266 | } | ||
3267 | else | ||
3268 | { | ||
3269 | AbsolutePosition = newPos; | ||
3270 | } | ||
2899 | 3271 | ||
2900 | HasGroupChanged = true; | 3272 | HasGroupChanged = true; |
2901 | ScheduleGroupForTerseUpdate(); | 3273 | if (m_rootPart.Undoing) |
3274 | { | ||
3275 | ScheduleGroupForFullUpdate(); | ||
3276 | } | ||
3277 | else | ||
3278 | { | ||
3279 | ScheduleGroupForTerseUpdate(); | ||
3280 | } | ||
2902 | } | 3281 | } |
2903 | 3282 | ||
2904 | public void OffsetForNewRegion(Vector3 offset) | 3283 | public void OffsetForNewRegion(Vector3 offset) |
@@ -2918,7 +3297,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2918 | { | 3297 | { |
2919 | SceneObjectPart[] parts = m_parts.GetArray(); | 3298 | SceneObjectPart[] parts = m_parts.GetArray(); |
2920 | for (int i = 0; i < parts.Length; i++) | 3299 | for (int i = 0; i < parts.Length; i++) |
2921 | parts[i].StoreUndoState(); | 3300 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
2922 | 3301 | ||
2923 | m_rootPart.UpdateRotation(rot); | 3302 | m_rootPart.UpdateRotation(rot); |
2924 | 3303 | ||
@@ -2942,7 +3321,7 @@ namespace OpenSim.Region.Framework.Scenes | |||
2942 | { | 3321 | { |
2943 | SceneObjectPart[] parts = m_parts.GetArray(); | 3322 | SceneObjectPart[] parts = m_parts.GetArray(); |
2944 | for (int i = 0; i < parts.Length; i++) | 3323 | for (int i = 0; i < parts.Length; i++) |
2945 | parts[i].StoreUndoState(); | 3324 | parts[i].StoreUndoState(UndoType.STATE_GROUP_ROTATION); |
2946 | 3325 | ||
2947 | m_rootPart.UpdateRotation(rot); | 3326 | m_rootPart.UpdateRotation(rot); |
2948 | 3327 | ||
@@ -2967,10 +3346,9 @@ namespace OpenSim.Region.Framework.Scenes | |||
2967 | public void UpdateSingleRotation(Quaternion rot, uint localID) | 3346 | public void UpdateSingleRotation(Quaternion rot, uint localID) |
2968 | { | 3347 | { |
2969 | SceneObjectPart part = GetChildPart(localID); | 3348 | SceneObjectPart part = GetChildPart(localID); |
2970 | |||
2971 | SceneObjectPart[] parts = m_parts.GetArray(); | 3349 | SceneObjectPart[] parts = m_parts.GetArray(); |
2972 | for (int i = 0; i < parts.Length; i++) | 3350 | for (int i = 0; i < parts.Length; i++) |
2973 | parts[i].StoreUndoState(); | 3351 | parts[i].StoreUndoState(UndoType.STATE_PRIM_ROTATION); |
2974 | 3352 | ||
2975 | if (part != null) | 3353 | if (part != null) |
2976 | { | 3354 | { |
@@ -2998,15 +3376,24 @@ namespace OpenSim.Region.Framework.Scenes | |||
2998 | if (part.UUID == m_rootPart.UUID) | 3376 | if (part.UUID == m_rootPart.UUID) |
2999 | { | 3377 | { |
3000 | UpdateRootRotation(rot); | 3378 | UpdateRootRotation(rot); |
3001 | AbsolutePosition = pos; | 3379 | if (!m_rootPart.Undoing) |
3380 | { | ||
3381 | m_rootPart.Undoing = true; | ||
3382 | AbsolutePosition = pos; | ||
3383 | m_rootPart.Undoing = false; | ||
3384 | } | ||
3385 | else | ||
3386 | { | ||
3387 | AbsolutePosition = pos; | ||
3388 | } | ||
3002 | } | 3389 | } |
3003 | else | 3390 | else |
3004 | { | 3391 | { |
3392 | part.StoreUndoState(UndoType.STATE_PRIM_ROTATION); | ||
3005 | part.IgnoreUndoUpdate = true; | 3393 | part.IgnoreUndoUpdate = true; |
3006 | part.UpdateRotation(rot); | 3394 | part.UpdateRotation(rot); |
3007 | part.OffsetPosition = pos; | 3395 | part.OffsetPosition = pos; |
3008 | part.IgnoreUndoUpdate = false; | 3396 | part.IgnoreUndoUpdate = false; |
3009 | part.StoreUndoState(); | ||
3010 | } | 3397 | } |
3011 | } | 3398 | } |
3012 | } | 3399 | } |
@@ -3020,8 +3407,16 @@ namespace OpenSim.Region.Framework.Scenes | |||
3020 | Quaternion axRot = rot; | 3407 | Quaternion axRot = rot; |
3021 | Quaternion oldParentRot = m_rootPart.RotationOffset; | 3408 | Quaternion oldParentRot = m_rootPart.RotationOffset; |
3022 | 3409 | ||
3023 | m_rootPart.StoreUndoState(); | 3410 | m_rootPart.StoreUndoState(UndoType.STATE_PRIM_ROTATION); |
3024 | m_rootPart.UpdateRotation(rot); | 3411 | bool cancelUndo = false; |
3412 | if (!m_rootPart.Undoing) | ||
3413 | { | ||
3414 | m_rootPart.Undoing = true; | ||
3415 | cancelUndo = true; | ||
3416 | } | ||
3417 | |||
3418 | //Don't use UpdateRotation because it schedules an update prematurely | ||
3419 | m_rootPart.RotationOffset = rot; | ||
3025 | if (m_rootPart.PhysActor != null) | 3420 | if (m_rootPart.PhysActor != null) |
3026 | { | 3421 | { |
3027 | m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; | 3422 | m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset; |
@@ -3036,28 +3431,22 @@ namespace OpenSim.Region.Framework.Scenes | |||
3036 | { | 3431 | { |
3037 | prim.IgnoreUndoUpdate = true; | 3432 | prim.IgnoreUndoUpdate = true; |
3038 | Vector3 axPos = prim.OffsetPosition; | 3433 | Vector3 axPos = prim.OffsetPosition; |
3434 | |||
3039 | axPos *= oldParentRot; | 3435 | axPos *= oldParentRot; |
3040 | axPos *= Quaternion.Inverse(axRot); | 3436 | axPos *= Quaternion.Inverse(axRot); |
3041 | prim.OffsetPosition = axPos; | 3437 | prim.OffsetPosition = axPos; |
3042 | Quaternion primsRot = prim.RotationOffset; | 3438 | |
3043 | Quaternion newRot = primsRot * oldParentRot; | 3439 | prim.RotationOffset *= Quaternion.Inverse(prim.GetWorldRotation()) * (oldParentRot * prim.RotationOffset); |
3044 | newRot *= Quaternion.Inverse(axRot); | 3440 | |
3045 | prim.RotationOffset = newRot; | 3441 | prim.IgnoreUndoUpdate = false; |
3046 | prim.ScheduleTerseUpdate(); | ||
3047 | } | 3442 | } |
3048 | } | 3443 | } |
3049 | 3444 | if (cancelUndo == true) | |
3050 | for (int i = 0; i < parts.Length; i++) | ||
3051 | { | 3445 | { |
3052 | SceneObjectPart childpart = parts[i]; | 3446 | m_rootPart.Undoing = false; |
3053 | if (childpart != m_rootPart) | ||
3054 | { | ||
3055 | childpart.IgnoreUndoUpdate = false; | ||
3056 | childpart.StoreUndoState(); | ||
3057 | } | ||
3058 | } | 3447 | } |
3059 | 3448 | HasGroupChanged = true; | |
3060 | m_rootPart.ScheduleTerseUpdate(); | 3449 | ScheduleGroupForFullUpdate(); |
3061 | } | 3450 | } |
3062 | 3451 | ||
3063 | #endregion | 3452 | #endregion |
@@ -3280,7 +3669,6 @@ namespace OpenSim.Region.Framework.Scenes | |||
3280 | public float GetMass() | 3669 | public float GetMass() |
3281 | { | 3670 | { |
3282 | float retmass = 0f; | 3671 | float retmass = 0f; |
3283 | |||
3284 | SceneObjectPart[] parts = m_parts.GetArray(); | 3672 | SceneObjectPart[] parts = m_parts.GetArray(); |
3285 | for (int i = 0; i < parts.Length; i++) | 3673 | for (int i = 0; i < parts.Length; i++) |
3286 | retmass += parts[i].GetMass(); | 3674 | retmass += parts[i].GetMass(); |
@@ -3396,6 +3784,14 @@ namespace OpenSim.Region.Framework.Scenes | |||
3396 | SetFromItemID(uuid); | 3784 | SetFromItemID(uuid); |
3397 | } | 3785 | } |
3398 | 3786 | ||
3787 | public void ResetOwnerChangeFlag() | ||
3788 | { | ||
3789 | ForEachPart(delegate(SceneObjectPart part) | ||
3790 | { | ||
3791 | part.ResetOwnerChangeFlag(); | ||
3792 | }); | ||
3793 | } | ||
3794 | |||
3399 | #endregion | 3795 | #endregion |
3400 | } | 3796 | } |
3401 | } | 3797 | } |