diff options
Diffstat (limited to 'OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs')
-rw-r--r-- | OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 1803 |
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 | ||
28 | using System; | 28 | using System; |
29 | using System.ComponentModel; | 29 | using System.ComponentModel; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Drawing; | 31 | using System.Drawing; |
32 | using System.IO; | 32 | using System.IO; |
33 | using System.Diagnostics; | ||
33 | using System.Linq; | 34 | using System.Linq; |
34 | using System.Threading; | 35 | using System.Threading; |
35 | using System.Xml; | 36 | using System.Xml; |
@@ -44,6 +45,7 @@ using PermissionMask = OpenSim.Framework.PermissionMask; | |||
44 | 45 | ||
45 | namespace OpenSim.Region.Framework.Scenes | 46 | namespace 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 | } |