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.cs1210
1 files changed, 1004 insertions, 206 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 8e786c1..7bd6c11 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,6 +1923,20 @@ 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);
@@ -1384,6 +1954,11 @@ namespace OpenSim.Region.Framework.Scenes
1384 1954
1385 backup_group.ForEachPart(delegate(SceneObjectPart part) 1955 backup_group.ForEachPart(delegate(SceneObjectPart part)
1386 { 1956 {
1957 if (part.KeyframeMotion != null)
1958 {
1959 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
1960 part.KeyframeMotion.UpdateSceneObject(this);
1961 }
1387 part.Inventory.ProcessInventoryBackup(datastore); 1962 part.Inventory.ProcessInventoryBackup(datastore);
1388 }); 1963 });
1389 1964
@@ -1436,6 +2011,7 @@ namespace OpenSim.Region.Framework.Scenes
1436 /// <returns></returns> 2011 /// <returns></returns>
1437 public SceneObjectGroup Copy(bool userExposed) 2012 public SceneObjectGroup Copy(bool userExposed)
1438 { 2013 {
2014 m_dupeInProgress = true;
1439 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2015 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1440 dupe.m_isBackedUp = false; 2016 dupe.m_isBackedUp = false;
1441 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2017 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1450,7 +2026,7 @@ namespace OpenSim.Region.Framework.Scenes
1450 // This is only necessary when userExposed is false! 2026 // This is only necessary when userExposed is false!
1451 2027
1452 bool previousAttachmentStatus = dupe.IsAttachment; 2028 bool previousAttachmentStatus = dupe.IsAttachment;
1453 2029
1454 if (!userExposed) 2030 if (!userExposed)
1455 dupe.IsAttachment = true; 2031 dupe.IsAttachment = true;
1456 2032
@@ -1468,11 +2044,11 @@ namespace OpenSim.Region.Framework.Scenes
1468 dupe.m_rootPart.TrimPermissions(); 2044 dupe.m_rootPart.TrimPermissions();
1469 2045
1470 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2046 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1471 2047
1472 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2048 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1473 { 2049 {
1474 return p1.LinkNum.CompareTo(p2.LinkNum); 2050 return p1.LinkNum.CompareTo(p2.LinkNum);
1475 } 2051 }
1476 ); 2052 );
1477 2053
1478 foreach (SceneObjectPart part in partList) 2054 foreach (SceneObjectPart part in partList)
@@ -1482,41 +2058,53 @@ namespace OpenSim.Region.Framework.Scenes
1482 { 2058 {
1483 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2059 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1484 newPart.LinkNum = part.LinkNum; 2060 newPart.LinkNum = part.LinkNum;
1485 } 2061 if (userExposed)
2062 newPart.ParentID = dupe.m_rootPart.LocalId;
2063 }
1486 else 2064 else
1487 { 2065 {
1488 newPart = dupe.m_rootPart; 2066 newPart = dupe.m_rootPart;
1489 } 2067 }
2068/*
2069 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2070 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1490 2071
1491 // Need to duplicate the physics actor as well 2072 // Need to duplicate the physics actor as well
1492 PhysicsActor originalPartPa = part.PhysActor; 2073 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1493 if (originalPartPa != null && userExposed)
1494 { 2074 {
1495 PrimitiveBaseShape pbs = newPart.Shape; 2075 PrimitiveBaseShape pbs = newPart.Shape;
1496
1497 newPart.PhysActor 2076 newPart.PhysActor
1498 = m_scene.PhysicsScene.AddPrimShape( 2077 = m_scene.PhysicsScene.AddPrimShape(
1499 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2078 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1500 pbs, 2079 pbs,
1501 newPart.AbsolutePosition, 2080 newPart.AbsolutePosition,
1502 newPart.Scale, 2081 newPart.Scale,
1503 newPart.RotationOffset, 2082 newPart.GetWorldRotation(),
1504 originalPartPa.IsPhysical, 2083 isphys,
2084 isphan,
1505 newPart.LocalId); 2085 newPart.LocalId);
1506 2086
1507 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2087 newPart.DoPhysicsPropertyUpdate(isphys, true);
1508 } 2088 */
2089 if (userExposed)
2090 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2091// }
1509 } 2092 }
1510 2093
1511 if (userExposed) 2094 if (userExposed)
1512 { 2095 {
1513 dupe.UpdateParentIDs(); 2096// done above dupe.UpdateParentIDs();
2097
2098 if (dupe.m_rootPart.PhysActor != null)
2099 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2100
1514 dupe.HasGroupChanged = true; 2101 dupe.HasGroupChanged = true;
1515 dupe.AttachToBackup(); 2102 dupe.AttachToBackup();
1516 2103
1517 ScheduleGroupForFullUpdate(); 2104 ScheduleGroupForFullUpdate();
1518 } 2105 }
1519 2106
2107 m_dupeInProgress = false;
1520 return dupe; 2108 return dupe;
1521 } 2109 }
1522 2110
@@ -1528,11 +2116,24 @@ namespace OpenSim.Region.Framework.Scenes
1528 /// <param name="cGroupID"></param> 2116 /// <param name="cGroupID"></param>
1529 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2117 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1530 { 2118 {
1531 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2119 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2120 // give newpart a new local ID lettng old part keep same
2121 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2122 newpart.LocalId = m_scene.AllocateLocalId();
2123
2124 SetRootPart(newpart);
2125 if (userExposed)
2126 RootPart.Velocity = Vector3.Zero; // In case source is moving
1532 } 2127 }
1533 2128
1534 public void ScriptSetPhysicsStatus(bool usePhysics) 2129 public void ScriptSetPhysicsStatus(bool usePhysics)
1535 { 2130 {
2131 if (usePhysics)
2132 {
2133 if (RootPart.KeyframeMotion != null)
2134 RootPart.KeyframeMotion.Stop();
2135 RootPart.KeyframeMotion = null;
2136 }
1536 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2137 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1537 } 2138 }
1538 2139
@@ -1586,7 +2187,7 @@ namespace OpenSim.Region.Framework.Scenes
1586 } 2187 }
1587 } 2188 }
1588 2189
1589 public void applyAngularImpulse(Vector3 impulse) 2190 public void ApplyAngularImpulse(Vector3 impulse)
1590 { 2191 {
1591 PhysicsActor pa = RootPart.PhysActor; 2192 PhysicsActor pa = RootPart.PhysActor;
1592 2193
@@ -1600,36 +2201,12 @@ namespace OpenSim.Region.Framework.Scenes
1600 } 2201 }
1601 } 2202 }
1602 2203
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() 2204 public Vector3 GetTorque()
1618 { 2205 {
1619 PhysicsActor pa = RootPart.PhysActor; 2206 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 } 2207 }
1632 2208
2209 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1633 public void moveToTarget(Vector3 target, float tau) 2210 public void moveToTarget(Vector3 target, float tau)
1634 { 2211 {
1635 if (IsAttachment) 2212 if (IsAttachment)
@@ -1661,6 +2238,46 @@ namespace OpenSim.Region.Framework.Scenes
1661 pa.PIDActive = false; 2238 pa.PIDActive = false;
1662 } 2239 }
1663 2240
2241 public void rotLookAt(Quaternion target, float strength, float damping)
2242 {
2243 SceneObjectPart rootpart = m_rootPart;
2244 if (rootpart != null)
2245 {
2246 if (IsAttachment)
2247 {
2248 /*
2249 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2250 if (avatar != null)
2251 {
2252 Rotate the Av?
2253 } */
2254 }
2255 else
2256 {
2257 if (rootpart.PhysActor != null)
2258 { // APID must be implemented in your physics system for this to function.
2259 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2260 rootpart.PhysActor.APIDStrength = strength;
2261 rootpart.PhysActor.APIDDamping = damping;
2262 rootpart.PhysActor.APIDActive = true;
2263 }
2264 }
2265 }
2266 }
2267
2268 public void stopLookAt()
2269 {
2270 SceneObjectPart rootpart = m_rootPart;
2271 if (rootpart != null)
2272 {
2273 if (rootpart.PhysActor != null)
2274 { // APID must be implemented in your physics system for this to function.
2275 rootpart.PhysActor.APIDActive = false;
2276 }
2277 }
2278
2279 }
2280
1664 /// <summary> 2281 /// <summary>
1665 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2282 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1666 /// </summary> 2283 /// </summary>
@@ -1717,7 +2334,12 @@ namespace OpenSim.Region.Framework.Scenes
1717 /// <param name="cGroupID"></param> 2334 /// <param name="cGroupID"></param>
1718 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2335 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1719 { 2336 {
1720 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2337 // give new ID to the new part, letting old keep original
2338 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2339 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2340 newPart.LocalId = m_scene.AllocateLocalId();
2341 newPart.SetParent(this);
2342
1721 AddPart(newPart); 2343 AddPart(newPart);
1722 2344
1723 SetPartAsNonRoot(newPart); 2345 SetPartAsNonRoot(newPart);
@@ -1846,11 +2468,11 @@ namespace OpenSim.Region.Framework.Scenes
1846 /// Immediately send a full update for this scene object. 2468 /// Immediately send a full update for this scene object.
1847 /// </summary> 2469 /// </summary>
1848 public void SendGroupFullUpdate() 2470 public void SendGroupFullUpdate()
1849 { 2471 {
1850 if (IsDeleted) 2472 if (IsDeleted)
1851 return; 2473 return;
1852 2474
1853// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2475// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1854 2476
1855 RootPart.SendFullUpdateToAllClients(); 2477 RootPart.SendFullUpdateToAllClients();
1856 2478
@@ -1969,6 +2591,11 @@ namespace OpenSim.Region.Framework.Scenes
1969 /// <param name="objectGroup">The group of prims which should be linked to this group</param> 2591 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1970 public void LinkToGroup(SceneObjectGroup objectGroup) 2592 public void LinkToGroup(SceneObjectGroup objectGroup)
1971 { 2593 {
2594 LinkToGroup(objectGroup, false);
2595 }
2596
2597 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2598 {
1972// m_log.DebugFormat( 2599// m_log.DebugFormat(
1973// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}", 2600// "[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); 2601// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
@@ -1979,6 +2606,15 @@ namespace OpenSim.Region.Framework.Scenes
1979 2606
1980 SceneObjectPart linkPart = objectGroup.m_rootPart; 2607 SceneObjectPart linkPart = objectGroup.m_rootPart;
1981 2608
2609 if (m_rootPart.PhysActor != null)
2610 m_rootPart.PhysActor.Building = true;
2611 if (linkPart.PhysActor != null)
2612 linkPart.PhysActor.Building = true;
2613
2614 // physics flags from group to be applied to linked parts
2615 bool grpusephys = UsesPhysics;
2616 bool grptemporary = IsTemporary;
2617
1982 Vector3 oldGroupPosition = linkPart.GroupPosition; 2618 Vector3 oldGroupPosition = linkPart.GroupPosition;
1983 Quaternion oldRootRotation = linkPart.RotationOffset; 2619 Quaternion oldRootRotation = linkPart.RotationOffset;
1984 2620
@@ -2002,13 +2638,34 @@ namespace OpenSim.Region.Framework.Scenes
2002 2638
2003 lock (m_parts.SyncRoot) 2639 lock (m_parts.SyncRoot)
2004 { 2640 {
2005 int linkNum = PrimCount + 1; 2641 int linkNum;
2642 if (insert)
2643 {
2644 linkNum = 2;
2645 foreach (SceneObjectPart part in Parts)
2646 {
2647 if (part.LinkNum > 1)
2648 part.LinkNum++;
2649 }
2650 }
2651 else
2652 {
2653 linkNum = PrimCount + 1;
2654 }
2006 2655
2007 m_parts.Add(linkPart.UUID, linkPart); 2656 m_parts.Add(linkPart.UUID, linkPart);
2008 2657
2009 linkPart.SetParent(this); 2658 linkPart.SetParent(this);
2010 linkPart.CreateSelected = true; 2659 linkPart.CreateSelected = true;
2011 2660
2661 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2662 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2663 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2664 {
2665 linkPart.PhysActor.link(m_rootPart.PhysActor);
2666 this.Scene.PhysicsScene.AddPhysicsActorTaint(linkPart.PhysActor);
2667 }
2668
2012 linkPart.LinkNum = linkNum++; 2669 linkPart.LinkNum = linkNum++;
2013 2670
2014 SceneObjectPart[] ogParts = objectGroup.Parts; 2671 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2021,7 +2678,16 @@ namespace OpenSim.Region.Framework.Scenes
2021 { 2678 {
2022 SceneObjectPart part = ogParts[i]; 2679 SceneObjectPart part = ogParts[i];
2023 if (part.UUID != objectGroup.m_rootPart.UUID) 2680 if (part.UUID != objectGroup.m_rootPart.UUID)
2681 {
2024 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2682 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2683 // let physics know
2684 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2685 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2686 {
2687 part.PhysActor.link(m_rootPart.PhysActor);
2688 this.Scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2689 }
2690 }
2025 part.ClearUndoState(); 2691 part.ClearUndoState();
2026 } 2692 }
2027 } 2693 }
@@ -2030,7 +2696,7 @@ namespace OpenSim.Region.Framework.Scenes
2030 objectGroup.IsDeleted = true; 2696 objectGroup.IsDeleted = true;
2031 2697
2032 objectGroup.m_parts.Clear(); 2698 objectGroup.m_parts.Clear();
2033 2699
2034 // Can't do this yet since backup still makes use of the root part without any synchronization 2700 // Can't do this yet since backup still makes use of the root part without any synchronization
2035// objectGroup.m_rootPart = null; 2701// objectGroup.m_rootPart = null;
2036 2702
@@ -2041,6 +2707,9 @@ namespace OpenSim.Region.Framework.Scenes
2041 // unmoved prims! 2707 // unmoved prims!
2042 ResetChildPrimPhysicsPositions(); 2708 ResetChildPrimPhysicsPositions();
2043 2709
2710 if (m_rootPart.PhysActor != null)
2711 m_rootPart.PhysActor.Building = false;
2712
2044 //HasGroupChanged = true; 2713 //HasGroupChanged = true;
2045 //ScheduleGroupForFullUpdate(); 2714 //ScheduleGroupForFullUpdate();
2046 } 2715 }
@@ -2108,7 +2777,10 @@ namespace OpenSim.Region.Framework.Scenes
2108// m_log.DebugFormat( 2777// m_log.DebugFormat(
2109// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2778// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2110// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2779// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2111 2780
2781 if (m_rootPart.PhysActor != null)
2782 m_rootPart.PhysActor.Building = true;
2783
2112 linkPart.ClearUndoState(); 2784 linkPart.ClearUndoState();
2113 2785
2114 Quaternion worldRot = linkPart.GetWorldRotation(); 2786 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2168,6 +2840,14 @@ namespace OpenSim.Region.Framework.Scenes
2168 2840
2169 // When we delete a group, we currently have to force persist to the database if the object id has changed 2841 // 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) 2842 // (since delete works by deleting all rows which have a given object id)
2843
2844 // this is as it seems to be in sl now
2845 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2846 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2847
2848 if (m_rootPart.PhysActor != null)
2849 m_rootPart.PhysActor.Building = false;
2850
2171 objectGroup.HasGroupChangedDueToDelink = true; 2851 objectGroup.HasGroupChangedDueToDelink = true;
2172 2852
2173 return objectGroup; 2853 return objectGroup;
@@ -2179,6 +2859,7 @@ namespace OpenSim.Region.Framework.Scenes
2179 /// <param name="objectGroup"></param> 2859 /// <param name="objectGroup"></param>
2180 public virtual void DetachFromBackup() 2860 public virtual void DetachFromBackup()
2181 { 2861 {
2862 m_scene.SceneGraph.FireDetachFromBackup(this);
2182 if (m_isBackedUp && Scene != null) 2863 if (m_isBackedUp && Scene != null)
2183 m_scene.EventManager.OnBackup -= ProcessBackup; 2864 m_scene.EventManager.OnBackup -= ProcessBackup;
2184 2865
@@ -2197,7 +2878,8 @@ namespace OpenSim.Region.Framework.Scenes
2197 2878
2198 axPos *= parentRot; 2879 axPos *= parentRot;
2199 part.OffsetPosition = axPos; 2880 part.OffsetPosition = axPos;
2200 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2881 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2882 part.GroupPosition = newPos;
2201 part.OffsetPosition = Vector3.Zero; 2883 part.OffsetPosition = Vector3.Zero;
2202 part.RotationOffset = worldRot; 2884 part.RotationOffset = worldRot;
2203 2885
@@ -2208,7 +2890,7 @@ namespace OpenSim.Region.Framework.Scenes
2208 2890
2209 part.LinkNum = linkNum; 2891 part.LinkNum = linkNum;
2210 2892
2211 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2893 part.OffsetPosition = newPos - AbsolutePosition;
2212 2894
2213 Quaternion rootRotation = m_rootPart.RotationOffset; 2895 Quaternion rootRotation = m_rootPart.RotationOffset;
2214 2896
@@ -2218,7 +2900,7 @@ namespace OpenSim.Region.Framework.Scenes
2218 2900
2219 parentRot = m_rootPart.RotationOffset; 2901 parentRot = m_rootPart.RotationOffset;
2220 oldRot = part.RotationOffset; 2902 oldRot = part.RotationOffset;
2221 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2903 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2222 part.RotationOffset = newRot; 2904 part.RotationOffset = newRot;
2223 } 2905 }
2224 2906
@@ -2470,8 +3152,31 @@ namespace OpenSim.Region.Framework.Scenes
2470 } 3152 }
2471 } 3153 }
2472 3154
3155/*
3156 RootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2473 for (int i = 0; i < parts.Length; i++) 3157 for (int i = 0; i < parts.Length; i++)
2474 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3158 {
3159 if (parts[i] != RootPart)
3160 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
3161 }
3162*/
3163 if (parts.Length > 1)
3164 {
3165 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3166
3167 for (int i = 0; i < parts.Length; i++)
3168 {
3169
3170 if (parts[i].UUID != m_rootPart.UUID)
3171 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3172 }
3173
3174 if (m_rootPart.PhysActor != null)
3175 m_rootPart.PhysActor.Building = false;
3176 }
3177 else
3178 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
3179
2475 } 3180 }
2476 } 3181 }
2477 3182
@@ -2484,6 +3189,17 @@ namespace OpenSim.Region.Framework.Scenes
2484 } 3189 }
2485 } 3190 }
2486 3191
3192
3193
3194 /// <summary>
3195 /// Gets the number of parts
3196 /// </summary>
3197 /// <returns></returns>
3198 public int GetPartCount()
3199 {
3200 return Parts.Count();
3201 }
3202
2487 /// <summary> 3203 /// <summary>
2488 /// Update the texture entry for this part 3204 /// Update the texture entry for this part
2489 /// </summary> 3205 /// </summary>
@@ -2545,11 +3261,6 @@ namespace OpenSim.Region.Framework.Scenes
2545 /// <param name="scale"></param> 3261 /// <param name="scale"></param>
2546 public void GroupResize(Vector3 scale) 3262 public void GroupResize(Vector3 scale)
2547 { 3263 {
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); 3264 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2554 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3265 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2555 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3266 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2576,7 +3287,6 @@ namespace OpenSim.Region.Framework.Scenes
2576 SceneObjectPart obPart = parts[i]; 3287 SceneObjectPart obPart = parts[i];
2577 if (obPart.UUID != m_rootPart.UUID) 3288 if (obPart.UUID != m_rootPart.UUID)
2578 { 3289 {
2579// obPart.IgnoreUndoUpdate = true;
2580 Vector3 oldSize = new Vector3(obPart.Scale); 3290 Vector3 oldSize = new Vector3(obPart.Scale);
2581 3291
2582 float f = 1.0f; 3292 float f = 1.0f;
@@ -2640,8 +3350,6 @@ namespace OpenSim.Region.Framework.Scenes
2640 z *= a; 3350 z *= a;
2641 } 3351 }
2642 } 3352 }
2643
2644// obPart.IgnoreUndoUpdate = false;
2645 } 3353 }
2646 } 3354 }
2647 } 3355 }
@@ -2651,9 +3359,7 @@ namespace OpenSim.Region.Framework.Scenes
2651 prevScale.Y *= y; 3359 prevScale.Y *= y;
2652 prevScale.Z *= z; 3360 prevScale.Z *= z;
2653 3361
2654// RootPart.IgnoreUndoUpdate = true;
2655 RootPart.Resize(prevScale); 3362 RootPart.Resize(prevScale);
2656// RootPart.IgnoreUndoUpdate = false;
2657 3363
2658 parts = m_parts.GetArray(); 3364 parts = m_parts.GetArray();
2659 for (int i = 0; i < parts.Length; i++) 3365 for (int i = 0; i < parts.Length; i++)
@@ -2662,8 +3368,6 @@ namespace OpenSim.Region.Framework.Scenes
2662 3368
2663 if (obPart.UUID != m_rootPart.UUID) 3369 if (obPart.UUID != m_rootPart.UUID)
2664 { 3370 {
2665 obPart.IgnoreUndoUpdate = true;
2666
2667 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3371 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2668 currentpos.X *= x; 3372 currentpos.X *= x;
2669 currentpos.Y *= y; 3373 currentpos.Y *= y;
@@ -2676,16 +3380,12 @@ namespace OpenSim.Region.Framework.Scenes
2676 3380
2677 obPart.Resize(newSize); 3381 obPart.Resize(newSize);
2678 obPart.UpdateOffSet(currentpos); 3382 obPart.UpdateOffSet(currentpos);
2679
2680 obPart.IgnoreUndoUpdate = false;
2681 } 3383 }
2682 3384
2683// obPart.IgnoreUndoUpdate = false; 3385 HasGroupChanged = true;
2684// obPart.StoreUndoState(); 3386 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3387 ScheduleGroupForTerseUpdate();
2685 } 3388 }
2686
2687// m_log.DebugFormat(
2688// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2689 } 3389 }
2690 3390
2691 #endregion 3391 #endregion
@@ -2698,14 +3398,6 @@ namespace OpenSim.Region.Framework.Scenes
2698 /// <param name="pos"></param> 3398 /// <param name="pos"></param>
2699 public void UpdateGroupPosition(Vector3 pos) 3399 public void UpdateGroupPosition(Vector3 pos)
2700 { 3400 {
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)) 3401 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2710 { 3402 {
2711 if (IsAttachment) 3403 if (IsAttachment)
@@ -2738,21 +3430,17 @@ namespace OpenSim.Region.Framework.Scenes
2738 /// </summary> 3430 /// </summary>
2739 /// <param name="pos"></param> 3431 /// <param name="pos"></param>
2740 /// <param name="localID"></param> 3432 /// <param name="localID"></param>
3433 ///
3434
2741 public void UpdateSinglePosition(Vector3 pos, uint localID) 3435 public void UpdateSinglePosition(Vector3 pos, uint localID)
2742 { 3436 {
2743 SceneObjectPart part = GetPart(localID); 3437 SceneObjectPart part = GetPart(localID);
2744 3438
2745// SceneObjectPart[] parts = m_parts.GetArray();
2746// for (int i = 0; i < parts.Length; i++)
2747// parts[i].StoreUndoState();
2748
2749 if (part != null) 3439 if (part != null)
2750 { 3440 {
2751// m_log.DebugFormat( 3441// unlock parts position change
2752// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3442 if (m_rootPart.PhysActor != null)
2753 3443 m_rootPart.PhysActor.Building = true;
2754 part.StoreUndoState(false);
2755 part.IgnoreUndoUpdate = true;
2756 3444
2757 if (part.UUID == m_rootPart.UUID) 3445 if (part.UUID == m_rootPart.UUID)
2758 { 3446 {
@@ -2763,8 +3451,10 @@ namespace OpenSim.Region.Framework.Scenes
2763 part.UpdateOffSet(pos); 3451 part.UpdateOffSet(pos);
2764 } 3452 }
2765 3453
3454 if (m_rootPart.PhysActor != null)
3455 m_rootPart.PhysActor.Building = false;
3456
2766 HasGroupChanged = true; 3457 HasGroupChanged = true;
2767 part.IgnoreUndoUpdate = false;
2768 } 3458 }
2769 } 3459 }
2770 3460
@@ -2774,13 +3464,7 @@ namespace OpenSim.Region.Framework.Scenes
2774 /// <param name="pos"></param> 3464 /// <param name="pos"></param>
2775 public void UpdateRootPosition(Vector3 pos) 3465 public void UpdateRootPosition(Vector3 pos)
2776 { 3466 {
2777// m_log.DebugFormat( 3467 // 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); 3468 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2785 Vector3 oldPos = 3469 Vector3 oldPos =
2786 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3470 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2803,7 +3487,14 @@ namespace OpenSim.Region.Framework.Scenes
2803 AbsolutePosition = newPos; 3487 AbsolutePosition = newPos;
2804 3488
2805 HasGroupChanged = true; 3489 HasGroupChanged = true;
2806 ScheduleGroupForTerseUpdate(); 3490 if (m_rootPart.Undoing)
3491 {
3492 ScheduleGroupForFullUpdate();
3493 }
3494 else
3495 {
3496 ScheduleGroupForTerseUpdate();
3497 }
2807 } 3498 }
2808 3499
2809 #endregion 3500 #endregion
@@ -2816,17 +3507,6 @@ namespace OpenSim.Region.Framework.Scenes
2816 /// <param name="rot"></param> 3507 /// <param name="rot"></param>
2817 public void UpdateGroupRotationR(Quaternion rot) 3508 public void UpdateGroupRotationR(Quaternion rot)
2818 { 3509 {
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; 3510 PhysicsActor actor = m_rootPart.PhysActor;
2831 if (actor != null) 3511 if (actor != null)
2832 { 3512 {
@@ -2845,16 +3525,6 @@ namespace OpenSim.Region.Framework.Scenes
2845 /// <param name="rot"></param> 3525 /// <param name="rot"></param>
2846 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3526 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2847 { 3527 {
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); 3528 m_rootPart.UpdateRotation(rot);
2859 3529
2860 PhysicsActor actor = m_rootPart.PhysActor; 3530 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2868,8 +3538,6 @@ namespace OpenSim.Region.Framework.Scenes
2868 3538
2869 HasGroupChanged = true; 3539 HasGroupChanged = true;
2870 ScheduleGroupForTerseUpdate(); 3540 ScheduleGroupForTerseUpdate();
2871
2872 RootPart.IgnoreUndoUpdate = false;
2873 } 3541 }
2874 3542
2875 /// <summary> 3543 /// <summary>
@@ -2882,13 +3550,11 @@ namespace OpenSim.Region.Framework.Scenes
2882 SceneObjectPart part = GetPart(localID); 3550 SceneObjectPart part = GetPart(localID);
2883 3551
2884 SceneObjectPart[] parts = m_parts.GetArray(); 3552 SceneObjectPart[] parts = m_parts.GetArray();
2885 for (int i = 0; i < parts.Length; i++)
2886 parts[i].StoreUndoState();
2887 3553
2888 if (part != null) 3554 if (part != null)
2889 { 3555 {
2890// m_log.DebugFormat( 3556 if (m_rootPart.PhysActor != null)
2891// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3557 m_rootPart.PhysActor.Building = true;
2892 3558
2893 if (part.UUID == m_rootPart.UUID) 3559 if (part.UUID == m_rootPart.UUID)
2894 { 3560 {
@@ -2898,6 +3564,9 @@ namespace OpenSim.Region.Framework.Scenes
2898 { 3564 {
2899 part.UpdateRotation(rot); 3565 part.UpdateRotation(rot);
2900 } 3566 }
3567
3568 if (m_rootPart.PhysActor != null)
3569 m_rootPart.PhysActor.Building = false;
2901 } 3570 }
2902 } 3571 }
2903 3572
@@ -2911,12 +3580,8 @@ namespace OpenSim.Region.Framework.Scenes
2911 SceneObjectPart part = GetPart(localID); 3580 SceneObjectPart part = GetPart(localID);
2912 if (part != null) 3581 if (part != null)
2913 { 3582 {
2914// m_log.DebugFormat( 3583 if (m_rootPart.PhysActor != null)
2915// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3584 m_rootPart.PhysActor.Building = true;
2916// part.Name, part.LocalId, rot);
2917
2918 part.StoreUndoState();
2919 part.IgnoreUndoUpdate = true;
2920 3585
2921 if (part.UUID == m_rootPart.UUID) 3586 if (part.UUID == m_rootPart.UUID)
2922 { 3587 {
@@ -2929,7 +3594,8 @@ namespace OpenSim.Region.Framework.Scenes
2929 part.OffsetPosition = pos; 3594 part.OffsetPosition = pos;
2930 } 3595 }
2931 3596
2932 part.IgnoreUndoUpdate = false; 3597 if (m_rootPart.PhysActor != null)
3598 m_rootPart.PhysActor.Building = false;
2933 } 3599 }
2934 } 3600 }
2935 3601
@@ -2939,15 +3605,12 @@ namespace OpenSim.Region.Framework.Scenes
2939 /// <param name="rot"></param> 3605 /// <param name="rot"></param>
2940 public void UpdateRootRotation(Quaternion rot) 3606 public void UpdateRootRotation(Quaternion rot)
2941 { 3607 {
2942// m_log.DebugFormat( 3608 // 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; 3609 Quaternion axRot = rot;
2947 Quaternion oldParentRot = m_rootPart.RotationOffset; 3610 Quaternion oldParentRot = m_rootPart.RotationOffset;
2948 3611
2949 m_rootPart.StoreUndoState(); 3612 //Don't use UpdateRotation because it schedules an update prematurely
2950 m_rootPart.UpdateRotation(rot); 3613 m_rootPart.RotationOffset = rot;
2951 3614
2952 PhysicsActor pa = m_rootPart.PhysActor; 3615 PhysicsActor pa = m_rootPart.PhysActor;
2953 3616
@@ -2963,35 +3626,135 @@ namespace OpenSim.Region.Framework.Scenes
2963 SceneObjectPart prim = parts[i]; 3626 SceneObjectPart prim = parts[i];
2964 if (prim.UUID != m_rootPart.UUID) 3627 if (prim.UUID != m_rootPart.UUID)
2965 { 3628 {
2966 prim.IgnoreUndoUpdate = true; 3629 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3630 NewRot = Quaternion.Inverse(axRot) * NewRot;
3631 prim.RotationOffset = NewRot;
3632
2967 Vector3 axPos = prim.OffsetPosition; 3633 Vector3 axPos = prim.OffsetPosition;
3634
2968 axPos *= oldParentRot; 3635 axPos *= oldParentRot;
2969 axPos *= Quaternion.Inverse(axRot); 3636 axPos *= Quaternion.Inverse(axRot);
2970 prim.OffsetPosition = axPos; 3637 prim.OffsetPosition = axPos;
2971 Quaternion primsRot = prim.RotationOffset; 3638 }
2972 Quaternion newRot = oldParentRot * primsRot; 3639 }
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 3640
2990 m_rootPart.ScheduleTerseUpdate(); 3641 HasGroupChanged = true;
3642 ScheduleGroupForFullUpdate();
3643 }
2991 3644
2992// m_log.DebugFormat( 3645 private enum updatetype :int
2993// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3646 {
2994// Name, LocalId, rot); 3647 none = 0,
3648 partterse = 1,
3649 partfull = 2,
3650 groupterse = 3,
3651 groupfull = 4
3652 }
3653
3654 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3655 {
3656 // TODO this still as excessive *.Schedule*Update()s
3657
3658 if (part != null && part.ParentGroup != null)
3659 {
3660 ObjectChangeType change = data.change;
3661 bool togroup = ((change & ObjectChangeType.Group) != 0);
3662 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3663
3664 SceneObjectGroup group = part.ParentGroup;
3665 PhysicsActor pha = group.RootPart.PhysActor;
3666
3667 updatetype updateType = updatetype.none;
3668
3669 if (togroup)
3670 {
3671 // related to group
3672 if ((change & ObjectChangeType.Position) != 0)
3673 {
3674 group.AbsolutePosition = data.position;
3675 updateType = updatetype.groupterse;
3676 }
3677 if ((change & ObjectChangeType.Rotation) != 0)
3678 {
3679 group.RootPart.UpdateRotation(data.rotation);
3680 updateType = updatetype.none;
3681 }
3682 if ((change & ObjectChangeType.Scale) != 0)
3683 {
3684 if (pha != null)
3685 pha.Building = true;
3686
3687 group.GroupResize(data.scale);
3688 updateType = updatetype.none;
3689
3690 if (pha != null)
3691 pha.Building = false;
3692 }
3693 }
3694 else
3695 {
3696 // related to single prim in a link-set ( ie group)
3697 if (pha != null)
3698 pha.Building = true;
3699
3700 // root part is special
3701 // parts offset positions or rotations need to change also
3702
3703 if (part == group.RootPart)
3704 {
3705 if ((change & ObjectChangeType.Position) != 0)
3706 group.UpdateRootPosition(data.position);
3707 if ((change & ObjectChangeType.Rotation) != 0)
3708 group.UpdateRootRotation(data.rotation);
3709 if ((change & ObjectChangeType.Scale) != 0)
3710 part.Resize(data.scale);
3711 }
3712 else
3713 {
3714 if ((change & ObjectChangeType.Position) != 0)
3715 {
3716 part.OffsetPosition = data.position;
3717 updateType = updatetype.partterse;
3718 }
3719 if ((change & ObjectChangeType.Rotation) != 0)
3720 {
3721 part.UpdateRotation(data.rotation);
3722 updateType = updatetype.none;
3723 }
3724 if ((change & ObjectChangeType.Scale) != 0)
3725 {
3726 part.Resize(data.scale);
3727 updateType = updatetype.none;
3728 }
3729 }
3730
3731 if (pha != null)
3732 pha.Building = false;
3733 }
3734
3735 if (updateType != updatetype.none)
3736 {
3737 group.HasGroupChanged = true;
3738
3739 switch (updateType)
3740 {
3741 case updatetype.partterse:
3742 part.ScheduleTerseUpdate();
3743 break;
3744 case updatetype.partfull:
3745 part.ScheduleFullUpdate();
3746 break;
3747 case updatetype.groupterse:
3748 group.ScheduleGroupForTerseUpdate();
3749 break;
3750 case updatetype.groupfull:
3751 group.ScheduleGroupForFullUpdate();
3752 break;
3753 default:
3754 break;
3755 }
3756 }
3757 }
2995 } 3758 }
2996 3759
2997 #endregion 3760 #endregion
@@ -3211,11 +3974,38 @@ namespace OpenSim.Region.Framework.Scenes
3211 } 3974 }
3212 } 3975 }
3213 } 3976 }
3214 3977
3978 public Vector3 GetGeometricCenter()
3979 {
3980 // this is not real geometric center but a average of positions relative to root prim acording to
3981 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
3982 // ignoring tortured prims details since sl also seems to ignore
3983 // so no real use in doing it on physics
3984
3985 Vector3 gc = Vector3.Zero;
3986
3987 int nparts = m_parts.Count;
3988 if (nparts <= 1)
3989 return gc;
3990
3991 SceneObjectPart[] parts = m_parts.GetArray();
3992 nparts = parts.Length; // just in case it changed
3993 if (nparts <= 1)
3994 return gc;
3995
3996 // average all parts positions
3997 for (int i = 0; i < nparts; i++)
3998 gc += parts[i].GetWorldPosition();
3999 gc /= nparts;
4000
4001 // relative to root:
4002 gc -= AbsolutePosition;
4003 return gc;
4004 }
4005
3215 public float GetMass() 4006 public float GetMass()
3216 { 4007 {
3217 float retmass = 0f; 4008 float retmass = 0f;
3218
3219 SceneObjectPart[] parts = m_parts.GetArray(); 4009 SceneObjectPart[] parts = m_parts.GetArray();
3220 for (int i = 0; i < parts.Length; i++) 4010 for (int i = 0; i < parts.Length; i++)
3221 retmass += parts[i].GetMass(); 4011 retmass += parts[i].GetMass();
@@ -3376,6 +4166,14 @@ namespace OpenSim.Region.Framework.Scenes
3376 FromItemID = uuid; 4166 FromItemID = uuid;
3377 } 4167 }
3378 4168
4169 public void ResetOwnerChangeFlag()
4170 {
4171 ForEachPart(delegate(SceneObjectPart part)
4172 {
4173 part.ResetOwnerChangeFlag();
4174 });
4175 }
4176
3379 #endregion 4177 #endregion
3380 } 4178 }
3381} 4179}