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.cs1216
1 files changed, 1010 insertions, 206 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 49a3485..2882463 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,11 +24,12 @@
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.Collections.Generic; 29using System.Collections.Generic;
30using System.Drawing; 30using System.Drawing;
31using System.IO; 31using System.IO;
32using System.Diagnostics;
32using System.Linq; 33using System.Linq;
33using System.Threading; 34using System.Threading;
34using System.Xml; 35using System.Xml;
@@ -42,6 +43,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
42 43
43namespace OpenSim.Region.Framework.Scenes 44namespace OpenSim.Region.Framework.Scenes
44{ 45{
46
45 [Flags] 47 [Flags]
46 public enum scriptEvents 48 public enum scriptEvents
47 { 49 {
@@ -105,8 +107,29 @@ namespace OpenSim.Region.Framework.Scenes
105 /// since the group's last persistent backup 107 /// since the group's last persistent backup
106 /// </summary> 108 /// </summary>
107 private bool m_hasGroupChanged = false; 109 private bool m_hasGroupChanged = false;
108 private long timeFirstChanged; 110 private long timeFirstChanged = 0;
109 private long timeLastChanged; 111 private long timeLastChanged = 0;
112 private long m_maxPersistTime = 0;
113 private long m_minPersistTime = 0;
114 private Random m_rand;
115 private bool m_suspendUpdates;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
117
118 public bool areUpdatesSuspended
119 {
120 get
121 {
122 return m_suspendUpdates;
123 }
124 set
125 {
126 m_suspendUpdates = value;
127 if (!value)
128 {
129 QueueForUpdateCheck();
130 }
131 }
132 }
110 133
111 public bool HasGroupChanged 134 public bool HasGroupChanged
112 { 135 {
@@ -114,9 +137,39 @@ namespace OpenSim.Region.Framework.Scenes
114 { 137 {
115 if (value) 138 if (value)
116 { 139 {
140 if (m_isBackedUp)
141 {
142 m_scene.SceneGraph.FireChangeBackup(this);
143 }
117 timeLastChanged = DateTime.Now.Ticks; 144 timeLastChanged = DateTime.Now.Ticks;
118 if (!m_hasGroupChanged) 145 if (!m_hasGroupChanged)
119 timeFirstChanged = DateTime.Now.Ticks; 146 timeFirstChanged = DateTime.Now.Ticks;
147 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
148 {
149 if (m_rand == null)
150 {
151 byte[] val = new byte[16];
152 m_rootPart.UUID.ToBytes(val, 0);
153 m_rand = new Random(BitConverter.ToInt32(val, 0));
154 }
155
156 if (m_scene.GetRootAgentCount() == 0)
157 {
158 //If the region is empty, this change has been made by an automated process
159 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
160
161 float factor = 1.5f + (float)(m_rand.NextDouble());
162 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
163 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
164 }
165 else
166 {
167 //If the region is not empty, we want to obey the minimum and maximum persist times
168 //but add a random factor so we stagger the object persistance a little
169 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
170 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
171 }
172 }
120 } 173 }
121 m_hasGroupChanged = value; 174 m_hasGroupChanged = value;
122 175
@@ -131,7 +184,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 184 /// 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. 185 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
133 /// </summary> 186 /// </summary>
134 public bool HasGroupChangedDueToDelink { get; private set; } 187 public bool HasGroupChangedDueToDelink { get; set; }
135 188
136 private bool isTimeToPersist() 189 private bool isTimeToPersist()
137 { 190 {
@@ -141,8 +194,19 @@ namespace OpenSim.Region.Framework.Scenes
141 return false; 194 return false;
142 if (m_scene.ShuttingDown) 195 if (m_scene.ShuttingDown)
143 return true; 196 return true;
197
198 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
199 {
200 m_maxPersistTime = m_scene.m_persistAfter;
201 m_minPersistTime = m_scene.m_dontPersistBefore;
202 }
203
144 long currentTime = DateTime.Now.Ticks; 204 long currentTime = DateTime.Now.Ticks;
145 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 205
206 if (timeLastChanged == 0) timeLastChanged = currentTime;
207 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
208
209 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
146 return true; 210 return true;
147 return false; 211 return false;
148 } 212 }
@@ -245,10 +309,10 @@ namespace OpenSim.Region.Framework.Scenes
245 309
246 private bool m_scriptListens_atTarget; 310 private bool m_scriptListens_atTarget;
247 private bool m_scriptListens_notAtTarget; 311 private bool m_scriptListens_notAtTarget;
248
249 private bool m_scriptListens_atRotTarget; 312 private bool m_scriptListens_atRotTarget;
250 private bool m_scriptListens_notAtRotTarget; 313 private bool m_scriptListens_notAtRotTarget;
251 314
315 public bool m_dupeInProgress = false;
252 internal Dictionary<UUID, string> m_savedScriptState; 316 internal Dictionary<UUID, string> m_savedScriptState;
253 317
254 #region Properties 318 #region Properties
@@ -285,6 +349,16 @@ namespace OpenSim.Region.Framework.Scenes
285 get { return m_parts.Count; } 349 get { return m_parts.Count; }
286 } 350 }
287 351
352// protected Quaternion m_rotation = Quaternion.Identity;
353//
354// public virtual Quaternion Rotation
355// {
356// get { return m_rotation; }
357// set {
358// m_rotation = value;
359// }
360// }
361
288 public Quaternion GroupRotation 362 public Quaternion GroupRotation
289 { 363 {
290 get { return m_rootPart.RotationOffset; } 364 get { return m_rootPart.RotationOffset; }
@@ -404,14 +478,99 @@ namespace OpenSim.Region.Framework.Scenes
404 478
405 if (Scene != null) 479 if (Scene != null)
406 { 480 {
407 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 481 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
408 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 482 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
483 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
484 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
485 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
409 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 486 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
410 { 487 {
411 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 488 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
489 uint x = 0;
490 uint y = 0;
491 string version = String.Empty;
492 Vector3 newpos = Vector3.Zero;
493 OpenSim.Services.Interfaces.GridRegion destination = null;
494
495 bool canCross = true;
496 foreach (ScenePresence av in m_linkedAvatars)
497 {
498 // We need to cross these agents. First, let's find
499 // out if any of them can't cross for some reason.
500 // We have to deny the crossing entirely if any
501 // of them are banned. Alternatively, we could
502 // unsit banned agents....
503
504
505 // We set the avatar position as being the object
506 // position to get the region to send to
507 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
508 {
509 canCross = false;
510 break;
511 }
512
513 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
514 }
515
516 if (canCross)
517 {
518 // We unparent the SP quietly so that it won't
519 // be made to stand up
520 foreach (ScenePresence av in m_linkedAvatars)
521 {
522 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
523 if (parentPart != null)
524 av.ParentUUID = parentPart.UUID;
525
526 av.ParentID = 0;
527 }
528
529 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
530
531 // Normalize
532 if (val.X >= Constants.RegionSize)
533 val.X -= Constants.RegionSize;
534 if (val.Y >= Constants.RegionSize)
535 val.Y -= Constants.RegionSize;
536 if (val.X < 0)
537 val.X += Constants.RegionSize;
538 if (val.Y < 0)
539 val.Y += Constants.RegionSize;
540
541 // If it's deleted, crossing was successful
542 if (IsDeleted)
543 {
544 foreach (ScenePresence av in m_linkedAvatars)
545 {
546 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
547
548 av.IsInTransit = true;
549
550 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
551 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
552 }
553
554 return;
555 }
556 }
557 else if (RootPart.PhysActor != null)
558 {
559 RootPart.PhysActor.CrossingFailure();
560 }
561
562 Vector3 oldp = AbsolutePosition;
563 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
564 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
565 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
412 } 566 }
413 } 567 }
414 568/* don't see the need but worse don't see where is restored to false if things stay in
569 foreach (SceneObjectPart part in m_parts.GetArray())
570 {
571 part.IgnoreUndoUpdate = true;
572 }
573 */
415 if (RootPart.GetStatusSandbox()) 574 if (RootPart.GetStatusSandbox())
416 { 575 {
417 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 576 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -425,10 +584,30 @@ namespace OpenSim.Region.Framework.Scenes
425 return; 584 return;
426 } 585 }
427 } 586 }
428
429 SceneObjectPart[] parts = m_parts.GetArray(); 587 SceneObjectPart[] parts = m_parts.GetArray();
430 for (int i = 0; i < parts.Length; i++) 588 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
431 parts[i].GroupPosition = val; 589 if (m_dupeInProgress)
590 triggerScriptEvent = false;
591 foreach (SceneObjectPart part in parts)
592 {
593 part.GroupPosition = val;
594 if (triggerScriptEvent)
595 part.TriggerScriptChangedEvent(Changed.POSITION);
596 }
597 if (!m_dupeInProgress)
598 {
599 foreach (ScenePresence av in m_linkedAvatars)
600 {
601 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
602 if (p != null && m_parts.TryGetValue(p.UUID, out p))
603 {
604 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
605 av.AbsolutePosition += offset;
606 av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
607 av.SendAvatarDataToAllAgents();
608 }
609 }
610 }
432 611
433 //if (m_rootPart.PhysActor != null) 612 //if (m_rootPart.PhysActor != null)
434 //{ 613 //{
@@ -443,6 +622,29 @@ namespace OpenSim.Region.Framework.Scenes
443 } 622 }
444 } 623 }
445 624
625 public override Vector3 Velocity
626 {
627 get { return RootPart.Velocity; }
628 set { RootPart.Velocity = value; }
629 }
630
631 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
632 {
633 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
634 ScenePresence agent = icon.EndInvoke(iar);
635
636 //// If the cross was successful, this agent is a child agent
637 //if (agent.IsChildAgent)
638 // agent.Reset();
639 //else // Not successful
640 // agent.RestoreInCurrentScene();
641
642 // In any case
643 agent.IsInTransit = false;
644
645 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
646 }
647
446 public override uint LocalId 648 public override uint LocalId
447 { 649 {
448 get { return m_rootPart.LocalId; } 650 get { return m_rootPart.LocalId; }
@@ -540,6 +742,8 @@ namespace OpenSim.Region.Framework.Scenes
540 childPa.Selected = value; 742 childPa.Selected = value;
541 } 743 }
542 } 744 }
745 if (RootPart.KeyframeMotion != null)
746 RootPart.KeyframeMotion.Selected = value;
543 } 747 }
544 } 748 }
545 749
@@ -617,6 +821,7 @@ namespace OpenSim.Region.Framework.Scenes
617 /// </summary> 821 /// </summary>
618 public SceneObjectGroup() 822 public SceneObjectGroup()
619 { 823 {
824
620 } 825 }
621 826
622 /// <summary> 827 /// <summary>
@@ -633,7 +838,7 @@ namespace OpenSim.Region.Framework.Scenes
633 /// Constructor. This object is added to the scene later via AttachToScene() 838 /// Constructor. This object is added to the scene later via AttachToScene()
634 /// </summary> 839 /// </summary>
635 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 840 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
636 { 841 {
637 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 842 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
638 } 843 }
639 844
@@ -669,6 +874,9 @@ namespace OpenSim.Region.Framework.Scenes
669 /// </summary> 874 /// </summary>
670 public virtual void AttachToBackup() 875 public virtual void AttachToBackup()
671 { 876 {
877 if (IsAttachment) return;
878 m_scene.SceneGraph.FireAttachToBackup(this);
879
672 if (InSceneBackup) 880 if (InSceneBackup)
673 { 881 {
674 //m_log.DebugFormat( 882 //m_log.DebugFormat(
@@ -711,6 +919,13 @@ namespace OpenSim.Region.Framework.Scenes
711 919
712 ApplyPhysics(); 920 ApplyPhysics();
713 921
922 if (RootPart.PhysActor != null)
923 RootPart.Force = RootPart.Force;
924 if (RootPart.PhysActor != null)
925 RootPart.Torque = RootPart.Torque;
926 if (RootPart.PhysActor != null)
927 RootPart.Buoyancy = RootPart.Buoyancy;
928
714 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 929 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
715 // for the same object with very different properties. The caller must schedule the update. 930 // for the same object with very different properties. The caller must schedule the update.
716 //ScheduleGroupForFullUpdate(); 931 //ScheduleGroupForFullUpdate();
@@ -726,6 +941,10 @@ namespace OpenSim.Region.Framework.Scenes
726 EntityIntersection result = new EntityIntersection(); 941 EntityIntersection result = new EntityIntersection();
727 942
728 SceneObjectPart[] parts = m_parts.GetArray(); 943 SceneObjectPart[] parts = m_parts.GetArray();
944
945 // Find closest hit here
946 float idist = float.MaxValue;
947
729 for (int i = 0; i < parts.Length; i++) 948 for (int i = 0; i < parts.Length; i++)
730 { 949 {
731 SceneObjectPart part = parts[i]; 950 SceneObjectPart part = parts[i];
@@ -740,11 +959,6 @@ namespace OpenSim.Region.Framework.Scenes
740 959
741 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 960 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
742 961
743 // This may need to be updated to the maximum draw distance possible..
744 // We might (and probably will) be checking for prim creation from other sims
745 // when the camera crosses the border.
746 float idist = Constants.RegionSize;
747
748 if (inter.HitTF) 962 if (inter.HitTF)
749 { 963 {
750 // We need to find the closest prim to return to the testcaller along the ray 964 // We need to find the closest prim to return to the testcaller along the ray
@@ -755,10 +969,11 @@ namespace OpenSim.Region.Framework.Scenes
755 result.obj = part; 969 result.obj = part;
756 result.normal = inter.normal; 970 result.normal = inter.normal;
757 result.distance = inter.distance; 971 result.distance = inter.distance;
972
973 idist = inter.distance;
758 } 974 }
759 } 975 }
760 } 976 }
761
762 return result; 977 return result;
763 } 978 }
764 979
@@ -770,25 +985,27 @@ namespace OpenSim.Region.Framework.Scenes
770 /// <returns></returns> 985 /// <returns></returns>
771 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 986 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
772 { 987 {
773 maxX = -256f; 988 maxX = float.MinValue;
774 maxY = -256f; 989 maxY = float.MinValue;
775 maxZ = -256f; 990 maxZ = float.MinValue;
776 minX = 256f; 991 minX = float.MaxValue;
777 minY = 256f; 992 minY = float.MaxValue;
778 minZ = 8192f; 993 minZ = float.MaxValue;
779 994
780 SceneObjectPart[] parts = m_parts.GetArray(); 995 SceneObjectPart[] parts = m_parts.GetArray();
781 for (int i = 0; i < parts.Length; i++) 996 foreach (SceneObjectPart part in parts)
782 { 997 {
783 SceneObjectPart part = parts[i];
784
785 Vector3 worldPos = part.GetWorldPosition(); 998 Vector3 worldPos = part.GetWorldPosition();
786 Vector3 offset = worldPos - AbsolutePosition; 999 Vector3 offset = worldPos - AbsolutePosition;
787 Quaternion worldRot; 1000 Quaternion worldRot;
788 if (part.ParentID == 0) 1001 if (part.ParentID == 0)
1002 {
789 worldRot = part.RotationOffset; 1003 worldRot = part.RotationOffset;
1004 }
790 else 1005 else
1006 {
791 worldRot = part.GetWorldRotation(); 1007 worldRot = part.GetWorldRotation();
1008 }
792 1009
793 Vector3 frontTopLeft; 1010 Vector3 frontTopLeft;
794 Vector3 frontTopRight; 1011 Vector3 frontTopRight;
@@ -800,6 +1017,8 @@ namespace OpenSim.Region.Framework.Scenes
800 Vector3 backBottomLeft; 1017 Vector3 backBottomLeft;
801 Vector3 backBottomRight; 1018 Vector3 backBottomRight;
802 1019
1020 // Vector3[] corners = new Vector3[8];
1021
803 Vector3 orig = Vector3.Zero; 1022 Vector3 orig = Vector3.Zero;
804 1023
805 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1024 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -834,6 +1053,38 @@ namespace OpenSim.Region.Framework.Scenes
834 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1053 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
835 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1054 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
836 1055
1056
1057
1058 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1059 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1060 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1061 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1062 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1063 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1064 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1065 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1066
1067 //for (int i = 0; i < 8; i++)
1068 //{
1069 // corners[i] = corners[i] * worldRot;
1070 // corners[i] += offset;
1071
1072 // if (corners[i].X > maxX)
1073 // maxX = corners[i].X;
1074 // if (corners[i].X < minX)
1075 // minX = corners[i].X;
1076
1077 // if (corners[i].Y > maxY)
1078 // maxY = corners[i].Y;
1079 // if (corners[i].Y < minY)
1080 // minY = corners[i].Y;
1081
1082 // if (corners[i].Z > maxZ)
1083 // maxZ = corners[i].Y;
1084 // if (corners[i].Z < minZ)
1085 // minZ = corners[i].Z;
1086 //}
1087
837 frontTopLeft = frontTopLeft * worldRot; 1088 frontTopLeft = frontTopLeft * worldRot;
838 frontTopRight = frontTopRight * worldRot; 1089 frontTopRight = frontTopRight * worldRot;
839 frontBottomLeft = frontBottomLeft * worldRot; 1090 frontBottomLeft = frontBottomLeft * worldRot;
@@ -855,6 +1106,15 @@ namespace OpenSim.Region.Framework.Scenes
855 backTopLeft += offset; 1106 backTopLeft += offset;
856 backTopRight += offset; 1107 backTopRight += offset;
857 1108
1109 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1110 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1111 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1112 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1113 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1114 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1115 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1116 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1117
858 if (frontTopRight.X > maxX) 1118 if (frontTopRight.X > maxX)
859 maxX = frontTopRight.X; 1119 maxX = frontTopRight.X;
860 if (frontTopLeft.X > maxX) 1120 if (frontTopLeft.X > maxX)
@@ -998,17 +1258,118 @@ namespace OpenSim.Region.Framework.Scenes
998 1258
999 #endregion 1259 #endregion
1000 1260
1261 public void GetResourcesCosts(SceneObjectPart apart,
1262 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1263 {
1264 // this information may need to be cached
1265
1266 float cost;
1267 float tmpcost;
1268
1269 bool ComplexCost = false;
1270
1271 SceneObjectPart p;
1272 SceneObjectPart[] parts;
1273
1274 lock (m_parts)
1275 {
1276 parts = m_parts.GetArray();
1277 }
1278
1279 int nparts = parts.Length;
1280
1281
1282 for (int i = 0; i < nparts; i++)
1283 {
1284 p = parts[i];
1285
1286 if (p.UsesComplexCost)
1287 {
1288 ComplexCost = true;
1289 break;
1290 }
1291 }
1292
1293 if (ComplexCost)
1294 {
1295 linksetResCost = 0;
1296 linksetPhysCost = 0;
1297 partCost = 0;
1298 partPhysCost = 0;
1299
1300 for (int i = 0; i < nparts; i++)
1301 {
1302 p = parts[i];
1303
1304 cost = p.StreamingCost;
1305 tmpcost = p.SimulationCost;
1306 if (tmpcost > cost)
1307 cost = tmpcost;
1308 tmpcost = p.PhysicsCost;
1309 if (tmpcost > cost)
1310 cost = tmpcost;
1311
1312 linksetPhysCost += tmpcost;
1313 linksetResCost += cost;
1314
1315 if (p == apart)
1316 {
1317 partCost = cost;
1318 partPhysCost = tmpcost;
1319 }
1320 }
1321 }
1322 else
1323 {
1324 partPhysCost = 1.0f;
1325 partCost = 1.0f;
1326 linksetResCost = (float)nparts;
1327 linksetPhysCost = linksetResCost;
1328 }
1329 }
1330
1331 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1332 {
1333 SceneObjectPart p;
1334 SceneObjectPart[] parts;
1335
1336 lock (m_parts)
1337 {
1338 parts = m_parts.GetArray();
1339 }
1340
1341 int nparts = parts.Length;
1342
1343 PhysCost = 0;
1344 StreamCost = 0;
1345 SimulCost = 0;
1346
1347 for (int i = 0; i < nparts; i++)
1348 {
1349 p = parts[i];
1350
1351 StreamCost += p.StreamingCost;
1352 SimulCost += p.SimulationCost;
1353 PhysCost += p.PhysicsCost;
1354 }
1355 }
1356
1001 public void SaveScriptedState(XmlTextWriter writer) 1357 public void SaveScriptedState(XmlTextWriter writer)
1002 { 1358 {
1359 SaveScriptedState(writer, false);
1360 }
1361
1362 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1363 {
1003 XmlDocument doc = new XmlDocument(); 1364 XmlDocument doc = new XmlDocument();
1004 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1365 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1005 1366
1006 SceneObjectPart[] parts = m_parts.GetArray(); 1367 SceneObjectPart[] parts = m_parts.GetArray();
1007 for (int i = 0; i < parts.Length; i++) 1368 for (int i = 0; i < parts.Length; i++)
1008 { 1369 {
1009 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1370 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1010 foreach (KeyValuePair<UUID, string> kvp in pstates) 1371 foreach (KeyValuePair<UUID, string> kvp in pstates)
1011 states.Add(kvp.Key, kvp.Value); 1372 states[kvp.Key] = kvp.Value;
1012 } 1373 }
1013 1374
1014 if (states.Count > 0) 1375 if (states.Count > 0)
@@ -1028,6 +1389,169 @@ namespace OpenSim.Region.Framework.Scenes
1028 } 1389 }
1029 1390
1030 /// <summary> 1391 /// <summary>
1392 /// Add the avatar to this linkset (avatar is sat).
1393 /// </summary>
1394 /// <param name="agentID"></param>
1395 public void AddAvatar(UUID agentID)
1396 {
1397 ScenePresence presence;
1398 if (m_scene.TryGetScenePresence(agentID, out presence))
1399 {
1400 if (!m_linkedAvatars.Contains(presence))
1401 {
1402 m_linkedAvatars.Add(presence);
1403 }
1404 }
1405 }
1406
1407 /// <summary>
1408 /// Delete the avatar from this linkset (avatar is unsat).
1409 /// </summary>
1410 /// <param name="agentID"></param>
1411 public void DeleteAvatar(UUID agentID)
1412 {
1413 ScenePresence presence;
1414 if (m_scene.TryGetScenePresence(agentID, out presence))
1415 {
1416 if (m_linkedAvatars.Contains(presence))
1417 {
1418 m_linkedAvatars.Remove(presence);
1419 }
1420 }
1421 }
1422
1423 /// <summary>
1424 /// Returns the list of linked presences (avatars sat on this group)
1425 /// </summary>
1426 /// <param name="agentID"></param>
1427 public List<ScenePresence> GetLinkedAvatars()
1428 {
1429 return m_linkedAvatars;
1430 }
1431
1432 /// <summary>
1433 /// Attach this scene object to the given avatar.
1434 /// </summary>
1435 /// <param name="agentID"></param>
1436 /// <param name="attachmentpoint"></param>
1437 /// <param name="AttachOffset"></param>
1438 private void AttachToAgent(
1439 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1440 {
1441 if (avatar != null)
1442 {
1443 // don't attach attachments to child agents
1444 if (avatar.IsChildAgent) return;
1445
1446 // Remove from database and parcel prim count
1447 m_scene.DeleteFromStorage(so.UUID);
1448 m_scene.EventManager.TriggerParcelPrimCountTainted();
1449
1450 so.AttachedAvatar = avatar.UUID;
1451
1452 if (so.RootPart.PhysActor != null)
1453 {
1454 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1455 so.RootPart.PhysActor = null;
1456 }
1457
1458 so.AbsolutePosition = attachOffset;
1459 so.RootPart.AttachedPos = attachOffset;
1460 so.IsAttachment = true;
1461 so.RootPart.SetParentLocalId(avatar.LocalId);
1462 so.AttachmentPoint = attachmentpoint;
1463
1464 avatar.AddAttachment(this);
1465
1466 if (!silent)
1467 {
1468 // Killing it here will cause the client to deselect it
1469 // It then reappears on the avatar, deselected
1470 // through the full update below
1471 //
1472 if (IsSelected)
1473 {
1474 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1475 }
1476
1477 IsSelected = false; // fudge....
1478 ScheduleGroupForFullUpdate();
1479 }
1480 }
1481 else
1482 {
1483 m_log.WarnFormat(
1484 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1485 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1486 }
1487 }
1488
1489 public byte GetAttachmentPoint()
1490 {
1491 return m_rootPart.Shape.State;
1492 }
1493
1494 public void DetachToGround()
1495 {
1496 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1497 if (avatar == null)
1498 return;
1499
1500 avatar.RemoveAttachment(this);
1501
1502 Vector3 detachedpos = new Vector3(127f,127f,127f);
1503 if (avatar == null)
1504 return;
1505
1506 detachedpos = avatar.AbsolutePosition;
1507 FromItemID = UUID.Zero;
1508
1509 AbsolutePosition = detachedpos;
1510 AttachedAvatar = UUID.Zero;
1511
1512 //SceneObjectPart[] parts = m_parts.GetArray();
1513 //for (int i = 0; i < parts.Length; i++)
1514 // parts[i].AttachedAvatar = UUID.Zero;
1515
1516 m_rootPart.SetParentLocalId(0);
1517 AttachmentPoint = (byte)0;
1518 // must check if buildind should be true or false here
1519 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1520 HasGroupChanged = true;
1521 RootPart.Rezzed = DateTime.Now;
1522 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1523 AttachToBackup();
1524 m_scene.EventManager.TriggerParcelPrimCountTainted();
1525 m_rootPart.ScheduleFullUpdate();
1526 m_rootPart.ClearUndoState();
1527 }
1528
1529 public void DetachToInventoryPrep()
1530 {
1531 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1532 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1533 if (avatar != null)
1534 {
1535 //detachedpos = avatar.AbsolutePosition;
1536 avatar.RemoveAttachment(this);
1537 }
1538
1539 AttachedAvatar = UUID.Zero;
1540
1541 /*SceneObjectPart[] parts = m_parts.GetArray();
1542 for (int i = 0; i < parts.Length; i++)
1543 parts[i].AttachedAvatar = UUID.Zero;*/
1544
1545 m_rootPart.SetParentLocalId(0);
1546 //m_rootPart.SetAttachmentPoint((byte)0);
1547 IsAttachment = false;
1548 AbsolutePosition = m_rootPart.AttachedPos;
1549 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1550 //AttachToBackup();
1551 //m_rootPart.ScheduleFullUpdate();
1552 }
1553
1554 /// <summary>
1031 /// 1555 ///
1032 /// </summary> 1556 /// </summary>
1033 /// <param name="part"></param> 1557 /// <param name="part"></param>
@@ -1077,7 +1601,10 @@ namespace OpenSim.Region.Framework.Scenes
1077 public void AddPart(SceneObjectPart part) 1601 public void AddPart(SceneObjectPart part)
1078 { 1602 {
1079 part.SetParent(this); 1603 part.SetParent(this);
1080 part.LinkNum = m_parts.Add(part.UUID, part); 1604 m_parts.Add(part.UUID, part);
1605
1606 part.LinkNum = m_parts.Count;
1607
1081 if (part.LinkNum == 2) 1608 if (part.LinkNum == 2)
1082 RootPart.LinkNum = 1; 1609 RootPart.LinkNum = 1;
1083 } 1610 }
@@ -1165,7 +1692,7 @@ namespace OpenSim.Region.Framework.Scenes
1165// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1692// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1166// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1693// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1167 1694
1168 part.StoreUndoState(); 1695// part.StoreUndoState();
1169 part.OnGrab(offsetPos, remoteClient); 1696 part.OnGrab(offsetPos, remoteClient);
1170 } 1697 }
1171 1698
@@ -1185,6 +1712,11 @@ namespace OpenSim.Region.Framework.Scenes
1185 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1712 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1186 public void DeleteGroupFromScene(bool silent) 1713 public void DeleteGroupFromScene(bool silent)
1187 { 1714 {
1715 // We need to keep track of this state in case this group is still queued for backup.
1716 IsDeleted = true;
1717
1718 DetachFromBackup();
1719
1188 SceneObjectPart[] parts = m_parts.GetArray(); 1720 SceneObjectPart[] parts = m_parts.GetArray();
1189 for (int i = 0; i < parts.Length; i++) 1721 for (int i = 0; i < parts.Length; i++)
1190 { 1722 {
@@ -1207,6 +1739,8 @@ namespace OpenSim.Region.Framework.Scenes
1207 } 1739 }
1208 }); 1740 });
1209 } 1741 }
1742
1743
1210 } 1744 }
1211 1745
1212 public void AddScriptLPS(int count) 1746 public void AddScriptLPS(int count)
@@ -1276,28 +1810,43 @@ namespace OpenSim.Region.Framework.Scenes
1276 /// </summary> 1810 /// </summary>
1277 public void ApplyPhysics() 1811 public void ApplyPhysics()
1278 { 1812 {
1279 // Apply physics to the root prim
1280 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1281
1282 // Apply physics to child prims
1283 SceneObjectPart[] parts = m_parts.GetArray(); 1813 SceneObjectPart[] parts = m_parts.GetArray();
1284 if (parts.Length > 1) 1814 if (parts.Length > 1)
1285 { 1815 {
1816 ResetChildPrimPhysicsPositions();
1817
1818 // Apply physics to the root prim
1819 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1820
1821
1286 for (int i = 0; i < parts.Length; i++) 1822 for (int i = 0; i < parts.Length; i++)
1287 { 1823 {
1288 SceneObjectPart part = parts[i]; 1824 SceneObjectPart part = parts[i];
1289 if (part.LocalId != m_rootPart.LocalId) 1825 if (part.LocalId != m_rootPart.LocalId)
1290 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1826 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1291 } 1827 }
1292
1293 // Hack to get the physics scene geometries in the right spot 1828 // Hack to get the physics scene geometries in the right spot
1294 ResetChildPrimPhysicsPositions(); 1829// ResetChildPrimPhysicsPositions();
1830 if (m_rootPart.PhysActor != null)
1831 {
1832 m_rootPart.PhysActor.Building = false;
1833 }
1834 }
1835 else
1836 {
1837 // Apply physics to the root prim
1838 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1295 } 1839 }
1296 } 1840 }
1297 1841
1298 public void SetOwnerId(UUID userId) 1842 public void SetOwnerId(UUID userId)
1299 { 1843 {
1300 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1844 ForEachPart(delegate(SceneObjectPart part)
1845 {
1846
1847 part.OwnerID = userId;
1848
1849 });
1301 } 1850 }
1302 1851
1303 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1852 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1329,11 +1878,17 @@ namespace OpenSim.Region.Framework.Scenes
1329 return; 1878 return;
1330 } 1879 }
1331 1880
1881 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1882 return;
1883
1332 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1884 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1333 // any exception propogate upwards. 1885 // any exception propogate upwards.
1334 try 1886 try
1335 { 1887 {
1336 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1888 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1889 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1890 m_scene.LoadingPrims) // Land may not be valid yet
1891
1337 { 1892 {
1338 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1893 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1339 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1894 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1360,6 +1915,7 @@ namespace OpenSim.Region.Framework.Scenes
1360 } 1915 }
1361 } 1916 }
1362 } 1917 }
1918
1363 } 1919 }
1364 1920
1365 if (m_scene.UseBackup && HasGroupChanged) 1921 if (m_scene.UseBackup && HasGroupChanged)
@@ -1367,10 +1923,30 @@ namespace OpenSim.Region.Framework.Scenes
1367 // don't backup while it's selected or you're asking for changes mid stream. 1923 // don't backup while it's selected or you're asking for changes mid stream.
1368 if (isTimeToPersist() || forcedBackup) 1924 if (isTimeToPersist() || forcedBackup)
1369 { 1925 {
1926 if (m_rootPart.PhysActor != null &&
1927 (!m_rootPart.PhysActor.IsPhysical))
1928 {
1929 // Possible ghost prim
1930 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1931 {
1932 foreach (SceneObjectPart part in m_parts.GetArray())
1933 {
1934 // Re-set physics actor positions and
1935 // orientations
1936 part.GroupPosition = m_rootPart.GroupPosition;
1937 }
1938 }
1939 }
1370// m_log.DebugFormat( 1940// m_log.DebugFormat(
1371// "[SCENE]: Storing {0}, {1} in {2}", 1941// "[SCENE]: Storing {0}, {1} in {2}",
1372// Name, UUID, m_scene.RegionInfo.RegionName); 1942// Name, UUID, m_scene.RegionInfo.RegionName);
1373 1943
1944 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
1945 {
1946 RootPart.Shape.State = 0;
1947 ScheduleGroupForFullUpdate();
1948 }
1949
1374 SceneObjectGroup backup_group = Copy(false); 1950 SceneObjectGroup backup_group = Copy(false);
1375 backup_group.RootPart.Velocity = RootPart.Velocity; 1951 backup_group.RootPart.Velocity = RootPart.Velocity;
1376 backup_group.RootPart.Acceleration = RootPart.Acceleration; 1952 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1384,6 +1960,11 @@ namespace OpenSim.Region.Framework.Scenes
1384 1960
1385 backup_group.ForEachPart(delegate(SceneObjectPart part) 1961 backup_group.ForEachPart(delegate(SceneObjectPart part)
1386 { 1962 {
1963 if (part.KeyframeMotion != null)
1964 {
1965 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
1966 part.KeyframeMotion.UpdateSceneObject(this);
1967 }
1387 part.Inventory.ProcessInventoryBackup(datastore); 1968 part.Inventory.ProcessInventoryBackup(datastore);
1388 }); 1969 });
1389 1970
@@ -1436,6 +2017,7 @@ namespace OpenSim.Region.Framework.Scenes
1436 /// <returns></returns> 2017 /// <returns></returns>
1437 public SceneObjectGroup Copy(bool userExposed) 2018 public SceneObjectGroup Copy(bool userExposed)
1438 { 2019 {
2020 m_dupeInProgress = true;
1439 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2021 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1440 dupe.m_isBackedUp = false; 2022 dupe.m_isBackedUp = false;
1441 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2023 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1450,7 +2032,7 @@ namespace OpenSim.Region.Framework.Scenes
1450 // This is only necessary when userExposed is false! 2032 // This is only necessary when userExposed is false!
1451 2033
1452 bool previousAttachmentStatus = dupe.IsAttachment; 2034 bool previousAttachmentStatus = dupe.IsAttachment;
1453 2035
1454 if (!userExposed) 2036 if (!userExposed)
1455 dupe.IsAttachment = true; 2037 dupe.IsAttachment = true;
1456 2038
@@ -1468,11 +2050,11 @@ namespace OpenSim.Region.Framework.Scenes
1468 dupe.m_rootPart.TrimPermissions(); 2050 dupe.m_rootPart.TrimPermissions();
1469 2051
1470 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2052 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1471 2053
1472 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2054 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1473 { 2055 {
1474 return p1.LinkNum.CompareTo(p2.LinkNum); 2056 return p1.LinkNum.CompareTo(p2.LinkNum);
1475 } 2057 }
1476 ); 2058 );
1477 2059
1478 foreach (SceneObjectPart part in partList) 2060 foreach (SceneObjectPart part in partList)
@@ -1482,41 +2064,53 @@ namespace OpenSim.Region.Framework.Scenes
1482 { 2064 {
1483 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2065 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1484 newPart.LinkNum = part.LinkNum; 2066 newPart.LinkNum = part.LinkNum;
1485 } 2067 if (userExposed)
2068 newPart.ParentID = dupe.m_rootPart.LocalId;
2069 }
1486 else 2070 else
1487 { 2071 {
1488 newPart = dupe.m_rootPart; 2072 newPart = dupe.m_rootPart;
1489 } 2073 }
2074/*
2075 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2076 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1490 2077
1491 // Need to duplicate the physics actor as well 2078 // Need to duplicate the physics actor as well
1492 PhysicsActor originalPartPa = part.PhysActor; 2079 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1493 if (originalPartPa != null && userExposed)
1494 { 2080 {
1495 PrimitiveBaseShape pbs = newPart.Shape; 2081 PrimitiveBaseShape pbs = newPart.Shape;
1496
1497 newPart.PhysActor 2082 newPart.PhysActor
1498 = m_scene.PhysicsScene.AddPrimShape( 2083 = m_scene.PhysicsScene.AddPrimShape(
1499 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2084 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1500 pbs, 2085 pbs,
1501 newPart.AbsolutePosition, 2086 newPart.AbsolutePosition,
1502 newPart.Scale, 2087 newPart.Scale,
1503 newPart.RotationOffset, 2088 newPart.GetWorldRotation(),
1504 originalPartPa.IsPhysical, 2089 isphys,
2090 isphan,
1505 newPart.LocalId); 2091 newPart.LocalId);
1506 2092
1507 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2093 newPart.DoPhysicsPropertyUpdate(isphys, true);
1508 } 2094 */
2095 if (userExposed)
2096 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2097// }
1509 } 2098 }
1510 2099
1511 if (userExposed) 2100 if (userExposed)
1512 { 2101 {
1513 dupe.UpdateParentIDs(); 2102// done above dupe.UpdateParentIDs();
2103
2104 if (dupe.m_rootPart.PhysActor != null)
2105 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2106
1514 dupe.HasGroupChanged = true; 2107 dupe.HasGroupChanged = true;
1515 dupe.AttachToBackup(); 2108 dupe.AttachToBackup();
1516 2109
1517 ScheduleGroupForFullUpdate(); 2110 ScheduleGroupForFullUpdate();
1518 } 2111 }
1519 2112
2113 m_dupeInProgress = false;
1520 return dupe; 2114 return dupe;
1521 } 2115 }
1522 2116
@@ -1528,11 +2122,24 @@ namespace OpenSim.Region.Framework.Scenes
1528 /// <param name="cGroupID"></param> 2122 /// <param name="cGroupID"></param>
1529 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2123 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1530 { 2124 {
1531 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2125 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2126 // give newpart a new local ID lettng old part keep same
2127 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2128 newpart.LocalId = m_scene.AllocateLocalId();
2129
2130 SetRootPart(newpart);
2131 if (userExposed)
2132 RootPart.Velocity = Vector3.Zero; // In case source is moving
1532 } 2133 }
1533 2134
1534 public void ScriptSetPhysicsStatus(bool usePhysics) 2135 public void ScriptSetPhysicsStatus(bool usePhysics)
1535 { 2136 {
2137 if (usePhysics)
2138 {
2139 if (RootPart.KeyframeMotion != null)
2140 RootPart.KeyframeMotion.Stop();
2141 RootPart.KeyframeMotion = null;
2142 }
1536 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2143 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1537 } 2144 }
1538 2145
@@ -1586,7 +2193,7 @@ namespace OpenSim.Region.Framework.Scenes
1586 } 2193 }
1587 } 2194 }
1588 2195
1589 public void applyAngularImpulse(Vector3 impulse) 2196 public void ApplyAngularImpulse(Vector3 impulse)
1590 { 2197 {
1591 PhysicsActor pa = RootPart.PhysActor; 2198 PhysicsActor pa = RootPart.PhysActor;
1592 2199
@@ -1600,36 +2207,12 @@ namespace OpenSim.Region.Framework.Scenes
1600 } 2207 }
1601 } 2208 }
1602 2209
1603 public void setAngularImpulse(Vector3 impulse)
1604 {
1605 PhysicsActor pa = RootPart.PhysActor;
1606
1607 if (pa != null)
1608 {
1609 if (!IsAttachment)
1610 {
1611 pa.Torque = impulse;
1612 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1613 }
1614 }
1615 }
1616
1617 public Vector3 GetTorque() 2210 public Vector3 GetTorque()
1618 { 2211 {
1619 PhysicsActor pa = RootPart.PhysActor; 2212 return RootPart.Torque;
1620
1621 if (pa != null)
1622 {
1623 if (!IsAttachment)
1624 {
1625 Vector3 torque = pa.Torque;
1626 return torque;
1627 }
1628 }
1629
1630 return Vector3.Zero;
1631 } 2213 }
1632 2214
2215 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1633 public void moveToTarget(Vector3 target, float tau) 2216 public void moveToTarget(Vector3 target, float tau)
1634 { 2217 {
1635 if (IsAttachment) 2218 if (IsAttachment)
@@ -1661,6 +2244,46 @@ namespace OpenSim.Region.Framework.Scenes
1661 pa.PIDActive = false; 2244 pa.PIDActive = false;
1662 } 2245 }
1663 2246
2247 public void rotLookAt(Quaternion target, float strength, float damping)
2248 {
2249 SceneObjectPart rootpart = m_rootPart;
2250 if (rootpart != null)
2251 {
2252 if (IsAttachment)
2253 {
2254 /*
2255 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2256 if (avatar != null)
2257 {
2258 Rotate the Av?
2259 } */
2260 }
2261 else
2262 {
2263 if (rootpart.PhysActor != null)
2264 { // APID must be implemented in your physics system for this to function.
2265 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2266 rootpart.PhysActor.APIDStrength = strength;
2267 rootpart.PhysActor.APIDDamping = damping;
2268 rootpart.PhysActor.APIDActive = true;
2269 }
2270 }
2271 }
2272 }
2273
2274 public void stopLookAt()
2275 {
2276 SceneObjectPart rootpart = m_rootPart;
2277 if (rootpart != null)
2278 {
2279 if (rootpart.PhysActor != null)
2280 { // APID must be implemented in your physics system for this to function.
2281 rootpart.PhysActor.APIDActive = false;
2282 }
2283 }
2284
2285 }
2286
1664 /// <summary> 2287 /// <summary>
1665 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2288 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1666 /// </summary> 2289 /// </summary>
@@ -1717,7 +2340,12 @@ namespace OpenSim.Region.Framework.Scenes
1717 /// <param name="cGroupID"></param> 2340 /// <param name="cGroupID"></param>
1718 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2341 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1719 { 2342 {
1720 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2343 // give new ID to the new part, letting old keep original
2344 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2345 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2346 newPart.LocalId = m_scene.AllocateLocalId();
2347 newPart.SetParent(this);
2348
1721 AddPart(newPart); 2349 AddPart(newPart);
1722 2350
1723 SetPartAsNonRoot(newPart); 2351 SetPartAsNonRoot(newPart);
@@ -1846,11 +2474,11 @@ namespace OpenSim.Region.Framework.Scenes
1846 /// Immediately send a full update for this scene object. 2474 /// Immediately send a full update for this scene object.
1847 /// </summary> 2475 /// </summary>
1848 public void SendGroupFullUpdate() 2476 public void SendGroupFullUpdate()
1849 { 2477 {
1850 if (IsDeleted) 2478 if (IsDeleted)
1851 return; 2479 return;
1852 2480
1853// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2481// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1854 2482
1855 RootPart.SendFullUpdateToAllClients(); 2483 RootPart.SendFullUpdateToAllClients();
1856 2484
@@ -1969,6 +2597,11 @@ namespace OpenSim.Region.Framework.Scenes
1969 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2597 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1970 public void LinkToGroup(SceneObjectGroup objectGroup) 2598 public void LinkToGroup(SceneObjectGroup objectGroup)
1971 { 2599 {
2600 LinkToGroup(objectGroup, false);
2601 }
2602
2603 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2604 {
1972// m_log.DebugFormat( 2605// m_log.DebugFormat(
1973// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2606// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1974// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID); 2607// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1979,6 +2612,15 @@ namespace OpenSim.Region.Framework.Scenes
1979 2612
1980 SceneObjectPart linkPart = objectGroup.m_rootPart; 2613 SceneObjectPart linkPart = objectGroup.m_rootPart;
1981 2614
2615 if (m_rootPart.PhysActor != null)
2616 m_rootPart.PhysActor.Building = true;
2617 if (linkPart.PhysActor != null)
2618 linkPart.PhysActor.Building = true;
2619
2620 // physics flags from group to be applied to linked parts
2621 bool grpusephys = UsesPhysics;
2622 bool grptemporary = IsTemporary;
2623
1982 Vector3 oldGroupPosition = linkPart.GroupPosition; 2624 Vector3 oldGroupPosition = linkPart.GroupPosition;
1983 Quaternion oldRootRotation = linkPart.RotationOffset; 2625 Quaternion oldRootRotation = linkPart.RotationOffset;
1984 2626
@@ -2002,13 +2644,34 @@ namespace OpenSim.Region.Framework.Scenes
2002 2644
2003 lock (m_parts.SyncRoot) 2645 lock (m_parts.SyncRoot)
2004 { 2646 {
2005 int linkNum = PrimCount + 1; 2647 int linkNum;
2648 if (insert)
2649 {
2650 linkNum = 2;
2651 foreach (SceneObjectPart part in Parts)
2652 {
2653 if (part.LinkNum > 1)
2654 part.LinkNum++;
2655 }
2656 }
2657 else
2658 {
2659 linkNum = PrimCount + 1;
2660 }
2006 2661
2007 m_parts.Add(linkPart.UUID, linkPart); 2662 m_parts.Add(linkPart.UUID, linkPart);
2008 2663
2009 linkPart.SetParent(this); 2664 linkPart.SetParent(this);
2010 linkPart.CreateSelected = true; 2665 linkPart.CreateSelected = true;
2011 2666
2667 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2668 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2669 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2670 {
2671 linkPart.PhysActor.link(m_rootPart.PhysActor);
2672 this.Scene.PhysicsScene.AddPhysicsActorTaint(linkPart.PhysActor);
2673 }
2674
2012 linkPart.LinkNum = linkNum++; 2675 linkPart.LinkNum = linkNum++;
2013 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2676 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2014 2677
@@ -2022,7 +2685,16 @@ namespace OpenSim.Region.Framework.Scenes
2022 { 2685 {
2023 SceneObjectPart part = ogParts[i]; 2686 SceneObjectPart part = ogParts[i];
2024 if (part.UUID != objectGroup.m_rootPart.UUID) 2687 if (part.UUID != objectGroup.m_rootPart.UUID)
2688 {
2025 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2689 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2690 // let physics know
2691 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2692 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2693 {
2694 part.PhysActor.link(m_rootPart.PhysActor);
2695 this.Scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2696 }
2697 }
2026 part.ClearUndoState(); 2698 part.ClearUndoState();
2027 } 2699 }
2028 } 2700 }
@@ -2031,7 +2703,7 @@ namespace OpenSim.Region.Framework.Scenes
2031 objectGroup.IsDeleted = true; 2703 objectGroup.IsDeleted = true;
2032 2704
2033 objectGroup.m_parts.Clear(); 2705 objectGroup.m_parts.Clear();
2034 2706
2035 // Can't do this yet since backup still makes use of the root part without any synchronization 2707 // Can't do this yet since backup still makes use of the root part without any synchronization
2036// objectGroup.m_rootPart = null; 2708// objectGroup.m_rootPart = null;
2037 2709
@@ -2042,6 +2714,9 @@ namespace OpenSim.Region.Framework.Scenes
2042 // unmoved prims! 2714 // unmoved prims!
2043 ResetChildPrimPhysicsPositions(); 2715 ResetChildPrimPhysicsPositions();
2044 2716
2717 if (m_rootPart.PhysActor != null)
2718 m_rootPart.PhysActor.Building = false;
2719
2045 //HasGroupChanged = true; 2720 //HasGroupChanged = true;
2046 //ScheduleGroupForFullUpdate(); 2721 //ScheduleGroupForFullUpdate();
2047 } 2722 }
@@ -2109,7 +2784,10 @@ namespace OpenSim.Region.Framework.Scenes
2109// m_log.DebugFormat( 2784// m_log.DebugFormat(
2110// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2785// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2111// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2786// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2112 2787
2788 if (m_rootPart.PhysActor != null)
2789 m_rootPart.PhysActor.Building = true;
2790
2113 linkPart.ClearUndoState(); 2791 linkPart.ClearUndoState();
2114 2792
2115 Quaternion worldRot = linkPart.GetWorldRotation(); 2793 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2169,6 +2847,14 @@ namespace OpenSim.Region.Framework.Scenes
2169 2847
2170 // When we delete a group, we currently have to force persist to the database if the object id has changed 2848 // When we delete a group, we currently have to force persist to the database if the object id has changed
2171 // (since delete works by deleting all rows which have a given object id) 2849 // (since delete works by deleting all rows which have a given object id)
2850
2851 // this is as it seems to be in sl now
2852 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2853 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2854
2855 if (m_rootPart.PhysActor != null)
2856 m_rootPart.PhysActor.Building = false;
2857
2172 objectGroup.HasGroupChangedDueToDelink = true; 2858 objectGroup.HasGroupChangedDueToDelink = true;
2173 2859
2174 return objectGroup; 2860 return objectGroup;
@@ -2180,6 +2866,7 @@ namespace OpenSim.Region.Framework.Scenes
2180 /// <param name="objectGroup"></param> 2866 /// <param name="objectGroup"></param>
2181 public virtual void DetachFromBackup() 2867 public virtual void DetachFromBackup()
2182 { 2868 {
2869 m_scene.SceneGraph.FireDetachFromBackup(this);
2183 if (m_isBackedUp && Scene != null) 2870 if (m_isBackedUp && Scene != null)
2184 m_scene.EventManager.OnBackup -= ProcessBackup; 2871 m_scene.EventManager.OnBackup -= ProcessBackup;
2185 2872
@@ -2198,7 +2885,8 @@ namespace OpenSim.Region.Framework.Scenes
2198 2885
2199 axPos *= parentRot; 2886 axPos *= parentRot;
2200 part.OffsetPosition = axPos; 2887 part.OffsetPosition = axPos;
2201 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2888 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2889 part.GroupPosition = newPos;
2202 part.OffsetPosition = Vector3.Zero; 2890 part.OffsetPosition = Vector3.Zero;
2203 part.RotationOffset = worldRot; 2891 part.RotationOffset = worldRot;
2204 2892
@@ -2209,7 +2897,7 @@ namespace OpenSim.Region.Framework.Scenes
2209 2897
2210 part.LinkNum = linkNum; 2898 part.LinkNum = linkNum;
2211 2899
2212 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2900 part.OffsetPosition = newPos - AbsolutePosition;
2213 2901
2214 Quaternion rootRotation = m_rootPart.RotationOffset; 2902 Quaternion rootRotation = m_rootPart.RotationOffset;
2215 2903
@@ -2219,7 +2907,7 @@ namespace OpenSim.Region.Framework.Scenes
2219 2907
2220 parentRot = m_rootPart.RotationOffset; 2908 parentRot = m_rootPart.RotationOffset;
2221 oldRot = part.RotationOffset; 2909 oldRot = part.RotationOffset;
2222 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2910 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2223 part.RotationOffset = newRot; 2911 part.RotationOffset = newRot;
2224 2912
2225 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2913 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect);
@@ -2473,8 +3161,31 @@ namespace OpenSim.Region.Framework.Scenes
2473 } 3161 }
2474 } 3162 }
2475 3163
3164/*
3165 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2476 for (int i = 0; i < parts.Length; i++) 3166 for (int i = 0; i < parts.Length; i++)
2477 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3167 {
3168 if (parts[i] != RootPart)
3169 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
3170 }
3171*/
3172 if (parts.Length > 1)
3173 {
3174 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3175
3176 for (int i = 0; i < parts.Length; i++)
3177 {
3178
3179 if (parts[i].UUID != m_rootPart.UUID)
3180 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3181 }
3182
3183 if (m_rootPart.PhysActor != null)
3184 m_rootPart.PhysActor.Building = false;
3185 }
3186 else
3187 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
3188
2478 } 3189 }
2479 } 3190 }
2480 3191
@@ -2487,6 +3198,17 @@ namespace OpenSim.Region.Framework.Scenes
2487 } 3198 }
2488 } 3199 }
2489 3200
3201
3202
3203 /// <summary>
3204 /// Gets the number of parts
3205 /// </summary>
3206 /// <returns></returns>
3207 public int GetPartCount()
3208 {
3209 return Parts.Count();
3210 }
3211
2490 /// <summary> 3212 /// <summary>
2491 /// Update the texture entry for this part 3213 /// Update the texture entry for this part
2492 /// </summary> 3214 /// </summary>
@@ -2548,11 +3270,6 @@ namespace OpenSim.Region.Framework.Scenes
2548 /// <param name="scale"></param> 3270 /// <param name="scale"></param>
2549 public void GroupResize(Vector3 scale) 3271 public void GroupResize(Vector3 scale)
2550 { 3272 {
2551// m_log.DebugFormat(
2552// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2553
2554 RootPart.StoreUndoState(true);
2555
2556 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3273 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2557 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3274 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2558 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3275 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2579,7 +3296,6 @@ namespace OpenSim.Region.Framework.Scenes
2579 SceneObjectPart obPart = parts[i]; 3296 SceneObjectPart obPart = parts[i];
2580 if (obPart.UUID != m_rootPart.UUID) 3297 if (obPart.UUID != m_rootPart.UUID)
2581 { 3298 {
2582// obPart.IgnoreUndoUpdate = true;
2583 Vector3 oldSize = new Vector3(obPart.Scale); 3299 Vector3 oldSize = new Vector3(obPart.Scale);
2584 3300
2585 float f = 1.0f; 3301 float f = 1.0f;
@@ -2643,8 +3359,6 @@ namespace OpenSim.Region.Framework.Scenes
2643 z *= a; 3359 z *= a;
2644 } 3360 }
2645 } 3361 }
2646
2647// obPart.IgnoreUndoUpdate = false;
2648 } 3362 }
2649 } 3363 }
2650 } 3364 }
@@ -2654,9 +3368,7 @@ namespace OpenSim.Region.Framework.Scenes
2654 prevScale.Y *= y; 3368 prevScale.Y *= y;
2655 prevScale.Z *= z; 3369 prevScale.Z *= z;
2656 3370
2657// RootPart.IgnoreUndoUpdate = true;
2658 RootPart.Resize(prevScale); 3371 RootPart.Resize(prevScale);
2659// RootPart.IgnoreUndoUpdate = false;
2660 3372
2661 parts = m_parts.GetArray(); 3373 parts = m_parts.GetArray();
2662 for (int i = 0; i < parts.Length; i++) 3374 for (int i = 0; i < parts.Length; i++)
@@ -2665,8 +3377,6 @@ namespace OpenSim.Region.Framework.Scenes
2665 3377
2666 if (obPart.UUID != m_rootPart.UUID) 3378 if (obPart.UUID != m_rootPart.UUID)
2667 { 3379 {
2668 obPart.IgnoreUndoUpdate = true;
2669
2670 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3380 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2671 currentpos.X *= x; 3381 currentpos.X *= x;
2672 currentpos.Y *= y; 3382 currentpos.Y *= y;
@@ -2679,16 +3389,12 @@ namespace OpenSim.Region.Framework.Scenes
2679 3389
2680 obPart.Resize(newSize); 3390 obPart.Resize(newSize);
2681 obPart.UpdateOffSet(currentpos); 3391 obPart.UpdateOffSet(currentpos);
2682
2683 obPart.IgnoreUndoUpdate = false;
2684 } 3392 }
2685 3393
2686// obPart.IgnoreUndoUpdate = false; 3394 HasGroupChanged = true;
2687// obPart.StoreUndoState(); 3395 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3396 ScheduleGroupForTerseUpdate();
2688 } 3397 }
2689
2690// m_log.DebugFormat(
2691// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2692 } 3398 }
2693 3399
2694 #endregion 3400 #endregion
@@ -2701,14 +3407,6 @@ namespace OpenSim.Region.Framework.Scenes
2701 /// <param name="pos"></param> 3407 /// <param name="pos"></param>
2702 public void UpdateGroupPosition(Vector3 pos) 3408 public void UpdateGroupPosition(Vector3 pos)
2703 { 3409 {
2704// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2705
2706 RootPart.StoreUndoState(true);
2707
2708// SceneObjectPart[] parts = m_parts.GetArray();
2709// for (int i = 0; i < parts.Length; i++)
2710// parts[i].StoreUndoState();
2711
2712 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3410 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2713 { 3411 {
2714 if (IsAttachment) 3412 if (IsAttachment)
@@ -2741,21 +3439,17 @@ namespace OpenSim.Region.Framework.Scenes
2741 /// </summary> 3439 /// </summary>
2742 /// <param name="pos"></param> 3440 /// <param name="pos"></param>
2743 /// <param name="localID"></param> 3441 /// <param name="localID"></param>
3442 ///
3443
2744 public void UpdateSinglePosition(Vector3 pos, uint localID) 3444 public void UpdateSinglePosition(Vector3 pos, uint localID)
2745 { 3445 {
2746 SceneObjectPart part = GetPart(localID); 3446 SceneObjectPart part = GetPart(localID);
2747 3447
2748// SceneObjectPart[] parts = m_parts.GetArray();
2749// for (int i = 0; i < parts.Length; i++)
2750// parts[i].StoreUndoState();
2751
2752 if (part != null) 3448 if (part != null)
2753 { 3449 {
2754// m_log.DebugFormat( 3450// unlock parts position change
2755// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3451 if (m_rootPart.PhysActor != null)
2756 3452 m_rootPart.PhysActor.Building = true;
2757 part.StoreUndoState(false);
2758 part.IgnoreUndoUpdate = true;
2759 3453
2760 if (part.UUID == m_rootPart.UUID) 3454 if (part.UUID == m_rootPart.UUID)
2761 { 3455 {
@@ -2766,8 +3460,10 @@ namespace OpenSim.Region.Framework.Scenes
2766 part.UpdateOffSet(pos); 3460 part.UpdateOffSet(pos);
2767 } 3461 }
2768 3462
3463 if (m_rootPart.PhysActor != null)
3464 m_rootPart.PhysActor.Building = false;
3465
2769 HasGroupChanged = true; 3466 HasGroupChanged = true;
2770 part.IgnoreUndoUpdate = false;
2771 } 3467 }
2772 } 3468 }
2773 3469
@@ -2777,13 +3473,7 @@ namespace OpenSim.Region.Framework.Scenes
2777 /// <param name="pos"></param> 3473 /// <param name="pos"></param>
2778 public void UpdateRootPosition(Vector3 pos) 3474 public void UpdateRootPosition(Vector3 pos)
2779 { 3475 {
2780// m_log.DebugFormat( 3476 // needs to be called with phys building true
2781// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2782
2783// SceneObjectPart[] parts = m_parts.GetArray();
2784// for (int i = 0; i < parts.Length; i++)
2785// parts[i].StoreUndoState();
2786
2787 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3477 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2788 Vector3 oldPos = 3478 Vector3 oldPos =
2789 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3479 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2806,7 +3496,14 @@ namespace OpenSim.Region.Framework.Scenes
2806 AbsolutePosition = newPos; 3496 AbsolutePosition = newPos;
2807 3497
2808 HasGroupChanged = true; 3498 HasGroupChanged = true;
2809 ScheduleGroupForTerseUpdate(); 3499 if (m_rootPart.Undoing)
3500 {
3501 ScheduleGroupForFullUpdate();
3502 }
3503 else
3504 {
3505 ScheduleGroupForTerseUpdate();
3506 }
2810 } 3507 }
2811 3508
2812 #endregion 3509 #endregion
@@ -2819,17 +3516,6 @@ namespace OpenSim.Region.Framework.Scenes
2819 /// <param name="rot"></param> 3516 /// <param name="rot"></param>
2820 public void UpdateGroupRotationR(Quaternion rot) 3517 public void UpdateGroupRotationR(Quaternion rot)
2821 { 3518 {
2822// m_log.DebugFormat(
2823// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2824
2825// SceneObjectPart[] parts = m_parts.GetArray();
2826// for (int i = 0; i < parts.Length; i++)
2827// parts[i].StoreUndoState();
2828
2829 m_rootPart.StoreUndoState(true);
2830
2831 m_rootPart.UpdateRotation(rot);
2832
2833 PhysicsActor actor = m_rootPart.PhysActor; 3519 PhysicsActor actor = m_rootPart.PhysActor;
2834 if (actor != null) 3520 if (actor != null)
2835 { 3521 {
@@ -2848,16 +3534,6 @@ namespace OpenSim.Region.Framework.Scenes
2848 /// <param name="rot"></param> 3534 /// <param name="rot"></param>
2849 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3535 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2850 { 3536 {
2851// m_log.DebugFormat(
2852// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2853
2854// SceneObjectPart[] parts = m_parts.GetArray();
2855// for (int i = 0; i < parts.Length; i++)
2856// parts[i].StoreUndoState();
2857
2858 RootPart.StoreUndoState(true);
2859 RootPart.IgnoreUndoUpdate = true;
2860
2861 m_rootPart.UpdateRotation(rot); 3537 m_rootPart.UpdateRotation(rot);
2862 3538
2863 PhysicsActor actor = m_rootPart.PhysActor; 3539 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2871,8 +3547,6 @@ namespace OpenSim.Region.Framework.Scenes
2871 3547
2872 HasGroupChanged = true; 3548 HasGroupChanged = true;
2873 ScheduleGroupForTerseUpdate(); 3549 ScheduleGroupForTerseUpdate();
2874
2875 RootPart.IgnoreUndoUpdate = false;
2876 } 3550 }
2877 3551
2878 /// <summary> 3552 /// <summary>
@@ -2885,13 +3559,11 @@ namespace OpenSim.Region.Framework.Scenes
2885 SceneObjectPart part = GetPart(localID); 3559 SceneObjectPart part = GetPart(localID);
2886 3560
2887 SceneObjectPart[] parts = m_parts.GetArray(); 3561 SceneObjectPart[] parts = m_parts.GetArray();
2888 for (int i = 0; i < parts.Length; i++)
2889 parts[i].StoreUndoState();
2890 3562
2891 if (part != null) 3563 if (part != null)
2892 { 3564 {
2893// m_log.DebugFormat( 3565 if (m_rootPart.PhysActor != null)
2894// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3566 m_rootPart.PhysActor.Building = true;
2895 3567
2896 if (part.UUID == m_rootPart.UUID) 3568 if (part.UUID == m_rootPart.UUID)
2897 { 3569 {
@@ -2901,6 +3573,9 @@ namespace OpenSim.Region.Framework.Scenes
2901 { 3573 {
2902 part.UpdateRotation(rot); 3574 part.UpdateRotation(rot);
2903 } 3575 }
3576
3577 if (m_rootPart.PhysActor != null)
3578 m_rootPart.PhysActor.Building = false;
2904 } 3579 }
2905 } 3580 }
2906 3581
@@ -2914,12 +3589,8 @@ namespace OpenSim.Region.Framework.Scenes
2914 SceneObjectPart part = GetPart(localID); 3589 SceneObjectPart part = GetPart(localID);
2915 if (part != null) 3590 if (part != null)
2916 { 3591 {
2917// m_log.DebugFormat( 3592 if (m_rootPart.PhysActor != null)
2918// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3593 m_rootPart.PhysActor.Building = true;
2919// part.Name, part.LocalId, rot);
2920
2921 part.StoreUndoState();
2922 part.IgnoreUndoUpdate = true;
2923 3594
2924 if (part.UUID == m_rootPart.UUID) 3595 if (part.UUID == m_rootPart.UUID)
2925 { 3596 {
@@ -2932,7 +3603,8 @@ namespace OpenSim.Region.Framework.Scenes
2932 part.OffsetPosition = pos; 3603 part.OffsetPosition = pos;
2933 } 3604 }
2934 3605
2935 part.IgnoreUndoUpdate = false; 3606 if (m_rootPart.PhysActor != null)
3607 m_rootPart.PhysActor.Building = false;
2936 } 3608 }
2937 } 3609 }
2938 3610
@@ -2942,15 +3614,12 @@ namespace OpenSim.Region.Framework.Scenes
2942 /// <param name="rot"></param> 3614 /// <param name="rot"></param>
2943 public void UpdateRootRotation(Quaternion rot) 3615 public void UpdateRootRotation(Quaternion rot)
2944 { 3616 {
2945// m_log.DebugFormat( 3617 // needs to be called with phys building true
2946// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2947// Name, LocalId, rot);
2948
2949 Quaternion axRot = rot; 3618 Quaternion axRot = rot;
2950 Quaternion oldParentRot = m_rootPart.RotationOffset; 3619 Quaternion oldParentRot = m_rootPart.RotationOffset;
2951 3620
2952 m_rootPart.StoreUndoState(); 3621 //Don't use UpdateRotation because it schedules an update prematurely
2953 m_rootPart.UpdateRotation(rot); 3622 m_rootPart.RotationOffset = rot;
2954 3623
2955 PhysicsActor pa = m_rootPart.PhysActor; 3624 PhysicsActor pa = m_rootPart.PhysActor;
2956 3625
@@ -2966,35 +3635,135 @@ namespace OpenSim.Region.Framework.Scenes
2966 SceneObjectPart prim = parts[i]; 3635 SceneObjectPart prim = parts[i];
2967 if (prim.UUID != m_rootPart.UUID) 3636 if (prim.UUID != m_rootPart.UUID)
2968 { 3637 {
2969 prim.IgnoreUndoUpdate = true; 3638 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3639 NewRot = Quaternion.Inverse(axRot) * NewRot;
3640 prim.RotationOffset = NewRot;
3641
2970 Vector3 axPos = prim.OffsetPosition; 3642 Vector3 axPos = prim.OffsetPosition;
3643
2971 axPos *= oldParentRot; 3644 axPos *= oldParentRot;
2972 axPos *= Quaternion.Inverse(axRot); 3645 axPos *= Quaternion.Inverse(axRot);
2973 prim.OffsetPosition = axPos; 3646 prim.OffsetPosition = axPos;
2974 Quaternion primsRot = prim.RotationOffset; 3647 }
2975 Quaternion newRot = oldParentRot * primsRot; 3648 }
2976 newRot = Quaternion.Inverse(axRot) * newRot;
2977 prim.RotationOffset = newRot;
2978 prim.ScheduleTerseUpdate();
2979 prim.IgnoreUndoUpdate = false;
2980 }
2981 }
2982
2983// for (int i = 0; i < parts.Length; i++)
2984// {
2985// SceneObjectPart childpart = parts[i];
2986// if (childpart != m_rootPart)
2987// {
2988//// childpart.IgnoreUndoUpdate = false;
2989//// childpart.StoreUndoState();
2990// }
2991// }
2992 3649
2993 m_rootPart.ScheduleTerseUpdate(); 3650 HasGroupChanged = true;
3651 ScheduleGroupForFullUpdate();
3652 }
2994 3653
2995// m_log.DebugFormat( 3654 private enum updatetype :int
2996// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3655 {
2997// Name, LocalId, rot); 3656 none = 0,
3657 partterse = 1,
3658 partfull = 2,
3659 groupterse = 3,
3660 groupfull = 4
3661 }
3662
3663 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3664 {
3665 // TODO this still as excessive *.Schedule*Update()s
3666
3667 if (part != null && part.ParentGroup != null)
3668 {
3669 ObjectChangeType change = data.change;
3670 bool togroup = ((change & ObjectChangeType.Group) != 0);
3671 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3672
3673 SceneObjectGroup group = part.ParentGroup;
3674 PhysicsActor pha = group.RootPart.PhysActor;
3675
3676 updatetype updateType = updatetype.none;
3677
3678 if (togroup)
3679 {
3680 // related to group
3681 if ((change & ObjectChangeType.Position) != 0)
3682 {
3683 group.AbsolutePosition = data.position;
3684 updateType = updatetype.groupterse;
3685 }
3686 if ((change & ObjectChangeType.Rotation) != 0)
3687 {
3688 group.RootPart.UpdateRotation(data.rotation);
3689 updateType = updatetype.none;
3690 }
3691 if ((change & ObjectChangeType.Scale) != 0)
3692 {
3693 if (pha != null)
3694 pha.Building = true;
3695
3696 group.GroupResize(data.scale);
3697 updateType = updatetype.none;
3698
3699 if (pha != null)
3700 pha.Building = false;
3701 }
3702 }
3703 else
3704 {
3705 // related to single prim in a link-set ( ie group)
3706 if (pha != null)
3707 pha.Building = true;
3708
3709 // root part is special
3710 // parts offset positions or rotations need to change also
3711
3712 if (part == group.RootPart)
3713 {
3714 if ((change & ObjectChangeType.Position) != 0)
3715 group.UpdateRootPosition(data.position);
3716 if ((change & ObjectChangeType.Rotation) != 0)
3717 group.UpdateRootRotation(data.rotation);
3718 if ((change & ObjectChangeType.Scale) != 0)
3719 part.Resize(data.scale);
3720 }
3721 else
3722 {
3723 if ((change & ObjectChangeType.Position) != 0)
3724 {
3725 part.OffsetPosition = data.position;
3726 updateType = updatetype.partterse;
3727 }
3728 if ((change & ObjectChangeType.Rotation) != 0)
3729 {
3730 part.UpdateRotation(data.rotation);
3731 updateType = updatetype.none;
3732 }
3733 if ((change & ObjectChangeType.Scale) != 0)
3734 {
3735 part.Resize(data.scale);
3736 updateType = updatetype.none;
3737 }
3738 }
3739
3740 if (pha != null)
3741 pha.Building = false;
3742 }
3743
3744 if (updateType != updatetype.none)
3745 {
3746 group.HasGroupChanged = true;
3747
3748 switch (updateType)
3749 {
3750 case updatetype.partterse:
3751 part.ScheduleTerseUpdate();
3752 break;
3753 case updatetype.partfull:
3754 part.ScheduleFullUpdate();
3755 break;
3756 case updatetype.groupterse:
3757 group.ScheduleGroupForTerseUpdate();
3758 break;
3759 case updatetype.groupfull:
3760 group.ScheduleGroupForFullUpdate();
3761 break;
3762 default:
3763 break;
3764 }
3765 }
3766 }
2998 } 3767 }
2999 3768
3000 #endregion 3769 #endregion
@@ -3214,11 +3983,38 @@ namespace OpenSim.Region.Framework.Scenes
3214 } 3983 }
3215 } 3984 }
3216 } 3985 }
3217 3986
3987 public Vector3 GetGeometricCenter()
3988 {
3989 // this is not real geometric center but a average of positions relative to root prim acording to
3990 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
3991 // ignoring tortured prims details since sl also seems to ignore
3992 // so no real use in doing it on physics
3993
3994 Vector3 gc = Vector3.Zero;
3995
3996 int nparts = m_parts.Count;
3997 if (nparts <= 1)
3998 return gc;
3999
4000 SceneObjectPart[] parts = m_parts.GetArray();
4001 nparts = parts.Length; // just in case it changed
4002 if (nparts <= 1)
4003 return gc;
4004
4005 // average all parts positions
4006 for (int i = 0; i < nparts; i++)
4007 gc += parts[i].GetWorldPosition();
4008 gc /= nparts;
4009
4010 // relative to root:
4011 gc -= AbsolutePosition;
4012 return gc;
4013 }
4014
3218 public float GetMass() 4015 public float GetMass()
3219 { 4016 {
3220 float retmass = 0f; 4017 float retmass = 0f;
3221
3222 SceneObjectPart[] parts = m_parts.GetArray(); 4018 SceneObjectPart[] parts = m_parts.GetArray();
3223 for (int i = 0; i < parts.Length; i++) 4019 for (int i = 0; i < parts.Length; i++)
3224 retmass += parts[i].GetMass(); 4020 retmass += parts[i].GetMass();
@@ -3379,6 +4175,14 @@ namespace OpenSim.Region.Framework.Scenes
3379 FromItemID = uuid; 4175 FromItemID = uuid;
3380 } 4176 }
3381 4177
4178 public void ResetOwnerChangeFlag()
4179 {
4180 ForEachPart(delegate(SceneObjectPart part)
4181 {
4182 part.ResetOwnerChangeFlag();
4183 });
4184 }
4185
3382 #endregion 4186 #endregion
3383 } 4187 }
3384} 4188}