aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs509
1 files changed, 405 insertions, 104 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index 15795e5..d08237e 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -38,8 +38,10 @@ using OpenMetaverse;
38using OpenMetaverse.Packets; 38using OpenMetaverse.Packets;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Region.Framework.Interfaces; 40using OpenSim.Region.Framework.Interfaces;
41using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.PhysicsModules.SharedBase;
42using OpenSim.Region.Framework.Scenes.Serialization; 42using OpenSim.Region.Framework.Scenes.Serialization;
43using PermissionMask = OpenSim.Framework.PermissionMask;
44using OpenSim.Services.Interfaces;
43 45
44namespace OpenSim.Region.Framework.Scenes 46namespace OpenSim.Region.Framework.Scenes
45{ 47{
@@ -74,6 +76,7 @@ namespace OpenSim.Region.Framework.Scenes
74 touch = 8, 76 touch = 8,
75 touch_end = 536870912, 77 touch_end = 536870912,
76 touch_start = 2097152, 78 touch_start = 2097152,
79 transaction_result = 33554432,
77 object_rez = 4194304 80 object_rez = 4194304
78 } 81 }
79 82
@@ -108,6 +111,9 @@ namespace OpenSim.Region.Framework.Scenes
108 STATUS_ROTATE_Z = 0x008, 111 STATUS_ROTATE_Z = 0x008,
109 } 112 }
110 113
114 // This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm
115 public static readonly uint SLAM = 16;
116
111 // private PrimCountTaintedDelegate handlerPrimCountTainted = null; 117 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
112 118
113 /// <summary> 119 /// <summary>
@@ -145,12 +151,27 @@ namespace OpenSim.Region.Framework.Scenes
145 151
146 get { return m_hasGroupChanged; } 152 get { return m_hasGroupChanged; }
147 } 153 }
154
155 private bool m_groupContainsForeignPrims = false;
148 156
149 /// <summary> 157 /// <summary>
150 /// Has the group changed due to an unlink operation? We record this in order to optimize deletion, since 158 /// Whether the group contains prims that came from a different group. This happens when
151 /// an unlinked group currently has to be persisted to the database before we can perform an unlink operation. 159 /// linking or delinking groups. The implication is that until the group is persisted,
160 /// the prims in the database still use the old SceneGroupID. That's a problem if the group
161 /// is deleted, because we delete groups by searching for prims by their SceneGroupID.
152 /// </summary> 162 /// </summary>
153 public bool HasGroupChangedDueToDelink { get; private set; } 163 public bool GroupContainsForeignPrims
164 {
165 private set
166 {
167 m_groupContainsForeignPrims = value;
168 if (m_groupContainsForeignPrims)
169 HasGroupChanged = true;
170 }
171
172 get { return m_groupContainsForeignPrims; }
173 }
174
154 175
155 private bool isTimeToPersist() 176 private bool isTimeToPersist()
156 { 177 {
@@ -267,7 +288,10 @@ namespace OpenSim.Region.Framework.Scenes
267 private Vector3 lastPhysGroupPos; 288 private Vector3 lastPhysGroupPos;
268 private Quaternion lastPhysGroupRot; 289 private Quaternion lastPhysGroupRot;
269 290
270 private bool m_isBackedUp; 291 /// <summary>
292 /// Is this entity set to be saved in persistent storage?
293 /// </summary>
294 public bool Backup { get; private set; }
271 295
272 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>(); 296 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
273 297
@@ -329,7 +353,7 @@ namespace OpenSim.Region.Framework.Scenes
329 { 353 {
330 get 354 get
331 { 355 {
332 Vector3 minScale = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionSize); 356 Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
333 Vector3 maxScale = Vector3.Zero; 357 Vector3 maxScale = Vector3.Zero;
334 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 358 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
335 359
@@ -424,9 +448,16 @@ namespace OpenSim.Region.Framework.Scenes
424 /// <returns></returns> 448 /// <returns></returns>
425 public bool IsAttachmentCheckFull() 449 public bool IsAttachmentCheckFull()
426 { 450 {
427 return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0)); 451 return (IsAttachment ||
452 (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0));
428 } 453 }
429 454
455 private struct avtocrossInfo
456 {
457 public ScenePresence av;
458 public uint ParentID;
459 }
460
430 /// <summary> 461 /// <summary>
431 /// The absolute position of this scene object in the scene 462 /// The absolute position of this scene object in the scene
432 /// </summary> 463 /// </summary>
@@ -440,24 +471,140 @@ namespace OpenSim.Region.Framework.Scenes
440 if (Scene != null) 471 if (Scene != null)
441 { 472 {
442 if ( 473 if (
443 // (Scene.TestBorderCross(val - Vector3.UnitX, Cardinals.E) 474 !Scene.PositionIsInCurrentRegion(val)
444 // || Scene.TestBorderCross(val + Vector3.UnitX, Cardinals.W) 475 && !IsAttachmentCheckFull()
445 // || Scene.TestBorderCross(val - Vector3.UnitY, Cardinals.N) 476 && (!Scene.LoadingPrims)
446 // || Scene.TestBorderCross(val + Vector3.UnitY, Cardinals.S)) 477 )
447 // Experimental change for better border crossings.
448 // The commented out original lines above would, it seems, trigger
449 // a border crossing a little early or late depending on which
450 // direction the object was moving.
451 (Scene.TestBorderCross(val, Cardinals.E)
452 || Scene.TestBorderCross(val, Cardinals.W)
453 || Scene.TestBorderCross(val, Cardinals.N)
454 || Scene.TestBorderCross(val, Cardinals.S))
455 && !IsAttachmentCheckFull() && (!Scene.LoadingPrims))
456 { 478 {
457 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 479 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
480 EntityTransferContext ctx = new EntityTransferContext();
481 Vector3 newpos = Vector3.Zero;
482 string failureReason = String.Empty;
483 OpenSim.Services.Interfaces.GridRegion destination = null;
484
485 if (m_rootPart.KeyframeMotion != null)
486 m_rootPart.KeyframeMotion.StartCrossingCheck();
487
488 bool canCross = true;
489 foreach (ScenePresence av in GetSittingAvatars())
490 {
491 // We need to cross these agents. First, let's find
492 // out if any of them can't cross for some reason.
493 // We have to deny the crossing entirely if any
494 // of them are banned. Alternatively, we could
495 // unsit banned agents....
496
497
498 // We set the avatar position as being the object
499 // position to get the region to send to
500 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, ctx, out newpos, out failureReason)) == null)
501 {
502 canCross = false;
503 break;
504 }
505
506 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
507 }
508
509 if (canCross)
510 {
511 // We unparent the SP quietly so that it won't
512 // be made to stand up
513
514 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
515
516 foreach (ScenePresence av in GetSittingAvatars())
517 {
518 avtocrossInfo avinfo = new avtocrossInfo();
519 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
520 if (parentPart != null)
521 av.ParentUUID = parentPart.UUID;
522
523 avinfo.av = av;
524 avinfo.ParentID = av.ParentID;
525 avsToCross.Add(avinfo);
526
527 av.PrevSitOffset = av.OffsetPosition;
528 av.ParentID = 0;
529 }
530
531 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
532
533 // Normalize
534 if (val.X >= m_scene.RegionInfo.RegionSizeX)
535 val.X -= m_scene.RegionInfo.RegionSizeX;
536 if (val.Y >= m_scene.RegionInfo.RegionSizeY)
537 val.Y -= m_scene.RegionInfo.RegionSizeY;
538 if (val.X < 0)
539 val.X += m_scene.RegionInfo.RegionSizeX;
540 if (val.Y < 0)
541 val.Y += m_scene.RegionInfo.RegionSizeY;
542
543 // If it's deleted, crossing was successful
544 if (IsDeleted)
545 {
546 foreach (avtocrossInfo avinfo in avsToCross)
547 {
548 ScenePresence av = avinfo.av;
549 if (!av.IsInTransit) // just in case...
550 {
551 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
552
553 av.IsInTransit = true;
554
555 // A temporary measure to allow regression tests to work.
556 // Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget
557 // or similar since BeginInvoke() always uses the system threadpool to launch
558 // threads rather than any replace threadpool that we might be using.
559 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
560 {
561 entityTransfer.CrossAgentToNewRegionAsync(av, val, destination, av.Flying, ctx);
562 CrossAgentToNewRegionCompleted(av);
563 }
564 else
565 {
566 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
567 d.BeginInvoke(
568 av, val, destination, av.Flying, ctx,
569 ar => CrossAgentToNewRegionCompleted(d.EndInvoke(ar)), null);
570 }
571 }
572 else
573 {
574 m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val);
575 }
576 }
577
578 return;
579 }
580 else // cross failed, put avas back ??
581 {
582 foreach (avtocrossInfo avinfo in avsToCross)
583 {
584 ScenePresence av = avinfo.av;
585 av.ParentUUID = UUID.Zero;
586 av.ParentID = avinfo.ParentID;
587 }
588 }
589 }
590 else
591 {
592 if (m_rootPart.KeyframeMotion != null)
593 m_rootPart.KeyframeMotion.CrossingFailure();
594
595 if (RootPart.PhysActor != null)
596 {
597 RootPart.PhysActor.CrossingFailure();
598 }
599 }
600
601 Vector3 oldp = AbsolutePosition;
602 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f);
603 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f);
604 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, Constants.RegionHeight);
458 } 605 }
459 } 606 }
460 607
461 if (RootPart.GetStatusSandbox()) 608 if (RootPart.GetStatusSandbox())
462 { 609 {
463 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 610 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
@@ -491,6 +638,36 @@ namespace OpenSim.Region.Framework.Scenes
491 } 638 }
492 } 639 }
493 640
641 public override Vector3 Velocity
642 {
643 get { return RootPart.Velocity; }
644 set { RootPart.Velocity = value; }
645 }
646
647 private void CrossAgentToNewRegionCompleted(ScenePresence agent)
648 {
649 //// If the cross was successful, this agent is a child agent
650 if (agent.IsChildAgent)
651 {
652 if (agent.ParentUUID != UUID.Zero)
653 {
654 agent.ParentPart = null;
655// agent.ParentPosition = Vector3.Zero;
656// agent.ParentUUID = UUID.Zero;
657 }
658 }
659
660 agent.ParentUUID = UUID.Zero;
661// agent.Reset();
662// else // Not successful
663// agent.RestoreInCurrentScene();
664
665 // In any case
666 agent.IsInTransit = false;
667
668 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
669 }
670
494 public override uint LocalId 671 public override uint LocalId
495 { 672 {
496 get { return m_rootPart.LocalId; } 673 get { return m_rootPart.LocalId; }
@@ -548,7 +725,11 @@ namespace OpenSim.Region.Framework.Scenes
548 set { m_rootPart.Text = value; } 725 set { m_rootPart.Text = value; }
549 } 726 }
550 727
551 protected virtual bool InSceneBackup 728 /// <summary>
729 /// If set to true then the scene object can be backed up in principle, though this will only actually occur
730 /// if Backup is set. If false then the scene object will never be backed up, Backup will always be false.
731 /// </summary>
732 protected virtual bool CanBeBackedUp
552 { 733 {
553 get { return true; } 734 get { return true; }
554 } 735 }
@@ -577,6 +758,8 @@ namespace OpenSim.Region.Framework.Scenes
577 childPa.Selected = value; 758 childPa.Selected = value;
578 } 759 }
579 } 760 }
761 if (RootPart.KeyframeMotion != null)
762 RootPart.KeyframeMotion.Selected = value;
580 } 763 }
581 } 764 }
582 765
@@ -648,6 +831,12 @@ namespace OpenSim.Region.Framework.Scenes
648 public UUID FromFolderID { get; set; } 831 public UUID FromFolderID { get; set; }
649 832
650 /// <summary> 833 /// <summary>
834 /// If true then grabs are blocked no matter what the individual part BlockGrab setting.
835 /// </summary>
836 /// <value><c>true</c> if block grab override; otherwise, <c>false</c>.</value>
837 public bool BlockGrabOverride { get; set; }
838
839 /// <summary>
651 /// IDs of all avatars sat on this scene object. 840 /// IDs of all avatars sat on this scene object.
652 /// </summary> 841 /// </summary>
653 /// <remarks> 842 /// <remarks>
@@ -657,7 +846,7 @@ namespace OpenSim.Region.Framework.Scenes
657 /// No avatar should appear more than once in this list. 846 /// No avatar should appear more than once in this list.
658 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart. 847 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
659 /// </remarks> 848 /// </remarks>
660 protected internal List<UUID> m_sittingAvatars = new List<UUID>(); 849 protected internal List<ScenePresence> m_sittingAvatars = new List<ScenePresence>();
661 850
662 #endregion 851 #endregion
663 852
@@ -722,20 +911,60 @@ namespace OpenSim.Region.Framework.Scenes
722 } 911 }
723 } 912 }
724 913
914 public void LoadScriptState(XmlReader reader)
915 {
916// m_log.DebugFormat("[SCENE OBJECT GROUP]: Looking for script state for {0}", Name);
917
918 while (true)
919 {
920 if (reader.Name == "SavedScriptState" && reader.NodeType == XmlNodeType.Element)
921 {
922// m_log.DebugFormat("[SCENE OBJECT GROUP]: Loading script state for {0}", Name);
923
924 if (m_savedScriptState == null)
925 m_savedScriptState = new Dictionary<UUID, string>();
926
927 string uuid = reader.GetAttribute("UUID");
928
929 // Even if there is no UUID attribute for some strange reason, we must always read the inner XML
930 // so we don't continually keep checking the same SavedScriptedState element.
931 string innerXml = reader.ReadInnerXml();
932
933 if (uuid != null)
934 {
935// m_log.DebugFormat("[SCENE OBJECT GROUP]: Found state for item ID {0} in object {1}", uuid, Name);
936
937 UUID itemid = new UUID(uuid);
938 if (itemid != UUID.Zero)
939 m_savedScriptState[itemid] = innerXml;
940 }
941 else
942 {
943 m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}", Name);
944 }
945 }
946 else
947 {
948 if (!reader.Read())
949 break;
950 }
951 }
952 }
953
725 /// <summary> 954 /// <summary>
726 /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes. 955 /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes.
727 /// </summary> 956 /// </summary>
728 public virtual void AttachToBackup() 957 public virtual void AttachToBackup()
729 { 958 {
730 if (InSceneBackup) 959 if (CanBeBackedUp)
731 { 960 {
732 //m_log.DebugFormat( 961// m_log.DebugFormat(
733 // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID); 962// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
734 963
735 if (!m_isBackedUp) 964 if (!Backup)
736 m_scene.EventManager.OnBackup += ProcessBackup; 965 m_scene.EventManager.OnBackup += ProcessBackup;
737 966
738 m_isBackedUp = true; 967 Backup = true;
739 } 968 }
740 } 969 }
741 970
@@ -757,6 +986,11 @@ namespace OpenSim.Region.Framework.Scenes
757 for (int i = 0; i < parts.Length; i++) 986 for (int i = 0; i < parts.Length; i++)
758 { 987 {
759 SceneObjectPart part = parts[i]; 988 SceneObjectPart part = parts[i];
989 if (part.KeyframeMotion != null)
990 {
991 part.KeyframeMotion.UpdateSceneObject(this);
992 }
993
760 if (Object.ReferenceEquals(part, m_rootPart)) 994 if (Object.ReferenceEquals(part, m_rootPart))
761 continue; 995 continue;
762 996
@@ -831,9 +1065,9 @@ namespace OpenSim.Region.Framework.Scenes
831 maxX = -256f; 1065 maxX = -256f;
832 maxY = -256f; 1066 maxY = -256f;
833 maxZ = -256f; 1067 maxZ = -256f;
834 minX = 256f; 1068 minX = 10000f;
835 minY = 256f; 1069 minY = 10000f;
836 minZ = 8192f; 1070 minZ = 10000f;
837 1071
838 SceneObjectPart[] parts = m_parts.GetArray(); 1072 SceneObjectPart[] parts = m_parts.GetArray();
839 for (int i = 0; i < parts.Length; i++) 1073 for (int i = 0; i < parts.Length; i++)
@@ -1085,6 +1319,7 @@ namespace OpenSim.Region.Framework.Scenes
1085 } 1319 }
1086 } 1320 }
1087 1321
1322
1088 /// <summary> 1323 /// <summary>
1089 /// 1324 ///
1090 /// </summary> 1325 /// </summary>
@@ -1220,11 +1455,11 @@ namespace OpenSim.Region.Framework.Scenes
1220 /// <summary> 1455 /// <summary>
1221 /// Delete this group from its scene. 1456 /// Delete this group from its scene.
1222 /// </summary> 1457 /// </summary>
1223 /// 1458 /// <remarks>
1224 /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood 1459 /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood
1225 /// up and all avatars receive notification of its removal. Removal of the scene object from database backup 1460 /// up and all avatars receive notification of its removal. Removal of the scene object from database backup
1226 /// must be handled by the caller. 1461 /// must be handled by the caller.
1227 /// 1462 /// </remarks>
1228 /// <param name="silent">If true then deletion is not broadcast to clients</param> 1463 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1229 public void DeleteGroupFromScene(bool silent) 1464 public void DeleteGroupFromScene(bool silent)
1230 { 1465 {
@@ -1233,10 +1468,10 @@ namespace OpenSim.Region.Framework.Scenes
1233 { 1468 {
1234 SceneObjectPart part = parts[i]; 1469 SceneObjectPart part = parts[i];
1235 1470
1236 Scene.ForEachRootScenePresence(delegate(ScenePresence avatar) 1471 Scene.ForEachScenePresence(sp =>
1237 { 1472 {
1238 if (avatar.ParentID == LocalId) 1473 if (!sp.IsChildAgent && sp.ParentID == part.LocalId)
1239 avatar.StandUp(); 1474 sp.StandUp();
1240 1475
1241 if (!silent) 1476 if (!silent)
1242 { 1477 {
@@ -1244,9 +1479,9 @@ namespace OpenSim.Region.Framework.Scenes
1244 if (part == m_rootPart) 1479 if (part == m_rootPart)
1245 { 1480 {
1246 if (!IsAttachment 1481 if (!IsAttachment
1247 || AttachedAvatar == avatar.ControllingClient.AgentId 1482 || AttachedAvatar == sp.UUID
1248 || !HasPrivateAttachmentPoint) 1483 || !HasPrivateAttachmentPoint)
1249 avatar.ControllingClient.SendKillObject(m_regionHandle, new List<uint> { part.LocalId }); 1484 sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId });
1250 } 1485 }
1251 } 1486 }
1252 }); 1487 });
@@ -1359,7 +1594,7 @@ namespace OpenSim.Region.Framework.Scenes
1359 /// <param name="datastore"></param> 1594 /// <param name="datastore"></param>
1360 public virtual void ProcessBackup(ISimulationDataService datastore, bool forcedBackup) 1595 public virtual void ProcessBackup(ISimulationDataService datastore, bool forcedBackup)
1361 { 1596 {
1362 if (!m_isBackedUp) 1597 if (!Backup)
1363 { 1598 {
1364// m_log.DebugFormat( 1599// m_log.DebugFormat(
1365// "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID); 1600// "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID);
@@ -1421,7 +1656,7 @@ namespace OpenSim.Region.Framework.Scenes
1421 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity; 1656 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity;
1422 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem; 1657 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem;
1423 HasGroupChanged = false; 1658 HasGroupChanged = false;
1424 HasGroupChangedDueToDelink = false; 1659 GroupContainsForeignPrims = false;
1425 1660
1426 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 1661 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
1427 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 1662 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
@@ -1480,31 +1715,14 @@ namespace OpenSim.Region.Framework.Scenes
1480 /// <returns></returns> 1715 /// <returns></returns>
1481 public SceneObjectGroup Copy(bool userExposed) 1716 public SceneObjectGroup Copy(bool userExposed)
1482 { 1717 {
1718 // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up
1719 // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator
1720 // but not between regions on different simulators). Really, all copying should be done explicitly.
1483 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 1721 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1484 dupe.m_isBackedUp = false;
1485 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1486
1487 // Warning, The following code related to previousAttachmentStatus is needed so that clones of
1488 // attachments do not bordercross while they're being duplicated. This is hacktastic!
1489 // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
1490 // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
1491 // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
1492 // then restore it's attachment state
1493
1494 // This is only necessary when userExposed is false!
1495
1496 bool previousAttachmentStatus = dupe.IsAttachment;
1497
1498 if (!userExposed)
1499 dupe.IsAttachment = true;
1500
1501 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1502
1503 if (!userExposed)
1504 {
1505 dupe.IsAttachment = previousAttachmentStatus;
1506 }
1507 1722
1723 dupe.Backup = false;
1724 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1725 dupe.m_sittingAvatars = new List<ScenePresence>();
1508 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 1726 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1509 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 1727 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1510 1728
@@ -1550,6 +1768,8 @@ namespace OpenSim.Region.Framework.Scenes
1550 1768
1551 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 1769 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true);
1552 } 1770 }
1771 if (part.KeyframeMotion != null)
1772 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1553 } 1773 }
1554 1774
1555 if (userExposed) 1775 if (userExposed)
@@ -1577,6 +1797,12 @@ namespace OpenSim.Region.Framework.Scenes
1577 1797
1578 public void ScriptSetPhysicsStatus(bool usePhysics) 1798 public void ScriptSetPhysicsStatus(bool usePhysics)
1579 { 1799 {
1800 if (usePhysics)
1801 {
1802 if (RootPart.KeyframeMotion != null)
1803 RootPart.KeyframeMotion.Stop();
1804 RootPart.KeyframeMotion = null;
1805 }
1580 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 1806 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1581 } 1807 }
1582 1808
@@ -1674,15 +1900,14 @@ namespace OpenSim.Region.Framework.Scenes
1674 return Vector3.Zero; 1900 return Vector3.Zero;
1675 } 1901 }
1676 1902
1677 public void moveToTarget(Vector3 target, float tau) 1903 public void MoveToTarget(Vector3 target, float tau)
1678 { 1904 {
1679 if (IsAttachment) 1905 if (IsAttachment)
1680 { 1906 {
1681 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); 1907 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1908
1682 if (avatar != null) 1909 if (avatar != null)
1683 {
1684 avatar.MoveToTarget(target, false, false); 1910 avatar.MoveToTarget(target, false, false);
1685 }
1686 } 1911 }
1687 else 1912 else
1688 { 1913 {
@@ -1697,12 +1922,26 @@ namespace OpenSim.Region.Framework.Scenes
1697 } 1922 }
1698 } 1923 }
1699 1924
1700 public void stopMoveToTarget() 1925 public void StopMoveToTarget()
1701 { 1926 {
1702 PhysicsActor pa = RootPart.PhysActor; 1927 if (IsAttachment)
1928 {
1929 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1703 1930
1704 if (pa != null) 1931 if (avatar != null)
1705 pa.PIDActive = false; 1932 avatar.ResetMoveToTarget();
1933 }
1934 else
1935 {
1936 PhysicsActor pa = RootPart.PhysActor;
1937
1938 if (pa != null && pa.PIDActive)
1939 {
1940 pa.PIDActive = false;
1941
1942 ScheduleGroupForTerseUpdate();
1943 }
1944 }
1706 } 1945 }
1707 1946
1708 /// <summary> 1947 /// <summary>
@@ -2175,7 +2414,9 @@ namespace OpenSim.Region.Framework.Scenes
2175// objectGroup.m_rootPart = null; 2414// objectGroup.m_rootPart = null;
2176 2415
2177 // If linking prims with different permissions, fix them 2416 // If linking prims with different permissions, fix them
2178 AdjustChildPrimPermissions(); 2417 AdjustChildPrimPermissions(false);
2418
2419 GroupContainsForeignPrims = true;
2179 2420
2180 AttachToBackup(); 2421 AttachToBackup();
2181 2422
@@ -2320,9 +2561,16 @@ namespace OpenSim.Region.Framework.Scenes
2320 2561
2321 linkPart.Rezzed = RootPart.Rezzed; 2562 linkPart.Rezzed = RootPart.Rezzed;
2322 2563
2323 // When we delete a group, we currently have to force persist to the database if the object id has changed 2564 // We must persist the delinked group to the database immediately, for safety. The problem
2324 // (since delete works by deleting all rows which have a given object id) 2565 // is that although in memory the new group has a new SceneGroupID, in the database it
2325 objectGroup.HasGroupChangedDueToDelink = true; 2566 // still has the parent group's SceneGroupID (until the next backup). This means that if the
2567 // parent group is deleted then the delinked group will also be deleted from the database.
2568 // This problem will disappear if the region remains alive long enough for another backup,
2569 // since at that time the delinked group's new SceneGroupID will be written to the database.
2570 // But if the region crashes before that then the prims will be permanently gone, and this must
2571 // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case
2572 // because the delinked group doesn't know when the source group is deleted.)
2573 m_scene.ForceSceneObjectBackup(objectGroup);
2326 2574
2327 return objectGroup; 2575 return objectGroup;
2328 } 2576 }
@@ -2333,10 +2581,10 @@ namespace OpenSim.Region.Framework.Scenes
2333 /// <param name="objectGroup"></param> 2581 /// <param name="objectGroup"></param>
2334 public virtual void DetachFromBackup() 2582 public virtual void DetachFromBackup()
2335 { 2583 {
2336 if (m_isBackedUp && Scene != null) 2584 if (Backup && Scene != null)
2337 m_scene.EventManager.OnBackup -= ProcessBackup; 2585 m_scene.EventManager.OnBackup -= ProcessBackup;
2338 2586
2339 m_isBackedUp = false; 2587 Backup = false;
2340 } 2588 }
2341 2589
2342 // This links an SOP from a previous linkset into my linkset. 2590 // This links an SOP from a previous linkset into my linkset.
@@ -2396,20 +2644,26 @@ namespace OpenSim.Region.Framework.Scenes
2396 /// If object is physical, apply force to move it around 2644 /// If object is physical, apply force to move it around
2397 /// If object is not physical, just put it at the resulting location 2645 /// If object is not physical, just put it at the resulting location
2398 /// </summary> 2646 /// </summary>
2647 /// <param name="partID">Part ID to check for grab</param>
2399 /// <param name="offset">Always seems to be 0,0,0, so ignoring</param> 2648 /// <param name="offset">Always seems to be 0,0,0, so ignoring</param>
2400 /// <param name="pos">New position. We do the math here to turn it into a force</param> 2649 /// <param name="pos">New position. We do the math here to turn it into a force</param>
2401 /// <param name="remoteClient"></param> 2650 /// <param name="remoteClient"></param>
2402 public void GrabMovement(Vector3 offset, Vector3 pos, IClientAPI remoteClient) 2651 public void GrabMovement(UUID partID, Vector3 offset, Vector3 pos, IClientAPI remoteClient)
2403 { 2652 {
2404 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 2653 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2405 { 2654 {
2655 SceneObjectPart part = GetPart(partID);
2656
2657 if (part == null)
2658 return;
2659
2406 PhysicsActor pa = m_rootPart.PhysActor; 2660 PhysicsActor pa = m_rootPart.PhysActor;
2407 2661
2408 if (pa != null) 2662 if (pa != null)
2409 { 2663 {
2410 if (pa.IsPhysical) 2664 if (pa.IsPhysical)
2411 { 2665 {
2412 if (!m_rootPart.BlockGrab) 2666 if (!BlockGrabOverride && !part.BlockGrab)
2413 { 2667 {
2414 Vector3 llmoveforce = pos - AbsolutePosition; 2668 Vector3 llmoveforce = pos - AbsolutePosition;
2415 Vector3 grabforce = llmoveforce; 2669 Vector3 grabforce = llmoveforce;
@@ -2420,20 +2674,27 @@ namespace OpenSim.Region.Framework.Scenes
2420 } 2674 }
2421 else 2675 else
2422 { 2676 {
2423 //NonPhysicalGrabMovement(pos); 2677 NonPhysicalGrabMovement(pos);
2424 } 2678 }
2425 } 2679 }
2426 else 2680 else
2427 { 2681 {
2428 //NonPhysicalGrabMovement(pos); 2682 NonPhysicalGrabMovement(pos);
2429 } 2683 }
2430 } 2684 }
2431 } 2685 }
2432 2686
2687 /// <summary>
2688 /// Apply possition for grabbing non-physical linksets (Ctrl+Drag)
2689 /// This MUST be blocked for linksets that contain touch scripts because the viewer triggers grab on the touch
2690 /// event (Viewer Bug?) This would allow anyone to drag a linkset with a touch script. SL behaviour is also to
2691 /// block grab on prims with touch events.
2692 /// </summary>
2693 /// <param name="pos">New Position</param>
2433 public void NonPhysicalGrabMovement(Vector3 pos) 2694 public void NonPhysicalGrabMovement(Vector3 pos)
2434 { 2695 {
2435 AbsolutePosition = pos; 2696 if(!IsAttachment && ScriptCount() == 0)
2436 m_rootPart.SendTerseUpdateToAllClients(); 2697 UpdateGroupPosition(pos);
2437 } 2698 }
2438 2699
2439 /// <summary> 2700 /// <summary>
@@ -2529,17 +2790,28 @@ namespace OpenSim.Region.Framework.Scenes
2529 } 2790 }
2530 else 2791 else
2531 { 2792 {
2532 //NonPhysicalSpinMovement(pos); 2793 NonPhysicalSpinMovement(newOrientation);
2533 } 2794 }
2534 } 2795 }
2535 else 2796 else
2536 { 2797 {
2537 //NonPhysicalSpinMovement(pos); 2798 NonPhysicalSpinMovement(newOrientation);
2538 } 2799 }
2539 } 2800 }
2540 } 2801 }
2541 2802
2542 /// <summary> 2803 /// <summary>
2804 /// Apply rotation for spinning non-physical linksets (Ctrl+Shift+Drag)
2805 /// As with dragging, scripted objects must be blocked from spinning
2806 /// </summary>
2807 /// <param name="newOrientation">New Rotation</param>
2808 private void NonPhysicalSpinMovement(Quaternion newOrientation)
2809 {
2810 if(!IsAttachment && ScriptCount() == 0)
2811 UpdateGroupRotationR(newOrientation);
2812 }
2813
2814 /// <summary>
2543 /// Set the name of a prim 2815 /// Set the name of a prim
2544 /// </summary> 2816 /// </summary>
2545 /// <param name="name"></param> 2817 /// <param name="name"></param>
@@ -2612,12 +2884,22 @@ namespace OpenSim.Region.Framework.Scenes
2612 { 2884 {
2613 SceneObjectPart selectionPart = GetPart(localID); 2885 SceneObjectPart selectionPart = GetPart(localID);
2614 2886
2615 if (SetTemporary && Scene != null) 2887 if (Scene != null)
2616 { 2888 {
2617 DetachFromBackup(); 2889 if (SetTemporary)
2618 // Remove from database and parcel prim count 2890 {
2619 // 2891 DetachFromBackup();
2620 m_scene.DeleteFromStorage(UUID); 2892 // Remove from database and parcel prim count
2893 //
2894 m_scene.DeleteFromStorage(UUID);
2895 }
2896 else if (!Backup)
2897 {
2898 // Previously been temporary now switching back so make it
2899 // available for persisting again
2900 AttachToBackup();
2901 }
2902
2621 m_scene.EventManager.TriggerParcelPrimCountTainted(); 2903 m_scene.EventManager.TriggerParcelPrimCountTainted();
2622 } 2904 }
2623 2905
@@ -2668,13 +2950,29 @@ namespace OpenSim.Region.Framework.Scenes
2668 } 2950 }
2669 } 2951 }
2670 2952
2671 public void AdjustChildPrimPermissions() 2953 public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive)
2672 { 2954 {
2955 uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits
2956 uint foldedPerms = RootPart.OwnerMask & 3;
2957
2673 ForEachPart(part => 2958 ForEachPart(part =>
2674 { 2959 {
2960 newOwnerMask &= part.BaseMask;
2675 if (part != RootPart) 2961 if (part != RootPart)
2676 part.ClonePermissions(RootPart); 2962 part.ClonePermissions(RootPart);
2963 if (forceTaskInventoryPermissive)
2964 part.Inventory.ApplyGodPermissions(part.BaseMask);
2677 }); 2965 });
2966
2967 uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify);
2968 uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify);
2969 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
2970
2971// m_log.DebugFormat(
2972// "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}",
2973// (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name);
2974
2975 RootPart.ScheduleFullUpdate();
2678 } 2976 }
2679 2977
2680 public void UpdatePermissions(UUID AgentID, byte field, uint localID, 2978 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
@@ -2682,7 +2980,7 @@ namespace OpenSim.Region.Framework.Scenes
2682 { 2980 {
2683 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 2981 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2684 2982
2685 AdjustChildPrimPermissions(); 2983 AdjustChildPrimPermissions(Scene.Permissions.IsGod(AgentID));
2686 2984
2687 HasGroupChanged = true; 2985 HasGroupChanged = true;
2688 2986
@@ -3000,8 +3298,8 @@ namespace OpenSim.Region.Framework.Scenes
3000 /// <summary> 3298 /// <summary>
3001 /// Update just the root prim position in a linkset 3299 /// Update just the root prim position in a linkset
3002 /// </summary> 3300 /// </summary>
3003 /// <param name="pos"></param> 3301 /// <param name="newPos"></param>
3004 public void UpdateRootPosition(Vector3 pos) 3302 public void UpdateRootPosition(Vector3 newPos)
3005 { 3303 {
3006// m_log.DebugFormat( 3304// m_log.DebugFormat(
3007// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos); 3305// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
@@ -3010,16 +3308,16 @@ namespace OpenSim.Region.Framework.Scenes
3010// for (int i = 0; i < parts.Length; i++) 3308// for (int i = 0; i < parts.Length; i++)
3011// parts[i].StoreUndoState(); 3309// parts[i].StoreUndoState();
3012 3310
3013 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z); 3311 Vector3 oldPos;
3014 Vector3 oldPos = 3312
3015 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X, 3313 if (IsAttachment)
3016 AbsolutePosition.Y + m_rootPart.OffsetPosition.Y, 3314 oldPos = m_rootPart.AttachedPos + m_rootPart.OffsetPosition; // OffsetPosition should always be 0 in an attachments's root prim
3017 AbsolutePosition.Z + m_rootPart.OffsetPosition.Z); 3315 else
3316 oldPos = AbsolutePosition + m_rootPart.OffsetPosition;
3317
3018 Vector3 diff = oldPos - newPos; 3318 Vector3 diff = oldPos - newPos;
3019 Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z);
3020 Quaternion partRotation = m_rootPart.RotationOffset; 3319 Quaternion partRotation = m_rootPart.RotationOffset;
3021 axDiff *= Quaternion.Inverse(partRotation); 3320 diff *= Quaternion.Inverse(partRotation);
3022 diff = axDiff;
3023 3321
3024 SceneObjectPart[] parts = m_parts.GetArray(); 3322 SceneObjectPart[] parts = m_parts.GetArray();
3025 for (int i = 0; i < parts.Length; i++) 3323 for (int i = 0; i < parts.Length; i++)
@@ -3030,6 +3328,9 @@ namespace OpenSim.Region.Framework.Scenes
3030 } 3328 }
3031 3329
3032 AbsolutePosition = newPos; 3330 AbsolutePosition = newPos;
3331
3332 if (IsAttachment)
3333 m_rootPart.AttachedPos = newPos;
3033 3334
3034 HasGroupChanged = true; 3335 HasGroupChanged = true;
3035 ScheduleGroupForTerseUpdate(); 3336 ScheduleGroupForTerseUpdate();
@@ -3583,10 +3884,10 @@ namespace OpenSim.Region.Framework.Scenes
3583 /// down after it move one place down the list. 3884 /// down after it move one place down the list.
3584 /// </remarks> 3885 /// </remarks>
3585 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns> 3886 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
3586 public List<UUID> GetSittingAvatars() 3887 public List<ScenePresence> GetSittingAvatars()
3587 { 3888 {
3588 lock (m_sittingAvatars) 3889 lock (m_sittingAvatars)
3589 return new List<UUID>(m_sittingAvatars); 3890 return new List<ScenePresence>(m_sittingAvatars);
3590 } 3891 }
3591 3892
3592 /// <summary> 3893 /// <summary>