aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs1237
1 files changed, 996 insertions, 241 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 9bd7632..2420048 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,12 +24,13 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.ComponentModel; 29using System.ComponentModel;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Drawing; 31using System.Drawing;
32using System.IO; 32using System.IO;
33using System.Diagnostics;
33using System.Linq; 34using System.Linq;
34using System.Threading; 35using System.Threading;
35using System.Xml; 36using System.Xml;
@@ -44,6 +45,7 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
44 45
45namespace OpenSim.Region.Framework.Scenes 46namespace OpenSim.Region.Framework.Scenes
46{ 47{
48
47 [Flags] 49 [Flags]
48 public enum scriptEvents 50 public enum scriptEvents
49 { 51 {
@@ -78,14 +80,14 @@ namespace OpenSim.Region.Framework.Scenes
78 object_rez = 4194304 80 object_rez = 4194304
79 } 81 }
80 82
81 struct scriptPosTarget 83 public struct scriptPosTarget
82 { 84 {
83 public Vector3 targetPos; 85 public Vector3 targetPos;
84 public float tolerance; 86 public float tolerance;
85 public uint handle; 87 public uint handle;
86 } 88 }
87 89
88 struct scriptRotTarget 90 public struct scriptRotTarget
89 { 91 {
90 public Quaternion targetRot; 92 public Quaternion targetRot;
91 public float tolerance; 93 public float tolerance;
@@ -119,8 +121,11 @@ namespace OpenSim.Region.Framework.Scenes
119 /// since the group's last persistent backup 121 /// since the group's last persistent backup
120 /// </summary> 122 /// </summary>
121 private bool m_hasGroupChanged = false; 123 private bool m_hasGroupChanged = false;
122 private long timeFirstChanged; 124 private long timeFirstChanged = 0;
123 private long timeLastChanged; 125 private long timeLastChanged = 0;
126 private long m_maxPersistTime = 0;
127 private long m_minPersistTime = 0;
128// private Random m_rand;
124 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>(); 129 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
125 130
126 /// <summary> 131 /// <summary>
@@ -138,9 +143,44 @@ namespace OpenSim.Region.Framework.Scenes
138 { 143 {
139 if (value) 144 if (value)
140 { 145 {
146
147 if (m_isBackedUp)
148 {
149 m_scene.SceneGraph.FireChangeBackup(this);
150 }
141 timeLastChanged = DateTime.Now.Ticks; 151 timeLastChanged = DateTime.Now.Ticks;
142 if (!m_hasGroupChanged) 152 if (!m_hasGroupChanged)
143 timeFirstChanged = DateTime.Now.Ticks; 153 timeFirstChanged = DateTime.Now.Ticks;
154 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
155 {
156/*
157 if (m_rand == null)
158 {
159 byte[] val = new byte[16];
160 m_rootPart.UUID.ToBytes(val, 0);
161 m_rand = new Random(BitConverter.ToInt32(val, 0));
162 }
163 */
164 if (m_scene.GetRootAgentCount() == 0)
165 {
166 //If the region is empty, this change has been made by an automated process
167 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
168
169// float factor = 1.5f + (float)(m_rand.NextDouble());
170 float factor = 2.0f;
171 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
172 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
173 }
174 else
175 {
176 //If the region is not empty, we want to obey the minimum and maximum persist times
177 //but add a random factor so we stagger the object persistance a little
178// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
179// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
180 m_maxPersistTime = m_scene.m_persistAfter;
181 m_minPersistTime = m_scene.m_dontPersistBefore;
182 }
183 }
144 } 184 }
145 m_hasGroupChanged = value; 185 m_hasGroupChanged = value;
146 186
@@ -155,7 +195,7 @@ namespace OpenSim.Region.Framework.Scenes
155 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 195 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
156 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 196 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
157 /// </summary> 197 /// </summary>
158 public bool HasGroupChangedDueToDelink { get; private set; } 198 public bool HasGroupChangedDueToDelink { get; set; }
159 199
160 private bool isTimeToPersist() 200 private bool isTimeToPersist()
161 { 201 {
@@ -165,8 +205,19 @@ namespace OpenSim.Region.Framework.Scenes
165 return false; 205 return false;
166 if (m_scene.ShuttingDown) 206 if (m_scene.ShuttingDown)
167 return true; 207 return true;
208
209 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
210 {
211 m_maxPersistTime = m_scene.m_persistAfter;
212 m_minPersistTime = m_scene.m_dontPersistBefore;
213 }
214
168 long currentTime = DateTime.Now.Ticks; 215 long currentTime = DateTime.Now.Ticks;
169 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 216
217 if (timeLastChanged == 0) timeLastChanged = currentTime;
218 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
219
220 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
170 return true; 221 return true;
171 return false; 222 return false;
172 } 223 }
@@ -224,6 +275,11 @@ namespace OpenSim.Region.Framework.Scenes
224 { 275 {
225 AttachmentPoint = 0; 276 AttachmentPoint = 0;
226 277
278 // Don't zap trees
279 if (RootPart.Shape.PCode == (byte)PCode.Tree ||
280 RootPart.Shape.PCode == (byte)PCode.NewTree)
281 return;
282
227 // Even though we don't use child part state parameters for attachments any more, we still need to set 283 // Even though we don't use child part state parameters for attachments any more, we still need to set
228 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if 284 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
229 // we store them correctly, scene objects that we receive from elsewhere might not. 285 // we store them correctly, scene objects that we receive from elsewhere might not.
@@ -269,26 +325,38 @@ namespace OpenSim.Region.Framework.Scenes
269 get { return RootPart.VolumeDetectActive; } 325 get { return RootPart.VolumeDetectActive; }
270 } 326 }
271 327
272 private Vector3 lastPhysGroupPos;
273 private Quaternion lastPhysGroupRot;
274
275 private bool m_isBackedUp; 328 private bool m_isBackedUp;
276 329
330 public bool IsBackedUp
331 {
332 get { return m_isBackedUp; }
333 }
334
277 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 335 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
278 336
279 protected ulong m_regionHandle; 337 protected ulong m_regionHandle;
280 protected SceneObjectPart m_rootPart; 338 protected SceneObjectPart m_rootPart;
281 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); 339 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
282 340
283 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); 341 private SortedDictionary<uint, scriptPosTarget> m_targets = new SortedDictionary<uint, scriptPosTarget>();
284 private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); 342 private SortedDictionary<uint, scriptRotTarget> m_rotTargets = new SortedDictionary<uint, scriptRotTarget>();
343
344 public SortedDictionary<uint, scriptPosTarget> AtTargets
345 {
346 get { return m_targets; }
347 }
348
349 public SortedDictionary<uint, scriptRotTarget> RotTargets
350 {
351 get { return m_rotTargets; }
352 }
285 353
286 private bool m_scriptListens_atTarget; 354 private bool m_scriptListens_atTarget;
287 private bool m_scriptListens_notAtTarget; 355 private bool m_scriptListens_notAtTarget;
288
289 private bool m_scriptListens_atRotTarget; 356 private bool m_scriptListens_atRotTarget;
290 private bool m_scriptListens_notAtRotTarget; 357 private bool m_scriptListens_notAtRotTarget;
291 358
359 public bool m_dupeInProgress = false;
292 internal Dictionary<UUID, string> m_savedScriptState; 360 internal Dictionary<UUID, string> m_savedScriptState;
293 361
294 #region Properties 362 #region Properties
@@ -325,6 +393,16 @@ namespace OpenSim.Region.Framework.Scenes
325 get { return m_parts.Count; } 393 get { return m_parts.Count; }
326 } 394 }
327 395
396// protected Quaternion m_rotation = Quaternion.Identity;
397//
398// public virtual Quaternion Rotation
399// {
400// get { return m_rotation; }
401// set {
402// m_rotation = value;
403// }
404// }
405
328 public Quaternion GroupRotation 406 public Quaternion GroupRotation
329 { 407 {
330 get { return m_rootPart.RotationOffset; } 408 get { return m_rootPart.RotationOffset; }
@@ -600,9 +678,38 @@ namespace OpenSim.Region.Framework.Scenes
600 // Restuff the new GroupPosition into each SOP of the linkset. 678 // Restuff the new GroupPosition into each SOP of the linkset.
601 // This has the affect of resetting and tainting the physics actors. 679 // This has the affect of resetting and tainting the physics actors.
602 SceneObjectPart[] parts = m_parts.GetArray(); 680 SceneObjectPart[] parts = m_parts.GetArray();
603 for (int i = 0; i < parts.Length; i++) 681 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
604 parts[i].GroupPosition = val; 682 if (m_dupeInProgress)
683 triggerScriptEvent = false;
684 foreach (SceneObjectPart part in parts)
685 {
686 part.GroupPosition = val;
687 if (triggerScriptEvent)
688 part.TriggerScriptChangedEvent(Changed.POSITION);
689 }
605 690
691/*
692 This seems not needed and should not be needed:
693 sp absolute position depends on sit part absolute position fixed above.
694 sp ParentPosition is not used anywhere.
695 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
696 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
697
698 if (!m_dupeInProgress)
699 {
700 foreach (ScenePresence av in m_linkedAvatars)
701 {
702 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
703 if (p != null && m_parts.TryGetValue(p.UUID, out p))
704 {
705 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
706 av.AbsolutePosition += offset;
707// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
708 av.SendAvatarDataToAllAgents();
709 }
710 }
711 }
712*/
606 //if (m_rootPart.PhysActor != null) 713 //if (m_rootPart.PhysActor != null)
607 //{ 714 //{
608 //m_rootPart.PhysActor.Position = 715 //m_rootPart.PhysActor.Position =
@@ -719,6 +826,11 @@ namespace OpenSim.Region.Framework.Scenes
719 m_isSelected = value; 826 m_isSelected = value;
720 // Tell physics engine that group is selected 827 // Tell physics engine that group is selected
721 828
829 // this is not right
830 // but ode engines should only really need to know about root part
831 // so they can put entire object simulation on hold and not colliding
832 // keep as was for now
833
722 PhysicsActor pa = m_rootPart.PhysActor; 834 PhysicsActor pa = m_rootPart.PhysActor;
723 if (pa != null) 835 if (pa != null)
724 { 836 {
@@ -740,6 +852,40 @@ namespace OpenSim.Region.Framework.Scenes
740 } 852 }
741 } 853 }
742 854
855 public void PartSelectChanged(bool partSelect)
856 {
857 // any part selected makes group selected
858 if (m_isSelected == partSelect)
859 return;
860
861 if (partSelect)
862 {
863 IsSelected = partSelect;
864// if (!IsAttachment)
865// ScheduleGroupForFullUpdate();
866 }
867 else
868 {
869 // bad bad bad 2 heavy for large linksets
870 // since viewer does send lot of (un)selects
871 // this needs to be replaced by a specific list or count ?
872 // but that will require extra code in several places
873
874 SceneObjectPart[] parts = m_parts.GetArray();
875 for (int i = 0; i < parts.Length; i++)
876 {
877 SceneObjectPart part = parts[i];
878 if (part.IsSelected)
879 return;
880 }
881 IsSelected = partSelect;
882 if (!IsAttachment)
883 {
884 ScheduleGroupForFullUpdate();
885 }
886 }
887 }
888
743 private SceneObjectPart m_PlaySoundMasterPrim = null; 889 private SceneObjectPart m_PlaySoundMasterPrim = null;
744 public SceneObjectPart PlaySoundMasterPrim 890 public SceneObjectPart PlaySoundMasterPrim
745 { 891 {
@@ -834,6 +980,7 @@ namespace OpenSim.Region.Framework.Scenes
834 /// </summary> 980 /// </summary>
835 public SceneObjectGroup() 981 public SceneObjectGroup()
836 { 982 {
983
837 } 984 }
838 985
839 /// <summary> 986 /// <summary>
@@ -851,8 +998,8 @@ namespace OpenSim.Region.Framework.Scenes
851 /// Constructor. This object is added to the scene later via AttachToScene() 998 /// Constructor. This object is added to the scene later via AttachToScene()
852 /// </summary> 999 /// </summary>
853 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 1000 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
854 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 1001 {
855 { 1002 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
856 } 1003 }
857 1004
858 /// <summary> 1005 /// <summary>
@@ -887,6 +1034,9 @@ namespace OpenSim.Region.Framework.Scenes
887 /// </summary> 1034 /// </summary>
888 public virtual void AttachToBackup() 1035 public virtual void AttachToBackup()
889 { 1036 {
1037 if (IsAttachment) return;
1038 m_scene.SceneGraph.FireAttachToBackup(this);
1039
890 if (InSceneBackup) 1040 if (InSceneBackup)
891 { 1041 {
892 //m_log.DebugFormat( 1042 //m_log.DebugFormat(
@@ -934,6 +1084,13 @@ namespace OpenSim.Region.Framework.Scenes
934 1084
935 ApplyPhysics(); 1085 ApplyPhysics();
936 1086
1087 if (RootPart.PhysActor != null)
1088 RootPart.Force = RootPart.Force;
1089 if (RootPart.PhysActor != null)
1090 RootPart.Torque = RootPart.Torque;
1091 if (RootPart.PhysActor != null)
1092 RootPart.Buoyancy = RootPart.Buoyancy;
1093
937 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1094 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
938 // for the same object with very different properties. The caller must schedule the update. 1095 // for the same object with very different properties. The caller must schedule the update.
939 //ScheduleGroupForFullUpdate(); 1096 //ScheduleGroupForFullUpdate();
@@ -949,6 +1106,10 @@ namespace OpenSim.Region.Framework.Scenes
949 EntityIntersection result = new EntityIntersection(); 1106 EntityIntersection result = new EntityIntersection();
950 1107
951 SceneObjectPart[] parts = m_parts.GetArray(); 1108 SceneObjectPart[] parts = m_parts.GetArray();
1109
1110 // Find closest hit here
1111 float idist = float.MaxValue;
1112
952 for (int i = 0; i < parts.Length; i++) 1113 for (int i = 0; i < parts.Length; i++)
953 { 1114 {
954 SceneObjectPart part = parts[i]; 1115 SceneObjectPart part = parts[i];
@@ -963,11 +1124,6 @@ namespace OpenSim.Region.Framework.Scenes
963 1124
964 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1125 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
965 1126
966 // This may need to be updated to the maximum draw distance possible..
967 // We might (and probably will) be checking for prim creation from other sims
968 // when the camera crosses the border.
969 float idist = Constants.RegionSize;
970
971 if (inter.HitTF) 1127 if (inter.HitTF)
972 { 1128 {
973 // We need to find the closest prim to return to the testcaller along the ray 1129 // We need to find the closest prim to return to the testcaller along the ray
@@ -978,10 +1134,11 @@ namespace OpenSim.Region.Framework.Scenes
978 result.obj = part; 1134 result.obj = part;
979 result.normal = inter.normal; 1135 result.normal = inter.normal;
980 result.distance = inter.distance; 1136 result.distance = inter.distance;
1137
1138 idist = inter.distance;
981 } 1139 }
982 } 1140 }
983 } 1141 }
984
985 return result; 1142 return result;
986 } 1143 }
987 1144
@@ -993,25 +1150,27 @@ namespace OpenSim.Region.Framework.Scenes
993 /// <returns></returns> 1150 /// <returns></returns>
994 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1151 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
995 { 1152 {
996 maxX = -256f; 1153 maxX = float.MinValue;
997 maxY = -256f; 1154 maxY = float.MinValue;
998 maxZ = -256f; 1155 maxZ = float.MinValue;
999 minX = 256f; 1156 minX = float.MaxValue;
1000 minY = 256f; 1157 minY = float.MaxValue;
1001 minZ = 8192f; 1158 minZ = float.MaxValue;
1002 1159
1003 SceneObjectPart[] parts = m_parts.GetArray(); 1160 SceneObjectPart[] parts = m_parts.GetArray();
1004 for (int i = 0; i < parts.Length; i++) 1161 foreach (SceneObjectPart part in parts)
1005 { 1162 {
1006 SceneObjectPart part = parts[i];
1007
1008 Vector3 worldPos = part.GetWorldPosition(); 1163 Vector3 worldPos = part.GetWorldPosition();
1009 Vector3 offset = worldPos - AbsolutePosition; 1164 Vector3 offset = worldPos - AbsolutePosition;
1010 Quaternion worldRot; 1165 Quaternion worldRot;
1011 if (part.ParentID == 0) 1166 if (part.ParentID == 0)
1167 {
1012 worldRot = part.RotationOffset; 1168 worldRot = part.RotationOffset;
1169 }
1013 else 1170 else
1171 {
1014 worldRot = part.GetWorldRotation(); 1172 worldRot = part.GetWorldRotation();
1173 }
1015 1174
1016 Vector3 frontTopLeft; 1175 Vector3 frontTopLeft;
1017 Vector3 frontTopRight; 1176 Vector3 frontTopRight;
@@ -1023,6 +1182,8 @@ namespace OpenSim.Region.Framework.Scenes
1023 Vector3 backBottomLeft; 1182 Vector3 backBottomLeft;
1024 Vector3 backBottomRight; 1183 Vector3 backBottomRight;
1025 1184
1185 // Vector3[] corners = new Vector3[8];
1186
1026 Vector3 orig = Vector3.Zero; 1187 Vector3 orig = Vector3.Zero;
1027 1188
1028 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1189 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -1057,6 +1218,38 @@ namespace OpenSim.Region.Framework.Scenes
1057 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1218 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
1058 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1219 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
1059 1220
1221
1222
1223 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1224 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1225 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1226 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1227 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1228 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1229 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1230 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1231
1232 //for (int i = 0; i < 8; i++)
1233 //{
1234 // corners[i] = corners[i] * worldRot;
1235 // corners[i] += offset;
1236
1237 // if (corners[i].X > maxX)
1238 // maxX = corners[i].X;
1239 // if (corners[i].X < minX)
1240 // minX = corners[i].X;
1241
1242 // if (corners[i].Y > maxY)
1243 // maxY = corners[i].Y;
1244 // if (corners[i].Y < minY)
1245 // minY = corners[i].Y;
1246
1247 // if (corners[i].Z > maxZ)
1248 // maxZ = corners[i].Y;
1249 // if (corners[i].Z < minZ)
1250 // minZ = corners[i].Z;
1251 //}
1252
1060 frontTopLeft = frontTopLeft * worldRot; 1253 frontTopLeft = frontTopLeft * worldRot;
1061 frontTopRight = frontTopRight * worldRot; 1254 frontTopRight = frontTopRight * worldRot;
1062 frontBottomLeft = frontBottomLeft * worldRot; 1255 frontBottomLeft = frontBottomLeft * worldRot;
@@ -1078,6 +1271,15 @@ namespace OpenSim.Region.Framework.Scenes
1078 backTopLeft += offset; 1271 backTopLeft += offset;
1079 backTopRight += offset; 1272 backTopRight += offset;
1080 1273
1274 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1275 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1276 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1277 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1278 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1279 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1280 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1281 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1282
1081 if (frontTopRight.X > maxX) 1283 if (frontTopRight.X > maxX)
1082 maxX = frontTopRight.X; 1284 maxX = frontTopRight.X;
1083 if (frontTopLeft.X > maxX) 1285 if (frontTopLeft.X > maxX)
@@ -1221,17 +1423,118 @@ namespace OpenSim.Region.Framework.Scenes
1221 1423
1222 #endregion 1424 #endregion
1223 1425
1426 public void GetResourcesCosts(SceneObjectPart apart,
1427 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1428 {
1429 // this information may need to be cached
1430
1431 float cost;
1432 float tmpcost;
1433
1434 bool ComplexCost = false;
1435
1436 SceneObjectPart p;
1437 SceneObjectPart[] parts;
1438
1439 lock (m_parts)
1440 {
1441 parts = m_parts.GetArray();
1442 }
1443
1444 int nparts = parts.Length;
1445
1446
1447 for (int i = 0; i < nparts; i++)
1448 {
1449 p = parts[i];
1450
1451 if (p.UsesComplexCost)
1452 {
1453 ComplexCost = true;
1454 break;
1455 }
1456 }
1457
1458 if (ComplexCost)
1459 {
1460 linksetResCost = 0;
1461 linksetPhysCost = 0;
1462 partCost = 0;
1463 partPhysCost = 0;
1464
1465 for (int i = 0; i < nparts; i++)
1466 {
1467 p = parts[i];
1468
1469 cost = p.StreamingCost;
1470 tmpcost = p.SimulationCost;
1471 if (tmpcost > cost)
1472 cost = tmpcost;
1473 tmpcost = p.PhysicsCost;
1474 if (tmpcost > cost)
1475 cost = tmpcost;
1476
1477 linksetPhysCost += tmpcost;
1478 linksetResCost += cost;
1479
1480 if (p == apart)
1481 {
1482 partCost = cost;
1483 partPhysCost = tmpcost;
1484 }
1485 }
1486 }
1487 else
1488 {
1489 partPhysCost = 1.0f;
1490 partCost = 1.0f;
1491 linksetResCost = (float)nparts;
1492 linksetPhysCost = linksetResCost;
1493 }
1494 }
1495
1496 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1497 {
1498 SceneObjectPart p;
1499 SceneObjectPart[] parts;
1500
1501 lock (m_parts)
1502 {
1503 parts = m_parts.GetArray();
1504 }
1505
1506 int nparts = parts.Length;
1507
1508 PhysCost = 0;
1509 StreamCost = 0;
1510 SimulCost = 0;
1511
1512 for (int i = 0; i < nparts; i++)
1513 {
1514 p = parts[i];
1515
1516 StreamCost += p.StreamingCost;
1517 SimulCost += p.SimulationCost;
1518 PhysCost += p.PhysicsCost;
1519 }
1520 }
1521
1224 public void SaveScriptedState(XmlTextWriter writer) 1522 public void SaveScriptedState(XmlTextWriter writer)
1225 { 1523 {
1524 SaveScriptedState(writer, false);
1525 }
1526
1527 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1528 {
1226 XmlDocument doc = new XmlDocument(); 1529 XmlDocument doc = new XmlDocument();
1227 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1530 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1228 1531
1229 SceneObjectPart[] parts = m_parts.GetArray(); 1532 SceneObjectPart[] parts = m_parts.GetArray();
1230 for (int i = 0; i < parts.Length; i++) 1533 for (int i = 0; i < parts.Length; i++)
1231 { 1534 {
1232 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1535 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1233 foreach (KeyValuePair<UUID, string> kvp in pstates) 1536 foreach (KeyValuePair<UUID, string> kvp in pstates)
1234 states.Add(kvp.Key, kvp.Value); 1537 states[kvp.Key] = kvp.Value;
1235 } 1538 }
1236 1539
1237 if (states.Count > 0) 1540 if (states.Count > 0)
@@ -1250,16 +1553,6 @@ namespace OpenSim.Region.Framework.Scenes
1250 } 1553 }
1251 } 1554 }
1252 1555
1253
1254 /// <summary>
1255 ///
1256 /// </summary>
1257 /// <param name="part"></param>
1258 private void SetPartAsNonRoot(SceneObjectPart part)
1259 {
1260 part.ParentID = m_rootPart.LocalId;
1261 part.ClearUndoState();
1262 }
1263 /// <summary> 1556 /// <summary>
1264 /// Add the avatar to this linkset (avatar is sat). 1557 /// Add the avatar to this linkset (avatar is sat).
1265 /// </summary> 1558 /// </summary>
@@ -1301,6 +1594,139 @@ namespace OpenSim.Region.Framework.Scenes
1301 return m_linkedAvatars; 1594 return m_linkedAvatars;
1302 } 1595 }
1303 1596
1597 /// <summary>
1598 /// Attach this scene object to the given avatar.
1599 /// </summary>
1600 /// <param name="agentID"></param>
1601 /// <param name="attachmentpoint"></param>
1602 /// <param name="AttachOffset"></param>
1603 private void AttachToAgent(
1604 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1605 {
1606 if (avatar != null)
1607 {
1608 // don't attach attachments to child agents
1609 if (avatar.IsChildAgent) return;
1610
1611 // Remove from database and parcel prim count
1612 m_scene.DeleteFromStorage(so.UUID);
1613 m_scene.EventManager.TriggerParcelPrimCountTainted();
1614
1615 so.AttachedAvatar = avatar.UUID;
1616
1617 if (so.RootPart.PhysActor != null)
1618 {
1619 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1620 so.RootPart.PhysActor = null;
1621 }
1622
1623 so.AbsolutePosition = attachOffset;
1624 so.RootPart.AttachedPos = attachOffset;
1625 so.IsAttachment = true;
1626 so.RootPart.SetParentLocalId(avatar.LocalId);
1627 so.AttachmentPoint = attachmentpoint;
1628
1629 avatar.AddAttachment(this);
1630
1631 if (!silent)
1632 {
1633 // Killing it here will cause the client to deselect it
1634 // It then reappears on the avatar, deselected
1635 // through the full update below
1636 //
1637 if (IsSelected)
1638 {
1639 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1640 }
1641
1642 IsSelected = false; // fudge....
1643 ScheduleGroupForFullUpdate();
1644 }
1645 }
1646 else
1647 {
1648 m_log.WarnFormat(
1649 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1650 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1651 }
1652 }
1653
1654 public byte GetAttachmentPoint()
1655 {
1656 return m_rootPart.Shape.State;
1657 }
1658
1659 public void DetachToGround()
1660 {
1661 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1662 if (avatar == null)
1663 return;
1664 m_rootPart.Shape.LastAttachPoint = m_rootPart.Shape.State;
1665 m_rootPart.AttachedPos = m_rootPart.OffsetPosition;
1666 avatar.RemoveAttachment(this);
1667
1668 Vector3 detachedpos = new Vector3(127f,127f,127f);
1669 if (avatar == null)
1670 return;
1671
1672 detachedpos = avatar.AbsolutePosition;
1673 FromItemID = UUID.Zero;
1674
1675 AbsolutePosition = detachedpos;
1676 AttachedAvatar = UUID.Zero;
1677
1678 //SceneObjectPart[] parts = m_parts.GetArray();
1679 //for (int i = 0; i < parts.Length; i++)
1680 // parts[i].AttachedAvatar = UUID.Zero;
1681
1682 m_rootPart.SetParentLocalId(0);
1683 AttachmentPoint = (byte)0;
1684 // must check if buildind should be true or false here
1685 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1686 HasGroupChanged = true;
1687 RootPart.Rezzed = DateTime.Now;
1688 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1689 AttachToBackup();
1690 m_scene.EventManager.TriggerParcelPrimCountTainted();
1691 m_rootPart.ScheduleFullUpdate();
1692 m_rootPart.ClearUndoState();
1693 }
1694
1695 public void DetachToInventoryPrep()
1696 {
1697 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1698 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1699 if (avatar != null)
1700 {
1701 //detachedpos = avatar.AbsolutePosition;
1702 avatar.RemoveAttachment(this);
1703 }
1704
1705 AttachedAvatar = UUID.Zero;
1706
1707 /*SceneObjectPart[] parts = m_parts.GetArray();
1708 for (int i = 0; i < parts.Length; i++)
1709 parts[i].AttachedAvatar = UUID.Zero;*/
1710
1711 m_rootPart.SetParentLocalId(0);
1712 //m_rootPart.SetAttachmentPoint((byte)0);
1713 IsAttachment = false;
1714 AbsolutePosition = m_rootPart.AttachedPos;
1715 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1716 //AttachToBackup();
1717 //m_rootPart.ScheduleFullUpdate();
1718 }
1719
1720 /// <summary>
1721 ///
1722 /// </summary>
1723 /// <param name="part"></param>
1724 private void SetPartAsNonRoot(SceneObjectPart part)
1725 {
1726 part.ParentID = m_rootPart.LocalId;
1727 part.ClearUndoState();
1728 }
1729
1304 public ushort GetTimeDilation() 1730 public ushort GetTimeDilation()
1305 { 1731 {
1306 return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); 1732 return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
@@ -1331,7 +1757,10 @@ namespace OpenSim.Region.Framework.Scenes
1331 public void AddPart(SceneObjectPart part) 1757 public void AddPart(SceneObjectPart part)
1332 { 1758 {
1333 part.SetParent(this); 1759 part.SetParent(this);
1334 part.LinkNum = m_parts.Add(part.UUID, part); 1760 m_parts.Add(part.UUID, part);
1761
1762 part.LinkNum = m_parts.Count;
1763
1335 if (part.LinkNum == 2) 1764 if (part.LinkNum == 2)
1336 RootPart.LinkNum = 1; 1765 RootPart.LinkNum = 1;
1337 } 1766 }
@@ -1357,6 +1786,14 @@ namespace OpenSim.Region.Framework.Scenes
1357 parts[i].UUID = UUID.Random(); 1786 parts[i].UUID = UUID.Random();
1358 } 1787 }
1359 1788
1789 // helper provided for parts.
1790 public int GetSceneMaxUndo()
1791 {
1792 if (m_scene != null)
1793 return m_scene.MaxUndoCount;
1794 return 5;
1795 }
1796
1360 // justincc: I don't believe this hack is needed any longer, especially since the physics 1797 // justincc: I don't believe this hack is needed any longer, especially since the physics
1361 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1798 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1362 // this method was preventing proper reload of scene objects. 1799 // this method was preventing proper reload of scene objects.
@@ -1414,7 +1851,7 @@ namespace OpenSim.Region.Framework.Scenes
1414// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1851// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1415// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1852// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1416 1853
1417 part.StoreUndoState(); 1854// part.StoreUndoState();
1418 part.OnGrab(offsetPos, remoteClient); 1855 part.OnGrab(offsetPos, remoteClient);
1419 } 1856 }
1420 1857
@@ -1434,6 +1871,11 @@ namespace OpenSim.Region.Framework.Scenes
1434 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1871 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1435 public void DeleteGroupFromScene(bool silent) 1872 public void DeleteGroupFromScene(bool silent)
1436 { 1873 {
1874 // We need to keep track of this state in case this group is still queued for backup.
1875 IsDeleted = true;
1876
1877 DetachFromBackup();
1878
1437 SceneObjectPart[] parts = m_parts.GetArray(); 1879 SceneObjectPart[] parts = m_parts.GetArray();
1438 for (int i = 0; i < parts.Length; i++) 1880 for (int i = 0; i < parts.Length; i++)
1439 { 1881 {
@@ -1457,6 +1899,7 @@ namespace OpenSim.Region.Framework.Scenes
1457 } 1899 }
1458 }); 1900 });
1459 } 1901 }
1902
1460 } 1903 }
1461 1904
1462 public void AddScriptLPS(int count) 1905 public void AddScriptLPS(int count)
@@ -1526,28 +1969,43 @@ namespace OpenSim.Region.Framework.Scenes
1526 /// </summary> 1969 /// </summary>
1527 public void ApplyPhysics() 1970 public void ApplyPhysics()
1528 { 1971 {
1529 // Apply physics to the root prim
1530 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1531
1532 // Apply physics to child prims
1533 SceneObjectPart[] parts = m_parts.GetArray(); 1972 SceneObjectPart[] parts = m_parts.GetArray();
1534 if (parts.Length > 1) 1973 if (parts.Length > 1)
1535 { 1974 {
1975 ResetChildPrimPhysicsPositions();
1976
1977 // Apply physics to the root prim
1978 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1979
1980
1536 for (int i = 0; i < parts.Length; i++) 1981 for (int i = 0; i < parts.Length; i++)
1537 { 1982 {
1538 SceneObjectPart part = parts[i]; 1983 SceneObjectPart part = parts[i];
1539 if (part.LocalId != m_rootPart.LocalId) 1984 if (part.LocalId != m_rootPart.LocalId)
1540 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1985 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1541 } 1986 }
1542
1543 // Hack to get the physics scene geometries in the right spot 1987 // Hack to get the physics scene geometries in the right spot
1544 ResetChildPrimPhysicsPositions(); 1988// ResetChildPrimPhysicsPositions();
1989 if (m_rootPart.PhysActor != null)
1990 {
1991 m_rootPart.PhysActor.Building = false;
1992 }
1993 }
1994 else
1995 {
1996 // Apply physics to the root prim
1997 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1545 } 1998 }
1546 } 1999 }
1547 2000
1548 public void SetOwnerId(UUID userId) 2001 public void SetOwnerId(UUID userId)
1549 { 2002 {
1550 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 2003 ForEachPart(delegate(SceneObjectPart part)
2004 {
2005
2006 part.OwnerID = userId;
2007
2008 });
1551 } 2009 }
1552 2010
1553 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2011 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1579,11 +2037,17 @@ namespace OpenSim.Region.Framework.Scenes
1579 return; 2037 return;
1580 } 2038 }
1581 2039
2040 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2041 return;
2042
1582 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2043 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1583 // any exception propogate upwards. 2044 // any exception propogate upwards.
1584 try 2045 try
1585 { 2046 {
1586 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2047 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2048 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2049 m_scene.LoadingPrims) // Land may not be valid yet
2050
1587 { 2051 {
1588 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2052 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1589 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2053 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1610,6 +2074,7 @@ namespace OpenSim.Region.Framework.Scenes
1610 } 2074 }
1611 } 2075 }
1612 } 2076 }
2077
1613 } 2078 }
1614 2079
1615 if (m_scene.UseBackup && HasGroupChanged) 2080 if (m_scene.UseBackup && HasGroupChanged)
@@ -1617,10 +2082,31 @@ namespace OpenSim.Region.Framework.Scenes
1617 // don't backup while it's selected or you're asking for changes mid stream. 2082 // don't backup while it's selected or you're asking for changes mid stream.
1618 if (isTimeToPersist() || forcedBackup) 2083 if (isTimeToPersist() || forcedBackup)
1619 { 2084 {
2085 if (m_rootPart.PhysActor != null &&
2086 (!m_rootPart.PhysActor.IsPhysical))
2087 {
2088 // Possible ghost prim
2089 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2090 {
2091 foreach (SceneObjectPart part in m_parts.GetArray())
2092 {
2093 // Re-set physics actor positions and
2094 // orientations
2095 part.GroupPosition = m_rootPart.GroupPosition;
2096 }
2097 }
2098 }
1620// m_log.DebugFormat( 2099// m_log.DebugFormat(
1621// "[SCENE]: Storing {0}, {1} in {2}", 2100// "[SCENE]: Storing {0}, {1} in {2}",
1622// Name, UUID, m_scene.RegionInfo.RegionName); 2101// Name, UUID, m_scene.RegionInfo.RegionName);
1623 2102
2103 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2104 {
2105 RootPart.Shape.LastAttachPoint = RootPart.Shape.State;
2106 RootPart.Shape.State = 0;
2107 ScheduleGroupForFullUpdate();
2108 }
2109
1624 SceneObjectGroup backup_group = Copy(false); 2110 SceneObjectGroup backup_group = Copy(false);
1625 backup_group.RootPart.Velocity = RootPart.Velocity; 2111 backup_group.RootPart.Velocity = RootPart.Velocity;
1626 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2112 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1630,6 +2116,16 @@ namespace OpenSim.Region.Framework.Scenes
1630 HasGroupChangedDueToDelink = false; 2116 HasGroupChangedDueToDelink = false;
1631 2117
1632 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2118 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2119/*
2120 backup_group.ForEachPart(delegate(SceneObjectPart part)
2121 {
2122 if (part.KeyframeMotion != null)
2123 {
2124 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2125// part.KeyframeMotion.UpdateSceneObject(this);
2126 }
2127 });
2128*/
1633 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2129 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1634 2130
1635 backup_group.ForEachPart(delegate(SceneObjectPart part) 2131 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1686,10 +2182,14 @@ namespace OpenSim.Region.Framework.Scenes
1686 /// <returns></returns> 2182 /// <returns></returns>
1687 public SceneObjectGroup Copy(bool userExposed) 2183 public SceneObjectGroup Copy(bool userExposed)
1688 { 2184 {
2185 m_dupeInProgress = true;
1689 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2186 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1690 dupe.m_isBackedUp = false; 2187 dupe.m_isBackedUp = false;
1691 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2188 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1692 2189
2190 // new group as no sitting avatars
2191 dupe.m_linkedAvatars = new List<ScenePresence>();
2192
1693 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2193 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1694 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2194 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1695 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2195 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1700,7 +2200,7 @@ namespace OpenSim.Region.Framework.Scenes
1700 // This is only necessary when userExposed is false! 2200 // This is only necessary when userExposed is false!
1701 2201
1702 bool previousAttachmentStatus = dupe.IsAttachment; 2202 bool previousAttachmentStatus = dupe.IsAttachment;
1703 2203
1704 if (!userExposed) 2204 if (!userExposed)
1705 dupe.IsAttachment = true; 2205 dupe.IsAttachment = true;
1706 2206
@@ -1713,16 +2213,17 @@ namespace OpenSim.Region.Framework.Scenes
1713 2213
1714 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2214 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1715 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2215 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2216
1716 2217
1717 if (userExposed) 2218 if (userExposed)
1718 dupe.m_rootPart.TrimPermissions(); 2219 dupe.m_rootPart.TrimPermissions();
1719 2220
1720 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2221 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1721 2222
1722 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2223 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1723 { 2224 {
1724 return p1.LinkNum.CompareTo(p2.LinkNum); 2225 return p1.LinkNum.CompareTo(p2.LinkNum);
1725 } 2226 }
1726 ); 2227 );
1727 2228
1728 foreach (SceneObjectPart part in partList) 2229 foreach (SceneObjectPart part in partList)
@@ -1732,43 +2233,56 @@ namespace OpenSim.Region.Framework.Scenes
1732 { 2233 {
1733 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2234 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1734 newPart.LinkNum = part.LinkNum; 2235 newPart.LinkNum = part.LinkNum;
1735 } 2236 if (userExposed)
2237 newPart.ParentID = dupe.m_rootPart.LocalId;
2238 }
1736 else 2239 else
1737 { 2240 {
1738 newPart = dupe.m_rootPart; 2241 newPart = dupe.m_rootPart;
1739 } 2242 }
2243/*
2244 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2245 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1740 2246
1741 // Need to duplicate the physics actor as well 2247 // Need to duplicate the physics actor as well
1742 PhysicsActor originalPartPa = part.PhysActor; 2248 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1743 if (originalPartPa != null && userExposed)
1744 { 2249 {
1745 PrimitiveBaseShape pbs = newPart.Shape; 2250 PrimitiveBaseShape pbs = newPart.Shape;
1746
1747 newPart.PhysActor 2251 newPart.PhysActor
1748 = m_scene.PhysicsScene.AddPrimShape( 2252 = m_scene.PhysicsScene.AddPrimShape(
1749 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2253 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1750 pbs, 2254 pbs,
1751 newPart.AbsolutePosition, 2255 newPart.AbsolutePosition,
1752 newPart.Scale, 2256 newPart.Scale,
1753 newPart.RotationOffset, 2257 newPart.GetWorldRotation(),
1754 originalPartPa.IsPhysical, 2258 isphys,
2259 isphan,
1755 newPart.LocalId); 2260 newPart.LocalId);
1756 2261
1757 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2262 newPart.DoPhysicsPropertyUpdate(isphys, true);
1758 } 2263 */
2264 if (userExposed)
2265 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2266// }
2267 // copy keyframemotion
1759 if (part.KeyframeMotion != null) 2268 if (part.KeyframeMotion != null)
1760 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); 2269 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1761 } 2270 }
1762 2271
1763 if (userExposed) 2272 if (userExposed)
1764 { 2273 {
1765 dupe.UpdateParentIDs(); 2274// done above dupe.UpdateParentIDs();
2275
2276 if (dupe.m_rootPart.PhysActor != null)
2277 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2278
1766 dupe.HasGroupChanged = true; 2279 dupe.HasGroupChanged = true;
1767 dupe.AttachToBackup(); 2280 dupe.AttachToBackup();
1768 2281
1769 ScheduleGroupForFullUpdate(); 2282 ScheduleGroupForFullUpdate();
1770 } 2283 }
1771 2284
2285 m_dupeInProgress = false;
1772 return dupe; 2286 return dupe;
1773 } 2287 }
1774 2288
@@ -1780,7 +2294,14 @@ namespace OpenSim.Region.Framework.Scenes
1780 /// <param name="cGroupID"></param> 2294 /// <param name="cGroupID"></param>
1781 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2295 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1782 { 2296 {
1783 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2297 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2298 // give newpart a new local ID lettng old part keep same
2299 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2300 newpart.LocalId = m_scene.AllocateLocalId();
2301
2302 SetRootPart(newpart);
2303 if (userExposed)
2304 RootPart.Velocity = Vector3.Zero; // In case source is moving
1784 } 2305 }
1785 2306
1786 public void ScriptSetPhysicsStatus(bool usePhysics) 2307 public void ScriptSetPhysicsStatus(bool usePhysics)
@@ -1838,13 +2359,14 @@ namespace OpenSim.Region.Framework.Scenes
1838 2359
1839 if (pa != null) 2360 if (pa != null)
1840 { 2361 {
1841 pa.AddForce(impulse, true); 2362 // false to be applied as a impulse
2363 pa.AddForce(impulse, false);
1842 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2364 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1843 } 2365 }
1844 } 2366 }
1845 } 2367 }
1846 2368
1847 public void applyAngularImpulse(Vector3 impulse) 2369 public void ApplyAngularImpulse(Vector3 impulse)
1848 { 2370 {
1849 PhysicsActor pa = RootPart.PhysActor; 2371 PhysicsActor pa = RootPart.PhysActor;
1850 2372
@@ -1852,21 +2374,8 @@ namespace OpenSim.Region.Framework.Scenes
1852 { 2374 {
1853 if (!IsAttachment) 2375 if (!IsAttachment)
1854 { 2376 {
1855 pa.AddAngularForce(impulse, true); 2377 // false to be applied as a impulse
1856 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2378 pa.AddAngularForce(impulse, false);
1857 }
1858 }
1859 }
1860
1861 public void setAngularImpulse(Vector3 impulse)
1862 {
1863 PhysicsActor pa = RootPart.PhysActor;
1864
1865 if (pa != null)
1866 {
1867 if (!IsAttachment)
1868 {
1869 pa.Torque = impulse;
1870 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2379 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1871 } 2380 }
1872 } 2381 }
@@ -1874,20 +2383,10 @@ namespace OpenSim.Region.Framework.Scenes
1874 2383
1875 public Vector3 GetTorque() 2384 public Vector3 GetTorque()
1876 { 2385 {
1877 PhysicsActor pa = RootPart.PhysActor; 2386 return RootPart.Torque;
1878
1879 if (pa != null)
1880 {
1881 if (!IsAttachment)
1882 {
1883 Vector3 torque = pa.Torque;
1884 return torque;
1885 }
1886 }
1887
1888 return Vector3.Zero;
1889 } 2387 }
1890 2388
2389 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1891 public void moveToTarget(Vector3 target, float tau) 2390 public void moveToTarget(Vector3 target, float tau)
1892 { 2391 {
1893 if (IsAttachment) 2392 if (IsAttachment)
@@ -1917,8 +2416,50 @@ namespace OpenSim.Region.Framework.Scenes
1917 2416
1918 if (pa != null) 2417 if (pa != null)
1919 pa.PIDActive = false; 2418 pa.PIDActive = false;
2419
2420 RootPart.ScheduleTerseUpdate(); // send a stop information
2421 }
2422
2423 public void rotLookAt(Quaternion target, float strength, float damping)
2424 {
2425 SceneObjectPart rootpart = m_rootPart;
2426 if (rootpart != null)
2427 {
2428 if (IsAttachment)
2429 {
2430 /*
2431 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2432 if (avatar != null)
2433 {
2434 Rotate the Av?
2435 } */
2436 }
2437 else
2438 {
2439 if (rootpart.PhysActor != null)
2440 { // APID must be implemented in your physics system for this to function.
2441 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2442 rootpart.PhysActor.APIDStrength = strength;
2443 rootpart.PhysActor.APIDDamping = damping;
2444 rootpart.PhysActor.APIDActive = true;
2445 }
2446 }
2447 }
1920 } 2448 }
2449
2450 public void stopLookAt()
2451 {
2452 SceneObjectPart rootpart = m_rootPart;
2453 if (rootpart != null)
2454 {
2455 if (rootpart.PhysActor != null)
2456 { // APID must be implemented in your physics system for this to function.
2457 rootpart.PhysActor.APIDActive = false;
2458 }
2459 }
1921 2460
2461 }
2462
1922 /// <summary> 2463 /// <summary>
1923 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2464 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1924 /// </summary> 2465 /// </summary>
@@ -1935,7 +2476,7 @@ namespace OpenSim.Region.Framework.Scenes
1935 { 2476 {
1936 pa.PIDHoverHeight = height; 2477 pa.PIDHoverHeight = height;
1937 pa.PIDHoverType = hoverType; 2478 pa.PIDHoverType = hoverType;
1938 pa.PIDTau = tau; 2479 pa.PIDHoverTau = tau;
1939 pa.PIDHoverActive = true; 2480 pa.PIDHoverActive = true;
1940 } 2481 }
1941 else 2482 else
@@ -1975,7 +2516,12 @@ namespace OpenSim.Region.Framework.Scenes
1975 /// <param name="cGroupID"></param> 2516 /// <param name="cGroupID"></param>
1976 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2517 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1977 { 2518 {
1978 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2519 // give new ID to the new part, letting old keep original
2520 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2521 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2522 newPart.LocalId = m_scene.AllocateLocalId();
2523 newPart.SetParent(this);
2524
1979 AddPart(newPart); 2525 AddPart(newPart);
1980 2526
1981 SetPartAsNonRoot(newPart); 2527 SetPartAsNonRoot(newPart);
@@ -2025,6 +2571,7 @@ namespace OpenSim.Region.Framework.Scenes
2025 2571
2026 #endregion 2572 #endregion
2027 2573
2574
2028 public override void Update() 2575 public override void Update()
2029 { 2576 {
2030 // Check that the group was not deleted before the scheduled update 2577 // Check that the group was not deleted before the scheduled update
@@ -2043,19 +2590,8 @@ namespace OpenSim.Region.Framework.Scenes
2043 // check to see if the physical position or rotation warrant an update. 2590 // check to see if the physical position or rotation warrant an update.
2044 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2591 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
2045 { 2592 {
2046 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2593 // rootpart SendScheduledUpdates will check if a update is needed
2047 2594 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2048 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
2049 {
2050 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2051 lastPhysGroupPos = AbsolutePosition;
2052 }
2053
2054 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
2055 {
2056 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2057 lastPhysGroupRot = GroupRotation;
2058 }
2059 } 2595 }
2060 2596
2061 SceneObjectPart[] parts = m_parts.GetArray(); 2597 SceneObjectPart[] parts = m_parts.GetArray();
@@ -2114,11 +2650,11 @@ namespace OpenSim.Region.Framework.Scenes
2114 /// Immediately send a full update for this scene object. 2650 /// Immediately send a full update for this scene object.
2115 /// </summary> 2651 /// </summary>
2116 public void SendGroupFullUpdate() 2652 public void SendGroupFullUpdate()
2117 { 2653 {
2118 if (IsDeleted) 2654 if (IsDeleted)
2119 return; 2655 return;
2120 2656
2121// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2657// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2122 2658
2123 RootPart.SendFullUpdateToAllClients(); 2659 RootPart.SendFullUpdateToAllClients();
2124 2660
@@ -2274,6 +2810,11 @@ namespace OpenSim.Region.Framework.Scenes
2274 // 'linkPart' == the root of the group being linked into this group 2810 // 'linkPart' == the root of the group being linked into this group
2275 SceneObjectPart linkPart = objectGroup.m_rootPart; 2811 SceneObjectPart linkPart = objectGroup.m_rootPart;
2276 2812
2813 if (m_rootPart.PhysActor != null)
2814 m_rootPart.PhysActor.Building = true;
2815 if (linkPart.PhysActor != null)
2816 linkPart.PhysActor.Building = true;
2817
2277 // physics flags from group to be applied to linked parts 2818 // physics flags from group to be applied to linked parts
2278 bool grpusephys = UsesPhysics; 2819 bool grpusephys = UsesPhysics;
2279 bool grptemporary = IsTemporary; 2820 bool grptemporary = IsTemporary;
@@ -2299,12 +2840,12 @@ namespace OpenSim.Region.Framework.Scenes
2299 Vector3 axPos = linkPart.OffsetPosition; 2840 Vector3 axPos = linkPart.OffsetPosition;
2300 // Rotate the linking root SOP's position to be relative to the new root prim 2841 // Rotate the linking root SOP's position to be relative to the new root prim
2301 Quaternion parentRot = m_rootPart.RotationOffset; 2842 Quaternion parentRot = m_rootPart.RotationOffset;
2302 axPos *= Quaternion.Inverse(parentRot); 2843 axPos *= Quaternion.Conjugate(parentRot);
2303 linkPart.OffsetPosition = axPos; 2844 linkPart.OffsetPosition = axPos;
2304 2845
2305 // Make the linking root SOP's rotation relative to the new root prim 2846 // Make the linking root SOP's rotation relative to the new root prim
2306 Quaternion oldRot = linkPart.RotationOffset; 2847 Quaternion oldRot = linkPart.RotationOffset;
2307 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2848 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2308 linkPart.RotationOffset = newRot; 2849 linkPart.RotationOffset = newRot;
2309 2850
2310 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2851 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2338,7 +2879,7 @@ namespace OpenSim.Region.Framework.Scenes
2338 linkPart.CreateSelected = true; 2879 linkPart.CreateSelected = true;
2339 2880
2340 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2881 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2341 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2882 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2342 2883
2343 // If the added SOP is physical, also tell the physics engine about the link relationship. 2884 // If the added SOP is physical, also tell the physics engine about the link relationship.
2344 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2885 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2348,6 +2889,7 @@ namespace OpenSim.Region.Framework.Scenes
2348 } 2889 }
2349 2890
2350 linkPart.LinkNum = linkNum++; 2891 linkPart.LinkNum = linkNum++;
2892 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2351 2893
2352 // Get a list of the SOP's in the old group in order of their linknum's. 2894 // Get a list of the SOP's in the old group in order of their linknum's.
2353 SceneObjectPart[] ogParts = objectGroup.Parts; 2895 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2366,7 +2908,7 @@ namespace OpenSim.Region.Framework.Scenes
2366 2908
2367 // Update the physics flags for the newly added SOP 2909 // Update the physics flags for the newly added SOP
2368 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2910 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2369 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2911 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2370 2912
2371 // If the added SOP is physical, also tell the physics engine about the link relationship. 2913 // If the added SOP is physical, also tell the physics engine about the link relationship.
2372 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2914 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2384,7 +2926,7 @@ namespace OpenSim.Region.Framework.Scenes
2384 objectGroup.IsDeleted = true; 2926 objectGroup.IsDeleted = true;
2385 2927
2386 objectGroup.m_parts.Clear(); 2928 objectGroup.m_parts.Clear();
2387 2929
2388 // Can't do this yet since backup still makes use of the root part without any synchronization 2930 // Can't do this yet since backup still makes use of the root part without any synchronization
2389// objectGroup.m_rootPart = null; 2931// objectGroup.m_rootPart = null;
2390 2932
@@ -2398,6 +2940,9 @@ namespace OpenSim.Region.Framework.Scenes
2398 // unmoved prims! 2940 // unmoved prims!
2399 ResetChildPrimPhysicsPositions(); 2941 ResetChildPrimPhysicsPositions();
2400 2942
2943 if (m_rootPart.PhysActor != null)
2944 m_rootPart.PhysActor.Building = false;
2945
2401 //HasGroupChanged = true; 2946 //HasGroupChanged = true;
2402 //ScheduleGroupForFullUpdate(); 2947 //ScheduleGroupForFullUpdate();
2403 } 2948 }
@@ -2465,7 +3010,10 @@ namespace OpenSim.Region.Framework.Scenes
2465// m_log.DebugFormat( 3010// m_log.DebugFormat(
2466// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3011// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2467// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3012// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2468 3013
3014 if (m_rootPart.PhysActor != null)
3015 m_rootPart.PhysActor.Building = true;
3016
2469 linkPart.ClearUndoState(); 3017 linkPart.ClearUndoState();
2470 3018
2471 Vector3 worldPos = linkPart.GetWorldPosition(); 3019 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2536,6 +3084,14 @@ namespace OpenSim.Region.Framework.Scenes
2536 3084
2537 // When we delete a group, we currently have to force persist to the database if the object id has changed 3085 // When we delete a group, we currently have to force persist to the database if the object id has changed
2538 // (since delete works by deleting all rows which have a given object id) 3086 // (since delete works by deleting all rows which have a given object id)
3087
3088 // this is as it seems to be in sl now
3089 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3090 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3091
3092 if (m_rootPart.PhysActor != null)
3093 m_rootPart.PhysActor.Building = false;
3094
2539 objectGroup.HasGroupChangedDueToDelink = true; 3095 objectGroup.HasGroupChangedDueToDelink = true;
2540 3096
2541 return objectGroup; 3097 return objectGroup;
@@ -2547,6 +3103,8 @@ namespace OpenSim.Region.Framework.Scenes
2547 /// <param name="objectGroup"></param> 3103 /// <param name="objectGroup"></param>
2548 public virtual void DetachFromBackup() 3104 public virtual void DetachFromBackup()
2549 { 3105 {
3106 if (m_scene != null)
3107 m_scene.SceneGraph.FireDetachFromBackup(this);
2550 if (m_isBackedUp && Scene != null) 3108 if (m_isBackedUp && Scene != null)
2551 m_scene.EventManager.OnBackup -= ProcessBackup; 3109 m_scene.EventManager.OnBackup -= ProcessBackup;
2552 3110
@@ -2567,7 +3125,8 @@ namespace OpenSim.Region.Framework.Scenes
2567 Vector3 axPos = part.OffsetPosition; 3125 Vector3 axPos = part.OffsetPosition;
2568 axPos *= parentRot; 3126 axPos *= parentRot;
2569 part.OffsetPosition = axPos; 3127 part.OffsetPosition = axPos;
2570 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3128 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3129 part.GroupPosition = newPos;
2571 part.OffsetPosition = Vector3.Zero; 3130 part.OffsetPosition = Vector3.Zero;
2572 3131
2573 // Compution our rotation to be not relative to the old parent 3132 // Compution our rotation to be not relative to the old parent
@@ -2582,7 +3141,7 @@ namespace OpenSim.Region.Framework.Scenes
2582 part.LinkNum = linkNum; 3141 part.LinkNum = linkNum;
2583 3142
2584 // Compute the new position of this SOP relative to the group position 3143 // Compute the new position of this SOP relative to the group position
2585 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3144 part.OffsetPosition = newPos - AbsolutePosition;
2586 3145
2587 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3146 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2588 // It would have the affect of setting the physics engine position multiple 3147 // It would have the affect of setting the physics engine position multiple
@@ -2592,18 +3151,19 @@ namespace OpenSim.Region.Framework.Scenes
2592 // Rotate the relative position by the rotation of the group 3151 // Rotate the relative position by the rotation of the group
2593 Quaternion rootRotation = m_rootPart.RotationOffset; 3152 Quaternion rootRotation = m_rootPart.RotationOffset;
2594 Vector3 pos = part.OffsetPosition; 3153 Vector3 pos = part.OffsetPosition;
2595 pos *= Quaternion.Inverse(rootRotation); 3154 pos *= Quaternion.Conjugate(rootRotation);
2596 part.OffsetPosition = pos; 3155 part.OffsetPosition = pos;
2597 3156
2598 // Compute the SOP's rotation relative to the rotation of the group. 3157 // Compute the SOP's rotation relative to the rotation of the group.
2599 parentRot = m_rootPart.RotationOffset; 3158 parentRot = m_rootPart.RotationOffset;
2600 oldRot = part.RotationOffset; 3159 oldRot = part.RotationOffset;
2601 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3160 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2602 part.RotationOffset = newRot; 3161 part.RotationOffset = newRot;
2603 3162
2604 // Since this SOP's state has changed, push those changes into the physics engine 3163 // Since this SOP's state has changed, push those changes into the physics engine
2605 // and the simulator. 3164 // and the simulator.
2606 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3165 // done on caller
3166// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2607 } 3167 }
2608 3168
2609 /// <summary> 3169 /// <summary>
@@ -2625,10 +3185,14 @@ namespace OpenSim.Region.Framework.Scenes
2625 { 3185 {
2626 if (!m_rootPart.BlockGrab) 3186 if (!m_rootPart.BlockGrab)
2627 { 3187 {
2628 Vector3 llmoveforce = pos - AbsolutePosition; 3188/* Vector3 llmoveforce = pos - AbsolutePosition;
2629 Vector3 grabforce = llmoveforce; 3189 Vector3 grabforce = llmoveforce;
2630 grabforce = (grabforce / 10) * pa.Mass; 3190 grabforce = (grabforce / 10) * pa.Mass;
2631 pa.AddForce(grabforce, true); 3191 */
3192 // empirically convert distance diference to a impulse
3193 Vector3 grabforce = pos - AbsolutePosition;
3194 grabforce = grabforce * (pa.Mass/ 10.0f);
3195 pa.AddForce(grabforce, false);
2632 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3196 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2633 } 3197 }
2634 } 3198 }
@@ -2824,6 +3388,8 @@ namespace OpenSim.Region.Framework.Scenes
2824 /// <param name="SetVolumeDetect"></param> 3388 /// <param name="SetVolumeDetect"></param>
2825 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3389 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2826 { 3390 {
3391 HasGroupChanged = true;
3392
2827 SceneObjectPart selectionPart = GetPart(localID); 3393 SceneObjectPart selectionPart = GetPart(localID);
2828 3394
2829 if (SetTemporary && Scene != null) 3395 if (SetTemporary && Scene != null)
@@ -2854,8 +3420,22 @@ namespace OpenSim.Region.Framework.Scenes
2854 } 3420 }
2855 } 3421 }
2856 3422
2857 for (int i = 0; i < parts.Length; i++) 3423 if (parts.Length > 1)
2858 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3424 {
3425 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3426
3427 for (int i = 0; i < parts.Length; i++)
3428 {
3429
3430 if (parts[i].UUID != m_rootPart.UUID)
3431 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3432 }
3433
3434 if (m_rootPart.PhysActor != null)
3435 m_rootPart.PhysActor.Building = false;
3436 }
3437 else
3438 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2859 } 3439 }
2860 } 3440 }
2861 3441
@@ -2868,6 +3448,17 @@ namespace OpenSim.Region.Framework.Scenes
2868 } 3448 }
2869 } 3449 }
2870 3450
3451
3452
3453 /// <summary>
3454 /// Gets the number of parts
3455 /// </summary>
3456 /// <returns></returns>
3457 public int GetPartCount()
3458 {
3459 return Parts.Count();
3460 }
3461
2871 /// <summary> 3462 /// <summary>
2872 /// Update the texture entry for this part 3463 /// Update the texture entry for this part
2873 /// </summary> 3464 /// </summary>
@@ -2905,8 +3496,24 @@ namespace OpenSim.Region.Framework.Scenes
2905 { 3496 {
2906 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3497 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2907 3498
3499 bool god = Scene.Permissions.IsGod(AgentID);
3500
3501 if (field == 1 && god)
3502 {
3503 ForEachPart(part =>
3504 {
3505 part.BaseMask = RootPart.BaseMask;
3506 });
3507 }
3508
2908 AdjustChildPrimPermissions(); 3509 AdjustChildPrimPermissions();
2909 3510
3511 if (field == 1 && god) // Base mask was set. Update all child part inventories
3512 {
3513 foreach (SceneObjectPart part in Parts)
3514 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3515 }
3516
2910 HasGroupChanged = true; 3517 HasGroupChanged = true;
2911 3518
2912 // Send the group's properties to all clients once all parts are updated 3519 // Send the group's properties to all clients once all parts are updated
@@ -2952,8 +3559,6 @@ namespace OpenSim.Region.Framework.Scenes
2952 3559
2953 PhysicsActor pa = m_rootPart.PhysActor; 3560 PhysicsActor pa = m_rootPart.PhysActor;
2954 3561
2955 RootPart.StoreUndoState(true);
2956
2957 if (Scene != null) 3562 if (Scene != null)
2958 { 3563 {
2959 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3564 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2981,7 +3586,6 @@ namespace OpenSim.Region.Framework.Scenes
2981 SceneObjectPart obPart = parts[i]; 3586 SceneObjectPart obPart = parts[i];
2982 if (obPart.UUID != m_rootPart.UUID) 3587 if (obPart.UUID != m_rootPart.UUID)
2983 { 3588 {
2984// obPart.IgnoreUndoUpdate = true;
2985 Vector3 oldSize = new Vector3(obPart.Scale); 3589 Vector3 oldSize = new Vector3(obPart.Scale);
2986 3590
2987 float f = 1.0f; 3591 float f = 1.0f;
@@ -3093,8 +3697,6 @@ namespace OpenSim.Region.Framework.Scenes
3093 z *= a; 3697 z *= a;
3094 } 3698 }
3095 } 3699 }
3096
3097// obPart.IgnoreUndoUpdate = false;
3098 } 3700 }
3099 } 3701 }
3100 } 3702 }
@@ -3104,9 +3706,7 @@ namespace OpenSim.Region.Framework.Scenes
3104 prevScale.Y *= y; 3706 prevScale.Y *= y;
3105 prevScale.Z *= z; 3707 prevScale.Z *= z;
3106 3708
3107// RootPart.IgnoreUndoUpdate = true;
3108 RootPart.Resize(prevScale); 3709 RootPart.Resize(prevScale);
3109// RootPart.IgnoreUndoUpdate = false;
3110 3710
3111 for (int i = 0; i < parts.Length; i++) 3711 for (int i = 0; i < parts.Length; i++)
3112 { 3712 {
@@ -3114,8 +3714,6 @@ namespace OpenSim.Region.Framework.Scenes
3114 3714
3115 if (obPart.UUID != m_rootPart.UUID) 3715 if (obPart.UUID != m_rootPart.UUID)
3116 { 3716 {
3117 obPart.IgnoreUndoUpdate = true;
3118
3119 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3717 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
3120 currentpos.X *= x; 3718 currentpos.X *= x;
3121 currentpos.Y *= y; 3719 currentpos.Y *= y;
@@ -3128,16 +3726,12 @@ namespace OpenSim.Region.Framework.Scenes
3128 3726
3129 obPart.Resize(newSize); 3727 obPart.Resize(newSize);
3130 obPart.UpdateOffSet(currentpos); 3728 obPart.UpdateOffSet(currentpos);
3131
3132 obPart.IgnoreUndoUpdate = false;
3133 } 3729 }
3134 3730
3135// obPart.IgnoreUndoUpdate = false; 3731 HasGroupChanged = true;
3136// obPart.StoreUndoState(); 3732 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3733 ScheduleGroupForTerseUpdate();
3137 } 3734 }
3138
3139// m_log.DebugFormat(
3140// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
3141 } 3735 }
3142 3736
3143 #endregion 3737 #endregion
@@ -3150,14 +3744,6 @@ namespace OpenSim.Region.Framework.Scenes
3150 /// <param name="pos"></param> 3744 /// <param name="pos"></param>
3151 public void UpdateGroupPosition(Vector3 pos) 3745 public void UpdateGroupPosition(Vector3 pos)
3152 { 3746 {
3153// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
3154
3155 RootPart.StoreUndoState(true);
3156
3157// SceneObjectPart[] parts = m_parts.GetArray();
3158// for (int i = 0; i < parts.Length; i++)
3159// parts[i].StoreUndoState();
3160
3161 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3747 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
3162 { 3748 {
3163 if (IsAttachment) 3749 if (IsAttachment)
@@ -3190,21 +3776,17 @@ namespace OpenSim.Region.Framework.Scenes
3190 /// </summary> 3776 /// </summary>
3191 /// <param name="pos"></param> 3777 /// <param name="pos"></param>
3192 /// <param name="localID"></param> 3778 /// <param name="localID"></param>
3779 ///
3780
3193 public void UpdateSinglePosition(Vector3 pos, uint localID) 3781 public void UpdateSinglePosition(Vector3 pos, uint localID)
3194 { 3782 {
3195 SceneObjectPart part = GetPart(localID); 3783 SceneObjectPart part = GetPart(localID);
3196 3784
3197// SceneObjectPart[] parts = m_parts.GetArray();
3198// for (int i = 0; i < parts.Length; i++)
3199// parts[i].StoreUndoState();
3200
3201 if (part != null) 3785 if (part != null)
3202 { 3786 {
3203// m_log.DebugFormat( 3787// unlock parts position change
3204// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3788 if (m_rootPart.PhysActor != null)
3205 3789 m_rootPart.PhysActor.Building = true;
3206 part.StoreUndoState(false);
3207 part.IgnoreUndoUpdate = true;
3208 3790
3209 if (part.UUID == m_rootPart.UUID) 3791 if (part.UUID == m_rootPart.UUID)
3210 { 3792 {
@@ -3215,8 +3797,10 @@ namespace OpenSim.Region.Framework.Scenes
3215 part.UpdateOffSet(pos); 3797 part.UpdateOffSet(pos);
3216 } 3798 }
3217 3799
3800 if (m_rootPart.PhysActor != null)
3801 m_rootPart.PhysActor.Building = false;
3802
3218 HasGroupChanged = true; 3803 HasGroupChanged = true;
3219 part.IgnoreUndoUpdate = false;
3220 } 3804 }
3221 } 3805 }
3222 3806
@@ -3226,13 +3810,7 @@ namespace OpenSim.Region.Framework.Scenes
3226 /// <param name="newPos"></param> 3810 /// <param name="newPos"></param>
3227 public void UpdateRootPosition(Vector3 newPos) 3811 public void UpdateRootPosition(Vector3 newPos)
3228 { 3812 {
3229// m_log.DebugFormat( 3813 // needs to be called with phys building true
3230// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3231
3232// SceneObjectPart[] parts = m_parts.GetArray();
3233// for (int i = 0; i < parts.Length; i++)
3234// parts[i].StoreUndoState();
3235
3236 Vector3 oldPos; 3814 Vector3 oldPos;
3237 3815
3238 if (IsAttachment) 3816 if (IsAttachment)
@@ -3258,7 +3836,14 @@ namespace OpenSim.Region.Framework.Scenes
3258 m_rootPart.AttachedPos = newPos; 3836 m_rootPart.AttachedPos = newPos;
3259 3837
3260 HasGroupChanged = true; 3838 HasGroupChanged = true;
3261 ScheduleGroupForTerseUpdate(); 3839 if (m_rootPart.Undoing)
3840 {
3841 ScheduleGroupForFullUpdate();
3842 }
3843 else
3844 {
3845 ScheduleGroupForTerseUpdate();
3846 }
3262 } 3847 }
3263 3848
3264 #endregion 3849 #endregion
@@ -3271,24 +3856,16 @@ namespace OpenSim.Region.Framework.Scenes
3271 /// <param name="rot"></param> 3856 /// <param name="rot"></param>
3272 public void UpdateGroupRotationR(Quaternion rot) 3857 public void UpdateGroupRotationR(Quaternion rot)
3273 { 3858 {
3274// m_log.DebugFormat(
3275// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3276
3277// SceneObjectPart[] parts = m_parts.GetArray();
3278// for (int i = 0; i < parts.Length; i++)
3279// parts[i].StoreUndoState();
3280
3281 m_rootPart.StoreUndoState(true);
3282
3283 m_rootPart.UpdateRotation(rot); 3859 m_rootPart.UpdateRotation(rot);
3284 3860
3861/* this is done by rootpart RotationOffset set called by UpdateRotation
3285 PhysicsActor actor = m_rootPart.PhysActor; 3862 PhysicsActor actor = m_rootPart.PhysActor;
3286 if (actor != null) 3863 if (actor != null)
3287 { 3864 {
3288 actor.Orientation = m_rootPart.RotationOffset; 3865 actor.Orientation = m_rootPart.RotationOffset;
3289 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3866 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3290 } 3867 }
3291 3868*/
3292 HasGroupChanged = true; 3869 HasGroupChanged = true;
3293 ScheduleGroupForTerseUpdate(); 3870 ScheduleGroupForTerseUpdate();
3294 } 3871 }
@@ -3300,16 +3877,6 @@ namespace OpenSim.Region.Framework.Scenes
3300 /// <param name="rot"></param> 3877 /// <param name="rot"></param>
3301 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3878 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3302 { 3879 {
3303// m_log.DebugFormat(
3304// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3305
3306// SceneObjectPart[] parts = m_parts.GetArray();
3307// for (int i = 0; i < parts.Length; i++)
3308// parts[i].StoreUndoState();
3309
3310 RootPart.StoreUndoState(true);
3311 RootPart.IgnoreUndoUpdate = true;
3312
3313 m_rootPart.UpdateRotation(rot); 3880 m_rootPart.UpdateRotation(rot);
3314 3881
3315 PhysicsActor actor = m_rootPart.PhysActor; 3882 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3328,8 +3895,6 @@ namespace OpenSim.Region.Framework.Scenes
3328 3895
3329 HasGroupChanged = true; 3896 HasGroupChanged = true;
3330 ScheduleGroupForTerseUpdate(); 3897 ScheduleGroupForTerseUpdate();
3331
3332 RootPart.IgnoreUndoUpdate = false;
3333 } 3898 }
3334 3899
3335 /// <summary> 3900 /// <summary>
@@ -3342,13 +3907,11 @@ namespace OpenSim.Region.Framework.Scenes
3342 SceneObjectPart part = GetPart(localID); 3907 SceneObjectPart part = GetPart(localID);
3343 3908
3344 SceneObjectPart[] parts = m_parts.GetArray(); 3909 SceneObjectPart[] parts = m_parts.GetArray();
3345 for (int i = 0; i < parts.Length; i++)
3346 parts[i].StoreUndoState();
3347 3910
3348 if (part != null) 3911 if (part != null)
3349 { 3912 {
3350// m_log.DebugFormat( 3913 if (m_rootPart.PhysActor != null)
3351// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3914 m_rootPart.PhysActor.Building = true;
3352 3915
3353 if (part.UUID == m_rootPart.UUID) 3916 if (part.UUID == m_rootPart.UUID)
3354 { 3917 {
@@ -3358,6 +3921,9 @@ namespace OpenSim.Region.Framework.Scenes
3358 { 3921 {
3359 part.UpdateRotation(rot); 3922 part.UpdateRotation(rot);
3360 } 3923 }
3924
3925 if (m_rootPart.PhysActor != null)
3926 m_rootPart.PhysActor.Building = false;
3361 } 3927 }
3362 } 3928 }
3363 3929
@@ -3371,12 +3937,8 @@ namespace OpenSim.Region.Framework.Scenes
3371 SceneObjectPart part = GetPart(localID); 3937 SceneObjectPart part = GetPart(localID);
3372 if (part != null) 3938 if (part != null)
3373 { 3939 {
3374// m_log.DebugFormat( 3940 if (m_rootPart.PhysActor != null)
3375// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3941 m_rootPart.PhysActor.Building = true;
3376// part.Name, part.LocalId, rot);
3377
3378 part.StoreUndoState();
3379 part.IgnoreUndoUpdate = true;
3380 3942
3381 if (part.UUID == m_rootPart.UUID) 3943 if (part.UUID == m_rootPart.UUID)
3382 { 3944 {
@@ -3389,7 +3951,8 @@ namespace OpenSim.Region.Framework.Scenes
3389 part.OffsetPosition = pos; 3951 part.OffsetPosition = pos;
3390 } 3952 }
3391 3953
3392 part.IgnoreUndoUpdate = false; 3954 if (m_rootPart.PhysActor != null)
3955 m_rootPart.PhysActor.Building = false;
3393 } 3956 }
3394 } 3957 }
3395 3958
@@ -3399,15 +3962,12 @@ namespace OpenSim.Region.Framework.Scenes
3399 /// <param name="rot"></param> 3962 /// <param name="rot"></param>
3400 public void UpdateRootRotation(Quaternion rot) 3963 public void UpdateRootRotation(Quaternion rot)
3401 { 3964 {
3402// m_log.DebugFormat( 3965 // needs to be called with phys building true
3403// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3404// Name, LocalId, rot);
3405
3406 Quaternion axRot = rot; 3966 Quaternion axRot = rot;
3407 Quaternion oldParentRot = m_rootPart.RotationOffset; 3967 Quaternion oldParentRot = m_rootPart.RotationOffset;
3408 3968
3409 m_rootPart.StoreUndoState(); 3969 //Don't use UpdateRotation because it schedules an update prematurely
3410 m_rootPart.UpdateRotation(rot); 3970 m_rootPart.RotationOffset = rot;
3411 3971
3412 PhysicsActor pa = m_rootPart.PhysActor; 3972 PhysicsActor pa = m_rootPart.PhysActor;
3413 3973
@@ -3423,35 +3983,145 @@ namespace OpenSim.Region.Framework.Scenes
3423 SceneObjectPart prim = parts[i]; 3983 SceneObjectPart prim = parts[i];
3424 if (prim.UUID != m_rootPart.UUID) 3984 if (prim.UUID != m_rootPart.UUID)
3425 { 3985 {
3426 prim.IgnoreUndoUpdate = true; 3986 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3987 NewRot = Quaternion.Inverse(axRot) * NewRot;
3988 prim.RotationOffset = NewRot;
3989
3427 Vector3 axPos = prim.OffsetPosition; 3990 Vector3 axPos = prim.OffsetPosition;
3991
3428 axPos *= oldParentRot; 3992 axPos *= oldParentRot;
3429 axPos *= Quaternion.Inverse(axRot); 3993 axPos *= Quaternion.Inverse(axRot);
3430 prim.OffsetPosition = axPos; 3994 prim.OffsetPosition = axPos;
3431 Quaternion primsRot = prim.RotationOffset; 3995 }
3432 Quaternion newRot = oldParentRot * primsRot; 3996 }
3433 newRot = Quaternion.Inverse(axRot) * newRot;
3434 prim.RotationOffset = newRot;
3435 prim.ScheduleTerseUpdate();
3436 prim.IgnoreUndoUpdate = false;
3437 }
3438 }
3439
3440// for (int i = 0; i < parts.Length; i++)
3441// {
3442// SceneObjectPart childpart = parts[i];
3443// if (childpart != m_rootPart)
3444// {
3445//// childpart.IgnoreUndoUpdate = false;
3446//// childpart.StoreUndoState();
3447// }
3448// }
3449 3997
3450 m_rootPart.ScheduleTerseUpdate(); 3998 HasGroupChanged = true;
3999 ScheduleGroupForFullUpdate();
4000 }
3451 4001
3452// m_log.DebugFormat( 4002 private enum updatetype :int
3453// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 4003 {
3454// Name, LocalId, rot); 4004 none = 0,
4005 partterse = 1,
4006 partfull = 2,
4007 groupterse = 3,
4008 groupfull = 4
4009 }
4010
4011 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
4012 {
4013 // TODO this still as excessive *.Schedule*Update()s
4014
4015 if (part != null && part.ParentGroup != null)
4016 {
4017 ObjectChangeType change = data.change;
4018 bool togroup = ((change & ObjectChangeType.Group) != 0);
4019 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4020
4021 SceneObjectGroup group = part.ParentGroup;
4022 PhysicsActor pha = group.RootPart.PhysActor;
4023
4024 updatetype updateType = updatetype.none;
4025
4026 if (togroup)
4027 {
4028 // related to group
4029 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4030 {
4031 if ((change & ObjectChangeType.Rotation) != 0)
4032 {
4033 group.RootPart.UpdateRotation(data.rotation);
4034 updateType = updatetype.none;
4035 }
4036 if ((change & ObjectChangeType.Position) != 0)
4037 {
4038 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4039 UpdateGroupPosition(data.position);
4040 updateType = updatetype.groupterse;
4041 }
4042 else
4043 // ugly rotation update of all parts
4044 {
4045 group.ResetChildPrimPhysicsPositions();
4046 }
4047
4048 }
4049 if ((change & ObjectChangeType.Scale) != 0)
4050 {
4051 if (pha != null)
4052 pha.Building = true;
4053
4054 group.GroupResize(data.scale);
4055 updateType = updatetype.none;
4056
4057 if (pha != null)
4058 pha.Building = false;
4059 }
4060 }
4061 else
4062 {
4063 // related to single prim in a link-set ( ie group)
4064 if (pha != null)
4065 pha.Building = true;
4066
4067 // root part is special
4068 // parts offset positions or rotations need to change also
4069
4070 if (part == group.RootPart)
4071 {
4072 if ((change & ObjectChangeType.Rotation) != 0)
4073 group.UpdateRootRotation(data.rotation);
4074 if ((change & ObjectChangeType.Position) != 0)
4075 group.UpdateRootPosition(data.position);
4076 if ((change & ObjectChangeType.Scale) != 0)
4077 part.Resize(data.scale);
4078 }
4079 else
4080 {
4081 if ((change & ObjectChangeType.Position) != 0)
4082 {
4083 part.OffsetPosition = data.position;
4084 updateType = updatetype.partterse;
4085 }
4086 if ((change & ObjectChangeType.Rotation) != 0)
4087 {
4088 part.UpdateRotation(data.rotation);
4089 updateType = updatetype.none;
4090 }
4091 if ((change & ObjectChangeType.Scale) != 0)
4092 {
4093 part.Resize(data.scale);
4094 updateType = updatetype.none;
4095 }
4096 }
4097
4098 if (pha != null)
4099 pha.Building = false;
4100 }
4101
4102 if (updateType != updatetype.none)
4103 {
4104 group.HasGroupChanged = true;
4105
4106 switch (updateType)
4107 {
4108 case updatetype.partterse:
4109 part.ScheduleTerseUpdate();
4110 break;
4111 case updatetype.partfull:
4112 part.ScheduleFullUpdate();
4113 break;
4114 case updatetype.groupterse:
4115 group.ScheduleGroupForTerseUpdate();
4116 break;
4117 case updatetype.groupfull:
4118 group.ScheduleGroupForFullUpdate();
4119 break;
4120 default:
4121 break;
4122 }
4123 }
4124 }
3455 } 4125 }
3456 4126
3457 #endregion 4127 #endregion
@@ -3492,6 +4162,8 @@ namespace OpenSim.Region.Framework.Scenes
3492 waypoint.handle = handle; 4162 waypoint.handle = handle;
3493 lock (m_rotTargets) 4163 lock (m_rotTargets)
3494 { 4164 {
4165 if (m_rotTargets.Count >= 8)
4166 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3495 m_rotTargets.Add(handle, waypoint); 4167 m_rotTargets.Add(handle, waypoint);
3496 } 4168 }
3497 m_scene.AddGroupTarget(this); 4169 m_scene.AddGroupTarget(this);
@@ -3517,6 +4189,8 @@ namespace OpenSim.Region.Framework.Scenes
3517 waypoint.handle = handle; 4189 waypoint.handle = handle;
3518 lock (m_targets) 4190 lock (m_targets)
3519 { 4191 {
4192 if (m_targets.Count >= 8)
4193 m_targets.Remove(m_targets.ElementAt(0).Key);
3520 m_targets.Add(handle, waypoint); 4194 m_targets.Add(handle, waypoint);
3521 } 4195 }
3522 m_scene.AddGroupTarget(this); 4196 m_scene.AddGroupTarget(this);
@@ -3550,10 +4224,11 @@ namespace OpenSim.Region.Framework.Scenes
3550 scriptPosTarget target = m_targets[idx]; 4224 scriptPosTarget target = m_targets[idx];
3551 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4225 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3552 { 4226 {
4227 at_target = true;
4228
3553 // trigger at_target 4229 // trigger at_target
3554 if (m_scriptListens_atTarget) 4230 if (m_scriptListens_atTarget)
3555 { 4231 {
3556 at_target = true;
3557 scriptPosTarget att = new scriptPosTarget(); 4232 scriptPosTarget att = new scriptPosTarget();
3558 att.targetPos = target.targetPos; 4233 att.targetPos = target.targetPos;
3559 att.tolerance = target.tolerance; 4234 att.tolerance = target.tolerance;
@@ -3671,11 +4346,50 @@ namespace OpenSim.Region.Framework.Scenes
3671 } 4346 }
3672 } 4347 }
3673 } 4348 }
3674 4349
4350 public Vector3 GetGeometricCenter()
4351 {
4352 // this is not real geometric center but a average of positions relative to root prim acording to
4353 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4354 // ignoring tortured prims details since sl also seems to ignore
4355 // so no real use in doing it on physics
4356
4357 Vector3 gc = Vector3.Zero;
4358
4359 int nparts = m_parts.Count;
4360 if (nparts <= 1)
4361 return gc;
4362
4363 SceneObjectPart[] parts = m_parts.GetArray();
4364 nparts = parts.Length; // just in case it changed
4365 if (nparts <= 1)
4366 return gc;
4367
4368 Quaternion parentRot = RootPart.RotationOffset;
4369 Vector3 pPos;
4370
4371 // average all parts positions
4372 for (int i = 0; i < nparts; i++)
4373 {
4374 // do it directly
4375 // gc += parts[i].GetWorldPosition();
4376 if (parts[i] != RootPart)
4377 {
4378 pPos = parts[i].OffsetPosition;
4379 gc += pPos;
4380 }
4381
4382 }
4383 gc /= nparts;
4384
4385 // relative to root:
4386// gc -= AbsolutePosition;
4387 return gc;
4388 }
4389
3675 public float GetMass() 4390 public float GetMass()
3676 { 4391 {
3677 float retmass = 0f; 4392 float retmass = 0f;
3678
3679 SceneObjectPart[] parts = m_parts.GetArray(); 4393 SceneObjectPart[] parts = m_parts.GetArray();
3680 for (int i = 0; i < parts.Length; i++) 4394 for (int i = 0; i < parts.Length; i++)
3681 retmass += parts[i].GetMass(); 4395 retmass += parts[i].GetMass();
@@ -3683,6 +4397,39 @@ namespace OpenSim.Region.Framework.Scenes
3683 return retmass; 4397 return retmass;
3684 } 4398 }
3685 4399
4400 // center of mass of full object
4401 public Vector3 GetCenterOfMass()
4402 {
4403 PhysicsActor pa = RootPart.PhysActor;
4404
4405 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4406 {
4407 // physics knows better about center of mass of physical prims
4408 Vector3 tmp = pa.CenterOfMass;
4409 return tmp;
4410 }
4411
4412 Vector3 Ptot = Vector3.Zero;
4413 float totmass = 0f;
4414 float m;
4415
4416 SceneObjectPart[] parts = m_parts.GetArray();
4417 for (int i = 0; i < parts.Length; i++)
4418 {
4419 m = parts[i].GetMass();
4420 Ptot += parts[i].GetPartCenterOfMass() * m;
4421 totmass += m;
4422 }
4423
4424 if (totmass == 0)
4425 totmass = 0;
4426 else
4427 totmass = 1 / totmass;
4428 Ptot *= totmass;
4429
4430 return Ptot;
4431 }
4432
3686 /// <summary> 4433 /// <summary>
3687 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4434 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3688 /// the physics engine can use it. 4435 /// the physics engine can use it.
@@ -3862,6 +4609,14 @@ namespace OpenSim.Region.Framework.Scenes
3862 FromItemID = uuid; 4609 FromItemID = uuid;
3863 } 4610 }
3864 4611
4612 public void ResetOwnerChangeFlag()
4613 {
4614 ForEachPart(delegate(SceneObjectPart part)
4615 {
4616 part.ResetOwnerChangeFlag();
4617 });
4618 }
4619
3865 #endregion 4620 #endregion
3866 } 4621 }
3867} 4622}