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.cs1214
1 files changed, 1005 insertions, 209 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 2686004..c47db97 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; }
@@ -524,6 +726,11 @@ namespace OpenSim.Region.Framework.Scenes
524 m_isSelected = value; 726 m_isSelected = value;
525 // Tell physics engine that group is selected 727 // Tell physics engine that group is selected
526 728
729 // this is not right
730 // but ode engines should only really need to know about root part
731 // so they can put entire object simulation on hold and not colliding
732 // keep as was for now
733
527 PhysicsActor pa = m_rootPart.PhysActor; 734 PhysicsActor pa = m_rootPart.PhysActor;
528 if (pa != null) 735 if (pa != null)
529 { 736 {
@@ -540,6 +747,42 @@ namespace OpenSim.Region.Framework.Scenes
540 childPa.Selected = value; 747 childPa.Selected = value;
541 } 748 }
542 } 749 }
750 if (RootPart.KeyframeMotion != null)
751 RootPart.KeyframeMotion.Selected = value;
752 }
753 }
754
755 public void PartSelectChanged(bool partSelect)
756 {
757 // any part selected makes group selected
758 if (m_isSelected == partSelect)
759 return;
760
761 if (partSelect)
762 {
763 IsSelected = partSelect;
764// if (!IsAttachment)
765// ScheduleGroupForFullUpdate();
766 }
767 else
768 {
769 // bad bad bad 2 heavy for large linksets
770 // since viewer does send lot of (un)selects
771 // this needs to be replaced by a specific list or count ?
772 // but that will require extra code in several places
773
774 SceneObjectPart[] parts = m_parts.GetArray();
775 for (int i = 0; i < parts.Length; i++)
776 {
777 SceneObjectPart part = parts[i];
778 if (part.IsSelected)
779 return;
780 }
781 IsSelected = partSelect;
782 if (!IsAttachment)
783 {
784 ScheduleGroupForFullUpdate();
785 }
543 } 786 }
544 } 787 }
545 788
@@ -617,6 +860,7 @@ namespace OpenSim.Region.Framework.Scenes
617 /// </summary> 860 /// </summary>
618 public SceneObjectGroup() 861 public SceneObjectGroup()
619 { 862 {
863
620 } 864 }
621 865
622 /// <summary> 866 /// <summary>
@@ -633,7 +877,7 @@ namespace OpenSim.Region.Framework.Scenes
633 /// Constructor. This object is added to the scene later via AttachToScene() 877 /// Constructor. This object is added to the scene later via AttachToScene()
634 /// </summary> 878 /// </summary>
635 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 879 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
636 { 880 {
637 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)); 881 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
638 } 882 }
639 883
@@ -669,6 +913,9 @@ namespace OpenSim.Region.Framework.Scenes
669 /// </summary> 913 /// </summary>
670 public virtual void AttachToBackup() 914 public virtual void AttachToBackup()
671 { 915 {
916 if (IsAttachment) return;
917 m_scene.SceneGraph.FireAttachToBackup(this);
918
672 if (InSceneBackup) 919 if (InSceneBackup)
673 { 920 {
674 //m_log.DebugFormat( 921 //m_log.DebugFormat(
@@ -711,6 +958,13 @@ namespace OpenSim.Region.Framework.Scenes
711 958
712 ApplyPhysics(); 959 ApplyPhysics();
713 960
961 if (RootPart.PhysActor != null)
962 RootPart.Force = RootPart.Force;
963 if (RootPart.PhysActor != null)
964 RootPart.Torque = RootPart.Torque;
965 if (RootPart.PhysActor != null)
966 RootPart.Buoyancy = RootPart.Buoyancy;
967
714 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 968 // 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. 969 // for the same object with very different properties. The caller must schedule the update.
716 //ScheduleGroupForFullUpdate(); 970 //ScheduleGroupForFullUpdate();
@@ -726,6 +980,10 @@ namespace OpenSim.Region.Framework.Scenes
726 EntityIntersection result = new EntityIntersection(); 980 EntityIntersection result = new EntityIntersection();
727 981
728 SceneObjectPart[] parts = m_parts.GetArray(); 982 SceneObjectPart[] parts = m_parts.GetArray();
983
984 // Find closest hit here
985 float idist = float.MaxValue;
986
729 for (int i = 0; i < parts.Length; i++) 987 for (int i = 0; i < parts.Length; i++)
730 { 988 {
731 SceneObjectPart part = parts[i]; 989 SceneObjectPart part = parts[i];
@@ -740,11 +998,6 @@ namespace OpenSim.Region.Framework.Scenes
740 998
741 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 999 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
742 1000
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) 1001 if (inter.HitTF)
749 { 1002 {
750 // We need to find the closest prim to return to the testcaller along the ray 1003 // We need to find the closest prim to return to the testcaller along the ray
@@ -755,10 +1008,11 @@ namespace OpenSim.Region.Framework.Scenes
755 result.obj = part; 1008 result.obj = part;
756 result.normal = inter.normal; 1009 result.normal = inter.normal;
757 result.distance = inter.distance; 1010 result.distance = inter.distance;
1011
1012 idist = inter.distance;
758 } 1013 }
759 } 1014 }
760 } 1015 }
761
762 return result; 1016 return result;
763 } 1017 }
764 1018
@@ -770,25 +1024,27 @@ namespace OpenSim.Region.Framework.Scenes
770 /// <returns></returns> 1024 /// <returns></returns>
771 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1025 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
772 { 1026 {
773 maxX = -256f; 1027 maxX = float.MinValue;
774 maxY = -256f; 1028 maxY = float.MinValue;
775 maxZ = -256f; 1029 maxZ = float.MinValue;
776 minX = 256f; 1030 minX = float.MaxValue;
777 minY = 256f; 1031 minY = float.MaxValue;
778 minZ = 8192f; 1032 minZ = float.MaxValue;
779 1033
780 SceneObjectPart[] parts = m_parts.GetArray(); 1034 SceneObjectPart[] parts = m_parts.GetArray();
781 for (int i = 0; i < parts.Length; i++) 1035 foreach (SceneObjectPart part in parts)
782 { 1036 {
783 SceneObjectPart part = parts[i];
784
785 Vector3 worldPos = part.GetWorldPosition(); 1037 Vector3 worldPos = part.GetWorldPosition();
786 Vector3 offset = worldPos - AbsolutePosition; 1038 Vector3 offset = worldPos - AbsolutePosition;
787 Quaternion worldRot; 1039 Quaternion worldRot;
788 if (part.ParentID == 0) 1040 if (part.ParentID == 0)
1041 {
789 worldRot = part.RotationOffset; 1042 worldRot = part.RotationOffset;
1043 }
790 else 1044 else
1045 {
791 worldRot = part.GetWorldRotation(); 1046 worldRot = part.GetWorldRotation();
1047 }
792 1048
793 Vector3 frontTopLeft; 1049 Vector3 frontTopLeft;
794 Vector3 frontTopRight; 1050 Vector3 frontTopRight;
@@ -800,6 +1056,8 @@ namespace OpenSim.Region.Framework.Scenes
800 Vector3 backBottomLeft; 1056 Vector3 backBottomLeft;
801 Vector3 backBottomRight; 1057 Vector3 backBottomRight;
802 1058
1059 // Vector3[] corners = new Vector3[8];
1060
803 Vector3 orig = Vector3.Zero; 1061 Vector3 orig = Vector3.Zero;
804 1062
805 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1063 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -834,6 +1092,38 @@ namespace OpenSim.Region.Framework.Scenes
834 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1092 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
835 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1093 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
836 1094
1095
1096
1097 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1098 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1099 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1100 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1101 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1102 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1103 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1104 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1105
1106 //for (int i = 0; i < 8; i++)
1107 //{
1108 // corners[i] = corners[i] * worldRot;
1109 // corners[i] += offset;
1110
1111 // if (corners[i].X > maxX)
1112 // maxX = corners[i].X;
1113 // if (corners[i].X < minX)
1114 // minX = corners[i].X;
1115
1116 // if (corners[i].Y > maxY)
1117 // maxY = corners[i].Y;
1118 // if (corners[i].Y < minY)
1119 // minY = corners[i].Y;
1120
1121 // if (corners[i].Z > maxZ)
1122 // maxZ = corners[i].Y;
1123 // if (corners[i].Z < minZ)
1124 // minZ = corners[i].Z;
1125 //}
1126
837 frontTopLeft = frontTopLeft * worldRot; 1127 frontTopLeft = frontTopLeft * worldRot;
838 frontTopRight = frontTopRight * worldRot; 1128 frontTopRight = frontTopRight * worldRot;
839 frontBottomLeft = frontBottomLeft * worldRot; 1129 frontBottomLeft = frontBottomLeft * worldRot;
@@ -855,6 +1145,15 @@ namespace OpenSim.Region.Framework.Scenes
855 backTopLeft += offset; 1145 backTopLeft += offset;
856 backTopRight += offset; 1146 backTopRight += offset;
857 1147
1148 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1149 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1150 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1151 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1152 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1153 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1154 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1155 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1156
858 if (frontTopRight.X > maxX) 1157 if (frontTopRight.X > maxX)
859 maxX = frontTopRight.X; 1158 maxX = frontTopRight.X;
860 if (frontTopLeft.X > maxX) 1159 if (frontTopLeft.X > maxX)
@@ -998,17 +1297,118 @@ namespace OpenSim.Region.Framework.Scenes
998 1297
999 #endregion 1298 #endregion
1000 1299
1300 public void GetResourcesCosts(SceneObjectPart apart,
1301 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1302 {
1303 // this information may need to be cached
1304
1305 float cost;
1306 float tmpcost;
1307
1308 bool ComplexCost = false;
1309
1310 SceneObjectPart p;
1311 SceneObjectPart[] parts;
1312
1313 lock (m_parts)
1314 {
1315 parts = m_parts.GetArray();
1316 }
1317
1318 int nparts = parts.Length;
1319
1320
1321 for (int i = 0; i < nparts; i++)
1322 {
1323 p = parts[i];
1324
1325 if (p.UsesComplexCost)
1326 {
1327 ComplexCost = true;
1328 break;
1329 }
1330 }
1331
1332 if (ComplexCost)
1333 {
1334 linksetResCost = 0;
1335 linksetPhysCost = 0;
1336 partCost = 0;
1337 partPhysCost = 0;
1338
1339 for (int i = 0; i < nparts; i++)
1340 {
1341 p = parts[i];
1342
1343 cost = p.StreamingCost;
1344 tmpcost = p.SimulationCost;
1345 if (tmpcost > cost)
1346 cost = tmpcost;
1347 tmpcost = p.PhysicsCost;
1348 if (tmpcost > cost)
1349 cost = tmpcost;
1350
1351 linksetPhysCost += tmpcost;
1352 linksetResCost += cost;
1353
1354 if (p == apart)
1355 {
1356 partCost = cost;
1357 partPhysCost = tmpcost;
1358 }
1359 }
1360 }
1361 else
1362 {
1363 partPhysCost = 1.0f;
1364 partCost = 1.0f;
1365 linksetResCost = (float)nparts;
1366 linksetPhysCost = linksetResCost;
1367 }
1368 }
1369
1370 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1371 {
1372 SceneObjectPart p;
1373 SceneObjectPart[] parts;
1374
1375 lock (m_parts)
1376 {
1377 parts = m_parts.GetArray();
1378 }
1379
1380 int nparts = parts.Length;
1381
1382 PhysCost = 0;
1383 StreamCost = 0;
1384 SimulCost = 0;
1385
1386 for (int i = 0; i < nparts; i++)
1387 {
1388 p = parts[i];
1389
1390 StreamCost += p.StreamingCost;
1391 SimulCost += p.SimulationCost;
1392 PhysCost += p.PhysicsCost;
1393 }
1394 }
1395
1001 public void SaveScriptedState(XmlTextWriter writer) 1396 public void SaveScriptedState(XmlTextWriter writer)
1002 { 1397 {
1398 SaveScriptedState(writer, false);
1399 }
1400
1401 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1402 {
1003 XmlDocument doc = new XmlDocument(); 1403 XmlDocument doc = new XmlDocument();
1004 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1404 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1005 1405
1006 SceneObjectPart[] parts = m_parts.GetArray(); 1406 SceneObjectPart[] parts = m_parts.GetArray();
1007 for (int i = 0; i < parts.Length; i++) 1407 for (int i = 0; i < parts.Length; i++)
1008 { 1408 {
1009 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1409 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1010 foreach (KeyValuePair<UUID, string> kvp in pstates) 1410 foreach (KeyValuePair<UUID, string> kvp in pstates)
1011 states.Add(kvp.Key, kvp.Value); 1411 states[kvp.Key] = kvp.Value;
1012 } 1412 }
1013 1413
1014 if (states.Count > 0) 1414 if (states.Count > 0)
@@ -1028,6 +1428,169 @@ namespace OpenSim.Region.Framework.Scenes
1028 } 1428 }
1029 1429
1030 /// <summary> 1430 /// <summary>
1431 /// Add the avatar to this linkset (avatar is sat).
1432 /// </summary>
1433 /// <param name="agentID"></param>
1434 public void AddAvatar(UUID agentID)
1435 {
1436 ScenePresence presence;
1437 if (m_scene.TryGetScenePresence(agentID, out presence))
1438 {
1439 if (!m_linkedAvatars.Contains(presence))
1440 {
1441 m_linkedAvatars.Add(presence);
1442 }
1443 }
1444 }
1445
1446 /// <summary>
1447 /// Delete the avatar from this linkset (avatar is unsat).
1448 /// </summary>
1449 /// <param name="agentID"></param>
1450 public void DeleteAvatar(UUID agentID)
1451 {
1452 ScenePresence presence;
1453 if (m_scene.TryGetScenePresence(agentID, out presence))
1454 {
1455 if (m_linkedAvatars.Contains(presence))
1456 {
1457 m_linkedAvatars.Remove(presence);
1458 }
1459 }
1460 }
1461
1462 /// <summary>
1463 /// Returns the list of linked presences (avatars sat on this group)
1464 /// </summary>
1465 /// <param name="agentID"></param>
1466 public List<ScenePresence> GetLinkedAvatars()
1467 {
1468 return m_linkedAvatars;
1469 }
1470
1471 /// <summary>
1472 /// Attach this scene object to the given avatar.
1473 /// </summary>
1474 /// <param name="agentID"></param>
1475 /// <param name="attachmentpoint"></param>
1476 /// <param name="AttachOffset"></param>
1477 private void AttachToAgent(
1478 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1479 {
1480 if (avatar != null)
1481 {
1482 // don't attach attachments to child agents
1483 if (avatar.IsChildAgent) return;
1484
1485 // Remove from database and parcel prim count
1486 m_scene.DeleteFromStorage(so.UUID);
1487 m_scene.EventManager.TriggerParcelPrimCountTainted();
1488
1489 so.AttachedAvatar = avatar.UUID;
1490
1491 if (so.RootPart.PhysActor != null)
1492 {
1493 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1494 so.RootPart.PhysActor = null;
1495 }
1496
1497 so.AbsolutePosition = attachOffset;
1498 so.RootPart.AttachedPos = attachOffset;
1499 so.IsAttachment = true;
1500 so.RootPart.SetParentLocalId(avatar.LocalId);
1501 so.AttachmentPoint = attachmentpoint;
1502
1503 avatar.AddAttachment(this);
1504
1505 if (!silent)
1506 {
1507 // Killing it here will cause the client to deselect it
1508 // It then reappears on the avatar, deselected
1509 // through the full update below
1510 //
1511 if (IsSelected)
1512 {
1513 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1514 }
1515
1516 IsSelected = false; // fudge....
1517 ScheduleGroupForFullUpdate();
1518 }
1519 }
1520 else
1521 {
1522 m_log.WarnFormat(
1523 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1524 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1525 }
1526 }
1527
1528 public byte GetAttachmentPoint()
1529 {
1530 return m_rootPart.Shape.State;
1531 }
1532
1533 public void DetachToGround()
1534 {
1535 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1536 if (avatar == null)
1537 return;
1538
1539 avatar.RemoveAttachment(this);
1540
1541 Vector3 detachedpos = new Vector3(127f,127f,127f);
1542 if (avatar == null)
1543 return;
1544
1545 detachedpos = avatar.AbsolutePosition;
1546 FromItemID = UUID.Zero;
1547
1548 AbsolutePosition = detachedpos;
1549 AttachedAvatar = UUID.Zero;
1550
1551 //SceneObjectPart[] parts = m_parts.GetArray();
1552 //for (int i = 0; i < parts.Length; i++)
1553 // parts[i].AttachedAvatar = UUID.Zero;
1554
1555 m_rootPart.SetParentLocalId(0);
1556 AttachmentPoint = (byte)0;
1557 // must check if buildind should be true or false here
1558 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1559 HasGroupChanged = true;
1560 RootPart.Rezzed = DateTime.Now;
1561 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1562 AttachToBackup();
1563 m_scene.EventManager.TriggerParcelPrimCountTainted();
1564 m_rootPart.ScheduleFullUpdate();
1565 m_rootPart.ClearUndoState();
1566 }
1567
1568 public void DetachToInventoryPrep()
1569 {
1570 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1571 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1572 if (avatar != null)
1573 {
1574 //detachedpos = avatar.AbsolutePosition;
1575 avatar.RemoveAttachment(this);
1576 }
1577
1578 AttachedAvatar = UUID.Zero;
1579
1580 /*SceneObjectPart[] parts = m_parts.GetArray();
1581 for (int i = 0; i < parts.Length; i++)
1582 parts[i].AttachedAvatar = UUID.Zero;*/
1583
1584 m_rootPart.SetParentLocalId(0);
1585 //m_rootPart.SetAttachmentPoint((byte)0);
1586 IsAttachment = false;
1587 AbsolutePosition = m_rootPart.AttachedPos;
1588 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1589 //AttachToBackup();
1590 //m_rootPart.ScheduleFullUpdate();
1591 }
1592
1593 /// <summary>
1031 /// 1594 ///
1032 /// </summary> 1595 /// </summary>
1033 /// <param name="part"></param> 1596 /// <param name="part"></param>
@@ -1077,7 +1640,10 @@ namespace OpenSim.Region.Framework.Scenes
1077 public void AddPart(SceneObjectPart part) 1640 public void AddPart(SceneObjectPart part)
1078 { 1641 {
1079 part.SetParent(this); 1642 part.SetParent(this);
1080 part.LinkNum = m_parts.Add(part.UUID, part); 1643 m_parts.Add(part.UUID, part);
1644
1645 part.LinkNum = m_parts.Count;
1646
1081 if (part.LinkNum == 2) 1647 if (part.LinkNum == 2)
1082 RootPart.LinkNum = 1; 1648 RootPart.LinkNum = 1;
1083 } 1649 }
@@ -1165,7 +1731,7 @@ namespace OpenSim.Region.Framework.Scenes
1165// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1731// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1166// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1732// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1167 1733
1168 part.StoreUndoState(); 1734// part.StoreUndoState();
1169 part.OnGrab(offsetPos, remoteClient); 1735 part.OnGrab(offsetPos, remoteClient);
1170 } 1736 }
1171 1737
@@ -1185,6 +1751,11 @@ namespace OpenSim.Region.Framework.Scenes
1185 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1751 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1186 public void DeleteGroupFromScene(bool silent) 1752 public void DeleteGroupFromScene(bool silent)
1187 { 1753 {
1754 // We need to keep track of this state in case this group is still queued for backup.
1755 IsDeleted = true;
1756
1757 DetachFromBackup();
1758
1188 SceneObjectPart[] parts = m_parts.GetArray(); 1759 SceneObjectPart[] parts = m_parts.GetArray();
1189 for (int i = 0; i < parts.Length; i++) 1760 for (int i = 0; i < parts.Length; i++)
1190 { 1761 {
@@ -1207,6 +1778,8 @@ namespace OpenSim.Region.Framework.Scenes
1207 } 1778 }
1208 }); 1779 });
1209 } 1780 }
1781
1782
1210 } 1783 }
1211 1784
1212 public void AddScriptLPS(int count) 1785 public void AddScriptLPS(int count)
@@ -1276,28 +1849,43 @@ namespace OpenSim.Region.Framework.Scenes
1276 /// </summary> 1849 /// </summary>
1277 public void ApplyPhysics() 1850 public void ApplyPhysics()
1278 { 1851 {
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(); 1852 SceneObjectPart[] parts = m_parts.GetArray();
1284 if (parts.Length > 1) 1853 if (parts.Length > 1)
1285 { 1854 {
1855 ResetChildPrimPhysicsPositions();
1856
1857 // Apply physics to the root prim
1858 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1859
1860
1286 for (int i = 0; i < parts.Length; i++) 1861 for (int i = 0; i < parts.Length; i++)
1287 { 1862 {
1288 SceneObjectPart part = parts[i]; 1863 SceneObjectPart part = parts[i];
1289 if (part.LocalId != m_rootPart.LocalId) 1864 if (part.LocalId != m_rootPart.LocalId)
1290 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1865 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1291 } 1866 }
1292
1293 // Hack to get the physics scene geometries in the right spot 1867 // Hack to get the physics scene geometries in the right spot
1294 ResetChildPrimPhysicsPositions(); 1868// ResetChildPrimPhysicsPositions();
1869 if (m_rootPart.PhysActor != null)
1870 {
1871 m_rootPart.PhysActor.Building = false;
1872 }
1873 }
1874 else
1875 {
1876 // Apply physics to the root prim
1877 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1295 } 1878 }
1296 } 1879 }
1297 1880
1298 public void SetOwnerId(UUID userId) 1881 public void SetOwnerId(UUID userId)
1299 { 1882 {
1300 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1883 ForEachPart(delegate(SceneObjectPart part)
1884 {
1885
1886 part.OwnerID = userId;
1887
1888 });
1301 } 1889 }
1302 1890
1303 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1891 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1329,11 +1917,17 @@ namespace OpenSim.Region.Framework.Scenes
1329 return; 1917 return;
1330 } 1918 }
1331 1919
1920 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1921 return;
1922
1332 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1923 // 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. 1924 // any exception propogate upwards.
1334 try 1925 try
1335 { 1926 {
1336 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1927 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1928 m_scene.LoginsDisabled || // We're starting up or doing maintenance, don't mess with things
1929 m_scene.LoadingPrims) // Land may not be valid yet
1930
1337 { 1931 {
1338 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1932 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1339 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 1933 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1360,6 +1954,7 @@ namespace OpenSim.Region.Framework.Scenes
1360 } 1954 }
1361 } 1955 }
1362 } 1956 }
1957
1363 } 1958 }
1364 1959
1365 if (m_scene.UseBackup && HasGroupChanged) 1960 if (m_scene.UseBackup && HasGroupChanged)
@@ -1367,10 +1962,30 @@ namespace OpenSim.Region.Framework.Scenes
1367 // don't backup while it's selected or you're asking for changes mid stream. 1962 // don't backup while it's selected or you're asking for changes mid stream.
1368 if (isTimeToPersist() || forcedBackup) 1963 if (isTimeToPersist() || forcedBackup)
1369 { 1964 {
1965 if (m_rootPart.PhysActor != null &&
1966 (!m_rootPart.PhysActor.IsPhysical))
1967 {
1968 // Possible ghost prim
1969 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
1970 {
1971 foreach (SceneObjectPart part in m_parts.GetArray())
1972 {
1973 // Re-set physics actor positions and
1974 // orientations
1975 part.GroupPosition = m_rootPart.GroupPosition;
1976 }
1977 }
1978 }
1370// m_log.DebugFormat( 1979// m_log.DebugFormat(
1371// "[SCENE]: Storing {0}, {1} in {2}", 1980// "[SCENE]: Storing {0}, {1} in {2}",
1372// Name, UUID, m_scene.RegionInfo.RegionName); 1981// Name, UUID, m_scene.RegionInfo.RegionName);
1373 1982
1983 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
1984 {
1985 RootPart.Shape.State = 0;
1986 ScheduleGroupForFullUpdate();
1987 }
1988
1374 SceneObjectGroup backup_group = Copy(false); 1989 SceneObjectGroup backup_group = Copy(false);
1375 backup_group.RootPart.Velocity = RootPart.Velocity; 1990 backup_group.RootPart.Velocity = RootPart.Velocity;
1376 backup_group.RootPart.Acceleration = RootPart.Acceleration; 1991 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1384,6 +1999,11 @@ namespace OpenSim.Region.Framework.Scenes
1384 1999
1385 backup_group.ForEachPart(delegate(SceneObjectPart part) 2000 backup_group.ForEachPart(delegate(SceneObjectPart part)
1386 { 2001 {
2002 if (part.KeyframeMotion != null)
2003 {
2004 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2005 part.KeyframeMotion.UpdateSceneObject(this);
2006 }
1387 part.Inventory.ProcessInventoryBackup(datastore); 2007 part.Inventory.ProcessInventoryBackup(datastore);
1388 }); 2008 });
1389 2009
@@ -1436,6 +2056,7 @@ namespace OpenSim.Region.Framework.Scenes
1436 /// <returns></returns> 2056 /// <returns></returns>
1437 public SceneObjectGroup Copy(bool userExposed) 2057 public SceneObjectGroup Copy(bool userExposed)
1438 { 2058 {
2059 m_dupeInProgress = true;
1439 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2060 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1440 dupe.m_isBackedUp = false; 2061 dupe.m_isBackedUp = false;
1441 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2062 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
@@ -1450,7 +2071,7 @@ namespace OpenSim.Region.Framework.Scenes
1450 // This is only necessary when userExposed is false! 2071 // This is only necessary when userExposed is false!
1451 2072
1452 bool previousAttachmentStatus = dupe.IsAttachment; 2073 bool previousAttachmentStatus = dupe.IsAttachment;
1453 2074
1454 if (!userExposed) 2075 if (!userExposed)
1455 dupe.IsAttachment = true; 2076 dupe.IsAttachment = true;
1456 2077
@@ -1468,11 +2089,11 @@ namespace OpenSim.Region.Framework.Scenes
1468 dupe.m_rootPart.TrimPermissions(); 2089 dupe.m_rootPart.TrimPermissions();
1469 2090
1470 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2091 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1471 2092
1472 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2093 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1473 { 2094 {
1474 return p1.LinkNum.CompareTo(p2.LinkNum); 2095 return p1.LinkNum.CompareTo(p2.LinkNum);
1475 } 2096 }
1476 ); 2097 );
1477 2098
1478 foreach (SceneObjectPart part in partList) 2099 foreach (SceneObjectPart part in partList)
@@ -1482,41 +2103,53 @@ namespace OpenSim.Region.Framework.Scenes
1482 { 2103 {
1483 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2104 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1484 newPart.LinkNum = part.LinkNum; 2105 newPart.LinkNum = part.LinkNum;
1485 } 2106 if (userExposed)
2107 newPart.ParentID = dupe.m_rootPart.LocalId;
2108 }
1486 else 2109 else
1487 { 2110 {
1488 newPart = dupe.m_rootPart; 2111 newPart = dupe.m_rootPart;
1489 } 2112 }
2113/*
2114 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2115 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1490 2116
1491 // Need to duplicate the physics actor as well 2117 // Need to duplicate the physics actor as well
1492 PhysicsActor originalPartPa = part.PhysActor; 2118 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1493 if (originalPartPa != null && userExposed)
1494 { 2119 {
1495 PrimitiveBaseShape pbs = newPart.Shape; 2120 PrimitiveBaseShape pbs = newPart.Shape;
1496
1497 newPart.PhysActor 2121 newPart.PhysActor
1498 = m_scene.PhysicsScene.AddPrimShape( 2122 = m_scene.PhysicsScene.AddPrimShape(
1499 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2123 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1500 pbs, 2124 pbs,
1501 newPart.AbsolutePosition, 2125 newPart.AbsolutePosition,
1502 newPart.Scale, 2126 newPart.Scale,
1503 newPart.RotationOffset, 2127 newPart.GetWorldRotation(),
1504 originalPartPa.IsPhysical, 2128 isphys,
2129 isphan,
1505 newPart.LocalId); 2130 newPart.LocalId);
1506 2131
1507 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2132 newPart.DoPhysicsPropertyUpdate(isphys, true);
1508 } 2133 */
2134 if (userExposed)
2135 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2136// }
1509 } 2137 }
1510 2138
1511 if (userExposed) 2139 if (userExposed)
1512 { 2140 {
1513 dupe.UpdateParentIDs(); 2141// done above dupe.UpdateParentIDs();
2142
2143 if (dupe.m_rootPart.PhysActor != null)
2144 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2145
1514 dupe.HasGroupChanged = true; 2146 dupe.HasGroupChanged = true;
1515 dupe.AttachToBackup(); 2147 dupe.AttachToBackup();
1516 2148
1517 ScheduleGroupForFullUpdate(); 2149 ScheduleGroupForFullUpdate();
1518 } 2150 }
1519 2151
2152 m_dupeInProgress = false;
1520 return dupe; 2153 return dupe;
1521 } 2154 }
1522 2155
@@ -1528,11 +2161,24 @@ namespace OpenSim.Region.Framework.Scenes
1528 /// <param name="cGroupID"></param> 2161 /// <param name="cGroupID"></param>
1529 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2162 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1530 { 2163 {
1531 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2164 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2165 // give newpart a new local ID lettng old part keep same
2166 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2167 newpart.LocalId = m_scene.AllocateLocalId();
2168
2169 SetRootPart(newpart);
2170 if (userExposed)
2171 RootPart.Velocity = Vector3.Zero; // In case source is moving
1532 } 2172 }
1533 2173
1534 public void ScriptSetPhysicsStatus(bool usePhysics) 2174 public void ScriptSetPhysicsStatus(bool usePhysics)
1535 { 2175 {
2176 if (usePhysics)
2177 {
2178 if (RootPart.KeyframeMotion != null)
2179 RootPart.KeyframeMotion.Stop();
2180 RootPart.KeyframeMotion = null;
2181 }
1536 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2182 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1537 } 2183 }
1538 2184
@@ -1586,7 +2232,7 @@ namespace OpenSim.Region.Framework.Scenes
1586 } 2232 }
1587 } 2233 }
1588 2234
1589 public void applyAngularImpulse(Vector3 impulse) 2235 public void ApplyAngularImpulse(Vector3 impulse)
1590 { 2236 {
1591 PhysicsActor pa = RootPart.PhysActor; 2237 PhysicsActor pa = RootPart.PhysActor;
1592 2238
@@ -1600,36 +2246,12 @@ namespace OpenSim.Region.Framework.Scenes
1600 } 2246 }
1601 } 2247 }
1602 2248
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() 2249 public Vector3 GetTorque()
1618 { 2250 {
1619 PhysicsActor pa = RootPart.PhysActor; 2251 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 } 2252 }
1632 2253
2254 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1633 public void moveToTarget(Vector3 target, float tau) 2255 public void moveToTarget(Vector3 target, float tau)
1634 { 2256 {
1635 if (IsAttachment) 2257 if (IsAttachment)
@@ -1661,6 +2283,46 @@ namespace OpenSim.Region.Framework.Scenes
1661 pa.PIDActive = false; 2283 pa.PIDActive = false;
1662 } 2284 }
1663 2285
2286 public void rotLookAt(Quaternion target, float strength, float damping)
2287 {
2288 SceneObjectPart rootpart = m_rootPart;
2289 if (rootpart != null)
2290 {
2291 if (IsAttachment)
2292 {
2293 /*
2294 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2295 if (avatar != null)
2296 {
2297 Rotate the Av?
2298 } */
2299 }
2300 else
2301 {
2302 if (rootpart.PhysActor != null)
2303 { // APID must be implemented in your physics system for this to function.
2304 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2305 rootpart.PhysActor.APIDStrength = strength;
2306 rootpart.PhysActor.APIDDamping = damping;
2307 rootpart.PhysActor.APIDActive = true;
2308 }
2309 }
2310 }
2311 }
2312
2313 public void stopLookAt()
2314 {
2315 SceneObjectPart rootpart = m_rootPart;
2316 if (rootpart != null)
2317 {
2318 if (rootpart.PhysActor != null)
2319 { // APID must be implemented in your physics system for this to function.
2320 rootpart.PhysActor.APIDActive = false;
2321 }
2322 }
2323
2324 }
2325
1664 /// <summary> 2326 /// <summary>
1665 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2327 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1666 /// </summary> 2328 /// </summary>
@@ -1717,7 +2379,12 @@ namespace OpenSim.Region.Framework.Scenes
1717 /// <param name="cGroupID"></param> 2379 /// <param name="cGroupID"></param>
1718 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2380 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1719 { 2381 {
1720 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2382 // give new ID to the new part, letting old keep original
2383 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2384 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2385 newPart.LocalId = m_scene.AllocateLocalId();
2386 newPart.SetParent(this);
2387
1721 AddPart(newPart); 2388 AddPart(newPart);
1722 2389
1723 SetPartAsNonRoot(newPart); 2390 SetPartAsNonRoot(newPart);
@@ -1846,11 +2513,11 @@ namespace OpenSim.Region.Framework.Scenes
1846 /// Immediately send a full update for this scene object. 2513 /// Immediately send a full update for this scene object.
1847 /// </summary> 2514 /// </summary>
1848 public void SendGroupFullUpdate() 2515 public void SendGroupFullUpdate()
1849 { 2516 {
1850 if (IsDeleted) 2517 if (IsDeleted)
1851 return; 2518 return;
1852 2519
1853// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2520// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1854 2521
1855 RootPart.SendFullUpdateToAllClients(); 2522 RootPart.SendFullUpdateToAllClients();
1856 2523
@@ -1984,6 +2651,11 @@ namespace OpenSim.Region.Framework.Scenes
1984 2651
1985 SceneObjectPart linkPart = objectGroup.m_rootPart; 2652 SceneObjectPart linkPart = objectGroup.m_rootPart;
1986 2653
2654 if (m_rootPart.PhysActor != null)
2655 m_rootPart.PhysActor.Building = true;
2656 if (linkPart.PhysActor != null)
2657 linkPart.PhysActor.Building = true;
2658
1987 // physics flags from group to be applied to linked parts 2659 // physics flags from group to be applied to linked parts
1988 bool grpusephys = UsesPhysics; 2660 bool grpusephys = UsesPhysics;
1989 bool grptemporary = IsTemporary; 2661 bool grptemporary = IsTemporary;
@@ -2032,7 +2704,7 @@ namespace OpenSim.Region.Framework.Scenes
2032 linkPart.CreateSelected = true; 2704 linkPart.CreateSelected = true;
2033 2705
2034 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2706 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2035 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2707 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2036 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2708 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2037 { 2709 {
2038 linkPart.PhysActor.link(m_rootPart.PhysActor); 2710 linkPart.PhysActor.link(m_rootPart.PhysActor);
@@ -2040,6 +2712,7 @@ namespace OpenSim.Region.Framework.Scenes
2040 } 2712 }
2041 2713
2042 linkPart.LinkNum = linkNum++; 2714 linkPart.LinkNum = linkNum++;
2715 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2043 2716
2044 SceneObjectPart[] ogParts = objectGroup.Parts; 2717 SceneObjectPart[] ogParts = objectGroup.Parts;
2045 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 2718 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
@@ -2054,7 +2727,7 @@ namespace OpenSim.Region.Framework.Scenes
2054 { 2727 {
2055 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++); 2728 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2056 // let physics know 2729 // let physics know
2057 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2730 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2058 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2731 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2059 { 2732 {
2060 part.PhysActor.link(m_rootPart.PhysActor); 2733 part.PhysActor.link(m_rootPart.PhysActor);
@@ -2069,7 +2742,7 @@ namespace OpenSim.Region.Framework.Scenes
2069 objectGroup.IsDeleted = true; 2742 objectGroup.IsDeleted = true;
2070 2743
2071 objectGroup.m_parts.Clear(); 2744 objectGroup.m_parts.Clear();
2072 2745
2073 // Can't do this yet since backup still makes use of the root part without any synchronization 2746 // Can't do this yet since backup still makes use of the root part without any synchronization
2074// objectGroup.m_rootPart = null; 2747// objectGroup.m_rootPart = null;
2075 2748
@@ -2080,6 +2753,9 @@ namespace OpenSim.Region.Framework.Scenes
2080 // unmoved prims! 2753 // unmoved prims!
2081 ResetChildPrimPhysicsPositions(); 2754 ResetChildPrimPhysicsPositions();
2082 2755
2756 if (m_rootPart.PhysActor != null)
2757 m_rootPart.PhysActor.Building = false;
2758
2083 //HasGroupChanged = true; 2759 //HasGroupChanged = true;
2084 //ScheduleGroupForFullUpdate(); 2760 //ScheduleGroupForFullUpdate();
2085 } 2761 }
@@ -2147,7 +2823,10 @@ namespace OpenSim.Region.Framework.Scenes
2147// m_log.DebugFormat( 2823// m_log.DebugFormat(
2148// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2824// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2149// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2825// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2150 2826
2827 if (m_rootPart.PhysActor != null)
2828 m_rootPart.PhysActor.Building = true;
2829
2151 linkPart.ClearUndoState(); 2830 linkPart.ClearUndoState();
2152 2831
2153 Quaternion worldRot = linkPart.GetWorldRotation(); 2832 Quaternion worldRot = linkPart.GetWorldRotation();
@@ -2207,6 +2886,14 @@ namespace OpenSim.Region.Framework.Scenes
2207 2886
2208 // When we delete a group, we currently have to force persist to the database if the object id has changed 2887 // When we delete a group, we currently have to force persist to the database if the object id has changed
2209 // (since delete works by deleting all rows which have a given object id) 2888 // (since delete works by deleting all rows which have a given object id)
2889
2890 // this is as it seems to be in sl now
2891 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2892 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2893
2894 if (m_rootPart.PhysActor != null)
2895 m_rootPart.PhysActor.Building = false;
2896
2210 objectGroup.HasGroupChangedDueToDelink = true; 2897 objectGroup.HasGroupChangedDueToDelink = true;
2211 2898
2212 return objectGroup; 2899 return objectGroup;
@@ -2218,6 +2905,7 @@ namespace OpenSim.Region.Framework.Scenes
2218 /// <param name="objectGroup"></param> 2905 /// <param name="objectGroup"></param>
2219 public virtual void DetachFromBackup() 2906 public virtual void DetachFromBackup()
2220 { 2907 {
2908 m_scene.SceneGraph.FireDetachFromBackup(this);
2221 if (m_isBackedUp && Scene != null) 2909 if (m_isBackedUp && Scene != null)
2222 m_scene.EventManager.OnBackup -= ProcessBackup; 2910 m_scene.EventManager.OnBackup -= ProcessBackup;
2223 2911
@@ -2236,7 +2924,8 @@ namespace OpenSim.Region.Framework.Scenes
2236 2924
2237 axPos *= parentRot; 2925 axPos *= parentRot;
2238 part.OffsetPosition = axPos; 2926 part.OffsetPosition = axPos;
2239 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 2927 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
2928 part.GroupPosition = newPos;
2240 part.OffsetPosition = Vector3.Zero; 2929 part.OffsetPosition = Vector3.Zero;
2241 part.RotationOffset = worldRot; 2930 part.RotationOffset = worldRot;
2242 2931
@@ -2247,7 +2936,7 @@ namespace OpenSim.Region.Framework.Scenes
2247 2936
2248 part.LinkNum = linkNum; 2937 part.LinkNum = linkNum;
2249 2938
2250 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 2939 part.OffsetPosition = newPos - AbsolutePosition;
2251 2940
2252 Quaternion rootRotation = m_rootPart.RotationOffset; 2941 Quaternion rootRotation = m_rootPart.RotationOffset;
2253 2942
@@ -2257,10 +2946,10 @@ namespace OpenSim.Region.Framework.Scenes
2257 2946
2258 parentRot = m_rootPart.RotationOffset; 2947 parentRot = m_rootPart.RotationOffset;
2259 oldRot = part.RotationOffset; 2948 oldRot = part.RotationOffset;
2260 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2949 Quaternion newRot = Quaternion.Inverse(parentRot) * worldRot;
2261 part.RotationOffset = newRot; 2950 part.RotationOffset = newRot;
2262 2951
2263 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2952 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2264 } 2953 }
2265 2954
2266 /// <summary> 2955 /// <summary>
@@ -2511,8 +3200,22 @@ namespace OpenSim.Region.Framework.Scenes
2511 } 3200 }
2512 } 3201 }
2513 3202
2514 for (int i = 0; i < parts.Length; i++) 3203 if (parts.Length > 1)
2515 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3204 {
3205 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3206
3207 for (int i = 0; i < parts.Length; i++)
3208 {
3209
3210 if (parts[i].UUID != m_rootPart.UUID)
3211 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3212 }
3213
3214 if (m_rootPart.PhysActor != null)
3215 m_rootPart.PhysActor.Building = false;
3216 }
3217 else
3218 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2516 } 3219 }
2517 } 3220 }
2518 3221
@@ -2525,6 +3228,17 @@ namespace OpenSim.Region.Framework.Scenes
2525 } 3228 }
2526 } 3229 }
2527 3230
3231
3232
3233 /// <summary>
3234 /// Gets the number of parts
3235 /// </summary>
3236 /// <returns></returns>
3237 public int GetPartCount()
3238 {
3239 return Parts.Count();
3240 }
3241
2528 /// <summary> 3242 /// <summary>
2529 /// Update the texture entry for this part 3243 /// Update the texture entry for this part
2530 /// </summary> 3244 /// </summary>
@@ -2586,11 +3300,6 @@ namespace OpenSim.Region.Framework.Scenes
2586 /// <param name="scale"></param> 3300 /// <param name="scale"></param>
2587 public void GroupResize(Vector3 scale) 3301 public void GroupResize(Vector3 scale)
2588 { 3302 {
2589// m_log.DebugFormat(
2590// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2591
2592 RootPart.StoreUndoState(true);
2593
2594 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3303 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2595 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3304 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2596 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3305 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2617,7 +3326,6 @@ namespace OpenSim.Region.Framework.Scenes
2617 SceneObjectPart obPart = parts[i]; 3326 SceneObjectPart obPart = parts[i];
2618 if (obPart.UUID != m_rootPart.UUID) 3327 if (obPart.UUID != m_rootPart.UUID)
2619 { 3328 {
2620// obPart.IgnoreUndoUpdate = true;
2621 Vector3 oldSize = new Vector3(obPart.Scale); 3329 Vector3 oldSize = new Vector3(obPart.Scale);
2622 3330
2623 float f = 1.0f; 3331 float f = 1.0f;
@@ -2681,8 +3389,6 @@ namespace OpenSim.Region.Framework.Scenes
2681 z *= a; 3389 z *= a;
2682 } 3390 }
2683 } 3391 }
2684
2685// obPart.IgnoreUndoUpdate = false;
2686 } 3392 }
2687 } 3393 }
2688 } 3394 }
@@ -2692,9 +3398,7 @@ namespace OpenSim.Region.Framework.Scenes
2692 prevScale.Y *= y; 3398 prevScale.Y *= y;
2693 prevScale.Z *= z; 3399 prevScale.Z *= z;
2694 3400
2695// RootPart.IgnoreUndoUpdate = true;
2696 RootPart.Resize(prevScale); 3401 RootPart.Resize(prevScale);
2697// RootPart.IgnoreUndoUpdate = false;
2698 3402
2699 parts = m_parts.GetArray(); 3403 parts = m_parts.GetArray();
2700 for (int i = 0; i < parts.Length; i++) 3404 for (int i = 0; i < parts.Length; i++)
@@ -2703,8 +3407,6 @@ namespace OpenSim.Region.Framework.Scenes
2703 3407
2704 if (obPart.UUID != m_rootPart.UUID) 3408 if (obPart.UUID != m_rootPart.UUID)
2705 { 3409 {
2706 obPart.IgnoreUndoUpdate = true;
2707
2708 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3410 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2709 currentpos.X *= x; 3411 currentpos.X *= x;
2710 currentpos.Y *= y; 3412 currentpos.Y *= y;
@@ -2717,16 +3419,12 @@ namespace OpenSim.Region.Framework.Scenes
2717 3419
2718 obPart.Resize(newSize); 3420 obPart.Resize(newSize);
2719 obPart.UpdateOffSet(currentpos); 3421 obPart.UpdateOffSet(currentpos);
2720
2721 obPart.IgnoreUndoUpdate = false;
2722 } 3422 }
2723 3423
2724// obPart.IgnoreUndoUpdate = false; 3424 HasGroupChanged = true;
2725// obPart.StoreUndoState(); 3425 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3426 ScheduleGroupForTerseUpdate();
2726 } 3427 }
2727
2728// m_log.DebugFormat(
2729// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2730 } 3428 }
2731 3429
2732 #endregion 3430 #endregion
@@ -2739,14 +3437,6 @@ namespace OpenSim.Region.Framework.Scenes
2739 /// <param name="pos"></param> 3437 /// <param name="pos"></param>
2740 public void UpdateGroupPosition(Vector3 pos) 3438 public void UpdateGroupPosition(Vector3 pos)
2741 { 3439 {
2742// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2743
2744 RootPart.StoreUndoState(true);
2745
2746// SceneObjectPart[] parts = m_parts.GetArray();
2747// for (int i = 0; i < parts.Length; i++)
2748// parts[i].StoreUndoState();
2749
2750 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3440 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2751 { 3441 {
2752 if (IsAttachment) 3442 if (IsAttachment)
@@ -2779,21 +3469,17 @@ namespace OpenSim.Region.Framework.Scenes
2779 /// </summary> 3469 /// </summary>
2780 /// <param name="pos"></param> 3470 /// <param name="pos"></param>
2781 /// <param name="localID"></param> 3471 /// <param name="localID"></param>
3472 ///
3473
2782 public void UpdateSinglePosition(Vector3 pos, uint localID) 3474 public void UpdateSinglePosition(Vector3 pos, uint localID)
2783 { 3475 {
2784 SceneObjectPart part = GetPart(localID); 3476 SceneObjectPart part = GetPart(localID);
2785 3477
2786// SceneObjectPart[] parts = m_parts.GetArray();
2787// for (int i = 0; i < parts.Length; i++)
2788// parts[i].StoreUndoState();
2789
2790 if (part != null) 3478 if (part != null)
2791 { 3479 {
2792// m_log.DebugFormat( 3480// unlock parts position change
2793// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3481 if (m_rootPart.PhysActor != null)
2794 3482 m_rootPart.PhysActor.Building = true;
2795 part.StoreUndoState(false);
2796 part.IgnoreUndoUpdate = true;
2797 3483
2798 if (part.UUID == m_rootPart.UUID) 3484 if (part.UUID == m_rootPart.UUID)
2799 { 3485 {
@@ -2804,8 +3490,10 @@ namespace OpenSim.Region.Framework.Scenes
2804 part.UpdateOffSet(pos); 3490 part.UpdateOffSet(pos);
2805 } 3491 }
2806 3492
3493 if (m_rootPart.PhysActor != null)
3494 m_rootPart.PhysActor.Building = false;
3495
2807 HasGroupChanged = true; 3496 HasGroupChanged = true;
2808 part.IgnoreUndoUpdate = false;
2809 } 3497 }
2810 } 3498 }
2811 3499
@@ -2815,13 +3503,7 @@ namespace OpenSim.Region.Framework.Scenes
2815 /// <param name="pos"></param> 3503 /// <param name="pos"></param>
2816 public void UpdateRootPosition(Vector3 pos) 3504 public void UpdateRootPosition(Vector3 pos)
2817 { 3505 {
2818// m_log.DebugFormat( 3506 // needs to be called with phys building true
2819// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2820
2821// SceneObjectPart[] parts = m_parts.GetArray();
2822// for (int i = 0; i < parts.Length; i++)
2823// parts[i].StoreUndoState();
2824
2825 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3507 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2826 Vector3 oldPos = 3508 Vector3 oldPos =
2827 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3509 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2844,7 +3526,14 @@ namespace OpenSim.Region.Framework.Scenes
2844 AbsolutePosition = newPos; 3526 AbsolutePosition = newPos;
2845 3527
2846 HasGroupChanged = true; 3528 HasGroupChanged = true;
2847 ScheduleGroupForTerseUpdate(); 3529 if (m_rootPart.Undoing)
3530 {
3531 ScheduleGroupForFullUpdate();
3532 }
3533 else
3534 {
3535 ScheduleGroupForTerseUpdate();
3536 }
2848 } 3537 }
2849 3538
2850 #endregion 3539 #endregion
@@ -2857,17 +3546,6 @@ namespace OpenSim.Region.Framework.Scenes
2857 /// <param name="rot"></param> 3546 /// <param name="rot"></param>
2858 public void UpdateGroupRotationR(Quaternion rot) 3547 public void UpdateGroupRotationR(Quaternion rot)
2859 { 3548 {
2860// m_log.DebugFormat(
2861// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2862
2863// SceneObjectPart[] parts = m_parts.GetArray();
2864// for (int i = 0; i < parts.Length; i++)
2865// parts[i].StoreUndoState();
2866
2867 m_rootPart.StoreUndoState(true);
2868
2869 m_rootPart.UpdateRotation(rot);
2870
2871 PhysicsActor actor = m_rootPart.PhysActor; 3549 PhysicsActor actor = m_rootPart.PhysActor;
2872 if (actor != null) 3550 if (actor != null)
2873 { 3551 {
@@ -2886,16 +3564,6 @@ namespace OpenSim.Region.Framework.Scenes
2886 /// <param name="rot"></param> 3564 /// <param name="rot"></param>
2887 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3565 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2888 { 3566 {
2889// m_log.DebugFormat(
2890// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2891
2892// SceneObjectPart[] parts = m_parts.GetArray();
2893// for (int i = 0; i < parts.Length; i++)
2894// parts[i].StoreUndoState();
2895
2896 RootPart.StoreUndoState(true);
2897 RootPart.IgnoreUndoUpdate = true;
2898
2899 m_rootPart.UpdateRotation(rot); 3567 m_rootPart.UpdateRotation(rot);
2900 3568
2901 PhysicsActor actor = m_rootPart.PhysActor; 3569 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2909,8 +3577,6 @@ namespace OpenSim.Region.Framework.Scenes
2909 3577
2910 HasGroupChanged = true; 3578 HasGroupChanged = true;
2911 ScheduleGroupForTerseUpdate(); 3579 ScheduleGroupForTerseUpdate();
2912
2913 RootPart.IgnoreUndoUpdate = false;
2914 } 3580 }
2915 3581
2916 /// <summary> 3582 /// <summary>
@@ -2923,13 +3589,11 @@ namespace OpenSim.Region.Framework.Scenes
2923 SceneObjectPart part = GetPart(localID); 3589 SceneObjectPart part = GetPart(localID);
2924 3590
2925 SceneObjectPart[] parts = m_parts.GetArray(); 3591 SceneObjectPart[] parts = m_parts.GetArray();
2926 for (int i = 0; i < parts.Length; i++)
2927 parts[i].StoreUndoState();
2928 3592
2929 if (part != null) 3593 if (part != null)
2930 { 3594 {
2931// m_log.DebugFormat( 3595 if (m_rootPart.PhysActor != null)
2932// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3596 m_rootPart.PhysActor.Building = true;
2933 3597
2934 if (part.UUID == m_rootPart.UUID) 3598 if (part.UUID == m_rootPart.UUID)
2935 { 3599 {
@@ -2939,6 +3603,9 @@ namespace OpenSim.Region.Framework.Scenes
2939 { 3603 {
2940 part.UpdateRotation(rot); 3604 part.UpdateRotation(rot);
2941 } 3605 }
3606
3607 if (m_rootPart.PhysActor != null)
3608 m_rootPart.PhysActor.Building = false;
2942 } 3609 }
2943 } 3610 }
2944 3611
@@ -2952,12 +3619,8 @@ namespace OpenSim.Region.Framework.Scenes
2952 SceneObjectPart part = GetPart(localID); 3619 SceneObjectPart part = GetPart(localID);
2953 if (part != null) 3620 if (part != null)
2954 { 3621 {
2955// m_log.DebugFormat( 3622 if (m_rootPart.PhysActor != null)
2956// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3623 m_rootPart.PhysActor.Building = true;
2957// part.Name, part.LocalId, rot);
2958
2959 part.StoreUndoState();
2960 part.IgnoreUndoUpdate = true;
2961 3624
2962 if (part.UUID == m_rootPart.UUID) 3625 if (part.UUID == m_rootPart.UUID)
2963 { 3626 {
@@ -2970,7 +3633,8 @@ namespace OpenSim.Region.Framework.Scenes
2970 part.OffsetPosition = pos; 3633 part.OffsetPosition = pos;
2971 } 3634 }
2972 3635
2973 part.IgnoreUndoUpdate = false; 3636 if (m_rootPart.PhysActor != null)
3637 m_rootPart.PhysActor.Building = false;
2974 } 3638 }
2975 } 3639 }
2976 3640
@@ -2980,15 +3644,12 @@ namespace OpenSim.Region.Framework.Scenes
2980 /// <param name="rot"></param> 3644 /// <param name="rot"></param>
2981 public void UpdateRootRotation(Quaternion rot) 3645 public void UpdateRootRotation(Quaternion rot)
2982 { 3646 {
2983// m_log.DebugFormat( 3647 // needs to be called with phys building true
2984// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
2985// Name, LocalId, rot);
2986
2987 Quaternion axRot = rot; 3648 Quaternion axRot = rot;
2988 Quaternion oldParentRot = m_rootPart.RotationOffset; 3649 Quaternion oldParentRot = m_rootPart.RotationOffset;
2989 3650
2990 m_rootPart.StoreUndoState(); 3651 //Don't use UpdateRotation because it schedules an update prematurely
2991 m_rootPart.UpdateRotation(rot); 3652 m_rootPart.RotationOffset = rot;
2992 3653
2993 PhysicsActor pa = m_rootPart.PhysActor; 3654 PhysicsActor pa = m_rootPart.PhysActor;
2994 3655
@@ -3004,35 +3665,135 @@ namespace OpenSim.Region.Framework.Scenes
3004 SceneObjectPart prim = parts[i]; 3665 SceneObjectPart prim = parts[i];
3005 if (prim.UUID != m_rootPart.UUID) 3666 if (prim.UUID != m_rootPart.UUID)
3006 { 3667 {
3007 prim.IgnoreUndoUpdate = true; 3668 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3669 NewRot = Quaternion.Inverse(axRot) * NewRot;
3670 prim.RotationOffset = NewRot;
3671
3008 Vector3 axPos = prim.OffsetPosition; 3672 Vector3 axPos = prim.OffsetPosition;
3673
3009 axPos *= oldParentRot; 3674 axPos *= oldParentRot;
3010 axPos *= Quaternion.Inverse(axRot); 3675 axPos *= Quaternion.Inverse(axRot);
3011 prim.OffsetPosition = axPos; 3676 prim.OffsetPosition = axPos;
3012 Quaternion primsRot = prim.RotationOffset; 3677 }
3013 Quaternion newRot = oldParentRot * primsRot; 3678 }
3014 newRot = Quaternion.Inverse(axRot) * newRot;
3015 prim.RotationOffset = newRot;
3016 prim.ScheduleTerseUpdate();
3017 prim.IgnoreUndoUpdate = false;
3018 }
3019 }
3020
3021// for (int i = 0; i < parts.Length; i++)
3022// {
3023// SceneObjectPart childpart = parts[i];
3024// if (childpart != m_rootPart)
3025// {
3026//// childpart.IgnoreUndoUpdate = false;
3027//// childpart.StoreUndoState();
3028// }
3029// }
3030 3679
3031 m_rootPart.ScheduleTerseUpdate(); 3680 HasGroupChanged = true;
3681 ScheduleGroupForFullUpdate();
3682 }
3032 3683
3033// m_log.DebugFormat( 3684 private enum updatetype :int
3034// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3685 {
3035// Name, LocalId, rot); 3686 none = 0,
3687 partterse = 1,
3688 partfull = 2,
3689 groupterse = 3,
3690 groupfull = 4
3691 }
3692
3693 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3694 {
3695 // TODO this still as excessive *.Schedule*Update()s
3696
3697 if (part != null && part.ParentGroup != null)
3698 {
3699 ObjectChangeType change = data.change;
3700 bool togroup = ((change & ObjectChangeType.Group) != 0);
3701 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3702
3703 SceneObjectGroup group = part.ParentGroup;
3704 PhysicsActor pha = group.RootPart.PhysActor;
3705
3706 updatetype updateType = updatetype.none;
3707
3708 if (togroup)
3709 {
3710 // related to group
3711 if ((change & ObjectChangeType.Position) != 0)
3712 {
3713 group.AbsolutePosition = data.position;
3714 updateType = updatetype.groupterse;
3715 }
3716 if ((change & ObjectChangeType.Rotation) != 0)
3717 {
3718 group.RootPart.UpdateRotation(data.rotation);
3719 updateType = updatetype.none;
3720 }
3721 if ((change & ObjectChangeType.Scale) != 0)
3722 {
3723 if (pha != null)
3724 pha.Building = true;
3725
3726 group.GroupResize(data.scale);
3727 updateType = updatetype.none;
3728
3729 if (pha != null)
3730 pha.Building = false;
3731 }
3732 }
3733 else
3734 {
3735 // related to single prim in a link-set ( ie group)
3736 if (pha != null)
3737 pha.Building = true;
3738
3739 // root part is special
3740 // parts offset positions or rotations need to change also
3741
3742 if (part == group.RootPart)
3743 {
3744 if ((change & ObjectChangeType.Position) != 0)
3745 group.UpdateRootPosition(data.position);
3746 if ((change & ObjectChangeType.Rotation) != 0)
3747 group.UpdateRootRotation(data.rotation);
3748 if ((change & ObjectChangeType.Scale) != 0)
3749 part.Resize(data.scale);
3750 }
3751 else
3752 {
3753 if ((change & ObjectChangeType.Position) != 0)
3754 {
3755 part.OffsetPosition = data.position;
3756 updateType = updatetype.partterse;
3757 }
3758 if ((change & ObjectChangeType.Rotation) != 0)
3759 {
3760 part.UpdateRotation(data.rotation);
3761 updateType = updatetype.none;
3762 }
3763 if ((change & ObjectChangeType.Scale) != 0)
3764 {
3765 part.Resize(data.scale);
3766 updateType = updatetype.none;
3767 }
3768 }
3769
3770 if (pha != null)
3771 pha.Building = false;
3772 }
3773
3774 if (updateType != updatetype.none)
3775 {
3776 group.HasGroupChanged = true;
3777
3778 switch (updateType)
3779 {
3780 case updatetype.partterse:
3781 part.ScheduleTerseUpdate();
3782 break;
3783 case updatetype.partfull:
3784 part.ScheduleFullUpdate();
3785 break;
3786 case updatetype.groupterse:
3787 group.ScheduleGroupForTerseUpdate();
3788 break;
3789 case updatetype.groupfull:
3790 group.ScheduleGroupForFullUpdate();
3791 break;
3792 default:
3793 break;
3794 }
3795 }
3796 }
3036 } 3797 }
3037 3798
3038 #endregion 3799 #endregion
@@ -3252,11 +4013,38 @@ namespace OpenSim.Region.Framework.Scenes
3252 } 4013 }
3253 } 4014 }
3254 } 4015 }
3255 4016
4017 public Vector3 GetGeometricCenter()
4018 {
4019 // this is not real geometric center but a average of positions relative to root prim acording to
4020 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4021 // ignoring tortured prims details since sl also seems to ignore
4022 // so no real use in doing it on physics
4023
4024 Vector3 gc = Vector3.Zero;
4025
4026 int nparts = m_parts.Count;
4027 if (nparts <= 1)
4028 return gc;
4029
4030 SceneObjectPart[] parts = m_parts.GetArray();
4031 nparts = parts.Length; // just in case it changed
4032 if (nparts <= 1)
4033 return gc;
4034
4035 // average all parts positions
4036 for (int i = 0; i < nparts; i++)
4037 gc += parts[i].GetWorldPosition();
4038 gc /= nparts;
4039
4040 // relative to root:
4041 gc -= AbsolutePosition;
4042 return gc;
4043 }
4044
3256 public float GetMass() 4045 public float GetMass()
3257 { 4046 {
3258 float retmass = 0f; 4047 float retmass = 0f;
3259
3260 SceneObjectPart[] parts = m_parts.GetArray(); 4048 SceneObjectPart[] parts = m_parts.GetArray();
3261 for (int i = 0; i < parts.Length; i++) 4049 for (int i = 0; i < parts.Length; i++)
3262 retmass += parts[i].GetMass(); 4050 retmass += parts[i].GetMass();
@@ -3417,6 +4205,14 @@ namespace OpenSim.Region.Framework.Scenes
3417 FromItemID = uuid; 4205 FromItemID = uuid;
3418 } 4206 }
3419 4207
4208 public void ResetOwnerChangeFlag()
4209 {
4210 ForEachPart(delegate(SceneObjectPart part)
4211 {
4212 part.ResetOwnerChangeFlag();
4213 });
4214 }
4215
3420 #endregion 4216 #endregion
3421 } 4217 }
3422} 4218}