aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs3160
1 files changed, 2385 insertions, 775 deletions
diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
index d08237e..21311b0 100644
--- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
+++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs
@@ -30,6 +30,7 @@ using System.ComponentModel;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Drawing; 31using System.Drawing;
32using System.IO; 32using System.IO;
33using System.Diagnostics;
33using System.Linq; 34using System.Linq;
34using System.Threading; 35using System.Threading;
35using System.Xml; 36using System.Xml;
@@ -45,6 +46,7 @@ using OpenSim.Services.Interfaces;
45 46
46namespace OpenSim.Region.Framework.Scenes 47namespace OpenSim.Region.Framework.Scenes
47{ 48{
49
48 [Flags] 50 [Flags]
49 public enum scriptEvents 51 public enum scriptEvents
50 { 52 {
@@ -77,17 +79,18 @@ namespace OpenSim.Region.Framework.Scenes
77 touch_end = 536870912, 79 touch_end = 536870912,
78 touch_start = 2097152, 80 touch_start = 2097152,
79 transaction_result = 33554432, 81 transaction_result = 33554432,
80 object_rez = 4194304 82 object_rez = 4194304,
83 anytouch = touch | touch_end | touch_start
81 } 84 }
82 85
83 struct scriptPosTarget 86 public struct scriptPosTarget
84 { 87 {
85 public Vector3 targetPos; 88 public Vector3 targetPos;
86 public float tolerance; 89 public float tolerance;
87 public uint handle; 90 public uint handle;
88 } 91 }
89 92
90 struct scriptRotTarget 93 public struct scriptRotTarget
91 { 94 {
92 public Quaternion targetRot; 95 public Quaternion targetRot;
93 public float tolerance; 96 public float tolerance;
@@ -109,11 +112,11 @@ namespace OpenSim.Region.Framework.Scenes
109 STATUS_ROTATE_X = 0x002, 112 STATUS_ROTATE_X = 0x002,
110 STATUS_ROTATE_Y = 0x004, 113 STATUS_ROTATE_Y = 0x004,
111 STATUS_ROTATE_Z = 0x008, 114 STATUS_ROTATE_Z = 0x008,
115 NOT_STATUS_ROTATE_X = 0xFD,
116 NOT_STATUS_ROTATE_Y = 0xFB,
117 NOT_STATUS_ROTATE_Z = 0xF7
112 } 118 }
113 119
114 // This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm
115 public static readonly uint SLAM = 16;
116
117 // private PrimCountTaintedDelegate handlerPrimCountTainted = null; 120 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
118 121
119 /// <summary> 122 /// <summary>
@@ -121,8 +124,11 @@ namespace OpenSim.Region.Framework.Scenes
121 /// since the group's last persistent backup 124 /// since the group's last persistent backup
122 /// </summary> 125 /// </summary>
123 private bool m_hasGroupChanged = false; 126 private bool m_hasGroupChanged = false;
124 private long timeFirstChanged; 127 private long timeFirstChanged = 0;
125 private long timeLastChanged; 128 private long timeLastChanged = 0;
129 private long m_maxPersistTime = 0;
130 private long m_minPersistTime = 0;
131// private Random m_rand;
126 132
127 /// <summary> 133 /// <summary>
128 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage 134 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
@@ -139,12 +145,47 @@ namespace OpenSim.Region.Framework.Scenes
139 { 145 {
140 if (value) 146 if (value)
141 { 147 {
142 timeLastChanged = DateTime.Now.Ticks; 148
149 if (Backup)
150 {
151 m_scene.SceneGraph.FireChangeBackup(this);
152 }
153 timeLastChanged = DateTime.UtcNow.Ticks;
143 if (!m_hasGroupChanged) 154 if (!m_hasGroupChanged)
144 timeFirstChanged = DateTime.Now.Ticks; 155 timeFirstChanged = DateTime.UtcNow.Ticks;
156 if (m_rootPart != null && m_scene != null)
157 {
158/*
159 if (m_rand == null)
160 {
161 byte[] val = new byte[16];
162 m_rootPart.UUID.ToBytes(val, 0);
163 m_rand = new Random(BitConverter.ToInt32(val, 0));
164 }
165 */
166 if (m_scene.GetRootAgentCount() == 0)
167 {
168 //If the region is empty, this change has been made by an automated process
169 //and thus we delay the persist time by a random amount between 1.5 and 2.5.
170
171// float factor = 1.5f + (float)(m_rand.NextDouble());
172 float factor = 2.0f;
173 m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
174 m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
175 }
176 else
177 {
178 //If the region is not empty, we want to obey the minimum and maximum persist times
179 //but add a random factor so we stagger the object persistance a little
180// m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
181// m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
182 m_maxPersistTime = m_scene.m_persistAfter;
183 m_minPersistTime = m_scene.m_dontPersistBefore;
184 }
185 }
145 } 186 }
146 m_hasGroupChanged = value; 187 m_hasGroupChanged = value;
147 188
148// m_log.DebugFormat( 189// m_log.DebugFormat(
149// "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId); 190// "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId);
150 } 191 }
@@ -153,7 +194,7 @@ namespace OpenSim.Region.Framework.Scenes
153 } 194 }
154 195
155 private bool m_groupContainsForeignPrims = false; 196 private bool m_groupContainsForeignPrims = false;
156 197
157 /// <summary> 198 /// <summary>
158 /// Whether the group contains prims that came from a different group. This happens when 199 /// Whether the group contains prims that came from a different group. This happens when
159 /// linking or delinking groups. The implication is that until the group is persisted, 200 /// linking or delinking groups. The implication is that until the group is persisted,
@@ -172,6 +213,7 @@ namespace OpenSim.Region.Framework.Scenes
172 get { return m_groupContainsForeignPrims; } 213 get { return m_groupContainsForeignPrims; }
173 } 214 }
174 215
216 public bool HasGroupChangedDueToDelink { get; set; }
175 217
176 private bool isTimeToPersist() 218 private bool isTimeToPersist()
177 { 219 {
@@ -181,8 +223,19 @@ namespace OpenSim.Region.Framework.Scenes
181 return false; 223 return false;
182 if (m_scene.ShuttingDown) 224 if (m_scene.ShuttingDown)
183 return true; 225 return true;
184 long currentTime = DateTime.Now.Ticks; 226
185 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter) 227 if (m_minPersistTime == 0 || m_maxPersistTime == 0)
228 {
229 m_maxPersistTime = m_scene.m_persistAfter;
230 m_minPersistTime = m_scene.m_dontPersistBefore;
231 }
232
233 long currentTime = DateTime.UtcNow.Ticks;
234
235 if (timeLastChanged == 0) timeLastChanged = currentTime;
236 if (timeFirstChanged == 0) timeFirstChanged = currentTime;
237
238 if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
186 return true; 239 return true;
187 return false; 240 return false;
188 } 241 }
@@ -240,6 +293,11 @@ namespace OpenSim.Region.Framework.Scenes
240 { 293 {
241 AttachmentPoint = 0; 294 AttachmentPoint = 0;
242 295
296 // Don't zap trees
297 if (RootPart.Shape.PCode == (byte)PCode.Tree ||
298 RootPart.Shape.PCode == (byte)PCode.NewTree)
299 return;
300
243 // Even though we don't use child part state parameters for attachments any more, we still need to set 301 // Even though we don't use child part state parameters for attachments any more, we still need to set
244 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if 302 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
245 // we store them correctly, scene objects that we receive from elsewhere might not. 303 // we store them correctly, scene objects that we receive from elsewhere might not.
@@ -269,6 +327,7 @@ namespace OpenSim.Region.Framework.Scenes
269 get { return (RootPart.Flags & PrimFlags.Physics) != 0; } 327 get { return (RootPart.Flags & PrimFlags.Physics) != 0; }
270 } 328 }
271 329
330
272 /// <summary> 331 /// <summary>
273 /// Is this scene object temporary? 332 /// Is this scene object temporary?
274 /// </summary> 333 /// </summary>
@@ -285,9 +344,6 @@ namespace OpenSim.Region.Framework.Scenes
285 get { return RootPart.VolumeDetectActive; } 344 get { return RootPart.VolumeDetectActive; }
286 } 345 }
287 346
288 private Vector3 lastPhysGroupPos;
289 private Quaternion lastPhysGroupRot;
290
291 /// <summary> 347 /// <summary>
292 /// Is this entity set to be saved in persistent storage? 348 /// Is this entity set to be saved in persistent storage?
293 /// </summary> 349 /// </summary>
@@ -299,17 +355,29 @@ namespace OpenSim.Region.Framework.Scenes
299 protected SceneObjectPart m_rootPart; 355 protected SceneObjectPart m_rootPart;
300 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>(); 356 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
301 357
302 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>(); 358 private SortedDictionary<uint, scriptPosTarget> m_targets = new SortedDictionary<uint, scriptPosTarget>();
303 private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>(); 359 private SortedDictionary<uint, scriptRotTarget> m_rotTargets = new SortedDictionary<uint, scriptRotTarget>();
360
361 public SortedDictionary<uint, scriptPosTarget> AtTargets
362 {
363 get { return m_targets; }
364 }
365
366 public SortedDictionary<uint, scriptRotTarget> RotTargets
367 {
368 get { return m_rotTargets; }
369 }
304 370
305 private bool m_scriptListens_atTarget; 371 private bool m_scriptListens_atTarget;
306 private bool m_scriptListens_notAtTarget; 372 private bool m_scriptListens_notAtTarget;
307
308 private bool m_scriptListens_atRotTarget; 373 private bool m_scriptListens_atRotTarget;
309 private bool m_scriptListens_notAtRotTarget; 374 private bool m_scriptListens_notAtRotTarget;
310 375
376 public bool m_dupeInProgress = false;
311 internal Dictionary<UUID, string> m_savedScriptState; 377 internal Dictionary<UUID, string> m_savedScriptState;
312 378
379 public UUID MonitoringObject { get; set; }
380
313 #region Properties 381 #region Properties
314 382
315 /// <summary> 383 /// <summary>
@@ -344,6 +412,16 @@ namespace OpenSim.Region.Framework.Scenes
344 get { return m_parts.Count; } 412 get { return m_parts.Count; }
345 } 413 }
346 414
415// protected Quaternion m_rotation = Quaternion.Identity;
416//
417// public virtual Quaternion Rotation
418// {
419// get { return m_rotation; }
420// set {
421// m_rotation = value;
422// }
423// }
424
347 public Quaternion GroupRotation 425 public Quaternion GroupRotation
348 { 426 {
349 get { return m_rootPart.RotationOffset; } 427 get { return m_rootPart.RotationOffset; }
@@ -356,27 +434,27 @@ namespace OpenSim.Region.Framework.Scenes
356 Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize); 434 Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
357 Vector3 maxScale = Vector3.Zero; 435 Vector3 maxScale = Vector3.Zero;
358 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f); 436 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
359 437
360 SceneObjectPart[] parts = m_parts.GetArray(); 438 SceneObjectPart[] parts = m_parts.GetArray();
361 for (int i = 0; i < parts.Length; i++) 439 for (int i = 0; i < parts.Length; i++)
362 { 440 {
363 SceneObjectPart part = parts[i]; 441 SceneObjectPart part = parts[i];
364 Vector3 partscale = part.Scale; 442 Vector3 partscale = part.Scale;
365 Vector3 partoffset = part.OffsetPosition; 443 Vector3 partoffset = part.OffsetPosition;
366 444
367 minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X; 445 minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X;
368 minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y; 446 minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y;
369 minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z; 447 minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z;
370 448
371 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X; 449 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
372 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y; 450 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
373 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z; 451 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
374 } 452 }
375 453
376 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X; 454 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
377 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y; 455 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
378 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z; 456 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
379 457
380 return finalScale; 458 return finalScale;
381 } 459 }
382 } 460 }
@@ -441,7 +519,7 @@ namespace OpenSim.Region.Framework.Scenes
441 /// <remarks> 519 /// <remarks>
442 /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't 520 /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't
443 /// have the IsAttachment property yet checked. 521 /// have the IsAttachment property yet checked.
444 /// 522 ///
445 /// FIXME: However, this should be fixed so that this property 523 /// FIXME: However, this should be fixed so that this property
446 /// propertly reflects the underlying status. 524 /// propertly reflects the underlying status.
447 /// </remarks> 525 /// </remarks>
@@ -451,13 +529,17 @@ namespace OpenSim.Region.Framework.Scenes
451 return (IsAttachment || 529 return (IsAttachment ||
452 (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0)); 530 (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0));
453 } 531 }
454 532
455 private struct avtocrossInfo 533 private struct avtocrossInfo
456 { 534 {
457 public ScenePresence av; 535 public ScenePresence av;
458 public uint ParentID; 536 public uint ParentID;
459 } 537 }
460 538
539
540 public bool inTransit = false;
541 private delegate SceneObjectGroup SOGCrossDelegate(SceneObjectGroup sog,Vector3 pos, TeleportObjectData tpData);
542
461 /// <summary> 543 /// <summary>
462 /// The absolute position of this scene object in the scene 544 /// The absolute position of this scene object in the scene
463 /// </summary> 545 /// </summary>
@@ -467,205 +549,547 @@ namespace OpenSim.Region.Framework.Scenes
467 set 549 set
468 { 550 {
469 Vector3 val = value; 551 Vector3 val = value;
552 if (Scene != null
553 && !Scene.PositionIsInCurrentRegion(val)
554 && !IsAttachmentCheckFull()
555 && !Scene.LoadingPrims
556 && !Scene.DisableObjectTransfer
557 )
558 {
559 if (!inTransit)
560 {
561 inTransit = true;
562 SOGCrossDelegate d = CrossAsync;
563 d.BeginInvoke(this, val, null, CrossAsyncCompleted, d);
564 }
565 return;
566 }
567
568 if (RootPart.GetStatusSandbox())
569 {
570 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
571 {
572 RootPart.ScriptSetPhysicsStatus(false);
573
574 if (Scene != null)
575 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
576 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
577
578 return;
579 }
580 }
581
582 bool triggerScriptEvent = m_rootPart.GroupPosition != val;
583 if (m_dupeInProgress || IsDeleted)
584 triggerScriptEvent = false;
585
586 m_rootPart.GroupPosition = val;
587
588 // Restuff the new GroupPosition into each child SOP of the linkset.
589 // this is needed because physics may not have linksets but just loose SOPs in world
590
591 SceneObjectPart[] parts = m_parts.GetArray();
592
593 foreach (SceneObjectPart part in parts)
594 {
595 if (part != m_rootPart)
596 part.GroupPosition = val;
597 }
598
599 foreach (ScenePresence av in m_sittingAvatars)
600 {
601 av.sitSOGmoved();
602 }
603
604 // now that position is changed tell it to scripts
605 if (triggerScriptEvent)
606 {
607 foreach (SceneObjectPart part in parts)
608 {
609 part.TriggerScriptChangedEvent(Changed.POSITION);
610 }
611 }
470 612
471 if (Scene != null) 613 if (Scene != null)
614 Scene.EventManager.TriggerParcelPrimCountTainted();
615
616 }
617 }
618
619 private SceneObjectGroup CrossAsync(SceneObjectGroup sog, Vector3 val, TeleportObjectData tpdata)
620 {
621 Scene sogScene = sog.m_scene;
622 SceneObjectPart root = sog.RootPart;
623
624 bool isTeleport = tpdata != null;
625
626 if(!isTeleport)
627 {
628 if (root.DIE_AT_EDGE)
472 { 629 {
473 if ( 630 try
474 !Scene.PositionIsInCurrentRegion(val)
475 && !IsAttachmentCheckFull()
476 && (!Scene.LoadingPrims)
477 )
478 { 631 {
479 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>(); 632 sogScene.DeleteSceneObject(sog, false);
480 EntityTransferContext ctx = new EntityTransferContext(); 633 }
481 Vector3 newpos = Vector3.Zero; 634 catch (Exception)
482 string failureReason = String.Empty; 635 {
483 OpenSim.Services.Interfaces.GridRegion destination = null; 636 m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border.");
637 }
638 return sog;
639 }
484 640
485 if (m_rootPart.KeyframeMotion != null) 641 if (root.RETURN_AT_EDGE)
486 m_rootPart.KeyframeMotion.StartCrossingCheck(); 642 {
643 // We remove the object here
644 try
645 {
646 List<uint> localIDs = new List<uint>();
647 localIDs.Add(root.LocalId);
648 sogScene.AddReturn(sog.OwnerID, sog.Name, sog.AbsolutePosition,
649 "Returned at region cross");
650 sogScene.DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, UUID.Zero, false);
651 }
652 catch (Exception)
653 {
654 m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border.");
655 }
656 return sog;
657 }
658 }
487 659
488 bool canCross = true; 660// if(!m_scene.IsRunning)
489 foreach (ScenePresence av in GetSittingAvatars()) 661// return sog;
490 {
491 // We need to cross these agents. First, let's find
492 // out if any of them can't cross for some reason.
493 // We have to deny the crossing entirely if any
494 // of them are banned. Alternatively, we could
495 // unsit banned agents....
496 662
663 if (root.KeyframeMotion != null)
664 root.KeyframeMotion.StartCrossingCheck();
497 665
498 // We set the avatar position as being the object 666 if(root.PhysActor != null)
499 // position to get the region to send to 667 root.PhysActor.CrossingStart();
500 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, ctx, out newpos, out failureReason)) == null)
501 {
502 canCross = false;
503 break;
504 }
505 668
506 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName); 669 IEntityTransferModule entityTransfer = sogScene.RequestModuleInterface<IEntityTransferModule>();
507 }
508 670
509 if (canCross) 671 if (entityTransfer == null)
510 { 672 return sog;
511 // We unparent the SP quietly so that it won't
512 // be made to stand up
513 673
514 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>(); 674 Vector3 newpos = Vector3.Zero;
675 OpenSim.Services.Interfaces.GridRegion destination = null;
515 676
516 foreach (ScenePresence av in GetSittingAvatars()) 677 destination = entityTransfer.GetObjectDestination(sog, val, out newpos);
517 { 678 if (destination == null)
518 avtocrossInfo avinfo = new avtocrossInfo(); 679 return sog;
519 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
520 if (parentPart != null)
521 av.ParentUUID = parentPart.UUID;
522 680
523 avinfo.av = av; 681 if (sog.m_sittingAvatars.Count == 0)
524 avinfo.ParentID = av.ParentID; 682 {
525 avsToCross.Add(avinfo); 683 entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, !isTeleport, true);
684 return sog;
685 }
526 686
527 av.PrevSitOffset = av.OffsetPosition; 687 string reason = String.Empty;
528 av.ParentID = 0; 688 EntityTransferContext ctx = new EntityTransferContext();
529 }
530 689
531 m_scene.CrossPrimGroupIntoNewRegion(val, this, true); 690 Vector3 curPos = root.GroupPosition;
691 foreach (ScenePresence av in sog.m_sittingAvatars)
692 {
693 // We need to cross these agents. First, let's find
694 // out if any of them can't cross for some reason.
695 // We have to deny the crossing entirely if any
696 // of them are banned. Alternatively, we could
697 // unsit banned agents....
698
699 // We set the avatar position as being the object
700 // position to get the region to send to
701 if(av.IsNPC)
702 continue;
532 703
533 // Normalize 704 if(av.IsInTransit)
534 if (val.X >= m_scene.RegionInfo.RegionSizeX) 705 return sog;
535 val.X -= m_scene.RegionInfo.RegionSizeX;
536 if (val.Y >= m_scene.RegionInfo.RegionSizeY)
537 val.Y -= m_scene.RegionInfo.RegionSizeY;
538 if (val.X < 0)
539 val.X += m_scene.RegionInfo.RegionSizeX;
540 if (val.Y < 0)
541 val.Y += m_scene.RegionInfo.RegionSizeY;
542 706
543 // If it's deleted, crossing was successful 707 if(!entityTransfer.checkAgentAccessToRegion(av, destination, newpos, ctx, out reason))
544 if (IsDeleted) 708 return sog;
545 {
546 foreach (avtocrossInfo avinfo in avsToCross)
547 {
548 ScenePresence av = avinfo.av;
549 if (!av.IsInTransit) // just in case...
550 {
551 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
552
553 av.IsInTransit = true;
554
555 // A temporary measure to allow regression tests to work.
556 // Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget
557 // or similar since BeginInvoke() always uses the system threadpool to launch
558 // threads rather than any replace threadpool that we might be using.
559 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
560 {
561 entityTransfer.CrossAgentToNewRegionAsync(av, val, destination, av.Flying, ctx);
562 CrossAgentToNewRegionCompleted(av);
563 }
564 else
565 {
566 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
567 d.BeginInvoke(
568 av, val, destination, av.Flying, ctx,
569 ar => CrossAgentToNewRegionCompleted(d.EndInvoke(ar)), null);
570 }
571 }
572 else
573 {
574 m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val);
575 }
576 }
577 709
578 return; 710 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
579 } 711 }
580 else // cross failed, put avas back ?? 712
713 // We unparent the SP quietly so that it won't
714 // be made to stand up
715
716 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
717 List<ScenePresence> avsToCrossFar = new List<ScenePresence>();
718 ulong destHandle = destination.RegionHandle;
719 List<ScenePresence> sittingAvatars = GetSittingAvatars();
720 foreach (ScenePresence av in sittingAvatars)
721 {
722 byte cflags = 1;
723
724 avtocrossInfo avinfo = new avtocrossInfo();
725 SceneObjectPart parentPart = sogScene.GetSceneObjectPart(av.ParentID);
726 if (parentPart != null)
727 {
728 av.ParentUUID = parentPart.UUID;
729 if(parentPart.SitTargetAvatar == av.UUID)
730 cflags = 7; // low 3 bits set
731 else
732 cflags = 3;
733 }
734 if(!av.knowsNeighbourRegion(destHandle))
735 cflags |= 8;
736
737 // 1 is crossing
738 // 2 is sitting
739 // 4 is sitting at sittarget
740 // 8 far crossing
741
742 avinfo.av = av;
743 avinfo.ParentID = av.ParentID;
744 avsToCross.Add(avinfo);
745
746 if(!av.knowsNeighbourRegion(destHandle))
747 {
748 cflags |= 8;
749 avsToCrossFar.Add(av);
750 }
751
752 if(av.IsNPC)
753 av.crossingFlags = 0;
754 else
755 av.crossingFlags = cflags;
756
757 av.PrevSitOffset = av.OffsetPosition;
758 av.ParentID = 0;
759 }
760
761 Vector3 vel = root.Velocity;
762 Vector3 avel = root.AngularVelocity;
763 Vector3 acc = root.Acceleration;
764 Quaternion ori = root.RotationOffset;
765
766 if(isTeleport)
767 {
768 root.Stop();
769 sogScene.ForEachScenePresence(delegate(ScenePresence av)
770 {
771 av.ControllingClient.SendEntityUpdate(root,PrimUpdateFlags.SendInTransit);
772 av.ControllingClient.SendEntityTerseUpdateImmediate(root);
773 });
774
775 root.Velocity = tpdata.vel;
776 root.AngularVelocity = tpdata.avel;
777 root.Acceleration = tpdata.acc;
778 root.RotationOffset = tpdata.ori;
779 }
780
781 if (entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true, false))
782 {
783 if(isTeleport)
784 {
785 sogScene.ForEachScenePresence(delegate(ScenePresence oav)
786 {
787 if(sittingAvatars.Contains(oav))
788 return;
789 if(oav.knowsNeighbourRegion(destHandle))
790 return;
791 oav.ControllingClient.SendEntityUpdate(root, PrimUpdateFlags.Kill);
792 foreach (ScenePresence sav in sittingAvatars)
793 {
794 sav.SendKillTo(oav);
795 }
796 });
797 }
798 bool crossedfar = false;
799 foreach (ScenePresence av in avsToCrossFar)
800 {
801 if(entityTransfer.CrossAgentCreateFarChild(av,destination, newpos, ctx))
802 crossedfar = true;
803 else
804 av.crossingFlags = 0;
805 }
806
807 if(crossedfar)
808 Thread.Sleep(1000);
809
810 foreach (avtocrossInfo avinfo in avsToCross)
811 {
812 ScenePresence av = avinfo.av;
813 av.IsInLocalTransit = true;
814 av.IsInTransit = true;
815 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
816
817 if(av.crossingFlags > 0)
818 entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, false, ctx);
819
820 if (av.IsChildAgent)
821 {
822 // avatar crossed do some extra cleanup
823 if (av.ParentUUID != UUID.Zero)
824 {
825 av.ClearControls();
826 av.ParentPart = null;
827 }
828 av.ParentUUID = UUID.Zero;
829 av.ParentPart = null;
830 // In any case
831 av.IsInTransit = false;
832 av.crossingFlags = 0;
833 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname);
834 }
835 else
836 {
837 // avatar cross failed we need do dedicated standUp
838 // part of it was done at CrossAgentToNewRegionAsync
839 // so for now just remove the sog controls
840 // this may need extra care
841 av.UnRegisterSeatControls(sog.UUID);
842 av.ParentUUID = UUID.Zero;
843 av.ParentPart = null;
844 Vector3 oldp = curPos;
845 oldp.X = Util.Clamp<float>(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f);
846 oldp.Y = Util.Clamp<float>(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f);
847 av.AbsolutePosition = oldp;
848 av.crossingFlags = 0;
849 av.sitAnimation = "SIT";
850 av.IsInTransit = false;
851 if(av.Animator!= null)
852 av.Animator.SetMovementAnimations("STAND");
853 av.AddToPhysicalScene(false);
854 sogScene.ForEachScenePresence(delegate(ScenePresence oav)
581 { 855 {
582 foreach (avtocrossInfo avinfo in avsToCross) 856 if(sittingAvatars.Contains(oav))
857 return;
858 if(oav.knowsNeighbourRegion(destHandle))
859 av.SendAvatarDataToAgent(oav);
860 else
583 { 861 {
584 ScenePresence av = avinfo.av; 862 av.SendAvatarDataToAgent(oav);
585 av.ParentUUID = UUID.Zero; 863 av.SendAppearanceToAgent(oav);
586 av.ParentID = avinfo.ParentID; 864 if (av.Animator != null)
865 av.Animator.SendAnimPackToClient(oav.ControllingClient);
866 av.SendAttachmentsToAgentNF(oav); // not ok
587 } 867 }
588 } 868 });
589 } 869 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} failed.", av.Firstname, av.Lastname);
590 else 870 }
591 { 871 }
592 if (m_rootPart.KeyframeMotion != null)
593 m_rootPart.KeyframeMotion.CrossingFailure();
594 872
595 if (RootPart.PhysActor != null) 873 if(crossedfar)
596 { 874 {
597 RootPart.PhysActor.CrossingFailure(); 875 Thread.Sleep(10000);
598 } 876 foreach (ScenePresence av in avsToCrossFar)
877 {
878 if(av.IsChildAgent)
879 {
880 av.Scene.CloseAgent(av.UUID, false);
599 } 881 }
600 882 else
601 Vector3 oldp = AbsolutePosition; 883 av.RemoveNeighbourRegion(destHandle);
602 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f);
603 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f);
604 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, Constants.RegionHeight);
605 } 884 }
606 } 885 }
607 886 avsToCrossFar.Clear();
608 if (RootPart.GetStatusSandbox()) 887 avsToCross.Clear();
888 sog.RemoveScriptInstances(true);
889 sog.Clear();
890 return sog;
891 }
892 else
893 {
894 if(isTeleport)
609 { 895 {
610 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10) 896 if((tpdata.flags & OSTPOBJ_STOPONFAIL) == 0)
611 { 897 {
612 RootPart.ScriptSetPhysicsStatus(false); 898 root.Velocity = vel;
613 899 root.AngularVelocity = avel;
614 if (Scene != null) 900 root.Acceleration = acc;
615 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
616 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
617
618 return;
619 } 901 }
902 root.RotationOffset = ori;
903 }
904 foreach (avtocrossInfo avinfo in avsToCross)
905 {
906 ScenePresence av = avinfo.av;
907 av.ParentUUID = UUID.Zero;
908 av.ParentID = avinfo.ParentID;
909 av.crossingFlags = 0;
620 } 910 }
911 }
912 avsToCross.Clear();
913 return sog;
914 }
621 915
622 // Restuff the new GroupPosition into each SOP of the linkset. 916 public void CrossAsyncCompleted(IAsyncResult iar)
623 // This has the affect of resetting and tainting the physics actors. 917 {
624 SceneObjectPart[] parts = m_parts.GetArray(); 918 SOGCrossDelegate icon = (SOGCrossDelegate)iar.AsyncState;
625 for (int i = 0; i < parts.Length; i++) 919 SceneObjectGroup sog = icon.EndInvoke(iar);
626 parts[i].GroupPosition = val;
627 920
628 //if (m_rootPart.PhysActor != null) 921 if (!sog.IsDeleted)
629 //{ 922 {
630 //m_rootPart.PhysActor.Position = 923 SceneObjectPart rootp = sog.m_rootPart;
631 //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y, 924
632 //m_rootPart.GroupPosition.Z); 925 Vector3 oldp = rootp.GroupPosition;
633 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor); 926 oldp.X = Util.Clamp<float>(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f);
634 //} 927 oldp.Y = Util.Clamp<float>(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f);
635 928 rootp.GroupPosition = oldp;
636 if (Scene != null) 929
637 Scene.EventManager.TriggerParcelPrimCountTainted(); 930 rootp.Stop();
931
932 SceneObjectPart[] parts = sog.m_parts.GetArray();
933
934 foreach (SceneObjectPart part in parts)
935 {
936 if (part != rootp)
937 part.GroupPosition = oldp;
938 }
939
940 foreach (ScenePresence av in sog.m_sittingAvatars)
941 {
942 av.sitSOGmoved();
943 }
944
945 if (sog.m_rootPart.KeyframeMotion != null)
946 sog.m_rootPart.KeyframeMotion.CrossingFailure();
947
948 if (sog.RootPart.PhysActor != null)
949 sog.RootPart.PhysActor.CrossingFailure();
950
951 sog.inTransit = false;
952 AttachToBackup();
953 sog.ScheduleGroupForFullUpdate();
638 } 954 }
639 } 955 }
640 956
641 public override Vector3 Velocity 957 private class TeleportObjectData
642 { 958 {
643 get { return RootPart.Velocity; } 959 public int flags;
644 set { RootPart.Velocity = value; } 960 public Vector3 vel;
961 public Vector3 avel;
962 public Vector3 acc;
963 public Quaternion ori;
964 public UUID sourceID;
645 } 965 }
646 966
647 private void CrossAgentToNewRegionCompleted(ScenePresence agent) 967 // copy from LSL_constants.cs
968 const int OSTPOBJ_STOPATTARGET = 0x1; // stops at destination
969 const int OSTPOBJ_STOPONFAIL = 0x2; // stops at start if tp fails
970 const int OSTPOBJ_SETROT = 0x4; // the rotation is the final rotation, otherwise is a added rotation
971
972 public int TeleportObject(UUID sourceID, Vector3 targetPosition, Quaternion rotation, int flags)
648 { 973 {
649 //// If the cross was successful, this agent is a child agent 974 if(inTransit || IsDeleted || IsAttachmentCheckFull() || IsSelected || Scene == null)
650 if (agent.IsChildAgent) 975 return -1;
976
977 inTransit = true;
978
979 PhysicsActor pa = RootPart.PhysActor;
980 if(pa == null || RootPart.KeyframeMotion != null /*|| m_sittingAvatars.Count == 0*/)
651 { 981 {
652 if (agent.ParentUUID != UUID.Zero) 982 inTransit = false;
983 return -1;
984 }
985
986 bool stop = (flags & OSTPOBJ_STOPATTARGET) != 0;
987 bool setrot = (flags & OSTPOBJ_SETROT) != 0;
988
989 rotation.Normalize();
990
991 Quaternion currentRot = RootPart.RotationOffset;
992 if(setrot)
993 rotation = Quaternion.Conjugate(currentRot) * rotation;
994
995 bool dorot = setrot | (Math.Abs(rotation.W) < 0.99999);
996
997 Vector3 vel = Vector3.Zero;
998 Vector3 avel = Vector3.Zero;
999 Vector3 acc = Vector3.Zero;
1000
1001 if(!stop)
1002 {
1003 vel = RootPart.Velocity;
1004 avel = RootPart.AngularVelocity;
1005 acc = RootPart.Acceleration;
1006 }
1007 Quaternion ori = RootPart.RotationOffset;
1008
1009 if(dorot)
1010 {
1011 if(!stop)
653 { 1012 {
654 agent.ParentPart = null; 1013 vel *= rotation;
655// agent.ParentPosition = Vector3.Zero; 1014 avel *= rotation;
656// agent.ParentUUID = UUID.Zero; 1015 acc *= rotation;
657 } 1016 }
1017 ori *= rotation;
658 } 1018 }
659 1019
660 agent.ParentUUID = UUID.Zero; 1020 if(Scene.PositionIsInCurrentRegion(targetPosition))
661// agent.Reset(); 1021 {
662// else // Not successful 1022 if(Scene.InTeleportTargetsCoolDown(UUID, sourceID, 1.0))
663// agent.RestoreInCurrentScene(); 1023 {
1024 inTransit = false;
1025 return -2;
1026 }
1027
1028 Vector3 curPos = AbsolutePosition;
1029 ILandObject curLand = Scene.LandChannel.GetLandObject(curPos.X, curPos.Y);
1030 float posX = targetPosition.X;
1031 float posY = targetPosition.Y;
1032 ILandObject land = Scene.LandChannel.GetLandObject(posX, posY);
1033 if(land != null && land != curLand)
1034 {
1035 if(!Scene.Permissions.CanObjectEnterWithScripts(this, land))
1036 {
1037 inTransit = false;
1038 return -3;
1039 }
1040
1041 UUID agentID;
1042 foreach (ScenePresence av in m_sittingAvatars)
1043 {
1044 agentID = av.UUID;
1045 if(land.IsRestrictedFromLand(agentID) || land.IsBannedFromLand(agentID))
1046 {
1047 inTransit = false;
1048 return -4;
1049 }
1050 }
1051 }
664 1052
665 // In any case 1053 RootPart.Velocity = vel;
666 agent.IsInTransit = false; 1054 RootPart.AngularVelocity = avel;
1055 RootPart.Acceleration = acc;
1056 RootPart.RotationOffset = ori;
667 1057
668 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname); 1058 Vector3 s = RootPart.Scale * RootPart.RotationOffset;
1059 float h = Scene.GetGroundHeight(posX, posY) + 0.5f * (float)Math.Abs(s.Z) + 0.01f;
1060 if(targetPosition.Z < h)
1061 targetPosition.Z = h;
1062
1063 inTransit = false;
1064 AbsolutePosition = targetPosition;
1065 RootPart.ScheduleTerseUpdate();
1066 return 1;
1067 }
1068
1069 if(Scene.InTeleportTargetsCoolDown(UUID, sourceID, 20.0))
1070 {
1071 inTransit = false;
1072 return -1;
1073 }
1074
1075 TeleportObjectData tdata = new TeleportObjectData();
1076 tdata.flags = flags;
1077 tdata.vel = vel;
1078 tdata.avel = avel;
1079 tdata.acc = acc;
1080 tdata.ori = ori;
1081 tdata.sourceID = sourceID;
1082
1083
1084 SOGCrossDelegate d = CrossAsync;
1085 d.BeginInvoke(this, targetPosition, tdata, CrossAsyncCompleted, d);
1086 return 0;
1087 }
1088
1089 public override Vector3 Velocity
1090 {
1091 get { return RootPart.Velocity; }
1092 set { RootPart.Velocity = value; }
669 } 1093 }
670 1094
671 public override uint LocalId 1095 public override uint LocalId
@@ -677,7 +1101,7 @@ namespace OpenSim.Region.Framework.Scenes
677 public override UUID UUID 1101 public override UUID UUID
678 { 1102 {
679 get { return m_rootPart.UUID; } 1103 get { return m_rootPart.UUID; }
680 set 1104 set
681 { 1105 {
682 lock (m_parts.SyncRoot) 1106 lock (m_parts.SyncRoot)
683 { 1107 {
@@ -694,6 +1118,12 @@ namespace OpenSim.Region.Framework.Scenes
694 set { m_rootPart.LastOwnerID = value; } 1118 set { m_rootPart.LastOwnerID = value; }
695 } 1119 }
696 1120
1121 public UUID RezzerID
1122 {
1123 get { return m_rootPart.RezzerID; }
1124 set { m_rootPart.RezzerID = value; }
1125 }
1126
697 public UUID OwnerID 1127 public UUID OwnerID
698 { 1128 {
699 get { return m_rootPart.OwnerID; } 1129 get { return m_rootPart.OwnerID; }
@@ -733,7 +1163,7 @@ namespace OpenSim.Region.Framework.Scenes
733 { 1163 {
734 get { return true; } 1164 get { return true; }
735 } 1165 }
736 1166
737 public bool IsSelected 1167 public bool IsSelected
738 { 1168 {
739 get { return m_isSelected; } 1169 get { return m_isSelected; }
@@ -742,6 +1172,11 @@ namespace OpenSim.Region.Framework.Scenes
742 m_isSelected = value; 1172 m_isSelected = value;
743 // Tell physics engine that group is selected 1173 // Tell physics engine that group is selected
744 1174
1175 // this is not right
1176 // but ode engines should only really need to know about root part
1177 // so they can put entire object simulation on hold and not colliding
1178 // keep as was for now
1179
745 PhysicsActor pa = m_rootPart.PhysActor; 1180 PhysicsActor pa = m_rootPart.PhysActor;
746 if (pa != null) 1181 if (pa != null)
747 { 1182 {
@@ -763,13 +1198,47 @@ namespace OpenSim.Region.Framework.Scenes
763 } 1198 }
764 } 1199 }
765 1200
1201 public void PartSelectChanged(bool partSelect)
1202 {
1203 // any part selected makes group selected
1204 if (m_isSelected == partSelect)
1205 return;
1206
1207 if (partSelect)
1208 {
1209 IsSelected = partSelect;
1210// if (!IsAttachment)
1211// ScheduleGroupForFullUpdate();
1212 }
1213 else
1214 {
1215 // bad bad bad 2 heavy for large linksets
1216 // since viewer does send lot of (un)selects
1217 // this needs to be replaced by a specific list or count ?
1218 // but that will require extra code in several places
1219
1220 SceneObjectPart[] parts = m_parts.GetArray();
1221 for (int i = 0; i < parts.Length; i++)
1222 {
1223 SceneObjectPart part = parts[i];
1224 if (part.IsSelected)
1225 return;
1226 }
1227 IsSelected = partSelect;
1228// if (!IsAttachment)
1229// {
1230// ScheduleGroupForFullUpdate();
1231// }
1232 }
1233 }
1234 // PlaySoundMasterPrim no longer in use to remove
766 private SceneObjectPart m_PlaySoundMasterPrim = null; 1235 private SceneObjectPart m_PlaySoundMasterPrim = null;
767 public SceneObjectPart PlaySoundMasterPrim 1236 public SceneObjectPart PlaySoundMasterPrim
768 { 1237 {
769 get { return m_PlaySoundMasterPrim; } 1238 get { return m_PlaySoundMasterPrim; }
770 set { m_PlaySoundMasterPrim = value; } 1239 set { m_PlaySoundMasterPrim = value; }
771 } 1240 }
772 1241 // PlaySoundSlavePrims no longer in use to remove
773 private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>(); 1242 private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>();
774 public List<SceneObjectPart> PlaySoundSlavePrims 1243 public List<SceneObjectPart> PlaySoundSlavePrims
775 { 1244 {
@@ -777,6 +1246,7 @@ namespace OpenSim.Region.Framework.Scenes
777 set { m_PlaySoundSlavePrims = value; } 1246 set { m_PlaySoundSlavePrims = value; }
778 } 1247 }
779 1248
1249 // LoopSoundMasterPrim no longer in use to remove
780 private SceneObjectPart m_LoopSoundMasterPrim = null; 1250 private SceneObjectPart m_LoopSoundMasterPrim = null;
781 public SceneObjectPart LoopSoundMasterPrim 1251 public SceneObjectPart LoopSoundMasterPrim
782 { 1252 {
@@ -784,6 +1254,7 @@ namespace OpenSim.Region.Framework.Scenes
784 set { m_LoopSoundMasterPrim = value; } 1254 set { m_LoopSoundMasterPrim = value; }
785 } 1255 }
786 1256
1257 // m_LoopSoundSlavePrims no longer in use to remove
787 private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>(); 1258 private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>();
788 public List<SceneObjectPart> LoopSoundSlavePrims 1259 public List<SceneObjectPart> LoopSoundSlavePrims
789 { 1260 {
@@ -791,6 +1262,8 @@ namespace OpenSim.Region.Framework.Scenes
791 set { m_LoopSoundSlavePrims = value; } 1262 set { m_LoopSoundSlavePrims = value; }
792 } 1263 }
793 1264
1265 private double m_lastCollisionSoundMS;
1266
794 /// <summary> 1267 /// <summary>
795 /// The UUID for the region this object is in. 1268 /// The UUID for the region this object is in.
796 /// </summary> 1269 /// </summary>
@@ -820,7 +1293,12 @@ namespace OpenSim.Region.Framework.Scenes
820 /// <remarks> 1293 /// <remarks>
821 /// If not applicable will be UUID.Zero 1294 /// If not applicable will be UUID.Zero
822 /// </remarks> 1295 /// </remarks>
823 public UUID FromPartID { get; set; } 1296 /// obsolete use RezzerID
1297 public UUID FromPartID
1298 {
1299 get { return RezzerID; }
1300 set {RezzerID = value; }
1301 }
824 1302
825 /// <summary> 1303 /// <summary>
826 /// The folder ID that this object was rezzed from, if applicable. 1304 /// The folder ID that this object was rezzed from, if applicable.
@@ -863,6 +1341,7 @@ namespace OpenSim.Region.Framework.Scenes
863 /// </summary> 1341 /// </summary>
864 public SceneObjectGroup() 1342 public SceneObjectGroup()
865 { 1343 {
1344 m_lastCollisionSoundMS = Util.GetTimeStampMS() + 1000.0;
866 } 1345 }
867 1346
868 /// <summary> 1347 /// <summary>
@@ -880,8 +1359,8 @@ namespace OpenSim.Region.Framework.Scenes
880 /// Constructor. This object is added to the scene later via AttachToScene() 1359 /// Constructor. This object is added to the scene later via AttachToScene()
881 /// </summary> 1360 /// </summary>
882 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape) 1361 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
883 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero)) 1362 {
884 { 1363 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
885 } 1364 }
886 1365
887 /// <summary> 1366 /// <summary>
@@ -907,7 +1386,7 @@ namespace OpenSim.Region.Framework.Scenes
907 if (itemid != UUID.Zero) 1386 if (itemid != UUID.Zero)
908 m_savedScriptState[itemid] = node.InnerXml; 1387 m_savedScriptState[itemid] = node.InnerXml;
909 } 1388 }
910 } 1389 }
911 } 1390 }
912 } 1391 }
913 1392
@@ -940,7 +1419,7 @@ namespace OpenSim.Region.Framework.Scenes
940 } 1419 }
941 else 1420 else
942 { 1421 {
943 m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}", Name); 1422 m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0} id: {1}", Name,UUID);
944 } 1423 }
945 } 1424 }
946 else 1425 else
@@ -956,18 +1435,21 @@ namespace OpenSim.Region.Framework.Scenes
956 /// </summary> 1435 /// </summary>
957 public virtual void AttachToBackup() 1436 public virtual void AttachToBackup()
958 { 1437 {
959 if (CanBeBackedUp) 1438 if (IsAttachment) return;
1439 m_scene.SceneGraph.FireAttachToBackup(this);
1440
1441// if (InSceneBackup)
960 { 1442 {
961// m_log.DebugFormat( 1443// m_log.DebugFormat(
962// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID); 1444// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
963 1445
964 if (!Backup) 1446 if (!Backup)
965 m_scene.EventManager.OnBackup += ProcessBackup; 1447 m_scene.EventManager.OnBackup += ProcessBackup;
966 1448
967 Backup = true; 1449 Backup = true;
968 } 1450 }
969 } 1451 }
970 1452
971 /// <summary> 1453 /// <summary>
972 /// Attach this object to a scene. It will also now appear to agents. 1454 /// Attach this object to a scene. It will also now appear to agents.
973 /// </summary> 1455 /// </summary>
@@ -1018,6 +1500,10 @@ namespace OpenSim.Region.Framework.Scenes
1018 EntityIntersection result = new EntityIntersection(); 1500 EntityIntersection result = new EntityIntersection();
1019 1501
1020 SceneObjectPart[] parts = m_parts.GetArray(); 1502 SceneObjectPart[] parts = m_parts.GetArray();
1503
1504 // Find closest hit here
1505 float idist = float.MaxValue;
1506
1021 for (int i = 0; i < parts.Length; i++) 1507 for (int i = 0; i < parts.Length; i++)
1022 { 1508 {
1023 SceneObjectPart part = parts[i]; 1509 SceneObjectPart part = parts[i];
@@ -1032,11 +1518,6 @@ namespace OpenSim.Region.Framework.Scenes
1032 1518
1033 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters); 1519 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
1034 1520
1035 // This may need to be updated to the maximum draw distance possible..
1036 // We might (and probably will) be checking for prim creation from other sims
1037 // when the camera crosses the border.
1038 float idist = Constants.RegionSize;
1039
1040 if (inter.HitTF) 1521 if (inter.HitTF)
1041 { 1522 {
1042 // We need to find the closest prim to return to the testcaller along the ray 1523 // We need to find the closest prim to return to the testcaller along the ray
@@ -1047,10 +1528,11 @@ namespace OpenSim.Region.Framework.Scenes
1047 result.obj = part; 1528 result.obj = part;
1048 result.normal = inter.normal; 1529 result.normal = inter.normal;
1049 result.distance = inter.distance; 1530 result.distance = inter.distance;
1531
1532 idist = inter.distance;
1050 } 1533 }
1051 } 1534 }
1052 } 1535 }
1053
1054 return result; 1536 return result;
1055 } 1537 }
1056 1538
@@ -1062,25 +1544,27 @@ namespace OpenSim.Region.Framework.Scenes
1062 /// <returns></returns> 1544 /// <returns></returns>
1063 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ) 1545 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
1064 { 1546 {
1065 maxX = -256f; 1547 maxX = float.MinValue;
1066 maxY = -256f; 1548 maxY = float.MinValue;
1067 maxZ = -256f; 1549 maxZ = float.MinValue;
1068 minX = 10000f; 1550 minX = float.MaxValue;
1069 minY = 10000f; 1551 minY = float.MaxValue;
1070 minZ = 10000f; 1552 minZ = float.MaxValue;
1071 1553
1072 SceneObjectPart[] parts = m_parts.GetArray(); 1554 SceneObjectPart[] parts = m_parts.GetArray();
1073 for (int i = 0; i < parts.Length; i++) 1555 foreach (SceneObjectPart part in parts)
1074 { 1556 {
1075 SceneObjectPart part = parts[i];
1076
1077 Vector3 worldPos = part.GetWorldPosition(); 1557 Vector3 worldPos = part.GetWorldPosition();
1078 Vector3 offset = worldPos - AbsolutePosition; 1558 Vector3 offset = worldPos - AbsolutePosition;
1079 Quaternion worldRot; 1559 Quaternion worldRot;
1080 if (part.ParentID == 0) 1560 if (part.ParentID == 0)
1561 {
1081 worldRot = part.RotationOffset; 1562 worldRot = part.RotationOffset;
1563 }
1082 else 1564 else
1565 {
1083 worldRot = part.GetWorldRotation(); 1566 worldRot = part.GetWorldRotation();
1567 }
1084 1568
1085 Vector3 frontTopLeft; 1569 Vector3 frontTopLeft;
1086 Vector3 frontTopRight; 1570 Vector3 frontTopRight;
@@ -1092,6 +1576,8 @@ namespace OpenSim.Region.Framework.Scenes
1092 Vector3 backBottomLeft; 1576 Vector3 backBottomLeft;
1093 Vector3 backBottomRight; 1577 Vector3 backBottomRight;
1094 1578
1579 // Vector3[] corners = new Vector3[8];
1580
1095 Vector3 orig = Vector3.Zero; 1581 Vector3 orig = Vector3.Zero;
1096 1582
1097 frontTopLeft.X = orig.X - (part.Scale.X / 2); 1583 frontTopLeft.X = orig.X - (part.Scale.X / 2);
@@ -1126,6 +1612,38 @@ namespace OpenSim.Region.Framework.Scenes
1126 backBottomRight.Y = orig.Y + (part.Scale.Y / 2); 1612 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
1127 backBottomRight.Z = orig.Z - (part.Scale.Z / 2); 1613 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
1128 1614
1615
1616
1617 //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1618 //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1619 //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1620 //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1621 //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1622 //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1623 //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1624 //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1625
1626 //for (int i = 0; i < 8; i++)
1627 //{
1628 // corners[i] = corners[i] * worldRot;
1629 // corners[i] += offset;
1630
1631 // if (corners[i].X > maxX)
1632 // maxX = corners[i].X;
1633 // if (corners[i].X < minX)
1634 // minX = corners[i].X;
1635
1636 // if (corners[i].Y > maxY)
1637 // maxY = corners[i].Y;
1638 // if (corners[i].Y < minY)
1639 // minY = corners[i].Y;
1640
1641 // if (corners[i].Z > maxZ)
1642 // maxZ = corners[i].Y;
1643 // if (corners[i].Z < minZ)
1644 // minZ = corners[i].Z;
1645 //}
1646
1129 frontTopLeft = frontTopLeft * worldRot; 1647 frontTopLeft = frontTopLeft * worldRot;
1130 frontTopRight = frontTopRight * worldRot; 1648 frontTopRight = frontTopRight * worldRot;
1131 frontBottomLeft = frontBottomLeft * worldRot; 1649 frontBottomLeft = frontBottomLeft * worldRot;
@@ -1147,6 +1665,15 @@ namespace OpenSim.Region.Framework.Scenes
1147 backTopLeft += offset; 1665 backTopLeft += offset;
1148 backTopRight += offset; 1666 backTopRight += offset;
1149 1667
1668 //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1669 //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1670 //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1671 //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1672 //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1673 //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1674 //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1675 //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1676
1150 if (frontTopRight.X > maxX) 1677 if (frontTopRight.X > maxX)
1151 maxX = frontTopRight.X; 1678 maxX = frontTopRight.X;
1152 if (frontTopLeft.X > maxX) 1679 if (frontTopLeft.X > maxX)
@@ -1290,17 +1817,192 @@ namespace OpenSim.Region.Framework.Scenes
1290 1817
1291 #endregion 1818 #endregion
1292 1819
1820 private float? m_boundsRadius = null;
1821 public void InvalidBoundsRadius()
1822 {
1823 m_boundsRadius = null;
1824 }
1825
1826 private Vector3 m_boundsCenter;
1827 public Vector3 getBoundsCenter()
1828 {
1829 // math is done in GetBoundsRadius();
1830 if(m_boundsRadius == null)
1831 GetBoundsRadius();
1832 return m_boundsCenter;
1833 }
1834
1835 private float m_areaFactor;
1836 public float getAreaFactor()
1837 {
1838 // math is done in GetBoundsRadius();
1839 if(m_boundsRadius == null)
1840 GetBoundsRadius();
1841 return m_areaFactor;
1842 }
1843
1844 public float GetBoundsRadius()
1845 {
1846 // this may need more threading work
1847 if(m_boundsRadius == null)
1848 {
1849 float res = 0;
1850 float areaF = 0;
1851 SceneObjectPart p;
1852 SceneObjectPart[] parts;
1853 float partR;
1854 Vector3 offset = Vector3.Zero;
1855 lock (m_parts)
1856 {
1857 parts = m_parts.GetArray();
1858 }
1859
1860 int nparts = parts.Length;
1861 for (int i = 0; i < nparts; i++)
1862 {
1863 p = parts[i];
1864 partR = 0.5f * p.Scale.Length();
1865 if(p != RootPart)
1866 {
1867 partR += p.OffsetPosition.Length();
1868 offset += p.OffsetPosition;
1869 }
1870 if(partR > res)
1871 res = partR;
1872 if(p.maxSimpleArea() > areaF)
1873 areaF = p.maxSimpleArea();
1874 }
1875 if(parts.Length > 1)
1876 {
1877 offset /= parts.Length; // basicly geometric center
1878 offset = offset * RootPart.RotationOffset;
1879 }
1880
1881 areaF = 10.0f / areaF; // scale it
1882 areaF = Util.Clamp(areaF, 0.001f, 1000f); // clamp it
1883
1884 m_areaFactor = (float)Math.Sqrt(areaF);
1885 m_boundsCenter = offset;
1886 m_boundsRadius = res;
1887 return res;
1888 }
1889
1890 return m_boundsRadius.Value;
1891 }
1892
1893 public void GetResourcesCosts(SceneObjectPart apart,
1894 out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1895 {
1896 // this information may need to be cached
1897
1898 float cost;
1899 float tmpcost;
1900
1901 bool ComplexCost = false;
1902
1903 SceneObjectPart p;
1904 SceneObjectPart[] parts;
1905
1906 lock (m_parts)
1907 {
1908 parts = m_parts.GetArray();
1909 }
1910
1911 int nparts = parts.Length;
1912
1913
1914 for (int i = 0; i < nparts; i++)
1915 {
1916 p = parts[i];
1917
1918 if (p.UsesComplexCost)
1919 {
1920 ComplexCost = true;
1921 break;
1922 }
1923 }
1924
1925 if (ComplexCost)
1926 {
1927 linksetResCost = 0;
1928 linksetPhysCost = 0;
1929 partCost = 0;
1930 partPhysCost = 0;
1931
1932 for (int i = 0; i < nparts; i++)
1933 {
1934 p = parts[i];
1935
1936 cost = p.StreamingCost;
1937 tmpcost = p.SimulationCost;
1938 if (tmpcost > cost)
1939 cost = tmpcost;
1940 tmpcost = p.PhysicsCost;
1941 if (tmpcost > cost)
1942 cost = tmpcost;
1943
1944 linksetPhysCost += tmpcost;
1945 linksetResCost += cost;
1946
1947 if (p == apart)
1948 {
1949 partCost = cost;
1950 partPhysCost = tmpcost;
1951 }
1952 }
1953 }
1954 else
1955 {
1956 partPhysCost = 1.0f;
1957 partCost = 1.0f;
1958 linksetResCost = (float)nparts;
1959 linksetPhysCost = linksetResCost;
1960 }
1961 }
1962
1963 public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1964 {
1965 SceneObjectPart p;
1966 SceneObjectPart[] parts;
1967
1968 lock (m_parts)
1969 {
1970 parts = m_parts.GetArray();
1971 }
1972
1973 int nparts = parts.Length;
1974
1975 PhysCost = 0;
1976 StreamCost = 0;
1977 SimulCost = 0;
1978
1979 for (int i = 0; i < nparts; i++)
1980 {
1981 p = parts[i];
1982
1983 StreamCost += p.StreamingCost;
1984 SimulCost += p.SimulationCost;
1985 PhysCost += p.PhysicsCost;
1986 }
1987 }
1988
1293 public void SaveScriptedState(XmlTextWriter writer) 1989 public void SaveScriptedState(XmlTextWriter writer)
1294 { 1990 {
1991 SaveScriptedState(writer, false);
1992 }
1993
1994 public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1995 {
1295 XmlDocument doc = new XmlDocument(); 1996 XmlDocument doc = new XmlDocument();
1997 doc.XmlResolver=null;
1296 Dictionary<UUID,string> states = new Dictionary<UUID,string>(); 1998 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1297 1999
1298 SceneObjectPart[] parts = m_parts.GetArray(); 2000 SceneObjectPart[] parts = m_parts.GetArray();
1299 for (int i = 0; i < parts.Length; i++) 2001 for (int i = 0; i < parts.Length; i++)
1300 { 2002 {
1301 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(); 2003 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1302 foreach (KeyValuePair<UUID, string> kvp in pstates) 2004 foreach (KeyValuePair<UUID, string> kvp in pstates)
1303 states.Add(kvp.Key, kvp.Value); 2005 states[kvp.Key] = kvp.Value;
1304 } 2006 }
1305 2007
1306 if (states.Count > 0) 2008 if (states.Count > 0)
@@ -1319,6 +2021,73 @@ namespace OpenSim.Region.Framework.Scenes
1319 } 2021 }
1320 } 2022 }
1321 2023
2024 public byte GetAttachmentPoint()
2025 {
2026 return m_rootPart.Shape.State;
2027 }
2028
2029 public void DetachToGround()
2030 {
2031 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
2032 if (avatar == null)
2033 return;
2034 m_rootPart.Shape.LastAttachPoint = m_rootPart.Shape.State;
2035 m_rootPart.AttachedPos = m_rootPart.OffsetPosition;
2036 avatar.RemoveAttachment(this);
2037
2038 Vector3 detachedpos = new Vector3(127f,127f,127f);
2039 if (avatar == null)
2040 return;
2041
2042 detachedpos = avatar.AbsolutePosition;
2043 FromItemID = UUID.Zero;
2044
2045 AbsolutePosition = detachedpos;
2046 AttachedAvatar = UUID.Zero;
2047
2048 //SceneObjectPart[] parts = m_parts.GetArray();
2049 //for (int i = 0; i < parts.Length; i++)
2050 // parts[i].AttachedAvatar = UUID.Zero;
2051
2052 m_rootPart.SetParentLocalId(0);
2053 AttachmentPoint = (byte)0;
2054 // must check if buildind should be true or false here
2055// m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
2056 ApplyPhysics();
2057
2058 HasGroupChanged = true;
2059 RootPart.Rezzed = DateTime.Now;
2060 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
2061 AttachToBackup();
2062 m_scene.EventManager.TriggerParcelPrimCountTainted();
2063 m_rootPart.ScheduleFullUpdate();
2064 m_rootPart.ClearUndoState();
2065 }
2066
2067 public void DetachToInventoryPrep()
2068 {
2069 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
2070 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
2071 if (avatar != null)
2072 {
2073 //detachedpos = avatar.AbsolutePosition;
2074 avatar.RemoveAttachment(this);
2075 }
2076
2077 AttachedAvatar = UUID.Zero;
2078
2079 /*SceneObjectPart[] parts = m_parts.GetArray();
2080 for (int i = 0; i < parts.Length; i++)
2081 parts[i].AttachedAvatar = UUID.Zero;*/
2082
2083 m_rootPart.SetParentLocalId(0);
2084 //m_rootPart.SetAttachmentPoint((byte)0);
2085 IsAttachment = false;
2086 AbsolutePosition = m_rootPart.AttachedPos;
2087 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
2088 //AttachToBackup();
2089 //m_rootPart.ScheduleFullUpdate();
2090 }
1322 2091
1323 /// <summary> 2092 /// <summary>
1324 /// 2093 ///
@@ -1334,7 +2103,7 @@ namespace OpenSim.Region.Framework.Scenes
1334 { 2103 {
1335 return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f); 2104 return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
1336 } 2105 }
1337 2106
1338 /// <summary> 2107 /// <summary>
1339 /// Set a part to act as the root part for this scene object 2108 /// Set a part to act as the root part for this scene object
1340 /// </summary> 2109 /// </summary>
@@ -1349,7 +2118,7 @@ namespace OpenSim.Region.Framework.Scenes
1349 if (!IsAttachment) 2118 if (!IsAttachment)
1350 part.ParentID = 0; 2119 part.ParentID = 0;
1351 part.LinkNum = 0; 2120 part.LinkNum = 0;
1352 2121
1353 m_parts.Add(m_rootPart.UUID, m_rootPart); 2122 m_parts.Add(m_rootPart.UUID, m_rootPart);
1354 } 2123 }
1355 2124
@@ -1360,9 +2129,13 @@ namespace OpenSim.Region.Framework.Scenes
1360 public void AddPart(SceneObjectPart part) 2129 public void AddPart(SceneObjectPart part)
1361 { 2130 {
1362 part.SetParent(this); 2131 part.SetParent(this);
1363 part.LinkNum = m_parts.Add(part.UUID, part); 2132 m_parts.Add(part.UUID, part);
2133
2134 part.LinkNum = m_parts.Count;
2135
1364 if (part.LinkNum == 2) 2136 if (part.LinkNum == 2)
1365 RootPart.LinkNum = 1; 2137 RootPart.LinkNum = 1;
2138 InvalidatePartsLinkMaps();
1366 } 2139 }
1367 2140
1368 /// <summary> 2141 /// <summary>
@@ -1386,32 +2159,50 @@ namespace OpenSim.Region.Framework.Scenes
1386 parts[i].UUID = UUID.Random(); 2159 parts[i].UUID = UUID.Random();
1387 } 2160 }
1388 2161
2162 // helper provided for parts.
2163 public int GetSceneMaxUndo()
2164 {
2165 if (m_scene != null)
2166 return m_scene.MaxUndoCount;
2167 return 5;
2168 }
2169
1389 // justincc: I don't believe this hack is needed any longer, especially since the physics 2170 // justincc: I don't believe this hack is needed any longer, especially since the physics
1390 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false 2171 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1391 // this method was preventing proper reload of scene objects. 2172 // this method was preventing proper reload of scene objects.
1392 2173
1393 // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects 2174 // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
1394 // at region startup 2175 // at region startup
1395 2176
1396 // teravus: After this was removed from the linking algorithm, Linked prims no longer collided 2177 // teravus: After this was removed from the linking algorithm, Linked prims no longer collided
1397 // properly when non-physical if they havn't been moved. This breaks ALL builds. 2178 // properly when non-physical if they havn't been moved. This breaks ALL builds.
1398 // see: http://opensimulator.org/mantis/view.php?id=3108 2179 // see: http://opensimulator.org/mantis/view.php?id=3108
1399 2180
1400 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the 2181 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
1401 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and 2182 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
1402 // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute 2183 // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute
1403 // Position has been set! 2184 // Position has been set!
1404 2185
1405 public void ResetChildPrimPhysicsPositions() 2186 public void ResetChildPrimPhysicsPositions()
1406 { 2187 {
1407 // Setting this SOG's absolute position also loops through and sets the positions 2188 // Setting this SOG's absolute position also loops through and sets the positions
1408 // of the SOP's in this SOG's linkset. This has the side affect of making sure 2189 // of the SOP's in this SOG's linkset. This has the side affect of making sure
1409 // the physics world matches the simulated world. 2190 // the physics world matches the simulated world.
1410 AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works? 2191 // AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
1411 2192
1412 // teravus: AbsolutePosition is NOT a normal property! 2193 // teravus: AbsolutePosition is NOT a normal property!
1413 // the code in the getter of AbsolutePosition is significantly different then the code in the setter! 2194 // the code in the getter of AbsolutePosition is significantly different then the code in the setter!
1414 // jhurliman: Then why is it a property instead of two methods? 2195 // jhurliman: Then why is it a property instead of two methods?
2196
2197 // do only what is supposed to do
2198 Vector3 groupPosition = m_rootPart.GroupPosition;
2199 SceneObjectPart[] parts = m_parts.GetArray();
2200
2201 foreach (SceneObjectPart part in parts)
2202 {
2203 if (part != m_rootPart)
2204 part.GroupPosition = groupPosition;
2205 }
1415 } 2206 }
1416 2207
1417 public UUID GetPartsFullID(uint localID) 2208 public UUID GetPartsFullID(uint localID)
@@ -1443,7 +2234,7 @@ namespace OpenSim.Region.Framework.Scenes
1443// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}", 2234// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1444// remoteClient.Name, part.Name, part.LocalId, offsetPos); 2235// remoteClient.Name, part.Name, part.LocalId, offsetPos);
1445 2236
1446 part.StoreUndoState(); 2237// part.StoreUndoState();
1447 part.OnGrab(offsetPos, remoteClient); 2238 part.OnGrab(offsetPos, remoteClient);
1448 } 2239 }
1449 2240
@@ -1463,15 +2254,23 @@ namespace OpenSim.Region.Framework.Scenes
1463 /// <param name="silent">If true then deletion is not broadcast to clients</param> 2254 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1464 public void DeleteGroupFromScene(bool silent) 2255 public void DeleteGroupFromScene(bool silent)
1465 { 2256 {
2257 // We need to keep track of this state in case this group is still queued for backup.
2258 IsDeleted = true;
2259
2260 DetachFromBackup();
2261
2262 if(Scene == null) // should not happen unless restart/shutdown ?
2263 return;
2264
1466 SceneObjectPart[] parts = m_parts.GetArray(); 2265 SceneObjectPart[] parts = m_parts.GetArray();
1467 for (int i = 0; i < parts.Length; i++) 2266 for (int i = 0; i < parts.Length; i++)
1468 { 2267 {
1469 SceneObjectPart part = parts[i]; 2268 SceneObjectPart part = parts[i];
1470 2269
1471 Scene.ForEachScenePresence(sp => 2270 Scene.ForEachScenePresence(delegate(ScenePresence avatar)
1472 { 2271 {
1473 if (!sp.IsChildAgent && sp.ParentID == part.LocalId) 2272 if (!avatar.IsChildAgent && avatar.ParentID == part.LocalId && avatar.ParentUUID == UUID.Zero)
1474 sp.StandUp(); 2273 avatar.StandUp();
1475 2274
1476 if (!silent) 2275 if (!silent)
1477 { 2276 {
@@ -1479,9 +2278,14 @@ namespace OpenSim.Region.Framework.Scenes
1479 if (part == m_rootPart) 2278 if (part == m_rootPart)
1480 { 2279 {
1481 if (!IsAttachment 2280 if (!IsAttachment
1482 || AttachedAvatar == sp.UUID 2281 || AttachedAvatar == avatar.ControllingClient.AgentId
1483 || !HasPrivateAttachmentPoint) 2282 || !HasPrivateAttachmentPoint)
1484 sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId }); 2283 {
2284 // Send a kill object immediately
2285 avatar.ControllingClient.SendKillObject(new List<uint> { part.LocalId });
2286 //direct enqueue another delayed kill
2287 avatar.ControllingClient.SendEntityUpdate(part,PrimUpdateFlags.Kill);
2288 }
1485 } 2289 }
1486 } 2290 }
1487 }); 2291 });
@@ -1499,6 +2303,12 @@ namespace OpenSim.Region.Framework.Scenes
1499 d.AddActiveScripts(count); 2303 d.AddActiveScripts(count);
1500 } 2304 }
1501 2305
2306 private const scriptEvents PhysicsNeeedSubsEvents = (
2307 scriptEvents.collision | scriptEvents.collision_start | scriptEvents.collision_end |
2308 scriptEvents.land_collision | scriptEvents.land_collision_start | scriptEvents.land_collision_end);
2309
2310 private scriptEvents lastRootPartPhysEvents = 0;
2311
1502 public void aggregateScriptEvents() 2312 public void aggregateScriptEvents()
1503 { 2313 {
1504 PrimFlags objectflagupdate = (PrimFlags)RootPart.GetEffectiveObjectFlags(); 2314 PrimFlags objectflagupdate = (PrimFlags)RootPart.GetEffectiveObjectFlags();
@@ -1535,6 +2345,20 @@ namespace OpenSim.Region.Framework.Scenes
1535 m_scene.RemoveGroupTarget(this); 2345 m_scene.RemoveGroupTarget(this);
1536 } 2346 }
1537 2347
2348 scriptEvents rootPartPhysEvents = RootPart.AggregateScriptEvents;
2349 rootPartPhysEvents &= PhysicsNeeedSubsEvents;
2350 if (rootPartPhysEvents != lastRootPartPhysEvents)
2351 {
2352 lastRootPartPhysEvents = rootPartPhysEvents;
2353 for (int i = 0; i < parts.Length; i++)
2354 {
2355 SceneObjectPart part = parts[i];
2356 if (part == null)
2357 continue;
2358 part.UpdatePhysicsSubscribedEvents();
2359 }
2360 }
2361
1538 ScheduleGroupForFullUpdate(); 2362 ScheduleGroupForFullUpdate();
1539 } 2363 }
1540 2364
@@ -1555,28 +2379,44 @@ namespace OpenSim.Region.Framework.Scenes
1555 /// </summary> 2379 /// </summary>
1556 public void ApplyPhysics() 2380 public void ApplyPhysics()
1557 { 2381 {
1558 // Apply physics to the root prim
1559 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1560
1561 // Apply physics to child prims
1562 SceneObjectPart[] parts = m_parts.GetArray(); 2382 SceneObjectPart[] parts = m_parts.GetArray();
1563 if (parts.Length > 1) 2383 if (parts.Length > 1)
1564 { 2384 {
2385 ResetChildPrimPhysicsPositions();
2386
2387 // Apply physics to the root prim
2388 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
2389
1565 for (int i = 0; i < parts.Length; i++) 2390 for (int i = 0; i < parts.Length; i++)
1566 { 2391 {
1567 SceneObjectPart part = parts[i]; 2392 SceneObjectPart part = parts[i];
1568 if (part.LocalId != m_rootPart.LocalId) 2393 if (part.LocalId != m_rootPart.LocalId)
1569 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive); 2394 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
1570 } 2395 }
1571
1572 // Hack to get the physics scene geometries in the right spot 2396 // Hack to get the physics scene geometries in the right spot
1573 ResetChildPrimPhysicsPositions(); 2397// ResetChildPrimPhysicsPositions();
2398
2399 if (m_rootPart.PhysActor != null)
2400 m_rootPart.PhysActor.Building = false;
2401 }
2402 else
2403 {
2404 // Apply physics to the root prim
2405 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
1574 } 2406 }
1575 } 2407 }
1576 2408
1577 public void SetOwnerId(UUID userId) 2409 public void SetOwnerId(UUID userId)
1578 { 2410 {
1579 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; }); 2411 ForEachPart(delegate(SceneObjectPart part)
2412 {
2413 if (part.OwnerID != userId)
2414 {
2415 if(part.GroupID != part.OwnerID)
2416 part.LastOwnerID = part.OwnerID;
2417 part.OwnerID = userId;
2418 }
2419 });
1580 } 2420 }
1581 2421
1582 public void ForEachPart(Action<SceneObjectPart> whatToDo) 2422 public void ForEachPart(Action<SceneObjectPart> whatToDo)
@@ -1601,18 +2441,24 @@ namespace OpenSim.Region.Framework.Scenes
1601 return; 2441 return;
1602 } 2442 }
1603 2443
1604 if (IsDeleted || UUID == UUID.Zero) 2444 if (IsDeleted || inTransit || UUID == UUID.Zero)
1605 { 2445 {
1606// m_log.DebugFormat( 2446// m_log.DebugFormat(
1607// "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID); 2447// "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID);
1608 return; 2448 return;
1609 } 2449 }
1610 2450
2451 if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2452 return;
2453
1611 // Since this is the top of the section of call stack for backing up a particular scene object, don't let 2454 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1612 // any exception propogate upwards. 2455 // any exception propogate upwards.
1613 try 2456 try
1614 { 2457 {
1615 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart 2458 // if shutting down then there will be nothing to handle the return so leave till next restart
2459 if (!m_scene.ShuttingDown &&
2460 m_scene.LoginsEnabled && // We're starting up or doing maintenance, don't mess with things
2461 !m_scene.LoadingPrims) // Land may not be valid yet
1616 { 2462 {
1617 ILandObject parcel = m_scene.LandChannel.GetLandObject( 2463 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1618 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y); 2464 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
@@ -1627,18 +2473,33 @@ namespace OpenSim.Region.Framework.Scenes
1627 if ((DateTime.UtcNow - RootPart.Rezzed).TotalMinutes > 2473 if ((DateTime.UtcNow - RootPart.Rezzed).TotalMinutes >
1628 parcel.LandData.OtherCleanTime) 2474 parcel.LandData.OtherCleanTime)
1629 { 2475 {
2476 // don't autoreturn if we have a sitting avatar
2477 // mantis 7828 (but none the provided patchs)
2478
2479 if(GetSittingAvatarsCount() > 0)
2480 {
2481 // do not respect npcs
2482 List<ScenePresence> sitters = GetSittingAvatars();
2483 foreach(ScenePresence sp in sitters)
2484 {
2485 if(!sp.IsDeleted && !sp.IsNPC && sp.IsSatOnObject)
2486 return;
2487 }
2488 }
2489
1630 DetachFromBackup(); 2490 DetachFromBackup();
1631 m_log.DebugFormat( 2491 m_log.DebugFormat(
1632 "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn", 2492 "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn",
1633 RootPart.UUID); 2493 RootPart.UUID);
1634 m_scene.AddReturn(OwnerID == GroupID ? LastOwnerID : OwnerID, Name, AbsolutePosition, "parcel autoreturn"); 2494 m_scene.AddReturn(OwnerID == GroupID ? LastOwnerID : OwnerID, Name, AbsolutePosition, "parcel autoreturn");
1635 m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero, 2495 m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero,
1636 DeRezAction.Return, UUID.Zero); 2496 DeRezAction.Return, UUID.Zero, false);
1637 2497
1638 return; 2498 return;
1639 } 2499 }
1640 } 2500 }
1641 } 2501 }
2502
1642 } 2503 }
1643 2504
1644 if (m_scene.UseBackup && HasGroupChanged) 2505 if (m_scene.UseBackup && HasGroupChanged)
@@ -1646,10 +2507,31 @@ namespace OpenSim.Region.Framework.Scenes
1646 // don't backup while it's selected or you're asking for changes mid stream. 2507 // don't backup while it's selected or you're asking for changes mid stream.
1647 if (isTimeToPersist() || forcedBackup) 2508 if (isTimeToPersist() || forcedBackup)
1648 { 2509 {
2510 if (m_rootPart.PhysActor != null &&
2511 (!m_rootPart.PhysActor.IsPhysical))
2512 {
2513 // Possible ghost prim
2514 if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2515 {
2516 foreach (SceneObjectPart part in m_parts.GetArray())
2517 {
2518 // Re-set physics actor positions and
2519 // orientations
2520 part.GroupPosition = m_rootPart.GroupPosition;
2521 }
2522 }
2523 }
1649// m_log.DebugFormat( 2524// m_log.DebugFormat(
1650// "[SCENE]: Storing {0}, {1} in {2}", 2525// "[SCENE]: Storing {0}, {1} in {2}",
1651// Name, UUID, m_scene.RegionInfo.RegionName); 2526// Name, UUID, m_scene.RegionInfo.RegionName);
1652 2527
2528 if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2529 {
2530 RootPart.Shape.LastAttachPoint = RootPart.Shape.State;
2531 RootPart.Shape.State = 0;
2532 ScheduleGroupForFullUpdate();
2533 }
2534
1653 SceneObjectGroup backup_group = Copy(false); 2535 SceneObjectGroup backup_group = Copy(false);
1654 backup_group.RootPart.Velocity = RootPart.Velocity; 2536 backup_group.RootPart.Velocity = RootPart.Velocity;
1655 backup_group.RootPart.Acceleration = RootPart.Acceleration; 2537 backup_group.RootPart.Acceleration = RootPart.Acceleration;
@@ -1659,13 +2541,21 @@ namespace OpenSim.Region.Framework.Scenes
1659 GroupContainsForeignPrims = false; 2541 GroupContainsForeignPrims = false;
1660 2542
1661 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this); 2543 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2544
1662 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID); 2545 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1663 2546
1664 backup_group.ForEachPart(delegate(SceneObjectPart part) 2547 backup_group.ForEachPart(delegate(SceneObjectPart part)
1665 { 2548 {
1666 part.Inventory.ProcessInventoryBackup(datastore); 2549 part.Inventory.ProcessInventoryBackup(datastore);
2550
2551 if(part.KeyframeMotion != null)
2552 {
2553 part.KeyframeMotion.Delete();
2554 part.KeyframeMotion = null;
2555 }
1667 }); 2556 });
1668 2557
2558 backup_group.Clear();
1669 backup_group = null; 2559 backup_group = null;
1670 } 2560 }
1671// else 2561// else
@@ -1679,7 +2569,7 @@ namespace OpenSim.Region.Framework.Scenes
1679 catch (Exception e) 2569 catch (Exception e)
1680 { 2570 {
1681 m_log.ErrorFormat( 2571 m_log.ErrorFormat(
1682 "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}", 2572 "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}",
1683 Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace); 2573 Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace);
1684 } 2574 }
1685 } 2575 }
@@ -1715,14 +2605,21 @@ namespace OpenSim.Region.Framework.Scenes
1715 /// <returns></returns> 2605 /// <returns></returns>
1716 public SceneObjectGroup Copy(bool userExposed) 2606 public SceneObjectGroup Copy(bool userExposed)
1717 { 2607 {
1718 // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up 2608 m_dupeInProgress = true;
1719 // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator
1720 // but not between regions on different simulators). Really, all copying should be done explicitly.
1721 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone(); 2609 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1722 2610
1723 dupe.Backup = false;
1724 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>(); 2611 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
2612
2613 // a copy isnt backedup
2614 dupe.Backup = false;
2615 dupe.InvalidBoundsRadius();
2616
2617 // a copy is not in transit hopefully
2618 dupe.inTransit = false;
2619
2620 // new group as no sitting avatars
1725 dupe.m_sittingAvatars = new List<ScenePresence>(); 2621 dupe.m_sittingAvatars = new List<ScenePresence>();
2622
1726 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed); 2623 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1727 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum; 2624 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1728 2625
@@ -1730,12 +2627,12 @@ namespace OpenSim.Region.Framework.Scenes
1730 dupe.m_rootPart.TrimPermissions(); 2627 dupe.m_rootPart.TrimPermissions();
1731 2628
1732 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray()); 2629 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1733 2630
1734 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2) 2631 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1735 { 2632 {
1736 return p1.LinkNum.CompareTo(p2.LinkNum); 2633 return p1.LinkNum.CompareTo(p2.LinkNum);
1737 } 2634 }
1738 ); 2635 );
1739 2636
1740 foreach (SceneObjectPart part in partList) 2637 foreach (SceneObjectPart part in partList)
1741 { 2638 {
@@ -1744,43 +2641,59 @@ namespace OpenSim.Region.Framework.Scenes
1744 { 2641 {
1745 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed); 2642 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1746 newPart.LinkNum = part.LinkNum; 2643 newPart.LinkNum = part.LinkNum;
1747 } 2644// if (userExposed)
2645 newPart.ParentID = dupe.m_rootPart.LocalId;
2646 }
1748 else 2647 else
1749 { 2648 {
1750 newPart = dupe.m_rootPart; 2649 newPart = dupe.m_rootPart;
1751 } 2650 }
2651/*
2652 bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2653 bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
1752 2654
1753 // Need to duplicate the physics actor as well 2655 // Need to duplicate the physics actor as well
1754 PhysicsActor originalPartPa = part.PhysActor; 2656 if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
1755 if (originalPartPa != null && userExposed)
1756 { 2657 {
1757 PrimitiveBaseShape pbs = newPart.Shape; 2658 PrimitiveBaseShape pbs = newPart.Shape;
1758
1759 newPart.PhysActor 2659 newPart.PhysActor
1760 = m_scene.PhysicsScene.AddPrimShape( 2660 = m_scene.PhysicsScene.AddPrimShape(
1761 string.Format("{0}/{1}", newPart.Name, newPart.UUID), 2661 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1762 pbs, 2662 pbs,
1763 newPart.AbsolutePosition, 2663 newPart.AbsolutePosition,
1764 newPart.Scale, 2664 newPart.Scale,
1765 newPart.RotationOffset, 2665 newPart.GetWorldRotation(),
1766 originalPartPa.IsPhysical, 2666 isphys,
2667 isphan,
1767 newPart.LocalId); 2668 newPart.LocalId);
1768 2669
1769 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true); 2670 newPart.DoPhysicsPropertyUpdate(isphys, true);
1770 } 2671 */
2672 if (userExposed)
2673 newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2674// }
2675 // copy keyframemotion
1771 if (part.KeyframeMotion != null) 2676 if (part.KeyframeMotion != null)
1772 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe); 2677 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1773 } 2678 }
1774 2679
1775 if (userExposed) 2680 if (userExposed)
1776 { 2681 {
1777 dupe.UpdateParentIDs(); 2682// done above dupe.UpdateParentIDs();
2683
2684 if (dupe.m_rootPart.PhysActor != null)
2685 dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2686
2687 dupe.InvalidateDeepEffectivePerms();
2688
1778 dupe.HasGroupChanged = true; 2689 dupe.HasGroupChanged = true;
1779 dupe.AttachToBackup(); 2690 dupe.AttachToBackup();
1780 2691
1781 ScheduleGroupForFullUpdate(); 2692 dupe.ScheduleGroupForFullUpdate();
1782 } 2693 }
1783 2694
2695 dupe.InvalidatePartsLinkMaps();
2696 m_dupeInProgress = false;
1784 return dupe; 2697 return dupe;
1785 } 2698 }
1786 2699
@@ -1792,7 +2705,13 @@ namespace OpenSim.Region.Framework.Scenes
1792 /// <param name="cGroupID"></param> 2705 /// <param name="cGroupID"></param>
1793 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2706 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1794 { 2707 {
1795 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed)); 2708 SceneObjectPart newpart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed);
2709// SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2710// newpart.LocalId = m_scene.AllocateLocalId();
2711
2712 SetRootPart(newpart);
2713 if (userExposed)
2714 RootPart.Velocity = Vector3.Zero; // In case source is moving
1796 } 2715 }
1797 2716
1798 public void ScriptSetPhysicsStatus(bool usePhysics) 2717 public void ScriptSetPhysicsStatus(bool usePhysics)
@@ -1803,35 +2722,22 @@ namespace OpenSim.Region.Framework.Scenes
1803 RootPart.KeyframeMotion.Stop(); 2722 RootPart.KeyframeMotion.Stop();
1804 RootPart.KeyframeMotion = null; 2723 RootPart.KeyframeMotion = null;
1805 } 2724 }
1806 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect); 2725 UpdateFlags(usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1807 } 2726 }
1808 2727
1809 public void ScriptSetTemporaryStatus(bool makeTemporary) 2728 public void ScriptSetTemporaryStatus(bool makeTemporary)
1810 { 2729 {
1811 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect); 2730 UpdateFlags(UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect);
1812 } 2731 }
1813 2732
1814 public void ScriptSetPhantomStatus(bool makePhantom) 2733 public void ScriptSetPhantomStatus(bool makePhantom)
1815 { 2734 {
1816 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect); 2735 UpdateFlags(UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect);
1817 } 2736 }
1818 2737
1819 public void ScriptSetVolumeDetect(bool makeVolumeDetect) 2738 public void ScriptSetVolumeDetect(bool makeVolumeDetect)
1820 { 2739 {
1821 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect); 2740 UpdateFlags(UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect);
1822
1823 /*
1824 ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore
1825
1826 if (PhysActor != null) // Should always be the case now
1827 {
1828 PhysActor.SetVolumeDetect(param);
1829 }
1830 if (param != 0)
1831 AddFlag(PrimFlags.Phantom);
1832
1833 ScheduleFullUpdate();
1834 */
1835 } 2741 }
1836 2742
1837 public void applyImpulse(Vector3 impulse) 2743 public void applyImpulse(Vector3 impulse)
@@ -1850,13 +2756,14 @@ namespace OpenSim.Region.Framework.Scenes
1850 2756
1851 if (pa != null) 2757 if (pa != null)
1852 { 2758 {
1853 pa.AddForce(impulse, true); 2759 // false to be applied as a impulse
2760 pa.AddForce(impulse, false);
1854 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2761 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1855 } 2762 }
1856 } 2763 }
1857 } 2764 }
1858 2765
1859 public void applyAngularImpulse(Vector3 impulse) 2766 public void ApplyAngularImpulse(Vector3 impulse)
1860 { 2767 {
1861 PhysicsActor pa = RootPart.PhysActor; 2768 PhysicsActor pa = RootPart.PhysActor;
1862 2769
@@ -1864,21 +2771,8 @@ namespace OpenSim.Region.Framework.Scenes
1864 { 2771 {
1865 if (!IsAttachment) 2772 if (!IsAttachment)
1866 { 2773 {
1867 pa.AddAngularForce(impulse, true); 2774 // false to be applied as a impulse
1868 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2775 pa.AddAngularForce(impulse, false);
1869 }
1870 }
1871 }
1872
1873 public void setAngularImpulse(Vector3 impulse)
1874 {
1875 PhysicsActor pa = RootPart.PhysActor;
1876
1877 if (pa != null)
1878 {
1879 if (!IsAttachment)
1880 {
1881 pa.Torque = impulse;
1882 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 2776 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1883 } 2777 }
1884 } 2778 }
@@ -1886,20 +2780,10 @@ namespace OpenSim.Region.Framework.Scenes
1886 2780
1887 public Vector3 GetTorque() 2781 public Vector3 GetTorque()
1888 { 2782 {
1889 PhysicsActor pa = RootPart.PhysActor; 2783 return RootPart.Torque;
1890
1891 if (pa != null)
1892 {
1893 if (!IsAttachment)
1894 {
1895 Vector3 torque = pa.Torque;
1896 return torque;
1897 }
1898 }
1899
1900 return Vector3.Zero;
1901 } 2784 }
1902 2785
2786 // This is used by llMoveToTarget() in an attached object
1903 public void MoveToTarget(Vector3 target, float tau) 2787 public void MoveToTarget(Vector3 target, float tau)
1904 { 2788 {
1905 if (IsAttachment) 2789 if (IsAttachment)
@@ -1907,7 +2791,7 @@ namespace OpenSim.Region.Framework.Scenes
1907 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); 2791 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1908 2792
1909 if (avatar != null) 2793 if (avatar != null)
1910 avatar.MoveToTarget(target, false, false); 2794 avatar.MoveToTarget(target, false, false, tau);
1911 } 2795 }
1912 else 2796 else
1913 { 2797 {
@@ -1929,21 +2813,73 @@ namespace OpenSim.Region.Framework.Scenes
1929 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar); 2813 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1930 2814
1931 if (avatar != null) 2815 if (avatar != null)
2816 {
1932 avatar.ResetMoveToTarget(); 2817 avatar.ResetMoveToTarget();
2818 }
1933 } 2819 }
1934 else 2820 else
1935 { 2821 {
1936 PhysicsActor pa = RootPart.PhysActor; 2822 PhysicsActor pa = RootPart.PhysActor;
1937 2823
1938 if (pa != null && pa.PIDActive) 2824 if (pa != null)
1939 {
1940 pa.PIDActive = false; 2825 pa.PIDActive = false;
1941 2826
1942 ScheduleGroupForTerseUpdate(); 2827 RootPart.ScheduleTerseUpdate(); // send a stop information
2828 }
2829 }
2830
2831 public void RotLookAt(Quaternion target, float strength, float damping)
2832 {
2833 if(IsDeleted)
2834 return;
2835
2836 // non physical is handle in LSL api
2837 if(!UsesPhysics || IsAttachment)
2838 return;
2839
2840 SceneObjectPart rootpart = m_rootPart;
2841 if (rootpart != null)
2842 {
2843/* physics still doesnt suport this
2844 if (rootpart.PhysActor != null)
2845 {
2846 rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2847 rootpart.PhysActor.APIDStrength = strength;
2848 rootpart.PhysActor.APIDDamping = damping;
2849 rootpart.PhysActor.APIDActive = true;
1943 } 2850 }
2851*/
2852 // so do it in rootpart
2853 rootpart.RotLookAt(target, strength, damping);
2854 }
2855 }
2856
2857 public void StartLookAt(Quaternion target, float strength, float damping)
2858 {
2859 if(IsDeleted)
2860 return;
2861
2862 // non physical is done by LSL APi
2863 if(!UsesPhysics || IsAttachment)
2864 return;
2865
2866 if (m_rootPart != null)
2867 m_rootPart.RotLookAt(target, strength, damping);
2868 }
2869
2870 public void StopLookAt()
2871 {
2872 SceneObjectPart rootpart = m_rootPart;
2873 if (rootpart != null)
2874 {
2875 if (rootpart.PhysActor != null)
2876 {
2877 rootpart.PhysActor.APIDActive = false;
2878 }
2879
2880 rootpart.StopLookAt();
1944 } 2881 }
1945 } 2882 }
1946
1947 /// <summary> 2883 /// <summary>
1948 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds. 2884 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1949 /// </summary> 2885 /// </summary>
@@ -1952,7 +2888,15 @@ namespace OpenSim.Region.Framework.Scenes
1952 /// <param name="tau">Number of seconds over which to reach target</param> 2888 /// <param name="tau">Number of seconds over which to reach target</param>
1953 public void SetHoverHeight(float height, PIDHoverType hoverType, float tau) 2889 public void SetHoverHeight(float height, PIDHoverType hoverType, float tau)
1954 { 2890 {
1955 PhysicsActor pa = RootPart.PhysActor; 2891 PhysicsActor pa = null;
2892 if(IsAttachment)
2893 {
2894 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
2895 if (avatar != null)
2896 pa = avatar.PhysicsActor;
2897 }
2898 else
2899 pa = RootPart.PhysActor;
1956 2900
1957 if (pa != null) 2901 if (pa != null)
1958 { 2902 {
@@ -1960,7 +2904,7 @@ namespace OpenSim.Region.Framework.Scenes
1960 { 2904 {
1961 pa.PIDHoverHeight = height; 2905 pa.PIDHoverHeight = height;
1962 pa.PIDHoverType = hoverType; 2906 pa.PIDHoverType = hoverType;
1963 pa.PIDTau = tau; 2907 pa.PIDHoverTau = tau;
1964 pa.PIDHoverActive = true; 2908 pa.PIDHoverActive = true;
1965 } 2909 }
1966 else 2910 else
@@ -1971,25 +2915,33 @@ namespace OpenSim.Region.Framework.Scenes
1971 } 2915 }
1972 2916
1973 /// <summary> 2917 /// <summary>
1974 /// Set the owner of the root part. 2918 /// Set the owner of all linkset.
1975 /// </summary> 2919 /// </summary>
1976 /// <param name="part"></param>
1977 /// <param name="cAgentID"></param> 2920 /// <param name="cAgentID"></param>
1978 /// <param name="cGroupID"></param> 2921 /// <param name="cGroupID"></param>
1979 public void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID) 2922 public void SetOwner(UUID cAgentID, UUID cGroupID)
1980 { 2923 {
1981 part.LastOwnerID = part.OwnerID; 2924 SceneObjectPart rpart = RootPart;
1982 part.OwnerID = cAgentID; 2925 UUID oldowner = rpart.OwnerID;
1983 part.GroupID = cGroupID; 2926 ForEachPart(delegate(SceneObjectPart part)
2927 {
2928 if(part.GroupID != part.OwnerID)
2929 part.LastOwnerID = part.OwnerID;
2930 part.OwnerID = cAgentID;
2931 part.GroupID = cGroupID;
2932 });
1984 2933
1985 if (part.OwnerID != cAgentID) 2934 if (oldowner != cAgentID)
1986 { 2935 {
1987 // Apply Next Owner Permissions if we're not bypassing permissions 2936 // Apply Next Owner Permissions if we're not bypassing permissions
1988 if (!m_scene.Permissions.BypassPermissions()) 2937 if (!m_scene.Permissions.BypassPermissions())
2938 {
1989 ApplyNextOwnerPermissions(); 2939 ApplyNextOwnerPermissions();
2940 InvalidateEffectivePerms();
2941 }
1990 } 2942 }
1991 2943
1992 part.ScheduleFullUpdate(); 2944 rpart.ScheduleFullUpdate();
1993 } 2945 }
1994 2946
1995 /// <summary> 2947 /// <summary>
@@ -2001,6 +2953,9 @@ namespace OpenSim.Region.Framework.Scenes
2001 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed) 2953 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
2002 { 2954 {
2003 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed); 2955 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2956// SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2957// newPart.LocalId = m_scene.AllocateLocalId();
2958
2004 AddPart(newPart); 2959 AddPart(newPart);
2005 2960
2006 SetPartAsNonRoot(newPart); 2961 SetPartAsNonRoot(newPart);
@@ -2035,7 +2990,7 @@ namespace OpenSim.Region.Framework.Scenes
2035 public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags) 2990 public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
2036 { 2991 {
2037 remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags); 2992 remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags);
2038 2993
2039// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask, 2994// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
2040// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask, 2995// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
2041// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category, 2996// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
@@ -2050,6 +3005,7 @@ namespace OpenSim.Region.Framework.Scenes
2050 3005
2051 #endregion 3006 #endregion
2052 3007
3008
2053 public override void Update() 3009 public override void Update()
2054 { 3010 {
2055 // Check that the group was not deleted before the scheduled update 3011 // Check that the group was not deleted before the scheduled update
@@ -2057,7 +3013,7 @@ namespace OpenSim.Region.Framework.Scenes
2057 // an object has been deleted from a scene before update was processed. 3013 // an object has been deleted from a scene before update was processed.
2058 // A more fundamental overhaul of the update mechanism is required to eliminate all 3014 // A more fundamental overhaul of the update mechanism is required to eliminate all
2059 // the race conditions. 3015 // the race conditions.
2060 if (IsDeleted) 3016 if (IsDeleted || inTransit)
2061 return; 3017 return;
2062 3018
2063 // Even temporary objects take part in physics (e.g. temp-on-rez bullets) 3019 // Even temporary objects take part in physics (e.g. temp-on-rez bullets)
@@ -2065,31 +3021,36 @@ namespace OpenSim.Region.Framework.Scenes
2065 // return; 3021 // return;
2066 3022
2067 // If we somehow got here to updating the SOG and its root part is not scheduled for update, 3023 // If we somehow got here to updating the SOG and its root part is not scheduled for update,
2068 // check to see if the physical position or rotation warrant an update. 3024 // check to see if the physical position or rotation warrant an update.
3025/*
2069 if (m_rootPart.UpdateFlag == UpdateRequired.NONE) 3026 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
2070 { 3027 {
2071 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0); 3028 // rootpart SendScheduledUpdates will check if a update is needed
2072 3029 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2073 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f)) 3030 }
2074 { 3031*/
2075 m_rootPart.UpdateFlag = UpdateRequired.TERSE; 3032 if (IsAttachment)
2076 lastPhysGroupPos = AbsolutePosition; 3033 {
2077 } 3034 ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
2078 3035 if (sp != null)
2079 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
2080 { 3036 {
2081 m_rootPart.UpdateFlag = UpdateRequired.TERSE; 3037 sp.SendAttachmentScheduleUpdate(this);
2082 lastPhysGroupRot = GroupRotation; 3038 return;
2083 } 3039 }
2084 } 3040 }
2085 3041
3042 // while physics doesn't suports LookAt, we do it in RootPart
3043 if (!IsSelected)
3044 RootPart.UpdateLookAt();
3045
3046 double now = Util.GetTimeStampMS();
3047 RootPart.SendScheduledUpdates(now);
2086 SceneObjectPart[] parts = m_parts.GetArray(); 3048 SceneObjectPart[] parts = m_parts.GetArray();
2087 for (int i = 0; i < parts.Length; i++) 3049 for (int i = 0; i < parts.Length; i++)
2088 { 3050 {
2089 SceneObjectPart part = parts[i]; 3051 SceneObjectPart part = parts[i];
2090 if (!IsSelected) 3052 if(part != RootPart)
2091 part.UpdateLookAt(); 3053 part.SendScheduledUpdates(now);
2092 part.SendScheduledUpdates();
2093 } 3054 }
2094 } 3055 }
2095 3056
@@ -2105,7 +3066,7 @@ namespace OpenSim.Region.Framework.Scenes
2105 { 3066 {
2106// if (IsAttachment) 3067// if (IsAttachment)
2107// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId); 3068// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId);
2108 3069
2109 checkAtTargets(); 3070 checkAtTargets();
2110 RootPart.ScheduleFullUpdate(); 3071 RootPart.ScheduleFullUpdate();
2111 3072
@@ -2144,15 +3105,24 @@ namespace OpenSim.Region.Framework.Scenes
2144 return; 3105 return;
2145 3106
2146// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID); 3107// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2147
2148 RootPart.SendFullUpdateToAllClients();
2149 3108
3109 if (IsAttachment)
3110 {
3111 ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
3112 if (sp != null)
3113 {
3114 sp.SendAttachmentUpdate(this,UpdateRequired.FULL);
3115 return;
3116 }
3117 }
3118
3119 RootPart.SendFullUpdateToAllClientsInternal();
2150 SceneObjectPart[] parts = m_parts.GetArray(); 3120 SceneObjectPart[] parts = m_parts.GetArray();
2151 for (int i = 0; i < parts.Length; i++) 3121 for (int i = 0; i < parts.Length; i++)
2152 { 3122 {
2153 SceneObjectPart part = parts[i]; 3123 SceneObjectPart part = parts[i];
2154 if (part != RootPart) 3124 if (part != RootPart)
2155 part.SendFullUpdateToAllClients(); 3125 part.SendFullUpdateToAllClientsInternal();
2156 } 3126 }
2157 } 3127 }
2158 3128
@@ -2164,7 +3134,7 @@ namespace OpenSim.Region.Framework.Scenes
2164 /// </summary> 3134 /// </summary>
2165 public void SendGroupRootTerseUpdate() 3135 public void SendGroupRootTerseUpdate()
2166 { 3136 {
2167 if (IsDeleted) 3137 if (IsDeleted || inTransit)
2168 return; 3138 return;
2169 3139
2170 RootPart.SendTerseUpdateToAllClients(); 3140 RootPart.SendTerseUpdateToAllClients();
@@ -2174,7 +3144,7 @@ namespace OpenSim.Region.Framework.Scenes
2174 { 3144 {
2175 if (m_scene == null) // Need to check here as it's null during object creation 3145 if (m_scene == null) // Need to check here as it's null during object creation
2176 return; 3146 return;
2177 3147
2178 m_scene.SceneGraph.AddToUpdateList(this); 3148 m_scene.SceneGraph.AddToUpdateList(this);
2179 } 3149 }
2180 3150
@@ -2183,12 +3153,22 @@ namespace OpenSim.Region.Framework.Scenes
2183 /// </summary> 3153 /// </summary>
2184 public void SendGroupTerseUpdate() 3154 public void SendGroupTerseUpdate()
2185 { 3155 {
2186 if (IsDeleted) 3156 if (IsDeleted || inTransit)
2187 return; 3157 return;
2188 3158
3159 if (IsAttachment)
3160 {
3161 ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
3162 if (sp != null)
3163 {
3164 sp.SendAttachmentUpdate(this, UpdateRequired.TERSE);
3165 return;
3166 }
3167 }
3168
2189 SceneObjectPart[] parts = m_parts.GetArray(); 3169 SceneObjectPart[] parts = m_parts.GetArray();
2190 for (int i = 0; i < parts.Length; i++) 3170 for (int i = 0; i < parts.Length; i++)
2191 parts[i].SendTerseUpdateToAllClients(); 3171 parts[i].SendTerseUpdateToAllClientsInternal();
2192 } 3172 }
2193 3173
2194 /// <summary> 3174 /// <summary>
@@ -2296,9 +3276,41 @@ namespace OpenSim.Region.Framework.Scenes
2296 return; 3276 return;
2297 } 3277 }
2298 3278
3279 // physical prims count limit
3280 // not very eficient :(
3281
3282 if (UsesPhysics && m_scene.m_linksetPhysCapacity > 0 && (PrimCount + objectGroup.PrimCount) >
3283 m_scene.m_linksetPhysCapacity)
3284 {
3285 int cntr = 0;
3286 foreach (SceneObjectPart part in Parts)
3287 {
3288 if (part.PhysicsShapeType != (byte)PhysicsShapeType.None)
3289 cntr++;
3290 }
3291 foreach (SceneObjectPart part in objectGroup.Parts)
3292 {
3293 if (part.PhysicsShapeType != (byte)PhysicsShapeType.None)
3294 cntr++;
3295 }
3296
3297 if (cntr > m_scene.m_linksetPhysCapacity)
3298 {
3299 // cancel physics
3300 RootPart.Flags &= ~PrimFlags.Physics;
3301 ApplyPhysics();
3302 }
3303 }
3304
3305
2299 // 'linkPart' == the root of the group being linked into this group 3306 // 'linkPart' == the root of the group being linked into this group
2300 SceneObjectPart linkPart = objectGroup.m_rootPart; 3307 SceneObjectPart linkPart = objectGroup.m_rootPart;
2301 3308
3309 if (m_rootPart.PhysActor != null)
3310 m_rootPart.PhysActor.Building = true;
3311 if (linkPart.PhysActor != null)
3312 linkPart.PhysActor.Building = true;
3313
2302 // physics flags from group to be applied to linked parts 3314 // physics flags from group to be applied to linked parts
2303 bool grpusephys = UsesPhysics; 3315 bool grpusephys = UsesPhysics;
2304 bool grptemporary = IsTemporary; 3316 bool grptemporary = IsTemporary;
@@ -2307,7 +3319,7 @@ namespace OpenSim.Region.Framework.Scenes
2307 Vector3 oldGroupPosition = linkPart.GroupPosition; 3319 Vector3 oldGroupPosition = linkPart.GroupPosition;
2308 Quaternion oldRootRotation = linkPart.RotationOffset; 3320 Quaternion oldRootRotation = linkPart.RotationOffset;
2309 3321
2310 // A linked SOP remembers its location and rotation relative to the root of a group. 3322 // A linked SOP remembers its location and rotation relative to the root of a group.
2311 // Convert the root of the group being linked to be relative to the 3323 // Convert the root of the group being linked to be relative to the
2312 // root of the group being linked to. 3324 // root of the group being linked to.
2313 // Note: Some of the assignments have complex side effects. 3325 // Note: Some of the assignments have complex side effects.
@@ -2315,22 +3327,24 @@ namespace OpenSim.Region.Framework.Scenes
2315 // First move the new group's root SOP's position to be relative to ours 3327 // First move the new group's root SOP's position to be relative to ours
2316 // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not, 3328 // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not,
2317 // this code can be reordered to have a more logical flow.) 3329 // this code can be reordered to have a more logical flow.)
2318 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition; 3330 linkPart.setOffsetPosition(linkPart.GroupPosition - AbsolutePosition);
2319 // Assign the new parent to the root of the old group 3331 // Assign the new parent to the root of the old group
2320 linkPart.ParentID = m_rootPart.LocalId; 3332 linkPart.ParentID = m_rootPart.LocalId;
2321 // Now that it's a child, it's group position is our root position 3333 // Now that it's a child, it's group position is our root position
2322 linkPart.GroupPosition = AbsolutePosition; 3334 linkPart.setGroupPosition(AbsolutePosition);
2323 3335
2324 Vector3 axPos = linkPart.OffsetPosition;
2325 // Rotate the linking root SOP's position to be relative to the new root prim 3336 // Rotate the linking root SOP's position to be relative to the new root prim
2326 Quaternion parentRot = m_rootPart.RotationOffset; 3337 Quaternion parentRot = m_rootPart.RotationOffset;
2327 axPos *= Quaternion.Inverse(parentRot);
2328 linkPart.OffsetPosition = axPos;
2329 3338
2330 // Make the linking root SOP's rotation relative to the new root prim 3339 // Make the linking root SOP's rotation relative to the new root prim
2331 Quaternion oldRot = linkPart.RotationOffset; 3340 Quaternion oldRot = linkPart.RotationOffset;
2332 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3341 Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
2333 linkPart.RotationOffset = newRot; 3342 linkPart.setRotationOffset(newRot);
3343
3344 Vector3 axPos = linkPart.OffsetPosition;
3345 axPos *= Quaternion.Conjugate(parentRot);
3346 linkPart.OffsetPosition = axPos;
3347
2334 3348
2335 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset. 3349 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
2336 // Now that we know this SOG has at least two SOPs in it, the new root 3350 // Now that we know this SOG has at least two SOPs in it, the new root
@@ -2345,10 +3359,11 @@ namespace OpenSim.Region.Framework.Scenes
2345 if (insert) 3359 if (insert)
2346 { 3360 {
2347 linkNum = 2; 3361 linkNum = 2;
3362 int insertSize = objectGroup.PrimCount;
2348 foreach (SceneObjectPart part in Parts) 3363 foreach (SceneObjectPart part in Parts)
2349 { 3364 {
2350 if (part.LinkNum > 1) 3365 if (part.LinkNum > 1)
2351 part.LinkNum++; 3366 part.LinkNum += insertSize;
2352 } 3367 }
2353 } 3368 }
2354 else 3369 else
@@ -2360,10 +3375,12 @@ namespace OpenSim.Region.Framework.Scenes
2360 m_parts.Add(linkPart.UUID, linkPart); 3375 m_parts.Add(linkPart.UUID, linkPart);
2361 3376
2362 linkPart.SetParent(this); 3377 linkPart.SetParent(this);
3378 m_scene.updateScenePartGroup(linkPart, this);
3379
2363 linkPart.CreateSelected = true; 3380 linkPart.CreateSelected = true;
2364 3381
2365 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now 3382 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2366 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive); 3383 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
2367 3384
2368 // If the added SOP is physical, also tell the physics engine about the link relationship. 3385 // If the added SOP is physical, also tell the physics engine about the link relationship.
2369 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 3386 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2373,15 +3390,16 @@ namespace OpenSim.Region.Framework.Scenes
2373 } 3390 }
2374 3391
2375 linkPart.LinkNum = linkNum++; 3392 linkPart.LinkNum = linkNum++;
3393 linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2376 3394
2377 // Get a list of the SOP's in the old group in order of their linknum's. 3395 // Get a list of the SOP's in the source group in order of their linknum's.
2378 SceneObjectPart[] ogParts = objectGroup.Parts; 3396 SceneObjectPart[] ogParts = objectGroup.Parts;
2379 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b) 3397 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
2380 { 3398 {
2381 return a.LinkNum - b.LinkNum; 3399 return a.LinkNum - b.LinkNum;
2382 }); 3400 });
2383 3401
2384 // Add each of the SOP's from the old linkset to our linkset 3402 // Add each of the SOP's from the source linkset to our linkset
2385 for (int i = 0; i < ogParts.Length; i++) 3403 for (int i = 0; i < ogParts.Length; i++)
2386 { 3404 {
2387 SceneObjectPart part = ogParts[i]; 3405 SceneObjectPart part = ogParts[i];
@@ -2391,7 +3409,7 @@ namespace OpenSim.Region.Framework.Scenes
2391 3409
2392 // Update the physics flags for the newly added SOP 3410 // Update the physics flags for the newly added SOP
2393 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??) 3411 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2394 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive); 3412 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
2395 3413
2396 // If the added SOP is physical, also tell the physics engine about the link relationship. 3414 // If the added SOP is physical, also tell the physics engine about the link relationship.
2397 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical) 3415 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
@@ -2420,11 +3438,17 @@ namespace OpenSim.Region.Framework.Scenes
2420 3438
2421 AttachToBackup(); 3439 AttachToBackup();
2422 3440
2423 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the 3441 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
2424 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and 3442 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
2425 // unmoved prims! 3443 // unmoved prims!
2426 ResetChildPrimPhysicsPositions(); 3444 ResetChildPrimPhysicsPositions();
2427 3445
3446 InvalidBoundsRadius();
3447 InvalidatePartsLinkMaps();
3448
3449 if (m_rootPart.PhysActor != null)
3450 m_rootPart.PhysActor.Building = false;
3451
2428 //HasGroupChanged = true; 3452 //HasGroupChanged = true;
2429 //ScheduleGroupForFullUpdate(); 3453 //ScheduleGroupForFullUpdate();
2430 } 3454 }
@@ -2492,7 +3516,10 @@ namespace OpenSim.Region.Framework.Scenes
2492// m_log.DebugFormat( 3516// m_log.DebugFormat(
2493// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}", 3517// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2494// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID); 3518// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2495 3519
3520 if (m_rootPart.PhysActor != null)
3521 m_rootPart.PhysActor.Building = true;
3522
2496 linkPart.ClearUndoState(); 3523 linkPart.ClearUndoState();
2497 3524
2498 Vector3 worldPos = linkPart.GetWorldPosition(); 3525 Vector3 worldPos = linkPart.GetWorldPosition();
@@ -2533,7 +3560,10 @@ namespace OpenSim.Region.Framework.Scenes
2533 // engine about the delink. Someday, linksets should be made first 3560 // engine about the delink. Someday, linksets should be made first
2534 // class objects in the physics engine interface). 3561 // class objects in the physics engine interface).
2535 if (linkPartPa != null) 3562 if (linkPartPa != null)
3563 {
2536 m_scene.PhysicsScene.RemovePrim(linkPartPa); 3564 m_scene.PhysicsScene.RemovePrim(linkPartPa);
3565 linkPart.PhysActor = null;
3566 }
2537 3567
2538 // We need to reset the child part's position 3568 // We need to reset the child part's position
2539 // ready for life as a separate object after being a part of another object 3569 // ready for life as a separate object after being a part of another object
@@ -2547,43 +3577,155 @@ namespace OpenSim.Region.Framework.Scenes
2547 linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition; 3577 linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
2548 linkPart.OffsetPosition = new Vector3(0, 0, 0); 3578 linkPart.OffsetPosition = new Vector3(0, 0, 0);
2549 */ 3579 */
2550 linkPart.GroupPosition = worldPos; 3580 linkPart.setGroupPosition(worldPos);
2551 linkPart.OffsetPosition = Vector3.Zero; 3581 linkPart.setOffsetPosition(Vector3.Zero);
2552 linkPart.RotationOffset = worldRot; 3582 linkPart.setRotationOffset(worldRot);
2553 3583
2554 // Create a new SOG to go around this unlinked and unattached SOP 3584 // Create a new SOG to go around this unlinked and unattached SOP
2555 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart); 3585 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
2556 3586
2557 m_scene.AddNewSceneObject(objectGroup, true); 3587 m_scene.AddNewSceneObject(objectGroup, true);
2558 3588
2559 if (sendEvents)
2560 linkPart.TriggerScriptChangedEvent(Changed.LINK);
2561
2562 linkPart.Rezzed = RootPart.Rezzed; 3589 linkPart.Rezzed = RootPart.Rezzed;
2563 3590
2564 // We must persist the delinked group to the database immediately, for safety. The problem 3591 // When we delete a group, we currently have to force persist to the database if the object id has changed
2565 // is that although in memory the new group has a new SceneGroupID, in the database it 3592 // (since delete works by deleting all rows which have a given object id)
2566 // still has the parent group's SceneGroupID (until the next backup). This means that if the 3593
2567 // parent group is deleted then the delinked group will also be deleted from the database. 3594 // this is as it seems to be in sl now
2568 // This problem will disappear if the region remains alive long enough for another backup, 3595 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
2569 // since at that time the delinked group's new SceneGroupID will be written to the database. 3596 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
2570 // But if the region crashes before that then the prims will be permanently gone, and this must 3597
2571 // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case 3598 if (m_rootPart.PhysActor != null)
2572 // because the delinked group doesn't know when the source group is deleted.) 3599 m_rootPart.PhysActor.Building = false;
2573 m_scene.ForceSceneObjectBackup(objectGroup); 3600
3601 objectGroup.HasGroupChangedDueToDelink = true;
3602
3603 InvalidBoundsRadius();
3604 InvalidatePartsLinkMaps();
3605 objectGroup.InvalidateEffectivePerms();
3606
3607 if (sendEvents)
3608 linkPart.TriggerScriptChangedEvent(Changed.LINK);
2574 3609
2575 return objectGroup; 3610 return objectGroup;
2576 } 3611 }
2577 3612
3613/* working on it
3614 public void DelinkFromGroup(List<SceneObjectPart> linkParts, bool sendEvents)
3615 {
3616// m_log.DebugFormat(
3617// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
3618// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
3619
3620 if(PrimCount == 1)
3621 return;
3622
3623 if (m_rootPart.PhysActor != null)
3624 m_rootPart.PhysActor.Building = true;
3625
3626 bool unlinkroot = false;
3627 foreach(SceneObjectPart linkPart in linkParts)
3628 {
3629 // first we only remove child parts
3630 if(linkPart.LocalId == m_rootPart.LocalId)
3631 {
3632 unlinkroot = true;
3633 continue;
3634 }
3635
3636 lock (m_parts.SyncRoot)
3637 if(!m_parts.Remove(linkPart.UUID))
3638 continue;
3639
3640 linkPart.ClearUndoState();
3641
3642 Vector3 worldPos = linkPart.GetWorldPosition();
3643 Quaternion worldRot = linkPart.GetWorldRotation();
3644
3645 linkPart.ParentID = 0;
3646 linkPart.LinkNum = 0;
3647
3648 PhysicsActor linkPartPa = linkPart.PhysActor;
3649
3650 // Remove the SOP from the physical scene.
3651 // If the new SOG is physical, it is re-created later.
3652 // (There is a problem here in that we have not yet told the physics
3653 // engine about the delink. Someday, linksets should be made first
3654 // class objects in the physics engine interface).
3655 if (linkPartPa != null)
3656 {
3657 m_scene.PhysicsScene.RemovePrim(linkPartPa);
3658 linkPart.PhysActor = null;
3659 }
3660
3661 linkPart.setGroupPosition(worldPos);
3662 linkPart.setOffsetPosition(Vector3.Zero);
3663 linkPart.setRotationOffset(worldRot);
3664
3665 // Create a new SOG to go around this unlinked and unattached SOP
3666 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
3667
3668 m_scene.AddNewSceneObject(objectGroup, true);
3669
3670 linkPart.Rezzed = RootPart.Rezzed;
3671
3672 // this is as it seems to be in sl now
3673 if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3674 linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3675
3676 objectGroup.HasGroupChangedDueToDelink = true;
3677 if (sendEvents)
3678 linkPart.TriggerScriptChangedEvent(Changed.LINK);
3679 }
3680
3681 if(unlinkroot)
3682 {
3683 //TODO
3684 }
3685
3686 lock (m_parts.SyncRoot)
3687 {
3688 SceneObjectPart[] parts = m_parts.GetArray();
3689 if (parts.Length == 1)
3690 {
3691 // Single prim left
3692 m_rootPart.LinkNum = 0;
3693 }
3694 else
3695 {
3696 m_rootPart.LinkNum = 1;
3697 int linknum = 2;
3698 for (int i = 1; i < parts.Length; i++)
3699 parts[i].LinkNum = linknum++;
3700 }
3701 }
3702
3703 InvalidBoundsRadius();
3704
3705 if (m_rootPart.PhysActor != null)
3706 m_rootPart.PhysActor.Building = false;
3707
3708 // When we delete a group, we currently have to force persist to the database if the object id has changed
3709 // (since delete works by deleting all rows which have a given object id)
3710
3711 Scene.SimulationDataService.RemoveObject(UUID, Scene.RegionInfo.RegionID);
3712 HasGroupChangedDueToDelink = true;
3713 TriggerScriptChangedEvent(Changed.LINK);
3714 return;
3715 }
3716*/
2578 /// <summary> 3717 /// <summary>
2579 /// Stop this object from being persisted over server restarts. 3718 /// Stop this object from being persisted over server restarts.
2580 /// </summary> 3719 /// </summary>
2581 /// <param name="objectGroup"></param> 3720 /// <param name="objectGroup"></param>
2582 public virtual void DetachFromBackup() 3721 public virtual void DetachFromBackup()
2583 { 3722 {
2584 if (Backup && Scene != null) 3723 if (m_scene != null)
2585 m_scene.EventManager.OnBackup -= ProcessBackup; 3724 {
2586 3725 m_scene.SceneGraph.FireDetachFromBackup(this);
3726 if (Backup)
3727 m_scene.EventManager.OnBackup -= ProcessBackup;
3728 }
2587 Backup = false; 3729 Backup = false;
2588 } 3730 }
2589 3731
@@ -2597,14 +3739,14 @@ namespace OpenSim.Region.Framework.Scenes
2597 Quaternion parentRot = oldGroupRotation; 3739 Quaternion parentRot = oldGroupRotation;
2598 Quaternion oldRot = part.RotationOffset; 3740 Quaternion oldRot = part.RotationOffset;
2599 3741
2600 // Move our position to not be relative to the old parent 3742 // Move our position in world
2601 Vector3 axPos = part.OffsetPosition; 3743 Vector3 axPos = part.OffsetPosition;
2602 axPos *= parentRot; 3744 axPos *= parentRot;
2603 part.OffsetPosition = axPos; 3745 Vector3 newPos = oldGroupPosition + axPos;
2604 part.GroupPosition = oldGroupPosition + part.OffsetPosition; 3746 part.setGroupPosition(newPos);
2605 part.OffsetPosition = Vector3.Zero; 3747 part.setOffsetPosition(Vector3.Zero);
2606 3748
2607 // Compution our rotation to be not relative to the old parent 3749 // Compution our rotation in world
2608 Quaternion worldRot = parentRot * oldRot; 3750 Quaternion worldRot = parentRot * oldRot;
2609 part.RotationOffset = worldRot; 3751 part.RotationOffset = worldRot;
2610 3752
@@ -2615,29 +3757,32 @@ namespace OpenSim.Region.Framework.Scenes
2615 3757
2616 part.LinkNum = linkNum; 3758 part.LinkNum = linkNum;
2617 3759
3760 m_scene.updateScenePartGroup(part, this);
3761
2618 // Compute the new position of this SOP relative to the group position 3762 // Compute the new position of this SOP relative to the group position
2619 part.OffsetPosition = part.GroupPosition - AbsolutePosition; 3763 part.setOffsetPosition(newPos - AbsolutePosition);
2620 3764
2621 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times. 3765 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2622 // It would have the affect of setting the physics engine position multiple 3766 // It would have the affect of setting the physics engine position multiple
2623 // times. In theory, that is not necessary but I don't have a good linkset 3767 // times. In theory, that is not necessary but I don't have a good linkset
2624 // test to know that cleaning up this code wouldn't break things.) 3768 // test to know that cleaning up this code wouldn't break things.)
2625 3769
2626 // Rotate the relative position by the rotation of the group
2627 Quaternion rootRotation = m_rootPart.RotationOffset;
2628 Vector3 pos = part.OffsetPosition;
2629 pos *= Quaternion.Inverse(rootRotation);
2630 part.OffsetPosition = pos;
2631
2632 // Compute the SOP's rotation relative to the rotation of the group. 3770 // Compute the SOP's rotation relative to the rotation of the group.
2633 parentRot = m_rootPart.RotationOffset; 3771 parentRot = m_rootPart.RotationOffset;
3772
2634 oldRot = part.RotationOffset; 3773 oldRot = part.RotationOffset;
2635 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot; 3774 Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
2636 part.RotationOffset = newRot; 3775 part.setRotationOffset(newRot);
3776
3777 Vector3 pos = part.OffsetPosition;
3778 pos *= Quaternion.Conjugate(parentRot);
3779
3780 part.OffsetPosition = pos; // update position and orientation on physics also
2637 3781
2638 // Since this SOP's state has changed, push those changes into the physics engine 3782 // Since this SOP's state has changed, push those changes into the physics engine
2639 // and the simulator. 3783 // and the simulator.
2640 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect); 3784 // done on caller
3785// part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
2641 } 3786 }
2642 3787
2643 /// <summary> 3788 /// <summary>
@@ -2652,30 +3797,26 @@ namespace OpenSim.Region.Framework.Scenes
2652 { 3797 {
2653 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 3798 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2654 { 3799 {
3800 if (BlockGrabOverride)
3801 return;
3802
2655 SceneObjectPart part = GetPart(partID); 3803 SceneObjectPart part = GetPart(partID);
2656 3804
2657 if (part == null) 3805 if (part == null)
2658 return; 3806 return;
2659 3807
3808 if (part.BlockGrab)
3809 return;
3810
2660 PhysicsActor pa = m_rootPart.PhysActor; 3811 PhysicsActor pa = m_rootPart.PhysActor;
2661 3812
2662 if (pa != null) 3813 if (pa != null && pa.IsPhysical)
2663 { 3814 {
2664 if (pa.IsPhysical) 3815 // empirically convert distance diference to a impulse
2665 { 3816 Vector3 grabforce = pos - AbsolutePosition;
2666 if (!BlockGrabOverride && !part.BlockGrab) 3817 grabforce = grabforce * (pa.Mass * 0.1f);
2667 { 3818 pa.AddForce(grabforce, false);
2668 Vector3 llmoveforce = pos - AbsolutePosition; 3819 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2669 Vector3 grabforce = llmoveforce;
2670 grabforce = (grabforce / 10) * pa.Mass;
2671 pa.AddForce(grabforce, true);
2672 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2673 }
2674 }
2675 else
2676 {
2677 NonPhysicalGrabMovement(pos);
2678 }
2679 } 3820 }
2680 else 3821 else
2681 { 3822 {
@@ -2704,6 +3845,8 @@ namespace OpenSim.Region.Framework.Scenes
2704 /// <param name="remoteClient"></param> 3845 /// <param name="remoteClient"></param>
2705 public void SpinStart(IClientAPI remoteClient) 3846 public void SpinStart(IClientAPI remoteClient)
2706 { 3847 {
3848 if (BlockGrabOverride || m_rootPart.BlockGrab)
3849 return;
2707 if (m_scene.EventManager.TriggerGroupSpinStart(UUID)) 3850 if (m_scene.EventManager.TriggerGroupSpinStart(UUID))
2708 { 3851 {
2709 PhysicsActor pa = m_rootPart.PhysActor; 3852 PhysicsActor pa = m_rootPart.PhysActor;
@@ -2725,72 +3868,74 @@ namespace OpenSim.Region.Framework.Scenes
2725 /// <param name="remoteClient"></param> 3868 /// <param name="remoteClient"></param>
2726 public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient) 3869 public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient)
2727 { 3870 {
2728 // The incoming newOrientation, sent by the client, "seems" to be the 3871 // The incoming newOrientation, sent by the client, "seems" to be the
2729 // desired target orientation. This needs further verification; in particular, 3872 // desired target orientation. This needs further verification; in particular,
2730 // one would expect that the initial incoming newOrientation should be 3873 // one would expect that the initial incoming newOrientation should be
2731 // fairly close to the original prim's physical orientation, 3874 // fairly close to the original prim's physical orientation,
2732 // m_rootPart.PhysActor.Orientation. This however does not seem to be the 3875 // m_rootPart.PhysActor.Orientation. This however does not seem to be the
2733 // case (might just be an issue with different quaternions representing the 3876 // case (might just be an issue with different quaternions representing the
2734 // same rotation, or it might be a coordinate system issue). 3877 // same rotation, or it might be a coordinate system issue).
2735 // 3878 //
2736 // Since it's not clear what the relationship is between the PhysActor.Orientation 3879 // Since it's not clear what the relationship is between the PhysActor.Orientation
2737 // and the incoming orientations sent by the client, we take an alternative approach 3880 // and the incoming orientations sent by the client, we take an alternative approach
2738 // of calculating the delta rotation between the orientations being sent by the 3881 // of calculating the delta rotation between the orientations being sent by the
2739 // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect 3882 // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect
2740 // a steady stream of several new orientations coming in from the client.) 3883 // a steady stream of several new orientations coming in from the client.)
2741 // This ensures that the delta rotations are being calculated from self-consistent 3884 // This ensures that the delta rotations are being calculated from self-consistent
2742 // pairs of old/new rotations. Given the delta rotation, we apply a torque around 3885 // pairs of old/new rotations. Given the delta rotation, we apply a torque around
2743 // the delta rotation axis, scaled by the object mass times an arbitrary scaling 3886 // the delta rotation axis, scaled by the object mass times an arbitrary scaling
2744 // factor (to ensure the resulting torque is not "too strong" or "too weak"). 3887 // factor (to ensure the resulting torque is not "too strong" or "too weak").
2745 // 3888 //
2746 // Ideally we need to calculate (probably iteratively) the exact torque or series 3889 // Ideally we need to calculate (probably iteratively) the exact torque or series
2747 // of torques needed to arrive exactly at the destination orientation. However, since 3890 // of torques needed to arrive exactly at the destination orientation. However, since
2748 // it is not yet clear how to map the destination orientation (provided by the viewer) 3891 // it is not yet clear how to map the destination orientation (provided by the viewer)
2749 // into PhysActor orientations (needed by the physics engine), we omit this step. 3892 // into PhysActor orientations (needed by the physics engine), we omit this step.
2750 // This means that the resulting torque will at least be in the correct direction, 3893 // This means that the resulting torque will at least be in the correct direction,
2751 // but it will result in over-shoot or under-shoot of the target orientation. 3894 // but it will result in over-shoot or under-shoot of the target orientation.
2752 // For the end user, this means that ctrl+shift+drag can be used for relative, 3895 // For the end user, this means that ctrl+shift+drag can be used for relative,
2753 // but not absolute, adjustments of orientation for physical prims. 3896 // but not absolute, adjustments of orientation for physical prims.
3897
3898 if (BlockGrabOverride || m_rootPart.BlockGrab)
3899 return;
3900
2754 if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation)) 3901 if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation))
2755 { 3902 {
2756 PhysicsActor pa = m_rootPart.PhysActor; 3903 PhysicsActor pa = m_rootPart.PhysActor;
2757 3904
2758 if (pa != null) 3905 if (pa != null && pa.IsPhysical)
2759 { 3906 {
2760 if (pa.IsPhysical) 3907 if (m_rootPart.IsWaitingForFirstSpinUpdatePacket)
2761 { 3908 {
2762 if (m_rootPart.IsWaitingForFirstSpinUpdatePacket) 3909 // first time initialization of "old" orientation for calculation of delta rotations
2763 { 3910 m_rootPart.SpinOldOrientation = newOrientation;
2764 // first time initialization of "old" orientation for calculation of delta rotations 3911 m_rootPart.IsWaitingForFirstSpinUpdatePacket = false;
2765 m_rootPart.SpinOldOrientation = newOrientation;
2766 m_rootPart.IsWaitingForFirstSpinUpdatePacket = false;
2767 }
2768 else
2769 {
2770 // save and update old orientation
2771 Quaternion old = m_rootPart.SpinOldOrientation;
2772 m_rootPart.SpinOldOrientation = newOrientation;
2773 //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
2774 //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
2775
2776 // compute difference between previous old rotation and new incoming rotation
2777 Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation;
2778
2779 float rotationAngle;
2780 Vector3 rotationAxis;
2781 minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle);
2782 rotationAxis.Normalize();
2783
2784 //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
2785 Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z);
2786 spinforce = (spinforce/8) * pa.Mass; // 8 is an arbitrary torque scaling factor
2787 pa.AddAngularForce(spinforce,true);
2788 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2789 }
2790 } 3912 }
2791 else 3913 else
2792 { 3914 {
2793 NonPhysicalSpinMovement(newOrientation); 3915 // save and update old orientation
3916 Quaternion old = m_rootPart.SpinOldOrientation;
3917 m_rootPart.SpinOldOrientation = newOrientation;
3918 //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
3919 //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
3920
3921 // compute difference between previous old rotation and new incoming rotation
3922 Quaternion minimalRotationFromQ1ToQ2 = newOrientation * Quaternion.Inverse(old);
3923
3924 float rotationAngle;
3925 Vector3 spinforce;
3926 minimalRotationFromQ1ToQ2.GetAxisAngle(out spinforce, out rotationAngle);
3927 if(Math.Abs(rotationAngle)< 0.001)
3928 return;
3929
3930 spinforce.Normalize();
3931
3932 //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
3933 if(rotationAngle > 0)
3934 spinforce = spinforce * pa.Mass * 0.1f; // 0.1 is an arbitrary torque scaling factor
3935 else
3936 spinforce = spinforce * pa.Mass * -0.1f; // 0.1 is an arbitrary torque scaling
3937 pa.AddAngularForce(spinforce,true);
3938 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2794 } 3939 }
2795 } 3940 }
2796 else 3941 else
@@ -2880,51 +4025,80 @@ namespace OpenSim.Region.Framework.Scenes
2880 /// <param name="SetTemporary"></param> 4025 /// <param name="SetTemporary"></param>
2881 /// <param name="SetPhantom"></param> 4026 /// <param name="SetPhantom"></param>
2882 /// <param name="SetVolumeDetect"></param> 4027 /// <param name="SetVolumeDetect"></param>
2883 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect) 4028 public void UpdateFlags(bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2884 { 4029 {
2885 SceneObjectPart selectionPart = GetPart(localID); 4030 if (m_scene == null || IsDeleted)
4031 return;
2886 4032
2887 if (Scene != null) 4033 HasGroupChanged = true;
2888 {
2889 if (SetTemporary)
2890 {
2891 DetachFromBackup();
2892 // Remove from database and parcel prim count
2893 //
2894 m_scene.DeleteFromStorage(UUID);
2895 }
2896 else if (!Backup)
2897 {
2898 // Previously been temporary now switching back so make it
2899 // available for persisting again
2900 AttachToBackup();
2901 }
2902 4034
2903 m_scene.EventManager.TriggerParcelPrimCountTainted(); 4035 if (SetTemporary)
4036 {
4037 DetachFromBackup();
4038 // Remove from database and parcel prim count
4039 //
4040 m_scene.DeleteFromStorage(UUID);
4041 }
4042 else if (!Backup)
4043 {
4044 // Previously been temporary now switching back so make it
4045 // available for persisting again
4046 AttachToBackup();
2904 } 4047 }
2905 4048
2906 if (selectionPart != null) 4049
4050 SceneObjectPart[] parts = m_parts.GetArray();
4051
4052 if (UsePhysics)
2907 { 4053 {
2908 SceneObjectPart[] parts = m_parts.GetArray(); 4054 int maxprims = m_scene.m_linksetPhysCapacity;
2909 4055 bool checkShape = (maxprims > 0 &&
2910 if (Scene != null) 4056 parts.Length > maxprims);
4057
4058 for (int i = 0; i < parts.Length; i++)
2911 { 4059 {
2912 for (int i = 0; i < parts.Length; i++) 4060 SceneObjectPart part = parts[i];
4061
4062 if(part.PhysicsShapeType == (byte)PhysicsShapeType.None)
4063 continue; // assuming root type was checked elsewhere
4064
4065 if (checkShape)
2913 { 4066 {
2914 SceneObjectPart part = parts[i]; 4067 if (--maxprims < 0)
2915 if (part.Scale.X > m_scene.m_maxPhys ||
2916 part.Scale.Y > m_scene.m_maxPhys ||
2917 part.Scale.Z > m_scene.m_maxPhys )
2918 { 4068 {
2919 UsePhysics = false; // Reset physics 4069 UsePhysics = false;
2920 break; 4070 break;
2921 } 4071 }
2922 } 4072 }
4073
4074 if (part.Scale.X > m_scene.m_maxPhys ||
4075 part.Scale.Y > m_scene.m_maxPhys ||
4076 part.Scale.Z > m_scene.m_maxPhys )
4077 {
4078 UsePhysics = false; // Reset physics
4079 break;
4080 }
2923 } 4081 }
4082 }
4083
4084 if (parts.Length > 1)
4085 {
4086 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
2924 4087
2925 for (int i = 0; i < parts.Length; i++) 4088 for (int i = 0; i < parts.Length; i++)
2926 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect); 4089 {
4090
4091 if (parts[i].UUID != m_rootPart.UUID)
4092 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
4093 }
4094
4095 if (m_rootPart.PhysActor != null)
4096 m_rootPart.PhysActor.Building = false;
2927 } 4097 }
4098 else
4099 m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
4100
4101 m_scene.EventManager.TriggerParcelPrimCountTainted();
2928 } 4102 }
2929 4103
2930 public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data) 4104 public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
@@ -2936,24 +4110,21 @@ namespace OpenSim.Region.Framework.Scenes
2936 } 4110 }
2937 } 4111 }
2938 4112
4113
4114
2939 /// <summary> 4115 /// <summary>
2940 /// Update the texture entry for this part 4116 /// Gets the number of parts
2941 /// </summary> 4117 /// </summary>
2942 /// <param name="localID"></param> 4118 /// <returns></returns>
2943 /// <param name="textureEntry"></param> 4119 public int GetPartCount()
2944 public void UpdateTextureEntry(uint localID, byte[] textureEntry)
2945 { 4120 {
2946 SceneObjectPart part = GetPart(localID); 4121 return Parts.Count();
2947 if (part != null)
2948 {
2949 part.UpdateTextureEntry(textureEntry);
2950 }
2951 } 4122 }
2952 4123
2953 public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive) 4124 public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive)
2954 { 4125 {
2955 uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits 4126 uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff0; // Mask folded bits
2956 uint foldedPerms = RootPart.OwnerMask & 3; 4127 uint foldedPerms = RootPart.OwnerMask & (uint)PermissionMask.FoldedMask;
2957 4128
2958 ForEachPart(part => 4129 ForEachPart(part =>
2959 { 4130 {
@@ -2964,14 +4135,14 @@ namespace OpenSim.Region.Framework.Scenes
2964 part.Inventory.ApplyGodPermissions(part.BaseMask); 4135 part.Inventory.ApplyGodPermissions(part.BaseMask);
2965 }); 4136 });
2966 4137
2967 uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify); 4138 uint lockMask = ~(uint)(PermissionMask.Move);
2968 uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify); 4139 uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move);
2969 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask); 4140 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
2970 4141
2971// m_log.DebugFormat( 4142// m_log.DebugFormat(
2972// "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}", 4143// "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}",
2973// (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name); 4144// (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name);
2974 4145 InvalidateEffectivePerms();
2975 RootPart.ScheduleFullUpdate(); 4146 RootPart.ScheduleFullUpdate();
2976 } 4147 }
2977 4148
@@ -2980,7 +4151,24 @@ namespace OpenSim.Region.Framework.Scenes
2980 { 4151 {
2981 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF); 4152 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2982 4153
2983 AdjustChildPrimPermissions(Scene.Permissions.IsGod(AgentID)); 4154 bool god = Scene.Permissions.IsGod(AgentID);
4155
4156 if (field == 1 && god)
4157 {
4158 ForEachPart(part =>
4159 {
4160 part.BaseMask = RootPart.BaseMask;
4161 });
4162 }
4163
4164 AdjustChildPrimPermissions(false);
4165
4166 if (field == 1 && god) // Base mask was set. Update all child part inventories
4167 {
4168 foreach (SceneObjectPart part in Parts)
4169 part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
4170 InvalidateEffectivePerms();
4171 }
2984 4172
2985 HasGroupChanged = true; 4173 HasGroupChanged = true;
2986 4174
@@ -3010,6 +4198,7 @@ namespace OpenSim.Region.Framework.Scenes
3010 if (pa != null) 4198 if (pa != null)
3011 m_scene.PhysicsScene.AddPhysicsActorTaint(pa); 4199 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
3012 } 4200 }
4201 InvalidBoundsRadius();
3013 } 4202 }
3014 4203
3015 #endregion 4204 #endregion
@@ -3025,163 +4214,101 @@ namespace OpenSim.Region.Framework.Scenes
3025// m_log.DebugFormat( 4214// m_log.DebugFormat(
3026// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale); 4215// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
3027 4216
4217 if (Scene == null)
4218 return;
4219
3028 PhysicsActor pa = m_rootPart.PhysActor; 4220 PhysicsActor pa = m_rootPart.PhysActor;
3029 4221
3030 RootPart.StoreUndoState(true); 4222 float minsize = Scene.m_minNonphys;
4223 float maxsize = Scene.m_maxNonphys;
3031 4224
3032 if (Scene != null) 4225 if (pa != null && pa.IsPhysical)
3033 { 4226 {
3034 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X)); 4227 minsize = Scene.m_minPhys;
3035 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y)); 4228 maxsize = Scene.m_maxPhys;
3036 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
3037
3038 if (pa != null && pa.IsPhysical)
3039 {
3040 scale.X = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.X));
3041 scale.Y = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Y));
3042 scale.Z = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Z));
3043 }
3044 } 4229 }
3045 4230
4231 scale.X = Util.Clamp(scale.X, minsize, maxsize);
4232 scale.Y = Util.Clamp(scale.Y, minsize, maxsize);
4233 scale.Z = Util.Clamp(scale.Z, minsize, maxsize);
4234
4235 // requested scaling factors
3046 float x = (scale.X / RootPart.Scale.X); 4236 float x = (scale.X / RootPart.Scale.X);
3047 float y = (scale.Y / RootPart.Scale.Y); 4237 float y = (scale.Y / RootPart.Scale.Y);
3048 float z = (scale.Z / RootPart.Scale.Z); 4238 float z = (scale.Z / RootPart.Scale.Z);
3049 4239
3050 SceneObjectPart[] parts = m_parts.GetArray(); 4240 SceneObjectPart[] parts = m_parts.GetArray();
3051 4241
3052 if (Scene != null & (x > 1.0f || y > 1.0f || z > 1.0f)) 4242 // fix scaling factors so parts don't violate dimensions
4243 for(int i = 0;i < parts.Length;i++)
3053 { 4244 {
3054 for (int i = 0; i < parts.Length; i++) 4245 SceneObjectPart obPart = parts[i];
4246 if(obPart.UUID != m_rootPart.UUID)
3055 { 4247 {
3056 SceneObjectPart obPart = parts[i]; 4248 Vector3 oldSize = new Vector3(obPart.Scale);
3057 if (obPart.UUID != m_rootPart.UUID)
3058 {
3059// obPart.IgnoreUndoUpdate = true;
3060 Vector3 oldSize = new Vector3(obPart.Scale);
3061 4249
3062 float f = 1.0f; 4250 float f = 1.0f;
3063 float a = 1.0f; 4251 float a = 1.0f;
3064
3065 if (pa != null && pa.IsPhysical)
3066 {
3067 if (oldSize.X * x > Scene.m_maxPhys)
3068 {
3069 f = m_scene.m_maxPhys / oldSize.X;
3070 a = f / x;
3071 x *= a;
3072 y *= a;
3073 z *= a;
3074 }
3075 else if (oldSize.X * x < Scene.m_minPhys)
3076 {
3077 f = m_scene.m_minPhys / oldSize.X;
3078 a = f / x;
3079 x *= a;
3080 y *= a;
3081 z *= a;
3082 }
3083 4252
3084 if (oldSize.Y * y > Scene.m_maxPhys) 4253 if(oldSize.X * x > maxsize)
3085 { 4254 {
3086 f = m_scene.m_maxPhys / oldSize.Y; 4255 f = maxsize / oldSize.X;
3087 a = f / y; 4256 a = f / x;
3088 x *= a; 4257 x *= a;
3089 y *= a; 4258 y *= a;
3090 z *= a; 4259 z *= a;
3091 } 4260 }
3092 else if (oldSize.Y * y < Scene.m_minPhys) 4261 else if(oldSize.X * x < minsize)
3093 { 4262 {
3094 f = m_scene.m_minPhys / oldSize.Y; 4263 f = minsize / oldSize.X;
3095 a = f / y; 4264 a = f / x;
3096 x *= a; 4265 x *= a;
3097 y *= a; 4266 y *= a;
3098 z *= a; 4267 z *= a;
3099 } 4268 }
3100
3101 if (oldSize.Z * z > Scene.m_maxPhys)
3102 {
3103 f = m_scene.m_maxPhys / oldSize.Z;
3104 a = f / z;
3105 x *= a;
3106 y *= a;
3107 z *= a;
3108 }
3109 else if (oldSize.Z * z < Scene.m_minPhys)
3110 {
3111 f = m_scene.m_minPhys / oldSize.Z;
3112 a = f / z;
3113 x *= a;
3114 y *= a;
3115 z *= a;
3116 }
3117 }
3118 else
3119 {
3120 if (oldSize.X * x > Scene.m_maxNonphys)
3121 {
3122 f = m_scene.m_maxNonphys / oldSize.X;
3123 a = f / x;
3124 x *= a;
3125 y *= a;
3126 z *= a;
3127 }
3128 else if (oldSize.X * x < Scene.m_minNonphys)
3129 {
3130 f = m_scene.m_minNonphys / oldSize.X;
3131 a = f / x;
3132 x *= a;
3133 y *= a;
3134 z *= a;
3135 }
3136
3137 if (oldSize.Y * y > Scene.m_maxNonphys)
3138 {
3139 f = m_scene.m_maxNonphys / oldSize.Y;
3140 a = f / y;
3141 x *= a;
3142 y *= a;
3143 z *= a;
3144 }
3145 else if (oldSize.Y * y < Scene.m_minNonphys)
3146 {
3147 f = m_scene.m_minNonphys / oldSize.Y;
3148 a = f / y;
3149 x *= a;
3150 y *= a;
3151 z *= a;
3152 }
3153 4269
3154 if (oldSize.Z * z > Scene.m_maxNonphys) 4270 if(oldSize.Y * y > maxsize)
3155 { 4271 {
3156 f = m_scene.m_maxNonphys / oldSize.Z; 4272 f = maxsize / oldSize.Y;
3157 a = f / z; 4273 a = f / y;
3158 x *= a; 4274 x *= a;
3159 y *= a; 4275 y *= a;
3160 z *= a; 4276 z *= a;
3161 } 4277 }
3162 else if (oldSize.Z * z < Scene.m_minNonphys) 4278 else if(oldSize.Y * y < minsize)
3163 { 4279 {
3164 f = m_scene.m_minNonphys / oldSize.Z; 4280 f = minsize / oldSize.Y;
3165 a = f / z; 4281 a = f / y;
3166 x *= a; 4282 x *= a;
3167 y *= a; 4283 y *= a;
3168 z *= a; 4284 z *= a;
3169 } 4285 }
3170 }
3171 4286
3172// obPart.IgnoreUndoUpdate = false; 4287 if(oldSize.Z * z > maxsize)
4288 {
4289 f = maxsize / oldSize.Z;
4290 a = f / z;
4291 x *= a;
4292 y *= a;
4293 z *= a;
4294 }
4295 else if(oldSize.Z * z < minsize)
4296 {
4297 f = minsize / oldSize.Z;
4298 a = f / z;
4299 x *= a;
4300 y *= a;
4301 z *= a;
3173 } 4302 }
3174 } 4303 }
3175 } 4304 }
3176 4305
3177 Vector3 prevScale = RootPart.Scale; 4306 Vector3 rootScale = RootPart.Scale;
3178 prevScale.X *= x; 4307 rootScale.X *= x;
3179 prevScale.Y *= y; 4308 rootScale.Y *= y;
3180 prevScale.Z *= z; 4309 rootScale.Z *= z;
3181 4310
3182// RootPart.IgnoreUndoUpdate = true; 4311 RootPart.Scale = rootScale;
3183 RootPart.Resize(prevScale);
3184// RootPart.IgnoreUndoUpdate = false;
3185 4312
3186 for (int i = 0; i < parts.Length; i++) 4313 for (int i = 0; i < parts.Length; i++)
3187 { 4314 {
@@ -3189,8 +4316,6 @@ namespace OpenSim.Region.Framework.Scenes
3189 4316
3190 if (obPart.UUID != m_rootPart.UUID) 4317 if (obPart.UUID != m_rootPart.UUID)
3191 { 4318 {
3192 obPart.IgnoreUndoUpdate = true;
3193
3194 Vector3 currentpos = new Vector3(obPart.OffsetPosition); 4319 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
3195 currentpos.X *= x; 4320 currentpos.X *= x;
3196 currentpos.Y *= y; 4321 currentpos.Y *= y;
@@ -3201,18 +4326,190 @@ namespace OpenSim.Region.Framework.Scenes
3201 newSize.Y *= y; 4326 newSize.Y *= y;
3202 newSize.Z *= z; 4327 newSize.Z *= z;
3203 4328
3204 obPart.Resize(newSize); 4329 obPart.Scale = newSize;
3205 obPart.UpdateOffSet(currentpos); 4330 obPart.UpdateOffSet(currentpos);
4331 }
4332 }
4333
4334 InvalidBoundsRadius();
4335 HasGroupChanged = true;
4336 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
4337 ScheduleGroupForFullUpdate();
4338
4339 }
4340
4341 public bool GroupResize(double fscale)
4342 {
4343// m_log.DebugFormat(
4344// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, fscale);
4345
4346 if (Scene == null || IsDeleted || inTransit || fscale < 0)
4347 return false;
4348
4349 // ignore lsl restrictions. let them be done a LSL
4350 PhysicsActor pa = m_rootPart.PhysActor;
4351
4352 if(RootPart.KeyframeMotion != null)
4353 RootPart.KeyframeMotion.Suspend();
4354
4355 float minsize = Scene.m_minNonphys;
4356 float maxsize = Scene.m_maxNonphys;
3206 4357
3207 obPart.IgnoreUndoUpdate = false; 4358 // assuming physics is more restrictive
4359 if (pa != null && pa.IsPhysical)
4360 {
4361 minsize = Scene.m_minPhys;
4362 maxsize = Scene.m_maxPhys;
4363 }
4364
4365 SceneObjectPart[] parts = m_parts.GetArray();
4366 float tmp;
4367 // check scaling factor so parts don't violate dimensions
4368 for(int i = 0; i < parts.Length; i++)
4369 {
4370 SceneObjectPart obPart = parts[i];
4371 Vector3 oldSize = new Vector3(obPart.Scale);
4372 tmp = (float)(oldSize.X * fscale);
4373 if(tmp > maxsize)
4374 return false;
4375 if(tmp < minsize)
4376 return false;
4377
4378 tmp = (float)(oldSize.Y * fscale);
4379 if(tmp > maxsize)
4380 return false;
4381 if(tmp < minsize)
4382 return false;
4383
4384 tmp = (float)(oldSize.Z * fscale);
4385 if(tmp > maxsize)
4386 return false;
4387 if(tmp < minsize)
4388 return false;
4389 }
4390
4391 Vector3 newSize = RootPart.Scale;
4392 newSize.X = (float)(newSize.X * fscale);
4393 newSize.Y = (float)(newSize.Y * fscale);
4394 newSize.Z = (float)(newSize.Z * fscale);
4395
4396 if(pa != null)
4397 pa.Building = true;
4398
4399 RootPart.Scale = newSize;
4400
4401 Vector3 currentpos;
4402 for (int i = 0; i < parts.Length; i++)
4403 {
4404 SceneObjectPart obPart = parts[i];
4405
4406 if (obPart.UUID != m_rootPart.UUID)
4407 {
4408 currentpos = obPart.OffsetPosition;
4409 currentpos.X = (float)(currentpos.X * fscale);
4410 currentpos.Y = (float)(currentpos.Y * fscale);
4411 currentpos.Z = (float)(currentpos.Z * fscale);
4412
4413 newSize = obPart.Scale;
4414 newSize.X = (float)(newSize.X * fscale);
4415 newSize.Y = (float)(newSize.Y * fscale);
4416 newSize.Z = (float)(newSize.Z * fscale);
4417
4418 obPart.Scale = newSize;
4419 obPart.UpdateOffSet(currentpos);
3208 } 4420 }
4421 }
4422
4423 if(pa != null)
4424 pa.Building = false;
4425
4426 InvalidBoundsRadius();
4427
4428 HasGroupChanged = true;
4429 m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
4430 ScheduleGroupForFullUpdate();
4431
4432 if(RootPart.KeyframeMotion != null)
4433 RootPart.KeyframeMotion.Resume();
4434
4435 return true;
4436 }
4437
4438 public float GetMaxGroupResizeScale()
4439 {
4440 if (Scene == null || IsDeleted || inTransit)
4441 return 1.0f;
4442
4443 float maxsize = Scene.m_maxNonphys;
4444 PhysicsActor pa = m_rootPart.PhysActor;
4445 // assuming physics is more restrictive
4446 if (pa != null && pa.IsPhysical)
4447 maxsize = Scene.m_maxPhys;
3209 4448
3210// obPart.IgnoreUndoUpdate = false; 4449 SceneObjectPart[] parts = m_parts.GetArray();
3211// obPart.StoreUndoState(); 4450 float larger = float.MinValue;
4451
4452 for(int i = 0; i < parts.Length; i++)
4453 {
4454 SceneObjectPart obPart = parts[i];
4455 Vector3 oldSize = new Vector3(obPart.Scale);
4456 if(larger < oldSize.X)
4457 larger = oldSize.X;
4458
4459 if(larger < oldSize.Y)
4460 larger = oldSize.Y;
4461
4462 if(larger < oldSize.Z)
4463 larger = oldSize.Z;
3212 } 4464 }
3213 4465
3214// m_log.DebugFormat( 4466 if(larger >= maxsize)
3215// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale); 4467 return 1.0f;
4468
4469 larger += 1e-3f;
4470 float fscale = maxsize / larger;
4471
4472 return fscale;
4473 }
4474
4475 public float GetMinGroupResizeScale()
4476 {
4477 if (Scene == null || IsDeleted || inTransit)
4478 return 1.0f;
4479
4480 float minsize = Scene.m_minNonphys;
4481 PhysicsActor pa = m_rootPart.PhysActor;
4482 // assuming physics is more restrictive
4483 if (pa != null && pa.IsPhysical)
4484 minsize = Scene.m_minPhys;
4485
4486 SceneObjectPart[] parts = m_parts.GetArray();
4487 float smaller = float.MaxValue;
4488
4489 for(int i = 0; i < parts.Length; i++)
4490 {
4491 SceneObjectPart obPart = parts[i];
4492 Vector3 oldSize = new Vector3(obPart.Scale);
4493 if(smaller > oldSize.X)
4494 smaller = oldSize.X;
4495
4496 if(smaller > oldSize.Y)
4497 smaller = oldSize.Y;
4498
4499 if(smaller > oldSize.Z)
4500 smaller = oldSize.Z;
4501 }
4502
4503 if(smaller <= minsize)
4504 return 1.0f;
4505
4506 if(smaller > 2e-3f)
4507 smaller -= 1e-3f;
4508 float fscale = minsize / smaller;
4509 if(fscale < 1e-8f)
4510 fscale = 1e-8f;
4511
4512 return fscale;
3216 } 4513 }
3217 4514
3218 #endregion 4515 #endregion
@@ -3225,14 +4522,6 @@ namespace OpenSim.Region.Framework.Scenes
3225 /// <param name="pos"></param> 4522 /// <param name="pos"></param>
3226 public void UpdateGroupPosition(Vector3 pos) 4523 public void UpdateGroupPosition(Vector3 pos)
3227 { 4524 {
3228// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
3229
3230 RootPart.StoreUndoState(true);
3231
3232// SceneObjectPart[] parts = m_parts.GetArray();
3233// for (int i = 0; i < parts.Length; i++)
3234// parts[i].StoreUndoState();
3235
3236 if (m_scene.EventManager.TriggerGroupMove(UUID, pos)) 4525 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
3237 { 4526 {
3238 if (IsAttachment) 4527 if (IsAttachment)
@@ -3265,21 +4554,17 @@ namespace OpenSim.Region.Framework.Scenes
3265 /// </summary> 4554 /// </summary>
3266 /// <param name="pos"></param> 4555 /// <param name="pos"></param>
3267 /// <param name="localID"></param> 4556 /// <param name="localID"></param>
4557 ///
4558
3268 public void UpdateSinglePosition(Vector3 pos, uint localID) 4559 public void UpdateSinglePosition(Vector3 pos, uint localID)
3269 { 4560 {
3270 SceneObjectPart part = GetPart(localID); 4561 SceneObjectPart part = GetPart(localID);
3271 4562
3272// SceneObjectPart[] parts = m_parts.GetArray();
3273// for (int i = 0; i < parts.Length; i++)
3274// parts[i].StoreUndoState();
3275
3276 if (part != null) 4563 if (part != null)
3277 { 4564 {
3278// m_log.DebugFormat( 4565// unlock parts position change
3279// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos); 4566 if (m_rootPart.PhysActor != null)
3280 4567 m_rootPart.PhysActor.Building = true;
3281 part.StoreUndoState(false);
3282 part.IgnoreUndoUpdate = true;
3283 4568
3284 if (part.UUID == m_rootPart.UUID) 4569 if (part.UUID == m_rootPart.UUID)
3285 { 4570 {
@@ -3290,8 +4575,10 @@ namespace OpenSim.Region.Framework.Scenes
3290 part.UpdateOffSet(pos); 4575 part.UpdateOffSet(pos);
3291 } 4576 }
3292 4577
4578 if (m_rootPart.PhysActor != null)
4579 m_rootPart.PhysActor.Building = false;
4580
3293 HasGroupChanged = true; 4581 HasGroupChanged = true;
3294 part.IgnoreUndoUpdate = false;
3295 } 4582 }
3296 } 4583 }
3297 4584
@@ -3301,13 +4588,7 @@ namespace OpenSim.Region.Framework.Scenes
3301 /// <param name="newPos"></param> 4588 /// <param name="newPos"></param>
3302 public void UpdateRootPosition(Vector3 newPos) 4589 public void UpdateRootPosition(Vector3 newPos)
3303 { 4590 {
3304// m_log.DebugFormat( 4591 // needs to be called with phys building true
3305// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3306
3307// SceneObjectPart[] parts = m_parts.GetArray();
3308// for (int i = 0; i < parts.Length; i++)
3309// parts[i].StoreUndoState();
3310
3311 Vector3 oldPos; 4592 Vector3 oldPos;
3312 4593
3313 if (IsAttachment) 4594 if (IsAttachment)
@@ -3328,12 +4609,19 @@ namespace OpenSim.Region.Framework.Scenes
3328 } 4609 }
3329 4610
3330 AbsolutePosition = newPos; 4611 AbsolutePosition = newPos;
3331 4612
3332 if (IsAttachment) 4613 if (IsAttachment)
3333 m_rootPart.AttachedPos = newPos; 4614 m_rootPart.AttachedPos = newPos;
3334 4615
3335 HasGroupChanged = true; 4616 HasGroupChanged = true;
3336 ScheduleGroupForTerseUpdate(); 4617 if (m_rootPart.Undoing)
4618 {
4619 ScheduleGroupForFullUpdate();
4620 }
4621 else
4622 {
4623 ScheduleGroupForTerseUpdate();
4624 }
3337 } 4625 }
3338 4626
3339 #endregion 4627 #endregion
@@ -3346,24 +4634,16 @@ namespace OpenSim.Region.Framework.Scenes
3346 /// <param name="rot"></param> 4634 /// <param name="rot"></param>
3347 public void UpdateGroupRotationR(Quaternion rot) 4635 public void UpdateGroupRotationR(Quaternion rot)
3348 { 4636 {
3349// m_log.DebugFormat(
3350// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3351
3352// SceneObjectPart[] parts = m_parts.GetArray();
3353// for (int i = 0; i < parts.Length; i++)
3354// parts[i].StoreUndoState();
3355
3356 m_rootPart.StoreUndoState(true);
3357
3358 m_rootPart.UpdateRotation(rot); 4637 m_rootPart.UpdateRotation(rot);
3359 4638
4639/* this is done by rootpart RotationOffset set called by UpdateRotation
3360 PhysicsActor actor = m_rootPart.PhysActor; 4640 PhysicsActor actor = m_rootPart.PhysActor;
3361 if (actor != null) 4641 if (actor != null)
3362 { 4642 {
3363 actor.Orientation = m_rootPart.RotationOffset; 4643 actor.Orientation = m_rootPart.RotationOffset;
3364 m_scene.PhysicsScene.AddPhysicsActorTaint(actor); 4644 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3365 } 4645 }
3366 4646*/
3367 HasGroupChanged = true; 4647 HasGroupChanged = true;
3368 ScheduleGroupForTerseUpdate(); 4648 ScheduleGroupForTerseUpdate();
3369 } 4649 }
@@ -3375,16 +4655,6 @@ namespace OpenSim.Region.Framework.Scenes
3375 /// <param name="rot"></param> 4655 /// <param name="rot"></param>
3376 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot) 4656 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3377 { 4657 {
3378// m_log.DebugFormat(
3379// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3380
3381// SceneObjectPart[] parts = m_parts.GetArray();
3382// for (int i = 0; i < parts.Length; i++)
3383// parts[i].StoreUndoState();
3384
3385 RootPart.StoreUndoState(true);
3386 RootPart.IgnoreUndoUpdate = true;
3387
3388 m_rootPart.UpdateRotation(rot); 4658 m_rootPart.UpdateRotation(rot);
3389 4659
3390 PhysicsActor actor = m_rootPart.PhysActor; 4660 PhysicsActor actor = m_rootPart.PhysActor;
@@ -3403,8 +4673,6 @@ namespace OpenSim.Region.Framework.Scenes
3403 4673
3404 HasGroupChanged = true; 4674 HasGroupChanged = true;
3405 ScheduleGroupForTerseUpdate(); 4675 ScheduleGroupForTerseUpdate();
3406
3407 RootPart.IgnoreUndoUpdate = false;
3408 } 4676 }
3409 4677
3410 /// <summary> 4678 /// <summary>
@@ -3417,13 +4685,11 @@ namespace OpenSim.Region.Framework.Scenes
3417 SceneObjectPart part = GetPart(localID); 4685 SceneObjectPart part = GetPart(localID);
3418 4686
3419 SceneObjectPart[] parts = m_parts.GetArray(); 4687 SceneObjectPart[] parts = m_parts.GetArray();
3420 for (int i = 0; i < parts.Length; i++)
3421 parts[i].StoreUndoState();
3422 4688
3423 if (part != null) 4689 if (part != null)
3424 { 4690 {
3425// m_log.DebugFormat( 4691 if (m_rootPart.PhysActor != null)
3426// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot); 4692 m_rootPart.PhysActor.Building = true;
3427 4693
3428 if (part.UUID == m_rootPart.UUID) 4694 if (part.UUID == m_rootPart.UUID)
3429 { 4695 {
@@ -3433,6 +4699,9 @@ namespace OpenSim.Region.Framework.Scenes
3433 { 4699 {
3434 part.UpdateRotation(rot); 4700 part.UpdateRotation(rot);
3435 } 4701 }
4702
4703 if (m_rootPart.PhysActor != null)
4704 m_rootPart.PhysActor.Building = false;
3436 } 4705 }
3437 } 4706 }
3438 4707
@@ -3446,12 +4715,8 @@ namespace OpenSim.Region.Framework.Scenes
3446 SceneObjectPart part = GetPart(localID); 4715 SceneObjectPart part = GetPart(localID);
3447 if (part != null) 4716 if (part != null)
3448 { 4717 {
3449// m_log.DebugFormat( 4718 if (m_rootPart.PhysActor != null)
3450// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}", 4719 m_rootPart.PhysActor.Building = true;
3451// part.Name, part.LocalId, rot);
3452
3453 part.StoreUndoState();
3454 part.IgnoreUndoUpdate = true;
3455 4720
3456 if (part.UUID == m_rootPart.UUID) 4721 if (part.UUID == m_rootPart.UUID)
3457 { 4722 {
@@ -3464,7 +4729,8 @@ namespace OpenSim.Region.Framework.Scenes
3464 part.OffsetPosition = pos; 4729 part.OffsetPosition = pos;
3465 } 4730 }
3466 4731
3467 part.IgnoreUndoUpdate = false; 4732 if (m_rootPart.PhysActor != null)
4733 m_rootPart.PhysActor.Building = false;
3468 } 4734 }
3469 } 4735 }
3470 4736
@@ -3474,15 +4740,12 @@ namespace OpenSim.Region.Framework.Scenes
3474 /// <param name="rot"></param> 4740 /// <param name="rot"></param>
3475 public void UpdateRootRotation(Quaternion rot) 4741 public void UpdateRootRotation(Quaternion rot)
3476 { 4742 {
3477// m_log.DebugFormat( 4743 // needs to be called with phys building true
3478// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3479// Name, LocalId, rot);
3480
3481 Quaternion axRot = rot; 4744 Quaternion axRot = rot;
3482 Quaternion oldParentRot = m_rootPart.RotationOffset; 4745 Quaternion oldParentRot = m_rootPart.RotationOffset;
3483 4746
3484 m_rootPart.StoreUndoState(); 4747 //Don't use UpdateRotation because it schedules an update prematurely
3485 m_rootPart.UpdateRotation(rot); 4748 m_rootPart.RotationOffset = rot;
3486 4749
3487 PhysicsActor pa = m_rootPart.PhysActor; 4750 PhysicsActor pa = m_rootPart.PhysActor;
3488 4751
@@ -3498,64 +4761,203 @@ namespace OpenSim.Region.Framework.Scenes
3498 SceneObjectPart prim = parts[i]; 4761 SceneObjectPart prim = parts[i];
3499 if (prim.UUID != m_rootPart.UUID) 4762 if (prim.UUID != m_rootPart.UUID)
3500 { 4763 {
3501 prim.IgnoreUndoUpdate = true; 4764 Quaternion NewRot = oldParentRot * prim.RotationOffset;
4765 NewRot = Quaternion.Inverse(axRot) * NewRot;
4766 prim.RotationOffset = NewRot;
4767
3502 Vector3 axPos = prim.OffsetPosition; 4768 Vector3 axPos = prim.OffsetPosition;
4769
3503 axPos *= oldParentRot; 4770 axPos *= oldParentRot;
3504 axPos *= Quaternion.Inverse(axRot); 4771 axPos *= Quaternion.Inverse(axRot);
3505 prim.OffsetPosition = axPos; 4772 prim.OffsetPosition = axPos;
3506 Quaternion primsRot = prim.RotationOffset;
3507 Quaternion newRot = oldParentRot * primsRot;
3508 newRot = Quaternion.Inverse(axRot) * newRot;
3509 prim.RotationOffset = newRot;
3510 prim.ScheduleTerseUpdate();
3511 prim.IgnoreUndoUpdate = false;
3512 } 4773 }
3513 } 4774 }
3514 4775
3515// for (int i = 0; i < parts.Length; i++) 4776 HasGroupChanged = true;
3516// { 4777 ScheduleGroupForFullUpdate();
3517// SceneObjectPart childpart = parts[i]; 4778 }
3518// if (childpart != m_rootPart)
3519// {
3520//// childpart.IgnoreUndoUpdate = false;
3521//// childpart.StoreUndoState();
3522// }
3523// }
3524 4779
3525 m_rootPart.ScheduleTerseUpdate(); 4780 private enum updatetype :int
4781 {
4782 none = 0,
4783 partterse = 1,
4784 partfull = 2,
4785 groupterse = 3,
4786 groupfull = 4
4787 }
3526 4788
3527// m_log.DebugFormat( 4789 public void doChangeObject(SceneObjectPart part, ObjectChangeData data)
3528// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}", 4790 {
3529// Name, LocalId, rot); 4791 // TODO this still as excessive *.Schedule*Update()s
4792
4793 if (part != null && part.ParentGroup != null)
4794 {
4795 ObjectChangeType change = data.change;
4796 bool togroup = ((change & ObjectChangeType.Group) != 0);
4797 // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4798
4799 SceneObjectGroup group = part.ParentGroup;
4800 PhysicsActor pha = group.RootPart.PhysActor;
4801
4802 updatetype updateType = updatetype.none;
4803
4804 if (togroup)
4805 {
4806 // related to group
4807 if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4808 {
4809 if ((change & ObjectChangeType.Rotation) != 0)
4810 {
4811 group.RootPart.UpdateRotation(data.rotation);
4812 updateType = updatetype.none;
4813 }
4814 if ((change & ObjectChangeType.Position) != 0)
4815 {
4816 if (IsAttachment || m_scene.Permissions.CanObjectEntry(group, false, data.position))
4817 UpdateGroupPosition(data.position);
4818 updateType = updatetype.groupterse;
4819 }
4820 else
4821 // ugly rotation update of all parts
4822 {
4823 group.ResetChildPrimPhysicsPositions();
4824 }
4825
4826 }
4827 if ((change & ObjectChangeType.Scale) != 0)
4828 {
4829 if (pha != null)
4830 pha.Building = true;
4831
4832 group.GroupResize(data.scale);
4833 updateType = updatetype.none;
4834
4835 if (pha != null)
4836 pha.Building = false;
4837 }
4838 }
4839 else
4840 {
4841 // related to single prim in a link-set ( ie group)
4842 if (pha != null)
4843 pha.Building = true;
4844
4845 // root part is special
4846 // parts offset positions or rotations need to change also
4847
4848 if (part == group.RootPart)
4849 {
4850 if ((change & ObjectChangeType.Rotation) != 0)
4851 group.UpdateRootRotation(data.rotation);
4852 if ((change & ObjectChangeType.Position) != 0)
4853 group.UpdateRootPosition(data.position);
4854 if ((change & ObjectChangeType.Scale) != 0)
4855 part.Resize(data.scale);
4856 }
4857 else
4858 {
4859 if ((change & ObjectChangeType.Position) != 0)
4860 {
4861 part.OffsetPosition = data.position;
4862 updateType = updatetype.partterse;
4863 }
4864 if ((change & ObjectChangeType.Rotation) != 0)
4865 {
4866 part.UpdateRotation(data.rotation);
4867 updateType = updatetype.none;
4868 }
4869 if ((change & ObjectChangeType.Scale) != 0)
4870 {
4871 part.Resize(data.scale);
4872 updateType = updatetype.none;
4873 }
4874 }
4875
4876 if (pha != null)
4877 pha.Building = false;
4878 }
4879
4880 if (updateType != updatetype.none)
4881 {
4882 group.HasGroupChanged = true;
4883
4884 switch (updateType)
4885 {
4886 case updatetype.partterse:
4887 part.ScheduleTerseUpdate();
4888 break;
4889 case updatetype.partfull:
4890 part.ScheduleFullUpdate();
4891 break;
4892 case updatetype.groupterse:
4893 group.ScheduleGroupForTerseUpdate();
4894 break;
4895 case updatetype.groupfull:
4896 group.ScheduleGroupForFullUpdate();
4897 break;
4898 default:
4899 break;
4900 }
4901 }
4902 }
3530 } 4903 }
3531 4904
3532 #endregion 4905 #endregion
3533 4906
3534 internal void SetAxisRotation(int axis, int rotate10) 4907 internal void SetAxisRotation(int axis, int rotate10)
3535 { 4908 {
3536 bool setX = false; 4909 bool setX = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0);
3537 bool setY = false; 4910 bool setY = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0);
3538 bool setZ = false; 4911 bool setZ = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0);
3539 4912
3540 int xaxis = 2; 4913 if (setX || setY || setZ)
3541 int yaxis = 4; 4914 {
3542 int zaxis = 8; 4915 bool lockaxis = (rotate10 == 0); // zero means axis locked
3543 4916
3544 setX = ((axis & xaxis) != 0) ? true : false; 4917 byte locks = RootPart.RotationAxisLocks;
3545 setY = ((axis & yaxis) != 0) ? true : false;
3546 setZ = ((axis & zaxis) != 0) ? true : false;
3547 4918
3548 float setval = (rotate10 > 0) ? 1f : 0f; 4919 if (setX)
4920 {
4921 if(lockaxis)
4922 locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X;
4923 else
4924 locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_X;
4925 }
3549 4926
3550 if (setX) 4927 if (setY)
3551 RootPart.RotationAxis.X = setval; 4928 {
3552 if (setY) 4929 if(lockaxis)
3553 RootPart.RotationAxis.Y = setval; 4930 locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y;
3554 if (setZ) 4931 else
3555 RootPart.RotationAxis.Z = setval; 4932 locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Y;
4933 }
3556 4934
3557 if (setX || setY || setZ) 4935 if (setZ)
4936 {
4937 if(lockaxis)
4938 locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z;
4939 else
4940 locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Z;
4941 }
4942
4943 RootPart.RotationAxisLocks = locks;
3558 RootPart.SetPhysicsAxisRotation(); 4944 RootPart.SetPhysicsAxisRotation();
4945 }
4946 }
4947
4948 public int GetAxisRotation(int axis)
4949 {
4950 byte rotAxislocks = RootPart.RotationAxisLocks;
4951
4952 // if multiple return the one with higher id
4953 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z)
4954 return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) == 0 ? 1:0;
4955 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y)
4956 return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) == 0 ? 1:0;
4957 if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X)
4958 return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) == 0 ? 1:0;
4959
4960 return 0;
3559 } 4961 }
3560 4962
3561 public int registerRotTargetWaypoint(Quaternion target, float tolerance) 4963 public int registerRotTargetWaypoint(Quaternion target, float tolerance)
@@ -3567,6 +4969,8 @@ namespace OpenSim.Region.Framework.Scenes
3567 waypoint.handle = handle; 4969 waypoint.handle = handle;
3568 lock (m_rotTargets) 4970 lock (m_rotTargets)
3569 { 4971 {
4972 if (m_rotTargets.Count >= 8)
4973 m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
3570 m_rotTargets.Add(handle, waypoint); 4974 m_rotTargets.Add(handle, waypoint);
3571 } 4975 }
3572 m_scene.AddGroupTarget(this); 4976 m_scene.AddGroupTarget(this);
@@ -3592,12 +4996,14 @@ namespace OpenSim.Region.Framework.Scenes
3592 waypoint.handle = handle; 4996 waypoint.handle = handle;
3593 lock (m_targets) 4997 lock (m_targets)
3594 { 4998 {
4999 if (m_targets.Count >= 8)
5000 m_targets.Remove(m_targets.ElementAt(0).Key);
3595 m_targets.Add(handle, waypoint); 5001 m_targets.Add(handle, waypoint);
3596 } 5002 }
3597 m_scene.AddGroupTarget(this); 5003 m_scene.AddGroupTarget(this);
3598 return (int)handle; 5004 return (int)handle;
3599 } 5005 }
3600 5006
3601 public void unregisterTargetWaypoint(int handle) 5007 public void unregisterTargetWaypoint(int handle)
3602 { 5008 {
3603 lock (m_targets) 5009 lock (m_targets)
@@ -3625,10 +5031,11 @@ namespace OpenSim.Region.Framework.Scenes
3625 scriptPosTarget target = m_targets[idx]; 5031 scriptPosTarget target = m_targets[idx];
3626 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance) 5032 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3627 { 5033 {
5034 at_target = true;
5035
3628 // trigger at_target 5036 // trigger at_target
3629 if (m_scriptListens_atTarget) 5037 if (m_scriptListens_atTarget)
3630 { 5038 {
3631 at_target = true;
3632 scriptPosTarget att = new scriptPosTarget(); 5039 scriptPosTarget att = new scriptPosTarget();
3633 att.targetPos = target.targetPos; 5040 att.targetPos = target.targetPos;
3634 att.tolerance = target.tolerance; 5041 att.tolerance = target.tolerance;
@@ -3638,14 +5045,14 @@ namespace OpenSim.Region.Framework.Scenes
3638 } 5045 }
3639 } 5046 }
3640 } 5047 }
3641 5048
3642 if (atTargets.Count > 0) 5049 if (atTargets.Count > 0)
3643 { 5050 {
3644 SceneObjectPart[] parts = m_parts.GetArray(); 5051 SceneObjectPart[] parts = m_parts.GetArray();
3645 uint[] localids = new uint[parts.Length]; 5052 uint[] localids = new uint[parts.Length];
3646 for (int i = 0; i < parts.Length; i++) 5053 for (int i = 0; i < parts.Length; i++)
3647 localids[i] = parts[i].LocalId; 5054 localids[i] = parts[i].LocalId;
3648 5055
3649 for (int ctr = 0; ctr < localids.Length; ctr++) 5056 for (int ctr = 0; ctr < localids.Length; ctr++)
3650 { 5057 {
3651 foreach (uint target in atTargets.Keys) 5058 foreach (uint target in atTargets.Keys)
@@ -3655,10 +5062,10 @@ namespace OpenSim.Region.Framework.Scenes
3655 localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition); 5062 localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition);
3656 } 5063 }
3657 } 5064 }
3658 5065
3659 return; 5066 return;
3660 } 5067 }
3661 5068
3662 if (m_scriptListens_notAtTarget && !at_target) 5069 if (m_scriptListens_notAtTarget && !at_target)
3663 { 5070 {
3664 //trigger not_at_target 5071 //trigger not_at_target
@@ -3666,7 +5073,7 @@ namespace OpenSim.Region.Framework.Scenes
3666 uint[] localids = new uint[parts.Length]; 5073 uint[] localids = new uint[parts.Length];
3667 for (int i = 0; i < parts.Length; i++) 5074 for (int i = 0; i < parts.Length; i++)
3668 localids[i] = parts[i].LocalId; 5075 localids[i] = parts[i].LocalId;
3669 5076
3670 for (int ctr = 0; ctr < localids.Length; ctr++) 5077 for (int ctr = 0; ctr < localids.Length; ctr++)
3671 { 5078 {
3672 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]); 5079 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
@@ -3746,11 +5153,35 @@ namespace OpenSim.Region.Framework.Scenes
3746 } 5153 }
3747 } 5154 }
3748 } 5155 }
3749 5156
5157 public Vector3 GetGeometricCenter()
5158 {
5159 // this is not real geometric center but a average of positions relative to root prim acording to
5160 // http://wiki.secondlife.com/wiki/llGetGeometricCenter
5161 // ignoring tortured prims details since sl also seems to ignore
5162 // so no real use in doing it on physics
5163
5164 Vector3 gc = Vector3.Zero;
5165
5166 SceneObjectPart[] parts = m_parts.GetArray();
5167 int nparts = parts.Length;
5168 if (nparts < 2)
5169 return gc;
5170
5171 // average all parts positions
5172 for (int i = 0; i < nparts; i++)
5173 {
5174 if (parts[i] != RootPart)
5175 gc += parts[i].OffsetPosition;
5176 }
5177 gc /= nparts;
5178
5179 return gc;
5180 }
5181
3750 public float GetMass() 5182 public float GetMass()
3751 { 5183 {
3752 float retmass = 0f; 5184 float retmass = 0f;
3753
3754 SceneObjectPart[] parts = m_parts.GetArray(); 5185 SceneObjectPart[] parts = m_parts.GetArray();
3755 for (int i = 0; i < parts.Length; i++) 5186 for (int i = 0; i < parts.Length; i++)
3756 retmass += parts[i].GetMass(); 5187 retmass += parts[i].GetMass();
@@ -3758,30 +5189,82 @@ namespace OpenSim.Region.Framework.Scenes
3758 return retmass; 5189 return retmass;
3759 } 5190 }
3760 5191
3761 /// <summary> 5192 // center of mass of full object
3762 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that 5193 public Vector3 GetCenterOfMass()
3763 /// the physics engine can use it.
3764 /// </summary>
3765 /// <remarks>
3766 /// When the physics engine has finished with it, the sculpt data is discarded to save memory.
3767 /// </remarks>
3768/*
3769 public void CheckSculptAndLoad()
3770 { 5194 {
3771 if (IsDeleted) 5195 PhysicsActor pa = RootPart.PhysActor;
3772 return;
3773 5196
3774 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0) 5197 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
3775 return; 5198 {
5199 // physics knows better about center of mass of physical prims
5200 Vector3 tmp = pa.CenterOfMass;
5201 return tmp;
5202 }
3776 5203
3777// m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId); 5204 Vector3 Ptot = Vector3.Zero;
5205 float totmass = 0f;
5206 float m;
3778 5207
3779 SceneObjectPart[] parts = m_parts.GetArray(); 5208 SceneObjectPart[] parts = m_parts.GetArray();
3780
3781 for (int i = 0; i < parts.Length; i++) 5209 for (int i = 0; i < parts.Length; i++)
3782 parts[i].CheckSculptAndLoad(); 5210 {
5211 m = parts[i].GetMass();
5212 Ptot += parts[i].GetPartCenterOfMass() * m;
5213 totmass += m;
5214 }
5215
5216 if (totmass == 0)
5217 totmass = 0;
5218 else
5219 totmass = 1 / totmass;
5220 Ptot *= totmass;
5221
5222 return Ptot;
3783 } 5223 }
3784*/ 5224
5225 public void GetInertiaData(out float TotalMass, out Vector3 CenterOfMass, out Vector3 Inertia, out Vector4 aux )
5226 {
5227 PhysicsActor pa = RootPart.PhysActor;
5228
5229 if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
5230 {
5231 PhysicsInertiaData inertia;
5232
5233 inertia = pa.GetInertiaData();
5234
5235 TotalMass = inertia.TotalMass;
5236 CenterOfMass = inertia.CenterOfMass;
5237 Inertia = inertia.Inertia;
5238 aux = inertia.InertiaRotation;
5239
5240 return;
5241 }
5242
5243 TotalMass = GetMass();
5244 CenterOfMass = GetCenterOfMass() - AbsolutePosition;
5245 CenterOfMass *= Quaternion.Conjugate(RootPart.RotationOffset);
5246 Inertia = Vector3.Zero;
5247 aux = Vector4.Zero;
5248 }
5249
5250 public void SetInertiaData(float TotalMass, Vector3 CenterOfMass, Vector3 Inertia, Vector4 aux )
5251 {
5252 PhysicsInertiaData inertia = new PhysicsInertiaData();
5253 inertia.TotalMass = TotalMass;
5254 inertia.CenterOfMass = CenterOfMass;
5255 inertia.Inertia = Inertia;
5256 inertia.InertiaRotation = aux;
5257
5258 if(TotalMass < 0)
5259 RootPart.PhysicsInertia = null;
5260 else
5261 RootPart.PhysicsInertia = new PhysicsInertiaData(inertia);
5262
5263 PhysicsActor pa = RootPart.PhysActor;
5264 if(pa !=null)
5265 pa.SetInertiaData(inertia);
5266 }
5267
3785 /// <summary> 5268 /// <summary>
3786 /// Set the user group to which this scene object belongs. 5269 /// Set the user group to which this scene object belongs.
3787 /// </summary> 5270 /// </summary>
@@ -3798,7 +5281,7 @@ namespace OpenSim.Region.Framework.Scenes
3798 } 5281 }
3799 5282
3800 HasGroupChanged = true; 5283 HasGroupChanged = true;
3801 5284
3802 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled 5285 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
3803 // for the same object with very different properties. The caller must schedule the update. 5286 // for the same object with very different properties. The caller must schedule the update.
3804 //ScheduleGroupForFullUpdate(); 5287 //ScheduleGroupForFullUpdate();
@@ -3937,6 +5420,133 @@ namespace OpenSim.Region.Framework.Scenes
3937 FromItemID = uuid; 5420 FromItemID = uuid;
3938 } 5421 }
3939 5422
5423 public void ResetOwnerChangeFlag()
5424 {
5425 ForEachPart(delegate(SceneObjectPart part)
5426 {
5427 part.ResetOwnerChangeFlag();
5428 });
5429 InvalidateEffectivePerms();
5430 }
5431
5432 // clear some references to easy cg
5433 public void Clear()
5434 {
5435 m_parts.Clear();
5436 m_sittingAvatars.Clear();
5437// m_rootPart = null;
5438
5439 m_PlaySoundMasterPrim = null;
5440 m_PlaySoundSlavePrims.Clear();
5441 m_LoopSoundMasterPrim = null;
5442 m_targets.Clear();
5443 m_partsNameToLinkMap.Clear();
5444 }
5445
5446 private Dictionary<string,int> m_partsNameToLinkMap = new Dictionary<string, int>();
5447 private string GetLinkNumber_lastname;
5448 private int GetLinkNumber_lastnumber;
5449
5450 // this scales bad but so does GetLinkNumPart
5451 public int GetLinkNumber(string name)
5452 {
5453 if(String.IsNullOrEmpty(name) || name == "Object")
5454 return -1;
5455
5456 lock(m_partsNameToLinkMap)
5457 {
5458 if(m_partsNameToLinkMap.Count == 0)
5459 {
5460 GetLinkNumber_lastname = String.Empty;
5461 GetLinkNumber_lastnumber = -1;
5462 SceneObjectPart[] parts = m_parts.GetArray();
5463 for (int i = 0; i < parts.Length; i++)
5464 {
5465 string s = parts[i].Name;
5466 if(String.IsNullOrEmpty(s) || s == "Object" || s == "Primitive")
5467 continue;
5468
5469 if(m_partsNameToLinkMap.ContainsKey(s))
5470 {
5471 int ol = parts[i].LinkNum;
5472 if(ol < m_partsNameToLinkMap[s])
5473 m_partsNameToLinkMap[s] = ol;
5474 }
5475 else
5476 m_partsNameToLinkMap[s] = parts[i].LinkNum;
5477 }
5478 }
5479
5480 if(name == GetLinkNumber_lastname)
5481 return GetLinkNumber_lastnumber;
5482
5483 if(m_partsNameToLinkMap.ContainsKey(name))
5484 {
5485 lock(m_partsNameToLinkMap)
5486 {
5487 GetLinkNumber_lastname = name;
5488 GetLinkNumber_lastnumber = m_partsNameToLinkMap[name];
5489 return GetLinkNumber_lastnumber;
5490 }
5491 }
5492 }
5493
5494 if(m_sittingAvatars.Count > 0)
5495 {
5496 int j = m_parts.Count + 1;
5497
5498 ScenePresence[] avs = m_sittingAvatars.ToArray();
5499 for (int i = 0; i < avs.Length; i++, j++)
5500 {
5501 if (avs[i].Name == name)
5502 {
5503 GetLinkNumber_lastname = name;
5504 GetLinkNumber_lastnumber = j;
5505 return j;
5506 }
5507 }
5508 }
5509
5510 return -1;
5511 }
5512
5513 public void InvalidatePartsLinkMaps()
5514 {
5515 lock(m_partsNameToLinkMap)
5516 {
5517 m_partsNameToLinkMap.Clear();
5518 GetLinkNumber_lastname = String.Empty;
5519 GetLinkNumber_lastnumber = -1;
5520 }
5521 }
5522
5523 public bool CollisionSoundThrottled(int collisionSoundType)
5524 {
5525 double time = m_lastCollisionSoundMS;
5526// m_lastCollisionSoundMS = Util.GetTimeStampMS();
5527// time = m_lastCollisionSoundMS - time;
5528 double now = Util.GetTimeStampMS();
5529 time = now - time;
5530 switch (collisionSoundType)
5531 {
5532 case 0: // default sounds
5533 case 2: // default sounds with volume set by script
5534 if(time < 300.0)
5535 return true;
5536 break;
5537 case 1: // selected sound
5538 if(time < 200.0)
5539 return true;
5540 break;
5541 default:
5542 break;
5543 }
5544 m_lastCollisionSoundMS = now;
5545 return false;
5546 }
5547
3940 #endregion 5548 #endregion
3941 } 5549 }
5550
5551
3942} 5552}