diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 509 |
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; | |||
38 | using OpenMetaverse.Packets; | 38 | using OpenMetaverse.Packets; |
39 | using OpenSim.Framework; | 39 | using OpenSim.Framework; |
40 | using OpenSim.Region.Framework.Interfaces; | 40 | using OpenSim.Region.Framework.Interfaces; |
41 | using OpenSim.Region.Physics.Manager; | 41 | using OpenSim.Region.PhysicsModules.SharedBase; |
42 | using OpenSim.Region.Framework.Scenes.Serialization; | 42 | using OpenSim.Region.Framework.Scenes.Serialization; |
43 | using PermissionMask = OpenSim.Framework.PermissionMask; | ||
44 | using OpenSim.Services.Interfaces; | ||
43 | 45 | ||
44 | namespace OpenSim.Region.Framework.Scenes | 46 | namespace 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> |