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.cs1803
1 files changed, 1369 insertions, 434 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 1c4b77a..b3bd7e0 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;
@@ -44,6 +45,7 @@ using PermissionMask = OpenSim.Framework.PermissionMask;
44 45
45namespace OpenSim.Region.Framework.Scenes 46namespace OpenSim.Region.Framework.Scenes
46{ 47{
48
47 [Flags] 49 [Flags]
48 public enum scriptEvents 50 public enum scriptEvents
49 { 51 {
@@ -79,14 +81,14 @@ namespace OpenSim.Region.Framework.Scenes
79 object_rez = 4194304 81 object_rez = 4194304
80 } 82 }
81 83
82 struct scriptPosTarget 84 public struct scriptPosTarget
83 { 85 {
84 public Vector3 targetPos; 86 public Vector3 targetPos;
85 public float tolerance; 87 public float tolerance;
86 public uint handle; 88 public uint handle;
87 } 89 }
88 90
89 struct scriptRotTarget 91 public struct scriptRotTarget
90 { 92 {
91 public Quaternion targetRot; 93 public Quaternion targetRot;
92 public float tolerance; 94 public float tolerance;
@@ -120,8 +122,12 @@ namespace OpenSim.Region.Framework.Scenes
120 /// since the group's last persistent backup 122 /// since the group's last persistent backup
121 /// </summary> 123 /// </summary>
122 private bool m_hasGroupChanged = false; 124 private bool m_hasGroupChanged = false;
123 private long timeFirstChanged; 125 private long timeFirstChanged = 0;
124 private long timeLastChanged; 126 private long timeLastChanged = 0;
127 private long m_maxPersistTime = 0;
128 private long m_minPersistTime = 0;
129// private Random m_rand;
130 private List<ScenePresence> m_linkedAvatars = new List<ScenePresence>();
125 131
126 /// <summary> 132 /// <summary>
127 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 133 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -138,9 +144,44 @@ namespace OpenSim.Region.Framework.Scenes
138 { 144 {
139 if (value) 145 if (value)
140 { 146 {
147
148 if (m_isBackedUp)
149 {
150 m_scene.SceneGraph.FireChangeBackup(this);
151 }
141 timeLastChanged = DateTime.Now.Ticks; 152 timeLastChanged = DateTime.Now.Ticks;
142 if (!m_hasGroupChanged) 153 if (!m_hasGroupChanged)
143 timeFirstChanged = DateTime.Now.Ticks; 154 timeFirstChanged = DateTime.Now.Ticks;
155 if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
156 {
157/*
158 if (m_rand == null)
159 {
160 byte[] val = new byte[16];
161 m_rootPart.UUID.ToBytes(val, 0);
162 m_rand = new Random(BitConverter.ToInt32(val, 0));
163 }
164 */
165 if (m_scene.GetRootAgentCount() == 0)
166 {
167 //If the region is empty, this change has been made by an automated process
168 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
169
170// float factor = 1.5f + (float)(m_rand.NextDouble());
171 float factor = 2.0f;
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 m_maxPersistTime = m_scene.m_persistAfter;
182 m_minPersistTime = m_scene.m_dontPersistBefore;
183 }
184 }
144 } 185 }
145 m_hasGroupChanged = value; 186 m_hasGroupChanged = value;
146 187
@@ -171,6 +212,7 @@ namespace OpenSim.Region.Framework.Scenes
171 get { return m_groupContainsForeignPrims; } 212 get { return m_groupContainsForeignPrims; }
172 } 213 }
173 214
215 public bool HasGroupChangedDueToDelink { get; set; }
174 216
175 private bool isTimeToPersist() 217 private bool isTimeToPersist()
176 { 218 {
@@ -180,8 +222,19 @@ namespace OpenSim.Region.Framework.Scenes
180 return false; 222 return false;
181 if (m_scene.ShuttingDown) 223 if (m_scene.ShuttingDown)
182 return true; 224 return true;
225
226 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
227 {
228 m_maxPersistTime = m_scene.m_persistAfter;
229 m_minPersistTime = m_scene.m_dontPersistBefore;
230 }
231
183 long currentTime = DateTime.Now.Ticks; 232 long currentTime = DateTime.Now.Ticks;
184 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 233
234 if (timeLastChanged == 0) timeLastChanged = currentTime;
235 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
236
237 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
185 return true; 238 return true;
186 return false; 239 return false;
187 } 240 }
@@ -239,6 +292,11 @@ namespace OpenSim.Region.Framework.Scenes
239 { 292 {
240 AttachmentPoint = 0; 293 AttachmentPoint = 0;
241 294
295 // Don't zap trees
296 if (RootPart.Shape.PCode == (byte)PCode.Tree ||
297 RootPart.Shape.PCode == (byte)PCode.NewTree)
298 return;
299
242 // Even though we don't use child part state parameters for attachments any more, we still need to set 300 // Even though we don't use child part state parameters for attachments any more, we still need to set
243 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if 301 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
244 // we store them correctly, scene objects that we receive from elsewhere might not. 302 // we store them correctly, scene objects that we receive from elsewhere might not.
@@ -292,21 +350,38 @@ namespace OpenSim.Region.Framework.Scenes
292 /// </summary> 350 /// </summary>
293 public bool Backup { get; private set; } 351 public bool Backup { get; private set; }
294 352
353 private bool m_isBackedUp;
354
355 public bool IsBackedUp
356 {
357 get { return m_isBackedUp; }
358 }
359
295 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 360 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
296 361
297 protected ulong m_regionHandle; 362 protected ulong m_regionHandle;
298 protected SceneObjectPart m_rootPart; 363 protected SceneObjectPart m_rootPart;
299 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); 364 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
300 365
301 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); 366 private SortedDictionary<uint, scriptPosTarget> m_targets = new SortedDictionary<uint, scriptPosTarget>();
302 private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); 367 private SortedDictionary<uint, scriptRotTarget> m_rotTargets = new SortedDictionary<uint, scriptRotTarget>();
368
369 public SortedDictionary<uint, scriptPosTarget> AtTargets
370 {
371 get { return m_targets; }
372 }
373
374 public SortedDictionary<uint, scriptRotTarget> RotTargets
375 {
376 get { return m_rotTargets; }
377 }
303 378
304 private bool m_scriptListens_atTarget; 379 private bool m_scriptListens_atTarget;
305 private bool m_scriptListens_notAtTarget; 380 private bool m_scriptListens_notAtTarget;
306
307 private bool m_scriptListens_atRotTarget; 381 private bool m_scriptListens_atRotTarget;
308 private bool m_scriptListens_notAtRotTarget; 382 private bool m_scriptListens_notAtRotTarget;
309 383
384 public bool m_dupeInProgress = false;
310 internal Dictionary<UUID, string> m_savedScriptState; 385 internal Dictionary<UUID, string> m_savedScriptState;
311 386
312 #region Properties 387 #region Properties
@@ -343,6 +418,16 @@ namespace OpenSim.Region.Framework.Scenes
343 get { return m_parts.Count; } 418 get { return m_parts.Count; }
344 } 419 }
345 420
421// protected Quaternion m_rotation = Quaternion.Identity;
422//
423// public virtual Quaternion Rotation
424// {
425// get { return m_rotation; }
426// set {
427// m_rotation = value;
428// }
429// }
430
346 public Quaternion GroupRotation 431 public Quaternion GroupRotation
347 { 432 {
348 get { return m_rootPart.RotationOffset; } 433 get { return m_rootPart.RotationOffset; }
@@ -456,6 +541,10 @@ namespace OpenSim.Region.Framework.Scenes
456 public uint ParentID; 541 public uint ParentID;
457 } 542 }
458 543
544
545 public bool inTransit = false;
546 public delegate SceneObjectGroup SOGCrossDelegate(SceneObjectGroup sog,Vector3 pos);
547
459 /// <summary> 548 /// <summary>
460 /// The absolute position of this scene object in the scene 549 /// The absolute position of this scene object in the scene
461 /// </summary> 550 /// </summary>
@@ -465,181 +554,255 @@ namespace OpenSim.Region.Framework.Scenes
465 set 554 set
466 { 555 {
467 Vector3 val = value; 556 Vector3 val = value;
557 if (Scene != null
558 && !Scene.PositionIsInCurrentRegion(val)
559 && !IsAttachmentCheckFull()
560 && !Scene.LoadingPrims
561 )
562 {
563 if (!inTransit)
564 {
565 inTransit = true;
566 SOGCrossDelegate d = CrossAsync;
567 d.BeginInvoke(this, val, CrossAsyncCompleted, d);
568 }
569 return;
570 }
468 571
469 if (Scene != null) 572 if (RootPart.GetStatusSandbox())
470 { 573 {
471 if ( 574 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
472 !Scene.PositionIsInCurrentRegion(val)
473 && !IsAttachmentCheckFull()
474 && (!Scene.LoadingPrims)
475 )
476 { 575 {
477 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); 576 RootPart.ScriptSetPhysicsStatus(false);
478 string version = String.Empty;
479 Vector3 newpos = Vector3.Zero;
480 string failureReason = String.Empty;
481 OpenSim.Services.Interfaces.GridRegion destination = null;
482 577
483 if (m_rootPart.KeyframeMotion != null) 578 if (Scene != null)
484 m_rootPart.KeyframeMotion.StartCrossingCheck(); 579 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
580 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
485 581
486 bool canCross = true; 582 return;
487 foreach (ScenePresence av in GetSittingAvatars()) 583 }
488 { 584 }
489 // We need to cross these agents. First, let's find
490 // out if any of them can't cross for some reason.
491 // We have to deny the crossing entirely if any
492 // of them are banned. Alternatively, we could
493 // unsit banned agents....
494 585
586 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
587 if (m_dupeInProgress || IsDeleted)
588 triggerScriptEvent = false;
495 589
496 // We set the avatar position as being the object 590 m_rootPart.GroupPosition = val;
497 // position to get the region to send to
498 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out version, out newpos, out failureReason)) == null)
499 {
500 canCross = false;
501 break;
502 }
503 591
504 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName); 592 // Restuff the new GroupPosition into each child SOP of the linkset.
505 } 593 // this is needed because physics may not have linksets but just loose SOPs in world
506 594
507 if (canCross) 595 SceneObjectPart[] parts = m_parts.GetArray();
508 {
509 // We unparent the SP quietly so that it won't
510 // be made to stand up
511 596
512 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>(); 597 foreach (SceneObjectPart part in parts)
598 {
599 if (part != m_rootPart)
600 part.GroupPosition = val;
601 }
513 602
514 foreach (ScenePresence av in GetSittingAvatars()) 603 foreach (ScenePresence av in m_linkedAvatars)
515 { 604 {
516 avtocrossInfo avinfo = new avtocrossInfo(); 605 av.sitSOGmoved();
517 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID); 606 }
518 if (parentPart != null)
519 av.ParentUUID = parentPart.UUID;
520 607
521 avinfo.av = av;
522 avinfo.ParentID = av.ParentID;
523 avsToCross.Add(avinfo);
524 608
525 av.PrevSitOffset = av.OffsetPosition; 609 // now that position is changed tell it to scripts
526 av.ParentID = 0; 610 if (triggerScriptEvent)
527 } 611 {
612 foreach (SceneObjectPart part in parts)
613 {
614 part.TriggerScriptChangedEvent(Changed.POSITION);
615 }
616 }
528 617
529 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 618 if (Scene != null)
619 Scene.EventManager.TriggerParcelPrimCountTainted();
530 620
531 // Normalize 621 }
532 if (val.X >= m_scene.RegionInfo.RegionSizeX) 622 }
533 val.X -= m_scene.RegionInfo.RegionSizeX;
534 if (val.Y >= m_scene.RegionInfo.RegionSizeY)
535 val.Y -= m_scene.RegionInfo.RegionSizeY;
536 if (val.X < 0)
537 val.X += m_scene.RegionInfo.RegionSizeX;
538 if (val.Y < 0)
539 val.Y += m_scene.RegionInfo.RegionSizeY;
540 623
541 // If it's deleted, crossing was successful 624 public SceneObjectGroup CrossAsync(SceneObjectGroup sog, Vector3 val)
542 if (IsDeleted) 625 {
543 { 626 Scene sogScene = sog.m_scene;
544 foreach (avtocrossInfo avinfo in avsToCross) 627 IEntityTransferModule entityTransfer = sogScene.RequestModuleInterface<IEntityTransferModule>();
545 {
546 ScenePresence av = avinfo.av;
547 if (!av.IsInTransit) // just in case...
548 {
549 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
550
551 av.IsInTransit = true;
552
553 // A temporary measure to allow regression tests to work.
554 // Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget
555 // or similar since BeginInvoke() always uses the system threadpool to launch
556 // threads rather than any replace threadpool that we might be using.
557 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
558 {
559 entityTransfer.CrossAgentToNewRegionAsync(av, val, destination, av.Flying, version);
560 CrossAgentToNewRegionCompleted(av);
561 }
562 else
563 {
564 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
565 d.BeginInvoke(
566 av, val, destination, av.Flying, version,
567 ar => CrossAgentToNewRegionCompleted(d.EndInvoke(ar)), null);
568 }
569 }
570 else
571 {
572 m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val);
573 }
574 }
575 628
576 return; 629 Vector3 newpos = Vector3.Zero;
577 } 630 OpenSim.Services.Interfaces.GridRegion destination = null;
578 else // cross failed, put avas back ??
579 {
580 foreach (avtocrossInfo avinfo in avsToCross)
581 {
582 ScenePresence av = avinfo.av;
583 av.ParentUUID = UUID.Zero;
584 av.ParentID = avinfo.ParentID;
585 }
586 }
587 }
588 else
589 {
590 if (m_rootPart.KeyframeMotion != null)
591 m_rootPart.KeyframeMotion.CrossingFailure();
592 631
593 if (RootPart.PhysActor != null) 632 if (sog.RootPart.DIE_AT_EDGE)
633 {
634 try
635 {
636 sogScene.DeleteSceneObject(sog, false);
637 }
638 catch (Exception)
639 {
640 m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border.");
641 }
642 return sog;
643 }
644
645 if (sog.RootPart.RETURN_AT_EDGE)
646 {
647 // We remove the object here
648 try
649 {
650 List<uint> localIDs = new List<uint>();
651 localIDs.Add(sog.RootPart.LocalId);
652 sogScene.AddReturn(sog.OwnerID, sog.Name, sog.AbsolutePosition,
653 "Returned at region cross");
654 sogScene.DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, UUID.Zero);
655 }
656 catch (Exception)
657 {
658 m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border.");
659 }
660 return sog;
661 }
662
663 if (sog.m_rootPart.KeyframeMotion != null)
664 sog.m_rootPart.KeyframeMotion.StartCrossingCheck();
665
666 if (entityTransfer == null)
667 return sog;
668
669 destination = entityTransfer.GetObjectDestination(sog, val, out newpos);
670 if (destination == null)
671 return sog;
672
673 if (sog.m_linkedAvatars.Count == 0)
674 {
675 entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true);
676 return sog;
677 }
678
679 string reason = String.Empty;
680 string version = String.Empty;
681
682 foreach (ScenePresence av in sog.m_linkedAvatars)
683 {
684 // We need to cross these agents. First, let's find
685 // out if any of them can't cross for some reason.
686 // We have to deny the crossing entirely if any
687 // of them are banned. Alternatively, we could
688 // unsit banned agents....
689
690 // We set the avatar position as being the object
691 // position to get the region to send to
692 if(!entityTransfer.checkAgentAccessToRegion(av, destination, newpos, out version, out reason))
693 {
694 return sog;
695 }
696 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
697 }
698
699 // We unparent the SP quietly so that it won't
700 // be made to stand up
701
702 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
703
704 foreach (ScenePresence av in sog.m_linkedAvatars)
705 {
706 avtocrossInfo avinfo = new avtocrossInfo();
707 SceneObjectPart parentPart = sogScene.GetSceneObjectPart(av.ParentID);
708 if (parentPart != null)
709 av.ParentUUID = parentPart.UUID;
710
711 avinfo.av = av;
712 avinfo.ParentID = av.ParentID;
713 avsToCross.Add(avinfo);
714
715 av.PrevSitOffset = av.OffsetPosition;
716 av.ParentID = 0;
717 }
718
719 if (entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true))
720 {
721 foreach (avtocrossInfo avinfo in avsToCross)
722 {
723 ScenePresence av = avinfo.av;
724 if (!av.IsInTransit) // just in case...
725 {
726 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
727
728 av.IsInTransit = true;
729
730// CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
731// d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
732 entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, av.Flying, version);
733 if(av.IsChildAgent)
734 {
735 if (av.ParentUUID != UUID.Zero)
594 { 736 {
595 RootPart.PhysActor.CrossingFailure(); 737 av.ClearControls();
738 av.ParentPart = null;
596 } 739 }
597 } 740 }
741 av.ParentUUID = UUID.Zero;
742 // In any case
743 av.IsInTransit = false;
598 744
599 Vector3 oldp = AbsolutePosition; 745 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname);
600 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f);
601 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f);
602 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, Constants.RegionHeight);
603 } 746 }
747 else
748 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar already in transit {0} to {1}", av.Name, val);
604 } 749 }
605 750 avsToCross.Clear();
606 if (RootPart.GetStatusSandbox()) 751 return sog;
752 }
753 else // cross failed, put avas back ??
754 {
755 foreach (avtocrossInfo avinfo in avsToCross)
607 { 756 {
608 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 757 ScenePresence av = avinfo.av;
609 { 758 av.ParentUUID = UUID.Zero;
610 RootPart.ScriptSetPhysicsStatus(false); 759 av.ParentID = avinfo.ParentID;
611
612 if (Scene != null)
613 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
614 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
615
616 return;
617 }
618 } 760 }
619
620 // Restuff the new GroupPosition into each SOP of the linkset.
621 // This has the affect of resetting and tainting the physics actors.
622 SceneObjectPart[] parts = m_parts.GetArray();
623 for (int i = 0; i < parts.Length; i++)
624 parts[i].GroupPosition = val;
625
626 //if (m_rootPart.PhysActor != null)
627 //{
628 //m_rootPart.PhysActor.Position =
629 //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y,
630 //m_rootPart.GroupPosition.Z);
631 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
632 //}
633
634 if (Scene != null)
635 Scene.EventManager.TriggerParcelPrimCountTainted();
636 } 761 }
762 avsToCross.Clear();
763
764 return sog;
637 } 765 }
638 766
639 public override Vector3 Velocity 767 public void CrossAsyncCompleted(IAsyncResult iar)
640 { 768 {
641 get { return RootPart.Velocity; } 769 SOGCrossDelegate icon = (SOGCrossDelegate)iar.AsyncState;
642 set { RootPart.Velocity = value; } 770 SceneObjectGroup sog = icon.EndInvoke(iar);
771
772 if (!sog.IsDeleted)
773 {
774 SceneObjectPart rootp = sog.m_rootPart;
775 Vector3 oldp = rootp.GroupPosition;
776 oldp.X = Util.Clamp<float>(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f);
777 oldp.Y = Util.Clamp<float>(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f);
778 rootp.GroupPosition = oldp;
779
780 SceneObjectPart[] parts = sog.m_parts.GetArray();
781
782 foreach (SceneObjectPart part in parts)
783 {
784 if (part != rootp)
785 part.GroupPosition = oldp;
786 }
787
788 foreach (ScenePresence av in sog.m_linkedAvatars)
789 {
790 av.sitSOGmoved();
791 }
792
793 sog.Velocity = Vector3.Zero;
794
795 if (sog.m_rootPart.KeyframeMotion != null)
796 sog.m_rootPart.KeyframeMotion.CrossingFailure();
797
798 if (sog.RootPart.PhysActor != null)
799 {
800 sog.RootPart.PhysActor.CrossingFailure();
801 }
802
803 sog.inTransit = false;
804 sog.ScheduleGroupForFullUpdate();
805 }
643 } 806 }
644 807
645 private void CrossAgentToNewRegionCompleted(ScenePresence agent) 808 private void CrossAgentToNewRegionCompleted(ScenePresence agent)
@@ -649,6 +812,7 @@ namespace OpenSim.Region.Framework.Scenes
649 { 812 {
650 if (agent.ParentUUID != UUID.Zero) 813 if (agent.ParentUUID != UUID.Zero)
651 { 814 {
815 agent.HandleForceReleaseControls(agent.ControllingClient,agent.UUID);
652 agent.ParentPart = null; 816 agent.ParentPart = null;
653// agent.ParentPosition = Vector3.Zero; 817// agent.ParentPosition = Vector3.Zero;
654// agent.ParentUUID = UUID.Zero; 818// agent.ParentUUID = UUID.Zero;
@@ -666,6 +830,12 @@ namespace OpenSim.Region.Framework.Scenes
666 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); 830 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
667 } 831 }
668 832
833 public override Vector3 Velocity
834 {
835 get { return RootPart.Velocity; }
836 set { RootPart.Velocity = value; }
837 }
838
669 public override uint LocalId 839 public override uint LocalId
670 { 840 {
671 get { return m_rootPart.LocalId; } 841 get { return m_rootPart.LocalId; }
@@ -740,6 +910,11 @@ namespace OpenSim.Region.Framework.Scenes
740 m_isSelected = value; 910 m_isSelected = value;
741 // Tell physics engine that group is selected 911 // Tell physics engine that group is selected
742 912
913 // this is not right
914 // but ode engines should only really need to know about root part
915 // so they can put entire object simulation on hold and not colliding
916 // keep as was for now
917
743 PhysicsActor pa = m_rootPart.PhysActor; 918 PhysicsActor pa = m_rootPart.PhysActor;
744 if (pa != null) 919 if (pa != null)
745 { 920 {
@@ -761,13 +936,47 @@ namespace OpenSim.Region.Framework.Scenes
761 } 936 }
762 } 937 }
763 938
939 public void PartSelectChanged(bool partSelect)
940 {
941 // any part selected makes group selected
942 if (m_isSelected == partSelect)
943 return;
944
945 if (partSelect)
946 {
947 IsSelected = partSelect;
948// if (!IsAttachment)
949// ScheduleGroupForFullUpdate();
950 }
951 else
952 {
953 // bad bad bad 2 heavy for large linksets
954 // since viewer does send lot of (un)selects
955 // this needs to be replaced by a specific list or count ?
956 // but that will require extra code in several places
957
958 SceneObjectPart[] parts = m_parts.GetArray();
959 for (int i = 0; i < parts.Length; i++)
960 {
961 SceneObjectPart part = parts[i];
962 if (part.IsSelected)
963 return;
964 }
965 IsSelected = partSelect;
966// if (!IsAttachment)
967// {
968// ScheduleGroupForFullUpdate();
969// }
970 }
971 }
972 // PlaySoundMasterPrim no longer in use to remove
764 private SceneObjectPart m_PlaySoundMasterPrim = null; 973 private SceneObjectPart m_PlaySoundMasterPrim = null;
765 public SceneObjectPart PlaySoundMasterPrim 974 public SceneObjectPart PlaySoundMasterPrim
766 { 975 {
767 get { return m_PlaySoundMasterPrim; } 976 get { return m_PlaySoundMasterPrim; }
768 set { m_PlaySoundMasterPrim = value; } 977 set { m_PlaySoundMasterPrim = value; }
769 } 978 }
770 979 // PlaySoundSlavePrims no longer in use to remove
771 private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>(); 980 private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>();
772 public List<SceneObjectPart> PlaySoundSlavePrims 981 public List<SceneObjectPart> PlaySoundSlavePrims
773 { 982 {
@@ -775,6 +984,7 @@ namespace OpenSim.Region.Framework.Scenes
775 set { m_PlaySoundSlavePrims = value; } 984 set { m_PlaySoundSlavePrims = value; }
776 } 985 }
777 986
987 // LoopSoundMasterPrim no longer in use to remove
778 private SceneObjectPart m_LoopSoundMasterPrim = null; 988 private SceneObjectPart m_LoopSoundMasterPrim = null;
779 public SceneObjectPart LoopSoundMasterPrim 989 public SceneObjectPart LoopSoundMasterPrim
780 { 990 {
@@ -782,6 +992,7 @@ namespace OpenSim.Region.Framework.Scenes
782 set { m_LoopSoundMasterPrim = value; } 992 set { m_LoopSoundMasterPrim = value; }
783 } 993 }
784 994
995 // m_LoopSoundSlavePrims no longer in use to remove
785 private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>(); 996 private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>();
786 public List<SceneObjectPart> LoopSoundSlavePrims 997 public List<SceneObjectPart> LoopSoundSlavePrims
787 { 998 {
@@ -844,7 +1055,7 @@ namespace OpenSim.Region.Framework.Scenes
844 /// No avatar should appear more than once in this list. 1055 /// No avatar should appear more than once in this list.
845 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart. 1056 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
846 /// </remarks> 1057 /// </remarks>
847 protected internal List<ScenePresence> m_sittingAvatars = new List<ScenePresence>(); 1058 protected internal List<UUID> m_sittingAvatars = new List<UUID>();
848 1059
849 #endregion 1060 #endregion
850 1061
@@ -861,6 +1072,7 @@ namespace OpenSim.Region.Framework.Scenes
861 /// </summary> 1072 /// </summary>
862 public SceneObjectGroup() 1073 public SceneObjectGroup()
863 { 1074 {
1075
864 } 1076 }
865 1077
866 /// <summary> 1078 /// <summary>
@@ -878,8 +1090,8 @@ namespace OpenSim.Region.Framework.Scenes
878 /// Constructor. This object is added to the scene later via AttachToScene() 1090 /// Constructor. This object is added to the scene later via AttachToScene()
879 /// </summary> 1091 /// </summary>
880 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 1092 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
881 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 1093 {
882 { 1094 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
883 } 1095 }
884 1096
885 /// <summary> 1097 /// <summary>
@@ -954,7 +1166,10 @@ namespace OpenSim.Region.Framework.Scenes
954 /// </summary> 1166 /// </summary>
955 public virtual void AttachToBackup() 1167 public virtual void AttachToBackup()
956 { 1168 {
957 if (CanBeBackedUp) 1169 if (IsAttachment) return;
1170 m_scene.SceneGraph.FireAttachToBackup(this);
1171
1172// if (InSceneBackup)
958 { 1173 {
959// m_log.DebugFormat( 1174// m_log.DebugFormat(
960// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID); 1175// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
@@ -1001,6 +1216,13 @@ namespace OpenSim.Region.Framework.Scenes
1001 1216
1002 ApplyPhysics(); 1217 ApplyPhysics();
1003 1218
1219 if (RootPart.PhysActor != null)
1220 RootPart.Force = RootPart.Force;
1221 if (RootPart.PhysActor != null)
1222 RootPart.Torque = RootPart.Torque;
1223 if (RootPart.PhysActor != null)
1224 RootPart.Buoyancy = RootPart.Buoyancy;
1225
1004 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 1226 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
1005 // for the same object with very different properties. The caller must schedule the update. 1227 // for the same object with very different properties. The caller must schedule the update.
1006 //ScheduleGroupForFullUpdate(); 1228 //ScheduleGroupForFullUpdate();
@@ -1016,6 +1238,10 @@ namespace OpenSim.Region.Framework.Scenes
1016 EntityIntersection result = new EntityIntersection(); 1238 EntityIntersection result = new EntityIntersection();
1017 1239
1018 SceneObjectPart[] parts = m_parts.GetArray(); 1240 SceneObjectPart[] parts = m_parts.GetArray();
1241
1242 // Find closest hit here
1243 float idist = float.MaxValue;
1244
1019 for (int i = 0; i < parts.Length; i++) 1245 for (int i = 0; i < parts.Length; i++)
1020 { 1246 {
1021 SceneObjectPart part = parts[i]; 1247 SceneObjectPart part = parts[i];
@@ -1030,11 +1256,6 @@ namespace OpenSim.Region.Framework.Scenes
1030 1256
1031 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1257 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
1032 1258
1033 // This may need to be updated to the maximum draw distance possible..
1034 // We might (and probably will) be checking for prim creation from other sims
1035 // when the camera crosses the border.
1036 float idist = Constants.RegionSize;
1037
1038 if (inter.HitTF) 1259 if (inter.HitTF)
1039 { 1260 {
1040 // We need to find the closest prim to return to the testcaller along the ray 1261 // We need to find the closest prim to return to the testcaller along the ray
@@ -1045,10 +1266,11 @@ namespace OpenSim.Region.Framework.Scenes
1045 result.obj = part; 1266 result.obj = part;
1046 result.normal = inter.normal; 1267 result.normal = inter.normal;
1047 result.distance = inter.distance; 1268 result.distance = inter.distance;
1269
1270 idist = inter.distance;
1048 } 1271 }
1049 } 1272 }
1050 } 1273 }
1051
1052 return result; 1274 return result;
1053 } 1275 }
1054 1276
@@ -1060,25 +1282,27 @@ namespace OpenSim.Region.Framework.Scenes
1060 /// <returns></returns> 1282 /// <returns></returns>
1061 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1283 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
1062 { 1284 {
1063 maxX = -256f; 1285 maxX = float.MinValue;
1064 maxY = -256f; 1286 maxY = float.MinValue;
1065 maxZ = -256f; 1287 maxZ = float.MinValue;
1066 minX = 10000f; 1288 minX = float.MaxValue;
1067 minY = 10000f; 1289 minY = float.MaxValue;
1068 minZ = 10000f; 1290 minZ = float.MaxValue;
1069 1291
1070 SceneObjectPart[] parts = m_parts.GetArray(); 1292 SceneObjectPart[] parts = m_parts.GetArray();
1071 for (int i = 0; i < parts.Length; i++) 1293 foreach (SceneObjectPart part in parts)
1072 { 1294 {
1073 SceneObjectPart part = parts[i];
1074
1075 Vector3 worldPos = part.GetWorldPosition(); 1295 Vector3 worldPos = part.GetWorldPosition();
1076 Vector3 offset = worldPos - AbsolutePosition; 1296 Vector3 offset = worldPos - AbsolutePosition;
1077 Quaternion worldRot; 1297 Quaternion worldRot;
1078 if (part.ParentID == 0) 1298 if (part.ParentID == 0)
1299 {
1079 worldRot = part.RotationOffset; 1300 worldRot = part.RotationOffset;
1301 }
1080 else 1302 else
1303 {
1081 worldRot = part.GetWorldRotation(); 1304 worldRot = part.GetWorldRotation();
1305 }
1082 1306
1083 Vector3 frontTopLeft; 1307 Vector3 frontTopLeft;
1084 Vector3 frontTopRight; 1308 Vector3 frontTopRight;
@@ -1090,6 +1314,8 @@ namespace OpenSim.Region.Framework.Scenes
1090 Vector3 backBottomLeft; 1314 Vector3 backBottomLeft;
1091 Vector3 backBottomRight; 1315 Vector3 backBottomRight;
1092 1316
1317 // Vector3[] corners = new Vector3[8];
1318
1093 Vector3 orig = Vector3.Zero; 1319 Vector3 orig = Vector3.Zero;
1094 1320
1095 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1321 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -1124,6 +1350,38 @@ namespace OpenSim.Region.Framework.Scenes
1124 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1350 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
1125 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1351 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
1126 1352
1353
1354
1355 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1356 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1357 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1358 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1359 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1360 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1361 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1362 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1363
1364 //for (int i = 0; i < 8; i++)
1365 //{
1366 // corners[i] = corners[i] * worldRot;
1367 // corners[i] += offset;
1368
1369 // if (corners[i].X > maxX)
1370 // maxX = corners[i].X;
1371 // if (corners[i].X < minX)
1372 // minX = corners[i].X;
1373
1374 // if (corners[i].Y > maxY)
1375 // maxY = corners[i].Y;
1376 // if (corners[i].Y < minY)
1377 // minY = corners[i].Y;
1378
1379 // if (corners[i].Z > maxZ)
1380 // maxZ = corners[i].Y;
1381 // if (corners[i].Z < minZ)
1382 // minZ = corners[i].Z;
1383 //}
1384
1127 frontTopLeft = frontTopLeft * worldRot; 1385 frontTopLeft = frontTopLeft * worldRot;
1128 frontTopRight = frontTopRight * worldRot; 1386 frontTopRight = frontTopRight * worldRot;
1129 frontBottomLeft = frontBottomLeft * worldRot; 1387 frontBottomLeft = frontBottomLeft * worldRot;
@@ -1145,6 +1403,15 @@ namespace OpenSim.Region.Framework.Scenes
1145 backTopLeft += offset; 1403 backTopLeft += offset;
1146 backTopRight += offset; 1404 backTopRight += offset;
1147 1405
1406 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1407 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1408 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1409 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1410 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1411 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1412 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1413 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1414
1148 if (frontTopRight.X > maxX) 1415 if (frontTopRight.X > maxX)
1149 maxX = frontTopRight.X; 1416 maxX = frontTopRight.X;
1150 if (frontTopLeft.X > maxX) 1417 if (frontTopLeft.X > maxX)
@@ -1288,17 +1555,118 @@ namespace OpenSim.Region.Framework.Scenes
1288 1555
1289 #endregion 1556 #endregion
1290 1557
1558 public void GetResourcesCosts(SceneObjectPart apart,
1559 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1560 {
1561 // this information may need to be cached
1562
1563 float cost;
1564 float tmpcost;
1565
1566 bool ComplexCost = false;
1567
1568 SceneObjectPart p;
1569 SceneObjectPart[] parts;
1570
1571 lock (m_parts)
1572 {
1573 parts = m_parts.GetArray();
1574 }
1575
1576 int nparts = parts.Length;
1577
1578
1579 for (int i = 0; i < nparts; i++)
1580 {
1581 p = parts[i];
1582
1583 if (p.UsesComplexCost)
1584 {
1585 ComplexCost = true;
1586 break;
1587 }
1588 }
1589
1590 if (ComplexCost)
1591 {
1592 linksetResCost = 0;
1593 linksetPhysCost = 0;
1594 partCost = 0;
1595 partPhysCost = 0;
1596
1597 for (int i = 0; i < nparts; i++)
1598 {
1599 p = parts[i];
1600
1601 cost = p.StreamingCost;
1602 tmpcost = p.SimulationCost;
1603 if (tmpcost > cost)
1604 cost = tmpcost;
1605 tmpcost = p.PhysicsCost;
1606 if (tmpcost > cost)
1607 cost = tmpcost;
1608
1609 linksetPhysCost += tmpcost;
1610 linksetResCost += cost;
1611
1612 if (p == apart)
1613 {
1614 partCost = cost;
1615 partPhysCost = tmpcost;
1616 }
1617 }
1618 }
1619 else
1620 {
1621 partPhysCost = 1.0f;
1622 partCost = 1.0f;
1623 linksetResCost = (float)nparts;
1624 linksetPhysCost = linksetResCost;
1625 }
1626 }
1627
1628 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1629 {
1630 SceneObjectPart p;
1631 SceneObjectPart[] parts;
1632
1633 lock (m_parts)
1634 {
1635 parts = m_parts.GetArray();
1636 }
1637
1638 int nparts = parts.Length;
1639
1640 PhysCost = 0;
1641 StreamCost = 0;
1642 SimulCost = 0;
1643
1644 for (int i = 0; i < nparts; i++)
1645 {
1646 p = parts[i];
1647
1648 StreamCost += p.StreamingCost;
1649 SimulCost += p.SimulationCost;
1650 PhysCost += p.PhysicsCost;
1651 }
1652 }
1653
1291 public void SaveScriptedState(XmlTextWriter writer) 1654 public void SaveScriptedState(XmlTextWriter writer)
1292 { 1655 {
1656 SaveScriptedState(writer, false);
1657 }
1658
1659 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1660 {
1293 XmlDocument doc = new XmlDocument(); 1661 XmlDocument doc = new XmlDocument();
1294 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1662 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1295 1663
1296 SceneObjectPart[] parts = m_parts.GetArray(); 1664 SceneObjectPart[] parts = m_parts.GetArray();
1297 for (int i = 0; i < parts.Length; i++) 1665 for (int i = 0; i < parts.Length; i++)
1298 { 1666 {
1299 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 1667 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1300 foreach (KeyValuePair<UUID, string> kvp in pstates) 1668 foreach (KeyValuePair<UUID, string> kvp in pstates)
1301 states.Add(kvp.Key, kvp.Value); 1669 states[kvp.Key] = kvp.Value;
1302 } 1670 }
1303 1671
1304 if (states.Count > 0) 1672 if (states.Count > 0)
@@ -1317,6 +1685,171 @@ namespace OpenSim.Region.Framework.Scenes
1317 } 1685 }
1318 } 1686 }
1319 1687
1688 /// <summary>
1689 /// Add the avatar to this linkset (avatar is sat).
1690 /// </summary>
1691 /// <param name="agentID"></param>
1692 public void AddAvatar(UUID agentID)
1693 {
1694 ScenePresence presence;
1695 if (m_scene.TryGetScenePresence(agentID, out presence))
1696 {
1697 if (!m_linkedAvatars.Contains(presence))
1698 {
1699 m_linkedAvatars.Add(presence);
1700 }
1701 }
1702 }
1703
1704 /// <summary>
1705 /// Delete the avatar from this linkset (avatar is unsat).
1706 /// </summary>
1707 /// <param name="agentID"></param>
1708 public void DeleteAvatar(UUID agentID)
1709 {
1710 ScenePresence presence;
1711 if (m_scene.TryGetScenePresence(agentID, out presence))
1712 {
1713 if (m_linkedAvatars.Contains(presence))
1714 {
1715 m_linkedAvatars.Remove(presence);
1716 }
1717 }
1718 }
1719
1720 /// <summary>
1721 /// Returns the list of linked presences (avatars sat on this group)
1722 /// </summary>
1723 /// <param name="agentID"></param>
1724 public List<ScenePresence> GetLinkedAvatars()
1725 {
1726 return m_linkedAvatars;
1727 }
1728
1729 /// <summary>
1730 /// Attach this scene object to the given avatar.
1731 /// </summary>
1732 /// <param name="agentID"></param>
1733 /// <param name="attachmentpoint"></param>
1734 /// <param name="AttachOffset"></param>
1735 private void AttachToAgent(
1736 ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1737 {
1738 if (avatar != null)
1739 {
1740 // don't attach attachments to child agents
1741 if (avatar.IsChildAgent) return;
1742
1743 // Remove from database and parcel prim count
1744 m_scene.DeleteFromStorage(so.UUID);
1745 m_scene.EventManager.TriggerParcelPrimCountTainted();
1746
1747 so.AttachedAvatar = avatar.UUID;
1748
1749 if (so.RootPart.PhysActor != null)
1750 {
1751 m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1752 so.RootPart.PhysActor = null;
1753 }
1754
1755 so.AbsolutePosition = attachOffset;
1756 so.RootPart.AttachedPos = attachOffset;
1757 so.IsAttachment = true;
1758 so.RootPart.SetParentLocalId(avatar.LocalId);
1759 so.AttachmentPoint = attachmentpoint;
1760
1761 avatar.AddAttachment(this);
1762
1763 if (!silent)
1764 {
1765 // Killing it here will cause the client to deselect it
1766 // It then reappears on the avatar, deselected
1767 // through the full update below
1768 //
1769 if (IsSelected)
1770 {
1771 m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1772 }
1773
1774 IsSelected = false; // fudge....
1775 ScheduleGroupForFullUpdate();
1776 }
1777 }
1778 else
1779 {
1780 m_log.WarnFormat(
1781 "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1782 UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1783 }
1784 }
1785
1786 public byte GetAttachmentPoint()
1787 {
1788 return m_rootPart.Shape.State;
1789 }
1790
1791 public void DetachToGround()
1792 {
1793 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1794 if (avatar == null)
1795 return;
1796 m_rootPart.Shape.LastAttachPoint = m_rootPart.Shape.State;
1797 m_rootPart.AttachedPos = m_rootPart.OffsetPosition;
1798 avatar.RemoveAttachment(this);
1799
1800 Vector3 detachedpos = new Vector3(127f,127f,127f);
1801 if (avatar == null)
1802 return;
1803
1804 detachedpos = avatar.AbsolutePosition;
1805 FromItemID = UUID.Zero;
1806
1807 AbsolutePosition = detachedpos;
1808 AttachedAvatar = UUID.Zero;
1809
1810 //SceneObjectPart[] parts = m_parts.GetArray();
1811 //for (int i = 0; i < parts.Length; i++)
1812 // parts[i].AttachedAvatar = UUID.Zero;
1813
1814 m_rootPart.SetParentLocalId(0);
1815 AttachmentPoint = (byte)0;
1816 // must check if buildind should be true or false here
1817// m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1818 ApplyPhysics();
1819
1820 HasGroupChanged = true;
1821 RootPart.Rezzed = DateTime.Now;
1822 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1823 AttachToBackup();
1824 m_scene.EventManager.TriggerParcelPrimCountTainted();
1825 m_rootPart.ScheduleFullUpdate();
1826 m_rootPart.ClearUndoState();
1827 }
1828
1829 public void DetachToInventoryPrep()
1830 {
1831 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1832 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1833 if (avatar != null)
1834 {
1835 //detachedpos = avatar.AbsolutePosition;
1836 avatar.RemoveAttachment(this);
1837 }
1838
1839 AttachedAvatar = UUID.Zero;
1840
1841 /*SceneObjectPart[] parts = m_parts.GetArray();
1842 for (int i = 0; i < parts.Length; i++)
1843 parts[i].AttachedAvatar = UUID.Zero;*/
1844
1845 m_rootPart.SetParentLocalId(0);
1846 //m_rootPart.SetAttachmentPoint((byte)0);
1847 IsAttachment = false;
1848 AbsolutePosition = m_rootPart.AttachedPos;
1849 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1850 //AttachToBackup();
1851 //m_rootPart.ScheduleFullUpdate();
1852 }
1320 1853
1321 /// <summary> 1854 /// <summary>
1322 /// 1855 ///
@@ -1358,7 +1891,10 @@ namespace OpenSim.Region.Framework.Scenes
1358 public void AddPart(SceneObjectPart part) 1891 public void AddPart(SceneObjectPart part)
1359 { 1892 {
1360 part.SetParent(this); 1893 part.SetParent(this);
1361 part.LinkNum = m_parts.Add(part.UUID, part); 1894 m_parts.Add(part.UUID, part);
1895
1896 part.LinkNum = m_parts.Count;
1897
1362 if (part.LinkNum == 2) 1898 if (part.LinkNum == 2)
1363 RootPart.LinkNum = 1; 1899 RootPart.LinkNum = 1;
1364 } 1900 }
@@ -1384,6 +1920,14 @@ namespace OpenSim.Region.Framework.Scenes
1384 parts[i].UUID = UUID.Random(); 1920 parts[i].UUID = UUID.Random();
1385 } 1921 }
1386 1922
1923 // helper provided for parts.
1924 public int GetSceneMaxUndo()
1925 {
1926 if (m_scene != null)
1927 return m_scene.MaxUndoCount;
1928 return 5;
1929 }
1930
1387 // justincc: I don't believe this hack is needed any longer, especially since the physics 1931 // justincc: I don't believe this hack is needed any longer, especially since the physics
1388 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 1932 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1389 // this method was preventing proper reload of scene objects. 1933 // this method was preventing proper reload of scene objects.
@@ -1405,11 +1949,21 @@ namespace OpenSim.Region.Framework.Scenes
1405 // Setting this SOG's absolute position also loops through and sets the positions 1949 // Setting this SOG's absolute position also loops through and sets the positions
1406 // of the SOP's in this SOG's linkset. This has the side affect of making sure 1950 // of the SOP's in this SOG's linkset. This has the side affect of making sure
1407 // the physics world matches the simulated world. 1951 // the physics world matches the simulated world.
1408 AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? 1952 // AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
1409 1953
1410 // teravus: AbsolutePosition is NOT a normal property! 1954 // teravus: AbsolutePosition is NOT a normal property!
1411 // the code in the getter of AbsolutePosition is significantly different then the code in the setter! 1955 // the code in the getter of AbsolutePosition is significantly different then the code in the setter!
1412 // jhurliman: Then why is it a property instead of two methods? 1956 // jhurliman: Then why is it a property instead of two methods?
1957
1958 // do only what is supposed to do
1959 Vector3 groupPosition = m_rootPart.GroupPosition;
1960 SceneObjectPart[] parts = m_parts.GetArray();
1961
1962 foreach (SceneObjectPart part in parts)
1963 {
1964 if (part != m_rootPart)
1965 part.GroupPosition = groupPosition;
1966 }
1413 } 1967 }
1414 1968
1415 public UUID GetPartsFullID(uint localID) 1969 public UUID GetPartsFullID(uint localID)
@@ -1441,7 +1995,7 @@ namespace OpenSim.Region.Framework.Scenes
1441// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 1995// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1442// remoteClient.Name, part.Name, part.LocalId, offsetPos); 1996// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1443 1997
1444 part.StoreUndoState(); 1998// part.StoreUndoState();
1445 part.OnGrab(offsetPos, remoteClient); 1999 part.OnGrab(offsetPos, remoteClient);
1446 } 2000 }
1447 2001
@@ -1461,28 +2015,36 @@ namespace OpenSim.Region.Framework.Scenes
1461 /// <param name="silent">If true then deletion is not broadcast to clients</param> 2015 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1462 public void DeleteGroupFromScene(bool silent) 2016 public void DeleteGroupFromScene(bool silent)
1463 { 2017 {
2018 // We need to keep track of this state in case this group is still queued for backup.
2019 IsDeleted = true;
2020
2021 DetachFromBackup();
2022
1464 SceneObjectPart[] parts = m_parts.GetArray(); 2023 SceneObjectPart[] parts = m_parts.GetArray();
1465 for (int i = 0; i < parts.Length; i++) 2024 for (int i = 0; i < parts.Length; i++)
1466 { 2025 {
1467 SceneObjectPart part = parts[i]; 2026 SceneObjectPart part = parts[i];
1468 2027
1469 Scene.ForEachScenePresence(sp => 2028 if (Scene != null)
1470 { 2029 {
1471 if (!sp.IsChildAgent && sp.ParentID == part.LocalId) 2030 Scene.ForEachRootScenePresence(delegate(ScenePresence avatar)
1472 sp.StandUp();
1473
1474 if (!silent)
1475 { 2031 {
1476 part.ClearUpdateSchedule(); 2032 if (avatar.ParentID == LocalId)
1477 if (part == m_rootPart) 2033 avatar.StandUp();
2034
2035 if (!silent)
1478 { 2036 {
1479 if (!IsAttachment 2037 part.ClearUpdateSchedule();
1480 || AttachedAvatar == sp.UUID 2038 if (part == m_rootPart)
1481 || !HasPrivateAttachmentPoint) 2039 {
1482 sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId }); 2040 if (!IsAttachment
2041 || AttachedAvatar == avatar.ControllingClient.AgentId
2042 || !HasPrivateAttachmentPoint)
2043 avatar.ControllingClient.SendKillObject(new List<uint> { part.LocalId });
2044 }
1483 } 2045 }
1484 } 2046 });
1485 }); 2047 }
1486 } 2048 }
1487 } 2049 }
1488 2050
@@ -1553,28 +2115,43 @@ namespace OpenSim.Region.Framework.Scenes
1553 /// </summary> 2115 /// </summary>
1554 public void ApplyPhysics() 2116 public void ApplyPhysics()
1555 { 2117 {
1556 // Apply physics to the root prim
1557 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1558
1559 // Apply physics to child prims
1560 SceneObjectPart[] parts = m_parts.GetArray(); 2118 SceneObjectPart[] parts = m_parts.GetArray();
1561 if (parts.Length > 1) 2119 if (parts.Length > 1)
1562 { 2120 {
2121 ResetChildPrimPhysicsPositions();
2122
2123 // Apply physics to the root prim
2124 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
2125
2126
1563 for (int i = 0; i < parts.Length; i++) 2127 for (int i = 0; i < parts.Length; i++)
1564 { 2128 {
1565 SceneObjectPart part = parts[i]; 2129 SceneObjectPart part = parts[i];
1566 if (part.LocalId != m_rootPart.LocalId) 2130 if (part.LocalId != m_rootPart.LocalId)
1567 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 2131 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1568 } 2132 }
1569
1570 // Hack to get the physics scene geometries in the right spot 2133 // Hack to get the physics scene geometries in the right spot
1571 ResetChildPrimPhysicsPositions(); 2134// ResetChildPrimPhysicsPositions();
2135 if (m_rootPart.PhysActor != null)
2136 {
2137 m_rootPart.PhysActor.Building = false;
2138 }
2139 }
2140 else
2141 {
2142 // Apply physics to the root prim
2143 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1572 } 2144 }
1573 } 2145 }
1574 2146
1575 public void SetOwnerId(UUID userId) 2147 public void SetOwnerId(UUID userId)
1576 { 2148 {
1577 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 2149 ForEachPart(delegate(SceneObjectPart part)
2150 {
2151
2152 part.OwnerID = userId;
2153
2154 });
1578 } 2155 }
1579 2156
1580 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2157 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1599,18 +2176,24 @@ namespace OpenSim.Region.Framework.Scenes
1599 return; 2176 return;
1600 } 2177 }
1601 2178
1602 if (IsDeleted || UUID == UUID.Zero) 2179 if (IsDeleted || inTransit || UUID == UUID.Zero)
1603 { 2180 {
1604// m_log.DebugFormat( 2181// m_log.DebugFormat(
1605// "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID); 2182// "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID);
1606 return; 2183 return;
1607 } 2184 }
1608 2185
2186 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2187 return;
2188
1609 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2189 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1610 // any exception propogate upwards. 2190 // any exception propogate upwards.
1611 try 2191 try
1612 { 2192 {
1613 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2193 if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2194 !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2195 m_scene.LoadingPrims) // Land may not be valid yet
2196
1614 { 2197 {
1615 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2198 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1616 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2199 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1637,6 +2220,7 @@ namespace OpenSim.Region.Framework.Scenes
1637 } 2220 }
1638 } 2221 }
1639 } 2222 }
2223
1640 } 2224 }
1641 2225
1642 if (m_scene.UseBackup && HasGroupChanged) 2226 if (m_scene.UseBackup && HasGroupChanged)
@@ -1644,10 +2228,31 @@ namespace OpenSim.Region.Framework.Scenes
1644 // don't backup while it's selected or you're asking for changes mid stream. 2228 // don't backup while it's selected or you're asking for changes mid stream.
1645 if (isTimeToPersist() || forcedBackup) 2229 if (isTimeToPersist() || forcedBackup)
1646 { 2230 {
2231 if (m_rootPart.PhysActor != null &&
2232 (!m_rootPart.PhysActor.IsPhysical))
2233 {
2234 // Possible ghost prim
2235 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2236 {
2237 foreach (SceneObjectPart part in m_parts.GetArray())
2238 {
2239 // Re-set physics actor positions and
2240 // orientations
2241 part.GroupPosition = m_rootPart.GroupPosition;
2242 }
2243 }
2244 }
1647// m_log.DebugFormat( 2245// m_log.DebugFormat(
1648// "[SCENE]: Storing {0}, {1} in {2}", 2246// "[SCENE]: Storing {0}, {1} in {2}",
1649// Name, UUID, m_scene.RegionInfo.RegionName); 2247// Name, UUID, m_scene.RegionInfo.RegionName);
1650 2248
2249 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2250 {
2251 RootPart.Shape.LastAttachPoint = RootPart.Shape.State;
2252 RootPart.Shape.State = 0;
2253 ScheduleGroupForFullUpdate();
2254 }
2255
1651 SceneObjectGroup backup_group = Copy(false); 2256 SceneObjectGroup backup_group = Copy(false);
1652 backup_group.RootPart.Velocity = RootPart.Velocity; 2257 backup_group.RootPart.Velocity = RootPart.Velocity;
1653 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2258 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1657,13 +2262,22 @@ namespace OpenSim.Region.Framework.Scenes
1657 GroupContainsForeignPrims = false; 2262 GroupContainsForeignPrims = false;
1658 2263
1659 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2264 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2265
1660 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2266 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1661 2267
1662 backup_group.ForEachPart(delegate(SceneObjectPart part) 2268 backup_group.ForEachPart(delegate(SceneObjectPart part)
1663 { 2269 {
1664 part.Inventory.ProcessInventoryBackup(datastore); 2270 part.Inventory.ProcessInventoryBackup(datastore);
2271
2272 // take the change to delete things
2273 if(part.KeyframeMotion != null)
2274 {
2275 part.KeyframeMotion.Delete();
2276 part.KeyframeMotion = null;
2277 }
1665 }); 2278 });
1666 2279
2280
1667 backup_group = null; 2281 backup_group = null;
1668 } 2282 }
1669// else 2283// else
@@ -1713,26 +2327,30 @@ namespace OpenSim.Region.Framework.Scenes
1713 /// <returns></returns> 2327 /// <returns></returns>
1714 public SceneObjectGroup Copy(bool userExposed) 2328 public SceneObjectGroup Copy(bool userExposed)
1715 { 2329 {
1716 // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up 2330 m_dupeInProgress = true;
1717 // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator
1718 // but not between regions on different simulators). Really, all copying should be done explicitly.
1719 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2331 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1720 2332 dupe.m_isBackedUp = false;
1721 dupe.Backup = false;
1722 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2333 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1723 dupe.m_sittingAvatars = new List<ScenePresence>(); 2334
2335 dupe.inTransit = inTransit; // this shouldn't be needed TEST
2336
2337 // new group as no sitting avatars
2338 dupe.m_linkedAvatars = new List<ScenePresence>();
2339 dupe.m_sittingAvatars = new List<UUID>();
2340
1724 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2341 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1725 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2342 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2343
1726 2344
1727 if (userExposed) 2345 if (userExposed)
1728 dupe.m_rootPart.TrimPermissions(); 2346 dupe.m_rootPart.TrimPermissions();
1729 2347
1730 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2348 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1731 2349
1732 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2350 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1733 { 2351 {
1734 return p1.LinkNum.CompareTo(p2.LinkNum); 2352 return p1.LinkNum.CompareTo(p2.LinkNum);
1735 } 2353 }
1736 ); 2354 );
1737 2355
1738 foreach (SceneObjectPart part in partList) 2356 foreach (SceneObjectPart part in partList)
@@ -1742,43 +2360,56 @@ namespace OpenSim.Region.Framework.Scenes
1742 { 2360 {
1743 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2361 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1744 newPart.LinkNum = part.LinkNum; 2362 newPart.LinkNum = part.LinkNum;
1745 } 2363// if (userExposed)
2364 newPart.ParentID = dupe.m_rootPart.LocalId;
2365 }
1746 else 2366 else
1747 { 2367 {
1748 newPart = dupe.m_rootPart; 2368 newPart = dupe.m_rootPart;
1749 } 2369 }
2370/*
2371 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2372 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1750 2373
1751 // Need to duplicate the physics actor as well 2374 // Need to duplicate the physics actor as well
1752 PhysicsActor originalPartPa = part.PhysActor; 2375 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1753 if (originalPartPa != null && userExposed)
1754 { 2376 {
1755 PrimitiveBaseShape pbs = newPart.Shape; 2377 PrimitiveBaseShape pbs = newPart.Shape;
1756
1757 newPart.PhysActor 2378 newPart.PhysActor
1758 = m_scene.PhysicsScene.AddPrimShape( 2379 = m_scene.PhysicsScene.AddPrimShape(
1759 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2380 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1760 pbs, 2381 pbs,
1761 newPart.AbsolutePosition, 2382 newPart.AbsolutePosition,
1762 newPart.Scale, 2383 newPart.Scale,
1763 newPart.RotationOffset, 2384 newPart.GetWorldRotation(),
1764 originalPartPa.IsPhysical, 2385 isphys,
2386 isphan,
1765 newPart.LocalId); 2387 newPart.LocalId);
1766 2388
1767 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2389 newPart.DoPhysicsPropertyUpdate(isphys, true);
1768 } 2390 */
2391 if (userExposed)
2392 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2393// }
2394 // copy keyframemotion
1769 if (part.KeyframeMotion != null) 2395 if (part.KeyframeMotion != null)
1770 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); 2396 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1771 } 2397 }
1772 2398
1773 if (userExposed) 2399 if (userExposed)
1774 { 2400 {
1775 dupe.UpdateParentIDs(); 2401// done above dupe.UpdateParentIDs();
2402
2403 if (dupe.m_rootPart.PhysActor != null)
2404 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2405
1776 dupe.HasGroupChanged = true; 2406 dupe.HasGroupChanged = true;
1777 dupe.AttachToBackup(); 2407 dupe.AttachToBackup();
1778 2408
1779 ScheduleGroupForFullUpdate(); 2409 ScheduleGroupForFullUpdate();
1780 } 2410 }
1781 2411
2412 m_dupeInProgress = false;
1782 return dupe; 2413 return dupe;
1783 } 2414 }
1784 2415
@@ -1790,7 +2421,13 @@ namespace OpenSim.Region.Framework.Scenes
1790 /// <param name="cGroupID"></param> 2421 /// <param name="cGroupID"></param>
1791 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2422 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1792 { 2423 {
1793 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2424 SceneObjectPart newpart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed);
2425// SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2426// newpart.LocalId = m_scene.AllocateLocalId();
2427
2428 SetRootPart(newpart);
2429 if (userExposed)
2430 RootPart.Velocity = Vector3.Zero; // In case source is moving
1794 } 2431 }
1795 2432
1796 public void ScriptSetPhysicsStatus(bool usePhysics) 2433 public void ScriptSetPhysicsStatus(bool usePhysics)
@@ -1848,13 +2485,14 @@ namespace OpenSim.Region.Framework.Scenes
1848 2485
1849 if (pa != null) 2486 if (pa != null)
1850 { 2487 {
1851 pa.AddForce(impulse, true); 2488 // false to be applied as a impulse
2489 pa.AddForce(impulse, false);
1852 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2490 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1853 } 2491 }
1854 } 2492 }
1855 } 2493 }
1856 2494
1857 public void applyAngularImpulse(Vector3 impulse) 2495 public void ApplyAngularImpulse(Vector3 impulse)
1858 { 2496 {
1859 PhysicsActor pa = RootPart.PhysActor; 2497 PhysicsActor pa = RootPart.PhysActor;
1860 2498
@@ -1862,21 +2500,8 @@ namespace OpenSim.Region.Framework.Scenes
1862 { 2500 {
1863 if (!IsAttachment) 2501 if (!IsAttachment)
1864 { 2502 {
1865 pa.AddAngularForce(impulse, true); 2503 // false to be applied as a impulse
1866 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2504 pa.AddAngularForce(impulse, false);
1867 }
1868 }
1869 }
1870
1871 public void setAngularImpulse(Vector3 impulse)
1872 {
1873 PhysicsActor pa = RootPart.PhysActor;
1874
1875 if (pa != null)
1876 {
1877 if (!IsAttachment)
1878 {
1879 pa.Torque = impulse;
1880 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2505 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1881 } 2506 }
1882 } 2507 }
@@ -1884,20 +2509,10 @@ namespace OpenSim.Region.Framework.Scenes
1884 2509
1885 public Vector3 GetTorque() 2510 public Vector3 GetTorque()
1886 { 2511 {
1887 PhysicsActor pa = RootPart.PhysActor; 2512 return RootPart.Torque;
1888
1889 if (pa != null)
1890 {
1891 if (!IsAttachment)
1892 {
1893 Vector3 torque = pa.Torque;
1894 return torque;
1895 }
1896 }
1897
1898 return Vector3.Zero;
1899 } 2513 }
1900 2514
2515 // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
1901 public void MoveToTarget(Vector3 target, float tau) 2516 public void MoveToTarget(Vector3 target, float tau)
1902 { 2517 {
1903 if (IsAttachment) 2518 if (IsAttachment)
@@ -1927,21 +2542,61 @@ namespace OpenSim.Region.Framework.Scenes
1927 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); 2542 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1928 2543
1929 if (avatar != null) 2544 if (avatar != null)
2545 {
1930 avatar.ResetMoveToTarget(); 2546 avatar.ResetMoveToTarget();
2547 }
1931 } 2548 }
1932 else 2549 else
1933 { 2550 {
1934 PhysicsActor pa = RootPart.PhysActor; 2551 PhysicsActor pa = RootPart.PhysActor;
1935 2552
1936 if (pa != null && pa.PIDActive) 2553 if (pa != null)
1937 {
1938 pa.PIDActive = false; 2554 pa.PIDActive = false;
1939 2555
1940 ScheduleGroupForTerseUpdate(); 2556 RootPart.ScheduleTerseUpdate(); // send a stop information
2557 }
2558 }
2559
2560 public void rotLookAt(Quaternion target, float strength, float damping)
2561 {
2562 SceneObjectPart rootpart = m_rootPart;
2563 if (rootpart != null)
2564 {
2565 if (IsAttachment)
2566 {
2567 /*
2568 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
2569 if (avatar != null)
2570 {
2571 Rotate the Av?
2572 } */
2573 }
2574 else
2575 {
2576 if (rootpart.PhysActor != null)
2577 { // APID must be implemented in your physics system for this to function.
2578 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2579 rootpart.PhysActor.APIDStrength = strength;
2580 rootpart.PhysActor.APIDDamping = damping;
2581 rootpart.PhysActor.APIDActive = true;
2582 }
1941 } 2583 }
1942 } 2584 }
1943 } 2585 }
2586
2587 public void stopLookAt()
2588 {
2589 SceneObjectPart rootpart = m_rootPart;
2590 if (rootpart != null)
2591 {
2592 if (rootpart.PhysActor != null)
2593 { // APID must be implemented in your physics system for this to function.
2594 rootpart.PhysActor.APIDActive = false;
2595 }
2596 }
1944 2597
2598 }
2599
1945 /// <summary> 2600 /// <summary>
1946 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2601 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1947 /// </summary> 2602 /// </summary>
@@ -1958,7 +2613,7 @@ namespace OpenSim.Region.Framework.Scenes
1958 { 2613 {
1959 pa.PIDHoverHeight = height; 2614 pa.PIDHoverHeight = height;
1960 pa.PIDHoverType = hoverType; 2615 pa.PIDHoverType = hoverType;
1961 pa.PIDTau = tau; 2616 pa.PIDHoverTau = tau;
1962 pa.PIDHoverActive = true; 2617 pa.PIDHoverActive = true;
1963 } 2618 }
1964 else 2619 else
@@ -1999,6 +2654,9 @@ namespace OpenSim.Region.Framework.Scenes
1999 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2654 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
2000 { 2655 {
2001 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2656 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2657// SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2658// newPart.LocalId = m_scene.AllocateLocalId();
2659
2002 AddPart(newPart); 2660 AddPart(newPart);
2003 2661
2004 SetPartAsNonRoot(newPart); 2662 SetPartAsNonRoot(newPart);
@@ -2048,6 +2706,7 @@ namespace OpenSim.Region.Framework.Scenes
2048 2706
2049 #endregion 2707 #endregion
2050 2708
2709
2051 public override void Update() 2710 public override void Update()
2052 { 2711 {
2053 // Check that the group was not deleted before the scheduled update 2712 // Check that the group was not deleted before the scheduled update
@@ -2055,7 +2714,7 @@ namespace OpenSim.Region.Framework.Scenes
2055 // an object has been deleted from a scene before update was processed. 2714 // an object has been deleted from a scene before update was processed.
2056 // A more fundamental overhaul of the update mechanism is required to eliminate all 2715 // A more fundamental overhaul of the update mechanism is required to eliminate all
2057 // the race conditions. 2716 // the race conditions.
2058 if (IsDeleted) 2717 if (IsDeleted || inTransit)
2059 return; 2718 return;
2060 2719
2061 // Even temporary objects take part in physics (e.g. temp-on-rez bullets) 2720 // Even temporary objects take part in physics (e.g. temp-on-rez bullets)
@@ -2066,18 +2725,17 @@ namespace OpenSim.Region.Framework.Scenes
2066 // check to see if the physical position or rotation warrant an update. 2725 // check to see if the physical position or rotation warrant an update.
2067 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 2726 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
2068 { 2727 {
2069 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 2728 // rootpart SendScheduledUpdates will check if a update is needed
2070 2729 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2071 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) 2730 }
2072 {
2073 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2074 lastPhysGroupPos = AbsolutePosition;
2075 }
2076 2731
2077 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f)) 2732 if (IsAttachment)
2733 {
2734 ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
2735 if (sp != null)
2078 { 2736 {
2079 m_rootPart.UpdateFlag = UpdateRequired.TERSE; 2737 sp.SendAttachmentScheduleUpdate(this);
2080 lastPhysGroupRot = GroupRotation; 2738 return;
2081 } 2739 }
2082 } 2740 }
2083 2741
@@ -2137,20 +2795,30 @@ namespace OpenSim.Region.Framework.Scenes
2137 /// Immediately send a full update for this scene object. 2795 /// Immediately send a full update for this scene object.
2138 /// </summary> 2796 /// </summary>
2139 public void SendGroupFullUpdate() 2797 public void SendGroupFullUpdate()
2140 { 2798 {
2141 if (IsDeleted) 2799 if (IsDeleted)
2142 return; 2800 return;
2143 2801
2144// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 2802// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2145 2803
2146 RootPart.SendFullUpdateToAllClients(); 2804 if (IsAttachment)
2805 {
2806 ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
2807 if (sp != null)
2808 {
2809 sp.SendAttachmentUpdate(this,UpdateRequired.FULL);
2810 return;
2811 }
2812 }
2813
2814 RootPart.SendFullUpdateToAllClientsInternal();
2147 2815
2148 SceneObjectPart[] parts = m_parts.GetArray(); 2816 SceneObjectPart[] parts = m_parts.GetArray();
2149 for (int i = 0; i < parts.Length; i++) 2817 for (int i = 0; i < parts.Length; i++)
2150 { 2818 {
2151 SceneObjectPart part = parts[i]; 2819 SceneObjectPart part = parts[i];
2152 if (part != RootPart) 2820 if (part != RootPart)
2153 part.SendFullUpdateToAllClients(); 2821 part.SendFullUpdateToAllClientsInternal();
2154 } 2822 }
2155 } 2823 }
2156 2824
@@ -2162,7 +2830,7 @@ namespace OpenSim.Region.Framework.Scenes
2162 /// </summary> 2830 /// </summary>
2163 public void SendGroupRootTerseUpdate() 2831 public void SendGroupRootTerseUpdate()
2164 { 2832 {
2165 if (IsDeleted) 2833 if (IsDeleted || inTransit)
2166 return; 2834 return;
2167 2835
2168 RootPart.SendTerseUpdateToAllClients(); 2836 RootPart.SendTerseUpdateToAllClients();
@@ -2181,12 +2849,22 @@ namespace OpenSim.Region.Framework.Scenes
2181 /// </summary> 2849 /// </summary>
2182 public void SendGroupTerseUpdate() 2850 public void SendGroupTerseUpdate()
2183 { 2851 {
2184 if (IsDeleted) 2852 if (IsDeleted || inTransit)
2185 return; 2853 return;
2186 2854
2855 if (IsAttachment)
2856 {
2857 ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
2858 if (sp != null)
2859 {
2860 sp.SendAttachmentUpdate(this, UpdateRequired.TERSE);
2861 return;
2862 }
2863 }
2864
2187 SceneObjectPart[] parts = m_parts.GetArray(); 2865 SceneObjectPart[] parts = m_parts.GetArray();
2188 for (int i = 0; i < parts.Length; i++) 2866 for (int i = 0; i < parts.Length; i++)
2189 parts[i].SendTerseUpdateToAllClients(); 2867 parts[i].SendTerseUpdateToAllClientsInternal();
2190 } 2868 }
2191 2869
2192 /// <summary> 2870 /// <summary>
@@ -2294,9 +2972,41 @@ namespace OpenSim.Region.Framework.Scenes
2294 return; 2972 return;
2295 } 2973 }
2296 2974
2975 // physical prims count limit
2976 // not very eficient :(
2977
2978 if (UsesPhysics && m_scene.m_linksetPhysCapacity > 0 && (PrimCount + objectGroup.PrimCount) >
2979 m_scene.m_linksetPhysCapacity)
2980 {
2981 int cntr = 0;
2982 foreach (SceneObjectPart part in Parts)
2983 {
2984 if (part.PhysicsShapeType != (byte)PhysicsShapeType.None)
2985 cntr++;
2986 }
2987 foreach (SceneObjectPart part in objectGroup.Parts)
2988 {
2989 if (part.PhysicsShapeType != (byte)PhysicsShapeType.None)
2990 cntr++;
2991 }
2992
2993 if (cntr > m_scene.m_linksetPhysCapacity)
2994 {
2995 // cancel physics
2996 RootPart.Flags &= ~PrimFlags.Physics;
2997 ApplyPhysics();
2998 }
2999 }
3000
3001
2297 // 'linkPart' == the root of the group being linked into this group 3002 // 'linkPart' == the root of the group being linked into this group
2298 SceneObjectPart linkPart = objectGroup.m_rootPart; 3003 SceneObjectPart linkPart = objectGroup.m_rootPart;
2299 3004
3005 if (m_rootPart.PhysActor != null)
3006 m_rootPart.PhysActor.Building = true;
3007 if (linkPart.PhysActor != null)
3008 linkPart.PhysActor.Building = true;
3009
2300 // physics flags from group to be applied to linked parts 3010 // physics flags from group to be applied to linked parts
2301 bool grpusephys = UsesPhysics; 3011 bool grpusephys = UsesPhysics;
2302 bool grptemporary = IsTemporary; 3012 bool grptemporary = IsTemporary;
@@ -2313,22 +3023,24 @@ namespace OpenSim.Region.Framework.Scenes
2313 // First move the new group's root SOP's position to be relative to ours 3023 // First move the new group's root SOP's position to be relative to ours
2314 // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, 3024 // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not,
2315 // this code can be reordered to have a more logical flow.) 3025 // this code can be reordered to have a more logical flow.)
2316 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 3026 linkPart.setOffsetPosition(linkPart.GroupPosition - AbsolutePosition);
2317 // Assign the new parent to the root of the old group 3027 // Assign the new parent to the root of the old group
2318 linkPart.ParentID = m_rootPart.LocalId; 3028 linkPart.ParentID = m_rootPart.LocalId;
2319 // Now that it's a child, it's group position is our root position 3029 // Now that it's a child, it's group position is our root position
2320 linkPart.GroupPosition = AbsolutePosition; 3030 linkPart.setGroupPosition(AbsolutePosition);
2321 3031
2322 Vector3 axPos = linkPart.OffsetPosition;
2323 // Rotate the linking root SOP's position to be relative to the new root prim 3032 // Rotate the linking root SOP's position to be relative to the new root prim
2324 Quaternion parentRot = m_rootPart.RotationOffset; 3033 Quaternion parentRot = m_rootPart.RotationOffset;
2325 axPos *= Quaternion.Inverse(parentRot);
2326 linkPart.OffsetPosition = axPos;
2327 3034
2328 // Make the linking root SOP's rotation relative to the new root prim 3035 // Make the linking root SOP's rotation relative to the new root prim
2329 Quaternion oldRot = linkPart.RotationOffset; 3036 Quaternion oldRot = linkPart.RotationOffset;
2330 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3037 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2331 linkPart.RotationOffset = newRot; 3038 linkPart.setRotationOffset(newRot);
3039
3040 Vector3 axPos = linkPart.OffsetPosition;
3041 axPos *= Quaternion.Conjugate(parentRot);
3042 linkPart.OffsetPosition = axPos;
3043
2332 3044
2333 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 3045 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
2334 // Now that we know this SOG has at least two SOPs in it, the new root 3046 // Now that we know this SOG has at least two SOPs in it, the new root
@@ -2358,10 +3070,12 @@ namespace OpenSim.Region.Framework.Scenes
2358 m_parts.Add(linkPart.UUID, linkPart); 3070 m_parts.Add(linkPart.UUID, linkPart);
2359 3071
2360 linkPart.SetParent(this); 3072 linkPart.SetParent(this);
3073 m_scene.updateScenePartGroup(linkPart, this);
3074
2361 linkPart.CreateSelected = true; 3075 linkPart.CreateSelected = true;
2362 3076
2363 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 3077 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2364 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 3078 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2365 3079
2366 // If the added SOP is physical, also tell the physics engine about the link relationship. 3080 // If the added SOP is physical, also tell the physics engine about the link relationship.
2367 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 3081 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2371,6 +3085,7 @@ namespace OpenSim.Region.Framework.Scenes
2371 } 3085 }
2372 3086
2373 linkPart.LinkNum = linkNum++; 3087 linkPart.LinkNum = linkNum++;
3088 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2374 3089
2375 // Get a list of the SOP's in the old group in order of their linknum's. 3090 // Get a list of the SOP's in the old group in order of their linknum's.
2376 SceneObjectPart[] ogParts = objectGroup.Parts; 3091 SceneObjectPart[] ogParts = objectGroup.Parts;
@@ -2389,7 +3104,7 @@ namespace OpenSim.Region.Framework.Scenes
2389 3104
2390 // Update the physics flags for the newly added SOP 3105 // Update the physics flags for the newly added SOP
2391 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 3106 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2392 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 3107 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2393 3108
2394 // If the added SOP is physical, also tell the physics engine about the link relationship. 3109 // If the added SOP is physical, also tell the physics engine about the link relationship.
2395 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 3110 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2407,7 +3122,7 @@ namespace OpenSim.Region.Framework.Scenes
2407 objectGroup.IsDeleted = true; 3122 objectGroup.IsDeleted = true;
2408 3123
2409 objectGroup.m_parts.Clear(); 3124 objectGroup.m_parts.Clear();
2410 3125
2411 // Can't do this yet since backup still makes use of the root part without any synchronization 3126 // Can't do this yet since backup still makes use of the root part without any synchronization
2412// objectGroup.m_rootPart = null; 3127// objectGroup.m_rootPart = null;
2413 3128
@@ -2423,6 +3138,9 @@ namespace OpenSim.Region.Framework.Scenes
2423 // unmoved prims! 3138 // unmoved prims!
2424 ResetChildPrimPhysicsPositions(); 3139 ResetChildPrimPhysicsPositions();
2425 3140
3141 if (m_rootPart.PhysActor != null)
3142 m_rootPart.PhysActor.Building = false;
3143
2426 //HasGroupChanged = true; 3144 //HasGroupChanged = true;
2427 //ScheduleGroupForFullUpdate(); 3145 //ScheduleGroupForFullUpdate();
2428 } 3146 }
@@ -2490,7 +3208,10 @@ namespace OpenSim.Region.Framework.Scenes
2490// m_log.DebugFormat( 3208// m_log.DebugFormat(
2491// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3209// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2492// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3210// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2493 3211
3212 if (m_rootPart.PhysActor != null)
3213 m_rootPart.PhysActor.Building = true;
3214
2494 linkPart.ClearUndoState(); 3215 linkPart.ClearUndoState();
2495 3216
2496 Vector3 worldPos = linkPart.GetWorldPosition(); 3217 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2545,30 +3266,31 @@ namespace OpenSim.Region.Framework.Scenes
2545 linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; 3266 linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
2546 linkPart.OffsetPosition = new Vector3(0, 0, 0); 3267 linkPart.OffsetPosition = new Vector3(0, 0, 0);
2547 */ 3268 */
2548 linkPart.GroupPosition = worldPos; 3269 linkPart.setGroupPosition(worldPos);
2549 linkPart.OffsetPosition = Vector3.Zero; 3270 linkPart.setOffsetPosition(Vector3.Zero);
2550 linkPart.RotationOffset = worldRot; 3271 linkPart.setRotationOffset(worldRot);
2551 3272
2552 // Create a new SOG to go around this unlinked and unattached SOP 3273 // Create a new SOG to go around this unlinked and unattached SOP
2553 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); 3274 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
2554 3275
2555 m_scene.AddNewSceneObject(objectGroup, true); 3276 m_scene.AddNewSceneObject(objectGroup, true);
2556 3277
2557 if (sendEvents)
2558 linkPart.TriggerScriptChangedEvent(Changed.LINK);
2559
2560 linkPart.Rezzed = RootPart.Rezzed; 3278 linkPart.Rezzed = RootPart.Rezzed;
2561 3279
2562 // We must persist the delinked group to the database immediately, for safety. The problem 3280 // When we delete a group, we currently have to force persist to the database if the object id has changed
2563 // is that although in memory the new group has a new SceneGroupID, in the database it 3281 // (since delete works by deleting all rows which have a given object id)
2564 // still has the parent group's SceneGroupID (until the next backup). This means that if the 3282
2565 // parent group is deleted then the delinked group will also be deleted from the database. 3283 // this is as it seems to be in sl now
2566 // This problem will disappear if the region remains alive long enough for another backup, 3284 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2567 // since at that time the delinked group's new SceneGroupID will be written to the database. 3285 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2568 // But if the region crashes before that then the prims will be permanently gone, and this must 3286
2569 // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case 3287 if (m_rootPart.PhysActor != null)
2570 // because the delinked group doesn't know when the source group is deleted.) 3288 m_rootPart.PhysActor.Building = false;
2571 m_scene.ForceSceneObjectBackup(objectGroup); 3289
3290 objectGroup.HasGroupChangedDueToDelink = true;
3291
3292 if (sendEvents)
3293 linkPart.TriggerScriptChangedEvent(Changed.LINK);
2572 3294
2573 return objectGroup; 3295 return objectGroup;
2574 } 3296 }
@@ -2579,7 +3301,9 @@ namespace OpenSim.Region.Framework.Scenes
2579 /// <param name="objectGroup"></param> 3301 /// <param name="objectGroup"></param>
2580 public virtual void DetachFromBackup() 3302 public virtual void DetachFromBackup()
2581 { 3303 {
2582 if (Backup && Scene != null) 3304 if (m_scene != null)
3305 m_scene.SceneGraph.FireDetachFromBackup(this);
3306 if (m_isBackedUp && Scene != null)
2583 m_scene.EventManager.OnBackup -= ProcessBackup; 3307 m_scene.EventManager.OnBackup -= ProcessBackup;
2584 3308
2585 Backup = false; 3309 Backup = false;
@@ -2595,14 +3319,14 @@ namespace OpenSim.Region.Framework.Scenes
2595 Quaternion parentRot = oldGroupRotation; 3319 Quaternion parentRot = oldGroupRotation;
2596 Quaternion oldRot = part.RotationOffset; 3320 Quaternion oldRot = part.RotationOffset;
2597 3321
2598 // Move our position to not be relative to the old parent 3322 // Move our position in world
2599 Vector3 axPos = part.OffsetPosition; 3323 Vector3 axPos = part.OffsetPosition;
2600 axPos *= parentRot; 3324 axPos *= parentRot;
2601 part.OffsetPosition = axPos; 3325 Vector3 newPos = oldGroupPosition + axPos;
2602 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3326 part.setGroupPosition(newPos);
2603 part.OffsetPosition = Vector3.Zero; 3327 part.setOffsetPosition(Vector3.Zero);
2604 3328
2605 // Compution our rotation to be not relative to the old parent 3329 // Compution our rotation in world
2606 Quaternion worldRot = parentRot * oldRot; 3330 Quaternion worldRot = parentRot * oldRot;
2607 part.RotationOffset = worldRot; 3331 part.RotationOffset = worldRot;
2608 3332
@@ -2613,29 +3337,32 @@ namespace OpenSim.Region.Framework.Scenes
2613 3337
2614 part.LinkNum = linkNum; 3338 part.LinkNum = linkNum;
2615 3339
3340 m_scene.updateScenePartGroup(part, this);
3341
2616 // Compute the new position of this SOP relative to the group position 3342 // Compute the new position of this SOP relative to the group position
2617 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3343 part.setOffsetPosition(newPos - AbsolutePosition);
2618 3344
2619 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3345 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2620 // It would have the affect of setting the physics engine position multiple 3346 // It would have the affect of setting the physics engine position multiple
2621 // times. In theory, that is not necessary but I don't have a good linkset 3347 // times. In theory, that is not necessary but I don't have a good linkset
2622 // test to know that cleaning up this code wouldn't break things.) 3348 // test to know that cleaning up this code wouldn't break things.)
2623 3349
2624 // Rotate the relative position by the rotation of the group
2625 Quaternion rootRotation = m_rootPart.RotationOffset;
2626 Vector3 pos = part.OffsetPosition;
2627 pos *= Quaternion.Inverse(rootRotation);
2628 part.OffsetPosition = pos;
2629
2630 // Compute the SOP's rotation relative to the rotation of the group. 3350 // Compute the SOP's rotation relative to the rotation of the group.
2631 parentRot = m_rootPart.RotationOffset; 3351 parentRot = m_rootPart.RotationOffset;
3352
2632 oldRot = part.RotationOffset; 3353 oldRot = part.RotationOffset;
2633 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3354 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2634 part.RotationOffset = newRot; 3355 part.setRotationOffset(newRot);
3356
3357 Vector3 pos = part.OffsetPosition;
3358 pos *= Quaternion.Conjugate(parentRot);
3359
3360 part.OffsetPosition = pos; // update position and orientation on physics also
2635 3361
2636 // Since this SOP's state has changed, push those changes into the physics engine 3362 // Since this SOP's state has changed, push those changes into the physics engine
2637 // and the simulator. 3363 // and the simulator.
2638 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3364 // done on caller
3365// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2639 } 3366 }
2640 3367
2641 /// <summary> 3368 /// <summary>
@@ -2663,10 +3390,14 @@ namespace OpenSim.Region.Framework.Scenes
2663 { 3390 {
2664 if (!BlockGrabOverride && !part.BlockGrab) 3391 if (!BlockGrabOverride && !part.BlockGrab)
2665 { 3392 {
2666 Vector3 llmoveforce = pos - AbsolutePosition; 3393/* Vector3 llmoveforce = pos - AbsolutePosition;
2667 Vector3 grabforce = llmoveforce; 3394 Vector3 grabforce = llmoveforce;
2668 grabforce = (grabforce / 10) * pa.Mass; 3395 grabforce = (grabforce / 10) * pa.Mass;
2669 pa.AddForce(grabforce, true); 3396 */
3397 // empirically convert distance diference to a impulse
3398 Vector3 grabforce = pos - AbsolutePosition;
3399 grabforce = grabforce * (pa.Mass/ 10.0f);
3400 pa.AddForce(grabforce, false);
2670 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 3401 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2671 } 3402 }
2672 } 3403 }
@@ -2880,6 +3611,8 @@ namespace OpenSim.Region.Framework.Scenes
2880 /// <param name="SetVolumeDetect"></param> 3611 /// <param name="SetVolumeDetect"></param>
2881 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 3612 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2882 { 3613 {
3614 HasGroupChanged = true;
3615
2883 SceneObjectPart selectionPart = GetPart(localID); 3616 SceneObjectPart selectionPart = GetPart(localID);
2884 3617
2885 if (Scene != null) 3618 if (Scene != null)
@@ -2905,8 +3638,12 @@ namespace OpenSim.Region.Framework.Scenes
2905 { 3638 {
2906 SceneObjectPart[] parts = m_parts.GetArray(); 3639 SceneObjectPart[] parts = m_parts.GetArray();
2907 3640
2908 if (Scene != null) 3641 if (Scene != null && UsePhysics)
2909 { 3642 {
3643 int maxprims = m_scene.m_linksetPhysCapacity;
3644 bool checkShape = (maxprims > 0 &&
3645 parts.Length > maxprims);
3646
2910 for (int i = 0; i < parts.Length; i++) 3647 for (int i = 0; i < parts.Length; i++)
2911 { 3648 {
2912 SceneObjectPart part = parts[i]; 3649 SceneObjectPart part = parts[i];
@@ -2917,11 +3654,34 @@ namespace OpenSim.Region.Framework.Scenes
2917 UsePhysics = false; // Reset physics 3654 UsePhysics = false; // Reset physics
2918 break; 3655 break;
2919 } 3656 }
3657
3658 if (checkShape && part.PhysicsShapeType != (byte)PhysicsShapeType.None)
3659 {
3660 if (--maxprims < 0)
3661 {
3662 UsePhysics = false;
3663 break;
3664 }
3665 }
2920 } 3666 }
2921 } 3667 }
2922 3668
2923 for (int i = 0; i < parts.Length; i++) 3669 if (parts.Length > 1)
2924 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 3670 {
3671 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3672
3673 for (int i = 0; i < parts.Length; i++)
3674 {
3675
3676 if (parts[i].UUID != m_rootPart.UUID)
3677 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3678 }
3679
3680 if (m_rootPart.PhysActor != null)
3681 m_rootPart.PhysActor.Building = false;
3682 }
3683 else
3684 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
2925 } 3685 }
2926 } 3686 }
2927 3687
@@ -2934,6 +3694,17 @@ namespace OpenSim.Region.Framework.Scenes
2934 } 3694 }
2935 } 3695 }
2936 3696
3697
3698
3699 /// <summary>
3700 /// Gets the number of parts
3701 /// </summary>
3702 /// <returns></returns>
3703 public int GetPartCount()
3704 {
3705 return Parts.Count();
3706 }
3707
2937 /// <summary> 3708 /// <summary>
2938 /// Update the texture entry for this part 3709 /// Update the texture entry for this part
2939 /// </summary> 3710 /// </summary>
@@ -2978,7 +3749,23 @@ namespace OpenSim.Region.Framework.Scenes
2978 { 3749 {
2979 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 3750 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2980 3751
2981 AdjustChildPrimPermissions(Scene.Permissions.IsGod(AgentID)); 3752 bool god = Scene.Permissions.IsGod(AgentID);
3753
3754 if (field == 1 && god)
3755 {
3756 ForEachPart(part =>
3757 {
3758 part.BaseMask = RootPart.BaseMask;
3759 });
3760 }
3761
3762 AdjustChildPrimPermissions(false);
3763
3764 if (field == 1 && god) // Base mask was set. Update all child part inventories
3765 {
3766 foreach (SceneObjectPart part in Parts)
3767 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3768 }
2982 3769
2983 HasGroupChanged = true; 3770 HasGroupChanged = true;
2984 3771
@@ -3025,8 +3812,6 @@ namespace OpenSim.Region.Framework.Scenes
3025 3812
3026 PhysicsActor pa = m_rootPart.PhysActor; 3813 PhysicsActor pa = m_rootPart.PhysActor;
3027 3814
3028 RootPart.StoreUndoState(true);
3029
3030 if (Scene != null) 3815 if (Scene != null)
3031 { 3816 {
3032 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 3817 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
@@ -3054,7 +3839,6 @@ namespace OpenSim.Region.Framework.Scenes
3054 SceneObjectPart obPart = parts[i]; 3839 SceneObjectPart obPart = parts[i];
3055 if (obPart.UUID != m_rootPart.UUID) 3840 if (obPart.UUID != m_rootPart.UUID)
3056 { 3841 {
3057// obPart.IgnoreUndoUpdate = true;
3058 Vector3 oldSize = new Vector3(obPart.Scale); 3842 Vector3 oldSize = new Vector3(obPart.Scale);
3059 3843
3060 float f = 1.0f; 3844 float f = 1.0f;
@@ -3166,8 +3950,6 @@ namespace OpenSim.Region.Framework.Scenes
3166 z *= a; 3950 z *= a;
3167 } 3951 }
3168 } 3952 }
3169
3170// obPart.IgnoreUndoUpdate = false;
3171 } 3953 }
3172 } 3954 }
3173 } 3955 }
@@ -3177,9 +3959,7 @@ namespace OpenSim.Region.Framework.Scenes
3177 prevScale.Y *= y; 3959 prevScale.Y *= y;
3178 prevScale.Z *= z; 3960 prevScale.Z *= z;
3179 3961
3180// RootPart.IgnoreUndoUpdate = true;
3181 RootPart.Resize(prevScale); 3962 RootPart.Resize(prevScale);
3182// RootPart.IgnoreUndoUpdate = false;
3183 3963
3184 for (int i = 0; i < parts.Length; i++) 3964 for (int i = 0; i < parts.Length; i++)
3185 { 3965 {
@@ -3187,8 +3967,6 @@ namespace OpenSim.Region.Framework.Scenes
3187 3967
3188 if (obPart.UUID != m_rootPart.UUID) 3968 if (obPart.UUID != m_rootPart.UUID)
3189 { 3969 {
3190 obPart.IgnoreUndoUpdate = true;
3191
3192 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 3970 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
3193 currentpos.X *= x; 3971 currentpos.X *= x;
3194 currentpos.Y *= y; 3972 currentpos.Y *= y;
@@ -3201,16 +3979,12 @@ namespace OpenSim.Region.Framework.Scenes
3201 3979
3202 obPart.Resize(newSize); 3980 obPart.Resize(newSize);
3203 obPart.UpdateOffSet(currentpos); 3981 obPart.UpdateOffSet(currentpos);
3204
3205 obPart.IgnoreUndoUpdate = false;
3206 } 3982 }
3207 3983
3208// obPart.IgnoreUndoUpdate = false; 3984 HasGroupChanged = true;
3209// obPart.StoreUndoState(); 3985 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3986 ScheduleGroupForTerseUpdate();
3210 } 3987 }
3211
3212// m_log.DebugFormat(
3213// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
3214 } 3988 }
3215 3989
3216 #endregion 3990 #endregion
@@ -3223,14 +3997,6 @@ namespace OpenSim.Region.Framework.Scenes
3223 /// <param name="pos"></param> 3997 /// <param name="pos"></param>
3224 public void UpdateGroupPosition(Vector3 pos) 3998 public void UpdateGroupPosition(Vector3 pos)
3225 { 3999 {
3226// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
3227
3228 RootPart.StoreUndoState(true);
3229
3230// SceneObjectPart[] parts = m_parts.GetArray();
3231// for (int i = 0; i < parts.Length; i++)
3232// parts[i].StoreUndoState();
3233
3234 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 4000 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
3235 { 4001 {
3236 if (IsAttachment) 4002 if (IsAttachment)
@@ -3263,21 +4029,17 @@ namespace OpenSim.Region.Framework.Scenes
3263 /// </summary> 4029 /// </summary>
3264 /// <param name="pos"></param> 4030 /// <param name="pos"></param>
3265 /// <param name="localID"></param> 4031 /// <param name="localID"></param>
4032 ///
4033
3266 public void UpdateSinglePosition(Vector3 pos, uint localID) 4034 public void UpdateSinglePosition(Vector3 pos, uint localID)
3267 { 4035 {
3268 SceneObjectPart part = GetPart(localID); 4036 SceneObjectPart part = GetPart(localID);
3269 4037
3270// SceneObjectPart[] parts = m_parts.GetArray();
3271// for (int i = 0; i < parts.Length; i++)
3272// parts[i].StoreUndoState();
3273
3274 if (part != null) 4038 if (part != null)
3275 { 4039 {
3276// m_log.DebugFormat( 4040// unlock parts position change
3277// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 4041 if (m_rootPart.PhysActor != null)
3278 4042 m_rootPart.PhysActor.Building = true;
3279 part.StoreUndoState(false);
3280 part.IgnoreUndoUpdate = true;
3281 4043
3282 if (part.UUID == m_rootPart.UUID) 4044 if (part.UUID == m_rootPart.UUID)
3283 { 4045 {
@@ -3288,8 +4050,10 @@ namespace OpenSim.Region.Framework.Scenes
3288 part.UpdateOffSet(pos); 4050 part.UpdateOffSet(pos);
3289 } 4051 }
3290 4052
4053 if (m_rootPart.PhysActor != null)
4054 m_rootPart.PhysActor.Building = false;
4055
3291 HasGroupChanged = true; 4056 HasGroupChanged = true;
3292 part.IgnoreUndoUpdate = false;
3293 } 4057 }
3294 } 4058 }
3295 4059
@@ -3299,13 +4063,7 @@ namespace OpenSim.Region.Framework.Scenes
3299 /// <param name="newPos"></param> 4063 /// <param name="newPos"></param>
3300 public void UpdateRootPosition(Vector3 newPos) 4064 public void UpdateRootPosition(Vector3 newPos)
3301 { 4065 {
3302// m_log.DebugFormat( 4066 // needs to be called with phys building true
3303// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3304
3305// SceneObjectPart[] parts = m_parts.GetArray();
3306// for (int i = 0; i < parts.Length; i++)
3307// parts[i].StoreUndoState();
3308
3309 Vector3 oldPos; 4067 Vector3 oldPos;
3310 4068
3311 if (IsAttachment) 4069 if (IsAttachment)
@@ -3326,12 +4084,19 @@ namespace OpenSim.Region.Framework.Scenes
3326 } 4084 }
3327 4085
3328 AbsolutePosition = newPos; 4086 AbsolutePosition = newPos;
3329 4087
3330 if (IsAttachment) 4088 if (IsAttachment)
3331 m_rootPart.AttachedPos = newPos; 4089 m_rootPart.AttachedPos = newPos;
3332 4090
3333 HasGroupChanged = true; 4091 HasGroupChanged = true;
3334 ScheduleGroupForTerseUpdate(); 4092 if (m_rootPart.Undoing)
4093 {
4094 ScheduleGroupForFullUpdate();
4095 }
4096 else
4097 {
4098 ScheduleGroupForTerseUpdate();
4099 }
3335 } 4100 }
3336 4101
3337 #endregion 4102 #endregion
@@ -3344,24 +4109,16 @@ namespace OpenSim.Region.Framework.Scenes
3344 /// <param name="rot"></param> 4109 /// <param name="rot"></param>
3345 public void UpdateGroupRotationR(Quaternion rot) 4110 public void UpdateGroupRotationR(Quaternion rot)
3346 { 4111 {
3347// m_log.DebugFormat(
3348// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3349
3350// SceneObjectPart[] parts = m_parts.GetArray();
3351// for (int i = 0; i < parts.Length; i++)
3352// parts[i].StoreUndoState();
3353
3354 m_rootPart.StoreUndoState(true);
3355
3356 m_rootPart.UpdateRotation(rot); 4112 m_rootPart.UpdateRotation(rot);
3357 4113
4114/* this is done by rootpart RotationOffset set called by UpdateRotation
3358 PhysicsActor actor = m_rootPart.PhysActor; 4115 PhysicsActor actor = m_rootPart.PhysActor;
3359 if (actor != null) 4116 if (actor != null)
3360 { 4117 {
3361 actor.Orientation = m_rootPart.RotationOffset; 4118 actor.Orientation = m_rootPart.RotationOffset;
3362 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 4119 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3363 } 4120 }
3364 4121*/
3365 HasGroupChanged = true; 4122 HasGroupChanged = true;
3366 ScheduleGroupForTerseUpdate(); 4123 ScheduleGroupForTerseUpdate();
3367 } 4124 }
@@ -3373,16 +4130,6 @@ namespace OpenSim.Region.Framework.Scenes
3373 /// <param name="rot"></param> 4130 /// <param name="rot"></param>
3374 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 4131 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3375 { 4132 {
3376// m_log.DebugFormat(
3377// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3378
3379// SceneObjectPart[] parts = m_parts.GetArray();
3380// for (int i = 0; i < parts.Length; i++)
3381// parts[i].StoreUndoState();
3382
3383 RootPart.StoreUndoState(true);
3384 RootPart.IgnoreUndoUpdate = true;
3385
3386 m_rootPart.UpdateRotation(rot); 4133 m_rootPart.UpdateRotation(rot);
3387 4134
3388 PhysicsActor actor = m_rootPart.PhysActor; 4135 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3401,8 +4148,6 @@ namespace OpenSim.Region.Framework.Scenes
3401 4148
3402 HasGroupChanged = true; 4149 HasGroupChanged = true;
3403 ScheduleGroupForTerseUpdate(); 4150 ScheduleGroupForTerseUpdate();
3404
3405 RootPart.IgnoreUndoUpdate = false;
3406 } 4151 }
3407 4152
3408 /// <summary> 4153 /// <summary>
@@ -3415,13 +4160,11 @@ namespace OpenSim.Region.Framework.Scenes
3415 SceneObjectPart part = GetPart(localID); 4160 SceneObjectPart part = GetPart(localID);
3416 4161
3417 SceneObjectPart[] parts = m_parts.GetArray(); 4162 SceneObjectPart[] parts = m_parts.GetArray();
3418 for (int i = 0; i < parts.Length; i++)
3419 parts[i].StoreUndoState();
3420 4163
3421 if (part != null) 4164 if (part != null)
3422 { 4165 {
3423// m_log.DebugFormat( 4166 if (m_rootPart.PhysActor != null)
3424// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 4167 m_rootPart.PhysActor.Building = true;
3425 4168
3426 if (part.UUID == m_rootPart.UUID) 4169 if (part.UUID == m_rootPart.UUID)
3427 { 4170 {
@@ -3431,6 +4174,9 @@ namespace OpenSim.Region.Framework.Scenes
3431 { 4174 {
3432 part.UpdateRotation(rot); 4175 part.UpdateRotation(rot);
3433 } 4176 }
4177
4178 if (m_rootPart.PhysActor != null)
4179 m_rootPart.PhysActor.Building = false;
3434 } 4180 }
3435 } 4181 }
3436 4182
@@ -3444,12 +4190,8 @@ namespace OpenSim.Region.Framework.Scenes
3444 SceneObjectPart part = GetPart(localID); 4190 SceneObjectPart part = GetPart(localID);
3445 if (part != null) 4191 if (part != null)
3446 { 4192 {
3447// m_log.DebugFormat( 4193 if (m_rootPart.PhysActor != null)
3448// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 4194 m_rootPart.PhysActor.Building = true;
3449// part.Name, part.LocalId, rot);
3450
3451 part.StoreUndoState();
3452 part.IgnoreUndoUpdate = true;
3453 4195
3454 if (part.UUID == m_rootPart.UUID) 4196 if (part.UUID == m_rootPart.UUID)
3455 { 4197 {
@@ -3462,7 +4204,8 @@ namespace OpenSim.Region.Framework.Scenes
3462 part.OffsetPosition = pos; 4204 part.OffsetPosition = pos;
3463 } 4205 }
3464 4206
3465 part.IgnoreUndoUpdate = false; 4207 if (m_rootPart.PhysActor != null)
4208 m_rootPart.PhysActor.Building = false;
3466 } 4209 }
3467 } 4210 }
3468 4211
@@ -3472,15 +4215,12 @@ namespace OpenSim.Region.Framework.Scenes
3472 /// <param name="rot"></param> 4215 /// <param name="rot"></param>
3473 public void UpdateRootRotation(Quaternion rot) 4216 public void UpdateRootRotation(Quaternion rot)
3474 { 4217 {
3475// m_log.DebugFormat( 4218 // needs to be called with phys building true
3476// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3477// Name, LocalId, rot);
3478
3479 Quaternion axRot = rot; 4219 Quaternion axRot = rot;
3480 Quaternion oldParentRot = m_rootPart.RotationOffset; 4220 Quaternion oldParentRot = m_rootPart.RotationOffset;
3481 4221
3482 m_rootPart.StoreUndoState(); 4222 //Don't use UpdateRotation because it schedules an update prematurely
3483 m_rootPart.UpdateRotation(rot); 4223 m_rootPart.RotationOffset = rot;
3484 4224
3485 PhysicsActor pa = m_rootPart.PhysActor; 4225 PhysicsActor pa = m_rootPart.PhysActor;
3486 4226
@@ -3496,35 +4236,145 @@ namespace OpenSim.Region.Framework.Scenes
3496 SceneObjectPart prim = parts[i]; 4236 SceneObjectPart prim = parts[i];
3497 if (prim.UUID != m_rootPart.UUID) 4237 if (prim.UUID != m_rootPart.UUID)
3498 { 4238 {
3499 prim.IgnoreUndoUpdate = true; 4239 Quaternion NewRot = oldParentRot * prim.RotationOffset;
4240 NewRot = Quaternion.Inverse(axRot) * NewRot;
4241 prim.RotationOffset = NewRot;
4242
3500 Vector3 axPos = prim.OffsetPosition; 4243 Vector3 axPos = prim.OffsetPosition;
4244
3501 axPos *= oldParentRot; 4245 axPos *= oldParentRot;
3502 axPos *= Quaternion.Inverse(axRot); 4246 axPos *= Quaternion.Inverse(axRot);
3503 prim.OffsetPosition = axPos; 4247 prim.OffsetPosition = axPos;
3504 Quaternion primsRot = prim.RotationOffset;
3505 Quaternion newRot = oldParentRot * primsRot;
3506 newRot = Quaternion.Inverse(axRot) * newRot;
3507 prim.RotationOffset = newRot;
3508 prim.ScheduleTerseUpdate();
3509 prim.IgnoreUndoUpdate = false;
3510 } 4248 }
3511 } 4249 }
3512 4250
3513// for (int i = 0; i < parts.Length; i++) 4251 HasGroupChanged = true;
3514// { 4252 ScheduleGroupForFullUpdate();
3515// SceneObjectPart childpart = parts[i]; 4253 }
3516// if (childpart != m_rootPart)
3517// {
3518//// childpart.IgnoreUndoUpdate = false;
3519//// childpart.StoreUndoState();
3520// }
3521// }
3522 4254
3523 m_rootPart.ScheduleTerseUpdate(); 4255 private enum updatetype :int
4256 {
4257 none = 0,
4258 partterse = 1,
4259 partfull = 2,
4260 groupterse = 3,
4261 groupfull = 4
4262 }
3524 4263
3525// m_log.DebugFormat( 4264 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3526// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 4265 {
3527// Name, LocalId, rot); 4266 // TODO this still as excessive *.Schedule*Update()s
4267
4268 if (part != null && part.ParentGroup != null)
4269 {
4270 ObjectChangeType change = data.change;
4271 bool togroup = ((change & ObjectChangeType.Group) != 0);
4272 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4273
4274 SceneObjectGroup group = part.ParentGroup;
4275 PhysicsActor pha = group.RootPart.PhysActor;
4276
4277 updatetype updateType = updatetype.none;
4278
4279 if (togroup)
4280 {
4281 // related to group
4282 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4283 {
4284 if ((change & ObjectChangeType.Rotation) != 0)
4285 {
4286 group.RootPart.UpdateRotation(data.rotation);
4287 updateType = updatetype.none;
4288 }
4289 if ((change & ObjectChangeType.Position) != 0)
4290 {
4291 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4292 UpdateGroupPosition(data.position);
4293 updateType = updatetype.groupterse;
4294 }
4295 else
4296 // ugly rotation update of all parts
4297 {
4298 group.ResetChildPrimPhysicsPositions();
4299 }
4300
4301 }
4302 if ((change & ObjectChangeType.Scale) != 0)
4303 {
4304 if (pha != null)
4305 pha.Building = true;
4306
4307 group.GroupResize(data.scale);
4308 updateType = updatetype.none;
4309
4310 if (pha != null)
4311 pha.Building = false;
4312 }
4313 }
4314 else
4315 {
4316 // related to single prim in a link-set ( ie group)
4317 if (pha != null)
4318 pha.Building = true;
4319
4320 // root part is special
4321 // parts offset positions or rotations need to change also
4322
4323 if (part == group.RootPart)
4324 {
4325 if ((change & ObjectChangeType.Rotation) != 0)
4326 group.UpdateRootRotation(data.rotation);
4327 if ((change & ObjectChangeType.Position) != 0)
4328 group.UpdateRootPosition(data.position);
4329 if ((change & ObjectChangeType.Scale) != 0)
4330 part.Resize(data.scale);
4331 }
4332 else
4333 {
4334 if ((change & ObjectChangeType.Position) != 0)
4335 {
4336 part.OffsetPosition = data.position;
4337 updateType = updatetype.partterse;
4338 }
4339 if ((change & ObjectChangeType.Rotation) != 0)
4340 {
4341 part.UpdateRotation(data.rotation);
4342 updateType = updatetype.none;
4343 }
4344 if ((change & ObjectChangeType.Scale) != 0)
4345 {
4346 part.Resize(data.scale);
4347 updateType = updatetype.none;
4348 }
4349 }
4350
4351 if (pha != null)
4352 pha.Building = false;
4353 }
4354
4355 if (updateType != updatetype.none)
4356 {
4357 group.HasGroupChanged = true;
4358
4359 switch (updateType)
4360 {
4361 case updatetype.partterse:
4362 part.ScheduleTerseUpdate();
4363 break;
4364 case updatetype.partfull:
4365 part.ScheduleFullUpdate();
4366 break;
4367 case updatetype.groupterse:
4368 group.ScheduleGroupForTerseUpdate();
4369 break;
4370 case updatetype.groupfull:
4371 group.ScheduleGroupForFullUpdate();
4372 break;
4373 default:
4374 break;
4375 }
4376 }
4377 }
3528 } 4378 }
3529 4379
3530 #endregion 4380 #endregion
@@ -3565,6 +4415,8 @@ namespace OpenSim.Region.Framework.Scenes
3565 waypoint.handle = handle; 4415 waypoint.handle = handle;
3566 lock (m_rotTargets) 4416 lock (m_rotTargets)
3567 { 4417 {
4418 if (m_rotTargets.Count >= 8)
4419 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3568 m_rotTargets.Add(handle, waypoint); 4420 m_rotTargets.Add(handle, waypoint);
3569 } 4421 }
3570 m_scene.AddGroupTarget(this); 4422 m_scene.AddGroupTarget(this);
@@ -3590,6 +4442,8 @@ namespace OpenSim.Region.Framework.Scenes
3590 waypoint.handle = handle; 4442 waypoint.handle = handle;
3591 lock (m_targets) 4443 lock (m_targets)
3592 { 4444 {
4445 if (m_targets.Count >= 8)
4446 m_targets.Remove(m_targets.ElementAt(0).Key);
3593 m_targets.Add(handle, waypoint); 4447 m_targets.Add(handle, waypoint);
3594 } 4448 }
3595 m_scene.AddGroupTarget(this); 4449 m_scene.AddGroupTarget(this);
@@ -3623,10 +4477,11 @@ namespace OpenSim.Region.Framework.Scenes
3623 scriptPosTarget target = m_targets[idx]; 4477 scriptPosTarget target = m_targets[idx];
3624 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 4478 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3625 { 4479 {
4480 at_target = true;
4481
3626 // trigger at_target 4482 // trigger at_target
3627 if (m_scriptListens_atTarget) 4483 if (m_scriptListens_atTarget)
3628 { 4484 {
3629 at_target = true;
3630 scriptPosTarget att = new scriptPosTarget(); 4485 scriptPosTarget att = new scriptPosTarget();
3631 att.targetPos = target.targetPos; 4486 att.targetPos = target.targetPos;
3632 att.tolerance = target.tolerance; 4487 att.tolerance = target.tolerance;
@@ -3744,11 +4599,50 @@ namespace OpenSim.Region.Framework.Scenes
3744 } 4599 }
3745 } 4600 }
3746 } 4601 }
3747 4602
4603 public Vector3 GetGeometricCenter()
4604 {
4605 // this is not real geometric center but a average of positions relative to root prim acording to
4606 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4607 // ignoring tortured prims details since sl also seems to ignore
4608 // so no real use in doing it on physics
4609
4610 Vector3 gc = Vector3.Zero;
4611
4612 int nparts = m_parts.Count;
4613 if (nparts <= 1)
4614 return gc;
4615
4616 SceneObjectPart[] parts = m_parts.GetArray();
4617 nparts = parts.Length; // just in case it changed
4618 if (nparts <= 1)
4619 return gc;
4620
4621 Quaternion parentRot = RootPart.RotationOffset;
4622 Vector3 pPos;
4623
4624 // average all parts positions
4625 for (int i = 0; i < nparts; i++)
4626 {
4627 // do it directly
4628 // gc += parts[i].GetWorldPosition();
4629 if (parts[i] != RootPart)
4630 {
4631 pPos = parts[i].OffsetPosition;
4632 gc += pPos;
4633 }
4634
4635 }
4636 gc /= nparts;
4637
4638 // relative to root:
4639// gc -= AbsolutePosition;
4640 return gc;
4641 }
4642
3748 public float GetMass() 4643 public float GetMass()
3749 { 4644 {
3750 float retmass = 0f; 4645 float retmass = 0f;
3751
3752 SceneObjectPart[] parts = m_parts.GetArray(); 4646 SceneObjectPart[] parts = m_parts.GetArray();
3753 for (int i = 0; i < parts.Length; i++) 4647 for (int i = 0; i < parts.Length; i++)
3754 retmass += parts[i].GetMass(); 4648 retmass += parts[i].GetMass();
@@ -3756,6 +4650,39 @@ namespace OpenSim.Region.Framework.Scenes
3756 return retmass; 4650 return retmass;
3757 } 4651 }
3758 4652
4653 // center of mass of full object
4654 public Vector3 GetCenterOfMass()
4655 {
4656 PhysicsActor pa = RootPart.PhysActor;
4657
4658 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4659 {
4660 // physics knows better about center of mass of physical prims
4661 Vector3 tmp = pa.CenterOfMass;
4662 return tmp;
4663 }
4664
4665 Vector3 Ptot = Vector3.Zero;
4666 float totmass = 0f;
4667 float m;
4668
4669 SceneObjectPart[] parts = m_parts.GetArray();
4670 for (int i = 0; i < parts.Length; i++)
4671 {
4672 m = parts[i].GetMass();
4673 Ptot += parts[i].GetPartCenterOfMass() * m;
4674 totmass += m;
4675 }
4676
4677 if (totmass == 0)
4678 totmass = 0;
4679 else
4680 totmass = 1 / totmass;
4681 Ptot *= totmass;
4682
4683 return Ptot;
4684 }
4685
3759 /// <summary> 4686 /// <summary>
3760 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 4687 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3761 /// the physics engine can use it. 4688 /// the physics engine can use it.
@@ -3882,10 +4809,10 @@ namespace OpenSim.Region.Framework.Scenes
3882 /// down after it move one place down the list. 4809 /// down after it move one place down the list.
3883 /// </remarks> 4810 /// </remarks>
3884 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns> 4811 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
3885 public List<ScenePresence> GetSittingAvatars() 4812 public List<UUID> GetSittingAvatars()
3886 { 4813 {
3887 lock (m_sittingAvatars) 4814 lock (m_sittingAvatars)
3888 return new List<ScenePresence>(m_sittingAvatars); 4815 return new List<UUID>(m_sittingAvatars);
3889 } 4816 }
3890 4817
3891 /// <summary> 4818 /// <summary>
@@ -3935,6 +4862,14 @@ namespace OpenSim.Region.Framework.Scenes
3935 FromItemID = uuid; 4862 FromItemID = uuid;
3936 } 4863 }
3937 4864
4865 public void ResetOwnerChangeFlag()
4866 {
4867 ForEachPart(delegate(SceneObjectPart part)
4868 {
4869 part.ResetOwnerChangeFlag();
4870 });
4871 }
4872
3938 #endregion 4873 #endregion
3939 } 4874 }
3940} 4875}