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.cs1400
1 files changed, 1184 insertions, 216 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 1fa6a75..b9f9c86 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,44 @@ namespace OpenSim.Region.Framework.Scenes
124 { 130 {
125 if (value) 131 if (value)
126 { 132 {
133
134 if (m_isBackedUp)
135 {
136 m_scene.SceneGraph.FireChangeBackup(this);
137 }
127 timeLastChanged = DateTime.Now.Ticks; 138 timeLastChanged = DateTime.Now.Ticks;
128 if (!m_hasGroupChanged) 139 if (!m_hasGroupChanged)
129 timeFirstChanged = DateTime.Now.Ticks; 140 timeFirstChanged = DateTime.Now.Ticks;
141 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
142 {
143/*
144 if (m_rand == null)
145 {
146 byte[] val = new byte[16];
147 m_rootPart.UUID.ToBytes(val, 0);
148 m_rand = new Random(BitConverter.ToInt32(val, 0));
149 }
150 */
151 if (m_scene.GetRootAgentCount() == 0)
152 {
153 //If the region is empty, this change has been made by an automated process
154 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
155
156// float factor = 1.5f + (float)(m_rand.NextDouble());
157 float factor = 2.0f;
158 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
159 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
160 }
161 else
162 {
163 //If the region is not empty, we want to obey the minimum and maximum persist times
164 //but add a random factor so we stagger the object persistance a little
165// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
166// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
167 m_maxPersistTime = m_scene.m_persistAfter;
168 m_minPersistTime = m_scene.m_dontPersistBefore;
169 }
170 }
130 } 171 }
131 m_hasGroupChanged = value; 172 m_hasGroupChanged = value;
132 173
@@ -141,7 +182,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 182 /// 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. 183 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation.
143 /// </summary> 184 /// </summary>
144 public bool HasGroupChangedDueToDelink { get; private set; } 185 public bool HasGroupChangedDueToDelink { get; set; }
145 186
146 private bool isTimeToPersist() 187 private bool isTimeToPersist()
147 { 188 {
@@ -151,8 +192,19 @@ namespace OpenSim.Region.Framework.Scenes
151 return false; 192 return false;
152 if (m_scene.ShuttingDown) 193 if (m_scene.ShuttingDown)
153 return true; 194 return true;
195
196 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
197 {
198 m_maxPersistTime = m_scene.m_persistAfter;
199 m_minPersistTime = m_scene.m_dontPersistBefore;
200 }
201
154 long currentTime = DateTime.Now.Ticks; 202 long currentTime = DateTime.Now.Ticks;
155 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 203
204 if (timeLastChanged == 0) timeLastChanged = currentTime;
205 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
206
207 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
156 return true; 208 return true;
157 return false; 209 return false;
158 } 210 }
@@ -260,6 +312,11 @@ namespace OpenSim.Region.Framework.Scenes
260 312
261 private bool m_isBackedUp; 313 private bool m_isBackedUp;
262 314
315 public bool IsBackedUp
316 {
317 get { return m_isBackedUp; }
318 }
319
263 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 320 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
264 321
265 protected ulong m_regionHandle; 322 protected ulong m_regionHandle;
@@ -271,10 +328,10 @@ namespace OpenSim.Region.Framework.Scenes
271 328
272 private bool m_scriptListens_atTarget; 329 private bool m_scriptListens_atTarget;
273 private bool m_scriptListens_notAtTarget; 330 private bool m_scriptListens_notAtTarget;
274
275 private bool m_scriptListens_atRotTarget; 331 private bool m_scriptListens_atRotTarget;
276 private bool m_scriptListens_notAtRotTarget; 332 private bool m_scriptListens_notAtRotTarget;
277 333
334 public bool m_dupeInProgress = false;
278 internal Dictionary<UUID, string> m_savedScriptState; 335 internal Dictionary<UUID, string> m_savedScriptState;
279 336
280 #region Properties 337 #region Properties
@@ -311,6 +368,16 @@ namespace OpenSim.Region.Framework.Scenes
311 get { return m_parts.Count; } 368 get { return m_parts.Count; }
312 } 369 }
313 370
371// protected Quaternion m_rotation = Quaternion.Identity;
372//
373// public virtual Quaternion Rotation
374// {
375// get { return m_rotation; }
376// set {
377// m_rotation = value;
378// }
379// }
380
314 public Quaternion GroupRotation 381 public Quaternion GroupRotation
315 { 382 {
316 get { return m_rootPart.RotationOffset; } 383 get { return m_rootPart.RotationOffset; }
@@ -417,7 +484,15 @@ namespace OpenSim.Region.Framework.Scenes
417 { 484 {
418 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 485 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
419 } 486 }
420 487
488
489
490 private struct avtocrossInfo
491 {
492 public ScenePresence av;
493 public uint ParentID;
494 }
495
421 /// <summary> 496 /// <summary>
422 /// The absolute position of this scene object in the scene 497 /// The absolute position of this scene object in the scene
423 /// </summary> 498 /// </summary>
@@ -430,14 +505,136 @@ namespace OpenSim.Region.Framework.Scenes
430 505
431 if (Scene != null) 506 if (Scene != null)
432 { 507 {
433 if ((Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 508 // 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)) 509 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S))
510 // && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
511 if ((Scene.TestBorderCross(val, Cardinals.E) || Scene.TestBorderCross(val, Cardinals.W)
512 || Scene.TestBorderCross(val, Cardinals.N) || Scene.TestBorderCross(val, Cardinals.S))
435 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims)) 513 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
436 { 514 {
437 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 515 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
516 uint x = 0;
517 uint y = 0;
518 string version = String.Empty;
519 Vector3 newpos = Vector3.Zero;
520 OpenSim.Services.Interfaces.GridRegion destination = null;
521
522 if (m_rootPart.KeyframeMotion != null)
523 m_rootPart.KeyframeMotion.StartCrossingCheck();
524
525 bool canCross = true;
526 foreach (ScenePresence av in m_linkedAvatars)
527 {
528 // We need to cross these agents. First, let's find
529 // out if any of them can't cross for some reason.
530 // We have to deny the crossing entirely if any
531 // of them are banned. Alternatively, we could
532 // unsit banned agents....
533
534
535 // We set the avatar position as being the object
536 // position to get the region to send to
537 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out x, out y, out version, out newpos)) == null)
538 {
539 canCross = false;
540 break;
541 }
542
543 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
544 }
545
546 if (canCross)
547 {
548 // We unparent the SP quietly so that it won't
549 // be made to stand up
550
551 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
552
553 foreach (ScenePresence av in m_linkedAvatars)
554 {
555 avtocrossInfo avinfo = new avtocrossInfo();
556 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
557 if (parentPart != null)
558 av.ParentUUID = parentPart.UUID;
559
560 avinfo.av = av;
561 avinfo.ParentID = av.ParentID;
562 avsToCross.Add(avinfo);
563
564 av.ParentID = 0;
565 }
566
567 // m_linkedAvatars.Clear();
568 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
569
570 // Normalize
571 if (val.X >= Constants.RegionSize)
572 val.X -= Constants.RegionSize;
573 if (val.Y >= Constants.RegionSize)
574 val.Y -= Constants.RegionSize;
575 if (val.X < 0)
576 val.X += Constants.RegionSize;
577 if (val.Y < 0)
578 val.Y += Constants.RegionSize;
579
580 // If it's deleted, crossing was successful
581 if (IsDeleted)
582 {
583 // foreach (ScenePresence av in m_linkedAvatars)
584 foreach (avtocrossInfo avinfo in avsToCross)
585 {
586 ScenePresence av = avinfo.av;
587 if (!av.IsInTransit) // just in case...
588 {
589 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
590
591 av.IsInTransit = true;
592
593 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
594 d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
595 }
596 else
597 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar alreasy in transit {0} to {1}", av.Name, val);
598 }
599 avsToCross.Clear();
600 return;
601 }
602 else // cross failed, put avas back ??
603 {
604 foreach (avtocrossInfo avinfo in avsToCross)
605 {
606 ScenePresence av = avinfo.av;
607 av.ParentUUID = UUID.Zero;
608 av.ParentID = avinfo.ParentID;
609// m_linkedAvatars.Add(av);
610 }
611 }
612 avsToCross.Clear();
613
614 }
615 else
616 {
617 if (m_rootPart.KeyframeMotion != null)
618 m_rootPart.KeyframeMotion.CrossingFailure();
619
620 if (RootPart.PhysActor != null)
621 {
622 RootPart.PhysActor.CrossingFailure();
623 }
624 }
625 Vector3 oldp = AbsolutePosition;
626 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)Constants.RegionSize - 0.5f);
627 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)Constants.RegionSize - 0.5f);
628 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, 4096.0f);
438 } 629 }
439 } 630 }
440 631
632/* don't see the need but worse don't see where is restored to false if things stay in
633 foreach (SceneObjectPart part in m_parts.GetArray())
634 {
635 part.IgnoreUndoUpdate = true;
636 }
637 */
441 if (RootPart.GetStatusSandbox()) 638 if (RootPart.GetStatusSandbox())
442 { 639 {
443 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 640 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -455,9 +652,38 @@ namespace OpenSim.Region.Framework.Scenes
455 // Restuff the new GroupPosition into each SOP of the linkset. 652 // Restuff the new GroupPosition into each SOP of the linkset.
456 // This has the affect of resetting and tainting the physics actors. 653 // This has the affect of resetting and tainting the physics actors.
457 SceneObjectPart[] parts = m_parts.GetArray(); 654 SceneObjectPart[] parts = m_parts.GetArray();
458 for (int i = 0; i < parts.Length; i++) 655 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
459 parts[i].GroupPosition = val; 656 if (m_dupeInProgress)
657 triggerScriptEvent = false;
658 foreach (SceneObjectPart part in parts)
659 {
660 part.GroupPosition = val;
661 if (triggerScriptEvent)
662 part.TriggerScriptChangedEvent(Changed.POSITION);
663 }
460 664
665/*
666 This seems not needed and should not be needed:
667 sp absolute position depends on sit part absolute position fixed above.
668 sp ParentPosition is not used anywhere.
669 Since presence is sitting, viewer considers it 'linked' to root prim, so it will move/rotate it
670 Sending a extra packet with avatar position is not only bandwidth waste, but may cause jitter in viewers due to UPD nature.
671
672 if (!m_dupeInProgress)
673 {
674 foreach (ScenePresence av in m_linkedAvatars)
675 {
676 SceneObjectPart p = m_scene.GetSceneObjectPart(av.ParentID);
677 if (p != null && m_parts.TryGetValue(p.UUID, out p))
678 {
679 Vector3 offset = p.GetWorldPosition() - av.ParentPosition;
680 av.AbsolutePosition += offset;
681// av.ParentPosition = p.GetWorldPosition(); //ParentPosition gets cleared by AbsolutePosition
682 av.SendAvatarDataToAllAgents();
683 }
684 }
685 }
686*/
461 //if (m_rootPart.PhysActor != null) 687 //if (m_rootPart.PhysActor != null)
462 //{ 688 //{
463 //m_rootPart.PhysActor.Position = 689 //m_rootPart.PhysActor.Position =
@@ -471,6 +697,40 @@ namespace OpenSim.Region.Framework.Scenes
471 } 697 }
472 } 698 }
473 699
700 public override Vector3 Velocity
701 {
702 get { return RootPart.Velocity; }
703 set { RootPart.Velocity = value; }
704 }
705
706 private void CrossAgentToNewRegionCompleted(IAsyncResult iar)
707 {
708 CrossAgentToNewRegionDelegate icon = (CrossAgentToNewRegionDelegate)iar.AsyncState;
709 ScenePresence agent = icon.EndInvoke(iar);
710
711 //// If the cross was successful, this agent is a child agent
712 if (agent.IsChildAgent)
713 {
714 if (agent.ParentUUID != UUID.Zero)
715 {
716 agent.ParentPart = null;
717// agent.ParentPosition = Vector3.Zero;
718// agent.ParentUUID = UUID.Zero;
719 }
720 }
721
722 agent.ParentUUID = UUID.Zero;
723
724// agent.Reset();
725// else // Not successful
726// agent.RestoreInCurrentScene();
727
728 // In any case
729 agent.IsInTransit = false;
730
731 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
732 }
733
474 public override uint LocalId 734 public override uint LocalId
475 { 735 {
476 get { return m_rootPart.LocalId; } 736 get { return m_rootPart.LocalId; }
@@ -541,6 +801,11 @@ namespace OpenSim.Region.Framework.Scenes
541 m_isSelected = value; 801 m_isSelected = value;
542 // Tell physics engine that group is selected 802 // Tell physics engine that group is selected
543 803
804 // this is not right
805 // but ode engines should only really need to know about root part
806 // so they can put entire object simulation on hold and not colliding
807 // keep as was for now
808
544 PhysicsActor pa = m_rootPart.PhysActor; 809 PhysicsActor pa = m_rootPart.PhysActor;
545 if (pa != null) 810 if (pa != null)
546 { 811 {
@@ -557,6 +822,42 @@ namespace OpenSim.Region.Framework.Scenes
557 childPa.Selected = value; 822 childPa.Selected = value;
558 } 823 }
559 } 824 }
825 if (RootPart.KeyframeMotion != null)
826 RootPart.KeyframeMotion.Selected = value;
827 }
828 }
829
830 public void PartSelectChanged(bool partSelect)
831 {
832 // any part selected makes group selected
833 if (m_isSelected == partSelect)
834 return;
835
836 if (partSelect)
837 {
838 IsSelected = partSelect;
839// if (!IsAttachment)
840// ScheduleGroupForFullUpdate();
841 }
842 else
843 {
844 // bad bad bad 2 heavy for large linksets
845 // since viewer does send lot of (un)selects
846 // this needs to be replaced by a specific list or count ?
847 // but that will require extra code in several places
848
849 SceneObjectPart[] parts = m_parts.GetArray();
850 for (int i = 0; i < parts.Length; i++)
851 {
852 SceneObjectPart part = parts[i];
853 if (part.IsSelected)
854 return;
855 }
856 IsSelected = partSelect;
857 if (!IsAttachment)
858 {
859 ScheduleGroupForFullUpdate();
860 }
560 } 861 }
561 } 862 }
562 863
@@ -642,6 +943,7 @@ namespace OpenSim.Region.Framework.Scenes
642 /// </summary> 943 /// </summary>
643 public SceneObjectGroup() 944 public SceneObjectGroup()
644 { 945 {
946
645 } 947 }
646 948
647 /// <summary> 949 /// <summary>
@@ -659,8 +961,8 @@ namespace OpenSim.Region.Framework.Scenes
659 /// Constructor. This object is added to the scene later via AttachToScene() 961 /// Constructor. This object is added to the scene later via AttachToScene()
660 /// </summary> 962 /// </summary>
661 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 963 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
662 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 964 {
663 { 965 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
664 } 966 }
665 967
666 /// <summary> 968 /// <summary>
@@ -695,6 +997,9 @@ namespace OpenSim.Region.Framework.Scenes
695 /// </summary> 997 /// </summary>
696 public virtual void AttachToBackup() 998 public virtual void AttachToBackup()
697 { 999 {
1000 if (IsAttachment) return;
1001 m_scene.SceneGraph.FireAttachToBackup(this);
1002
698 if (InSceneBackup) 1003 if (InSceneBackup)
699 { 1004 {
700 //m_log.DebugFormat( 1005 //m_log.DebugFormat(
@@ -737,6 +1042,13 @@ namespace OpenSim.Region.Framework.Scenes
737 1042
738 ApplyPhysics(); 1043 ApplyPhysics();
739 1044
1045 if (RootPart.PhysActor != null)
1046 RootPart.Force = RootPart.Force;
1047 if (RootPart.PhysActor != null)
1048 RootPart.Torque = RootPart.Torque;
1049 if (RootPart.PhysActor != null)
1050 RootPart.Buoyancy = RootPart.Buoyancy;
1051
740 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1052 // 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. 1053 // for the same object with very different properties. The caller must schedule the update.
742 //ScheduleGroupForFullUpdate(); 1054 //ScheduleGroupForFullUpdate();
@@ -752,6 +1064,10 @@ namespace OpenSim.Region.Framework.Scenes
752 EntityIntersection result = new EntityIntersection(); 1064 EntityIntersection result = new EntityIntersection();
753 1065
754 SceneObjectPart[] parts = m_parts.GetArray(); 1066 SceneObjectPart[] parts = m_parts.GetArray();
1067
1068 // Find closest hit here
1069 float idist = float.MaxValue;
1070
755 for (int i = 0; i < parts.Length; i++) 1071 for (int i = 0; i < parts.Length; i++)
756 { 1072 {
757 SceneObjectPart part = parts[i]; 1073 SceneObjectPart part = parts[i];
@@ -766,11 +1082,6 @@ namespace OpenSim.Region.Framework.Scenes
766 1082
767 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1083 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
768 1084
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) 1085 if (inter.HitTF)
775 { 1086 {
776 // We need to find the closest prim to return to the testcaller along the ray 1087 // We need to find the closest prim to return to the testcaller along the ray
@@ -781,10 +1092,11 @@ namespace OpenSim.Region.Framework.Scenes
781 result.obj = part; 1092 result.obj = part;
782 result.normal = inter.normal; 1093 result.normal = inter.normal;
783 result.distance = inter.distance; 1094 result.distance = inter.distance;
1095
1096 idist = inter.distance;
784 } 1097 }
785 } 1098 }
786 } 1099 }
787
788 return result; 1100 return result;
789 } 1101 }
790 1102
@@ -796,25 +1108,27 @@ namespace OpenSim.Region.Framework.Scenes
796 /// <returns></returns> 1108 /// <returns></returns>
797 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1109 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
798 { 1110 {
799 maxX = -256f; 1111 maxX = float.MinValue;
800 maxY = -256f; 1112 maxY = float.MinValue;
801 maxZ = -256f; 1113 maxZ = float.MinValue;
802 minX = 256f; 1114 minX = float.MaxValue;
803 minY = 256f; 1115 minY = float.MaxValue;
804 minZ = 8192f; 1116 minZ = float.MaxValue;
805 1117
806 SceneObjectPart[] parts = m_parts.GetArray(); 1118 SceneObjectPart[] parts = m_parts.GetArray();
807 for (int i = 0; i < parts.Length; i++) 1119 foreach (SceneObjectPart part in parts)
808 { 1120 {
809 SceneObjectPart part = parts[i];
810
811 Vector3 worldPos = part.GetWorldPosition(); 1121 Vector3 worldPos = part.GetWorldPosition();
812 Vector3 offset = worldPos - AbsolutePosition; 1122 Vector3 offset = worldPos - AbsolutePosition;
813 Quaternion worldRot; 1123 Quaternion worldRot;
814 if (part.ParentID == 0) 1124 if (part.ParentID == 0)
1125 {
815 worldRot = part.RotationOffset; 1126 worldRot = part.RotationOffset;
1127 }
816 else 1128 else
1129 {
817 worldRot = part.GetWorldRotation(); 1130 worldRot = part.GetWorldRotation();
1131 }
818 1132
819 Vector3 frontTopLeft; 1133 Vector3 frontTopLeft;
820 Vector3 frontTopRight; 1134 Vector3 frontTopRight;
@@ -826,6 +1140,8 @@ namespace OpenSim.Region.Framework.Scenes
826 Vector3 backBottomLeft; 1140 Vector3 backBottomLeft;
827 Vector3 backBottomRight; 1141 Vector3 backBottomRight;
828 1142
1143 // Vector3[] corners = new Vector3[8];
1144
829 Vector3 orig = Vector3.Zero; 1145 Vector3 orig = Vector3.Zero;
830 1146
831 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1147 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -860,6 +1176,38 @@ namespace OpenSim.Region.Framework.Scenes
860 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1176 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
861 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1177 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
862 1178
1179
1180
1181 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1182 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1183 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1184 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1185 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1186 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1187 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1188 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1189
1190 //for (int i = 0; i < 8; i++)
1191 //{
1192 // corners[i] = corners[i] * worldRot;
1193 // corners[i] += offset;
1194
1195 // if (corners[i].X > maxX)
1196 // maxX = corners[i].X;
1197 // if (corners[i].X < minX)
1198 // minX = corners[i].X;
1199
1200 // if (corners[i].Y > maxY)
1201 // maxY = corners[i].Y;
1202 // if (corners[i].Y < minY)
1203 // minY = corners[i].Y;
1204
1205 // if (corners[i].Z > maxZ)
1206 // maxZ = corners[i].Y;
1207 // if (corners[i].Z < minZ)
1208 // minZ = corners[i].Z;
1209 //}
1210
863 frontTopLeft = frontTopLeft * worldRot; 1211 frontTopLeft = frontTopLeft * worldRot;
864 frontTopRight = frontTopRight * worldRot; 1212 frontTopRight = frontTopRight * worldRot;
865 frontBottomLeft = frontBottomLeft * worldRot; 1213 frontBottomLeft = frontBottomLeft * worldRot;
@@ -881,6 +1229,15 @@ namespace OpenSim.Region.Framework.Scenes
881 backTopLeft += offset; 1229 backTopLeft += offset;
882 backTopRight += offset; 1230 backTopRight += offset;
883 1231
1232 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1233 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1234 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1235 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1236 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1237 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1238 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1239 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1240
884 if (frontTopRight.X > maxX) 1241 if (frontTopRight.X > maxX)
885 maxX = frontTopRight.X; 1242 maxX = frontTopRight.X;
886 if (frontTopLeft.X > maxX) 1243 if (frontTopLeft.X > maxX)
@@ -1024,17 +1381,118 @@ namespace OpenSim.Region.Framework.Scenes
1024 1381
1025 #endregion 1382 #endregion
1026 1383
1384 public void GetResourcesCosts(SceneObjectPart apart,
1385 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1386 {
1387 // this information may need to be cached
1388
1389 float cost;
1390 float tmpcost;
1391
1392 bool ComplexCost = false;
1393
1394 SceneObjectPart p;
1395 SceneObjectPart[] parts;
1396
1397 lock (m_parts)
1398 {
1399 parts = m_parts.GetArray();
1400 }
1401
1402 int nparts = parts.Length;
1403
1404
1405 for (int i = 0; i < nparts; i++)
1406 {
1407 p = parts[i];
1408
1409 if (p.UsesComplexCost)
1410 {
1411 ComplexCost = true;
1412 break;
1413 }
1414 }
1415
1416 if (ComplexCost)
1417 {
1418 linksetResCost = 0;
1419 linksetPhysCost = 0;
1420 partCost = 0;
1421 partPhysCost = 0;
1422
1423 for (int i = 0; i < nparts; i++)
1424 {
1425 p = parts[i];
1426
1427 cost = p.StreamingCost;
1428 tmpcost = p.SimulationCost;
1429 if (tmpcost > cost)
1430 cost = tmpcost;
1431 tmpcost = p.PhysicsCost;
1432 if (tmpcost > cost)
1433 cost = tmpcost;
1434
1435 linksetPhysCost += tmpcost;
1436 linksetResCost += cost;
1437
1438 if (p == apart)
1439 {
1440 partCost = cost;
1441 partPhysCost = tmpcost;
1442 }
1443 }
1444 }
1445 else
1446 {
1447 partPhysCost = 1.0f;
1448 partCost = 1.0f;
1449 linksetResCost = (float)nparts;
1450 linksetPhysCost = linksetResCost;
1451 }
1452 }
1453
1454 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1455 {
1456 SceneObjectPart p;
1457 SceneObjectPart[] parts;
1458
1459 lock (m_parts)
1460 {
1461 parts = m_parts.GetArray();
1462 }
1463
1464 int nparts = parts.Length;
1465
1466 PhysCost = 0;
1467 StreamCost = 0;
1468 SimulCost = 0;
1469
1470 for (int i = 0; i < nparts; i++)
1471 {
1472 p = parts[i];
1473
1474 StreamCost += p.StreamingCost;
1475 SimulCost += p.SimulationCost;
1476 PhysCost += p.PhysicsCost;
1477 }
1478 }
1479
1027 public void SaveScriptedState(XmlTextWriter writer) 1480 public void SaveScriptedState(XmlTextWriter writer)
1028 { 1481 {
1482 SaveScriptedState(writer, false);
1483 }
1484
1485 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1486 {
1029 XmlDocument doc = new XmlDocument(); 1487 XmlDocument doc = new XmlDocument();
1030 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1488 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1031 1489
1032 SceneObjectPart[] parts = m_parts.GetArray(); 1490 SceneObjectPart[] parts = m_parts.GetArray();
1033 for (int i = 0; i < parts.Length; i++) 1491 for (int i = 0; i < parts.Length; i++)
1034 { 1492 {
1035 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1493 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1036 foreach (KeyValuePair<UUID, string> kvp in pstates) 1494 foreach (KeyValuePair<UUID, string> kvp in pstates)
1037 states.Add(kvp.Key, kvp.Value); 1495 states[kvp.Key] = kvp.Value;
1038 } 1496 }
1039 1497
1040 if (states.Count > 0) 1498 if (states.Count > 0)
@@ -1054,6 +1512,169 @@ namespace OpenSim.Region.Framework.Scenes
1054 } 1512 }
1055 1513
1056 /// <summary> 1514 /// <summary>
1515 /// Add the avatar to this linkset (avatar is sat).
1516 /// </summary>
1517 /// <param name="agentID"></param>
1518 public void AddAvatar(UUID agentID)
1519 {
1520 ScenePresence presence;
1521 if (m_scene.TryGetScenePresence(agentID, out presence))
1522 {
1523 if (!m_linkedAvatars.Contains(presence))
1524 {
1525 m_linkedAvatars.Add(presence);
1526 }
1527 }
1528 }
1529
1530 /// <summary>
1531 /// Delete the avatar from this linkset (avatar is unsat).
1532 /// </summary>
1533 /// <param name="agentID"></param>
1534 public void DeleteAvatar(UUID agentID)
1535 {
1536 ScenePresence presence;
1537 if (m_scene.TryGetScenePresence(agentID, out presence))
1538 {
1539 if (m_linkedAvatars.Contains(presence))
1540 {
1541 m_linkedAvatars.Remove(presence);
1542 }
1543 }
1544 }
1545
1546 /// <summary>
1547 /// Returns the list of linked presences (avatars sat on this group)
1548 /// </summary>
1549 /// <param name="agentID"></param>
1550 public List<ScenePresence> GetLinkedAvatars()
1551 {
1552 return m_linkedAvatars;
1553 }
1554
1555 /// <summary>
1556 /// Attach this scene object to the given avatar.
1557 /// </summary>
1558 /// <param name="agentID"></param>
1559 /// <param name="attachmentpoint"></param>
1560 /// <param name="AttachOffset"></param>
1561 private void AttachToAgent(
1562 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1563 {
1564 if (avatar != null)
1565 {
1566 // don't attach attachments to child agents
1567 if (avatar.IsChildAgent) return;
1568
1569 // Remove from database and parcel prim count
1570 m_scene.DeleteFromStorage(so.UUID);
1571 m_scene.EventManager.TriggerParcelPrimCountTainted();
1572
1573 so.AttachedAvatar = avatar.UUID;
1574
1575 if (so.RootPart.PhysActor != null)
1576 {
1577 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1578 so.RootPart.PhysActor = null;
1579 }
1580
1581 so.AbsolutePosition = attachOffset;
1582 so.RootPart.AttachedPos = attachOffset;
1583 so.IsAttachment = true;
1584 so.RootPart.SetParentLocalId(avatar.LocalId);
1585 so.AttachmentPoint = attachmentpoint;
1586
1587 avatar.AddAttachment(this);
1588
1589 if (!silent)
1590 {
1591 // Killing it here will cause the client to deselect it
1592 // It then reappears on the avatar, deselected
1593 // through the full update below
1594 //
1595 if (IsSelected)
1596 {
1597 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1598 }
1599
1600 IsSelected = false; // fudge....
1601 ScheduleGroupForFullUpdate();
1602 }
1603 }
1604 else
1605 {
1606 m_log.WarnFormat(
1607 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1608 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1609 }
1610 }
1611
1612 public byte GetAttachmentPoint()
1613 {
1614 return m_rootPart.Shape.State;
1615 }
1616
1617 public void DetachToGround()
1618 {
1619 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1620 if (avatar == null)
1621 return;
1622
1623 avatar.RemoveAttachment(this);
1624
1625 Vector3 detachedpos = new Vector3(127f,127f,127f);
1626 if (avatar == null)
1627 return;
1628
1629 detachedpos = avatar.AbsolutePosition;
1630 FromItemID = UUID.Zero;
1631
1632 AbsolutePosition = detachedpos;
1633 AttachedAvatar = UUID.Zero;
1634
1635 //SceneObjectPart[] parts = m_parts.GetArray();
1636 //for (int i = 0; i < parts.Length; i++)
1637 // parts[i].AttachedAvatar = UUID.Zero;
1638
1639 m_rootPart.SetParentLocalId(0);
1640 AttachmentPoint = (byte)0;
1641 // must check if buildind should be true or false here
1642 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1643 HasGroupChanged = true;
1644 RootPart.Rezzed = DateTime.Now;
1645 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1646 AttachToBackup();
1647 m_scene.EventManager.TriggerParcelPrimCountTainted();
1648 m_rootPart.ScheduleFullUpdate();
1649 m_rootPart.ClearUndoState();
1650 }
1651
1652 public void DetachToInventoryPrep()
1653 {
1654 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1655 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1656 if (avatar != null)
1657 {
1658 //detachedpos = avatar.AbsolutePosition;
1659 avatar.RemoveAttachment(this);
1660 }
1661
1662 AttachedAvatar = UUID.Zero;
1663
1664 /*SceneObjectPart[] parts = m_parts.GetArray();
1665 for (int i = 0; i < parts.Length; i++)
1666 parts[i].AttachedAvatar = UUID.Zero;*/
1667
1668 m_rootPart.SetParentLocalId(0);
1669 //m_rootPart.SetAttachmentPoint((byte)0);
1670 IsAttachment = false;
1671 AbsolutePosition = m_rootPart.AttachedPos;
1672 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1673 //AttachToBackup();
1674 //m_rootPart.ScheduleFullUpdate();
1675 }
1676
1677 /// <summary>
1057 /// 1678 ///
1058 /// </summary> 1679 /// </summary>
1059 /// <param name="part"></param> 1680 /// <param name="part"></param>
@@ -1093,7 +1714,10 @@ namespace OpenSim.Region.Framework.Scenes
1093 public void AddPart(SceneObjectPart part) 1714 public void AddPart(SceneObjectPart part)
1094 { 1715 {
1095 part.SetParent(this); 1716 part.SetParent(this);
1096 part.LinkNum = m_parts.Add(part.UUID, part); 1717 m_parts.Add(part.UUID, part);
1718
1719 part.LinkNum = m_parts.Count;
1720
1097 if (part.LinkNum == 2) 1721 if (part.LinkNum == 2)
1098 RootPart.LinkNum = 1; 1722 RootPart.LinkNum = 1;
1099 } 1723 }
@@ -1119,6 +1743,14 @@ namespace OpenSim.Region.Framework.Scenes
1119 parts[i].UUID = UUID.Random(); 1743 parts[i].UUID = UUID.Random();
1120 } 1744 }
1121 1745
1746 // helper provided for parts.
1747 public int GetSceneMaxUndo()
1748 {
1749 if (m_scene != null)
1750 return m_scene.MaxUndoCount;
1751 return 5;
1752 }
1753
1122 // justincc: I don't believe this hack is needed any longer, especially since the physics 1754 // 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 1755 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1124 // this method was preventing proper reload of scene objects. 1756 // this method was preventing proper reload of scene objects.
@@ -1176,7 +1808,7 @@ namespace OpenSim.Region.Framework.Scenes
1176// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1808// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1177// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1809// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1178 1810
1179 part.StoreUndoState(); 1811// part.StoreUndoState();
1180 part.OnGrab(offsetPos, remoteClient); 1812 part.OnGrab(offsetPos, remoteClient);
1181 } 1813 }
1182 1814
@@ -1196,6 +1828,11 @@ namespace OpenSim.Region.Framework.Scenes
1196 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1828 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1197 public void DeleteGroupFromScene(bool silent) 1829 public void DeleteGroupFromScene(bool silent)
1198 { 1830 {
1831 // We need to keep track of this state in case this group is still queued for backup.
1832 IsDeleted = true;
1833
1834 DetachFromBackup();
1835
1199 SceneObjectPart[] parts = m_parts.GetArray(); 1836 SceneObjectPart[] parts = m_parts.GetArray();
1200 for (int i = 0; i < parts.Length; i++) 1837 for (int i = 0; i < parts.Length; i++)
1201 { 1838 {
@@ -1219,6 +1856,7 @@ namespace OpenSim.Region.Framework.Scenes
1219 } 1856 }
1220 }); 1857 });
1221 } 1858 }
1859
1222 } 1860 }
1223 1861
1224 public void AddScriptLPS(int count) 1862 public void AddScriptLPS(int count)
@@ -1288,28 +1926,43 @@ namespace OpenSim.Region.Framework.Scenes
1288 /// </summary> 1926 /// </summary>
1289 public void ApplyPhysics() 1927 public void ApplyPhysics()
1290 { 1928 {
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(); 1929 SceneObjectPart[] parts = m_parts.GetArray();
1296 if (parts.Length > 1) 1930 if (parts.Length > 1)
1297 { 1931 {
1932 ResetChildPrimPhysicsPositions();
1933
1934 // Apply physics to the root prim
1935 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
1936
1937
1298 for (int i = 0; i < parts.Length; i++) 1938 for (int i = 0; i < parts.Length; i++)
1299 { 1939 {
1300 SceneObjectPart part = parts[i]; 1940 SceneObjectPart part = parts[i];
1301 if (part.LocalId != m_rootPart.LocalId) 1941 if (part.LocalId != m_rootPart.LocalId)
1302 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 1942 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1303 } 1943 }
1304
1305 // Hack to get the physics scene geometries in the right spot 1944 // Hack to get the physics scene geometries in the right spot
1306 ResetChildPrimPhysicsPositions(); 1945// ResetChildPrimPhysicsPositions();
1946 if (m_rootPart.PhysActor != null)
1947 {
1948 m_rootPart.PhysActor.Building = false;
1949 }
1950 }
1951 else
1952 {
1953 // Apply physics to the root prim
1954 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1307 } 1955 }
1308 } 1956 }
1309 1957
1310 public void SetOwnerId(UUID userId) 1958 public void SetOwnerId(UUID userId)
1311 { 1959 {
1312 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 1960 ForEachPart(delegate(SceneObjectPart part)
1961 {
1962
1963 part.OwnerID = userId;
1964
1965 });
1313 } 1966 }
1314 1967
1315 public void ForEachPart(Action<SceneObjectPart> whatToDo) 1968 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1341,11 +1994,17 @@ namespace OpenSim.Region.Framework.Scenes
1341 return; 1994 return;
1342 } 1995 }
1343 1996
1997 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
1998 return;
1999
1344 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2000 // 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. 2001 // any exception propogate upwards.
1346 try 2002 try
1347 { 2003 {
1348 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2004 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2005 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2006 m_scene.LoadingPrims) // Land may not be valid yet
2007
1349 { 2008 {
1350 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2009 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1351 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2010 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1372,6 +2031,7 @@ namespace OpenSim.Region.Framework.Scenes
1372 } 2031 }
1373 } 2032 }
1374 } 2033 }
2034
1375 } 2035 }
1376 2036
1377 if (m_scene.UseBackup && HasGroupChanged) 2037 if (m_scene.UseBackup && HasGroupChanged)
@@ -1379,10 +2039,30 @@ namespace OpenSim.Region.Framework.Scenes
1379 // don't backup while it's selected or you're asking for changes mid stream. 2039 // don't backup while it's selected or you're asking for changes mid stream.
1380 if (isTimeToPersist() || forcedBackup) 2040 if (isTimeToPersist() || forcedBackup)
1381 { 2041 {
2042 if (m_rootPart.PhysActor != null &&
2043 (!m_rootPart.PhysActor.IsPhysical))
2044 {
2045 // Possible ghost prim
2046 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2047 {
2048 foreach (SceneObjectPart part in m_parts.GetArray())
2049 {
2050 // Re-set physics actor positions and
2051 // orientations
2052 part.GroupPosition = m_rootPart.GroupPosition;
2053 }
2054 }
2055 }
1382// m_log.DebugFormat( 2056// m_log.DebugFormat(
1383// "[SCENE]: Storing {0}, {1} in {2}", 2057// "[SCENE]: Storing {0}, {1} in {2}",
1384// Name, UUID, m_scene.RegionInfo.RegionName); 2058// Name, UUID, m_scene.RegionInfo.RegionName);
1385 2059
2060 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2061 {
2062 RootPart.Shape.State = 0;
2063 ScheduleGroupForFullUpdate();
2064 }
2065
1386 SceneObjectGroup backup_group = Copy(false); 2066 SceneObjectGroup backup_group = Copy(false);
1387 backup_group.RootPart.Velocity = RootPart.Velocity; 2067 backup_group.RootPart.Velocity = RootPart.Velocity;
1388 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2068 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1392,6 +2072,16 @@ namespace OpenSim.Region.Framework.Scenes
1392 HasGroupChangedDueToDelink = false; 2072 HasGroupChangedDueToDelink = false;
1393 2073
1394 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2074 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2075/*
2076 backup_group.ForEachPart(delegate(SceneObjectPart part)
2077 {
2078 if (part.KeyframeMotion != null)
2079 {
2080 part.KeyframeMotion = KeyframeMotion.FromData(backup_group, part.KeyframeMotion.Serialize());
2081// part.KeyframeMotion.UpdateSceneObject(this);
2082 }
2083 });
2084*/
1395 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2085 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1396 2086
1397 backup_group.ForEachPart(delegate(SceneObjectPart part) 2087 backup_group.ForEachPart(delegate(SceneObjectPart part)
@@ -1448,10 +2138,14 @@ namespace OpenSim.Region.Framework.Scenes
1448 /// <returns></returns> 2138 /// <returns></returns>
1449 public SceneObjectGroup Copy(bool userExposed) 2139 public SceneObjectGroup Copy(bool userExposed)
1450 { 2140 {
2141 m_dupeInProgress = true;
1451 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2142 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1452 dupe.m_isBackedUp = false; 2143 dupe.m_isBackedUp = false;
1453 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2144 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1454 2145
2146 // new group as no sitting avatars
2147 dupe.m_linkedAvatars = new List<ScenePresence>();
2148
1455 // Warning, The following code related to previousAttachmentStatus is needed so that clones of 2149 // 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! 2150 // 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! 2151 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
@@ -1462,7 +2156,7 @@ namespace OpenSim.Region.Framework.Scenes
1462 // This is only necessary when userExposed is false! 2156 // This is only necessary when userExposed is false!
1463 2157
1464 bool previousAttachmentStatus = dupe.IsAttachment; 2158 bool previousAttachmentStatus = dupe.IsAttachment;
1465 2159
1466 if (!userExposed) 2160 if (!userExposed)
1467 dupe.IsAttachment = true; 2161 dupe.IsAttachment = true;
1468 2162
@@ -1475,16 +2169,17 @@ namespace OpenSim.Region.Framework.Scenes
1475 2169
1476 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2170 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1477 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2171 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2172
1478 2173
1479 if (userExposed) 2174 if (userExposed)
1480 dupe.m_rootPart.TrimPermissions(); 2175 dupe.m_rootPart.TrimPermissions();
1481 2176
1482 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2177 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1483 2178
1484 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2179 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1485 { 2180 {
1486 return p1.LinkNum.CompareTo(p2.LinkNum); 2181 return p1.LinkNum.CompareTo(p2.LinkNum);
1487 } 2182 }
1488 ); 2183 );
1489 2184
1490 foreach (SceneObjectPart part in partList) 2185 foreach (SceneObjectPart part in partList)
@@ -1494,41 +2189,56 @@ namespace OpenSim.Region.Framework.Scenes
1494 { 2189 {
1495 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2190 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1496 newPart.LinkNum = part.LinkNum; 2191 newPart.LinkNum = part.LinkNum;
1497 } 2192 if (userExposed)
2193 newPart.ParentID = dupe.m_rootPart.LocalId;
2194 }
1498 else 2195 else
1499 { 2196 {
1500 newPart = dupe.m_rootPart; 2197 newPart = dupe.m_rootPart;
1501 } 2198 }
2199/*
2200 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2201 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1502 2202
1503 // Need to duplicate the physics actor as well 2203 // Need to duplicate the physics actor as well
1504 PhysicsActor originalPartPa = part.PhysActor; 2204 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1505 if (originalPartPa != null && userExposed)
1506 { 2205 {
1507 PrimitiveBaseShape pbs = newPart.Shape; 2206 PrimitiveBaseShape pbs = newPart.Shape;
1508
1509 newPart.PhysActor 2207 newPart.PhysActor
1510 = m_scene.PhysicsScene.AddPrimShape( 2208 = m_scene.PhysicsScene.AddPrimShape(
1511 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2209 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1512 pbs, 2210 pbs,
1513 newPart.AbsolutePosition, 2211 newPart.AbsolutePosition,
1514 newPart.Scale, 2212 newPart.Scale,
1515 newPart.RotationOffset, 2213 newPart.GetWorldRotation(),
1516 originalPartPa.IsPhysical, 2214 isphys,
2215 isphan,
1517 newPart.LocalId); 2216 newPart.LocalId);
1518 2217
1519 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2218 newPart.DoPhysicsPropertyUpdate(isphys, true);
1520 } 2219 */
2220 if (userExposed)
2221 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2222// }
2223 // copy keyframemotion
2224 if (part.KeyframeMotion != null)
2225 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1521 } 2226 }
1522 2227
1523 if (userExposed) 2228 if (userExposed)
1524 { 2229 {
1525 dupe.UpdateParentIDs(); 2230// done above dupe.UpdateParentIDs();
2231
2232 if (dupe.m_rootPart.PhysActor != null)
2233 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2234
1526 dupe.HasGroupChanged = true; 2235 dupe.HasGroupChanged = true;
1527 dupe.AttachToBackup(); 2236 dupe.AttachToBackup();
1528 2237
1529 ScheduleGroupForFullUpdate(); 2238 ScheduleGroupForFullUpdate();
1530 } 2239 }
1531 2240
2241 m_dupeInProgress = false;
1532 return dupe; 2242 return dupe;
1533 } 2243 }
1534 2244
@@ -1540,11 +2250,24 @@ namespace OpenSim.Region.Framework.Scenes
1540 /// <param name="cGroupID"></param> 2250 /// <param name="cGroupID"></param>
1541 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2251 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1542 { 2252 {
1543 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2253 // SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
2254 // give newpart a new local ID lettng old part keep same
2255 SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2256 newpart.LocalId = m_scene.AllocateLocalId();
2257
2258 SetRootPart(newpart);
2259 if (userExposed)
2260 RootPart.Velocity = Vector3.Zero; // In case source is moving
1544 } 2261 }
1545 2262
1546 public void ScriptSetPhysicsStatus(bool usePhysics) 2263 public void ScriptSetPhysicsStatus(bool usePhysics)
1547 { 2264 {
2265 if (usePhysics)
2266 {
2267 if (RootPart.KeyframeMotion != null)
2268 RootPart.KeyframeMotion.Stop();
2269 RootPart.KeyframeMotion = null;
2270 }
1548 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2271 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1549 } 2272 }
1550 2273
@@ -1592,27 +2315,14 @@ namespace OpenSim.Region.Framework.Scenes
1592 2315
1593 if (pa != null) 2316 if (pa != null)
1594 { 2317 {
1595 pa.AddForce(impulse, true); 2318 // false to be applied as a impulse
1596 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2319 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); 2320 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1611 } 2321 }
1612 } 2322 }
1613 } 2323 }
1614 2324
1615 public void setAngularImpulse(Vector3 impulse) 2325 public void ApplyAngularImpulse(Vector3 impulse)
1616 { 2326 {
1617 PhysicsActor pa = RootPart.PhysActor; 2327 PhysicsActor pa = RootPart.PhysActor;
1618 2328
@@ -1620,7 +2330,8 @@ namespace OpenSim.Region.Framework.Scenes
1620 { 2330 {
1621 if (!IsAttachment) 2331 if (!IsAttachment)
1622 { 2332 {
1623 pa.Torque = impulse; 2333 // false to be applied as a impulse
2334 pa.AddAngularForce(impulse, false);
1624 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2335 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1625 } 2336 }
1626 } 2337 }
@@ -1628,20 +2339,10 @@ namespace OpenSim.Region.Framework.Scenes
1628 2339
1629 public Vector3 GetTorque() 2340 public Vector3 GetTorque()
1630 { 2341 {
1631 PhysicsActor pa = RootPart.PhysActor; 2342 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 } 2343 }
1644 2344
2345 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1645 public void moveToTarget(Vector3 target, float tau) 2346 public void moveToTarget(Vector3 target, float tau)
1646 { 2347 {
1647 if (IsAttachment) 2348 if (IsAttachment)
@@ -1673,6 +2374,46 @@ namespace OpenSim.Region.Framework.Scenes
1673 pa.PIDActive = false; 2374 pa.PIDActive = false;
1674 } 2375 }
1675 2376
2377 public void rotLookAt(Quaternion target, float strength, float damping)
2378 {
2379 SceneObjectPart rootpart = m_rootPart;
2380 if (rootpart != null)
2381 {
2382 if (IsAttachment)
2383 {
2384 /*
2385 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2386 if (avatar != null)
2387 {
2388 Rotate the Av?
2389 } */
2390 }
2391 else
2392 {
2393 if (rootpart.PhysActor != null)
2394 { // APID must be implemented in your physics system for this to function.
2395 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2396 rootpart.PhysActor.APIDStrength = strength;
2397 rootpart.PhysActor.APIDDamping = damping;
2398 rootpart.PhysActor.APIDActive = true;
2399 }
2400 }
2401 }
2402 }
2403
2404 public void stopLookAt()
2405 {
2406 SceneObjectPart rootpart = m_rootPart;
2407 if (rootpart != null)
2408 {
2409 if (rootpart.PhysActor != null)
2410 { // APID must be implemented in your physics system for this to function.
2411 rootpart.PhysActor.APIDActive = false;
2412 }
2413 }
2414
2415 }
2416
1676 /// <summary> 2417 /// <summary>
1677 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2418 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1678 /// </summary> 2419 /// </summary>
@@ -1689,7 +2430,7 @@ namespace OpenSim.Region.Framework.Scenes
1689 { 2430 {
1690 pa.PIDHoverHeight = height; 2431 pa.PIDHoverHeight = height;
1691 pa.PIDHoverType = hoverType; 2432 pa.PIDHoverType = hoverType;
1692 pa.PIDTau = tau; 2433 pa.PIDHoverTau = tau;
1693 pa.PIDHoverActive = true; 2434 pa.PIDHoverActive = true;
1694 } 2435 }
1695 else 2436 else
@@ -1729,7 +2470,12 @@ namespace OpenSim.Region.Framework.Scenes
1729 /// <param name="cGroupID"></param> 2470 /// <param name="cGroupID"></param>
1730 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2471 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1731 { 2472 {
1732 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2473 // give new ID to the new part, letting old keep original
2474 // SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2475 SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2476 newPart.LocalId = m_scene.AllocateLocalId();
2477 newPart.SetParent(this);
2478
1733 AddPart(newPart); 2479 AddPart(newPart);
1734 2480
1735 SetPartAsNonRoot(newPart); 2481 SetPartAsNonRoot(newPart);
@@ -1868,11 +2614,11 @@ namespace OpenSim.Region.Framework.Scenes
1868 /// Immediately send a full update for this scene object. 2614 /// Immediately send a full update for this scene object.
1869 /// </summary> 2615 /// </summary>
1870 public void SendGroupFullUpdate() 2616 public void SendGroupFullUpdate()
1871 { 2617 {
1872 if (IsDeleted) 2618 if (IsDeleted)
1873 return; 2619 return;
1874 2620
1875// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2621// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
1876 2622
1877 RootPart.SendFullUpdateToAllClients(); 2623 RootPart.SendFullUpdateToAllClients();
1878 2624
@@ -2028,6 +2774,11 @@ namespace OpenSim.Region.Framework.Scenes
2028 // 'linkPart' == the root of the group being linked into this group 2774 // 'linkPart' == the root of the group being linked into this group
2029 SceneObjectPart linkPart = objectGroup.m_rootPart; 2775 SceneObjectPart linkPart = objectGroup.m_rootPart;
2030 2776
2777 if (m_rootPart.PhysActor != null)
2778 m_rootPart.PhysActor.Building = true;
2779 if (linkPart.PhysActor != null)
2780 linkPart.PhysActor.Building = true;
2781
2031 // physics flags from group to be applied to linked parts 2782 // physics flags from group to be applied to linked parts
2032 bool grpusephys = UsesPhysics; 2783 bool grpusephys = UsesPhysics;
2033 bool grptemporary = IsTemporary; 2784 bool grptemporary = IsTemporary;
@@ -2053,12 +2804,12 @@ namespace OpenSim.Region.Framework.Scenes
2053 Vector3 axPos = linkPart.OffsetPosition; 2804 Vector3 axPos = linkPart.OffsetPosition;
2054 // Rotate the linking root SOP's position to be relative to the new root prim 2805 // Rotate the linking root SOP's position to be relative to the new root prim
2055 Quaternion parentRot = m_rootPart.RotationOffset; 2806 Quaternion parentRot = m_rootPart.RotationOffset;
2056 axPos *= Quaternion.Inverse(parentRot); 2807 axPos *= Quaternion.Conjugate(parentRot);
2057 linkPart.OffsetPosition = axPos; 2808 linkPart.OffsetPosition = axPos;
2058 2809
2059 // Make the linking root SOP's rotation relative to the new root prim 2810 // Make the linking root SOP's rotation relative to the new root prim
2060 Quaternion oldRot = linkPart.RotationOffset; 2811 Quaternion oldRot = linkPart.RotationOffset;
2061 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 2812 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2062 linkPart.RotationOffset = newRot; 2813 linkPart.RotationOffset = newRot;
2063 2814
2064 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 2815 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
@@ -2092,7 +2843,7 @@ namespace OpenSim.Region.Framework.Scenes
2092 linkPart.CreateSelected = true; 2843 linkPart.CreateSelected = true;
2093 2844
2094 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 2845 // 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); 2846 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2096 2847
2097 // If the added SOP is physical, also tell the physics engine about the link relationship. 2848 // 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) 2849 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2102,6 +2853,7 @@ namespace OpenSim.Region.Framework.Scenes
2102 } 2853 }
2103 2854
2104 linkPart.LinkNum = linkNum++; 2855 linkPart.LinkNum = linkNum++;
2856 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2105 2857
2106 // Get a list of the SOP's in the old group in order of their linknum's. 2858 // Get a list of the SOP's in the old group in order of their linknum's.
2107 SceneObjectPart[] ogParts = objectGroup.Parts; 2859 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2120,7 +2872,7 @@ namespace OpenSim.Region.Framework.Scenes
2120 2872
2121 // Update the physics flags for the newly added SOP 2873 // Update the physics flags for the newly added SOP
2122 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 2874 // (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); 2875 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2124 2876
2125 // If the added SOP is physical, also tell the physics engine about the link relationship. 2877 // 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) 2878 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2138,7 +2890,7 @@ namespace OpenSim.Region.Framework.Scenes
2138 objectGroup.IsDeleted = true; 2890 objectGroup.IsDeleted = true;
2139 2891
2140 objectGroup.m_parts.Clear(); 2892 objectGroup.m_parts.Clear();
2141 2893
2142 // Can't do this yet since backup still makes use of the root part without any synchronization 2894 // Can't do this yet since backup still makes use of the root part without any synchronization
2143// objectGroup.m_rootPart = null; 2895// objectGroup.m_rootPart = null;
2144 2896
@@ -2152,6 +2904,9 @@ namespace OpenSim.Region.Framework.Scenes
2152 // unmoved prims! 2904 // unmoved prims!
2153 ResetChildPrimPhysicsPositions(); 2905 ResetChildPrimPhysicsPositions();
2154 2906
2907 if (m_rootPart.PhysActor != null)
2908 m_rootPart.PhysActor.Building = false;
2909
2155 //HasGroupChanged = true; 2910 //HasGroupChanged = true;
2156 //ScheduleGroupForFullUpdate(); 2911 //ScheduleGroupForFullUpdate();
2157 } 2912 }
@@ -2219,7 +2974,10 @@ namespace OpenSim.Region.Framework.Scenes
2219// m_log.DebugFormat( 2974// m_log.DebugFormat(
2220// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 2975// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2221// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 2976// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2222 2977
2978 if (m_rootPart.PhysActor != null)
2979 m_rootPart.PhysActor.Building = true;
2980
2223 linkPart.ClearUndoState(); 2981 linkPart.ClearUndoState();
2224 2982
2225 Vector3 worldPos = linkPart.GetWorldPosition(); 2983 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2290,6 +3048,14 @@ namespace OpenSim.Region.Framework.Scenes
2290 3048
2291 // When we delete a group, we currently have to force persist to the database if the object id has changed 3049 // 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) 3050 // (since delete works by deleting all rows which have a given object id)
3051
3052 // this is as it seems to be in sl now
3053 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3054 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3055
3056 if (m_rootPart.PhysActor != null)
3057 m_rootPart.PhysActor.Building = false;
3058
2293 objectGroup.HasGroupChangedDueToDelink = true; 3059 objectGroup.HasGroupChangedDueToDelink = true;
2294 3060
2295 return objectGroup; 3061 return objectGroup;
@@ -2301,6 +3067,8 @@ namespace OpenSim.Region.Framework.Scenes
2301 /// <param name="objectGroup"></param> 3067 /// <param name="objectGroup"></param>
2302 public virtual void DetachFromBackup() 3068 public virtual void DetachFromBackup()
2303 { 3069 {
3070 if (m_scene != null)
3071 m_scene.SceneGraph.FireDetachFromBackup(this);
2304 if (m_isBackedUp && Scene != null) 3072 if (m_isBackedUp && Scene != null)
2305 m_scene.EventManager.OnBackup -= ProcessBackup; 3073 m_scene.EventManager.OnBackup -= ProcessBackup;
2306 3074
@@ -2321,7 +3089,8 @@ namespace OpenSim.Region.Framework.Scenes
2321 Vector3 axPos = part.OffsetPosition; 3089 Vector3 axPos = part.OffsetPosition;
2322 axPos *= parentRot; 3090 axPos *= parentRot;
2323 part.OffsetPosition = axPos; 3091 part.OffsetPosition = axPos;
2324 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3092 Vector3 newPos = oldGroupPosition + part.OffsetPosition;
3093 part.GroupPosition = newPos;
2325 part.OffsetPosition = Vector3.Zero; 3094 part.OffsetPosition = Vector3.Zero;
2326 3095
2327 // Compution our rotation to be not relative to the old parent 3096 // Compution our rotation to be not relative to the old parent
@@ -2336,7 +3105,7 @@ namespace OpenSim.Region.Framework.Scenes
2336 part.LinkNum = linkNum; 3105 part.LinkNum = linkNum;
2337 3106
2338 // Compute the new position of this SOP relative to the group position 3107 // Compute the new position of this SOP relative to the group position
2339 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3108 part.OffsetPosition = newPos - AbsolutePosition;
2340 3109
2341 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3110 // (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 3111 // It would have the affect of setting the physics engine position multiple
@@ -2346,18 +3115,19 @@ namespace OpenSim.Region.Framework.Scenes
2346 // Rotate the relative position by the rotation of the group 3115 // Rotate the relative position by the rotation of the group
2347 Quaternion rootRotation = m_rootPart.RotationOffset; 3116 Quaternion rootRotation = m_rootPart.RotationOffset;
2348 Vector3 pos = part.OffsetPosition; 3117 Vector3 pos = part.OffsetPosition;
2349 pos *= Quaternion.Inverse(rootRotation); 3118 pos *= Quaternion.Conjugate(rootRotation);
2350 part.OffsetPosition = pos; 3119 part.OffsetPosition = pos;
2351 3120
2352 // Compute the SOP's rotation relative to the rotation of the group. 3121 // Compute the SOP's rotation relative to the rotation of the group.
2353 parentRot = m_rootPart.RotationOffset; 3122 parentRot = m_rootPart.RotationOffset;
2354 oldRot = part.RotationOffset; 3123 oldRot = part.RotationOffset;
2355 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3124 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2356 part.RotationOffset = newRot; 3125 part.RotationOffset = newRot;
2357 3126
2358 // Since this SOP's state has changed, push those changes into the physics engine 3127 // Since this SOP's state has changed, push those changes into the physics engine
2359 // and the simulator. 3128 // and the simulator.
2360 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3129 // done on caller
3130// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2361 } 3131 }
2362 3132
2363 /// <summary> 3133 /// <summary>
@@ -2379,10 +3149,14 @@ namespace OpenSim.Region.Framework.Scenes
2379 { 3149 {
2380 if (!m_rootPart.BlockGrab) 3150 if (!m_rootPart.BlockGrab)
2381 { 3151 {
2382 Vector3 llmoveforce = pos - AbsolutePosition; 3152/* Vector3 llmoveforce = pos - AbsolutePosition;
2383 Vector3 grabforce = llmoveforce; 3153 Vector3 grabforce = llmoveforce;
2384 grabforce = (grabforce / 10) * pa.Mass; 3154 grabforce = (grabforce / 10) * pa.Mass;
2385 pa.AddForce(grabforce, true); 3155 */
3156 // empirically convert distance diference to a impulse
3157 Vector3 grabforce = pos - AbsolutePosition;
3158 grabforce = grabforce * (pa.Mass/ 10.0f);
3159 pa.AddForce(grabforce, false);
2386 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3160 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2387 } 3161 }
2388 } 3162 }
@@ -2578,6 +3352,8 @@ namespace OpenSim.Region.Framework.Scenes
2578 /// <param name="SetVolumeDetect"></param> 3352 /// <param name="SetVolumeDetect"></param>
2579 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3353 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2580 { 3354 {
3355 HasGroupChanged = true;
3356
2581 SceneObjectPart selectionPart = GetPart(localID); 3357 SceneObjectPart selectionPart = GetPart(localID);
2582 3358
2583 if (SetTemporary && Scene != null) 3359 if (SetTemporary && Scene != null)
@@ -2608,8 +3384,22 @@ namespace OpenSim.Region.Framework.Scenes
2608 } 3384 }
2609 } 3385 }
2610 3386
2611 for (int i = 0; i < parts.Length; i++) 3387 if (parts.Length > 1)
2612 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3388 {
3389 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3390
3391 for (int i = 0; i < parts.Length; i++)
3392 {
3393
3394 if (parts[i].UUID != m_rootPart.UUID)
3395 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3396 }
3397
3398 if (m_rootPart.PhysActor != null)
3399 m_rootPart.PhysActor.Building = false;
3400 }
3401 else
3402 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2613 } 3403 }
2614 } 3404 }
2615 3405
@@ -2622,6 +3412,17 @@ namespace OpenSim.Region.Framework.Scenes
2622 } 3412 }
2623 } 3413 }
2624 3414
3415
3416
3417 /// <summary>
3418 /// Gets the number of parts
3419 /// </summary>
3420 /// <returns></returns>
3421 public int GetPartCount()
3422 {
3423 return Parts.Count();
3424 }
3425
2625 /// <summary> 3426 /// <summary>
2626 /// Update the texture entry for this part 3427 /// Update the texture entry for this part
2627 /// </summary> 3428 /// </summary>
@@ -2638,11 +3439,18 @@ namespace OpenSim.Region.Framework.Scenes
2638 3439
2639 public void AdjustChildPrimPermissions() 3440 public void AdjustChildPrimPermissions()
2640 { 3441 {
3442 uint newOwnerMask = (uint)PermissionMask.All & 0xfffffff8; // Mask folded bits
3443 uint foldedPerms = RootPart.OwnerMask & 3;
3444
2641 ForEachPart(part => 3445 ForEachPart(part =>
2642 { 3446 {
3447 newOwnerMask &= part.BaseMask;
2643 if (part != RootPart) 3448 if (part != RootPart)
2644 part.ClonePermissions(RootPart); 3449 part.ClonePermissions(RootPart);
2645 }); 3450 });
3451
3452 RootPart.OwnerMask = newOwnerMask | foldedPerms;
3453 RootPart.ScheduleFullUpdate();
2646 } 3454 }
2647 3455
2648 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 3456 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2650,8 +3458,24 @@ namespace OpenSim.Region.Framework.Scenes
2650 { 3458 {
2651 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3459 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2652 3460
3461 bool god = Scene.Permissions.IsGod(AgentID);
3462
3463 if (field == 1 && god)
3464 {
3465 ForEachPart(part =>
3466 {
3467 part.BaseMask = RootPart.BaseMask;
3468 });
3469 }
3470
2653 AdjustChildPrimPermissions(); 3471 AdjustChildPrimPermissions();
2654 3472
3473 if (field == 1 && god) // Base mask was set. Update all child part inventories
3474 {
3475 foreach (SceneObjectPart part in Parts)
3476 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3477 }
3478
2655 HasGroupChanged = true; 3479 HasGroupChanged = true;
2656 3480
2657 // Send the group's properties to all clients once all parts are updated 3481 // Send the group's properties to all clients once all parts are updated
@@ -2697,8 +3521,6 @@ namespace OpenSim.Region.Framework.Scenes
2697 3521
2698 PhysicsActor pa = m_rootPart.PhysActor; 3522 PhysicsActor pa = m_rootPart.PhysActor;
2699 3523
2700 RootPart.StoreUndoState(true);
2701
2702 if (Scene != null) 3524 if (Scene != null)
2703 { 3525 {
2704 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3526 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -2726,7 +3548,6 @@ namespace OpenSim.Region.Framework.Scenes
2726 SceneObjectPart obPart = parts[i]; 3548 SceneObjectPart obPart = parts[i];
2727 if (obPart.UUID != m_rootPart.UUID) 3549 if (obPart.UUID != m_rootPart.UUID)
2728 { 3550 {
2729// obPart.IgnoreUndoUpdate = true;
2730 Vector3 oldSize = new Vector3(obPart.Scale); 3551 Vector3 oldSize = new Vector3(obPart.Scale);
2731 3552
2732 float f = 1.0f; 3553 float f = 1.0f;
@@ -2838,8 +3659,6 @@ namespace OpenSim.Region.Framework.Scenes
2838 z *= a; 3659 z *= a;
2839 } 3660 }
2840 } 3661 }
2841
2842// obPart.IgnoreUndoUpdate = false;
2843 } 3662 }
2844 } 3663 }
2845 } 3664 }
@@ -2849,9 +3668,7 @@ namespace OpenSim.Region.Framework.Scenes
2849 prevScale.Y *= y; 3668 prevScale.Y *= y;
2850 prevScale.Z *= z; 3669 prevScale.Z *= z;
2851 3670
2852// RootPart.IgnoreUndoUpdate = true;
2853 RootPart.Resize(prevScale); 3671 RootPart.Resize(prevScale);
2854// RootPart.IgnoreUndoUpdate = false;
2855 3672
2856 for (int i = 0; i < parts.Length; i++) 3673 for (int i = 0; i < parts.Length; i++)
2857 { 3674 {
@@ -2859,8 +3676,6 @@ namespace OpenSim.Region.Framework.Scenes
2859 3676
2860 if (obPart.UUID != m_rootPart.UUID) 3677 if (obPart.UUID != m_rootPart.UUID)
2861 { 3678 {
2862 obPart.IgnoreUndoUpdate = true;
2863
2864 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3679 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2865 currentpos.X *= x; 3680 currentpos.X *= x;
2866 currentpos.Y *= y; 3681 currentpos.Y *= y;
@@ -2873,16 +3688,12 @@ namespace OpenSim.Region.Framework.Scenes
2873 3688
2874 obPart.Resize(newSize); 3689 obPart.Resize(newSize);
2875 obPart.UpdateOffSet(currentpos); 3690 obPart.UpdateOffSet(currentpos);
2876
2877 obPart.IgnoreUndoUpdate = false;
2878 } 3691 }
2879 3692
2880// obPart.IgnoreUndoUpdate = false; 3693 HasGroupChanged = true;
2881// obPart.StoreUndoState(); 3694 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3695 ScheduleGroupForTerseUpdate();
2882 } 3696 }
2883
2884// m_log.DebugFormat(
2885// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2886 } 3697 }
2887 3698
2888 #endregion 3699 #endregion
@@ -2895,14 +3706,6 @@ namespace OpenSim.Region.Framework.Scenes
2895 /// <param name="pos"></param> 3706 /// <param name="pos"></param>
2896 public void UpdateGroupPosition(Vector3 pos) 3707 public void UpdateGroupPosition(Vector3 pos)
2897 { 3708 {
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)) 3709 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2907 { 3710 {
2908 if (IsAttachment) 3711 if (IsAttachment)
@@ -2935,21 +3738,17 @@ namespace OpenSim.Region.Framework.Scenes
2935 /// </summary> 3738 /// </summary>
2936 /// <param name="pos"></param> 3739 /// <param name="pos"></param>
2937 /// <param name="localID"></param> 3740 /// <param name="localID"></param>
3741 ///
3742
2938 public void UpdateSinglePosition(Vector3 pos, uint localID) 3743 public void UpdateSinglePosition(Vector3 pos, uint localID)
2939 { 3744 {
2940 SceneObjectPart part = GetPart(localID); 3745 SceneObjectPart part = GetPart(localID);
2941 3746
2942// SceneObjectPart[] parts = m_parts.GetArray();
2943// for (int i = 0; i < parts.Length; i++)
2944// parts[i].StoreUndoState();
2945
2946 if (part != null) 3747 if (part != null)
2947 { 3748 {
2948// m_log.DebugFormat( 3749// unlock parts position change
2949// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 3750 if (m_rootPart.PhysActor != null)
2950 3751 m_rootPart.PhysActor.Building = true;
2951 part.StoreUndoState(false);
2952 part.IgnoreUndoUpdate = true;
2953 3752
2954 if (part.UUID == m_rootPart.UUID) 3753 if (part.UUID == m_rootPart.UUID)
2955 { 3754 {
@@ -2960,8 +3759,10 @@ namespace OpenSim.Region.Framework.Scenes
2960 part.UpdateOffSet(pos); 3759 part.UpdateOffSet(pos);
2961 } 3760 }
2962 3761
3762 if (m_rootPart.PhysActor != null)
3763 m_rootPart.PhysActor.Building = false;
3764
2963 HasGroupChanged = true; 3765 HasGroupChanged = true;
2964 part.IgnoreUndoUpdate = false;
2965 } 3766 }
2966 } 3767 }
2967 3768
@@ -2971,13 +3772,7 @@ namespace OpenSim.Region.Framework.Scenes
2971 /// <param name="pos"></param> 3772 /// <param name="pos"></param>
2972 public void UpdateRootPosition(Vector3 pos) 3773 public void UpdateRootPosition(Vector3 pos)
2973 { 3774 {
2974// m_log.DebugFormat( 3775 // 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); 3776 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2982 Vector3 oldPos = 3777 Vector3 oldPos =
2983 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3778 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
@@ -3000,7 +3795,14 @@ namespace OpenSim.Region.Framework.Scenes
3000 AbsolutePosition = newPos; 3795 AbsolutePosition = newPos;
3001 3796
3002 HasGroupChanged = true; 3797 HasGroupChanged = true;
3003 ScheduleGroupForTerseUpdate(); 3798 if (m_rootPart.Undoing)
3799 {
3800 ScheduleGroupForFullUpdate();
3801 }
3802 else
3803 {
3804 ScheduleGroupForTerseUpdate();
3805 }
3004 } 3806 }
3005 3807
3006 #endregion 3808 #endregion
@@ -3013,24 +3815,16 @@ namespace OpenSim.Region.Framework.Scenes
3013 /// <param name="rot"></param> 3815 /// <param name="rot"></param>
3014 public void UpdateGroupRotationR(Quaternion rot) 3816 public void UpdateGroupRotationR(Quaternion rot)
3015 { 3817 {
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); 3818 m_rootPart.UpdateRotation(rot);
3026 3819
3820/* this is done by rootpart RotationOffset set called by UpdateRotation
3027 PhysicsActor actor = m_rootPart.PhysActor; 3821 PhysicsActor actor = m_rootPart.PhysActor;
3028 if (actor != null) 3822 if (actor != null)
3029 { 3823 {
3030 actor.Orientation = m_rootPart.RotationOffset; 3824 actor.Orientation = m_rootPart.RotationOffset;
3031 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 3825 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3032 } 3826 }
3033 3827*/
3034 HasGroupChanged = true; 3828 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3829 ScheduleGroupForTerseUpdate();
3036 } 3830 }
@@ -3042,16 +3836,6 @@ namespace OpenSim.Region.Framework.Scenes
3042 /// <param name="rot"></param> 3836 /// <param name="rot"></param>
3043 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 3837 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3044 { 3838 {
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); 3839 m_rootPart.UpdateRotation(rot);
3056 3840
3057 PhysicsActor actor = m_rootPart.PhysActor; 3841 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3070,8 +3854,6 @@ namespace OpenSim.Region.Framework.Scenes
3070 3854
3071 HasGroupChanged = true; 3855 HasGroupChanged = true;
3072 ScheduleGroupForTerseUpdate(); 3856 ScheduleGroupForTerseUpdate();
3073
3074 RootPart.IgnoreUndoUpdate = false;
3075 } 3857 }
3076 3858
3077 /// <summary> 3859 /// <summary>
@@ -3084,13 +3866,11 @@ namespace OpenSim.Region.Framework.Scenes
3084 SceneObjectPart part = GetPart(localID); 3866 SceneObjectPart part = GetPart(localID);
3085 3867
3086 SceneObjectPart[] parts = m_parts.GetArray(); 3868 SceneObjectPart[] parts = m_parts.GetArray();
3087 for (int i = 0; i < parts.Length; i++)
3088 parts[i].StoreUndoState();
3089 3869
3090 if (part != null) 3870 if (part != null)
3091 { 3871 {
3092// m_log.DebugFormat( 3872 if (m_rootPart.PhysActor != null)
3093// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 3873 m_rootPart.PhysActor.Building = true;
3094 3874
3095 if (part.UUID == m_rootPart.UUID) 3875 if (part.UUID == m_rootPart.UUID)
3096 { 3876 {
@@ -3100,6 +3880,9 @@ namespace OpenSim.Region.Framework.Scenes
3100 { 3880 {
3101 part.UpdateRotation(rot); 3881 part.UpdateRotation(rot);
3102 } 3882 }
3883
3884 if (m_rootPart.PhysActor != null)
3885 m_rootPart.PhysActor.Building = false;
3103 } 3886 }
3104 } 3887 }
3105 3888
@@ -3113,12 +3896,8 @@ namespace OpenSim.Region.Framework.Scenes
3113 SceneObjectPart part = GetPart(localID); 3896 SceneObjectPart part = GetPart(localID);
3114 if (part != null) 3897 if (part != null)
3115 { 3898 {
3116// m_log.DebugFormat( 3899 if (m_rootPart.PhysActor != null)
3117// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 3900 m_rootPart.PhysActor.Building = true;
3118// part.Name, part.LocalId, rot);
3119
3120 part.StoreUndoState();
3121 part.IgnoreUndoUpdate = true;
3122 3901
3123 if (part.UUID == m_rootPart.UUID) 3902 if (part.UUID == m_rootPart.UUID)
3124 { 3903 {
@@ -3131,7 +3910,8 @@ namespace OpenSim.Region.Framework.Scenes
3131 part.OffsetPosition = pos; 3910 part.OffsetPosition = pos;
3132 } 3911 }
3133 3912
3134 part.IgnoreUndoUpdate = false; 3913 if (m_rootPart.PhysActor != null)
3914 m_rootPart.PhysActor.Building = false;
3135 } 3915 }
3136 } 3916 }
3137 3917
@@ -3141,15 +3921,12 @@ namespace OpenSim.Region.Framework.Scenes
3141 /// <param name="rot"></param> 3921 /// <param name="rot"></param>
3142 public void UpdateRootRotation(Quaternion rot) 3922 public void UpdateRootRotation(Quaternion rot)
3143 { 3923 {
3144// m_log.DebugFormat( 3924 // 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; 3925 Quaternion axRot = rot;
3149 Quaternion oldParentRot = m_rootPart.RotationOffset; 3926 Quaternion oldParentRot = m_rootPart.RotationOffset;
3150 3927
3151 m_rootPart.StoreUndoState(); 3928 //Don't use UpdateRotation because it schedules an update prematurely
3152 m_rootPart.UpdateRotation(rot); 3929 m_rootPart.RotationOffset = rot;
3153 3930
3154 PhysicsActor pa = m_rootPart.PhysActor; 3931 PhysicsActor pa = m_rootPart.PhysActor;
3155 3932
@@ -3165,35 +3942,145 @@ namespace OpenSim.Region.Framework.Scenes
3165 SceneObjectPart prim = parts[i]; 3942 SceneObjectPart prim = parts[i];
3166 if (prim.UUID != m_rootPart.UUID) 3943 if (prim.UUID != m_rootPart.UUID)
3167 { 3944 {
3168 prim.IgnoreUndoUpdate = true; 3945 Quaternion NewRot = oldParentRot * prim.RotationOffset;
3946 NewRot = Quaternion.Inverse(axRot) * NewRot;
3947 prim.RotationOffset = NewRot;
3948
3169 Vector3 axPos = prim.OffsetPosition; 3949 Vector3 axPos = prim.OffsetPosition;
3950
3170 axPos *= oldParentRot; 3951 axPos *= oldParentRot;
3171 axPos *= Quaternion.Inverse(axRot); 3952 axPos *= Quaternion.Inverse(axRot);
3172 prim.OffsetPosition = axPos; 3953 prim.OffsetPosition = axPos;
3173 Quaternion primsRot = prim.RotationOffset; 3954 }
3174 Quaternion newRot = oldParentRot * primsRot; 3955 }
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 3956
3192 m_rootPart.ScheduleTerseUpdate(); 3957 HasGroupChanged = true;
3958 ScheduleGroupForFullUpdate();
3959 }
3193 3960
3194// m_log.DebugFormat( 3961 private enum updatetype :int
3195// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 3962 {
3196// Name, LocalId, rot); 3963 none = 0,
3964 partterse = 1,
3965 partfull = 2,
3966 groupterse = 3,
3967 groupfull = 4
3968 }
3969
3970 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3971 {
3972 // TODO this still as excessive *.Schedule*Update()s
3973
3974 if (part != null && part.ParentGroup != null)
3975 {
3976 ObjectChangeType change = data.change;
3977 bool togroup = ((change & ObjectChangeType.Group) != 0);
3978 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
3979
3980 SceneObjectGroup group = part.ParentGroup;
3981 PhysicsActor pha = group.RootPart.PhysActor;
3982
3983 updatetype updateType = updatetype.none;
3984
3985 if (togroup)
3986 {
3987 // related to group
3988 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
3989 {
3990 if ((change & ObjectChangeType.Rotation) != 0)
3991 {
3992 group.RootPart.UpdateRotation(data.rotation);
3993 updateType = updatetype.none;
3994 }
3995 if ((change & ObjectChangeType.Position) != 0)
3996 {
3997 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
3998 UpdateGroupPosition(data.position);
3999 updateType = updatetype.groupterse;
4000 }
4001 else
4002 // ugly rotation update of all parts
4003 {
4004 group.ResetChildPrimPhysicsPositions();
4005 }
4006
4007 }
4008 if ((change & ObjectChangeType.Scale) != 0)
4009 {
4010 if (pha != null)
4011 pha.Building = true;
4012
4013 group.GroupResize(data.scale);
4014 updateType = updatetype.none;
4015
4016 if (pha != null)
4017 pha.Building = false;
4018 }
4019 }
4020 else
4021 {
4022 // related to single prim in a link-set ( ie group)
4023 if (pha != null)
4024 pha.Building = true;
4025
4026 // root part is special
4027 // parts offset positions or rotations need to change also
4028
4029 if (part == group.RootPart)
4030 {
4031 if ((change & ObjectChangeType.Rotation) != 0)
4032 group.UpdateRootRotation(data.rotation);
4033 if ((change & ObjectChangeType.Position) != 0)
4034 group.UpdateRootPosition(data.position);
4035 if ((change & ObjectChangeType.Scale) != 0)
4036 part.Resize(data.scale);
4037 }
4038 else
4039 {
4040 if ((change & ObjectChangeType.Position) != 0)
4041 {
4042 part.OffsetPosition = data.position;
4043 updateType = updatetype.partterse;
4044 }
4045 if ((change & ObjectChangeType.Rotation) != 0)
4046 {
4047 part.UpdateRotation(data.rotation);
4048 updateType = updatetype.none;
4049 }
4050 if ((change & ObjectChangeType.Scale) != 0)
4051 {
4052 part.Resize(data.scale);
4053 updateType = updatetype.none;
4054 }
4055 }
4056
4057 if (pha != null)
4058 pha.Building = false;
4059 }
4060
4061 if (updateType != updatetype.none)
4062 {
4063 group.HasGroupChanged = true;
4064
4065 switch (updateType)
4066 {
4067 case updatetype.partterse:
4068 part.ScheduleTerseUpdate();
4069 break;
4070 case updatetype.partfull:
4071 part.ScheduleFullUpdate();
4072 break;
4073 case updatetype.groupterse:
4074 group.ScheduleGroupForTerseUpdate();
4075 break;
4076 case updatetype.groupfull:
4077 group.ScheduleGroupForFullUpdate();
4078 break;
4079 default:
4080 break;
4081 }
4082 }
4083 }
3197 } 4084 }
3198 4085
3199 #endregion 4086 #endregion
@@ -3292,10 +4179,11 @@ namespace OpenSim.Region.Framework.Scenes
3292 scriptPosTarget target = m_targets[idx]; 4179 scriptPosTarget target = m_targets[idx];
3293 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4180 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3294 { 4181 {
4182 at_target = true;
4183
3295 // trigger at_target 4184 // trigger at_target
3296 if (m_scriptListens_atTarget) 4185 if (m_scriptListens_atTarget)
3297 { 4186 {
3298 at_target = true;
3299 scriptPosTarget att = new scriptPosTarget(); 4187 scriptPosTarget att = new scriptPosTarget();
3300 att.targetPos = target.targetPos; 4188 att.targetPos = target.targetPos;
3301 att.tolerance = target.tolerance; 4189 att.tolerance = target.tolerance;
@@ -3413,11 +4301,50 @@ namespace OpenSim.Region.Framework.Scenes
3413 } 4301 }
3414 } 4302 }
3415 } 4303 }
3416 4304
4305 public Vector3 GetGeometricCenter()
4306 {
4307 // this is not real geometric center but a average of positions relative to root prim acording to
4308 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4309 // ignoring tortured prims details since sl also seems to ignore
4310 // so no real use in doing it on physics
4311
4312 Vector3 gc = Vector3.Zero;
4313
4314 int nparts = m_parts.Count;
4315 if (nparts <= 1)
4316 return gc;
4317
4318 SceneObjectPart[] parts = m_parts.GetArray();
4319 nparts = parts.Length; // just in case it changed
4320 if (nparts <= 1)
4321 return gc;
4322
4323 Quaternion parentRot = RootPart.RotationOffset;
4324 Vector3 pPos;
4325
4326 // average all parts positions
4327 for (int i = 0; i < nparts; i++)
4328 {
4329 // do it directly
4330 // gc += parts[i].GetWorldPosition();
4331 if (parts[i] != RootPart)
4332 {
4333 pPos = parts[i].OffsetPosition;
4334 gc += pPos;
4335 }
4336
4337 }
4338 gc /= nparts;
4339
4340 // relative to root:
4341// gc -= AbsolutePosition;
4342 return gc;
4343 }
4344
3417 public float GetMass() 4345 public float GetMass()
3418 { 4346 {
3419 float retmass = 0f; 4347 float retmass = 0f;
3420
3421 SceneObjectPart[] parts = m_parts.GetArray(); 4348 SceneObjectPart[] parts = m_parts.GetArray();
3422 for (int i = 0; i < parts.Length; i++) 4349 for (int i = 0; i < parts.Length; i++)
3423 retmass += parts[i].GetMass(); 4350 retmass += parts[i].GetMass();
@@ -3425,6 +4352,39 @@ namespace OpenSim.Region.Framework.Scenes
3425 return retmass; 4352 return retmass;
3426 } 4353 }
3427 4354
4355 // center of mass of full object
4356 public Vector3 GetCenterOfMass()
4357 {
4358 PhysicsActor pa = RootPart.PhysActor;
4359
4360 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4361 {
4362 // physics knows better about center of mass of physical prims
4363 Vector3 tmp = pa.CenterOfMass;
4364 return tmp;
4365 }
4366
4367 Vector3 Ptot = Vector3.Zero;
4368 float totmass = 0f;
4369 float m;
4370
4371 SceneObjectPart[] parts = m_parts.GetArray();
4372 for (int i = 0; i < parts.Length; i++)
4373 {
4374 m = parts[i].GetMass();
4375 Ptot += parts[i].GetPartCenterOfMass() * m;
4376 totmass += m;
4377 }
4378
4379 if (totmass == 0)
4380 totmass = 0;
4381 else
4382 totmass = 1 / totmass;
4383 Ptot *= totmass;
4384
4385 return Ptot;
4386 }
4387
3428 /// <summary> 4388 /// <summary>
3429 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4389 /// 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. 4390 /// the physics engine can use it.
@@ -3593,6 +4553,14 @@ namespace OpenSim.Region.Framework.Scenes
3593 FromItemID = uuid; 4553 FromItemID = uuid;
3594 } 4554 }
3595 4555
4556 public void ResetOwnerChangeFlag()
4557 {
4558 ForEachPart(delegate(SceneObjectPart part)
4559 {
4560 part.ResetOwnerChangeFlag();
4561 });
4562 }
4563
3596 #endregion 4564 #endregion
3597 } 4565 }
3598} 4566}