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.cs1367
1 files changed, 1151 insertions, 216 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 45bbbda..bf898bb 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -24,12 +24,13 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System;
29using System.ComponentModel; 29using System.ComponentModel;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Drawing; 31using System.Drawing;
32using System.IO; 32using System.IO;
33using System.Diagnostics;
33using System.Linq; 34using System.Linq;
34using System.Threading; 35using System.Threading;
35using System.Xml; 36using System.Xml;
@@ -43,6 +44,7 @@ using OpenSim.Region.Framework.Scenes.Serialization;
43 44
44namespace OpenSim.Region.Framework.Scenes 45namespace OpenSim.Region.Framework.Scenes
45{ 46{
47
46 [Flags] 48 [Flags]
47 public enum scriptEvents 49 public enum scriptEvents
48 { 50 {
@@ -106,8 +108,12 @@ namespace OpenSim.Region.Framework.Scenes
106 /// since the group's last persistent backup 108 /// since the group's last persistent backup
107 /// </summary> 109 /// </summary>
108 private bool m_hasGroupChanged = false; 110 private bool m_hasGroupChanged = false;
109 private long timeFirstChanged; 111 private long timeFirstChanged = 0;
110 private long timeLastChanged; 112 private long timeLastChanged = 0;
113 private long m_maxPersistTime = 0;
114 private long m_minPersistTime = 0;
115 private Random m_rand;
116 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
111 117
112 /// <summary> 118 /// <summary>
113 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 119 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -124,9 +130,39 @@ namespace OpenSim.Region.Framework.Scenes
124 { 130 {
125 if (value) 131 if (value)
126 { 132 {
133 if (m_isBackedUp)
134 {
135 m_scene.SceneGraph.FireChangeBackup(this);
136 }
127 timeLastChanged = DateTime.Now.Ticks; 137 timeLastChanged = DateTime.Now.Ticks;
128 if (!m_hasGroupChanged) 138 if (!m_hasGroupChanged)
129 timeFirstChanged = DateTime.Now.Ticks; 139 timeFirstChanged = DateTime.Now.Ticks;
140 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
141 {
142 if (m_rand == null)
143 {
144 byte[] val = new byte[16];
145 m_rootPart.UUID.ToBytes(val, 0);
146 m_rand = new Random(BitConverter.ToInt32(val, 0));
147 }
148
149 if (m_scene.GetRootAgentCount() == 0)
150 {
151 //If the region is empty, this change has been made by an automated process
152 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
153
154 float factor = 1.5f + (float)(m_rand.NextDouble());
155 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
156 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
157 }
158 else
159 {
160 //If the region is not empty, we want to obey the minimum and maximum persist times
161 //but add a random factor so we stagger the object persistance a little
162 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
163 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
164 }
165 }
130 } 166 }
131 m_hasGroupChanged = value; 167 m_hasGroupChanged = value;
132 168
@@ -141,7 +177,7 @@ namespace OpenSim.Region.Framework.Scenes
141 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 177 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since
142 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 178 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
143 /// </summary> 179 /// </summary>
144 public bool HasGroupChangedDueToDelink { get; private set; } 180 public bool HasGroupChangedDueToDelink { get; set; }
145 181
146 private bool isTimeToPersist() 182 private bool isTimeToPersist()
147 { 183 {
@@ -151,8 +187,19 @@ namespace OpenSim.Region.Framework.Scenes
151 return false; 187 return false;
152 if (m_scene.ShuttingDown) 188 if (m_scene.ShuttingDown)
153 return true; 189 return true;
190
191 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
192 {
193 m_maxPersistTime = m_scene.m_persistAfter;
194 m_minPersistTime = m_scene.m_dontPersistBefore;
195 }
196
154 long currentTime = DateTime.Now.Ticks; 197 long currentTime = DateTime.Now.Ticks;
155 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 198
199 if (timeLastChanged == 0) timeLastChanged = currentTime;
200 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
201
202 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
156 return true; 203 return true;
157 return false; 204 return false;
158 } 205 }
@@ -271,10 +318,10 @@ namespace OpenSim.Region.Framework.Scenes
271 318
272 private bool m_scriptListens_atTarget; 319 private bool m_scriptListens_atTarget;
273 private bool m_scriptListens_notAtTarget; 320 private bool m_scriptListens_notAtTarget;
274
275 private bool m_scriptListens_atRotTarget; 321 private bool m_scriptListens_atRotTarget;
276 private bool m_scriptListens_notAtRotTarget; 322 private bool m_scriptListens_notAtRotTarget;
277 323
324 public bool m_dupeInProgress = false;
278 internal Dictionary<UUID, string> m_savedScriptState; 325 internal Dictionary<UUID, string> m_savedScriptState;
279 326
280 #region Properties 327 #region Properties
@@ -311,6 +358,16 @@ namespace OpenSim.Region.Framework.Scenes
311 get { return m_parts.Count; } 358 get { return m_parts.Count; }
312 } 359 }
313 360
361// protected Quaternion m_rotation = Quaternion.Identity;
362//
363// public virtual Quaternion Rotation
364// {
365// get { return m_rotation; }
366// set {
367// m_rotation = value;
368// }
369// }
370
314 public Quaternion GroupRotation 371 public Quaternion GroupRotation
315 { 372 {
316 get { return m_rootPart.RotationOffset; } 373 get { return m_rootPart.RotationOffset; }
@@ -417,7 +474,15 @@ namespace OpenSim.Region.Framework.Scenes
417 { 474 {
418 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 475 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
419 } 476 }
420 477
478
479
480 private struct avtocrossInfo
481 {
482 public ScenePresence av;
483 public uint ParentID;
484 }
485
421 /// <summary> 486 /// <summary>
422 /// The absolute position of this scene object in the scene 487 /// The absolute position of this scene object in the scene
423 /// </summary> 488 /// </summary>
@@ -430,14 +495,136 @@ namespace OpenSim.Region.Framework.Scenes
430 495
431 if (Scene != null) 496 if (Scene != null)
432 { 497 {
433 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 498 // if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W)
434 || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 499 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
500 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
501 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
502 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
435 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 503 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
436 { 504 {
437 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 505 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
506 uint x = 0;
507 uint y = 0;
508 string version = String.Empty;
509 Vector3 newpos = Vector3.Zero;
510 OpenSim.Services.Interfaces.GridRegion destination = null;
511
512 if (m_rootPart.KeyframeMotion != null)
513 m_rootPart.KeyframeMotion.StartCrossingCheck();
514
515 bool canCross = true;
516 foreach (ScenePresence av in m_linkedAvatars)
517 {
518 // We need to cross these agents. First, let's find
519 // out if any of them can't cross for some reason.
520 // We have to deny the crossing entirely if any
521 // of them are banned. Alternatively, we could
522 // unsit banned agents....
523
524
525 // We set the avatar position as being the object
526 // position to get the region to send to
527 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
528 {
529 canCross = false;
530 break;
531 }
532
533 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
534 }
535
536 if (canCross)
537 {
538 // We unparent the SP quietly so that it won't
539 // be made to stand up
540
541 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
542
543 foreach (ScenePresence av in m_linkedAvatars)
544 {
545 avtocrossInfo avinfo = new avtocrossInfo();
546 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
547 if (parentPart != null)
548 av.ParentUUID = parentPart.UUID;
549
550 avinfo.av = av;
551 avinfo.ParentID = av.ParentID;
552 avsToCross.Add(avinfo);
553
554 av.ParentID = 0;
555 }
556
557 // m_linkedAvatars.Clear();
558 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
559
560 // Normalize
561 if (val.X >= Constants.RegionSize)
562 val.X -= Constants.RegionSize;
563 if (val.Y >= Constants.RegionSize)
564 val.Y -= Constants.RegionSize;
565 if (val.X < 0)
566 val.X += Constants.RegionSize;
567 if (val.Y < 0)
568 val.Y += Constants.RegionSize;
569
570 // If it's deleted, crossing was successful
571 if (IsDeleted)
572 {
573 // foreach (ScenePresence av in m_linkedAvatars)
574 foreach (avtocrossInfo avinfo in avsToCross)
575 {
576 ScenePresence av = avinfo.av;
577 if (!av.IsInTransit) // just in case...
578 {
579 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
580
581 av.IsInTransit = true;
582
583 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
584 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
585 }
586 else
587 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
588 }
589 avsToCross.Clear();
590 return;
591 }
592 else // cross failed, put avas back ??
593 {
594 foreach (avtocrossInfo avinfo in avsToCross)
595 {
596 ScenePresence av = avinfo.av;
597 av.ParentUUID = UUID.Zero;
598 av.ParentID = avinfo.ParentID;
599// m_linkedAvatars.Add(av);
600 }
601 }
602 avsToCross.Clear();
603
604 }
605 else
606 {
607 if (m_rootPart.KeyframeMotion != null)
608 m_rootPart.KeyframeMotion.CrossingFailure();
609
610 if (RootPart.PhysActor != null)
611 {
612 RootPart.PhysActor.CrossingFailure();
613 }
614 }
615 Vector3 oldp = AbsolutePosition;
616 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
617 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
618 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
438 } 619 }
439 } 620 }
440 621
622/* don't see the need but worse don't see where is restored to false if things stay in
623 foreach (SceneObjectPart part in m_parts.GetArray())
624 {
625 part.IgnoreUndoUpdate = true;
626 }
627 */
441 if (RootPart.GetStatusSandbox()) 628 if (RootPart.GetStatusSandbox())
442 { 629 {
443 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 630 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -455,9 +642,38 @@ namespace OpenSim.Region.Framework.Scenes
455 // Restuff the new GroupPosition into each SOP of the linkset. 642 // Restuff the new GroupPosition into each SOP of the linkset.
456 // This has the affect of resetting and tainting the physics actors. 643 // This has the affect of resetting and tainting the physics actors.
457 SceneObjectPart[] parts = m_parts.GetArray(); 644 SceneObjectPart[] parts = m_parts.GetArray();
458 for (int i = 0; i < parts.Length; i++) 645 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
459 parts[i].GroupPosition = val; 646 if (m_dupeInProgress)
647 triggerScriptEvent = false;
648 foreach (SceneObjectPart part in parts)
649 {
650 part.GroupPosition = val;
651 if (triggerScriptEvent)
652 part.TriggerScriptChangedEvent(Changed.POSITION);
653 }
460 654
655/*
656 This seems not needed and should not be needed:
657 sp absolute position depends on sit part absolute position fixed above.
658 sp ParentPosition is not used anywhere.
659 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
660 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
661
662 if (!m_dupeInProgress)
663 {
664 foreach (ScenePresence av in m_linkedAvatars)
665 {
666 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
667 if (p != null && m_parts.TryGetValue(p.UUID, out p))
668 {
669 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
670 av.AbsolutePosition += offset;
671// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
672 av.SendAvatarDataToAllAgents();
673 }
674 }
675 }
676*/
461 //if (m_rootPart.PhysActor != null) 677 //if (m_rootPart.PhysActor != null)
462 //{ 678 //{
463 //m_rootPart.PhysActor.Position = 679 //m_rootPart.PhysActor.Position =
@@ -471,6 +687,40 @@ namespace OpenSim.Region.Framework.Scenes
471 } 687 }
472 } 688 }
473 689
690 public override Vector3 Velocity
691 {
692 get { return RootPart.Velocity; }
693 set { RootPart.Velocity = value; }
694 }
695
696 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
697 {
698 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
699 ScenePresence agent = icon.EndInvoke(iar);
700
701 //// If the cross was successful, this agent is a child agent
702 if (agent.IsChildAgent)
703 {
704 if (agent.ParentUUID != UUID.Zero)
705 {
706 agent.ParentPart = null;
707// agent.ParentPosition = Vector3.Zero;
708// agent.ParentUUID = UUID.Zero;
709 }
710 }
711
712 agent.ParentUUID = UUID.Zero;
713
714// agent.Reset();
715// else // Not successful
716// agent.RestoreInCurrentScene();
717
718 // In any case
719 agent.IsInTransit = false;
720
721 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
722 }
723
474 public override uint LocalId 724 public override uint LocalId
475 { 725 {
476 get { return m_rootPart.LocalId; } 726 get { return m_rootPart.LocalId; }
@@ -541,6 +791,11 @@ namespace OpenSim.Region.Framework.Scenes
541 m_isSelected = value; 791 m_isSelected = value;
542 // Tell physics engine that group is selected 792 // Tell physics engine that group is selected
543 793
794 // this is not right
795 // but ode engines should only really need to know about root part
796 // so they can put entire object simulation on hold and not colliding
797 // keep as was for now
798
544 PhysicsActor pa = m_rootPart.PhysActor; 799 PhysicsActor pa = m_rootPart.PhysActor;
545 if (pa != null) 800 if (pa != null)
546 { 801 {
@@ -557,6 +812,42 @@ namespace OpenSim.Region.Framework.Scenes
557 childPa.Selected = value; 812 childPa.Selected = value;
558 } 813 }
559 } 814 }
815 if (RootPart.KeyframeMotion != null)
816 RootPart.KeyframeMotion.Selected = value;
817 }
818 }
819
820 public void PartSelectChanged(bool partSelect)
821 {
822 // any part selected makes group selected
823 if (m_isSelected == partSelect)
824 return;
825
826 if (partSelect)
827 {
828 IsSelected = partSelect;
829// if (!IsAttachment)
830// ScheduleGroupForFullUpdate();
831 }
832 else
833 {
834 // bad bad bad 2 heavy for large linksets
835 // since viewer does send lot of (un)selects
836 // this needs to be replaced by a specific list or count ?
837 // but that will require extra code in several places
838
839 SceneObjectPart[] parts = m_parts.GetArray();
840 for (int i = 0; i < parts.Length; i++)
841 {
842 SceneObjectPart part = parts[i];
843 if (part.IsSelected)
844 return;
845 }
846 IsSelected = partSelect;
847 if (!IsAttachment)
848 {
849 ScheduleGroupForFullUpdate();
850 }
560 } 851 }
561 } 852 }
562 853
@@ -642,6 +933,7 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 933 /// </summary>
643 public SceneObjectGroup() 934 public SceneObjectGroup()
644 { 935 {
936
645 } 937 }
646 938
647 /// <summary> 939 /// <summary>
@@ -659,8 +951,8 @@ namespace OpenSim.Region.Framework.Scenes
659 /// Constructor. This object is added to the scene later via AttachToScene() 951 /// Constructor. This object is added to the scene later via AttachToScene()
660 /// </summary> 952 /// </summary>
661 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 953 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
662 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 954 {
663 { 955 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
664 } 956 }
665 957
666 /// <summary> 958 /// <summary>
@@ -695,6 +987,9 @@ namespace OpenSim.Region.Framework.Scenes
695 /// </summary> 987 /// </summary>
696 public virtual void AttachToBackup() 988 public virtual void AttachToBackup()
697 { 989 {
990 if (IsAttachment) return;
991 m_scene.SceneGraph.FireAttachToBackup(this);
992
698 if (InSceneBackup) 993 if (InSceneBackup)
699 { 994 {
700 //m_log.DebugFormat( 995 //m_log.DebugFormat(
@@ -737,6 +1032,13 @@ namespace OpenSim.Region.Framework.Scenes
737 1032
738 ApplyPhysics(); 1033 ApplyPhysics();
739 1034
1035 if (RootPart.PhysActor != null)
1036 RootPart.Force = RootPart.Force;
1037 if (RootPart.PhysActor != null)
1038 RootPart.Torque = RootPart.Torque;
1039 if (RootPart.PhysActor != null)
1040 RootPart.Buoyancy = RootPart.Buoyancy;
1041
740 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1042 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
741 // for the same object with very different properties. The caller must schedule the update. 1043 // for the same object with very different properties. The caller must schedule the update.
742 //ScheduleGroupForFullUpdate(); 1044 //ScheduleGroupForFullUpdate();
@@ -752,6 +1054,10 @@ namespace OpenSim.Region.Framework.Scenes
752 EntityIntersection result = new EntityIntersection(); 1054 EntityIntersection result = new EntityIntersection();
753 1055
754 SceneObjectPart[] parts = m_parts.GetArray(); 1056 SceneObjectPart[] parts = m_parts.GetArray();
1057
1058 // Find closest hit here
1059 float idist = float.MaxValue;
1060
755 for (int i = 0; i < parts.Length; i++) 1061 for (int i = 0; i < parts.Length; i++)
756 { 1062 {
757 SceneObjectPart part = parts[i]; 1063 SceneObjectPart part = parts[i];
@@ -766,11 +1072,6 @@ namespace OpenSim.Region.Framework.Scenes
766 1072
767 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1073 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
768 1074
769 // This may need to be updated to the maximum draw distance possible..
770 // We might (and probably will) be checking for prim creation from other sims
771 // when the camera crosses the border.
772 float idist = Constants.RegionSize;
773
774 if (inter.HitTF) 1075 if (inter.HitTF)
775 { 1076 {
776 // We need to find the closest prim to return to the testcaller along the ray 1077 // We need to find the closest prim to return to the testcaller along the ray
@@ -781,10 +1082,11 @@ namespace OpenSim.Region.Framework.Scenes
781 result.obj = part; 1082 result.obj = part;
782 result.normal = inter.normal; 1083 result.normal = inter.normal;
783 result.distance = inter.distance; 1084 result.distance = inter.distance;
1085
1086 idist = inter.distance;
784 } 1087 }
785 } 1088 }
786 } 1089 }
787
788 return result; 1090 return result;
789 } 1091 }
790 1092
@@ -796,25 +1098,27 @@ namespace OpenSim.Region.Framework.Scenes
796 /// <returns></returns> 1098 /// <returns></returns>
797 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1099 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
798 { 1100 {
799 maxX = -256f; 1101 maxX = float.MinValue;
800 maxY = -256f; 1102 maxY = float.MinValue;
801 maxZ = -256f; 1103 maxZ = float.MinValue;
802 minX = 256f; 1104 minX = float.MaxValue;
803 minY = 256f; 1105 minY = float.MaxValue;
804 minZ = 8192f; 1106 minZ = float.MaxValue;
805 1107
806 SceneObjectPart[] parts = m_parts.GetArray(); 1108 SceneObjectPart[] parts = m_parts.GetArray();
807 for (int i = 0; i < parts.Length; i++) 1109 foreach (SceneObjectPart part in parts)
808 { 1110 {
809 SceneObjectPart part = parts[i];
810
811 Vector3 worldPos = part.GetWorldPosition(); 1111 Vector3 worldPos = part.GetWorldPosition();
812 Vector3 offset = worldPos - AbsolutePosition; 1112 Vector3 offset = worldPos - AbsolutePosition;
813 Quaternion worldRot; 1113 Quaternion worldRot;
814 if (part.ParentID == 0) 1114 if (part.ParentID == 0)
1115 {
815 worldRot = part.RotationOffset; 1116 worldRot = part.RotationOffset;
1117 }
816 else 1118 else
1119 {
817 worldRot = part.GetWorldRotation(); 1120 worldRot = part.GetWorldRotation();
1121 }
818 1122
819 Vector3 frontTopLeft; 1123 Vector3 frontTopLeft;
820 Vector3 frontTopRight; 1124 Vector3 frontTopRight;
@@ -826,6 +1130,8 @@ namespace OpenSim.Region.Framework.Scenes
826 Vector3 backBottomLeft; 1130 Vector3 backBottomLeft;
827 Vector3 backBottomRight; 1131 Vector3 backBottomRight;
828 1132
1133 // Vector3[] corners = new Vector3[8];
1134
829 Vector3 orig = Vector3.Zero; 1135 Vector3 orig = Vector3.Zero;
830 1136
831 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1137 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -860,6 +1166,38 @@ namespace OpenSim.Region.Framework.Scenes
860 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1166 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
861 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1167 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
862 1168
1169
1170
1171 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1172 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1173 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1174 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1175 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1176 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1177 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1178 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1179
1180 //for (int i = 0; i < 8; i++)
1181 //{
1182 // corners[i] = corners[i] * worldRot;
1183 // corners[i] += offset;
1184
1185 // if (corners[i].X > maxX)
1186 // maxX = corners[i].X;
1187 // if (corners[i].X < minX)
1188 // minX = corners[i].X;
1189
1190 // if (corners[i].Y > maxY)
1191 // maxY = corners[i].Y;
1192 // if (corners[i].Y < minY)
1193 // minY = corners[i].Y;
1194
1195 // if (corners[i].Z > maxZ)
1196 // maxZ = corners[i].Y;
1197 // if (corners[i].Z < minZ)
1198 // minZ = corners[i].Z;
1199 //}
1200
863 frontTopLeft = frontTopLeft * worldRot; 1201 frontTopLeft = frontTopLeft * worldRot;
864 frontTopRight = frontTopRight * worldRot; 1202 frontTopRight = frontTopRight * worldRot;
865 frontBottomLeft = frontBottomLeft * worldRot; 1203 frontBottomLeft = frontBottomLeft * worldRot;
@@ -881,6 +1219,15 @@ namespace OpenSim.Region.Framework.Scenes
881 backTopLeft += offset; 1219 backTopLeft += offset;
882 backTopRight += offset; 1220 backTopRight += offset;
883 1221
1222 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1223 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1224 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1225 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1226 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1227 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1228 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1229 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1230
884 if (frontTopRight.X > maxX) 1231 if (frontTopRight.X > maxX)
885 maxX = frontTopRight.X; 1232 maxX = frontTopRight.X;
886 if (frontTopLeft.X > maxX) 1233 if (frontTopLeft.X > maxX)
@@ -1024,17 +1371,118 @@ namespace OpenSim.Region.Framework.Scenes
1024 1371
1025 #endregion 1372 #endregion
1026 1373
1374 public void GetResourcesCosts(SceneObjectPart apart,
1375 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1376 {
1377 // this information may need to be cached
1378
1379 float cost;
1380 float tmpcost;
1381
1382 bool ComplexCost = false;
1383
1384 SceneObjectPart p;
1385 SceneObjectPart[] parts;
1386
1387 lock (m_parts)
1388 {
1389 parts = m_parts.GetArray();
1390 }
1391
1392 int nparts = parts.Length;
1393
1394
1395 for (int i = 0; i < nparts; i++)
1396 {
1397 p = parts[i];
1398
1399 if (p.UsesComplexCost)
1400 {
1401 ComplexCost = true;
1402 break;
1403 }
1404 }
1405
1406 if (ComplexCost)
1407 {
1408 linksetResCost = 0;
1409 linksetPhysCost = 0;
1410 partCost = 0;
1411 partPhysCost = 0;
1412
1413 for (int i = 0; i < nparts; i++)
1414 {
1415 p = parts[i];
1416
1417 cost = p.StreamingCost;
1418 tmpcost = p.SimulationCost;
1419 if (tmpcost > cost)
1420 cost = tmpcost;
1421 tmpcost = p.PhysicsCost;
1422 if (tmpcost > cost)
1423 cost = tmpcost;
1424
1425 linksetPhysCost += tmpcost;
1426 linksetResCost += cost;
1427
1428 if (p == apart)
1429 {
1430 partCost = cost;
1431 partPhysCost = tmpcost;
1432 }
1433 }
1434 }
1435 else
1436 {
1437 partPhysCost = 1.0f;
1438 partCost = 1.0f;
1439 linksetResCost = (float)nparts;
1440 linksetPhysCost = linksetResCost;
1441 }
1442 }
1443
1444 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1445 {
1446 SceneObjectPart p;
1447 SceneObjectPart[] parts;
1448
1449 lock (m_parts)
1450 {
1451 parts = m_parts.GetArray();
1452 }
1453
1454 int nparts = parts.Length;
1455
1456 PhysCost = 0;
1457 StreamCost = 0;
1458 SimulCost = 0;
1459
1460 for (int i = 0; i < nparts; i++)
1461 {
1462 p = parts[i];
1463
1464 StreamCost += p.StreamingCost;
1465 SimulCost += p.SimulationCost;
1466 PhysCost += p.PhysicsCost;
1467 }
1468 }
1469
1027 public void SaveScriptedState(XmlTextWriter writer) 1470 public void SaveScriptedState(XmlTextWriter writer)
1028 { 1471 {
1472 SaveScriptedState(writer, false);
1473 }
1474
1475 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1476 {
1029 XmlDocument doc = new XmlDocument(); 1477 XmlDocument doc = new XmlDocument();
1030 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1478 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1031 1479
1032 SceneObjectPart[] parts = m_parts.GetArray(); 1480 SceneObjectPart[] parts = m_parts.GetArray();
1033 for (int i = 0; i < parts.Length; i++) 1481 for (int i = 0; i < parts.Length; i++)
1034 { 1482 {
1035 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1483 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1036 foreach (KeyValuePair<UUID, string> kvp in pstates) 1484 foreach (KeyValuePair<UUID, string> kvp in pstates)
1037 states.Add(kvp.Key, kvp.Value); 1485 states[kvp.Key] = kvp.Value;
1038 } 1486 }
1039 1487
1040 if (states.Count > 0) 1488 if (states.Count > 0)
@@ -1054,6 +1502,169 @@ namespace OpenSim.Region.Framework.Scenes
1054 } 1502 }
1055 1503
1056 /// <summary> 1504 /// <summary>
1505 /// Add the avatar to this linkset (avatar is sat).
1506 /// </summary>
1507 /// <param name="agentID"></param>
1508 public void AddAvatar(UUID agentID)
1509 {
1510 ScenePresence presence;
1511 if (m_scene.TryGetScenePresence(agentID, out presence))
1512 {
1513 if (!m_linkedAvatars.Contains(presence))
1514 {
1515 m_linkedAvatars.Add(presence);
1516 }
1517 }
1518 }
1519
1520 /// <summary>
1521 /// Delete the avatar from this linkset (avatar is unsat).
1522 /// </summary>
1523 /// <param name="agentID"></param>
1524 public void DeleteAvatar(UUID agentID)
1525 {
1526 ScenePresence presence;
1527 if (m_scene.TryGetScenePresence(agentID, out presence))
1528 {
1529 if (m_linkedAvatars.Contains(presence))
1530 {
1531 m_linkedAvatars.Remove(presence);
1532 }
1533 }
1534 }
1535
1536 /// <summary>
1537 /// Returns the list of linked presences (avatars sat on this group)
1538 /// </summary>
1539 /// <param name="agentID"></param>
1540 public List<ScenePresence> GetLinkedAvatars()
1541 {
1542 return m_linkedAvatars;
1543 }
1544
1545 /// <summary>
1546 /// Attach this scene object to the given avatar.
1547 /// </summary>
1548 /// <param name="agentID"></param>
1549 /// <param name="attachmentpoint"></param>
1550 /// <param name="AttachOffset"></param>
1551 private void AttachToAgent(
1552 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1553 {
1554 if (avatar != null)
1555 {
1556 // don't attach attachments to child agents
1557 if (avatar.IsChildAgent) return;
1558
1559 // Remove from database and parcel prim count
1560 m_scene.DeleteFromStorage(so.UUID);
1561 m_scene.EventManager.TriggerParcelPrimCountTainted();
1562
1563 so.AttachedAvatar = avatar.UUID;
1564
1565 if (so.RootPart.PhysActor != null)
1566 {
1567 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1568 so.RootPart.PhysActor = null;
1569 }
1570
1571 so.AbsolutePosition = attachOffset;
1572 so.RootPart.AttachedPos = attachOffset;
1573 so.IsAttachment = true;
1574 so.RootPart.SetParentLocalId(avatar.LocalId);
1575 so.AttachmentPoint = attachmentpoint;
1576
1577 avatar.AddAttachment(this);
1578
1579 if (!silent)
1580 {
1581 // Killing it here will cause the client to deselect it
1582 // It then reappears on the avatar, deselected
1583 // through the full update below
1584 //
1585 if (IsSelected)
1586 {
1587 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1588 }
1589
1590 IsSelected = false; // fudge....
1591 ScheduleGroupForFullUpdate();
1592 }
1593 }
1594 else
1595 {
1596 m_log.WarnFormat(
1597 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1598 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1599 }
1600 }
1601
1602 public byte GetAttachmentPoint()
1603 {
1604 return m_rootPart.Shape.State;
1605 }
1606
1607 public void DetachToGround()
1608 {
1609 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1610 if (avatar == null)
1611 return;
1612
1613 avatar.RemoveAttachment(this);
1614
1615 Vector3 detachedpos = new Vector3(127f,127f,127f);
1616 if (avatar == null)
1617 return;
1618
1619 detachedpos = avatar.AbsolutePosition;
1620 FromItemID = UUID.Zero;
1621
1622 AbsolutePosition = detachedpos;
1623 AttachedAvatar = UUID.Zero;
1624
1625 //SceneObjectPart[] parts = m_parts.GetArray();
1626 //for (int i = 0; i < parts.Length; i++)
1627 // parts[i].AttachedAvatar = UUID.Zero;
1628
1629 m_rootPart.SetParentLocalId(0);
1630 AttachmentPoint = (byte)0;
1631 // must check if buildind should be true or false here
1632 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1633 HasGroupChanged = true;
1634 RootPart.Rezzed = DateTime.Now;
1635 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1636 AttachToBackup();
1637 m_scene.EventManager.TriggerParcelPrimCountTainted();
1638 m_rootPart.ScheduleFullUpdate();
1639 m_rootPart.ClearUndoState();
1640 }
1641
1642 public void DetachToInventoryPrep()
1643 {
1644 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1645 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1646 if (avatar != null)
1647 {
1648 //detachedpos = avatar.AbsolutePosition;
1649 avatar.RemoveAttachment(this);
1650 }
1651
1652 AttachedAvatar = UUID.Zero;
1653
1654 /*SceneObjectPart[] parts = m_parts.GetArray();
1655 for (int i = 0; i < parts.Length; i++)
1656 parts[i].AttachedAvatar = UUID.Zero;*/
1657
1658 m_rootPart.SetParentLocalId(0);
1659 //m_rootPart.SetAttachmentPoint((byte)0);
1660 IsAttachment = false;
1661 AbsolutePosition = m_rootPart.AttachedPos;
1662 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1663 //AttachToBackup();
1664 //m_rootPart.ScheduleFullUpdate();
1665 }
1666
1667 /// <summary>
1057 /// 1668 ///
1058 /// </summary> 1669 /// </summary>
1059 /// <param name="part"></param> 1670 /// <param name="part"></param>
@@ -1093,7 +1704,10 @@ namespace OpenSim.Region.Framework.Scenes
1093 public void AddPart(SceneObjectPart part) 1704 public void AddPart(SceneObjectPart part)
1094 { 1705 {
1095 part.SetParent(this); 1706 part.SetParent(this);
1096 part.LinkNum = m_parts.Add(part.UUID, part); 1707 m_parts.Add(part.UUID, part);
1708
1709 part.LinkNum = m_parts.Count;
1710
1097 if (part.LinkNum == 2) 1711 if (part.LinkNum == 2)
1098 RootPart.LinkNum = 1; 1712 RootPart.LinkNum = 1;
1099 } 1713 }
@@ -1119,6 +1733,14 @@ namespace OpenSim.Region.Framework.Scenes
1119 parts[i].UUID = UUID.Random(); 1733 parts[i].UUID = UUID.Random();
1120 } 1734 }
1121 1735
1736 // helper provided for parts.
1737 public int GetSceneMaxUndo()
1738 {
1739 if (m_scene != null)
1740 return m_scene.MaxUndoCount;
1741 return 5;
1742 }
1743
1122 // justincc: I don't believe this hack is needed any longer, especially since the physics 1744 // justincc: I don't believe this hack is needed any longer, especially since the physics
1123 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1745 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1124 // this method was preventing proper reload of scene objects. 1746 // this method was preventing proper reload of scene objects.
@@ -1176,7 +1798,7 @@ namespace OpenSim.Region.Framework.Scenes
1176// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1798// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1177// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1799// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1178 1800
1179 part.StoreUndoState(); 1801// part.StoreUndoState();
1180 part.OnGrab(offsetPos, remoteClient); 1802 part.OnGrab(offsetPos, remoteClient);
1181 } 1803 }
1182 1804
@@ -1196,6 +1818,11 @@ namespace OpenSim.Region.Framework.Scenes
1196 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1818 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1197 public void DeleteGroupFromScene(bool silent) 1819 public void DeleteGroupFromScene(bool silent)
1198 { 1820 {
1821 // We need to keep track of this state in case this group is still queued for backup.
1822 IsDeleted = true;
1823
1824 DetachFromBackup();
1825
1199 SceneObjectPart[] parts = m_parts.GetArray(); 1826 SceneObjectPart[] parts = m_parts.GetArray();
1200 for (int i = 0; i < parts.Length; i++) 1827 for (int i = 0; i < parts.Length; i++)
1201 { 1828 {
@@ -1219,6 +1846,7 @@ namespace OpenSim.Region.Framework.Scenes
1219 } 1846 }
1220 }); 1847 });
1221 } 1848 }
1849
1222 } 1850 }
1223 1851
1224 public void AddScriptLPS(int count) 1852 public void AddScriptLPS(int count)
@@ -1288,28 +1916,43 @@ namespace OpenSim.Region.Framework.Scenes
1288 /// </summary> 1916 /// </summary>
1289 public void ApplyPhysics() 1917 public void ApplyPhysics()
1290 { 1918 {
1291 // Apply physics to the root prim
1292 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1293
1294 // Apply physics to child prims
1295 SceneObjectPart[] parts = m_parts.GetArray(); 1919 SceneObjectPart[] parts = m_parts.GetArray();
1296 if (parts.Length > 1) 1920 if (parts.Length > 1)
1297 { 1921 {
1922 ResetChildPrimPhysicsPositions();
1923
1924 // Apply physics to the root prim
1925 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1926
1927
1298 for (int i = 0; i < parts.Length; i++) 1928 for (int i = 0; i < parts.Length; i++)
1299 { 1929 {
1300 SceneObjectPart part = parts[i]; 1930 SceneObjectPart part = parts[i];
1301 if (part.LocalId != m_rootPart.LocalId) 1931 if (part.LocalId != m_rootPart.LocalId)
1302 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1932 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1303 } 1933 }
1304
1305 // Hack to get the physics scene geometries in the right spot 1934 // Hack to get the physics scene geometries in the right spot
1306 ResetChildPrimPhysicsPositions(); 1935// ResetChildPrimPhysicsPositions();
1936 if (m_rootPart.PhysActor != null)
1937 {
1938 m_rootPart.PhysActor.Building = false;
1939 }
1940 }
1941 else
1942 {
1943 // Apply physics to the root prim
1944 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1307 } 1945 }
1308 } 1946 }
1309 1947
1310 public void SetOwnerId(UUID userId) 1948 public void SetOwnerId(UUID userId)
1311 { 1949 {
1312 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1950 ForEachPart(delegate(SceneObjectPart part)
1951 {
1952
1953 part.OwnerID = userId;
1954
1955 });
1313 } 1956 }
1314 1957
1315 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1958 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1341,11 +1984,17 @@ namespace OpenSim.Region.Framework.Scenes
1341 return; 1984 return;
1342 } 1985 }
1343 1986
1987 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1988 return;
1989
1344 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1990 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1345 // any exception propogate upwards. 1991 // any exception propogate upwards.
1346 try 1992 try
1347 { 1993 {
1348 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 1994 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
1995 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
1996 m_scene.LoadingPrims) // Land may not be valid yet
1997
1349 { 1998 {
1350 ILandObject parcel = m_scene.LandChannel.GetLandObject( 1999 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1351 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2000 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1372,6 +2021,7 @@ namespace OpenSim.Region.Framework.Scenes
1372 } 2021 }
1373 } 2022 }
1374 } 2023 }
2024
1375 } 2025 }
1376 2026
1377 if (m_scene.UseBackup && HasGroupChanged) 2027 if (m_scene.UseBackup && HasGroupChanged)
@@ -1379,10 +2029,30 @@ namespace OpenSim.Region.Framework.Scenes
1379 // don't backup while it's selected or you're asking for changes mid stream. 2029 // don't backup while it's selected or you're asking for changes mid stream.
1380 if (isTimeToPersist() || forcedBackup) 2030 if (isTimeToPersist() || forcedBackup)
1381 { 2031 {
2032 if (m_rootPart.PhysActor != null &&
2033 (!m_rootPart.PhysActor.IsPhysical))
2034 {
2035 // Possible ghost prim
2036 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2037 {
2038 foreach (SceneObjectPart part in m_parts.GetArray())
2039 {
2040 // Re-set physics actor positions and
2041 // orientations
2042 part.GroupPosition = m_rootPart.GroupPosition;
2043 }
2044 }
2045 }
1382// m_log.DebugFormat( 2046// m_log.DebugFormat(
1383// "[SCENE]: Storing {0}, {1} in {2}", 2047// "[SCENE]: Storing {0}, {1} in {2}",
1384// Name, UUID, m_scene.RegionInfo.RegionName); 2048// Name, UUID, m_scene.RegionInfo.RegionName);
1385 2049
2050 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2051 {
2052 RootPart.Shape.State = 0;
2053 ScheduleGroupForFullUpdate();
2054 }
2055
1386 SceneObjectGroup backup_group = Copy(false); 2056 SceneObjectGroup backup_group = Copy(false);
1387 backup_group.RootPart.Velocity = RootPart.Velocity; 2057 backup_group.RootPart.Velocity = RootPart.Velocity;
1388 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2058 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1392,6 +2062,16 @@ namespace OpenSim.Region.Framework.Scenes
1392 HasGroupChangedDueToDelink = false; 2062 HasGroupChangedDueToDelink = false;
1393 2063
1394 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2064 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2065/*
2066 backup_group.ForEachPart(delegate(SceneObjectPart part)
2067 {
2068 if (part.KeyframeMotion != null)
2069 {
2070 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2071// part.KeyframeMotion.UpdateSceneObject(this);
2072 }
2073 });
2074*/
1395 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2075 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1396 2076
1397 backup_group.ForEachPart(delegate(SceneObjectPart part) 2077 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1448,10 +2128,14 @@ namespace OpenSim.Region.Framework.Scenes
1448 /// <returns></returns> 2128 /// <returns></returns>
1449 public SceneObjectGroup Copy(bool userExposed) 2129 public SceneObjectGroup Copy(bool userExposed)
1450 { 2130 {
2131 m_dupeInProgress = true;
1451 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2132 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1452 dupe.m_isBackedUp = false; 2133 dupe.m_isBackedUp = false;
1453 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2134 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1454 2135
2136 // new group as no sitting avatars
2137 dupe.m_linkedAvatars = new List<ScenePresence>();
2138
1455 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2139 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1456 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2140 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1457 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2141 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1462,7 +2146,7 @@ namespace OpenSim.Region.Framework.Scenes
1462 // This is only necessary when userExposed is false! 2146 // This is only necessary when userExposed is false!
1463 2147
1464 bool previousAttachmentStatus = dupe.IsAttachment; 2148 bool previousAttachmentStatus = dupe.IsAttachment;
1465 2149
1466 if (!userExposed) 2150 if (!userExposed)
1467 dupe.IsAttachment = true; 2151 dupe.IsAttachment = true;
1468 2152
@@ -1475,16 +2159,17 @@ namespace OpenSim.Region.Framework.Scenes
1475 2159
1476 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2160 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1477 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2161 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2162
1478 2163
1479 if (userExposed) 2164 if (userExposed)
1480 dupe.m_rootPart.TrimPermissions(); 2165 dupe.m_rootPart.TrimPermissions();
1481 2166
1482 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2167 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1483 2168
1484 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2169 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1485 { 2170 {
1486 return p1.LinkNum.CompareTo(p2.LinkNum); 2171 return p1.LinkNum.CompareTo(p2.LinkNum);
1487 } 2172 }
1488 ); 2173 );
1489 2174
1490 foreach (SceneObjectPart part in partList) 2175 foreach (SceneObjectPart part in partList)
@@ -1494,41 +2179,56 @@ namespace OpenSim.Region.Framework.Scenes
1494 { 2179 {
1495 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2180 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1496 newPart.LinkNum = part.LinkNum; 2181 newPart.LinkNum = part.LinkNum;
1497 } 2182 if (userExposed)
2183 newPart.ParentID = dupe.m_rootPart.LocalId;
2184 }
1498 else 2185 else
1499 { 2186 {
1500 newPart = dupe.m_rootPart; 2187 newPart = dupe.m_rootPart;
1501 } 2188 }
2189/*
2190 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2191 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1502 2192
1503 // Need to duplicate the physics actor as well 2193 // Need to duplicate the physics actor as well
1504 PhysicsActor originalPartPa = part.PhysActor; 2194 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1505 if (originalPartPa != null && userExposed)
1506 { 2195 {
1507 PrimitiveBaseShape pbs = newPart.Shape; 2196 PrimitiveBaseShape pbs = newPart.Shape;
1508
1509 newPart.PhysActor 2197 newPart.PhysActor
1510 = m_scene.PhysicsScene.AddPrimShape( 2198 = m_scene.PhysicsScene.AddPrimShape(
1511 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2199 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1512 pbs, 2200 pbs,
1513 newPart.AbsolutePosition, 2201 newPart.AbsolutePosition,
1514 newPart.Scale, 2202 newPart.Scale,
1515 newPart.RotationOffset, 2203 newPart.GetWorldRotation(),
1516 originalPartPa.IsPhysical, 2204 isphys,
2205 isphan,
1517 newPart.LocalId); 2206 newPart.LocalId);
1518 2207
1519 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2208 newPart.DoPhysicsPropertyUpdate(isphys, true);
1520 } 2209 */
2210 if (userExposed)
2211 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2212// }
2213 // copy keyframemotion
2214 if (part.KeyframeMotion != null)
2215 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1521 } 2216 }
1522 2217
1523 if (userExposed) 2218 if (userExposed)
1524 { 2219 {
1525 dupe.UpdateParentIDs(); 2220// done above dupe.UpdateParentIDs();
2221
2222 if (dupe.m_rootPart.PhysActor != null)
2223 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2224
1526 dupe.HasGroupChanged = true; 2225 dupe.HasGroupChanged = true;
1527 dupe.AttachToBackup(); 2226 dupe.AttachToBackup();
1528 2227
1529 ScheduleGroupForFullUpdate(); 2228 ScheduleGroupForFullUpdate();
1530 } 2229 }
1531 2230
2231 m_dupeInProgress = false;
1532 return dupe; 2232 return dupe;
1533 } 2233 }
1534 2234
@@ -1540,11 +2240,24 @@ namespace OpenSim.Region.Framework.Scenes
1540 /// <param name="cGroupID"></param> 2240 /// <param name="cGroupID"></param>
1541 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2241 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1542 { 2242 {
1543 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2243 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2244 // give newpart a new local ID lettng old part keep same
2245 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2246 newpart.LocalId = m_scene.AllocateLocalId();
2247
2248 SetRootPart(newpart);
2249 if (userExposed)
2250 RootPart.Velocity = Vector3.Zero; // In case source is moving
1544 } 2251 }
1545 2252
1546 public void ScriptSetPhysicsStatus(bool usePhysics) 2253 public void ScriptSetPhysicsStatus(bool usePhysics)
1547 { 2254 {
2255 if (usePhysics)
2256 {
2257 if (RootPart.KeyframeMotion != null)
2258 RootPart.KeyframeMotion.Stop();
2259 RootPart.KeyframeMotion = null;
2260 }
1548 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2261 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1549 } 2262 }
1550 2263
@@ -1592,27 +2305,14 @@ namespace OpenSim.Region.Framework.Scenes
1592 2305
1593 if (pa != null) 2306 if (pa != null)
1594 { 2307 {
1595 pa.AddForce(impulse, true); 2308 // false to be applied as a impulse
1596 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2309 pa.AddForce(impulse, false);
1597 }
1598 }
1599 }
1600
1601 public void applyAngularImpulse(Vector3 impulse)
1602 {
1603 PhysicsActor pa = RootPart.PhysActor;
1604
1605 if (pa != null)
1606 {
1607 if (!IsAttachment)
1608 {
1609 pa.AddAngularForce(impulse, true);
1610 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2310 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1611 } 2311 }
1612 } 2312 }
1613 } 2313 }
1614 2314
1615 public void setAngularImpulse(Vector3 impulse) 2315 public void ApplyAngularImpulse(Vector3 impulse)
1616 { 2316 {
1617 PhysicsActor pa = RootPart.PhysActor; 2317 PhysicsActor pa = RootPart.PhysActor;
1618 2318
@@ -1620,7 +2320,8 @@ namespace OpenSim.Region.Framework.Scenes
1620 { 2320 {
1621 if (!IsAttachment) 2321 if (!IsAttachment)
1622 { 2322 {
1623 pa.Torque = impulse; 2323 // false to be applied as a impulse
2324 pa.AddAngularForce(impulse, false);
1624 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2325 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1625 } 2326 }
1626 } 2327 }
@@ -1628,20 +2329,10 @@ namespace OpenSim.Region.Framework.Scenes
1628 2329
1629 public Vector3 GetTorque() 2330 public Vector3 GetTorque()
1630 { 2331 {
1631 PhysicsActor pa = RootPart.PhysActor; 2332 return RootPart.Torque;
1632
1633 if (pa != null)
1634 {
1635 if (!IsAttachment)
1636 {
1637 Vector3 torque = pa.Torque;
1638 return torque;
1639 }
1640 }
1641
1642 return Vector3.Zero;
1643 } 2333 }
1644 2334
2335 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1645 public void moveToTarget(Vector3 target, float tau) 2336 public void moveToTarget(Vector3 target, float tau)
1646 { 2337 {
1647 if (IsAttachment) 2338 if (IsAttachment)
@@ -1673,6 +2364,46 @@ namespace OpenSim.Region.Framework.Scenes
1673 pa.PIDActive = false; 2364 pa.PIDActive = false;
1674 } 2365 }
1675 2366
2367 public void rotLookAt(Quaternion target, float strength, float damping)
2368 {
2369 SceneObjectPart rootpart = m_rootPart;
2370 if (rootpart != null)
2371 {
2372 if (IsAttachment)
2373 {
2374 /*
2375 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2376 if (avatar != null)
2377 {
2378 Rotate the Av?
2379 } */
2380 }
2381 else
2382 {
2383 if (rootpart.PhysActor != null)
2384 { // APID must be implemented in your physics system for this to function.
2385 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2386 rootpart.PhysActor.APIDStrength = strength;
2387 rootpart.PhysActor.APIDDamping = damping;
2388 rootpart.PhysActor.APIDActive = true;
2389 }
2390 }
2391 }
2392 }
2393
2394 public void stopLookAt()
2395 {
2396 SceneObjectPart rootpart = m_rootPart;
2397 if (rootpart != null)
2398 {
2399 if (rootpart.PhysActor != null)
2400 { // APID must be implemented in your physics system for this to function.
2401 rootpart.PhysActor.APIDActive = false;
2402 }
2403 }
2404
2405 }
2406
1676 /// <summary> 2407 /// <summary>
1677 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2408 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1678 /// </summary> 2409 /// </summary>
@@ -1689,7 +2420,7 @@ namespace OpenSim.Region.Framework.Scenes
1689 { 2420 {
1690 pa.PIDHoverHeight = height; 2421 pa.PIDHoverHeight = height;
1691 pa.PIDHoverType = hoverType; 2422 pa.PIDHoverType = hoverType;
1692 pa.PIDTau = tau; 2423 pa.PIDHoverTau = tau;
1693 pa.PIDHoverActive = true; 2424 pa.PIDHoverActive = true;
1694 } 2425 }
1695 else 2426 else
@@ -1729,7 +2460,12 @@ namespace OpenSim.Region.Framework.Scenes
1729 /// <param name="cGroupID"></param> 2460 /// <param name="cGroupID"></param>
1730 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2461 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1731 { 2462 {
1732 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2463 // give new ID to the new part, letting old keep original
2464 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2465 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2466 newPart.LocalId = m_scene.AllocateLocalId();
2467 newPart.SetParent(this);
2468
1733 AddPart(newPart); 2469 AddPart(newPart);
1734 2470
1735 SetPartAsNonRoot(newPart); 2471 SetPartAsNonRoot(newPart);
@@ -1868,11 +2604,11 @@ namespace OpenSim.Region.Framework.Scenes
1868 /// Immediately send a full update for this scene object. 2604 /// Immediately send a full update for this scene object.
1869 /// </summary> 2605 /// </summary>
1870 public void SendGroupFullUpdate() 2606 public void SendGroupFullUpdate()
1871 { 2607 {
1872 if (IsDeleted) 2608 if (IsDeleted)
1873 return; 2609 return;
1874 2610
1875// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2611// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1876 2612
1877 RootPart.SendFullUpdateToAllClients(); 2613 RootPart.SendFullUpdateToAllClients();
1878 2614
@@ -2028,6 +2764,11 @@ namespace OpenSim.Region.Framework.Scenes
2028 // 'linkPart' == the root of the group being linked into this group 2764 // 'linkPart' == the root of the group being linked into this group
2029 SceneObjectPart linkPart = objectGroup.m_rootPart; 2765 SceneObjectPart linkPart = objectGroup.m_rootPart;
2030 2766
2767 if (m_rootPart.PhysActor != null)
2768 m_rootPart.PhysActor.Building = true;
2769 if (linkPart.PhysActor != null)
2770 linkPart.PhysActor.Building = true;
2771
2031 // physics flags from group to be applied to linked parts 2772 // physics flags from group to be applied to linked parts
2032 bool grpusephys = UsesPhysics; 2773 bool grpusephys = UsesPhysics;
2033 bool grptemporary = IsTemporary; 2774 bool grptemporary = IsTemporary;
@@ -2053,12 +2794,12 @@ namespace OpenSim.Region.Framework.Scenes
2053 Vector3 axPos = linkPart.OffsetPosition; 2794 Vector3 axPos = linkPart.OffsetPosition;
2054 // Rotate the linking root SOP's position to be relative to the new root prim 2795 // Rotate the linking root SOP's position to be relative to the new root prim
2055 Quaternion parentRot = m_rootPart.RotationOffset; 2796 Quaternion parentRot = m_rootPart.RotationOffset;
2056 axPos *= Quaternion.Inverse(parentRot); 2797 axPos *= Quaternion.Conjugate(parentRot);
2057 linkPart.OffsetPosition = axPos; 2798 linkPart.OffsetPosition = axPos;
2058 2799
2059 // Make the linking root SOP's rotation relative to the new root prim 2800 // Make the linking root SOP's rotation relative to the new root prim
2060 Quaternion oldRot = linkPart.RotationOffset; 2801 Quaternion oldRot = linkPart.RotationOffset;
2061 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2802 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2062 linkPart.RotationOffset = newRot; 2803 linkPart.RotationOffset = newRot;
2063 2804
2064 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2805 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2092,7 +2833,7 @@ namespace OpenSim.Region.Framework.Scenes
2092 linkPart.CreateSelected = true; 2833 linkPart.CreateSelected = true;
2093 2834
2094 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2835 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2095 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2836 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2096 2837
2097 // If the added SOP is physical, also tell the physics engine about the link relationship. 2838 // If the added SOP is physical, also tell the physics engine about the link relationship.
2098 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2839 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2102,6 +2843,7 @@ namespace OpenSim.Region.Framework.Scenes
2102 } 2843 }
2103 2844
2104 linkPart.LinkNum = linkNum++; 2845 linkPart.LinkNum = linkNum++;
2846 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2105 2847
2106 // Get a list of the SOP's in the old group in order of their linknum's. 2848 // Get a list of the SOP's in the old group in order of their linknum's.
2107 SceneObjectPart[] ogParts = objectGroup.Parts; 2849 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2120,7 +2862,7 @@ namespace OpenSim.Region.Framework.Scenes
2120 2862
2121 // Update the physics flags for the newly added SOP 2863 // Update the physics flags for the newly added SOP
2122 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2864 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2123 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2865 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2124 2866
2125 // If the added SOP is physical, also tell the physics engine about the link relationship. 2867 // If the added SOP is physical, also tell the physics engine about the link relationship.
2126 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2868 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2138,7 +2880,7 @@ namespace OpenSim.Region.Framework.Scenes
2138 objectGroup.IsDeleted = true; 2880 objectGroup.IsDeleted = true;
2139 2881
2140 objectGroup.m_parts.Clear(); 2882 objectGroup.m_parts.Clear();
2141 2883
2142 // Can't do this yet since backup still makes use of the root part without any synchronization 2884 // Can't do this yet since backup still makes use of the root part without any synchronization
2143// objectGroup.m_rootPart = null; 2885// objectGroup.m_rootPart = null;
2144 2886
@@ -2152,6 +2894,9 @@ namespace OpenSim.Region.Framework.Scenes
2152 // unmoved prims! 2894 // unmoved prims!
2153 ResetChildPrimPhysicsPositions(); 2895 ResetChildPrimPhysicsPositions();
2154 2896
2897 if (m_rootPart.PhysActor != null)
2898 m_rootPart.PhysActor.Building = false;
2899
2155 //HasGroupChanged = true; 2900 //HasGroupChanged = true;
2156 //ScheduleGroupForFullUpdate(); 2901 //ScheduleGroupForFullUpdate();
2157 } 2902 }
@@ -2219,7 +2964,10 @@ namespace OpenSim.Region.Framework.Scenes
2219// m_log.DebugFormat( 2964// m_log.DebugFormat(
2220// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2965// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2221// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2966// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2222 2967
2968 if (m_rootPart.PhysActor != null)
2969 m_rootPart.PhysActor.Building = true;
2970
2223 linkPart.ClearUndoState(); 2971 linkPart.ClearUndoState();
2224 2972
2225 Vector3 worldPos = linkPart.GetWorldPosition(); 2973 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2290,6 +3038,14 @@ namespace OpenSim.Region.Framework.Scenes
2290 3038
2291 // When we delete a group, we currently have to force persist to the database if the object id has changed 3039 // When we delete a group, we currently have to force persist to the database if the object id has changed
2292 // (since delete works by deleting all rows which have a given object id) 3040 // (since delete works by deleting all rows which have a given object id)
3041
3042 // this is as it seems to be in sl now
3043 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3044 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3045
3046 if (m_rootPart.PhysActor != null)
3047 m_rootPart.PhysActor.Building = false;
3048
2293 objectGroup.HasGroupChangedDueToDelink = true; 3049 objectGroup.HasGroupChangedDueToDelink = true;
2294 3050
2295 return objectGroup; 3051 return objectGroup;
@@ -2301,6 +3057,8 @@ namespace OpenSim.Region.Framework.Scenes
2301 /// <param name="objectGroup"></param> 3057 /// <param name="objectGroup"></param>
2302 public virtual void DetachFromBackup() 3058 public virtual void DetachFromBackup()
2303 { 3059 {
3060 if (m_scene != null)
3061 m_scene.SceneGraph.FireDetachFromBackup(this);
2304 if (m_isBackedUp && Scene != null) 3062 if (m_isBackedUp && Scene != null)
2305 m_scene.EventManager.OnBackup -= ProcessBackup; 3063 m_scene.EventManager.OnBackup -= ProcessBackup;
2306 3064
@@ -2321,7 +3079,8 @@ namespace OpenSim.Region.Framework.Scenes
2321 Vector3 axPos = part.OffsetPosition; 3079 Vector3 axPos = part.OffsetPosition;
2322 axPos *= parentRot; 3080 axPos *= parentRot;
2323 part.OffsetPosition = axPos; 3081 part.OffsetPosition = axPos;
2324 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3082 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3083 part.GroupPosition = newPos;
2325 part.OffsetPosition = Vector3.Zero; 3084 part.OffsetPosition = Vector3.Zero;
2326 3085
2327 // Compution our rotation to be not relative to the old parent 3086 // Compution our rotation to be not relative to the old parent
@@ -2336,7 +3095,7 @@ namespace OpenSim.Region.Framework.Scenes
2336 part.LinkNum = linkNum; 3095 part.LinkNum = linkNum;
2337 3096
2338 // Compute the new position of this SOP relative to the group position 3097 // Compute the new position of this SOP relative to the group position
2339 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3098 part.OffsetPosition = newPos - AbsolutePosition;
2340 3099
2341 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3100 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2342 // It would have the affect of setting the physics engine position multiple 3101 // It would have the affect of setting the physics engine position multiple
@@ -2346,18 +3105,19 @@ namespace OpenSim.Region.Framework.Scenes
2346 // Rotate the relative position by the rotation of the group 3105 // Rotate the relative position by the rotation of the group
2347 Quaternion rootRotation = m_rootPart.RotationOffset; 3106 Quaternion rootRotation = m_rootPart.RotationOffset;
2348 Vector3 pos = part.OffsetPosition; 3107 Vector3 pos = part.OffsetPosition;
2349 pos *= Quaternion.Inverse(rootRotation); 3108 pos *= Quaternion.Conjugate(rootRotation);
2350 part.OffsetPosition = pos; 3109 part.OffsetPosition = pos;
2351 3110
2352 // Compute the SOP's rotation relative to the rotation of the group. 3111 // Compute the SOP's rotation relative to the rotation of the group.
2353 parentRot = m_rootPart.RotationOffset; 3112 parentRot = m_rootPart.RotationOffset;
2354 oldRot = part.RotationOffset; 3113 oldRot = part.RotationOffset;
2355 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3114 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2356 part.RotationOffset = newRot; 3115 part.RotationOffset = newRot;
2357 3116
2358 // Since this SOP's state has changed, push those changes into the physics engine 3117 // Since this SOP's state has changed, push those changes into the physics engine
2359 // and the simulator. 3118 // and the simulator.
2360 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3119 // done on caller
3120// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2361 } 3121 }
2362 3122
2363 /// <summary> 3123 /// <summary>
@@ -2379,10 +3139,14 @@ namespace OpenSim.Region.Framework.Scenes
2379 { 3139 {
2380 if (!m_rootPart.BlockGrab) 3140 if (!m_rootPart.BlockGrab)
2381 { 3141 {
2382 Vector3 llmoveforce = pos - AbsolutePosition; 3142/* Vector3 llmoveforce = pos - AbsolutePosition;
2383 Vector3 grabforce = llmoveforce; 3143 Vector3 grabforce = llmoveforce;
2384 grabforce = (grabforce / 10) * pa.Mass; 3144 grabforce = (grabforce / 10) * pa.Mass;
2385 pa.AddForce(grabforce, true); 3145 */
3146 // empirically convert distance diference to a impulse
3147 Vector3 grabforce = pos - AbsolutePosition;
3148 grabforce = grabforce * (pa.Mass/ 10.0f);
3149 pa.AddForce(grabforce, false);
2386 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3150 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2387 } 3151 }
2388 } 3152 }
@@ -2578,6 +3342,8 @@ namespace OpenSim.Region.Framework.Scenes
2578 /// <param name="SetVolumeDetect"></param> 3342 /// <param name="SetVolumeDetect"></param>
2579 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3343 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2580 { 3344 {
3345 HasGroupChanged = true;
3346
2581 SceneObjectPart selectionPart = GetPart(localID); 3347 SceneObjectPart selectionPart = GetPart(localID);
2582 3348
2583 if (SetTemporary && Scene != null) 3349 if (SetTemporary && Scene != null)
@@ -2608,8 +3374,22 @@ namespace OpenSim.Region.Framework.Scenes
2608 } 3374 }
2609 } 3375 }
2610 3376
2611 for (int i = 0; i < parts.Length; i++) 3377 if (parts.Length > 1)
2612 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3378 {
3379 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3380
3381 for (int i = 0; i < parts.Length; i++)
3382 {
3383
3384 if (parts[i].UUID != m_rootPart.UUID)
3385 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3386 }
3387
3388 if (m_rootPart.PhysActor != null)
3389 m_rootPart.PhysActor.Building = false;
3390 }
3391 else
3392 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2613 } 3393 }
2614 } 3394 }
2615 3395
@@ -2622,6 +3402,17 @@ namespace OpenSim.Region.Framework.Scenes
2622 } 3402 }
2623 } 3403 }
2624 3404
3405
3406
3407 /// <summary>
3408 /// Gets the number of parts
3409 /// </summary>
3410 /// <returns></returns>
3411 public int GetPartCount()
3412 {
3413 return Parts.Count();
3414 }
3415
2625 /// <summary> 3416 /// <summary>
2626 /// Update the texture entry for this part 3417 /// Update the texture entry for this part
2627 /// </summary> 3418 /// </summary>
@@ -2697,8 +3488,6 @@ namespace OpenSim.Region.Framework.Scenes
2697 3488
2698 PhysicsActor pa = m_rootPart.PhysActor; 3489 PhysicsActor pa = m_rootPart.PhysActor;
2699 3490
2700 RootPart.StoreUndoState(true);
2701
2702 if (Scene != null) 3491 if (Scene != null)
2703 { 3492 {
2704 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3493 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2726,7 +3515,6 @@ namespace OpenSim.Region.Framework.Scenes
2726 SceneObjectPart obPart = parts[i]; 3515 SceneObjectPart obPart = parts[i];
2727 if (obPart.UUID != m_rootPart.UUID) 3516 if (obPart.UUID != m_rootPart.UUID)
2728 { 3517 {
2729// obPart.IgnoreUndoUpdate = true;
2730 Vector3 oldSize = new Vector3(obPart.Scale); 3518 Vector3 oldSize = new Vector3(obPart.Scale);
2731 3519
2732 float f = 1.0f; 3520 float f = 1.0f;
@@ -2838,8 +3626,6 @@ namespace OpenSim.Region.Framework.Scenes
2838 z *= a; 3626 z *= a;
2839 } 3627 }
2840 } 3628 }
2841
2842// obPart.IgnoreUndoUpdate = false;
2843 } 3629 }
2844 } 3630 }
2845 } 3631 }
@@ -2849,9 +3635,7 @@ namespace OpenSim.Region.Framework.Scenes
2849 prevScale.Y *= y; 3635 prevScale.Y *= y;
2850 prevScale.Z *= z; 3636 prevScale.Z *= z;
2851 3637
2852// RootPart.IgnoreUndoUpdate = true;
2853 RootPart.Resize(prevScale); 3638 RootPart.Resize(prevScale);
2854// RootPart.IgnoreUndoUpdate = false;
2855 3639
2856 for (int i = 0; i < parts.Length; i++) 3640 for (int i = 0; i < parts.Length; i++)
2857 { 3641 {
@@ -2859,8 +3643,6 @@ namespace OpenSim.Region.Framework.Scenes
2859 3643
2860 if (obPart.UUID != m_rootPart.UUID) 3644 if (obPart.UUID != m_rootPart.UUID)
2861 { 3645 {
2862 obPart.IgnoreUndoUpdate = true;
2863
2864 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3646 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2865 currentpos.X *= x; 3647 currentpos.X *= x;
2866 currentpos.Y *= y; 3648 currentpos.Y *= y;
@@ -2873,16 +3655,12 @@ namespace OpenSim.Region.Framework.Scenes
2873 3655
2874 obPart.Resize(newSize); 3656 obPart.Resize(newSize);
2875 obPart.UpdateOffSet(currentpos); 3657 obPart.UpdateOffSet(currentpos);
2876
2877 obPart.IgnoreUndoUpdate = false;
2878 } 3658 }
2879 3659
2880// obPart.IgnoreUndoUpdate = false; 3660 HasGroupChanged = true;
2881// obPart.StoreUndoState(); 3661 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3662 ScheduleGroupForTerseUpdate();
2882 } 3663 }
2883
2884// m_log.DebugFormat(
2885// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2886 } 3664 }
2887 3665
2888 #endregion 3666 #endregion
@@ -2895,14 +3673,6 @@ namespace OpenSim.Region.Framework.Scenes
2895 /// <param name="pos"></param> 3673 /// <param name="pos"></param>
2896 public void UpdateGroupPosition(Vector3 pos) 3674 public void UpdateGroupPosition(Vector3 pos)
2897 { 3675 {
2898// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2899
2900 RootPart.StoreUndoState(true);
2901
2902// SceneObjectPart[] parts = m_parts.GetArray();
2903// for (int i = 0; i < parts.Length; i++)
2904// parts[i].StoreUndoState();
2905
2906 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3676 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2907 { 3677 {
2908 if (IsAttachment) 3678 if (IsAttachment)
@@ -2935,21 +3705,17 @@ namespace OpenSim.Region.Framework.Scenes
2935 /// </summary> 3705 /// </summary>
2936 /// <param name="pos"></param> 3706 /// <param name="pos"></param>
2937 /// <param name="localID"></param> 3707 /// <param name="localID"></param>
3708 ///
3709
2938 public void UpdateSinglePosition(Vector3 pos, uint localID) 3710 public void UpdateSinglePosition(Vector3 pos, uint localID)
2939 { 3711 {
2940 SceneObjectPart part = GetPart(localID); 3712 SceneObjectPart part = GetPart(localID);
2941 3713
2942// SceneObjectPart[] parts = m_parts.GetArray();
2943// for (int i = 0; i < parts.Length; i++)
2944// parts[i].StoreUndoState();
2945
2946 if (part != null) 3714 if (part != null)
2947 { 3715 {
2948// m_log.DebugFormat( 3716// unlock parts position change
2949// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3717 if (m_rootPart.PhysActor != null)
2950 3718 m_rootPart.PhysActor.Building = true;
2951 part.StoreUndoState(false);
2952 part.IgnoreUndoUpdate = true;
2953 3719
2954 if (part.UUID == m_rootPart.UUID) 3720 if (part.UUID == m_rootPart.UUID)
2955 { 3721 {
@@ -2960,8 +3726,10 @@ namespace OpenSim.Region.Framework.Scenes
2960 part.UpdateOffSet(pos); 3726 part.UpdateOffSet(pos);
2961 } 3727 }
2962 3728
3729 if (m_rootPart.PhysActor != null)
3730 m_rootPart.PhysActor.Building = false;
3731
2963 HasGroupChanged = true; 3732 HasGroupChanged = true;
2964 part.IgnoreUndoUpdate = false;
2965 } 3733 }
2966 } 3734 }
2967 3735
@@ -2971,13 +3739,7 @@ namespace OpenSim.Region.Framework.Scenes
2971 /// <param name="pos"></param> 3739 /// <param name="pos"></param>
2972 public void UpdateRootPosition(Vector3 pos) 3740 public void UpdateRootPosition(Vector3 pos)
2973 { 3741 {
2974// m_log.DebugFormat( 3742 // needs to be called with phys building true
2975// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2976
2977// SceneObjectPart[] parts = m_parts.GetArray();
2978// for (int i = 0; i < parts.Length; i++)
2979// parts[i].StoreUndoState();
2980
2981 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3743 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2982 Vector3 oldPos = 3744 Vector3 oldPos =
2983 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3745 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3000,7 +3762,14 @@ namespace OpenSim.Region.Framework.Scenes
3000 AbsolutePosition = newPos; 3762 AbsolutePosition = newPos;
3001 3763
3002 HasGroupChanged = true; 3764 HasGroupChanged = true;
3003 ScheduleGroupForTerseUpdate(); 3765 if (m_rootPart.Undoing)
3766 {
3767 ScheduleGroupForFullUpdate();
3768 }
3769 else
3770 {
3771 ScheduleGroupForTerseUpdate();
3772 }
3004 } 3773 }
3005 3774
3006 #endregion 3775 #endregion
@@ -3013,24 +3782,16 @@ namespace OpenSim.Region.Framework.Scenes
3013 /// <param name="rot"></param> 3782 /// <param name="rot"></param>
3014 public void UpdateGroupRotationR(Quaternion rot) 3783 public void UpdateGroupRotationR(Quaternion rot)
3015 { 3784 {
3016// m_log.DebugFormat(
3017// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3018
3019// SceneObjectPart[] parts = m_parts.GetArray();
3020// for (int i = 0; i < parts.Length; i++)
3021// parts[i].StoreUndoState();
3022
3023 m_rootPart.StoreUndoState(true);
3024
3025 m_rootPart.UpdateRotation(rot); 3785 m_rootPart.UpdateRotation(rot);
3026 3786
3787/* this is done by rootpart RotationOffset set called by UpdateRotation
3027 PhysicsActor actor = m_rootPart.PhysActor; 3788 PhysicsActor actor = m_rootPart.PhysActor;
3028 if (actor != null) 3789 if (actor != null)
3029 { 3790 {
3030 actor.Orientation = m_rootPart.RotationOffset; 3791 actor.Orientation = m_rootPart.RotationOffset;
3031 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3792 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3032 } 3793 }
3033 3794*/
3034 HasGroupChanged = true; 3795 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3796 ScheduleGroupForTerseUpdate();
3036 } 3797 }
@@ -3042,16 +3803,6 @@ namespace OpenSim.Region.Framework.Scenes
3042 /// <param name="rot"></param> 3803 /// <param name="rot"></param>
3043 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3804 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3044 { 3805 {
3045// m_log.DebugFormat(
3046// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3047
3048// SceneObjectPart[] parts = m_parts.GetArray();
3049// for (int i = 0; i < parts.Length; i++)
3050// parts[i].StoreUndoState();
3051
3052 RootPart.StoreUndoState(true);
3053 RootPart.IgnoreUndoUpdate = true;
3054
3055 m_rootPart.UpdateRotation(rot); 3806 m_rootPart.UpdateRotation(rot);
3056 3807
3057 PhysicsActor actor = m_rootPart.PhysActor; 3808 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3070,8 +3821,6 @@ namespace OpenSim.Region.Framework.Scenes
3070 3821
3071 HasGroupChanged = true; 3822 HasGroupChanged = true;
3072 ScheduleGroupForTerseUpdate(); 3823 ScheduleGroupForTerseUpdate();
3073
3074 RootPart.IgnoreUndoUpdate = false;
3075 } 3824 }
3076 3825
3077 /// <summary> 3826 /// <summary>
@@ -3084,13 +3833,11 @@ namespace OpenSim.Region.Framework.Scenes
3084 SceneObjectPart part = GetPart(localID); 3833 SceneObjectPart part = GetPart(localID);
3085 3834
3086 SceneObjectPart[] parts = m_parts.GetArray(); 3835 SceneObjectPart[] parts = m_parts.GetArray();
3087 for (int i = 0; i < parts.Length; i++)
3088 parts[i].StoreUndoState();
3089 3836
3090 if (part != null) 3837 if (part != null)
3091 { 3838 {
3092// m_log.DebugFormat( 3839 if (m_rootPart.PhysActor != null)
3093// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3840 m_rootPart.PhysActor.Building = true;
3094 3841
3095 if (part.UUID == m_rootPart.UUID) 3842 if (part.UUID == m_rootPart.UUID)
3096 { 3843 {
@@ -3100,6 +3847,9 @@ namespace OpenSim.Region.Framework.Scenes
3100 { 3847 {
3101 part.UpdateRotation(rot); 3848 part.UpdateRotation(rot);
3102 } 3849 }
3850
3851 if (m_rootPart.PhysActor != null)
3852 m_rootPart.PhysActor.Building = false;
3103 } 3853 }
3104 } 3854 }
3105 3855
@@ -3113,12 +3863,8 @@ namespace OpenSim.Region.Framework.Scenes
3113 SceneObjectPart part = GetPart(localID); 3863 SceneObjectPart part = GetPart(localID);
3114 if (part != null) 3864 if (part != null)
3115 { 3865 {
3116// m_log.DebugFormat( 3866 if (m_rootPart.PhysActor != null)
3117// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3867 m_rootPart.PhysActor.Building = true;
3118// part.Name, part.LocalId, rot);
3119
3120 part.StoreUndoState();
3121 part.IgnoreUndoUpdate = true;
3122 3868
3123 if (part.UUID == m_rootPart.UUID) 3869 if (part.UUID == m_rootPart.UUID)
3124 { 3870 {
@@ -3131,7 +3877,8 @@ namespace OpenSim.Region.Framework.Scenes
3131 part.OffsetPosition = pos; 3877 part.OffsetPosition = pos;
3132 } 3878 }
3133 3879
3134 part.IgnoreUndoUpdate = false; 3880 if (m_rootPart.PhysActor != null)
3881 m_rootPart.PhysActor.Building = false;
3135 } 3882 }
3136 } 3883 }
3137 3884
@@ -3141,15 +3888,12 @@ namespace OpenSim.Region.Framework.Scenes
3141 /// <param name="rot"></param> 3888 /// <param name="rot"></param>
3142 public void UpdateRootRotation(Quaternion rot) 3889 public void UpdateRootRotation(Quaternion rot)
3143 { 3890 {
3144// m_log.DebugFormat( 3891 // needs to be called with phys building true
3145// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3146// Name, LocalId, rot);
3147
3148 Quaternion axRot = rot; 3892 Quaternion axRot = rot;
3149 Quaternion oldParentRot = m_rootPart.RotationOffset; 3893 Quaternion oldParentRot = m_rootPart.RotationOffset;
3150 3894
3151 m_rootPart.StoreUndoState(); 3895 //Don't use UpdateRotation because it schedules an update prematurely
3152 m_rootPart.UpdateRotation(rot); 3896 m_rootPart.RotationOffset = rot;
3153 3897
3154 PhysicsActor pa = m_rootPart.PhysActor; 3898 PhysicsActor pa = m_rootPart.PhysActor;
3155 3899
@@ -3165,35 +3909,145 @@ namespace OpenSim.Region.Framework.Scenes
3165 SceneObjectPart prim = parts[i]; 3909 SceneObjectPart prim = parts[i];
3166 if (prim.UUID != m_rootPart.UUID) 3910 if (prim.UUID != m_rootPart.UUID)
3167 { 3911 {
3168 prim.IgnoreUndoUpdate = true; 3912 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3913 NewRot = Quaternion.Inverse(axRot) * NewRot;
3914 prim.RotationOffset = NewRot;
3915
3169 Vector3 axPos = prim.OffsetPosition; 3916 Vector3 axPos = prim.OffsetPosition;
3917
3170 axPos *= oldParentRot; 3918 axPos *= oldParentRot;
3171 axPos *= Quaternion.Inverse(axRot); 3919 axPos *= Quaternion.Inverse(axRot);
3172 prim.OffsetPosition = axPos; 3920 prim.OffsetPosition = axPos;
3173 Quaternion primsRot = prim.RotationOffset; 3921 }
3174 Quaternion newRot = oldParentRot * primsRot; 3922 }
3175 newRot = Quaternion.Inverse(axRot) * newRot;
3176 prim.RotationOffset = newRot;
3177 prim.ScheduleTerseUpdate();
3178 prim.IgnoreUndoUpdate = false;
3179 }
3180 }
3181
3182// for (int i = 0; i < parts.Length; i++)
3183// {
3184// SceneObjectPart childpart = parts[i];
3185// if (childpart != m_rootPart)
3186// {
3187//// childpart.IgnoreUndoUpdate = false;
3188//// childpart.StoreUndoState();
3189// }
3190// }
3191 3923
3192 m_rootPart.ScheduleTerseUpdate(); 3924 HasGroupChanged = true;
3925 ScheduleGroupForFullUpdate();
3926 }
3193 3927
3194// m_log.DebugFormat( 3928 private enum updatetype :int
3195// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3929 {
3196// Name, LocalId, rot); 3930 none = 0,
3931 partterse = 1,
3932 partfull = 2,
3933 groupterse = 3,
3934 groupfull = 4
3935 }
3936
3937 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3938 {
3939 // TODO this still as excessive *.Schedule*Update()s
3940
3941 if (part != null && part.ParentGroup != null)
3942 {
3943 ObjectChangeType change = data.change;
3944 bool togroup = ((change & ObjectChangeType.Group) != 0);
3945 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3946
3947 SceneObjectGroup group = part.ParentGroup;
3948 PhysicsActor pha = group.RootPart.PhysActor;
3949
3950 updatetype updateType = updatetype.none;
3951
3952 if (togroup)
3953 {
3954 // related to group
3955 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3956 {
3957 if ((change & ObjectChangeType.Rotation) != 0)
3958 {
3959 group.RootPart.UpdateRotation(data.rotation);
3960 updateType = updatetype.none;
3961 }
3962 if ((change & ObjectChangeType.Position) != 0)
3963 {
3964 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3965 UpdateGroupPosition(data.position);
3966 updateType = updatetype.groupterse;
3967 }
3968 else
3969 // ugly rotation update of all parts
3970 {
3971 group.ResetChildPrimPhysicsPositions();
3972 }
3973
3974 }
3975 if ((change & ObjectChangeType.Scale) != 0)
3976 {
3977 if (pha != null)
3978 pha.Building = true;
3979
3980 group.GroupResize(data.scale);
3981 updateType = updatetype.none;
3982
3983 if (pha != null)
3984 pha.Building = false;
3985 }
3986 }
3987 else
3988 {
3989 // related to single prim in a link-set ( ie group)
3990 if (pha != null)
3991 pha.Building = true;
3992
3993 // root part is special
3994 // parts offset positions or rotations need to change also
3995
3996 if (part == group.RootPart)
3997 {
3998 if ((change & ObjectChangeType.Rotation) != 0)
3999 group.UpdateRootRotation(data.rotation);
4000 if ((change & ObjectChangeType.Position) != 0)
4001 group.UpdateRootPosition(data.position);
4002 if ((change & ObjectChangeType.Scale) != 0)
4003 part.Resize(data.scale);
4004 }
4005 else
4006 {
4007 if ((change & ObjectChangeType.Position) != 0)
4008 {
4009 part.OffsetPosition = data.position;
4010 updateType = updatetype.partterse;
4011 }
4012 if ((change & ObjectChangeType.Rotation) != 0)
4013 {
4014 part.UpdateRotation(data.rotation);
4015 updateType = updatetype.none;
4016 }
4017 if ((change & ObjectChangeType.Scale) != 0)
4018 {
4019 part.Resize(data.scale);
4020 updateType = updatetype.none;
4021 }
4022 }
4023
4024 if (pha != null)
4025 pha.Building = false;
4026 }
4027
4028 if (updateType != updatetype.none)
4029 {
4030 group.HasGroupChanged = true;
4031
4032 switch (updateType)
4033 {
4034 case updatetype.partterse:
4035 part.ScheduleTerseUpdate();
4036 break;
4037 case updatetype.partfull:
4038 part.ScheduleFullUpdate();
4039 break;
4040 case updatetype.groupterse:
4041 group.ScheduleGroupForTerseUpdate();
4042 break;
4043 case updatetype.groupfull:
4044 group.ScheduleGroupForFullUpdate();
4045 break;
4046 default:
4047 break;
4048 }
4049 }
4050 }
3197 } 4051 }
3198 4052
3199 #endregion 4053 #endregion
@@ -3292,10 +4146,11 @@ namespace OpenSim.Region.Framework.Scenes
3292 scriptPosTarget target = m_targets[idx]; 4146 scriptPosTarget target = m_targets[idx];
3293 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4147 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3294 { 4148 {
4149 at_target = true;
4150
3295 // trigger at_target 4151 // trigger at_target
3296 if (m_scriptListens_atTarget) 4152 if (m_scriptListens_atTarget)
3297 { 4153 {
3298 at_target = true;
3299 scriptPosTarget att = new scriptPosTarget(); 4154 scriptPosTarget att = new scriptPosTarget();
3300 att.targetPos = target.targetPos; 4155 att.targetPos = target.targetPos;
3301 att.tolerance = target.tolerance; 4156 att.tolerance = target.tolerance;
@@ -3413,11 +4268,50 @@ namespace OpenSim.Region.Framework.Scenes
3413 } 4268 }
3414 } 4269 }
3415 } 4270 }
3416 4271
4272 public Vector3 GetGeometricCenter()
4273 {
4274 // this is not real geometric center but a average of positions relative to root prim acording to
4275 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4276 // ignoring tortured prims details since sl also seems to ignore
4277 // so no real use in doing it on physics
4278
4279 Vector3 gc = Vector3.Zero;
4280
4281 int nparts = m_parts.Count;
4282 if (nparts <= 1)
4283 return gc;
4284
4285 SceneObjectPart[] parts = m_parts.GetArray();
4286 nparts = parts.Length; // just in case it changed
4287 if (nparts <= 1)
4288 return gc;
4289
4290 Quaternion parentRot = RootPart.RotationOffset;
4291 Vector3 pPos;
4292
4293 // average all parts positions
4294 for (int i = 0; i < nparts; i++)
4295 {
4296 // do it directly
4297 // gc += parts[i].GetWorldPosition();
4298 if (parts[i] != RootPart)
4299 {
4300 pPos = parts[i].OffsetPosition;
4301 gc += pPos;
4302 }
4303
4304 }
4305 gc /= nparts;
4306
4307 // relative to root:
4308// gc -= AbsolutePosition;
4309 return gc;
4310 }
4311
3417 public float GetMass() 4312 public float GetMass()
3418 { 4313 {
3419 float retmass = 0f; 4314 float retmass = 0f;
3420
3421 SceneObjectPart[] parts = m_parts.GetArray(); 4315 SceneObjectPart[] parts = m_parts.GetArray();
3422 for (int i = 0; i < parts.Length; i++) 4316 for (int i = 0; i < parts.Length; i++)
3423 retmass += parts[i].GetMass(); 4317 retmass += parts[i].GetMass();
@@ -3425,6 +4319,39 @@ namespace OpenSim.Region.Framework.Scenes
3425 return retmass; 4319 return retmass;
3426 } 4320 }
3427 4321
4322 // center of mass of full object
4323 public Vector3 GetCenterOfMass()
4324 {
4325 PhysicsActor pa = RootPart.PhysActor;
4326
4327 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4328 {
4329 // physics knows better about center of mass of physical prims
4330 Vector3 tmp = pa.CenterOfMass;
4331 return tmp;
4332 }
4333
4334 Vector3 Ptot = Vector3.Zero;
4335 float totmass = 0f;
4336 float m;
4337
4338 SceneObjectPart[] parts = m_parts.GetArray();
4339 for (int i = 0; i < parts.Length; i++)
4340 {
4341 m = parts[i].GetMass();
4342 Ptot += parts[i].GetPartCenterOfMass() * m;
4343 totmass += m;
4344 }
4345
4346 if (totmass == 0)
4347 totmass = 0;
4348 else
4349 totmass = 1 / totmass;
4350 Ptot *= totmass;
4351
4352 return Ptot;
4353 }
4354
3428 /// <summary> 4355 /// <summary>
3429 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4356 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3430 /// the physics engine can use it. 4357 /// the physics engine can use it.
@@ -3592,6 +4519,14 @@ namespace OpenSim.Region.Framework.Scenes
3592 FromItemID = uuid; 4519 FromItemID = uuid;
3593 } 4520 }
3594 4521
4522 public void ResetOwnerChangeFlag()
4523 {
4524 ForEachPart(delegate(SceneObjectPart part)
4525 {
4526 part.ResetOwnerChangeFlag();
4527 });
4528 }
4529
3595 #endregion 4530 #endregion
3596 } 4531 }
3597} 4532}