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.cs1363
1 files changed, 1144 insertions, 219 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 7b284ae..d51281d 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,29 @@ 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 bool m_suspendUpdates;
117 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
118
119 public bool areUpdatesSuspended
120 {
121 get
122 {
123 return m_suspendUpdates;
124 }
125 set
126 {
127 m_suspendUpdates = value;
128 if (!value)
129 {
130 QueueForUpdateCheck();
131 }
132 }
133 }
111 134
112 /// <summary> 135 /// <summary>
113 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 136 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -124,9 +147,39 @@ namespace OpenSim.Region.Framework.Scenes
124 { 147 {
125 if (value) 148 if (value)
126 { 149 {
150 if (m_isBackedUp)
151 {
152 m_scene.SceneGraph.FireChangeBackup(this);
153 }
127 timeLastChanged = DateTime.Now.Ticks; 154 timeLastChanged = DateTime.Now.Ticks;
128 if (!m_hasGroupChanged) 155 if (!m_hasGroupChanged)
129 timeFirstChanged = DateTime.Now.Ticks; 156 timeFirstChanged = DateTime.Now.Ticks;
157 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
158 {
159 if (m_rand == null)
160 {
161 byte[] val = new byte[16];
162 m_rootPart.UUID.ToBytes(val, 0);
163 m_rand = new Random(BitConverter.ToInt32(val, 0));
164 }
165
166 if (m_scene.GetRootAgentCount() == 0)
167 {
168 //If the region is empty, this change has been made by an automated process
169 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
170
171 float factor = 1.5f + (float)(m_rand.NextDouble());
172 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
173 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
174 }
175 else
176 {
177 //If the region is not empty, we want to obey the minimum and maximum persist times
178 //but add a random factor so we stagger the object persistance a little
179 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
180 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
181 }
182 }
130 } 183 }
131 m_hasGroupChanged = value; 184 m_hasGroupChanged = value;
132 185
@@ -141,7 +194,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 194 /// 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. 195 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
143 /// </summary> 196 /// </summary>
144 public bool HasGroupChangedDueToDelink { get; private set; } 197 public bool HasGroupChangedDueToDelink { get; set; }
145 198
146 private bool isTimeToPersist() 199 private bool isTimeToPersist()
147 { 200 {
@@ -151,8 +204,19 @@ namespace OpenSim.Region.Framework.Scenes
151 return false; 204 return false;
152 if (m_scene.ShuttingDown) 205 if (m_scene.ShuttingDown)
153 return true; 206 return true;
207
208 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
209 {
210 m_maxPersistTime = m_scene.m_persistAfter;
211 m_minPersistTime = m_scene.m_dontPersistBefore;
212 }
213
154 long currentTime = DateTime.Now.Ticks; 214 long currentTime = DateTime.Now.Ticks;
155 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 215
216 if (timeLastChanged == 0) timeLastChanged = currentTime;
217 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
218
219 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
156 return true; 220 return true;
157 return false; 221 return false;
158 } 222 }
@@ -271,10 +335,10 @@ namespace OpenSim.Region.Framework.Scenes
271 335
272 private bool m_scriptListens_atTarget; 336 private bool m_scriptListens_atTarget;
273 private bool m_scriptListens_notAtTarget; 337 private bool m_scriptListens_notAtTarget;
274
275 private bool m_scriptListens_atRotTarget; 338 private bool m_scriptListens_atRotTarget;
276 private bool m_scriptListens_notAtRotTarget; 339 private bool m_scriptListens_notAtRotTarget;
277 340
341 public bool m_dupeInProgress = false;
278 internal Dictionary<UUID, string> m_savedScriptState; 342 internal Dictionary<UUID, string> m_savedScriptState;
279 343
280 #region Properties 344 #region Properties
@@ -311,6 +375,16 @@ namespace OpenSim.Region.Framework.Scenes
311 get { return m_parts.Count; } 375 get { return m_parts.Count; }
312 } 376 }
313 377
378// protected Quaternion m_rotation = Quaternion.Identity;
379//
380// public virtual Quaternion Rotation
381// {
382// get { return m_rotation; }
383// set {
384// m_rotation = value;
385// }
386// }
387
314 public Quaternion GroupRotation 388 public Quaternion GroupRotation
315 { 389 {
316 get { return m_rootPart.RotationOffset; } 390 get { return m_rootPart.RotationOffset; }
@@ -417,7 +491,15 @@ namespace OpenSim.Region.Framework.Scenes
417 { 491 {
418 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 492 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
419 } 493 }
420 494
495
496
497 private struct avtocrossInfo
498 {
499 public ScenePresence av;
500 public uint ParentID;
501 }
502
421 /// <summary> 503 /// <summary>
422 /// The absolute position of this scene object in the scene 504 /// The absolute position of this scene object in the scene
423 /// </summary> 505 /// </summary>
@@ -430,14 +512,128 @@ namespace OpenSim.Region.Framework.Scenes
430 512
431 if (Scene != null) 513 if (Scene != null)
432 { 514 {
433 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 515 // 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)) 516 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
517 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
518 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
519 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
435 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 520 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
436 { 521 {
437 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 522 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
523 uint x = 0;
524 uint y = 0;
525 string version = String.Empty;
526 Vector3 newpos = Vector3.Zero;
527 OpenSim.Services.Interfaces.GridRegion destination = null;
528
529 bool canCross = true;
530 foreach (ScenePresence av in m_linkedAvatars)
531 {
532 // We need to cross these agents. First, let's find
533 // out if any of them can't cross for some reason.
534 // We have to deny the crossing entirely if any
535 // of them are banned. Alternatively, we could
536 // unsit banned agents....
537
538
539 // We set the avatar position as being the object
540 // position to get the region to send to
541 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
542 {
543 canCross = false;
544 break;
545 }
546
547 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
548 }
549
550 if (canCross)
551 {
552 // We unparent the SP quietly so that it won't
553 // be made to stand up
554
555 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
556
557 foreach (ScenePresence av in m_linkedAvatars)
558 {
559 avtocrossInfo avinfo = new avtocrossInfo();
560 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
561 if (parentPart != null)
562 av.ParentUUID = parentPart.UUID;
563
564 avinfo.av = av;
565 avinfo.ParentID = av.ParentID;
566 avsToCross.Add(avinfo);
567
568 av.ParentID = 0;
569 }
570
571// m_linkedAvatars.Clear();
572 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
573
574 // Normalize
575 if (val.X >= Constants.RegionSize)
576 val.X -= Constants.RegionSize;
577 if (val.Y >= Constants.RegionSize)
578 val.Y -= Constants.RegionSize;
579 if (val.X < 0)
580 val.X += Constants.RegionSize;
581 if (val.Y < 0)
582 val.Y += Constants.RegionSize;
583
584 // If it's deleted, crossing was successful
585 if (IsDeleted)
586 {
587 // foreach (ScenePresence av in m_linkedAvatars)
588 foreach (avtocrossInfo avinfo in avsToCross)
589 {
590 ScenePresence av = avinfo.av;
591 if (!av.IsInTransit) // just in case...
592 {
593 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
594
595 av.IsInTransit = true;
596
597 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
598 d.BeginInvoke(av, val, x, y, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
599 }
600 else
601 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
602 }
603 avsToCross.Clear();
604 return;
605 }
606 else // cross failed, put avas back ??
607 {
608 foreach (avtocrossInfo avinfo in avsToCross)
609 {
610 ScenePresence av = avinfo.av;
611 av.ParentUUID = UUID.Zero;
612 av.ParentID = avinfo.ParentID;
613// m_linkedAvatars.Add(av);
614 }
615 }
616 avsToCross.Clear();
617
618 }
619 else if (RootPart.PhysActor != null)
620 {
621 RootPart.PhysActor.CrossingFailure();
622 }
623
624 Vector3 oldp = AbsolutePosition;
625 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
626 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
627 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
438 } 628 }
439 } 629 }
440 630
631/* don't see the need but worse don't see where is restored to false if things stay in
632 foreach (SceneObjectPart part in m_parts.GetArray())
633 {
634 part.IgnoreUndoUpdate = true;
635 }
636 */
441 if (RootPart.GetStatusSandbox()) 637 if (RootPart.GetStatusSandbox())
442 { 638 {
443 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 639 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -455,9 +651,38 @@ namespace OpenSim.Region.Framework.Scenes
455 // Restuff the new GroupPosition into each SOP of the linkset. 651 // Restuff the new GroupPosition into each SOP of the linkset.
456 // This has the affect of resetting and tainting the physics actors. 652 // This has the affect of resetting and tainting the physics actors.
457 SceneObjectPart[] parts = m_parts.GetArray(); 653 SceneObjectPart[] parts = m_parts.GetArray();
458 for (int i = 0; i < parts.Length; i++) 654 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
459 parts[i].GroupPosition = val; 655 if (m_dupeInProgress)
656 triggerScriptEvent = false;
657 foreach (SceneObjectPart part in parts)
658 {
659 part.GroupPosition = val;
660 if (triggerScriptEvent)
661 part.TriggerScriptChangedEvent(Changed.POSITION);
662 }
460 663
664/*
665 This seems not needed and should not be needed:
666 sp absolute position depends on sit part absolute position fixed above.
667 sp ParentPosition is not used anywhere.
668 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
669 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
670
671 if (!m_dupeInProgress)
672 {
673 foreach (ScenePresence av in m_linkedAvatars)
674 {
675 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
676 if (p != null && m_parts.TryGetValue(p.UUID, out p))
677 {
678 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
679 av.AbsolutePosition += offset;
680// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
681 av.SendAvatarDataToAllAgents();
682 }
683 }
684 }
685*/
461 //if (m_rootPart.PhysActor != null) 686 //if (m_rootPart.PhysActor != null)
462 //{ 687 //{
463 //m_rootPart.PhysActor.Position = 688 //m_rootPart.PhysActor.Position =
@@ -471,6 +696,40 @@ namespace OpenSim.Region.Framework.Scenes
471 } 696 }
472 } 697 }
473 698
699 public override Vector3 Velocity
700 {
701 get { return RootPart.Velocity; }
702 set { RootPart.Velocity = value; }
703 }
704
705 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
706 {
707 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
708 ScenePresence agent = icon.EndInvoke(iar);
709
710 //// If the cross was successful, this agent is a child agent
711 if (agent.IsChildAgent)
712 {
713 if (agent.ParentUUID != UUID.Zero)
714 {
715 agent.ParentPart = null;
716// agent.ParentPosition = Vector3.Zero;
717// agent.ParentUUID = UUID.Zero;
718 }
719 }
720
721 agent.ParentUUID = UUID.Zero;
722
723// agent.Reset();
724// else // Not successful
725// agent.RestoreInCurrentScene();
726
727 // In any case
728 agent.IsInTransit = false;
729
730 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
731 }
732
474 public override uint LocalId 733 public override uint LocalId
475 { 734 {
476 get { return m_rootPart.LocalId; } 735 get { return m_rootPart.LocalId; }
@@ -541,6 +800,11 @@ namespace OpenSim.Region.Framework.Scenes
541 m_isSelected = value; 800 m_isSelected = value;
542 // Tell physics engine that group is selected 801 // Tell physics engine that group is selected
543 802
803 // this is not right
804 // but ode engines should only really need to know about root part
805 // so they can put entire object simulation on hold and not colliding
806 // keep as was for now
807
544 PhysicsActor pa = m_rootPart.PhysActor; 808 PhysicsActor pa = m_rootPart.PhysActor;
545 if (pa != null) 809 if (pa != null)
546 { 810 {
@@ -557,6 +821,42 @@ namespace OpenSim.Region.Framework.Scenes
557 childPa.Selected = value; 821 childPa.Selected = value;
558 } 822 }
559 } 823 }
824 if (RootPart.KeyframeMotion != null)
825 RootPart.KeyframeMotion.Selected = value;
826 }
827 }
828
829 public void PartSelectChanged(bool partSelect)
830 {
831 // any part selected makes group selected
832 if (m_isSelected == partSelect)
833 return;
834
835 if (partSelect)
836 {
837 IsSelected = partSelect;
838// if (!IsAttachment)
839// ScheduleGroupForFullUpdate();
840 }
841 else
842 {
843 // bad bad bad 2 heavy for large linksets
844 // since viewer does send lot of (un)selects
845 // this needs to be replaced by a specific list or count ?
846 // but that will require extra code in several places
847
848 SceneObjectPart[] parts = m_parts.GetArray();
849 for (int i = 0; i < parts.Length; i++)
850 {
851 SceneObjectPart part = parts[i];
852 if (part.IsSelected)
853 return;
854 }
855 IsSelected = partSelect;
856 if (!IsAttachment)
857 {
858 ScheduleGroupForFullUpdate();
859 }
560 } 860 }
561 } 861 }
562 862
@@ -642,6 +942,7 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 942 /// </summary>
643 public SceneObjectGroup() 943 public SceneObjectGroup()
644 { 944 {
945
645 } 946 }
646 947
647 /// <summary> 948 /// <summary>
@@ -659,8 +960,8 @@ namespace OpenSim.Region.Framework.Scenes
659 /// Constructor. This object is added to the scene later via AttachToScene() 960 /// Constructor. This object is added to the scene later via AttachToScene()
660 /// </summary> 961 /// </summary>
661 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 962 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
662 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 963 {
663 { 964 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
664 } 965 }
665 966
666 /// <summary> 967 /// <summary>
@@ -695,6 +996,9 @@ namespace OpenSim.Region.Framework.Scenes
695 /// </summary> 996 /// </summary>
696 public virtual void AttachToBackup() 997 public virtual void AttachToBackup()
697 { 998 {
999 if (IsAttachment) return;
1000 m_scene.SceneGraph.FireAttachToBackup(this);
1001
698 if (InSceneBackup) 1002 if (InSceneBackup)
699 { 1003 {
700 //m_log.DebugFormat( 1004 //m_log.DebugFormat(
@@ -737,6 +1041,13 @@ namespace OpenSim.Region.Framework.Scenes
737 1041
738 ApplyPhysics(); 1042 ApplyPhysics();
739 1043
1044 if (RootPart.PhysActor != null)
1045 RootPart.Force = RootPart.Force;
1046 if (RootPart.PhysActor != null)
1047 RootPart.Torque = RootPart.Torque;
1048 if (RootPart.PhysActor != null)
1049 RootPart.Buoyancy = RootPart.Buoyancy;
1050
740 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1051 // 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. 1052 // for the same object with very different properties. The caller must schedule the update.
742 //ScheduleGroupForFullUpdate(); 1053 //ScheduleGroupForFullUpdate();
@@ -752,6 +1063,10 @@ namespace OpenSim.Region.Framework.Scenes
752 EntityIntersection result = new EntityIntersection(); 1063 EntityIntersection result = new EntityIntersection();
753 1064
754 SceneObjectPart[] parts = m_parts.GetArray(); 1065 SceneObjectPart[] parts = m_parts.GetArray();
1066
1067 // Find closest hit here
1068 float idist = float.MaxValue;
1069
755 for (int i = 0; i < parts.Length; i++) 1070 for (int i = 0; i < parts.Length; i++)
756 { 1071 {
757 SceneObjectPart part = parts[i]; 1072 SceneObjectPart part = parts[i];
@@ -766,11 +1081,6 @@ namespace OpenSim.Region.Framework.Scenes
766 1081
767 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1082 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
768 1083
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) 1084 if (inter.HitTF)
775 { 1085 {
776 // We need to find the closest prim to return to the testcaller along the ray 1086 // We need to find the closest prim to return to the testcaller along the ray
@@ -781,10 +1091,11 @@ namespace OpenSim.Region.Framework.Scenes
781 result.obj = part; 1091 result.obj = part;
782 result.normal = inter.normal; 1092 result.normal = inter.normal;
783 result.distance = inter.distance; 1093 result.distance = inter.distance;
1094
1095 idist = inter.distance;
784 } 1096 }
785 } 1097 }
786 } 1098 }
787
788 return result; 1099 return result;
789 } 1100 }
790 1101
@@ -796,25 +1107,27 @@ namespace OpenSim.Region.Framework.Scenes
796 /// <returns></returns> 1107 /// <returns></returns>
797 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1108 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
798 { 1109 {
799 maxX = -256f; 1110 maxX = float.MinValue;
800 maxY = -256f; 1111 maxY = float.MinValue;
801 maxZ = -256f; 1112 maxZ = float.MinValue;
802 minX = 256f; 1113 minX = float.MaxValue;
803 minY = 256f; 1114 minY = float.MaxValue;
804 minZ = 8192f; 1115 minZ = float.MaxValue;
805 1116
806 SceneObjectPart[] parts = m_parts.GetArray(); 1117 SceneObjectPart[] parts = m_parts.GetArray();
807 for (int i = 0; i < parts.Length; i++) 1118 foreach (SceneObjectPart part in parts)
808 { 1119 {
809 SceneObjectPart part = parts[i];
810
811 Vector3 worldPos = part.GetWorldPosition(); 1120 Vector3 worldPos = part.GetWorldPosition();
812 Vector3 offset = worldPos - AbsolutePosition; 1121 Vector3 offset = worldPos - AbsolutePosition;
813 Quaternion worldRot; 1122 Quaternion worldRot;
814 if (part.ParentID == 0) 1123 if (part.ParentID == 0)
1124 {
815 worldRot = part.RotationOffset; 1125 worldRot = part.RotationOffset;
1126 }
816 else 1127 else
1128 {
817 worldRot = part.GetWorldRotation(); 1129 worldRot = part.GetWorldRotation();
1130 }
818 1131
819 Vector3 frontTopLeft; 1132 Vector3 frontTopLeft;
820 Vector3 frontTopRight; 1133 Vector3 frontTopRight;
@@ -826,6 +1139,8 @@ namespace OpenSim.Region.Framework.Scenes
826 Vector3 backBottomLeft; 1139 Vector3 backBottomLeft;
827 Vector3 backBottomRight; 1140 Vector3 backBottomRight;
828 1141
1142 // Vector3[] corners = new Vector3[8];
1143
829 Vector3 orig = Vector3.Zero; 1144 Vector3 orig = Vector3.Zero;
830 1145
831 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1146 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -860,6 +1175,38 @@ namespace OpenSim.Region.Framework.Scenes
860 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1175 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
861 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1176 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
862 1177
1178
1179
1180 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1181 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1182 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1183 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1184 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1185 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1186 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1187 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1188
1189 //for (int i = 0; i < 8; i++)
1190 //{
1191 // corners[i] = corners[i] * worldRot;
1192 // corners[i] += offset;
1193
1194 // if (corners[i].X > maxX)
1195 // maxX = corners[i].X;
1196 // if (corners[i].X < minX)
1197 // minX = corners[i].X;
1198
1199 // if (corners[i].Y > maxY)
1200 // maxY = corners[i].Y;
1201 // if (corners[i].Y < minY)
1202 // minY = corners[i].Y;
1203
1204 // if (corners[i].Z > maxZ)
1205 // maxZ = corners[i].Y;
1206 // if (corners[i].Z < minZ)
1207 // minZ = corners[i].Z;
1208 //}
1209
863 frontTopLeft = frontTopLeft * worldRot; 1210 frontTopLeft = frontTopLeft * worldRot;
864 frontTopRight = frontTopRight * worldRot; 1211 frontTopRight = frontTopRight * worldRot;
865 frontBottomLeft = frontBottomLeft * worldRot; 1212 frontBottomLeft = frontBottomLeft * worldRot;
@@ -881,6 +1228,15 @@ namespace OpenSim.Region.Framework.Scenes
881 backTopLeft += offset; 1228 backTopLeft += offset;
882 backTopRight += offset; 1229 backTopRight += offset;
883 1230
1231 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1232 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1233 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1234 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1235 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1236 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1237 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1238 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1239
884 if (frontTopRight.X > maxX) 1240 if (frontTopRight.X > maxX)
885 maxX = frontTopRight.X; 1241 maxX = frontTopRight.X;
886 if (frontTopLeft.X > maxX) 1242 if (frontTopLeft.X > maxX)
@@ -1024,17 +1380,118 @@ namespace OpenSim.Region.Framework.Scenes
1024 1380
1025 #endregion 1381 #endregion
1026 1382
1383 public void GetResourcesCosts(SceneObjectPart apart,
1384 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1385 {
1386 // this information may need to be cached
1387
1388 float cost;
1389 float tmpcost;
1390
1391 bool ComplexCost = false;
1392
1393 SceneObjectPart p;
1394 SceneObjectPart[] parts;
1395
1396 lock (m_parts)
1397 {
1398 parts = m_parts.GetArray();
1399 }
1400
1401 int nparts = parts.Length;
1402
1403
1404 for (int i = 0; i < nparts; i++)
1405 {
1406 p = parts[i];
1407
1408 if (p.UsesComplexCost)
1409 {
1410 ComplexCost = true;
1411 break;
1412 }
1413 }
1414
1415 if (ComplexCost)
1416 {
1417 linksetResCost = 0;
1418 linksetPhysCost = 0;
1419 partCost = 0;
1420 partPhysCost = 0;
1421
1422 for (int i = 0; i < nparts; i++)
1423 {
1424 p = parts[i];
1425
1426 cost = p.StreamingCost;
1427 tmpcost = p.SimulationCost;
1428 if (tmpcost > cost)
1429 cost = tmpcost;
1430 tmpcost = p.PhysicsCost;
1431 if (tmpcost > cost)
1432 cost = tmpcost;
1433
1434 linksetPhysCost += tmpcost;
1435 linksetResCost += cost;
1436
1437 if (p == apart)
1438 {
1439 partCost = cost;
1440 partPhysCost = tmpcost;
1441 }
1442 }
1443 }
1444 else
1445 {
1446 partPhysCost = 1.0f;
1447 partCost = 1.0f;
1448 linksetResCost = (float)nparts;
1449 linksetPhysCost = linksetResCost;
1450 }
1451 }
1452
1453 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1454 {
1455 SceneObjectPart p;
1456 SceneObjectPart[] parts;
1457
1458 lock (m_parts)
1459 {
1460 parts = m_parts.GetArray();
1461 }
1462
1463 int nparts = parts.Length;
1464
1465 PhysCost = 0;
1466 StreamCost = 0;
1467 SimulCost = 0;
1468
1469 for (int i = 0; i < nparts; i++)
1470 {
1471 p = parts[i];
1472
1473 StreamCost += p.StreamingCost;
1474 SimulCost += p.SimulationCost;
1475 PhysCost += p.PhysicsCost;
1476 }
1477 }
1478
1027 public void SaveScriptedState(XmlTextWriter writer) 1479 public void SaveScriptedState(XmlTextWriter writer)
1028 { 1480 {
1481 SaveScriptedState(writer, false);
1482 }
1483
1484 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1485 {
1029 XmlDocument doc = new XmlDocument(); 1486 XmlDocument doc = new XmlDocument();
1030 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1487 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1031 1488
1032 SceneObjectPart[] parts = m_parts.GetArray(); 1489 SceneObjectPart[] parts = m_parts.GetArray();
1033 for (int i = 0; i < parts.Length; i++) 1490 for (int i = 0; i < parts.Length; i++)
1034 { 1491 {
1035 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1492 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1036 foreach (KeyValuePair<UUID, string> kvp in pstates) 1493 foreach (KeyValuePair<UUID, string> kvp in pstates)
1037 states.Add(kvp.Key, kvp.Value); 1494 states[kvp.Key] = kvp.Value;
1038 } 1495 }
1039 1496
1040 if (states.Count > 0) 1497 if (states.Count > 0)
@@ -1054,6 +1511,169 @@ namespace OpenSim.Region.Framework.Scenes
1054 } 1511 }
1055 1512
1056 /// <summary> 1513 /// <summary>
1514 /// Add the avatar to this linkset (avatar is sat).
1515 /// </summary>
1516 /// <param name="agentID"></param>
1517 public void AddAvatar(UUID agentID)
1518 {
1519 ScenePresence presence;
1520 if (m_scene.TryGetScenePresence(agentID, out presence))
1521 {
1522 if (!m_linkedAvatars.Contains(presence))
1523 {
1524 m_linkedAvatars.Add(presence);
1525 }
1526 }
1527 }
1528
1529 /// <summary>
1530 /// Delete the avatar from this linkset (avatar is unsat).
1531 /// </summary>
1532 /// <param name="agentID"></param>
1533 public void DeleteAvatar(UUID agentID)
1534 {
1535 ScenePresence presence;
1536 if (m_scene.TryGetScenePresence(agentID, out presence))
1537 {
1538 if (m_linkedAvatars.Contains(presence))
1539 {
1540 m_linkedAvatars.Remove(presence);
1541 }
1542 }
1543 }
1544
1545 /// <summary>
1546 /// Returns the list of linked presences (avatars sat on this group)
1547 /// </summary>
1548 /// <param name="agentID"></param>
1549 public List<ScenePresence> GetLinkedAvatars()
1550 {
1551 return m_linkedAvatars;
1552 }
1553
1554 /// <summary>
1555 /// Attach this scene object to the given avatar.
1556 /// </summary>
1557 /// <param name="agentID"></param>
1558 /// <param name="attachmentpoint"></param>
1559 /// <param name="AttachOffset"></param>
1560 private void AttachToAgent(
1561 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1562 {
1563 if (avatar != null)
1564 {
1565 // don't attach attachments to child agents
1566 if (avatar.IsChildAgent) return;
1567
1568 // Remove from database and parcel prim count
1569 m_scene.DeleteFromStorage(so.UUID);
1570 m_scene.EventManager.TriggerParcelPrimCountTainted();
1571
1572 so.AttachedAvatar = avatar.UUID;
1573
1574 if (so.RootPart.PhysActor != null)
1575 {
1576 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1577 so.RootPart.PhysActor = null;
1578 }
1579
1580 so.AbsolutePosition = attachOffset;
1581 so.RootPart.AttachedPos = attachOffset;
1582 so.IsAttachment = true;
1583 so.RootPart.SetParentLocalId(avatar.LocalId);
1584 so.AttachmentPoint = attachmentpoint;
1585
1586 avatar.AddAttachment(this);
1587
1588 if (!silent)
1589 {
1590 // Killing it here will cause the client to deselect it
1591 // It then reappears on the avatar, deselected
1592 // through the full update below
1593 //
1594 if (IsSelected)
1595 {
1596 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1597 }
1598
1599 IsSelected = false; // fudge....
1600 ScheduleGroupForFullUpdate();
1601 }
1602 }
1603 else
1604 {
1605 m_log.WarnFormat(
1606 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1607 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1608 }
1609 }
1610
1611 public byte GetAttachmentPoint()
1612 {
1613 return m_rootPart.Shape.State;
1614 }
1615
1616 public void DetachToGround()
1617 {
1618 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1619 if (avatar == null)
1620 return;
1621
1622 avatar.RemoveAttachment(this);
1623
1624 Vector3 detachedpos = new Vector3(127f,127f,127f);
1625 if (avatar == null)
1626 return;
1627
1628 detachedpos = avatar.AbsolutePosition;
1629 FromItemID = UUID.Zero;
1630
1631 AbsolutePosition = detachedpos;
1632 AttachedAvatar = UUID.Zero;
1633
1634 //SceneObjectPart[] parts = m_parts.GetArray();
1635 //for (int i = 0; i < parts.Length; i++)
1636 // parts[i].AttachedAvatar = UUID.Zero;
1637
1638 m_rootPart.SetParentLocalId(0);
1639 AttachmentPoint = (byte)0;
1640 // must check if buildind should be true or false here
1641 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1642 HasGroupChanged = true;
1643 RootPart.Rezzed = DateTime.Now;
1644 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1645 AttachToBackup();
1646 m_scene.EventManager.TriggerParcelPrimCountTainted();
1647 m_rootPart.ScheduleFullUpdate();
1648 m_rootPart.ClearUndoState();
1649 }
1650
1651 public void DetachToInventoryPrep()
1652 {
1653 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1654 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1655 if (avatar != null)
1656 {
1657 //detachedpos = avatar.AbsolutePosition;
1658 avatar.RemoveAttachment(this);
1659 }
1660
1661 AttachedAvatar = UUID.Zero;
1662
1663 /*SceneObjectPart[] parts = m_parts.GetArray();
1664 for (int i = 0; i < parts.Length; i++)
1665 parts[i].AttachedAvatar = UUID.Zero;*/
1666
1667 m_rootPart.SetParentLocalId(0);
1668 //m_rootPart.SetAttachmentPoint((byte)0);
1669 IsAttachment = false;
1670 AbsolutePosition = m_rootPart.AttachedPos;
1671 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1672 //AttachToBackup();
1673 //m_rootPart.ScheduleFullUpdate();
1674 }
1675
1676 /// <summary>
1057 /// 1677 ///
1058 /// </summary> 1678 /// </summary>
1059 /// <param name="part"></param> 1679 /// <param name="part"></param>
@@ -1093,7 +1713,10 @@ namespace OpenSim.Region.Framework.Scenes
1093 public void AddPart(SceneObjectPart part) 1713 public void AddPart(SceneObjectPart part)
1094 { 1714 {
1095 part.SetParent(this); 1715 part.SetParent(this);
1096 part.LinkNum = m_parts.Add(part.UUID, part); 1716 m_parts.Add(part.UUID, part);
1717
1718 part.LinkNum = m_parts.Count;
1719
1097 if (part.LinkNum == 2) 1720 if (part.LinkNum == 2)
1098 RootPart.LinkNum = 1; 1721 RootPart.LinkNum = 1;
1099 } 1722 }
@@ -1184,7 +1807,7 @@ namespace OpenSim.Region.Framework.Scenes
1184// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1807// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1185// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1808// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1186 1809
1187 part.StoreUndoState(); 1810// part.StoreUndoState();
1188 part.OnGrab(offsetPos, remoteClient); 1811 part.OnGrab(offsetPos, remoteClient);
1189 } 1812 }
1190 1813
@@ -1204,6 +1827,11 @@ namespace OpenSim.Region.Framework.Scenes
1204 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1827 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1205 public void DeleteGroupFromScene(bool silent) 1828 public void DeleteGroupFromScene(bool silent)
1206 { 1829 {
1830 // We need to keep track of this state in case this group is still queued for backup.
1831 IsDeleted = true;
1832
1833 DetachFromBackup();
1834
1207 SceneObjectPart[] parts = m_parts.GetArray(); 1835 SceneObjectPart[] parts = m_parts.GetArray();
1208 for (int i = 0; i < parts.Length; i++) 1836 for (int i = 0; i < parts.Length; i++)
1209 { 1837 {
@@ -1227,6 +1855,7 @@ namespace OpenSim.Region.Framework.Scenes
1227 } 1855 }
1228 }); 1856 });
1229 } 1857 }
1858
1230 } 1859 }
1231 1860
1232 public void AddScriptLPS(int count) 1861 public void AddScriptLPS(int count)
@@ -1296,28 +1925,43 @@ namespace OpenSim.Region.Framework.Scenes
1296 /// </summary> 1925 /// </summary>
1297 public void ApplyPhysics() 1926 public void ApplyPhysics()
1298 { 1927 {
1299 // Apply physics to the root prim
1300 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1301
1302 // Apply physics to child prims
1303 SceneObjectPart[] parts = m_parts.GetArray(); 1928 SceneObjectPart[] parts = m_parts.GetArray();
1304 if (parts.Length > 1) 1929 if (parts.Length > 1)
1305 { 1930 {
1931 ResetChildPrimPhysicsPositions();
1932
1933 // Apply physics to the root prim
1934 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1935
1936
1306 for (int i = 0; i < parts.Length; i++) 1937 for (int i = 0; i < parts.Length; i++)
1307 { 1938 {
1308 SceneObjectPart part = parts[i]; 1939 SceneObjectPart part = parts[i];
1309 if (part.LocalId != m_rootPart.LocalId) 1940 if (part.LocalId != m_rootPart.LocalId)
1310 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1941 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1311 } 1942 }
1312
1313 // Hack to get the physics scene geometries in the right spot 1943 // Hack to get the physics scene geometries in the right spot
1314 ResetChildPrimPhysicsPositions(); 1944// ResetChildPrimPhysicsPositions();
1945 if (m_rootPart.PhysActor != null)
1946 {
1947 m_rootPart.PhysActor.Building = false;
1948 }
1949 }
1950 else
1951 {
1952 // Apply physics to the root prim
1953 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1315 } 1954 }
1316 } 1955 }
1317 1956
1318 public void SetOwnerId(UUID userId) 1957 public void SetOwnerId(UUID userId)
1319 { 1958 {
1320 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1959 ForEachPart(delegate(SceneObjectPart part)
1960 {
1961
1962 part.OwnerID = userId;
1963
1964 });
1321 } 1965 }
1322 1966
1323 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1967 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1349,11 +1993,17 @@ namespace OpenSim.Region.Framework.Scenes
1349 return; 1993 return;
1350 } 1994 }
1351 1995
1996 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1997 return;
1998
1352 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 1999 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1353 // any exception propogate upwards. 2000 // any exception propogate upwards.
1354 try 2001 try
1355 { 2002 {
1356 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2003 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2004 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2005 m_scene.LoadingPrims) // Land may not be valid yet
2006
1357 { 2007 {
1358 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2008 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1359 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2009 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1380,6 +2030,7 @@ namespace OpenSim.Region.Framework.Scenes
1380 } 2030 }
1381 } 2031 }
1382 } 2032 }
2033
1383 } 2034 }
1384 2035
1385 if (m_scene.UseBackup && HasGroupChanged) 2036 if (m_scene.UseBackup && HasGroupChanged)
@@ -1387,10 +2038,30 @@ namespace OpenSim.Region.Framework.Scenes
1387 // don't backup while it's selected or you're asking for changes mid stream. 2038 // don't backup while it's selected or you're asking for changes mid stream.
1388 if (isTimeToPersist() || forcedBackup) 2039 if (isTimeToPersist() || forcedBackup)
1389 { 2040 {
2041 if (m_rootPart.PhysActor != null &&
2042 (!m_rootPart.PhysActor.IsPhysical))
2043 {
2044 // Possible ghost prim
2045 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2046 {
2047 foreach (SceneObjectPart part in m_parts.GetArray())
2048 {
2049 // Re-set physics actor positions and
2050 // orientations
2051 part.GroupPosition = m_rootPart.GroupPosition;
2052 }
2053 }
2054 }
1390// m_log.DebugFormat( 2055// m_log.DebugFormat(
1391// "[SCENE]: Storing {0}, {1} in {2}", 2056// "[SCENE]: Storing {0}, {1} in {2}",
1392// Name, UUID, m_scene.RegionInfo.RegionName); 2057// Name, UUID, m_scene.RegionInfo.RegionName);
1393 2058
2059 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2060 {
2061 RootPart.Shape.State = 0;
2062 ScheduleGroupForFullUpdate();
2063 }
2064
1394 SceneObjectGroup backup_group = Copy(false); 2065 SceneObjectGroup backup_group = Copy(false);
1395 backup_group.RootPart.Velocity = RootPart.Velocity; 2066 backup_group.RootPart.Velocity = RootPart.Velocity;
1396 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2067 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1400,6 +2071,15 @@ namespace OpenSim.Region.Framework.Scenes
1400 HasGroupChangedDueToDelink = false; 2071 HasGroupChangedDueToDelink = false;
1401 2072
1402 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2073 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2074 backup_group.ForEachPart(delegate(SceneObjectPart part)
2075 {
2076 if (part.KeyframeMotion != null)
2077 {
2078 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2079 part.KeyframeMotion.UpdateSceneObject(this);
2080 }
2081 });
2082
1403 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2083 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1404 2084
1405 backup_group.ForEachPart(delegate(SceneObjectPart part) 2085 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1456,10 +2136,14 @@ namespace OpenSim.Region.Framework.Scenes
1456 /// <returns></returns> 2136 /// <returns></returns>
1457 public SceneObjectGroup Copy(bool userExposed) 2137 public SceneObjectGroup Copy(bool userExposed)
1458 { 2138 {
2139 m_dupeInProgress = true;
1459 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2140 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1460 dupe.m_isBackedUp = false; 2141 dupe.m_isBackedUp = false;
1461 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2142 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1462 2143
2144 // new group as no sitting avatars
2145 dupe.m_linkedAvatars = new List<ScenePresence>();
2146
1463 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2147 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1464 // attachments do not bordercross while they're being duplicated. This is hacktastic! 2148 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1465 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region! 2149 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1470,7 +2154,7 @@ namespace OpenSim.Region.Framework.Scenes
1470 // This is only necessary when userExposed is false! 2154 // This is only necessary when userExposed is false!
1471 2155
1472 bool previousAttachmentStatus = dupe.IsAttachment; 2156 bool previousAttachmentStatus = dupe.IsAttachment;
1473 2157
1474 if (!userExposed) 2158 if (!userExposed)
1475 dupe.IsAttachment = true; 2159 dupe.IsAttachment = true;
1476 2160
@@ -1488,11 +2172,11 @@ namespace OpenSim.Region.Framework.Scenes
1488 dupe.m_rootPart.TrimPermissions(); 2172 dupe.m_rootPart.TrimPermissions();
1489 2173
1490 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2174 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1491 2175
1492 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2176 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1493 { 2177 {
1494 return p1.LinkNum.CompareTo(p2.LinkNum); 2178 return p1.LinkNum.CompareTo(p2.LinkNum);
1495 } 2179 }
1496 ); 2180 );
1497 2181
1498 foreach (SceneObjectPart part in partList) 2182 foreach (SceneObjectPart part in partList)
@@ -1502,41 +2186,53 @@ namespace OpenSim.Region.Framework.Scenes
1502 { 2186 {
1503 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2187 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1504 newPart.LinkNum = part.LinkNum; 2188 newPart.LinkNum = part.LinkNum;
1505 } 2189 if (userExposed)
2190 newPart.ParentID = dupe.m_rootPart.LocalId;
2191 }
1506 else 2192 else
1507 { 2193 {
1508 newPart = dupe.m_rootPart; 2194 newPart = dupe.m_rootPart;
1509 } 2195 }
2196/*
2197 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2198 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1510 2199
1511 // Need to duplicate the physics actor as well 2200 // Need to duplicate the physics actor as well
1512 PhysicsActor originalPartPa = part.PhysActor; 2201 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1513 if (originalPartPa != null && userExposed)
1514 { 2202 {
1515 PrimitiveBaseShape pbs = newPart.Shape; 2203 PrimitiveBaseShape pbs = newPart.Shape;
1516
1517 newPart.PhysActor 2204 newPart.PhysActor
1518 = m_scene.PhysicsScene.AddPrimShape( 2205 = m_scene.PhysicsScene.AddPrimShape(
1519 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2206 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1520 pbs, 2207 pbs,
1521 newPart.AbsolutePosition, 2208 newPart.AbsolutePosition,
1522 newPart.Scale, 2209 newPart.Scale,
1523 newPart.RotationOffset, 2210 newPart.GetWorldRotation(),
1524 originalPartPa.IsPhysical, 2211 isphys,
2212 isphan,
1525 newPart.LocalId); 2213 newPart.LocalId);
1526 2214
1527 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2215 newPart.DoPhysicsPropertyUpdate(isphys, true);
1528 } 2216 */
2217 if (userExposed)
2218 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2219// }
1529 } 2220 }
1530 2221
1531 if (userExposed) 2222 if (userExposed)
1532 { 2223 {
1533 dupe.UpdateParentIDs(); 2224// done above dupe.UpdateParentIDs();
2225
2226 if (dupe.m_rootPart.PhysActor != null)
2227 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2228
1534 dupe.HasGroupChanged = true; 2229 dupe.HasGroupChanged = true;
1535 dupe.AttachToBackup(); 2230 dupe.AttachToBackup();
1536 2231
1537 ScheduleGroupForFullUpdate(); 2232 ScheduleGroupForFullUpdate();
1538 } 2233 }
1539 2234
2235 m_dupeInProgress = false;
1540 return dupe; 2236 return dupe;
1541 } 2237 }
1542 2238
@@ -1548,11 +2244,24 @@ namespace OpenSim.Region.Framework.Scenes
1548 /// <param name="cGroupID"></param> 2244 /// <param name="cGroupID"></param>
1549 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2245 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1550 { 2246 {
1551 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2247 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2248 // give newpart a new local ID lettng old part keep same
2249 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2250 newpart.LocalId = m_scene.AllocateLocalId();
2251
2252 SetRootPart(newpart);
2253 if (userExposed)
2254 RootPart.Velocity = Vector3.Zero; // In case source is moving
1552 } 2255 }
1553 2256
1554 public void ScriptSetPhysicsStatus(bool usePhysics) 2257 public void ScriptSetPhysicsStatus(bool usePhysics)
1555 { 2258 {
2259 if (usePhysics)
2260 {
2261 if (RootPart.KeyframeMotion != null)
2262 RootPart.KeyframeMotion.Stop();
2263 RootPart.KeyframeMotion = null;
2264 }
1556 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2265 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1557 } 2266 }
1558 2267
@@ -1600,13 +2309,14 @@ namespace OpenSim.Region.Framework.Scenes
1600 2309
1601 if (pa != null) 2310 if (pa != null)
1602 { 2311 {
1603 pa.AddForce(impulse, true); 2312 // false to be applied as a impulse
2313 pa.AddForce(impulse, false);
1604 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2314 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1605 } 2315 }
1606 } 2316 }
1607 } 2317 }
1608 2318
1609 public void applyAngularImpulse(Vector3 impulse) 2319 public void ApplyAngularImpulse(Vector3 impulse)
1610 { 2320 {
1611 PhysicsActor pa = RootPart.PhysActor; 2321 PhysicsActor pa = RootPart.PhysActor;
1612 2322
@@ -1614,21 +2324,8 @@ namespace OpenSim.Region.Framework.Scenes
1614 { 2324 {
1615 if (!IsAttachment) 2325 if (!IsAttachment)
1616 { 2326 {
1617 pa.AddAngularForce(impulse, true); 2327 // false to be applied as a impulse
1618 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2328 pa.AddAngularForce(impulse, false);
1619 }
1620 }
1621 }
1622
1623 public void setAngularImpulse(Vector3 impulse)
1624 {
1625 PhysicsActor pa = RootPart.PhysActor;
1626
1627 if (pa != null)
1628 {
1629 if (!IsAttachment)
1630 {
1631 pa.Torque = impulse;
1632 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2329 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1633 } 2330 }
1634 } 2331 }
@@ -1636,20 +2333,10 @@ namespace OpenSim.Region.Framework.Scenes
1636 2333
1637 public Vector3 GetTorque() 2334 public Vector3 GetTorque()
1638 { 2335 {
1639 PhysicsActor pa = RootPart.PhysActor; 2336 return RootPart.Torque;
1640
1641 if (pa != null)
1642 {
1643 if (!IsAttachment)
1644 {
1645 Vector3 torque = pa.Torque;
1646 return torque;
1647 }
1648 }
1649
1650 return Vector3.Zero;
1651 } 2337 }
1652 2338
2339 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1653 public void moveToTarget(Vector3 target, float tau) 2340 public void moveToTarget(Vector3 target, float tau)
1654 { 2341 {
1655 if (IsAttachment) 2342 if (IsAttachment)
@@ -1681,6 +2368,46 @@ namespace OpenSim.Region.Framework.Scenes
1681 pa.PIDActive = false; 2368 pa.PIDActive = false;
1682 } 2369 }
1683 2370
2371 public void rotLookAt(Quaternion target, float strength, float damping)
2372 {
2373 SceneObjectPart rootpart = m_rootPart;
2374 if (rootpart != null)
2375 {
2376 if (IsAttachment)
2377 {
2378 /*
2379 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2380 if (avatar != null)
2381 {
2382 Rotate the Av?
2383 } */
2384 }
2385 else
2386 {
2387 if (rootpart.PhysActor != null)
2388 { // APID must be implemented in your physics system for this to function.
2389 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2390 rootpart.PhysActor.APIDStrength = strength;
2391 rootpart.PhysActor.APIDDamping = damping;
2392 rootpart.PhysActor.APIDActive = true;
2393 }
2394 }
2395 }
2396 }
2397
2398 public void stopLookAt()
2399 {
2400 SceneObjectPart rootpart = m_rootPart;
2401 if (rootpart != null)
2402 {
2403 if (rootpart.PhysActor != null)
2404 { // APID must be implemented in your physics system for this to function.
2405 rootpart.PhysActor.APIDActive = false;
2406 }
2407 }
2408
2409 }
2410
1684 /// <summary> 2411 /// <summary>
1685 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2412 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1686 /// </summary> 2413 /// </summary>
@@ -1697,7 +2424,7 @@ namespace OpenSim.Region.Framework.Scenes
1697 { 2424 {
1698 pa.PIDHoverHeight = height; 2425 pa.PIDHoverHeight = height;
1699 pa.PIDHoverType = hoverType; 2426 pa.PIDHoverType = hoverType;
1700 pa.PIDTau = tau; 2427 pa.PIDHoverTau = tau;
1701 pa.PIDHoverActive = true; 2428 pa.PIDHoverActive = true;
1702 } 2429 }
1703 else 2430 else
@@ -1737,7 +2464,12 @@ namespace OpenSim.Region.Framework.Scenes
1737 /// <param name="cGroupID"></param> 2464 /// <param name="cGroupID"></param>
1738 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2465 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1739 { 2466 {
1740 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2467 // give new ID to the new part, letting old keep original
2468 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2469 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2470 newPart.LocalId = m_scene.AllocateLocalId();
2471 newPart.SetParent(this);
2472
1741 AddPart(newPart); 2473 AddPart(newPart);
1742 2474
1743 SetPartAsNonRoot(newPart); 2475 SetPartAsNonRoot(newPart);
@@ -1876,11 +2608,11 @@ namespace OpenSim.Region.Framework.Scenes
1876 /// Immediately send a full update for this scene object. 2608 /// Immediately send a full update for this scene object.
1877 /// </summary> 2609 /// </summary>
1878 public void SendGroupFullUpdate() 2610 public void SendGroupFullUpdate()
1879 { 2611 {
1880 if (IsDeleted) 2612 if (IsDeleted)
1881 return; 2613 return;
1882 2614
1883// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2615// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1884 2616
1885 RootPart.SendFullUpdateToAllClients(); 2617 RootPart.SendFullUpdateToAllClients();
1886 2618
@@ -2017,6 +2749,11 @@ namespace OpenSim.Region.Framework.Scenes
2017 // 'linkPart' == the root of the group being linked into this group 2749 // 'linkPart' == the root of the group being linked into this group
2018 SceneObjectPart linkPart = objectGroup.m_rootPart; 2750 SceneObjectPart linkPart = objectGroup.m_rootPart;
2019 2751
2752 if (m_rootPart.PhysActor != null)
2753 m_rootPart.PhysActor.Building = true;
2754 if (linkPart.PhysActor != null)
2755 linkPart.PhysActor.Building = true;
2756
2020 // physics flags from group to be applied to linked parts 2757 // physics flags from group to be applied to linked parts
2021 bool grpusephys = UsesPhysics; 2758 bool grpusephys = UsesPhysics;
2022 bool grptemporary = IsTemporary; 2759 bool grptemporary = IsTemporary;
@@ -2042,12 +2779,12 @@ namespace OpenSim.Region.Framework.Scenes
2042 Vector3 axPos = linkPart.OffsetPosition; 2779 Vector3 axPos = linkPart.OffsetPosition;
2043 // Rotate the linking root SOP's position to be relative to the new root prim 2780 // Rotate the linking root SOP's position to be relative to the new root prim
2044 Quaternion parentRot = m_rootPart.RotationOffset; 2781 Quaternion parentRot = m_rootPart.RotationOffset;
2045 axPos *= Quaternion.Inverse(parentRot); 2782 axPos *= Quaternion.Conjugate(parentRot);
2046 linkPart.OffsetPosition = axPos; 2783 linkPart.OffsetPosition = axPos;
2047 2784
2048 // Make the linking root SOP's rotation relative to the new root prim 2785 // Make the linking root SOP's rotation relative to the new root prim
2049 Quaternion oldRot = linkPart.RotationOffset; 2786 Quaternion oldRot = linkPart.RotationOffset;
2050 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2787 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2051 linkPart.RotationOffset = newRot; 2788 linkPart.RotationOffset = newRot;
2052 2789
2053 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2790 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2081,7 +2818,7 @@ namespace OpenSim.Region.Framework.Scenes
2081 linkPart.CreateSelected = true; 2818 linkPart.CreateSelected = true;
2082 2819
2083 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2820 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2084 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 2821 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2085 2822
2086 // If the added SOP is physical, also tell the physics engine about the link relationship. 2823 // If the added SOP is physical, also tell the physics engine about the link relationship.
2087 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2824 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2091,6 +2828,7 @@ namespace OpenSim.Region.Framework.Scenes
2091 } 2828 }
2092 2829
2093 linkPart.LinkNum = linkNum++; 2830 linkPart.LinkNum = linkNum++;
2831 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2094 2832
2095 // Get a list of the SOP's in the old group in order of their linknum's. 2833 // Get a list of the SOP's in the old group in order of their linknum's.
2096 SceneObjectPart[] ogParts = objectGroup.Parts; 2834 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2109,7 +2847,7 @@ namespace OpenSim.Region.Framework.Scenes
2109 2847
2110 // Update the physics flags for the newly added SOP 2848 // Update the physics flags for the newly added SOP
2111 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2849 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2112 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 2850 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2113 2851
2114 // If the added SOP is physical, also tell the physics engine about the link relationship. 2852 // If the added SOP is physical, also tell the physics engine about the link relationship.
2115 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 2853 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2127,7 +2865,7 @@ namespace OpenSim.Region.Framework.Scenes
2127 objectGroup.IsDeleted = true; 2865 objectGroup.IsDeleted = true;
2128 2866
2129 objectGroup.m_parts.Clear(); 2867 objectGroup.m_parts.Clear();
2130 2868
2131 // Can't do this yet since backup still makes use of the root part without any synchronization 2869 // Can't do this yet since backup still makes use of the root part without any synchronization
2132// objectGroup.m_rootPart = null; 2870// objectGroup.m_rootPart = null;
2133 2871
@@ -2138,6 +2876,9 @@ namespace OpenSim.Region.Framework.Scenes
2138 // unmoved prims! 2876 // unmoved prims!
2139 ResetChildPrimPhysicsPositions(); 2877 ResetChildPrimPhysicsPositions();
2140 2878
2879 if (m_rootPart.PhysActor != null)
2880 m_rootPart.PhysActor.Building = false;
2881
2141 //HasGroupChanged = true; 2882 //HasGroupChanged = true;
2142 //ScheduleGroupForFullUpdate(); 2883 //ScheduleGroupForFullUpdate();
2143 } 2884 }
@@ -2205,7 +2946,10 @@ namespace OpenSim.Region.Framework.Scenes
2205// m_log.DebugFormat( 2946// m_log.DebugFormat(
2206// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2947// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2207// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2948// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2208 2949
2950 if (m_rootPart.PhysActor != null)
2951 m_rootPart.PhysActor.Building = true;
2952
2209 linkPart.ClearUndoState(); 2953 linkPart.ClearUndoState();
2210 2954
2211 Vector3 worldPos = linkPart.GetWorldPosition(); 2955 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2276,6 +3020,14 @@ namespace OpenSim.Region.Framework.Scenes
2276 3020
2277 // When we delete a group, we currently have to force persist to the database if the object id has changed 3021 // When we delete a group, we currently have to force persist to the database if the object id has changed
2278 // (since delete works by deleting all rows which have a given object id) 3022 // (since delete works by deleting all rows which have a given object id)
3023
3024 // this is as it seems to be in sl now
3025 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3026 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3027
3028 if (m_rootPart.PhysActor != null)
3029 m_rootPart.PhysActor.Building = false;
3030
2279 objectGroup.HasGroupChangedDueToDelink = true; 3031 objectGroup.HasGroupChangedDueToDelink = true;
2280 3032
2281 return objectGroup; 3033 return objectGroup;
@@ -2287,6 +3039,7 @@ namespace OpenSim.Region.Framework.Scenes
2287 /// <param name="objectGroup"></param> 3039 /// <param name="objectGroup"></param>
2288 public virtual void DetachFromBackup() 3040 public virtual void DetachFromBackup()
2289 { 3041 {
3042 m_scene.SceneGraph.FireDetachFromBackup(this);
2290 if (m_isBackedUp && Scene != null) 3043 if (m_isBackedUp && Scene != null)
2291 m_scene.EventManager.OnBackup -= ProcessBackup; 3044 m_scene.EventManager.OnBackup -= ProcessBackup;
2292 3045
@@ -2307,7 +3060,8 @@ namespace OpenSim.Region.Framework.Scenes
2307 Vector3 axPos = part.OffsetPosition; 3060 Vector3 axPos = part.OffsetPosition;
2308 axPos *= parentRot; 3061 axPos *= parentRot;
2309 part.OffsetPosition = axPos; 3062 part.OffsetPosition = axPos;
2310 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3063 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3064 part.GroupPosition = newPos;
2311 part.OffsetPosition = Vector3.Zero; 3065 part.OffsetPosition = Vector3.Zero;
2312 3066
2313 // Compution our rotation to be not relative to the old parent 3067 // Compution our rotation to be not relative to the old parent
@@ -2322,7 +3076,7 @@ namespace OpenSim.Region.Framework.Scenes
2322 part.LinkNum = linkNum; 3076 part.LinkNum = linkNum;
2323 3077
2324 // Compute the new position of this SOP relative to the group position 3078 // Compute the new position of this SOP relative to the group position
2325 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3079 part.OffsetPosition = newPos - AbsolutePosition;
2326 3080
2327 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3081 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2328 // It would have the affect of setting the physics engine position multiple 3082 // It would have the affect of setting the physics engine position multiple
@@ -2332,18 +3086,19 @@ namespace OpenSim.Region.Framework.Scenes
2332 // Rotate the relative position by the rotation of the group 3086 // Rotate the relative position by the rotation of the group
2333 Quaternion rootRotation = m_rootPart.RotationOffset; 3087 Quaternion rootRotation = m_rootPart.RotationOffset;
2334 Vector3 pos = part.OffsetPosition; 3088 Vector3 pos = part.OffsetPosition;
2335 pos *= Quaternion.Inverse(rootRotation); 3089 pos *= Quaternion.Conjugate(rootRotation);
2336 part.OffsetPosition = pos; 3090 part.OffsetPosition = pos;
2337 3091
2338 // Compute the SOP's rotation relative to the rotation of the group. 3092 // Compute the SOP's rotation relative to the rotation of the group.
2339 parentRot = m_rootPart.RotationOffset; 3093 parentRot = m_rootPart.RotationOffset;
2340 oldRot = part.RotationOffset; 3094 oldRot = part.RotationOffset;
2341 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3095 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2342 part.RotationOffset = newRot; 3096 part.RotationOffset = newRot;
2343 3097
2344 // Since this SOP's state has changed, push those changes into the physics engine 3098 // Since this SOP's state has changed, push those changes into the physics engine
2345 // and the simulator. 3099 // and the simulator.
2346 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3100 // done on caller
3101// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2347 } 3102 }
2348 3103
2349 /// <summary> 3104 /// <summary>
@@ -2365,10 +3120,14 @@ namespace OpenSim.Region.Framework.Scenes
2365 { 3120 {
2366 if (!m_rootPart.BlockGrab) 3121 if (!m_rootPart.BlockGrab)
2367 { 3122 {
2368 Vector3 llmoveforce = pos - AbsolutePosition; 3123/* Vector3 llmoveforce = pos - AbsolutePosition;
2369 Vector3 grabforce = llmoveforce; 3124 Vector3 grabforce = llmoveforce;
2370 grabforce = (grabforce / 10) * pa.Mass; 3125 grabforce = (grabforce / 10) * pa.Mass;
2371 pa.AddForce(grabforce, true); 3126 */
3127 // empirically convert distance diference to a impulse
3128 Vector3 grabforce = pos - AbsolutePosition;
3129 grabforce = grabforce * (pa.Mass/ 10.0f);
3130 pa.AddForce(grabforce, false);
2372 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3131 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2373 } 3132 }
2374 } 3133 }
@@ -2594,8 +3353,22 @@ namespace OpenSim.Region.Framework.Scenes
2594 } 3353 }
2595 } 3354 }
2596 3355
2597 for (int i = 0; i < parts.Length; i++) 3356 if (parts.Length > 1)
2598 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3357 {
3358 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3359
3360 for (int i = 0; i < parts.Length; i++)
3361 {
3362
3363 if (parts[i].UUID != m_rootPart.UUID)
3364 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3365 }
3366
3367 if (m_rootPart.PhysActor != null)
3368 m_rootPart.PhysActor.Building = false;
3369 }
3370 else
3371 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2599 } 3372 }
2600 } 3373 }
2601 3374
@@ -2608,6 +3381,17 @@ namespace OpenSim.Region.Framework.Scenes
2608 } 3381 }
2609 } 3382 }
2610 3383
3384
3385
3386 /// <summary>
3387 /// Gets the number of parts
3388 /// </summary>
3389 /// <returns></returns>
3390 public int GetPartCount()
3391 {
3392 return Parts.Count();
3393 }
3394
2611 /// <summary> 3395 /// <summary>
2612 /// Update the texture entry for this part 3396 /// Update the texture entry for this part
2613 /// </summary> 3397 /// </summary>
@@ -2669,11 +3453,6 @@ namespace OpenSim.Region.Framework.Scenes
2669 /// <param name="scale"></param> 3453 /// <param name="scale"></param>
2670 public void GroupResize(Vector3 scale) 3454 public void GroupResize(Vector3 scale)
2671 { 3455 {
2672// m_log.DebugFormat(
2673// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2674
2675 RootPart.StoreUndoState(true);
2676
2677 scale.X = Math.Min(scale.X, Scene.m_maxNonphys); 3456 scale.X = Math.Min(scale.X, Scene.m_maxNonphys);
2678 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys); 3457 scale.Y = Math.Min(scale.Y, Scene.m_maxNonphys);
2679 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys); 3458 scale.Z = Math.Min(scale.Z, Scene.m_maxNonphys);
@@ -2700,7 +3479,6 @@ namespace OpenSim.Region.Framework.Scenes
2700 SceneObjectPart obPart = parts[i]; 3479 SceneObjectPart obPart = parts[i];
2701 if (obPart.UUID != m_rootPart.UUID) 3480 if (obPart.UUID != m_rootPart.UUID)
2702 { 3481 {
2703// obPart.IgnoreUndoUpdate = true;
2704 Vector3 oldSize = new Vector3(obPart.Scale); 3482 Vector3 oldSize = new Vector3(obPart.Scale);
2705 3483
2706 float f = 1.0f; 3484 float f = 1.0f;
@@ -2764,8 +3542,6 @@ namespace OpenSim.Region.Framework.Scenes
2764 z *= a; 3542 z *= a;
2765 } 3543 }
2766 } 3544 }
2767
2768// obPart.IgnoreUndoUpdate = false;
2769 } 3545 }
2770 } 3546 }
2771 } 3547 }
@@ -2775,9 +3551,7 @@ namespace OpenSim.Region.Framework.Scenes
2775 prevScale.Y *= y; 3551 prevScale.Y *= y;
2776 prevScale.Z *= z; 3552 prevScale.Z *= z;
2777 3553
2778// RootPart.IgnoreUndoUpdate = true;
2779 RootPart.Resize(prevScale); 3554 RootPart.Resize(prevScale);
2780// RootPart.IgnoreUndoUpdate = false;
2781 3555
2782 parts = m_parts.GetArray(); 3556 parts = m_parts.GetArray();
2783 for (int i = 0; i < parts.Length; i++) 3557 for (int i = 0; i < parts.Length; i++)
@@ -2786,8 +3560,6 @@ namespace OpenSim.Region.Framework.Scenes
2786 3560
2787 if (obPart.UUID != m_rootPart.UUID) 3561 if (obPart.UUID != m_rootPart.UUID)
2788 { 3562 {
2789 obPart.IgnoreUndoUpdate = true;
2790
2791 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3563 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2792 currentpos.X *= x; 3564 currentpos.X *= x;
2793 currentpos.Y *= y; 3565 currentpos.Y *= y;
@@ -2800,16 +3572,12 @@ namespace OpenSim.Region.Framework.Scenes
2800 3572
2801 obPart.Resize(newSize); 3573 obPart.Resize(newSize);
2802 obPart.UpdateOffSet(currentpos); 3574 obPart.UpdateOffSet(currentpos);
2803
2804 obPart.IgnoreUndoUpdate = false;
2805 } 3575 }
2806 3576
2807// obPart.IgnoreUndoUpdate = false; 3577 HasGroupChanged = true;
2808// obPart.StoreUndoState(); 3578 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3579 ScheduleGroupForTerseUpdate();
2809 } 3580 }
2810
2811// m_log.DebugFormat(
2812// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2813 } 3581 }
2814 3582
2815 #endregion 3583 #endregion
@@ -2822,14 +3590,6 @@ namespace OpenSim.Region.Framework.Scenes
2822 /// <param name="pos"></param> 3590 /// <param name="pos"></param>
2823 public void UpdateGroupPosition(Vector3 pos) 3591 public void UpdateGroupPosition(Vector3 pos)
2824 { 3592 {
2825// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2826
2827 RootPart.StoreUndoState(true);
2828
2829// SceneObjectPart[] parts = m_parts.GetArray();
2830// for (int i = 0; i < parts.Length; i++)
2831// parts[i].StoreUndoState();
2832
2833 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3593 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2834 { 3594 {
2835 if (IsAttachment) 3595 if (IsAttachment)
@@ -2862,21 +3622,17 @@ namespace OpenSim.Region.Framework.Scenes
2862 /// </summary> 3622 /// </summary>
2863 /// <param name="pos"></param> 3623 /// <param name="pos"></param>
2864 /// <param name="localID"></param> 3624 /// <param name="localID"></param>
3625 ///
3626
2865 public void UpdateSinglePosition(Vector3 pos, uint localID) 3627 public void UpdateSinglePosition(Vector3 pos, uint localID)
2866 { 3628 {
2867 SceneObjectPart part = GetPart(localID); 3629 SceneObjectPart part = GetPart(localID);
2868 3630
2869// SceneObjectPart[] parts = m_parts.GetArray();
2870// for (int i = 0; i < parts.Length; i++)
2871// parts[i].StoreUndoState();
2872
2873 if (part != null) 3631 if (part != null)
2874 { 3632 {
2875// m_log.DebugFormat( 3633// unlock parts position change
2876// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3634 if (m_rootPart.PhysActor != null)
2877 3635 m_rootPart.PhysActor.Building = true;
2878 part.StoreUndoState(false);
2879 part.IgnoreUndoUpdate = true;
2880 3636
2881 if (part.UUID == m_rootPart.UUID) 3637 if (part.UUID == m_rootPart.UUID)
2882 { 3638 {
@@ -2887,8 +3643,10 @@ namespace OpenSim.Region.Framework.Scenes
2887 part.UpdateOffSet(pos); 3643 part.UpdateOffSet(pos);
2888 } 3644 }
2889 3645
3646 if (m_rootPart.PhysActor != null)
3647 m_rootPart.PhysActor.Building = false;
3648
2890 HasGroupChanged = true; 3649 HasGroupChanged = true;
2891 part.IgnoreUndoUpdate = false;
2892 } 3650 }
2893 } 3651 }
2894 3652
@@ -2898,13 +3656,7 @@ namespace OpenSim.Region.Framework.Scenes
2898 /// <param name="pos"></param> 3656 /// <param name="pos"></param>
2899 public void UpdateRootPosition(Vector3 pos) 3657 public void UpdateRootPosition(Vector3 pos)
2900 { 3658 {
2901// m_log.DebugFormat( 3659 // needs to be called with phys building true
2902// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2903
2904// SceneObjectPart[] parts = m_parts.GetArray();
2905// for (int i = 0; i < parts.Length; i++)
2906// parts[i].StoreUndoState();
2907
2908 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3660 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2909 Vector3 oldPos = 3661 Vector3 oldPos =
2910 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3662 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -2927,7 +3679,14 @@ namespace OpenSim.Region.Framework.Scenes
2927 AbsolutePosition = newPos; 3679 AbsolutePosition = newPos;
2928 3680
2929 HasGroupChanged = true; 3681 HasGroupChanged = true;
2930 ScheduleGroupForTerseUpdate(); 3682 if (m_rootPart.Undoing)
3683 {
3684 ScheduleGroupForFullUpdate();
3685 }
3686 else
3687 {
3688 ScheduleGroupForTerseUpdate();
3689 }
2931 } 3690 }
2932 3691
2933 #endregion 3692 #endregion
@@ -2940,24 +3699,16 @@ namespace OpenSim.Region.Framework.Scenes
2940 /// <param name="rot"></param> 3699 /// <param name="rot"></param>
2941 public void UpdateGroupRotationR(Quaternion rot) 3700 public void UpdateGroupRotationR(Quaternion rot)
2942 { 3701 {
2943// m_log.DebugFormat(
2944// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2945
2946// SceneObjectPart[] parts = m_parts.GetArray();
2947// for (int i = 0; i < parts.Length; i++)
2948// parts[i].StoreUndoState();
2949
2950 m_rootPart.StoreUndoState(true);
2951
2952 m_rootPart.UpdateRotation(rot); 3702 m_rootPart.UpdateRotation(rot);
2953 3703
3704/* this is done by rootpart RotationOffset set called by UpdateRotation
2954 PhysicsActor actor = m_rootPart.PhysActor; 3705 PhysicsActor actor = m_rootPart.PhysActor;
2955 if (actor != null) 3706 if (actor != null)
2956 { 3707 {
2957 actor.Orientation = m_rootPart.RotationOffset; 3708 actor.Orientation = m_rootPart.RotationOffset;
2958 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3709 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
2959 } 3710 }
2960 3711*/
2961 HasGroupChanged = true; 3712 HasGroupChanged = true;
2962 ScheduleGroupForTerseUpdate(); 3713 ScheduleGroupForTerseUpdate();
2963 } 3714 }
@@ -2969,16 +3720,6 @@ namespace OpenSim.Region.Framework.Scenes
2969 /// <param name="rot"></param> 3720 /// <param name="rot"></param>
2970 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3721 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
2971 { 3722 {
2972// m_log.DebugFormat(
2973// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2974
2975// SceneObjectPart[] parts = m_parts.GetArray();
2976// for (int i = 0; i < parts.Length; i++)
2977// parts[i].StoreUndoState();
2978
2979 RootPart.StoreUndoState(true);
2980 RootPart.IgnoreUndoUpdate = true;
2981
2982 m_rootPart.UpdateRotation(rot); 3723 m_rootPart.UpdateRotation(rot);
2983 3724
2984 PhysicsActor actor = m_rootPart.PhysActor; 3725 PhysicsActor actor = m_rootPart.PhysActor;
@@ -2997,8 +3738,6 @@ namespace OpenSim.Region.Framework.Scenes
2997 3738
2998 HasGroupChanged = true; 3739 HasGroupChanged = true;
2999 ScheduleGroupForTerseUpdate(); 3740 ScheduleGroupForTerseUpdate();
3000
3001 RootPart.IgnoreUndoUpdate = false;
3002 } 3741 }
3003 3742
3004 /// <summary> 3743 /// <summary>
@@ -3011,13 +3750,11 @@ namespace OpenSim.Region.Framework.Scenes
3011 SceneObjectPart part = GetPart(localID); 3750 SceneObjectPart part = GetPart(localID);
3012 3751
3013 SceneObjectPart[] parts = m_parts.GetArray(); 3752 SceneObjectPart[] parts = m_parts.GetArray();
3014 for (int i = 0; i < parts.Length; i++)
3015 parts[i].StoreUndoState();
3016 3753
3017 if (part != null) 3754 if (part != null)
3018 { 3755 {
3019// m_log.DebugFormat( 3756 if (m_rootPart.PhysActor != null)
3020// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3757 m_rootPart.PhysActor.Building = true;
3021 3758
3022 if (part.UUID == m_rootPart.UUID) 3759 if (part.UUID == m_rootPart.UUID)
3023 { 3760 {
@@ -3027,6 +3764,9 @@ namespace OpenSim.Region.Framework.Scenes
3027 { 3764 {
3028 part.UpdateRotation(rot); 3765 part.UpdateRotation(rot);
3029 } 3766 }
3767
3768 if (m_rootPart.PhysActor != null)
3769 m_rootPart.PhysActor.Building = false;
3030 } 3770 }
3031 } 3771 }
3032 3772
@@ -3040,12 +3780,8 @@ namespace OpenSim.Region.Framework.Scenes
3040 SceneObjectPart part = GetPart(localID); 3780 SceneObjectPart part = GetPart(localID);
3041 if (part != null) 3781 if (part != null)
3042 { 3782 {
3043// m_log.DebugFormat( 3783 if (m_rootPart.PhysActor != null)
3044// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3784 m_rootPart.PhysActor.Building = true;
3045// part.Name, part.LocalId, rot);
3046
3047 part.StoreUndoState();
3048 part.IgnoreUndoUpdate = true;
3049 3785
3050 if (part.UUID == m_rootPart.UUID) 3786 if (part.UUID == m_rootPart.UUID)
3051 { 3787 {
@@ -3058,7 +3794,8 @@ namespace OpenSim.Region.Framework.Scenes
3058 part.OffsetPosition = pos; 3794 part.OffsetPosition = pos;
3059 } 3795 }
3060 3796
3061 part.IgnoreUndoUpdate = false; 3797 if (m_rootPart.PhysActor != null)
3798 m_rootPart.PhysActor.Building = false;
3062 } 3799 }
3063 } 3800 }
3064 3801
@@ -3068,15 +3805,12 @@ namespace OpenSim.Region.Framework.Scenes
3068 /// <param name="rot"></param> 3805 /// <param name="rot"></param>
3069 public void UpdateRootRotation(Quaternion rot) 3806 public void UpdateRootRotation(Quaternion rot)
3070 { 3807 {
3071// m_log.DebugFormat( 3808 // needs to be called with phys building true
3072// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3073// Name, LocalId, rot);
3074
3075 Quaternion axRot = rot; 3809 Quaternion axRot = rot;
3076 Quaternion oldParentRot = m_rootPart.RotationOffset; 3810 Quaternion oldParentRot = m_rootPart.RotationOffset;
3077 3811
3078 m_rootPart.StoreUndoState(); 3812 //Don't use UpdateRotation because it schedules an update prematurely
3079 m_rootPart.UpdateRotation(rot); 3813 m_rootPart.RotationOffset = rot;
3080 3814
3081 PhysicsActor pa = m_rootPart.PhysActor; 3815 PhysicsActor pa = m_rootPart.PhysActor;
3082 3816
@@ -3092,35 +3826,145 @@ namespace OpenSim.Region.Framework.Scenes
3092 SceneObjectPart prim = parts[i]; 3826 SceneObjectPart prim = parts[i];
3093 if (prim.UUID != m_rootPart.UUID) 3827 if (prim.UUID != m_rootPart.UUID)
3094 { 3828 {
3095 prim.IgnoreUndoUpdate = true; 3829 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3830 NewRot = Quaternion.Inverse(axRot) * NewRot;
3831 prim.RotationOffset = NewRot;
3832
3096 Vector3 axPos = prim.OffsetPosition; 3833 Vector3 axPos = prim.OffsetPosition;
3834
3097 axPos *= oldParentRot; 3835 axPos *= oldParentRot;
3098 axPos *= Quaternion.Inverse(axRot); 3836 axPos *= Quaternion.Inverse(axRot);
3099 prim.OffsetPosition = axPos; 3837 prim.OffsetPosition = axPos;
3100 Quaternion primsRot = prim.RotationOffset; 3838 }
3101 Quaternion newRot = oldParentRot * primsRot; 3839 }
3102 newRot = Quaternion.Inverse(axRot) * newRot;
3103 prim.RotationOffset = newRot;
3104 prim.ScheduleTerseUpdate();
3105 prim.IgnoreUndoUpdate = false;
3106 }
3107 }
3108
3109// for (int i = 0; i < parts.Length; i++)
3110// {
3111// SceneObjectPart childpart = parts[i];
3112// if (childpart != m_rootPart)
3113// {
3114//// childpart.IgnoreUndoUpdate = false;
3115//// childpart.StoreUndoState();
3116// }
3117// }
3118 3840
3119 m_rootPart.ScheduleTerseUpdate(); 3841 HasGroupChanged = true;
3842 ScheduleGroupForFullUpdate();
3843 }
3120 3844
3121// m_log.DebugFormat( 3845 private enum updatetype :int
3122// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3846 {
3123// Name, LocalId, rot); 3847 none = 0,
3848 partterse = 1,
3849 partfull = 2,
3850 groupterse = 3,
3851 groupfull = 4
3852 }
3853
3854 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3855 {
3856 // TODO this still as excessive *.Schedule*Update()s
3857
3858 if (part != null && part.ParentGroup != null)
3859 {
3860 ObjectChangeType change = data.change;
3861 bool togroup = ((change & ObjectChangeType.Group) != 0);
3862 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3863
3864 SceneObjectGroup group = part.ParentGroup;
3865 PhysicsActor pha = group.RootPart.PhysActor;
3866
3867 updatetype updateType = updatetype.none;
3868
3869 if (togroup)
3870 {
3871 // related to group
3872 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3873 {
3874 if ((change & ObjectChangeType.Rotation) != 0)
3875 {
3876 group.RootPart.UpdateRotation(data.rotation);
3877 updateType = updatetype.none;
3878 }
3879 if ((change & ObjectChangeType.Position) != 0)
3880 {
3881 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3882 UpdateGroupPosition(data.position);
3883 updateType = updatetype.groupterse;
3884 }
3885 else
3886 // ugly rotation update of all parts
3887 {
3888 group.ResetChildPrimPhysicsPositions();
3889 }
3890
3891 }
3892 if ((change & ObjectChangeType.Scale) != 0)
3893 {
3894 if (pha != null)
3895 pha.Building = true;
3896
3897 group.GroupResize(data.scale);
3898 updateType = updatetype.none;
3899
3900 if (pha != null)
3901 pha.Building = false;
3902 }
3903 }
3904 else
3905 {
3906 // related to single prim in a link-set ( ie group)
3907 if (pha != null)
3908 pha.Building = true;
3909
3910 // root part is special
3911 // parts offset positions or rotations need to change also
3912
3913 if (part == group.RootPart)
3914 {
3915 if ((change & ObjectChangeType.Rotation) != 0)
3916 group.UpdateRootRotation(data.rotation);
3917 if ((change & ObjectChangeType.Position) != 0)
3918 group.UpdateRootPosition(data.position);
3919 if ((change & ObjectChangeType.Scale) != 0)
3920 part.Resize(data.scale);
3921 }
3922 else
3923 {
3924 if ((change & ObjectChangeType.Position) != 0)
3925 {
3926 part.OffsetPosition = data.position;
3927 updateType = updatetype.partterse;
3928 }
3929 if ((change & ObjectChangeType.Rotation) != 0)
3930 {
3931 part.UpdateRotation(data.rotation);
3932 updateType = updatetype.none;
3933 }
3934 if ((change & ObjectChangeType.Scale) != 0)
3935 {
3936 part.Resize(data.scale);
3937 updateType = updatetype.none;
3938 }
3939 }
3940
3941 if (pha != null)
3942 pha.Building = false;
3943 }
3944
3945 if (updateType != updatetype.none)
3946 {
3947 group.HasGroupChanged = true;
3948
3949 switch (updateType)
3950 {
3951 case updatetype.partterse:
3952 part.ScheduleTerseUpdate();
3953 break;
3954 case updatetype.partfull:
3955 part.ScheduleFullUpdate();
3956 break;
3957 case updatetype.groupterse:
3958 group.ScheduleGroupForTerseUpdate();
3959 break;
3960 case updatetype.groupfull:
3961 group.ScheduleGroupForFullUpdate();
3962 break;
3963 default:
3964 break;
3965 }
3966 }
3967 }
3124 } 3968 }
3125 3969
3126 #endregion 3970 #endregion
@@ -3219,10 +4063,11 @@ namespace OpenSim.Region.Framework.Scenes
3219 scriptPosTarget target = m_targets[idx]; 4063 scriptPosTarget target = m_targets[idx];
3220 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4064 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3221 { 4065 {
4066 at_target = true;
4067
3222 // trigger at_target 4068 // trigger at_target
3223 if (m_scriptListens_atTarget) 4069 if (m_scriptListens_atTarget)
3224 { 4070 {
3225 at_target = true;
3226 scriptPosTarget att = new scriptPosTarget(); 4071 scriptPosTarget att = new scriptPosTarget();
3227 att.targetPos = target.targetPos; 4072 att.targetPos = target.targetPos;
3228 att.tolerance = target.tolerance; 4073 att.tolerance = target.tolerance;
@@ -3340,11 +4185,50 @@ namespace OpenSim.Region.Framework.Scenes
3340 } 4185 }
3341 } 4186 }
3342 } 4187 }
3343 4188
4189 public Vector3 GetGeometricCenter()
4190 {
4191 // this is not real geometric center but a average of positions relative to root prim acording to
4192 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4193 // ignoring tortured prims details since sl also seems to ignore
4194 // so no real use in doing it on physics
4195
4196 Vector3 gc = Vector3.Zero;
4197
4198 int nparts = m_parts.Count;
4199 if (nparts <= 1)
4200 return gc;
4201
4202 SceneObjectPart[] parts = m_parts.GetArray();
4203 nparts = parts.Length; // just in case it changed
4204 if (nparts <= 1)
4205 return gc;
4206
4207 Quaternion parentRot = RootPart.RotationOffset;
4208 Vector3 pPos;
4209
4210 // average all parts positions
4211 for (int i = 0; i < nparts; i++)
4212 {
4213 // do it directly
4214 // gc += parts[i].GetWorldPosition();
4215 if (parts[i] != RootPart)
4216 {
4217 pPos = parts[i].OffsetPosition;
4218 gc += pPos;
4219 }
4220
4221 }
4222 gc /= nparts;
4223
4224 // relative to root:
4225// gc -= AbsolutePosition;
4226 return gc;
4227 }
4228
3344 public float GetMass() 4229 public float GetMass()
3345 { 4230 {
3346 float retmass = 0f; 4231 float retmass = 0f;
3347
3348 SceneObjectPart[] parts = m_parts.GetArray(); 4232 SceneObjectPart[] parts = m_parts.GetArray();
3349 for (int i = 0; i < parts.Length; i++) 4233 for (int i = 0; i < parts.Length; i++)
3350 retmass += parts[i].GetMass(); 4234 retmass += parts[i].GetMass();
@@ -3352,6 +4236,39 @@ namespace OpenSim.Region.Framework.Scenes
3352 return retmass; 4236 return retmass;
3353 } 4237 }
3354 4238
4239 // center of mass of full object
4240 public Vector3 GetCenterOfMass()
4241 {
4242 PhysicsActor pa = RootPart.PhysActor;
4243
4244 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4245 {
4246 // physics knows better about center of mass of physical prims
4247 Vector3 tmp = pa.CenterOfMass;
4248 return tmp;
4249 }
4250
4251 Vector3 Ptot = Vector3.Zero;
4252 float totmass = 0f;
4253 float m;
4254
4255 SceneObjectPart[] parts = m_parts.GetArray();
4256 for (int i = 0; i < parts.Length; i++)
4257 {
4258 m = parts[i].GetMass();
4259 Ptot += parts[i].GetPartCenterOfMass() * m;
4260 totmass += m;
4261 }
4262
4263 if (totmass == 0)
4264 totmass = 0;
4265 else
4266 totmass = 1 / totmass;
4267 Ptot *= totmass;
4268
4269 return Ptot;
4270 }
4271
3355 /// <summary> 4272 /// <summary>
3356 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4273 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3357 /// the physics engine can use it. 4274 /// the physics engine can use it.
@@ -3519,6 +4436,14 @@ namespace OpenSim.Region.Framework.Scenes
3519 FromItemID = uuid; 4436 FromItemID = uuid;
3520 } 4437 }
3521 4438
4439 public void ResetOwnerChangeFlag()
4440 {
4441 ForEachPart(delegate(SceneObjectPart part)
4442 {
4443 part.ResetOwnerChangeFlag();
4444 });
4445 }
4446
3522 #endregion 4447 #endregion
3523 } 4448 }
3524} 4449}