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 8e786c1..cb0a57a 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 2676
2014 SceneObjectPart[] ogParts = objectGroup.Parts; 2677 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2021,7 +2684,16 @@ namespace OpenSim.Region.Framework.Scenes
2021 { 2684 {
2022 SceneObjectPart part = ogParts[i]; 2685 SceneObjectPart part = ogParts[i];
2023 if (part.UUID != objectGroup.m_rootPart.UUID) 2686 if (part.UUID != objectGroup.m_rootPart.UUID)
2687 {
2024 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2688 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2689 // let physics know
2690 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2691 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2692 {
2693 part.PhysActor.link(m_rootPart.PhysActor);
2694 this.Scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2695 }
2696 }
2025 part.ClearUndoState(); 2697 part.ClearUndoState();
2026 } 2698 }
2027 } 2699 }
@@ -2030,7 +2702,7 @@ namespace OpenSim.Region.Framework.Scenes
2030 objectGroup.IsDeleted = true; 2702 objectGroup.IsDeleted = true;
2031 2703
2032 objectGroup.m_parts.Clear(); 2704 objectGroup.m_parts.Clear();
2033 2705
2034 // Can't do this yet since backup still makes use of the root part without any synchronization 2706 // Can't do this yet since backup still makes use of the root part without any synchronization
2035// objectGroup.m_rootPart = null; 2707// objectGroup.m_rootPart = null;
2036 2708
@@ -2041,6 +2713,9 @@ namespace OpenSim.Region.Framework.Scenes
2041 // unmoved prims! 2713 // unmoved prims!
2042 ResetChildPrimPhysicsPositions(); 2714 ResetChildPrimPhysicsPositions();
2043 2715
2716 if (m_rootPart.PhysActor != null)
2717 m_rootPart.PhysActor.Building = false;
2718
2044 //HasGroupChanged = true; 2719 //HasGroupChanged = true;
2045 //ScheduleGroupForFullUpdate(); 2720 //ScheduleGroupForFullUpdate();
2046 } 2721 }
@@ -2108,7 +2783,10 @@ namespace OpenSim.Region.Framework.Scenes
2108// m_log.DebugFormat( 2783// m_log.DebugFormat(
2109// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2784// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2110// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2785// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2111 2786
2787 if (m_rootPart.PhysActor != null)
2788 m_rootPart.PhysActor.Building = true;
2789
2112 linkPart.ClearUndoState(); 2790 linkPart.ClearUndoState();
2113 2791
2114 Quaternion worldRot = linkPart.GetWorldRotation(); 2792 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2168,6 +2846,14 @@ namespace OpenSim.Region.Framework.Scenes
2168 2846
2169 // When we delete a group, we currently have to force persist to the database if the object id has changed 2847 // When we delete a group, we currently have to force persist to the database if the object id has changed
2170 // (since delete works by deleting all rows which have a given object id) 2848 // (since delete works by deleting all rows which have a given object id)
2849
2850 // this is as it seems to be in sl now
2851 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2852 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2853
2854 if (m_rootPart.PhysActor != null)
2855 m_rootPart.PhysActor.Building = false;
2856
2171 objectGroup.HasGroupChangedDueToDelink = true; 2857 objectGroup.HasGroupChangedDueToDelink = true;
2172 2858
2173 return objectGroup; 2859 return objectGroup;
@@ -2179,6 +2865,7 @@ namespace OpenSim.Region.Framework.Scenes
2179 /// <param name="objectGroup"></param> 2865 /// <param name="objectGroup"></param>
2180 public virtual void DetachFromBackup() 2866 public virtual void DetachFromBackup()
2181 { 2867 {
2868 m_scene.SceneGraph.FireDetachFromBackup(this);
2182 if (m_isBackedUp && Scene != null) 2869 if (m_isBackedUp && Scene != null)
2183 m_scene.EventManager.OnBackup -= ProcessBackup; 2870 m_scene.EventManager.OnBackup -= ProcessBackup;
2184 2871
@@ -2197,7 +2884,8 @@ namespace OpenSim.Region.Framework.Scenes
2197 2884
2198 axPos *= parentRot; 2885 axPos *= parentRot;
2199 part.OffsetPosition = axPos; 2886 part.OffsetPosition = axPos;
2200 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2887 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2888 part.GroupPosition = newPos;
2201 part.OffsetPosition = Vector3.Zero; 2889 part.OffsetPosition = Vector3.Zero;
2202 part.RotationOffset = worldRot; 2890 part.RotationOffset = worldRot;
2203 2891
@@ -2208,7 +2896,7 @@ namespace OpenSim.Region.Framework.Scenes
2208 2896
2209 part.LinkNum = linkNum; 2897 part.LinkNum = linkNum;
2210 2898
2211 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2899 part.OffsetPosition = newPos - AbsolutePosition;
2212 2900
2213 Quaternion rootRotation = m_rootPart.RotationOffset; 2901 Quaternion rootRotation = m_rootPart.RotationOffset;
2214 2902
@@ -2218,7 +2906,7 @@ namespace OpenSim.Region.Framework.Scenes
2218 2906
2219 parentRot = m_rootPart.RotationOffset; 2907 parentRot = m_rootPart.RotationOffset;
2220 oldRot = part.RotationOffset; 2908 oldRot = part.RotationOffset;
2221 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2909 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2222 part.RotationOffset = newRot; 2910 part.RotationOffset = newRot;
2223 } 2911 }
2224 2912
@@ -2470,8 +3158,31 @@ namespace OpenSim.Region.Framework.Scenes
2470 } 3158 }
2471 } 3159 }
2472 3160
3161/*
3162 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2473 for (int i = 0; i < parts.Length; i++) 3163 for (int i = 0; i < parts.Length; i++)
2474 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3164 {
3165 if (parts[i] != RootPart)
3166 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
3167 }
3168*/
3169 if (parts.Length > 1)
3170 {
3171 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3172
3173 for (int i = 0; i < parts.Length; i++)
3174 {
3175
3176 if (parts[i].UUID != m_rootPart.UUID)
3177 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3178 }
3179
3180 if (m_rootPart.PhysActor != null)
3181 m_rootPart.PhysActor.Building = false;
3182 }
3183 else
3184 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
3185
2475 } 3186 }
2476 } 3187 }
2477 3188
@@ -2484,6 +3195,17 @@ namespace OpenSim.Region.Framework.Scenes
2484 } 3195 }
2485 } 3196 }
2486 3197
3198
3199
3200 /// <summary>
3201 /// Gets the number of parts
3202 /// </summary>
3203 /// <returns></returns>
3204 public int GetPartCount()
3205 {
3206 return Parts.Count();
3207 }
3208
2487 /// <summary> 3209 /// <summary>
2488 /// Update the texture entry for this part 3210 /// Update the texture entry for this part
2489 /// </summary> 3211 /// </summary>
@@ -2545,11 +3267,6 @@ namespace OpenSim.Region.Framework.Scenes
2545 /// <param name="scale"></param> 3267 /// <param name="scale"></param>
2546 public void GroupResize(Vector3 scale) 3268 public void GroupResize(Vector3 scale)
2547 { 3269 {
2548// m_log.DebugFormat(
2549// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2550
2551 RootPart.StoreUndoState(true);
2552
2553 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3270 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2554 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3271 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2555 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3272 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2576,7 +3293,6 @@ namespace OpenSim.Region.Framework.Scenes
2576 SceneObjectPart obPart = parts[i]; 3293 SceneObjectPart obPart = parts[i];
2577 if (obPart.UUID != m_rootPart.UUID) 3294 if (obPart.UUID != m_rootPart.UUID)
2578 { 3295 {
2579// obPart.IgnoreUndoUpdate = true;
2580 Vector3 oldSize = new Vector3(obPart.Scale); 3296 Vector3 oldSize = new Vector3(obPart.Scale);
2581 3297
2582 float f = 1.0f; 3298 float f = 1.0f;
@@ -2640,8 +3356,6 @@ namespace OpenSim.Region.Framework.Scenes
2640 z *= a; 3356 z *= a;
2641 } 3357 }
2642 } 3358 }
2643
2644// obPart.IgnoreUndoUpdate = false;
2645 } 3359 }
2646 } 3360 }
2647 } 3361 }
@@ -2651,9 +3365,7 @@ namespace OpenSim.Region.Framework.Scenes
2651 prevScale.Y *= y; 3365 prevScale.Y *= y;
2652 prevScale.Z *= z; 3366 prevScale.Z *= z;
2653 3367
2654// RootPart.IgnoreUndoUpdate = true;
2655 RootPart.Resize(prevScale); 3368 RootPart.Resize(prevScale);
2656// RootPart.IgnoreUndoUpdate = false;
2657 3369
2658 parts = m_parts.GetArray(); 3370 parts = m_parts.GetArray();
2659 for (int i = 0; i < parts.Length; i++) 3371 for (int i = 0; i < parts.Length; i++)
@@ -2662,8 +3374,6 @@ namespace OpenSim.Region.Framework.Scenes
2662 3374
2663 if (obPart.UUID != m_rootPart.UUID) 3375 if (obPart.UUID != m_rootPart.UUID)
2664 { 3376 {
2665 obPart.IgnoreUndoUpdate = true;
2666
2667 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3377 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2668 currentpos.X *= x; 3378 currentpos.X *= x;
2669 currentpos.Y *= y; 3379 currentpos.Y *= y;
@@ -2676,16 +3386,12 @@ namespace OpenSim.Region.Framework.Scenes
2676 3386
2677 obPart.Resize(newSize); 3387 obPart.Resize(newSize);
2678 obPart.UpdateOffSet(currentpos); 3388 obPart.UpdateOffSet(currentpos);
2679
2680 obPart.IgnoreUndoUpdate = false;
2681 } 3389 }
2682 3390
2683// obPart.IgnoreUndoUpdate = false; 3391 HasGroupChanged = true;
2684// obPart.StoreUndoState(); 3392 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3393 ScheduleGroupForTerseUpdate();
2685 } 3394 }
2686
2687// m_log.DebugFormat(
2688// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2689 } 3395 }
2690 3396
2691 #endregion 3397 #endregion
@@ -2698,14 +3404,6 @@ namespace OpenSim.Region.Framework.Scenes
2698 /// <param name="pos"></param> 3404 /// <param name="pos"></param>
2699 public void UpdateGroupPosition(Vector3 pos) 3405 public void UpdateGroupPosition(Vector3 pos)
2700 { 3406 {
2701// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2702
2703 RootPart.StoreUndoState(true);
2704
2705// SceneObjectPart[] parts = m_parts.GetArray();
2706// for (int i = 0; i < parts.Length; i++)
2707// parts[i].StoreUndoState();
2708
2709 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3407 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2710 { 3408 {
2711 if (IsAttachment) 3409 if (IsAttachment)
@@ -2738,21 +3436,17 @@ namespace OpenSim.Region.Framework.Scenes
2738 /// </summary> 3436 /// </summary>
2739 /// <param name="pos"></param> 3437 /// <param name="pos"></param>
2740 /// <param name="localID"></param> 3438 /// <param name="localID"></param>
3439 ///
3440
2741 public void UpdateSinglePosition(Vector3 pos, uint localID) 3441 public void UpdateSinglePosition(Vector3 pos, uint localID)
2742 { 3442 {
2743 SceneObjectPart part = GetPart(localID); 3443 SceneObjectPart part = GetPart(localID);
2744 3444
2745// SceneObjectPart[] parts = m_parts.GetArray();
2746// for (int i = 0; i < parts.Length; i++)
2747// parts[i].StoreUndoState();
2748
2749 if (part != null) 3445 if (part != null)
2750 { 3446 {
2751// m_log.DebugFormat( 3447// unlock parts position change
2752// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3448 if (m_rootPart.PhysActor != null)
2753 3449 m_rootPart.PhysActor.Building = true;
2754 part.StoreUndoState(false);
2755 part.IgnoreUndoUpdate = true;
2756 3450
2757 if (part.UUID == m_rootPart.UUID) 3451 if (part.UUID == m_rootPart.UUID)
2758 { 3452 {
@@ -2763,8 +3457,10 @@ namespace OpenSim.Region.Framework.Scenes
2763 part.UpdateOffSet(pos); 3457 part.UpdateOffSet(pos);
2764 } 3458 }
2765 3459
3460 if (m_rootPart.PhysActor != null)
3461 m_rootPart.PhysActor.Building = false;
3462
2766 HasGroupChanged = true; 3463 HasGroupChanged = true;
2767 part.IgnoreUndoUpdate = false;
2768 } 3464 }
2769 } 3465 }
2770 3466
@@ -2774,13 +3470,7 @@ namespace OpenSim.Region.Framework.Scenes
2774 /// <param name="pos"></param> 3470 /// <param name="pos"></param>
2775 public void UpdateRootPosition(Vector3 pos) 3471 public void UpdateRootPosition(Vector3 pos)
2776 { 3472 {
2777// m_log.DebugFormat( 3473 // needs to be called with phys building true
2778// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2779
2780// SceneObjectPart[] parts = m_parts.GetArray();
2781// for (int i = 0; i < parts.Length; i++)
2782// parts[i].StoreUndoState();
2783
2784 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3474 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2785 Vector3 oldPos = 3475 Vector3 oldPos =
2786 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3476 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2803,7 +3493,14 @@ namespace OpenSim.Region.Framework.Scenes
2803 AbsolutePosition = newPos; 3493 AbsolutePosition = newPos;
2804 3494
2805 HasGroupChanged = true; 3495 HasGroupChanged = true;
2806 ScheduleGroupForTerseUpdate(); 3496 if (m_rootPart.Undoing)
3497 {
3498 ScheduleGroupForFullUpdate();
3499 }
3500 else
3501 {
3502 ScheduleGroupForTerseUpdate();
3503 }
2807 } 3504 }
2808 3505
2809 #endregion 3506 #endregion
@@ -2816,17 +3513,6 @@ namespace OpenSim.Region.Framework.Scenes
2816 /// <param name="rot"></param> 3513 /// <param name="rot"></param>
2817 public void UpdateGroupRotationR(Quaternion rot) 3514 public void UpdateGroupRotationR(Quaternion rot)
2818 { 3515 {
2819// m_log.DebugFormat(
2820// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2821
2822// SceneObjectPart[] parts = m_parts.GetArray();
2823// for (int i = 0; i < parts.Length; i++)
2824// parts[i].StoreUndoState();
2825
2826 m_rootPart.StoreUndoState(true);
2827
2828 m_rootPart.UpdateRotation(rot);
2829
2830 PhysicsActor actor = m_rootPart.PhysActor; 3516 PhysicsActor actor = m_rootPart.PhysActor;
2831 if (actor != null) 3517 if (actor != null)
2832 { 3518 {
@@ -2845,16 +3531,6 @@ namespace OpenSim.Region.Framework.Scenes
2845 /// <param name="rot"></param> 3531 /// <param name="rot"></param>
2846 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3532 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2847 { 3533 {
2848// m_log.DebugFormat(
2849// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2850
2851// SceneObjectPart[] parts = m_parts.GetArray();
2852// for (int i = 0; i < parts.Length; i++)
2853// parts[i].StoreUndoState();
2854
2855 RootPart.StoreUndoState(true);
2856 RootPart.IgnoreUndoUpdate = true;
2857
2858 m_rootPart.UpdateRotation(rot); 3534 m_rootPart.UpdateRotation(rot);
2859 3535
2860 PhysicsActor actor = m_rootPart.PhysActor; 3536 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2868,8 +3544,6 @@ namespace OpenSim.Region.Framework.Scenes
2868 3544
2869 HasGroupChanged = true; 3545 HasGroupChanged = true;
2870 ScheduleGroupForTerseUpdate(); 3546 ScheduleGroupForTerseUpdate();
2871
2872 RootPart.IgnoreUndoUpdate = false;
2873 } 3547 }
2874 3548
2875 /// <summary> 3549 /// <summary>
@@ -2882,13 +3556,11 @@ namespace OpenSim.Region.Framework.Scenes
2882 SceneObjectPart part = GetPart(localID); 3556 SceneObjectPart part = GetPart(localID);
2883 3557
2884 SceneObjectPart[] parts = m_parts.GetArray(); 3558 SceneObjectPart[] parts = m_parts.GetArray();
2885 for (int i = 0; i < parts.Length; i++)
2886 parts[i].StoreUndoState();
2887 3559
2888 if (part != null) 3560 if (part != null)
2889 { 3561 {
2890// m_log.DebugFormat( 3562 if (m_rootPart.PhysActor != null)
2891// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3563 m_rootPart.PhysActor.Building = true;
2892 3564
2893 if (part.UUID == m_rootPart.UUID) 3565 if (part.UUID == m_rootPart.UUID)
2894 { 3566 {
@@ -2898,6 +3570,9 @@ namespace OpenSim.Region.Framework.Scenes
2898 { 3570 {
2899 part.UpdateRotation(rot); 3571 part.UpdateRotation(rot);
2900 } 3572 }
3573
3574 if (m_rootPart.PhysActor != null)
3575 m_rootPart.PhysActor.Building = false;
2901 } 3576 }
2902 } 3577 }
2903 3578
@@ -2911,12 +3586,8 @@ namespace OpenSim.Region.Framework.Scenes
2911 SceneObjectPart part = GetPart(localID); 3586 SceneObjectPart part = GetPart(localID);
2912 if (part != null) 3587 if (part != null)
2913 { 3588 {
2914// m_log.DebugFormat( 3589 if (m_rootPart.PhysActor != null)
2915// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3590 m_rootPart.PhysActor.Building = true;
2916// part.Name, part.LocalId, rot);
2917
2918 part.StoreUndoState();
2919 part.IgnoreUndoUpdate = true;
2920 3591
2921 if (part.UUID == m_rootPart.UUID) 3592 if (part.UUID == m_rootPart.UUID)
2922 { 3593 {
@@ -2929,7 +3600,8 @@ namespace OpenSim.Region.Framework.Scenes
2929 part.OffsetPosition = pos; 3600 part.OffsetPosition = pos;
2930 } 3601 }
2931 3602
2932 part.IgnoreUndoUpdate = false; 3603 if (m_rootPart.PhysActor != null)
3604 m_rootPart.PhysActor.Building = false;
2933 } 3605 }
2934 } 3606 }
2935 3607
@@ -2939,15 +3611,12 @@ namespace OpenSim.Region.Framework.Scenes
2939 /// <param name="rot"></param> 3611 /// <param name="rot"></param>
2940 public void UpdateRootRotation(Quaternion rot) 3612 public void UpdateRootRotation(Quaternion rot)
2941 { 3613 {
2942// m_log.DebugFormat( 3614 // needs to be called with phys building true
2943// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2944// Name, LocalId, rot);
2945
2946 Quaternion axRot = rot; 3615 Quaternion axRot = rot;
2947 Quaternion oldParentRot = m_rootPart.RotationOffset; 3616 Quaternion oldParentRot = m_rootPart.RotationOffset;
2948 3617
2949 m_rootPart.StoreUndoState(); 3618 //Don't use UpdateRotation because it schedules an update prematurely
2950 m_rootPart.UpdateRotation(rot); 3619 m_rootPart.RotationOffset = rot;
2951 3620
2952 PhysicsActor pa = m_rootPart.PhysActor; 3621 PhysicsActor pa = m_rootPart.PhysActor;
2953 3622
@@ -2963,35 +3632,135 @@ namespace OpenSim.Region.Framework.Scenes
2963 SceneObjectPart prim = parts[i]; 3632 SceneObjectPart prim = parts[i];
2964 if (prim.UUID != m_rootPart.UUID) 3633 if (prim.UUID != m_rootPart.UUID)
2965 { 3634 {
2966 prim.IgnoreUndoUpdate = true; 3635 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3636 NewRot = Quaternion.Inverse(axRot) * NewRot;
3637 prim.RotationOffset = NewRot;
3638
2967 Vector3 axPos = prim.OffsetPosition; 3639 Vector3 axPos = prim.OffsetPosition;
3640
2968 axPos *= oldParentRot; 3641 axPos *= oldParentRot;
2969 axPos *= Quaternion.Inverse(axRot); 3642 axPos *= Quaternion.Inverse(axRot);
2970 prim.OffsetPosition = axPos; 3643 prim.OffsetPosition = axPos;
2971 Quaternion primsRot = prim.RotationOffset; 3644 }
2972 Quaternion newRot = oldParentRot * primsRot; 3645 }
2973 newRot = Quaternion.Inverse(axRot) * newRot;
2974 prim.RotationOffset = newRot;
2975 prim.ScheduleTerseUpdate();
2976 prim.IgnoreUndoUpdate = false;
2977 }
2978 }
2979
2980// for (int i = 0; i < parts.Length; i++)
2981// {
2982// SceneObjectPart childpart = parts[i];
2983// if (childpart != m_rootPart)
2984// {
2985//// childpart.IgnoreUndoUpdate = false;
2986//// childpart.StoreUndoState();
2987// }
2988// }
2989 3646
2990 m_rootPart.ScheduleTerseUpdate(); 3647 HasGroupChanged = true;
3648 ScheduleGroupForFullUpdate();
3649 }
2991 3650
2992// m_log.DebugFormat( 3651 private enum updatetype :int
2993// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3652 {
2994// Name, LocalId, rot); 3653 none = 0,
3654 partterse = 1,
3655 partfull = 2,
3656 groupterse = 3,
3657 groupfull = 4
3658 }
3659
3660 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3661 {
3662 // TODO this still as excessive *.Schedule*Update()s
3663
3664 if (part != null && part.ParentGroup != null)
3665 {
3666 ObjectChangeType change = data.change;
3667 bool togroup = ((change & ObjectChangeType.Group) != 0);
3668 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3669
3670 SceneObjectGroup group = part.ParentGroup;
3671 PhysicsActor pha = group.RootPart.PhysActor;
3672
3673 updatetype updateType = updatetype.none;
3674
3675 if (togroup)
3676 {
3677 // related to group
3678 if ((change & ObjectChangeType.Position) != 0)
3679 {
3680 group.AbsolutePosition = data.position;
3681 updateType = updatetype.groupterse;
3682 }
3683 if ((change & ObjectChangeType.Rotation) != 0)
3684 {
3685 group.RootPart.UpdateRotation(data.rotation);
3686 updateType = updatetype.none;
3687 }
3688 if ((change & ObjectChangeType.Scale) != 0)
3689 {
3690 if (pha != null)
3691 pha.Building = true;
3692
3693 group.GroupResize(data.scale);
3694 updateType = updatetype.none;
3695
3696 if (pha != null)
3697 pha.Building = false;
3698 }
3699 }
3700 else
3701 {
3702 // related to single prim in a link-set ( ie group)
3703 if (pha != null)
3704 pha.Building = true;
3705
3706 // root part is special
3707 // parts offset positions or rotations need to change also
3708
3709 if (part == group.RootPart)
3710 {
3711 if ((change & ObjectChangeType.Position) != 0)
3712 group.UpdateRootPosition(data.position);
3713 if ((change & ObjectChangeType.Rotation) != 0)
3714 group.UpdateRootRotation(data.rotation);
3715 if ((change & ObjectChangeType.Scale) != 0)
3716 part.Resize(data.scale);
3717 }
3718 else
3719 {
3720 if ((change & ObjectChangeType.Position) != 0)
3721 {
3722 part.OffsetPosition = data.position;
3723 updateType = updatetype.partterse;
3724 }
3725 if ((change & ObjectChangeType.Rotation) != 0)
3726 {
3727 part.UpdateRotation(data.rotation);
3728 updateType = updatetype.none;
3729 }
3730 if ((change & ObjectChangeType.Scale) != 0)
3731 {
3732 part.Resize(data.scale);
3733 updateType = updatetype.none;
3734 }
3735 }
3736
3737 if (pha != null)
3738 pha.Building = false;
3739 }
3740
3741 if (updateType != updatetype.none)
3742 {
3743 group.HasGroupChanged = true;
3744
3745 switch (updateType)
3746 {
3747 case updatetype.partterse:
3748 part.ScheduleTerseUpdate();
3749 break;
3750 case updatetype.partfull:
3751 part.ScheduleFullUpdate();
3752 break;
3753 case updatetype.groupterse:
3754 group.ScheduleGroupForTerseUpdate();
3755 break;
3756 case updatetype.groupfull:
3757 group.ScheduleGroupForFullUpdate();
3758 break;
3759 default:
3760 break;
3761 }
3762 }
3763 }
2995 } 3764 }
2996 3765
2997 #endregion 3766 #endregion
@@ -3211,11 +3980,38 @@ namespace OpenSim.Region.Framework.Scenes
3211 } 3980 }
3212 } 3981 }
3213 } 3982 }
3214 3983
3984 public Vector3 GetGeometricCenter()
3985 {
3986 // this is not real geometric center but a average of positions relative to root prim acording to
3987 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
3988 // ignoring tortured prims details since sl also seems to ignore
3989 // so no real use in doing it on physics
3990
3991 Vector3 gc = Vector3.Zero;
3992
3993 int nparts = m_parts.Count;
3994 if (nparts <= 1)
3995 return gc;
3996
3997 SceneObjectPart[] parts = m_parts.GetArray();
3998 nparts = parts.Length; // just in case it changed
3999 if (nparts <= 1)
4000 return gc;
4001
4002 // average all parts positions
4003 for (int i = 0; i < nparts; i++)
4004 gc += parts[i].GetWorldPosition();
4005 gc /= nparts;
4006
4007 // relative to root:
4008 gc -= AbsolutePosition;
4009 return gc;
4010 }
4011
3215 public float GetMass() 4012 public float GetMass()
3216 { 4013 {
3217 float retmass = 0f; 4014 float retmass = 0f;
3218
3219 SceneObjectPart[] parts = m_parts.GetArray(); 4015 SceneObjectPart[] parts = m_parts.GetArray();
3220 for (int i = 0; i < parts.Length; i++) 4016 for (int i = 0; i < parts.Length; i++)
3221 retmass += parts[i].GetMass(); 4017 retmass += parts[i].GetMass();
@@ -3376,6 +4172,14 @@ namespace OpenSim.Region.Framework.Scenes
3376 FromItemID = uuid; 4172 FromItemID = uuid;
3377 } 4173 }
3378 4174
4175 public void ResetOwnerChangeFlag()
4176 {
4177 ForEachPart(delegate(SceneObjectPart part)
4178 {
4179 part.ResetOwnerChangeFlag();
4180 });
4181 }
4182
3379 #endregion 4183 #endregion
3380 } 4184 }
3381} 4185}