OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
SceneObjectGroup.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.ComponentModel;
30 using System.Collections.Generic;
31 using System.Drawing;
32 using System.IO;
33 using System.Diagnostics;
34 using System.Linq;
35 using System.Threading;
36 using System.Xml;
37 using System.Xml.Serialization;
38 using OpenMetaverse;
39 using OpenMetaverse.Packets;
40 using OpenSim.Framework;
41 using OpenSim.Region.Framework.Interfaces;
42 using OpenSim.Region.PhysicsModules.SharedBase;
43 using OpenSim.Region.Framework.Scenes.Serialization;
45 using OpenSim.Services.Interfaces;
46 
47 namespace OpenSim.Region.Framework.Scenes
48 {
49 
50  [Flags]
51  public enum scriptEvents
52  {
53  None = 0,
54  attach = 1,
55  collision = 16,
56  collision_end = 32,
57  collision_start = 64,
58  control = 128,
59  dataserver = 256,
60  email = 512,
61  http_response = 1024,
62  land_collision = 2048,
63  land_collision_end = 4096,
64  land_collision_start = 8192,
65  at_target = 16384,
66  at_rot_target = 16777216,
67  listen = 32768,
68  money = 65536,
69  moving_end = 131072,
70  moving_start = 262144,
71  not_at_rot_target = 524288,
72  not_at_target = 1048576,
73  remote_data = 8388608,
74  run_time_permissions = 268435456,
75  state_entry = 1073741824,
76  state_exit = 2,
77  timer = 4,
78  touch = 8,
79  touch_end = 536870912,
80  touch_start = 2097152,
81  transaction_result = 33554432,
82  object_rez = 4194304
83  }
84 
85  public struct scriptPosTarget
86  {
87  public Vector3 targetPos;
88  public float tolerance;
89  public uint handle;
90  }
91 
92  public struct scriptRotTarget
93  {
94  public Quaternion targetRot;
95  public float tolerance;
96  public uint handle;
97  }
98 
99  public delegate void PrimCountTaintedDelegate();
100 
105  public partial class SceneObjectGroup : EntityBase, ISceneObject
106  {
107  // Axis selection bitmask used by SetAxisRotation()
108  // Just happen to be the same bits used by llSetStatus() and defined in ScriptBaseClass.
109  public enum axisSelect : int
110  {
111  STATUS_ROTATE_X = 0x002,
112  STATUS_ROTATE_Y = 0x004,
113  STATUS_ROTATE_Z = 0x008,
114  NOT_STATUS_ROTATE_X = 0xFD,
115  NOT_STATUS_ROTATE_Y = 0xFB,
116  NOT_STATUS_ROTATE_Z = 0xF7
117  }
118 
119  // This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm
120  public static readonly uint SLAM = 16;
121 
122  // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
123 
128  private bool m_hasGroupChanged = false;
129  private long timeFirstChanged = 0;
130  private long timeLastChanged = 0;
131  private long m_maxPersistTime = 0;
132  private long m_minPersistTime = 0;
133 // private Random m_rand;
134 
144  public bool HasGroupChanged
145  {
146  set
147  {
148  if (value)
149  {
150 
151  if (Backup)
152  {
153  m_scene.SceneGraph.FireChangeBackup(this);
154  }
155  timeLastChanged = DateTime.Now.Ticks;
156  if (!m_hasGroupChanged)
157  timeFirstChanged = DateTime.Now.Ticks;
158  if (m_rootPart != null && m_rootPart.UUID != null && m_scene != null)
159  {
160 /*
161  if (m_rand == null)
162  {
163  byte[] val = new byte[16];
164  m_rootPart.UUID.ToBytes(val, 0);
165  m_rand = new Random(BitConverter.ToInt32(val, 0));
166  }
167  */
168  if (m_scene.GetRootAgentCount() == 0)
169  {
170  //If the region is empty, this change has been made by an automated process
171  //and thus we delay the persist time by a random amount between 1.5 and 2.5.
172 
173 // float factor = 1.5f + (float)(m_rand.NextDouble());
174  float factor = 2.0f;
175  m_maxPersistTime = (long)((float)m_scene.m_persistAfter * factor);
176  m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * factor);
177  }
178  else
179  {
180  //If the region is not empty, we want to obey the minimum and maximum persist times
181  //but add a random factor so we stagger the object persistance a little
182 // m_maxPersistTime = (long)((float)m_scene.m_persistAfter * (1.0d - (m_rand.NextDouble() / 5.0d))); //Multiply by 1.0-1.5
183 // m_minPersistTime = (long)((float)m_scene.m_dontPersistBefore * (1.0d + (m_rand.NextDouble() / 2.0d))); //Multiply by 0.8-1.0
184  m_maxPersistTime = m_scene.m_persistAfter;
185  m_minPersistTime = m_scene.m_dontPersistBefore;
186  }
187  }
188  }
189  m_hasGroupChanged = value;
190 
191 // m_log.DebugFormat(
192 // "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId);
193  }
194 
195  get { return m_hasGroupChanged; }
196  }
197 
198  private bool m_groupContainsForeignPrims = false;
199 
206  public bool GroupContainsForeignPrims
207  {
208  private set
209  {
210  m_groupContainsForeignPrims = value;
211  if (m_groupContainsForeignPrims)
212  HasGroupChanged = true;
213  }
214 
215  get { return m_groupContainsForeignPrims; }
216  }
217 
218  public bool HasGroupChangedDueToDelink { get; set; }
219 
220  private bool isTimeToPersist()
221  {
222  if (IsSelected || IsDeleted || IsAttachment)
223  return false;
224  if (!m_hasGroupChanged)
225  return false;
226  if (m_scene.ShuttingDown)
227  return true;
228 
229  if (m_minPersistTime == 0 || m_maxPersistTime == 0)
230  {
231  m_maxPersistTime = m_scene.m_persistAfter;
232  m_minPersistTime = m_scene.m_dontPersistBefore;
233  }
234 
235  long currentTime = DateTime.Now.Ticks;
236 
237  if (timeLastChanged == 0) timeLastChanged = currentTime;
238  if (timeFirstChanged == 0) timeFirstChanged = currentTime;
239 
240  if (currentTime - timeLastChanged > m_minPersistTime || currentTime - timeFirstChanged > m_maxPersistTime)
241  return true;
242  return false;
243  }
244 
248  public bool IsAttachment { get; set; }
249 
256  public UUID AttachedAvatar { get; set; }
257 
264  public uint AttachmentPoint
265  {
266  get
267  {
268  return m_rootPart.Shape.State;
269  }
270 
271  set
272  {
273  IsAttachment = value != 0;
274  m_rootPart.Shape.State = (byte)value;
275  }
276  }
277 
285  public bool HasPrivateAttachmentPoint
286  {
287  get
288  {
289  return AttachmentPoint >= (uint)OpenMetaverse.AttachmentPoint.HUDCenter2
290  && AttachmentPoint <= (uint)OpenMetaverse.AttachmentPoint.HUDBottomRight;
291  }
292  }
293 
295  {
296  AttachmentPoint = 0;
297 
298  // Don't zap trees
299  if (RootPart.Shape.PCode == (byte)PCode.Tree ||
300  RootPart.Shape.PCode == (byte)PCode.NewTree)
301  return;
302 
303  // Even though we don't use child part state parameters for attachments any more, we still need to set
304  // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
305  // we store them correctly, scene objects that we receive from elsewhere might not.
306  foreach (SceneObjectPart part in Parts)
307  part.Shape.State = 0;
308  }
309 
316  public bool IsPhantom
317  {
318  get { return (RootPart.Flags & PrimFlags.Phantom) != 0; }
319  }
320 
327  public bool UsesPhysics
328  {
329  get { return (RootPart.Flags & PrimFlags.Physics) != 0; }
330  }
331 
332 
339  public bool IsTemporary
340  {
341  get { return (RootPart.Flags & PrimFlags.TemporaryOnRez) != 0; }
342  }
343 
344  public bool IsVolumeDetect
345  {
346  get { return RootPart.VolumeDetectActive; }
347  }
348 
349  private Vector3 lastPhysGroupPos;
350  private Quaternion lastPhysGroupRot;
351 
355  public bool Backup { get; private set; }
356 
357  protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
358 
359  protected ulong m_regionHandle;
361  // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
362 
363  private SortedDictionary<uint, scriptPosTarget> m_targets = new SortedDictionary<uint, scriptPosTarget>();
364  private SortedDictionary<uint, scriptRotTarget> m_rotTargets = new SortedDictionary<uint, scriptRotTarget>();
365 
366  public SortedDictionary<uint, scriptPosTarget> AtTargets
367  {
368  get { return m_targets; }
369  }
370 
371  public SortedDictionary<uint, scriptRotTarget> RotTargets
372  {
373  get { return m_rotTargets; }
374  }
375 
376  private bool m_scriptListens_atTarget;
377  private bool m_scriptListens_notAtTarget;
378  private bool m_scriptListens_atRotTarget;
379  private bool m_scriptListens_notAtRotTarget;
380 
381  public bool m_dupeInProgress = false;
382  internal Dictionary<UUID, string> m_savedScriptState;
383 
384  #region Properties
385 
389  public override string Name
390  {
391  get { return RootPart.Name; }
392  set { RootPart.Name = value; }
393  }
394 
395  public string Description
396  {
397  get { return RootPart.Description; }
398  set { RootPart.Description = value; }
399  }
400 
408  protected bool m_isSelected = false;
409 
413  public int PrimCount
414  {
415  get { return m_parts.Count; }
416  }
417 
418 // protected Quaternion m_rotation = Quaternion.Identity;
419 //
420 // public virtual Quaternion Rotation
421 // {
422 // get { return m_rotation; }
423 // set {
424 // m_rotation = value;
425 // }
426 // }
427 
428  public Quaternion GroupRotation
429  {
430  get { return m_rootPart.RotationOffset; }
431  }
432 
433  public Vector3 GroupScale
434  {
435  get
436  {
438  Vector3 maxScale = Vector3.Zero;
439  Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
440 
441  SceneObjectPart[] parts = m_parts.GetArray();
442  for (int i = 0; i < parts.Length; i++)
443  {
444  SceneObjectPart part = parts[i];
445  Vector3 partscale = part.Scale;
446  Vector3 partoffset = part.OffsetPosition;
447 
448  minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X;
449  minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y;
450  minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z;
451 
452  maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
453  maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
454  maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
455  }
456 
457  finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
458  finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
459  finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
460 
461  return finalScale;
462  }
463  }
464 
465  public UUID GroupID
466  {
467  get { return m_rootPart.GroupID; }
468  set { m_rootPart.GroupID = value; }
469  }
470 
471  public SceneObjectPart[] Parts
472  {
473  get { return m_parts.GetArray(); }
474  }
475 
476  public bool ContainsPart(UUID partID)
477  {
478  return m_parts.ContainsKey(partID);
479  }
480 
487  public bool ContainsPart(uint localID)
488  {
489  SceneObjectPart[] parts = m_parts.GetArray();
490  for (int i = 0; i < parts.Length; i++)
491  {
492  if (parts[i].LocalId == localID)
493  return true;
494  }
495 
496  return false;
497  }
498 
502  public SceneObjectPart RootPart
503  {
504  get { return m_rootPart; }
505  }
506 
507  public ulong RegionHandle
508  {
509  get { return m_regionHandle; }
510  set
511  {
512  m_regionHandle = value;
513  SceneObjectPart[] parts = m_parts.GetArray();
514  for (int i = 0; i < parts.Length; i++)
515  parts[i].RegionHandle = value;
516  }
517  }
518 
530  public bool IsAttachmentCheckFull()
531  {
532  return (IsAttachment ||
533  (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0));
534  }
535 
536  private struct avtocrossInfo
537  {
538  public ScenePresence av;
539  public uint ParentID;
540  }
541 
542 
543  public bool inTransit = false;
544  public delegate SceneObjectGroup SOGCrossDelegate(SceneObjectGroup sog,Vector3 pos);
545 
549  public override Vector3 AbsolutePosition
550  {
551  get { return m_rootPart.GroupPosition; }
552  set
553  {
554  Vector3 val = value;
555  if (Scene != null
557  && !IsAttachmentCheckFull()
558  && !Scene.LoadingPrims
559  )
560  {
561  if (!inTransit)
562  {
563  inTransit = true;
564  SOGCrossDelegate d = CrossAsync;
565  d.BeginInvoke(this, val, CrossAsyncCompleted, d);
566  }
567  return;
568  }
569 
570  if (RootPart.GetStatusSandbox())
571  {
572  if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
573  {
574  RootPart.ScriptSetPhysicsStatus(false);
575 
576  if (Scene != null)
577  Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
578  ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
579 
580  return;
581  }
582  }
583 
584  bool triggerScriptEvent = m_rootPart.GroupPosition != val;
585  if (m_dupeInProgress || IsDeleted)
586  triggerScriptEvent = false;
587 
588  m_rootPart.GroupPosition = val;
589 
590  // Restuff the new GroupPosition into each child SOP of the linkset.
591  // this is needed because physics may not have linksets but just loose SOPs in world
592 
593  SceneObjectPart[] parts = m_parts.GetArray();
594 
595  foreach (SceneObjectPart part in parts)
596  {
597  if (part != m_rootPart)
598  part.GroupPosition = val;
599  }
600 
601  foreach (ScenePresence av in m_sittingAvatars)
602  {
603  av.sitSOGmoved();
604  }
605 
606 
607  // now that position is changed tell it to scripts
608  if (triggerScriptEvent)
609  {
610  foreach (SceneObjectPart part in parts)
611  {
612  part.TriggerScriptChangedEvent(Changed.POSITION);
613  }
614  }
615 
616  if (Scene != null)
617  Scene.EventManager.TriggerParcelPrimCountTainted();
618 
619  }
620  }
621 
623  {
624  Scene sogScene = sog.m_scene;
625  IEntityTransferModule entityTransfer = sogScene.RequestModuleInterface<IEntityTransferModule>();
626 
627  Vector3 newpos = Vector3.Zero;
628  OpenSim.Services.Interfaces.GridRegion destination = null;
629 
630  if (sog.RootPart.DIE_AT_EDGE)
631  {
632  try
633  {
634  sogScene.DeleteSceneObject(sog, false);
635  }
636  catch (Exception)
637  {
638  m_log.Warn("[SCENE]: exception when trying to remove the prim that crossed the border.");
639  }
640  return sog;
641  }
642 
643  if (sog.RootPart.RETURN_AT_EDGE)
644  {
645  // We remove the object here
646  try
647  {
648  List<uint> localIDs = new List<uint>();
649  localIDs.Add(sog.RootPart.LocalId);
650  sogScene.AddReturn(sog.OwnerID, sog.Name, sog.AbsolutePosition,
651  "Returned at region cross");
652  sogScene.DeRezObjects(null, localIDs, UUID.Zero, DeRezAction.Return, UUID.Zero);
653  }
654  catch (Exception)
655  {
656  m_log.Warn("[SCENE]: exception when trying to return the prim that crossed the border.");
657  }
658  return sog;
659  }
660 
661  if (sog.m_rootPart.KeyframeMotion != null)
662  sog.m_rootPart.KeyframeMotion.StartCrossingCheck();
663 
664  if (entityTransfer == null)
665  return sog;
666 
667  destination = entityTransfer.GetObjectDestination(sog, val, out newpos);
668  if (destination == null)
669  return sog;
670 
671  if (sog.m_sittingAvatars.Count == 0)
672  {
673  entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true, true);
674  return sog;
675  }
676 
677  string reason = String.Empty;
679 
680  foreach (ScenePresence av in sog.m_sittingAvatars)
681  {
682  // We need to cross these agents. First, let's find
683  // out if any of them can't cross for some reason.
684  // We have to deny the crossing entirely if any
685  // of them are banned. Alternatively, we could
686  // unsit banned agents....
687 
688  // We set the avatar position as being the object
689  // position to get the region to send to
690  if(!entityTransfer.checkAgentAccessToRegion(av, destination, newpos, ctx, out reason))
691  {
692  return sog;
693  }
694  m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
695  }
696 
697  // We unparent the SP quietly so that it won't
698  // be made to stand up
699 
700  List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
701 
702  foreach (ScenePresence av in sog.m_sittingAvatars)
703  {
704  avtocrossInfo avinfo = new avtocrossInfo();
705  SceneObjectPart parentPart = sogScene.GetSceneObjectPart(av.ParentID);
706  if (parentPart != null)
707  av.ParentUUID = parentPart.UUID;
708 
709  avinfo.av = av;
710  avinfo.ParentID = av.ParentID;
711  avsToCross.Add(avinfo);
712 
713  av.PrevSitOffset = av.OffsetPosition;
714  av.ParentID = 0;
715  }
716 
717  if (entityTransfer.CrossPrimGroupIntoNewRegion(destination, newpos, sog, true, false))
718  {
719  foreach (avtocrossInfo avinfo in avsToCross)
720  {
721  ScenePresence av = avinfo.av;
722  if (!av.IsInTransit) // just in case...
723  {
724  m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
725 
726  av.IsInTransit = true;
727 
728 // CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
729 // d.BeginInvoke(av, val, destination, av.Flying, version, CrossAgentToNewRegionCompleted, d);
730  entityTransfer.CrossAgentToNewRegionAsync(av, newpos, destination, av.Flying, ctx);
731  if (av.IsChildAgent)
732  {
733  // avatar crossed do some extra cleanup
734  if (av.ParentUUID != UUID.Zero)
735  {
736  av.ClearControls();
737  av.ParentPart = null;
738  }
739  }
740  else
741  {
742  // avatar cross failed we need do dedicated standUp
743  // part of it was done at CrossAgentToNewRegionAsync
744  // so for now just remove the sog controls
745  // this may need extra care
746  av.UnRegisterSeatControls(sog.UUID);
747  }
748 
749  av.ParentUUID = UUID.Zero;
750  // In any case
751  av.IsInTransit = false;
752 
753  m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", av.Firstname, av.Lastname);
754  }
755  else
756  m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar already in transit {0} to {1}", av.Name, val);
757  }
758  avsToCross.Clear();
759  sog.RemoveScriptInstances(true);
760  sog.Clear();
761  return sog;
762  }
763  else // cross failed, put avas back ??
764  {
765  foreach (avtocrossInfo avinfo in avsToCross)
766  {
767  ScenePresence av = avinfo.av;
768  av.ParentUUID = UUID.Zero;
769  av.ParentID = avinfo.ParentID;
770  }
771  }
772  avsToCross.Clear();
773 
774  return sog;
775  }
776 
777  public void CrossAsyncCompleted(IAsyncResult iar)
778  {
779  SOGCrossDelegate icon = (SOGCrossDelegate)iar.AsyncState;
780  SceneObjectGroup sog = icon.EndInvoke(iar);
781 
782  if (!sog.IsDeleted)
783  {
784  SceneObjectPart rootp = sog.m_rootPart;
785  Vector3 oldp = rootp.GroupPosition;
786  oldp.X = Util.Clamp<float>(oldp.X, 0.5f, sog.m_scene.RegionInfo.RegionSizeX - 0.5f);
787  oldp.Y = Util.Clamp<float>(oldp.Y, 0.5f, sog.m_scene.RegionInfo.RegionSizeY - 0.5f);
788  rootp.GroupPosition = oldp;
789 
790  SceneObjectPart[] parts = sog.m_parts.GetArray();
791 
792  foreach (SceneObjectPart part in parts)
793  {
794  if (part != rootp)
795  part.GroupPosition = oldp;
796  }
797 
798  foreach (ScenePresence av in sog.m_sittingAvatars)
799  {
800  av.sitSOGmoved();
801  }
802 
803  sog.Velocity = Vector3.Zero;
804 
805  if (sog.m_rootPart.KeyframeMotion != null)
806  sog.m_rootPart.KeyframeMotion.CrossingFailure();
807 
808  if (sog.RootPart.PhysActor != null)
809  {
810  sog.RootPart.PhysActor.CrossingFailure();
811  }
812 
813  sog.inTransit = false;
814  sog.ScheduleGroupForFullUpdate();
815  }
816  }
817 
818 /* outdated
819  private void CrossAgentToNewRegionCompleted(ScenePresence agent)
820  {
822  if (agent.IsChildAgent)
823  {
824  if (agent.ParentUUID != UUID.Zero)
825  {
826  agent.HandleForceReleaseControls(agent.ControllingClient,agent.UUID);
827  agent.ParentPart = null;
828 // agent.ParentPosition = Vector3.Zero;
829 // agent.ParentUUID = UUID.Zero;
830  }
831  }
832 
833  agent.ParentUUID = UUID.Zero;
834 // agent.Reset();
835 // else // Not successful
836 // agent.RestoreInCurrentScene();
837 
838  // In any case
839  agent.IsInTransit = false;
840 
841  m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
842  }
843 */
844  public override Vector3 Velocity
845  {
846  get { return RootPart.Velocity; }
847  set { RootPart.Velocity = value; }
848  }
849 
850  public override uint LocalId
851  {
852  get { return m_rootPart.LocalId; }
853  set { m_rootPart.LocalId = value; }
854  }
855 
856  public override UUID UUID
857  {
858  get { return m_rootPart.UUID; }
859  set
860  {
861  lock (m_parts.SyncRoot)
862  {
863  m_parts.Remove(m_rootPart.UUID);
864  m_rootPart.UUID = value;
865  m_parts.Add(value, m_rootPart);
866  }
867  }
868  }
869 
870  public UUID LastOwnerID
871  {
872  get { return m_rootPart.LastOwnerID; }
873  set { m_rootPart.LastOwnerID = value; }
874  }
875 
876  public UUID OwnerID
877  {
878  get { return m_rootPart.OwnerID; }
879  set { m_rootPart.OwnerID = value; }
880  }
881 
882  public float Damage
883  {
884  get { return m_rootPart.Damage; }
885  set { m_rootPart.Damage = value; }
886  }
887 
888  public Color Color
889  {
890  get { return m_rootPart.Color; }
891  set { m_rootPart.Color = value; }
892  }
893 
894  public string Text
895  {
896  get {
897  string returnstr = m_rootPart.Text;
898  if (returnstr.Length > 255)
899  {
900  returnstr = returnstr.Substring(0, 255);
901  }
902  return returnstr;
903  }
904  set { m_rootPart.Text = value; }
905  }
906 
911  protected virtual bool CanBeBackedUp
912  {
913  get { return true; }
914  }
915 
916  public bool IsSelected
917  {
918  get { return m_isSelected; }
919  set
920  {
921  m_isSelected = value;
922  // Tell physics engine that group is selected
923 
924  // this is not right
925  // but ode engines should only really need to know about root part
926  // so they can put entire object simulation on hold and not colliding
927  // keep as was for now
928 
929  PhysicsActor pa = m_rootPart.PhysActor;
930  if (pa != null)
931  {
932  pa.Selected = value;
933 
934  // Pass it on to the children.
935  SceneObjectPart[] parts = m_parts.GetArray();
936  for (int i = 0; i < parts.Length; i++)
937  {
938  SceneObjectPart child = parts[i];
939 
940  PhysicsActor childPa = child.PhysActor;
941  if (childPa != null)
942  childPa.Selected = value;
943  }
944  }
945  if (RootPart.KeyframeMotion != null)
946  RootPart.KeyframeMotion.Selected = value;
947  }
948  }
949 
950  public void PartSelectChanged(bool partSelect)
951  {
952  // any part selected makes group selected
953  if (m_isSelected == partSelect)
954  return;
955 
956  if (partSelect)
957  {
958  IsSelected = partSelect;
959 // if (!IsAttachment)
960 // ScheduleGroupForFullUpdate();
961  }
962  else
963  {
964  // bad bad bad 2 heavy for large linksets
965  // since viewer does send lot of (un)selects
966  // this needs to be replaced by a specific list or count ?
967  // but that will require extra code in several places
968 
969  SceneObjectPart[] parts = m_parts.GetArray();
970  for (int i = 0; i < parts.Length; i++)
971  {
972  SceneObjectPart part = parts[i];
973  if (part.IsSelected)
974  return;
975  }
976  IsSelected = partSelect;
977 // if (!IsAttachment)
978 // {
979 // ScheduleGroupForFullUpdate();
980 // }
981  }
982  }
983  // PlaySoundMasterPrim no longer in use to remove
984  private SceneObjectPart m_PlaySoundMasterPrim = null;
985  public SceneObjectPart PlaySoundMasterPrim
986  {
987  get { return m_PlaySoundMasterPrim; }
988  set { m_PlaySoundMasterPrim = value; }
989  }
990  // PlaySoundSlavePrims no longer in use to remove
991  private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>();
992  public List<SceneObjectPart> PlaySoundSlavePrims
993  {
994  get { return m_PlaySoundSlavePrims; }
995  set { m_PlaySoundSlavePrims = value; }
996  }
997 
998  // LoopSoundMasterPrim no longer in use to remove
999  private SceneObjectPart m_LoopSoundMasterPrim = null;
1000  public SceneObjectPart LoopSoundMasterPrim
1001  {
1002  get { return m_LoopSoundMasterPrim; }
1003  set { m_LoopSoundMasterPrim = value; }
1004  }
1005 
1006  // m_LoopSoundSlavePrims no longer in use to remove
1007  private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>();
1008  public List<SceneObjectPart> LoopSoundSlavePrims
1009  {
1010  get { return m_LoopSoundSlavePrims; }
1011  set { m_LoopSoundSlavePrims = value; }
1012  }
1013 
1017  public UUID RegionUUID
1018  {
1019  get
1020  {
1021  if (m_scene != null)
1022  {
1023  return m_scene.RegionInfo.RegionID;
1024  }
1025  return UUID.Zero;
1026  }
1027  }
1028 
1035  public UUID FromItemID { get; set; }
1036 
1043  public UUID FromPartID { get; set; }
1044 
1051  public UUID FromFolderID { get; set; }
1052 
1057  public bool BlockGrabOverride { get; set; }
1058 
1069  protected internal List<ScenePresence> m_sittingAvatars = new List<ScenePresence>();
1070 
1071  #endregion
1072 
1073 // ~SceneObjectGroup()
1074 // {
1075 // //m_log.DebugFormat("[SCENE OBJECT GROUP]: Destructor called for {0}, local id {1}", Name, LocalId);
1076 // Console.WriteLine("Destructor called for {0}, local id {1}", Name, LocalId);
1077 // }
1078 
1079  #region Constructors
1080 
1085  {
1086 
1087  }
1088 
1095  public SceneObjectGroup(SceneObjectPart part) : this()
1096  {
1097  SetRootPart(part);
1098  }
1099 
1103  public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
1104  {
1105  SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero));
1106  }
1107 
1111  public SceneObjectGroup(UUID ownerID, Vector3 pos, PrimitiveBaseShape shape)
1112  : this(ownerID, pos, Quaternion.Identity, shape)
1113  {
1114  }
1115 
1116  public void LoadScriptState(XmlDocument doc)
1117  {
1118  XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState");
1119  if (nodes.Count > 0)
1120  {
1121  if (m_savedScriptState == null)
1122  m_savedScriptState = new Dictionary<UUID, string>();
1123  foreach (XmlNode node in nodes)
1124  {
1125  if (node.Attributes["UUID"] != null)
1126  {
1127  UUID itemid = new UUID(node.Attributes["UUID"].Value);
1128  if (itemid != UUID.Zero)
1129  m_savedScriptState[itemid] = node.InnerXml;
1130  }
1131  }
1132  }
1133  }
1134 
1135  public void LoadScriptState(XmlReader reader)
1136  {
1137 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Looking for script state for {0}", Name);
1138 
1139  while (true)
1140  {
1141  if (reader.Name == "SavedScriptState" && reader.NodeType == XmlNodeType.Element)
1142  {
1143 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Loading script state for {0}", Name);
1144 
1145  if (m_savedScriptState == null)
1146  m_savedScriptState = new Dictionary<UUID, string>();
1147 
1148  string uuid = reader.GetAttribute("UUID");
1149 
1150  // Even if there is no UUID attribute for some strange reason, we must always read the inner XML
1151  // so we don't continually keep checking the same SavedScriptedState element.
1152  string innerXml = reader.ReadInnerXml();
1153 
1154  if (uuid != null)
1155  {
1156 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Found state for item ID {0} in object {1}", uuid, Name);
1157 
1158  UUID itemid = new UUID(uuid);
1159  if (itemid != UUID.Zero)
1160  m_savedScriptState[itemid] = innerXml;
1161  }
1162  else
1163  {
1164  m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}", Name);
1165  }
1166  }
1167  else
1168  {
1169  if (!reader.Read())
1170  break;
1171  }
1172  }
1173  }
1174 
1178  public virtual void AttachToBackup()
1179  {
1180  if (IsAttachment) return;
1181  m_scene.SceneGraph.FireAttachToBackup(this);
1182 
1183 // if (InSceneBackup)
1184  {
1185 // m_log.DebugFormat(
1186 // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
1187 
1188  if (!Backup)
1189  m_scene.EventManager.OnBackup += ProcessBackup;
1190 
1191  Backup = true;
1192  }
1193  }
1194 
1199  public void AttachToScene(Scene scene)
1200  {
1201  m_scene = scene;
1202  RegionHandle = m_scene.RegionInfo.RegionHandle;
1203 
1204  if (m_rootPart.Shape.PCode != 9 || m_rootPart.Shape.State == 0)
1205  m_rootPart.ParentID = 0;
1206  if (m_rootPart.LocalId == 0)
1207  m_rootPart.LocalId = m_scene.AllocateLocalId();
1208 
1209  SceneObjectPart[] parts = m_parts.GetArray();
1210  for (int i = 0; i < parts.Length; i++)
1211  {
1212  SceneObjectPart part = parts[i];
1213  if (part.KeyframeMotion != null)
1214  {
1215  part.KeyframeMotion.UpdateSceneObject(this);
1216  }
1217 
1218  if (Object.ReferenceEquals(part, m_rootPart))
1219  continue;
1220 
1221  if (part.LocalId == 0)
1222  part.LocalId = m_scene.AllocateLocalId();
1223 
1224  part.ParentID = m_rootPart.LocalId;
1225  //m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID);
1226  }
1227 
1228  ApplyPhysics();
1229 
1230  if (RootPart.PhysActor != null)
1231  RootPart.Force = RootPart.Force;
1232  if (RootPart.PhysActor != null)
1233  RootPart.Torque = RootPart.Torque;
1234  if (RootPart.PhysActor != null)
1235  RootPart.Buoyancy = RootPart.Buoyancy;
1236 
1237  // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
1238  // for the same object with very different properties. The caller must schedule the update.
1239  //ScheduleGroupForFullUpdate();
1240  }
1241 
1242  public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
1243  {
1244  // We got a request from the inner_scene to raytrace along the Ray hRay
1245  // We're going to check all of the prim in this group for intersection with the ray
1246  // If we get a result, we're going to find the closest result to the origin of the ray
1247  // and send back the intersection information back to the innerscene.
1248 
1249  EntityIntersection result = new EntityIntersection();
1250 
1251  SceneObjectPart[] parts = m_parts.GetArray();
1252 
1253  // Find closest hit here
1254  float idist = float.MaxValue;
1255 
1256  for (int i = 0; i < parts.Length; i++)
1257  {
1258  SceneObjectPart part = parts[i];
1259 
1260  // Temporary commented to stop compiler warning
1261  //Vector3 partPosition =
1262  // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
1263  Quaternion parentrotation = GroupRotation;
1264 
1265  // Telling the prim to raytrace.
1266  //EntityIntersection inter = part.TestIntersection(hRay, parentrotation);
1267 
1268  EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
1269 
1270  if (inter.HitTF)
1271  {
1272  // We need to find the closest prim to return to the testcaller along the ray
1273  if (inter.distance < idist)
1274  {
1275  result.HitTF = true;
1276  result.ipoint = inter.ipoint;
1277  result.obj = part;
1278  result.normal = inter.normal;
1279  result.distance = inter.distance;
1280 
1281  idist = inter.distance;
1282  }
1283  }
1284  }
1285  return result;
1286  }
1287 
1294  public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
1295  {
1296  maxX = float.MinValue;
1297  maxY = float.MinValue;
1298  maxZ = float.MinValue;
1299  minX = float.MaxValue;
1300  minY = float.MaxValue;
1301  minZ = float.MaxValue;
1302 
1303  SceneObjectPart[] parts = m_parts.GetArray();
1304  foreach (SceneObjectPart part in parts)
1305  {
1306  Vector3 worldPos = part.GetWorldPosition();
1307  Vector3 offset = worldPos - AbsolutePosition;
1308  Quaternion worldRot;
1309  if (part.ParentID == 0)
1310  {
1311  worldRot = part.RotationOffset;
1312  }
1313  else
1314  {
1315  worldRot = part.GetWorldRotation();
1316  }
1317 
1318  Vector3 frontTopLeft;
1319  Vector3 frontTopRight;
1320  Vector3 frontBottomLeft;
1321  Vector3 frontBottomRight;
1322 
1323  Vector3 backTopLeft;
1324  Vector3 backTopRight;
1325  Vector3 backBottomLeft;
1326  Vector3 backBottomRight;
1327 
1328  // Vector3[] corners = new Vector3[8];
1329 
1330  Vector3 orig = Vector3.Zero;
1331 
1332  frontTopLeft.X = orig.X - (part.Scale.X / 2);
1333  frontTopLeft.Y = orig.Y - (part.Scale.Y / 2);
1334  frontTopLeft.Z = orig.Z + (part.Scale.Z / 2);
1335 
1336  frontTopRight.X = orig.X - (part.Scale.X / 2);
1337  frontTopRight.Y = orig.Y + (part.Scale.Y / 2);
1338  frontTopRight.Z = orig.Z + (part.Scale.Z / 2);
1339 
1340  frontBottomLeft.X = orig.X - (part.Scale.X / 2);
1341  frontBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
1342  frontBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
1343 
1344  frontBottomRight.X = orig.X - (part.Scale.X / 2);
1345  frontBottomRight.Y = orig.Y + (part.Scale.Y / 2);
1346  frontBottomRight.Z = orig.Z - (part.Scale.Z / 2);
1347 
1348  backTopLeft.X = orig.X + (part.Scale.X / 2);
1349  backTopLeft.Y = orig.Y - (part.Scale.Y / 2);
1350  backTopLeft.Z = orig.Z + (part.Scale.Z / 2);
1351 
1352  backTopRight.X = orig.X + (part.Scale.X / 2);
1353  backTopRight.Y = orig.Y + (part.Scale.Y / 2);
1354  backTopRight.Z = orig.Z + (part.Scale.Z / 2);
1355 
1356  backBottomLeft.X = orig.X + (part.Scale.X / 2);
1357  backBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
1358  backBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
1359 
1360  backBottomRight.X = orig.X + (part.Scale.X / 2);
1361  backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
1362  backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
1363 
1364 
1365 
1366  //m_log.InfoFormat("pre corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1367  //m_log.InfoFormat("pre corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1368  //m_log.InfoFormat("pre corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1369  //m_log.InfoFormat("pre corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1370  //m_log.InfoFormat("pre corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1371  //m_log.InfoFormat("pre corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1372  //m_log.InfoFormat("pre corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1373  //m_log.InfoFormat("pre corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1374 
1375  //for (int i = 0; i < 8; i++)
1376  //{
1377  // corners[i] = corners[i] * worldRot;
1378  // corners[i] += offset;
1379 
1380  // if (corners[i].X > maxX)
1381  // maxX = corners[i].X;
1382  // if (corners[i].X < minX)
1383  // minX = corners[i].X;
1384 
1385  // if (corners[i].Y > maxY)
1386  // maxY = corners[i].Y;
1387  // if (corners[i].Y < minY)
1388  // minY = corners[i].Y;
1389 
1390  // if (corners[i].Z > maxZ)
1391  // maxZ = corners[i].Y;
1392  // if (corners[i].Z < minZ)
1393  // minZ = corners[i].Z;
1394  //}
1395 
1396  frontTopLeft = frontTopLeft * worldRot;
1397  frontTopRight = frontTopRight * worldRot;
1398  frontBottomLeft = frontBottomLeft * worldRot;
1399  frontBottomRight = frontBottomRight * worldRot;
1400 
1401  backBottomLeft = backBottomLeft * worldRot;
1402  backBottomRight = backBottomRight * worldRot;
1403  backTopLeft = backTopLeft * worldRot;
1404  backTopRight = backTopRight * worldRot;
1405 
1406 
1407  frontTopLeft += offset;
1408  frontTopRight += offset;
1409  frontBottomLeft += offset;
1410  frontBottomRight += offset;
1411 
1412  backBottomLeft += offset;
1413  backBottomRight += offset;
1414  backTopLeft += offset;
1415  backTopRight += offset;
1416 
1417  //m_log.InfoFormat("corner 1 is {0} {1} {2}", frontTopLeft.X, frontTopLeft.Y, frontTopLeft.Z);
1418  //m_log.InfoFormat("corner 2 is {0} {1} {2}", frontTopRight.X, frontTopRight.Y, frontTopRight.Z);
1419  //m_log.InfoFormat("corner 3 is {0} {1} {2}", frontBottomRight.X, frontBottomRight.Y, frontBottomRight.Z);
1420  //m_log.InfoFormat("corner 4 is {0} {1} {2}", frontBottomLeft.X, frontBottomLeft.Y, frontBottomLeft.Z);
1421  //m_log.InfoFormat("corner 5 is {0} {1} {2}", backTopLeft.X, backTopLeft.Y, backTopLeft.Z);
1422  //m_log.InfoFormat("corner 6 is {0} {1} {2}", backTopRight.X, backTopRight.Y, backTopRight.Z);
1423  //m_log.InfoFormat("corner 7 is {0} {1} {2}", backBottomRight.X, backBottomRight.Y, backBottomRight.Z);
1424  //m_log.InfoFormat("corner 8 is {0} {1} {2}", backBottomLeft.X, backBottomLeft.Y, backBottomLeft.Z);
1425 
1426  if (frontTopRight.X > maxX)
1427  maxX = frontTopRight.X;
1428  if (frontTopLeft.X > maxX)
1429  maxX = frontTopLeft.X;
1430  if (frontBottomRight.X > maxX)
1431  maxX = frontBottomRight.X;
1432  if (frontBottomLeft.X > maxX)
1433  maxX = frontBottomLeft.X;
1434 
1435  if (backTopRight.X > maxX)
1436  maxX = backTopRight.X;
1437  if (backTopLeft.X > maxX)
1438  maxX = backTopLeft.X;
1439  if (backBottomRight.X > maxX)
1440  maxX = backBottomRight.X;
1441  if (backBottomLeft.X > maxX)
1442  maxX = backBottomLeft.X;
1443 
1444  if (frontTopRight.X < minX)
1445  minX = frontTopRight.X;
1446  if (frontTopLeft.X < minX)
1447  minX = frontTopLeft.X;
1448  if (frontBottomRight.X < minX)
1449  minX = frontBottomRight.X;
1450  if (frontBottomLeft.X < minX)
1451  minX = frontBottomLeft.X;
1452 
1453  if (backTopRight.X < minX)
1454  minX = backTopRight.X;
1455  if (backTopLeft.X < minX)
1456  minX = backTopLeft.X;
1457  if (backBottomRight.X < minX)
1458  minX = backBottomRight.X;
1459  if (backBottomLeft.X < minX)
1460  minX = backBottomLeft.X;
1461 
1462  //
1463  if (frontTopRight.Y > maxY)
1464  maxY = frontTopRight.Y;
1465  if (frontTopLeft.Y > maxY)
1466  maxY = frontTopLeft.Y;
1467  if (frontBottomRight.Y > maxY)
1468  maxY = frontBottomRight.Y;
1469  if (frontBottomLeft.Y > maxY)
1470  maxY = frontBottomLeft.Y;
1471 
1472  if (backTopRight.Y > maxY)
1473  maxY = backTopRight.Y;
1474  if (backTopLeft.Y > maxY)
1475  maxY = backTopLeft.Y;
1476  if (backBottomRight.Y > maxY)
1477  maxY = backBottomRight.Y;
1478  if (backBottomLeft.Y > maxY)
1479  maxY = backBottomLeft.Y;
1480 
1481  if (frontTopRight.Y < minY)
1482  minY = frontTopRight.Y;
1483  if (frontTopLeft.Y < minY)
1484  minY = frontTopLeft.Y;
1485  if (frontBottomRight.Y < minY)
1486  minY = frontBottomRight.Y;
1487  if (frontBottomLeft.Y < minY)
1488  minY = frontBottomLeft.Y;
1489 
1490  if (backTopRight.Y < minY)
1491  minY = backTopRight.Y;
1492  if (backTopLeft.Y < minY)
1493  minY = backTopLeft.Y;
1494  if (backBottomRight.Y < minY)
1495  minY = backBottomRight.Y;
1496  if (backBottomLeft.Y < minY)
1497  minY = backBottomLeft.Y;
1498 
1499  //
1500  if (frontTopRight.Z > maxZ)
1501  maxZ = frontTopRight.Z;
1502  if (frontTopLeft.Z > maxZ)
1503  maxZ = frontTopLeft.Z;
1504  if (frontBottomRight.Z > maxZ)
1505  maxZ = frontBottomRight.Z;
1506  if (frontBottomLeft.Z > maxZ)
1507  maxZ = frontBottomLeft.Z;
1508 
1509  if (backTopRight.Z > maxZ)
1510  maxZ = backTopRight.Z;
1511  if (backTopLeft.Z > maxZ)
1512  maxZ = backTopLeft.Z;
1513  if (backBottomRight.Z > maxZ)
1514  maxZ = backBottomRight.Z;
1515  if (backBottomLeft.Z > maxZ)
1516  maxZ = backBottomLeft.Z;
1517 
1518  if (frontTopRight.Z < minZ)
1519  minZ = frontTopRight.Z;
1520  if (frontTopLeft.Z < minZ)
1521  minZ = frontTopLeft.Z;
1522  if (frontBottomRight.Z < minZ)
1523  minZ = frontBottomRight.Z;
1524  if (frontBottomLeft.Z < minZ)
1525  minZ = frontBottomLeft.Z;
1526 
1527  if (backTopRight.Z < minZ)
1528  minZ = backTopRight.Z;
1529  if (backTopLeft.Z < minZ)
1530  minZ = backTopLeft.Z;
1531  if (backBottomRight.Z < minZ)
1532  minZ = backBottomRight.Z;
1533  if (backBottomLeft.Z < minZ)
1534  minZ = backBottomLeft.Z;
1535  }
1536  }
1537 
1538  public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
1539  {
1540  float minX;
1541  float maxX;
1542  float minY;
1543  float maxY;
1544  float minZ;
1545  float maxZ;
1546 
1547  GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
1548  Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ);
1549 
1550  offsetHeight = 0;
1551  float lower = (minZ * -1);
1552  if (lower > maxZ)
1553  {
1554  offsetHeight = lower - (boundingBox.Z / 2);
1555 
1556  }
1557  else if (maxZ > lower)
1558  {
1559  offsetHeight = maxZ - (boundingBox.Z / 2);
1560  offsetHeight *= -1;
1561  }
1562 
1563  // m_log.InfoFormat("BoundingBox is {0} , {1} , {2} ", boundingBox.X, boundingBox.Y, boundingBox.Z);
1564  return boundingBox;
1565  }
1566 
1567  #endregion
1568 
1570  out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
1571  {
1572  // this information may need to be cached
1573 
1574  float cost;
1575  float tmpcost;
1576 
1577  bool ComplexCost = false;
1578 
1579  SceneObjectPart p;
1580  SceneObjectPart[] parts;
1581 
1582  lock (m_parts)
1583  {
1584  parts = m_parts.GetArray();
1585  }
1586 
1587  int nparts = parts.Length;
1588 
1589 
1590  for (int i = 0; i < nparts; i++)
1591  {
1592  p = parts[i];
1593 
1594  if (p.UsesComplexCost)
1595  {
1596  ComplexCost = true;
1597  break;
1598  }
1599  }
1600 
1601  if (ComplexCost)
1602  {
1603  linksetResCost = 0;
1604  linksetPhysCost = 0;
1605  partCost = 0;
1606  partPhysCost = 0;
1607 
1608  for (int i = 0; i < nparts; i++)
1609  {
1610  p = parts[i];
1611 
1612  cost = p.StreamingCost;
1613  tmpcost = p.SimulationCost;
1614  if (tmpcost > cost)
1615  cost = tmpcost;
1616  tmpcost = p.PhysicsCost;
1617  if (tmpcost > cost)
1618  cost = tmpcost;
1619 
1620  linksetPhysCost += tmpcost;
1621  linksetResCost += cost;
1622 
1623  if (p == apart)
1624  {
1625  partCost = cost;
1626  partPhysCost = tmpcost;
1627  }
1628  }
1629  }
1630  else
1631  {
1632  partPhysCost = 1.0f;
1633  partCost = 1.0f;
1634  linksetResCost = (float)nparts;
1635  linksetPhysCost = linksetResCost;
1636  }
1637  }
1638 
1639  public void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
1640  {
1641  SceneObjectPart p;
1642  SceneObjectPart[] parts;
1643 
1644  lock (m_parts)
1645  {
1646  parts = m_parts.GetArray();
1647  }
1648 
1649  int nparts = parts.Length;
1650 
1651  PhysCost = 0;
1652  StreamCost = 0;
1653  SimulCost = 0;
1654 
1655  for (int i = 0; i < nparts; i++)
1656  {
1657  p = parts[i];
1658 
1659  StreamCost += p.StreamingCost;
1660  SimulCost += p.SimulationCost;
1661  PhysCost += p.PhysicsCost;
1662  }
1663  }
1664 
1665  public void SaveScriptedState(XmlTextWriter writer)
1666  {
1667  SaveScriptedState(writer, false);
1668  }
1669 
1670  public void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
1671  {
1672  XmlDocument doc = new XmlDocument();
1673  Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1674 
1675  SceneObjectPart[] parts = m_parts.GetArray();
1676  for (int i = 0; i < parts.Length; i++)
1677  {
1678  Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates(oldIDs);
1679  foreach (KeyValuePair<UUID, string> kvp in pstates)
1680  states[kvp.Key] = kvp.Value;
1681  }
1682 
1683  if (states.Count > 0)
1684  {
1685  // Now generate the necessary XML wrappings
1686  writer.WriteStartElement(String.Empty, "GroupScriptStates", String.Empty);
1687  foreach (UUID itemid in states.Keys)
1688  {
1689  doc.LoadXml(states[itemid]);
1690  writer.WriteStartElement(String.Empty, "SavedScriptState", String.Empty);
1691  writer.WriteAttributeString(String.Empty, "UUID", String.Empty, itemid.ToString());
1692  writer.WriteRaw(doc.DocumentElement.OuterXml); // Writes ScriptState element
1693  writer.WriteEndElement(); // End of SavedScriptState
1694  }
1695  writer.WriteEndElement(); // End of GroupScriptStates
1696  }
1697  }
1698 
1705  private void AttachToAgent(
1706  ScenePresence avatar, SceneObjectGroup so, uint attachmentpoint, Vector3 attachOffset, bool silent)
1707  {
1708  if (avatar != null)
1709  {
1710  // don't attach attachments to child agents
1711  if (avatar.IsChildAgent) return;
1712 
1713  // Remove from database and parcel prim count
1714  m_scene.DeleteFromStorage(so.UUID);
1715  m_scene.EventManager.TriggerParcelPrimCountTainted();
1716 
1717  so.AttachedAvatar = avatar.UUID;
1718 
1719  if (so.RootPart.PhysActor != null)
1720  {
1721  m_scene.PhysicsScene.RemovePrim(so.RootPart.PhysActor);
1722  so.RootPart.PhysActor = null;
1723  }
1724 
1725  so.AbsolutePosition = attachOffset;
1726  so.RootPart.AttachedPos = attachOffset;
1727  so.IsAttachment = true;
1728  so.RootPart.SetParentLocalId(avatar.LocalId);
1729  so.AttachmentPoint = attachmentpoint;
1730 
1731  avatar.AddAttachment(this);
1732 
1733  if (!silent)
1734  {
1735  // Killing it here will cause the client to deselect it
1736  // It then reappears on the avatar, deselected
1737  // through the full update below
1738  //
1739  if (IsSelected)
1740  {
1741  m_scene.SendKillObject(new List<uint> { m_rootPart.LocalId });
1742  }
1743 
1744  IsSelected = false; // fudge....
1745  ScheduleGroupForFullUpdate();
1746  }
1747  }
1748  else
1749  {
1750  m_log.WarnFormat(
1751  "[SOG]: Tried to add attachment {0} to avatar with UUID {1} in region {2} but the avatar is not present",
1752  UUID, avatar.ControllingClient.AgentId, Scene.RegionInfo.RegionName);
1753  }
1754  }
1755 
1756  public byte GetAttachmentPoint()
1757  {
1758  return m_rootPart.Shape.State;
1759  }
1760 
1761  public void DetachToGround()
1762  {
1763  ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1764  if (avatar == null)
1765  return;
1766  m_rootPart.Shape.LastAttachPoint = m_rootPart.Shape.State;
1767  m_rootPart.AttachedPos = m_rootPart.OffsetPosition;
1768  avatar.RemoveAttachment(this);
1769 
1770  Vector3 detachedpos = new Vector3(127f,127f,127f);
1771  if (avatar == null)
1772  return;
1773 
1774  detachedpos = avatar.AbsolutePosition;
1775  FromItemID = UUID.Zero;
1776 
1777  AbsolutePosition = detachedpos;
1778  AttachedAvatar = UUID.Zero;
1779 
1780  //SceneObjectPart[] parts = m_parts.GetArray();
1781  //for (int i = 0; i < parts.Length; i++)
1782  // parts[i].AttachedAvatar = UUID.Zero;
1783 
1784  m_rootPart.SetParentLocalId(0);
1785  AttachmentPoint = (byte)0;
1786  // must check if buildind should be true or false here
1787 // m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive,false);
1788  ApplyPhysics();
1789 
1790  HasGroupChanged = true;
1791  RootPart.Rezzed = DateTime.Now;
1792  RootPart.RemFlag(PrimFlags.TemporaryOnRez);
1793  AttachToBackup();
1794  m_scene.EventManager.TriggerParcelPrimCountTainted();
1795  m_rootPart.ScheduleFullUpdate();
1796  m_rootPart.ClearUndoState();
1797  }
1798 
1800  {
1801  ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1802  //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
1803  if (avatar != null)
1804  {
1805  //detachedpos = avatar.AbsolutePosition;
1806  avatar.RemoveAttachment(this);
1807  }
1808 
1809  AttachedAvatar = UUID.Zero;
1810 
1811  /*SceneObjectPart[] parts = m_parts.GetArray();
1812  for (int i = 0; i < parts.Length; i++)
1813  parts[i].AttachedAvatar = UUID.Zero;*/
1814 
1815  m_rootPart.SetParentLocalId(0);
1816  //m_rootPart.SetAttachmentPoint((byte)0);
1817  IsAttachment = false;
1818  AbsolutePosition = m_rootPart.AttachedPos;
1819  //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
1820  //AttachToBackup();
1821  //m_rootPart.ScheduleFullUpdate();
1822  }
1823 
1828  private void SetPartAsNonRoot(SceneObjectPart part)
1829  {
1830  part.ParentID = m_rootPart.LocalId;
1831  part.ClearUndoState();
1832  }
1833 
1834  public ushort GetTimeDilation()
1835  {
1836  return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
1837  }
1838 
1843  public void SetRootPart(SceneObjectPart part)
1844  {
1845  if (part == null)
1846  throw new ArgumentNullException("Cannot give SceneObjectGroup a null root SceneObjectPart");
1847 
1848  part.SetParent(this);
1849  m_rootPart = part;
1850  if (!IsAttachment)
1851  part.ParentID = 0;
1852  part.LinkNum = 0;
1853 
1854  m_parts.Add(m_rootPart.UUID, m_rootPart);
1855  }
1856 
1861  public void AddPart(SceneObjectPart part)
1862  {
1863  part.SetParent(this);
1864  m_parts.Add(part.UUID, part);
1865 
1866  part.LinkNum = m_parts.Count;
1867 
1868  if (part.LinkNum == 2)
1869  RootPart.LinkNum = 1;
1870  }
1871 
1875  private void UpdateParentIDs()
1876  {
1877  SceneObjectPart[] parts = m_parts.GetArray();
1878  for (int i = 0; i < parts.Length; i++)
1879  {
1880  SceneObjectPart part = parts[i];
1881  if (part.UUID != m_rootPart.UUID)
1882  part.ParentID = m_rootPart.LocalId;
1883  }
1884  }
1885 
1886  public void RegenerateFullIDs()
1887  {
1888  SceneObjectPart[] parts = m_parts.GetArray();
1889  for (int i = 0; i < parts.Length; i++)
1890  parts[i].UUID = UUID.Random();
1891  }
1892 
1893  // helper provided for parts.
1894  public int GetSceneMaxUndo()
1895  {
1896  if (m_scene != null)
1897  return m_scene.MaxUndoCount;
1898  return 5;
1899  }
1900 
1901  // justincc: I don't believe this hack is needed any longer, especially since the physics
1902  // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1903  // this method was preventing proper reload of scene objects.
1904 
1905  // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
1906  // at region startup
1907 
1908  // teravus: After this was removed from the linking algorithm, Linked prims no longer collided
1909  // properly when non-physical if they havn't been moved. This breaks ALL builds.
1910  // see: http://opensimulator.org/mantis/view.php?id=3108
1911 
1912  // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
1913  // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
1914  // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute
1915  // Position has been set!
1916 
1918  {
1919  // Setting this SOG's absolute position also loops through and sets the positions
1920  // of the SOP's in this SOG's linkset. This has the side affect of making sure
1921  // the physics world matches the simulated world.
1922  // AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
1923 
1924  // teravus: AbsolutePosition is NOT a normal property!
1925  // the code in the getter of AbsolutePosition is significantly different then the code in the setter!
1926  // jhurliman: Then why is it a property instead of two methods?
1927 
1928  // do only what is supposed to do
1929  Vector3 groupPosition = m_rootPart.GroupPosition;
1930  SceneObjectPart[] parts = m_parts.GetArray();
1931 
1932  foreach (SceneObjectPart part in parts)
1933  {
1934  if (part != m_rootPart)
1935  part.GroupPosition = groupPosition;
1936  }
1937  }
1938 
1939  public UUID GetPartsFullID(uint localID)
1940  {
1941  SceneObjectPart part = GetPart(localID);
1942  if (part != null)
1943  {
1944  return part.UUID;
1945  }
1946  return UUID.Zero;
1947  }
1948 
1949  public void ObjectGrabHandler(uint localId, Vector3 offsetPos, IClientAPI remoteClient)
1950  {
1951  if (m_rootPart.LocalId == localId)
1952  {
1953  OnGrabGroup(offsetPos, remoteClient);
1954  }
1955  else
1956  {
1957  SceneObjectPart part = GetPart(localId);
1958  OnGrabPart(part, offsetPos, remoteClient);
1959  }
1960  }
1961 
1962  public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1963  {
1964 // m_log.DebugFormat(
1965 // "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1966 // remoteClient.Name, part.Name, part.LocalId, offsetPos);
1967 
1968 // part.StoreUndoState();
1969  part.OnGrab(offsetPos, remoteClient);
1970  }
1971 
1972  public virtual void OnGrabGroup(Vector3 offsetPos, IClientAPI remoteClient)
1973  {
1974  m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId);
1975  }
1976 
1986  public void DeleteGroupFromScene(bool silent)
1987  {
1988  // We need to keep track of this state in case this group is still queued for backup.
1989  IsDeleted = true;
1990 
1991  DetachFromBackup();
1992 
1993  SceneObjectPart[] parts = m_parts.GetArray();
1994  for (int i = 0; i < parts.Length; i++)
1995  {
1996  SceneObjectPart part = parts[i];
1997 
1998  if (Scene != null)
1999  {
2000  Scene.ForEachRootScenePresence(delegate(ScenePresence avatar)
2001  {
2002  if (avatar.ParentID == LocalId)
2003  avatar.StandUp();
2004 
2005  if (!silent)
2006  {
2007  part.ClearUpdateSchedule();
2008  if (part == m_rootPart)
2009  {
2010  if (!IsAttachment
2011  || AttachedAvatar == avatar.ControllingClient.AgentId
2012  || !HasPrivateAttachmentPoint)
2013  avatar.ControllingClient.SendKillObject(new List<uint> { part.LocalId });
2014  }
2015  }
2016  });
2017  }
2018  }
2019  }
2020 
2021  public void AddScriptLPS(int count)
2022  {
2023  m_scene.SceneGraph.AddToScriptLPS(count);
2024  }
2025 
2026  public void AddActiveScriptCount(int count)
2027  {
2028  SceneGraph d = m_scene.SceneGraph;
2029  d.AddActiveScripts(count);
2030  }
2031 
2033  {
2034  PrimFlags objectflagupdate = (PrimFlags)RootPart.GetEffectiveObjectFlags();
2035 
2036  scriptEvents aggregateScriptEvents = 0;
2037 
2038  SceneObjectPart[] parts = m_parts.GetArray();
2039  for (int i = 0; i < parts.Length; i++)
2040  {
2041  SceneObjectPart part = parts[i];
2042  if (part == null)
2043  continue;
2044  if (part != RootPart)
2045  part.Flags = objectflagupdate;
2046  aggregateScriptEvents |= part.AggregateScriptEvents;
2047  }
2048 
2049  m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
2050  m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
2051 
2052  if (!m_scriptListens_atTarget && !m_scriptListens_notAtTarget)
2053  {
2054  lock (m_targets)
2055  m_targets.Clear();
2056  m_scene.RemoveGroupTarget(this);
2057  }
2058  m_scriptListens_atRotTarget = ((aggregateScriptEvents & scriptEvents.at_rot_target) != 0);
2059  m_scriptListens_notAtRotTarget = ((aggregateScriptEvents & scriptEvents.not_at_rot_target) != 0);
2060 
2061  if (!m_scriptListens_atRotTarget && !m_scriptListens_notAtRotTarget)
2062  {
2063  lock (m_rotTargets)
2064  m_rotTargets.Clear();
2065  m_scene.RemoveGroupTarget(this);
2066  }
2067 
2068  ScheduleGroupForFullUpdate();
2069  }
2070 
2071  public void SetText(string text, Vector3 color, double alpha)
2072  {
2073  Color = Color.FromArgb(0xff - (int) (alpha * 0xff),
2074  (int) (color.X * 0xff),
2075  (int) (color.Y * 0xff),
2076  (int) (color.Z * 0xff));
2077  Text = text;
2078 
2079  HasGroupChanged = true;
2080  m_rootPart.ScheduleFullUpdate();
2081  }
2082 
2086  public void ApplyPhysics()
2087  {
2088  SceneObjectPart[] parts = m_parts.GetArray();
2089  if (parts.Length > 1)
2090  {
2091  ResetChildPrimPhysicsPositions();
2092 
2093  // Apply physics to the root prim
2094  m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, true);
2095 
2096 
2097  for (int i = 0; i < parts.Length; i++)
2098  {
2099  SceneObjectPart part = parts[i];
2100  if (part.LocalId != m_rootPart.LocalId)
2101  part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, true);
2102  }
2103  // Hack to get the physics scene geometries in the right spot
2104 // ResetChildPrimPhysicsPositions();
2105  if (m_rootPart.PhysActor != null)
2106  {
2107  m_rootPart.PhysActor.Building = false;
2108  }
2109  }
2110  else
2111  {
2112  // Apply physics to the root prim
2113  m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, false);
2114  }
2115  }
2116 
2117  public void SetOwnerId(UUID userId)
2118  {
2119  ForEachPart(delegate(SceneObjectPart part)
2120  {
2121 
2122  part.OwnerID = userId;
2123 
2124  });
2125  }
2126 
2127  public void ForEachPart(Action<SceneObjectPart> whatToDo)
2128  {
2129  SceneObjectPart[] parts = m_parts.GetArray();
2130  for (int i = 0; i < parts.Length; i++)
2131  whatToDo(parts[i]);
2132  }
2133 
2134  #region Events
2135 
2140  public virtual void ProcessBackup(ISimulationDataService datastore, bool forcedBackup)
2141  {
2142  if (!Backup)
2143  {
2144 // m_log.DebugFormat(
2145 // "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID);
2146  return;
2147  }
2148 
2149  if (IsDeleted || inTransit || UUID == UUID.Zero)
2150  {
2151 // m_log.DebugFormat(
2152 // "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID);
2153  return;
2154  }
2155 
2156  if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2157  return;
2158 
2159  // Since this is the top of the section of call stack for backing up a particular scene object, don't let
2160  // any exception propogate upwards.
2161  try
2162  {
2163  if (!m_scene.ShuttingDown || // if shutting down then there will be nothing to handle the return so leave till next restart
2164  !m_scene.LoginsEnabled || // We're starting up or doing maintenance, don't mess with things
2165  m_scene.LoadingPrims) // Land may not be valid yet
2166 
2167  {
2168  ILandObject parcel = m_scene.LandChannel.GetLandObject(
2169  m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
2170 
2171  if (parcel != null && parcel.LandData != null &&
2172  parcel.LandData.OtherCleanTime != 0)
2173  {
2174  if (parcel.LandData.OwnerID != OwnerID &&
2175  (parcel.LandData.GroupID != GroupID ||
2176  parcel.LandData.GroupID == UUID.Zero))
2177  {
2178  if ((DateTime.UtcNow - RootPart.Rezzed).TotalMinutes >
2179  parcel.LandData.OtherCleanTime)
2180  {
2181  DetachFromBackup();
2182  m_log.DebugFormat(
2183  "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn",
2184  RootPart.UUID);
2185  m_scene.AddReturn(OwnerID == GroupID ? LastOwnerID : OwnerID, Name, AbsolutePosition, "parcel autoreturn");
2186  m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero,
2187  DeRezAction.Return, UUID.Zero);
2188 
2189  return;
2190  }
2191  }
2192  }
2193 
2194  }
2195 
2196  if (m_scene.UseBackup && HasGroupChanged)
2197  {
2198  // don't backup while it's selected or you're asking for changes mid stream.
2199  if (isTimeToPersist() || forcedBackup)
2200  {
2201  if (m_rootPart.PhysActor != null &&
2202  (!m_rootPart.PhysActor.IsPhysical))
2203  {
2204  // Possible ghost prim
2205  if (m_rootPart.PhysActor.Position != m_rootPart.GroupPosition)
2206  {
2207  foreach (SceneObjectPart part in m_parts.GetArray())
2208  {
2209  // Re-set physics actor positions and
2210  // orientations
2211  part.GroupPosition = m_rootPart.GroupPosition;
2212  }
2213  }
2214  }
2215 // m_log.DebugFormat(
2216 // "[SCENE]: Storing {0}, {1} in {2}",
2217 // Name, UUID, m_scene.RegionInfo.RegionName);
2218 
2219  if (RootPart.Shape.PCode == 9 && RootPart.Shape.State != 0)
2220  {
2221  RootPart.Shape.LastAttachPoint = RootPart.Shape.State;
2222  RootPart.Shape.State = 0;
2223  ScheduleGroupForFullUpdate();
2224  }
2225 
2226  SceneObjectGroup backup_group = Copy(false);
2227  backup_group.RootPart.Velocity = RootPart.Velocity;
2228  backup_group.RootPart.Acceleration = RootPart.Acceleration;
2229  backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity;
2230  backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem;
2231  HasGroupChanged = false;
2232  GroupContainsForeignPrims = false;
2233 
2234  m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
2235 
2236  datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
2237 
2238  backup_group.ForEachPart(delegate(SceneObjectPart part)
2239  {
2240  part.Inventory.ProcessInventoryBackup(datastore);
2241 
2242  if(part.KeyframeMotion != null)
2243  {
2244  part.KeyframeMotion.Delete();
2245  part.KeyframeMotion = null;
2246  }
2247  });
2248 
2249  backup_group.Clear();
2250  backup_group = null;
2251  }
2252 // else
2253 // {
2254 // m_log.DebugFormat(
2255 // "[SCENE]: Did not update persistence of object {0} {1}, selected = {2}",
2256 // Name, UUID, IsSelected);
2257 // }
2258  }
2259  }
2260  catch (Exception e)
2261  {
2262  m_log.ErrorFormat(
2263  "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}",
2264  Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace);
2265  }
2266  }
2267 
2268  #endregion
2269 
2277  public void SendFullUpdateToClient(IClientAPI remoteClient)
2278  {
2279  RootPart.SendFullUpdate(remoteClient);
2280 
2281  SceneObjectPart[] parts = m_parts.GetArray();
2282  for (int i = 0; i < parts.Length; i++)
2283  {
2284  SceneObjectPart part = parts[i];
2285  if (part != RootPart)
2286  part.SendFullUpdate(remoteClient);
2287  }
2288  }
2289 
2290  #region Copying
2291 
2297  public SceneObjectGroup Copy(bool userExposed)
2298  {
2299  m_dupeInProgress = true;
2300  SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
2301 
2302  dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
2303 
2304  // a copy isnt backedup
2305  dupe.Backup = false;
2306 
2307  // a copy is not in transit hopefully
2308  dupe.inTransit = false;
2309 
2310  // new group as no sitting avatars
2311  dupe.m_sittingAvatars = new List<ScenePresence>();
2312 
2313  dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
2314  dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
2315 
2316 
2317  if (userExposed)
2318  dupe.m_rootPart.TrimPermissions();
2319 
2320  List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
2321 
2322  partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
2323  {
2324  return p1.LinkNum.CompareTo(p2.LinkNum);
2325  }
2326  );
2327 
2328  foreach (SceneObjectPart part in partList)
2329  {
2330  SceneObjectPart newPart;
2331  if (part.UUID != m_rootPart.UUID)
2332  {
2333  newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
2334  newPart.LinkNum = part.LinkNum;
2335 // if (userExposed)
2336  newPart.ParentID = dupe.m_rootPart.LocalId;
2337  }
2338  else
2339  {
2340  newPart = dupe.m_rootPart;
2341  }
2342 /*
2343  bool isphys = ((newPart.Flags & PrimFlags.Physics) != 0);
2344  bool isphan = ((newPart.Flags & PrimFlags.Phantom) != 0);
2345 
2346  // Need to duplicate the physics actor as well
2347  if (userExposed && (isphys || !isphan || newPart.VolumeDetectActive))
2348  {
2349  PrimitiveBaseShape pbs = newPart.Shape;
2350  newPart.PhysActor
2351  = m_scene.PhysicsScene.AddPrimShape(
2352  string.Format("{0}/{1}", newPart.Name, newPart.UUID),
2353  pbs,
2354  newPart.AbsolutePosition,
2355  newPart.Scale,
2356  newPart.GetWorldRotation(),
2357  isphys,
2358  isphan,
2359  newPart.LocalId);
2360 
2361  newPart.DoPhysicsPropertyUpdate(isphys, true);
2362  */
2363  if (userExposed)
2364  newPart.ApplyPhysics((uint)newPart.Flags,newPart.VolumeDetectActive,true);
2365 // }
2366  // copy keyframemotion
2367  if (part.KeyframeMotion != null)
2368  newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
2369  }
2370 
2371  if (userExposed)
2372  {
2373 // done above dupe.UpdateParentIDs();
2374 
2375  if (dupe.m_rootPart.PhysActor != null)
2376  dupe.m_rootPart.PhysActor.Building = false; // tell physics to finish building
2377 
2378  dupe.HasGroupChanged = true;
2379  dupe.AttachToBackup();
2380 
2381  ScheduleGroupForFullUpdate();
2382  }
2383 
2384  m_dupeInProgress = false;
2385  return dupe;
2386  }
2387 
2394  public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
2395  {
2396  SceneObjectPart newpart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed);
2397 // SceneObjectPart newpart = part.Copy(part.LocalId, OwnerID, GroupID, 0, userExposed);
2398 // newpart.LocalId = m_scene.AllocateLocalId();
2399 
2400  SetRootPart(newpart);
2401  if (userExposed)
2402  RootPart.Velocity = Vector3.Zero; // In case source is moving
2403  }
2404 
2405  public void ScriptSetPhysicsStatus(bool usePhysics)
2406  {
2407  if (usePhysics)
2408  {
2409  if (RootPart.KeyframeMotion != null)
2410  RootPart.KeyframeMotion.Stop();
2411  RootPart.KeyframeMotion = null;
2412  }
2413  UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2414  }
2415 
2416  public void ScriptSetTemporaryStatus(bool makeTemporary)
2417  {
2418  UpdatePrimFlags(RootPart.LocalId, UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect);
2419  }
2420 
2421  public void ScriptSetPhantomStatus(bool makePhantom)
2422  {
2423  UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect);
2424  }
2425 
2426  public void ScriptSetVolumeDetect(bool makeVolumeDetect)
2427  {
2428  UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect);
2429 
2430  /*
2431  ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore
2432 
2433  if (PhysActor != null) // Should always be the case now
2434  {
2435  PhysActor.SetVolumeDetect(param);
2436  }
2437  if (param != 0)
2438  AddFlag(PrimFlags.Phantom);
2439 
2440  ScheduleFullUpdate();
2441  */
2442  }
2443 
2444  public void applyImpulse(Vector3 impulse)
2445  {
2446  if (IsAttachment)
2447  {
2448  ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
2449  if (avatar != null)
2450  {
2451  avatar.PushForce(impulse);
2452  }
2453  }
2454  else
2455  {
2456  PhysicsActor pa = RootPart.PhysActor;
2457 
2458  if (pa != null)
2459  {
2460  // false to be applied as a impulse
2461  pa.AddForce(impulse, false);
2462  m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2463  }
2464  }
2465  }
2466 
2467  public void ApplyAngularImpulse(Vector3 impulse)
2468  {
2469  PhysicsActor pa = RootPart.PhysActor;
2470 
2471  if (pa != null)
2472  {
2473  if (!IsAttachment)
2474  {
2475  // false to be applied as a impulse
2476  pa.AddAngularForce(impulse, false);
2477  m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2478  }
2479  }
2480  }
2481 
2482  public Vector3 GetTorque()
2483  {
2484  return RootPart.Torque;
2485  }
2486 
2487  // This is used by both Double-Click Auto-Pilot and llMoveToTarget() in an attached object
2488  public void MoveToTarget(Vector3 target, float tau)
2489  {
2490  if (IsAttachment)
2491  {
2492  ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
2493 
2494  if (avatar != null)
2495  avatar.MoveToTarget(target, false, false);
2496  }
2497  else
2498  {
2499  PhysicsActor pa = RootPart.PhysActor;
2500 
2501  if (pa != null)
2502  {
2503  pa.PIDTarget = target;
2504  pa.PIDTau = tau;
2505  pa.PIDActive = true;
2506  }
2507  }
2508  }
2509 
2510  public void StopMoveToTarget()
2511  {
2512  if (IsAttachment)
2513  {
2514  ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
2515 
2516  if (avatar != null)
2517  {
2518  avatar.ResetMoveToTarget();
2519  }
2520  }
2521  else
2522  {
2523  PhysicsActor pa = RootPart.PhysActor;
2524 
2525  if (pa != null)
2526  pa.PIDActive = false;
2527 
2528  RootPart.ScheduleTerseUpdate(); // send a stop information
2529  }
2530  }
2531 
2532  public void RotLookAt(Quaternion target, float strength, float damping)
2533  {
2534  if(IsDeleted)
2535  return;
2536 
2537  // non physical is handle in LSL api
2538  if(!UsesPhysics || IsAttachment)
2539  return;
2540 
2541  SceneObjectPart rootpart = m_rootPart;
2542  if (rootpart != null)
2543  {
2544 /* physics still doesnt suport this
2545  if (rootpart.PhysActor != null)
2546  {
2547  rootpart.PhysActor.APIDTarget = new Quaternion(target.X, target.Y, target.Z, target.W);
2548  rootpart.PhysActor.APIDStrength = strength;
2549  rootpart.PhysActor.APIDDamping = damping;
2550  rootpart.PhysActor.APIDActive = true;
2551  }
2552 */
2553  // so do it in rootpart
2554  rootpart.RotLookAt(target, strength, damping);
2555  }
2556  }
2557 
2558  public void StartLookAt(Quaternion target, float strength, float damping)
2559  {
2560  if(IsDeleted)
2561  return;
2562 
2563  // non physical is done by LSL APi
2564  if(!UsesPhysics || IsAttachment)
2565  return;
2566 
2567  if (m_rootPart != null)
2568  m_rootPart.RotLookAt(target, strength, damping);
2569  }
2570 
2571  public void StopLookAt()
2572  {
2573  SceneObjectPart rootpart = m_rootPart;
2574  if (rootpart != null)
2575  {
2576  if (rootpart.PhysActor != null)
2577  {
2578  rootpart.PhysActor.APIDActive = false;
2579  }
2580 
2581  rootpart.StopLookAt();
2582  }
2583  }
2590  public void SetHoverHeight(float height, PIDHoverType hoverType, float tau)
2591  {
2592  PhysicsActor pa = null;
2593  if(IsAttachment)
2594  {
2595  ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
2596  if (avatar != null)
2597  pa = avatar.PhysicsActor;
2598  }
2599  else
2600  pa = RootPart.PhysActor;
2601 
2602  if (pa != null)
2603  {
2604  if (height != 0f)
2605  {
2606  pa.PIDHoverHeight = height;
2607  pa.PIDHoverType = hoverType;
2608  pa.PIDHoverTau = tau;
2609  pa.PIDHoverActive = true;
2610  }
2611  else
2612  {
2613  pa.PIDHoverActive = false;
2614  }
2615  }
2616  }
2617 
2624  public void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
2625  {
2626  part.LastOwnerID = part.OwnerID;
2627  part.OwnerID = cAgentID;
2628  part.GroupID = cGroupID;
2629 
2630  if (part.OwnerID != cAgentID)
2631  {
2632  // Apply Next Owner Permissions if we're not bypassing permissions
2633  if (!m_scene.Permissions.BypassPermissions())
2634  ApplyNextOwnerPermissions();
2635  }
2636 
2637  part.ScheduleFullUpdate();
2638  }
2639 
2646  public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
2647  {
2648  SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
2649 // SceneObjectPart newPart = part.Copy(part.LocalId, OwnerID, GroupID, m_parts.Count, userExposed);
2650 // newPart.LocalId = m_scene.AllocateLocalId();
2651 
2652  AddPart(newPart);
2653 
2654  SetPartAsNonRoot(newPart);
2655  return newPart;
2656  }
2657 
2665  public void ResetIDs()
2666  {
2667  lock (m_parts.SyncRoot)
2668  {
2669  List<SceneObjectPart> partsList = new List<SceneObjectPart>(m_parts.GetArray());
2670  m_parts.Clear();
2671  foreach (SceneObjectPart part in partsList)
2672  {
2673  part.ResetIDs(part.LinkNum); // Don't change link nums
2674  m_parts.Add(part.UUID, part);
2675  }
2676  }
2677  }
2678 
2683  public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
2684  {
2685  remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags);
2686 
2687 // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
2688 // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
2689 // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
2690 // RootPart.CreatorID, RootPart.Name, RootPart.Description);
2691  }
2692 
2693  public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
2694  {
2695  part.OwnerID = cAgentID;
2696  part.GroupID = cGroupID;
2697  }
2698 
2699  #endregion
2700 
2701 
2702  public override void Update()
2703  {
2704  // Check that the group was not deleted before the scheduled update
2705  // FIXME: This is merely a temporary measure to reduce the incidence of failure when
2706  // an object has been deleted from a scene before update was processed.
2707  // A more fundamental overhaul of the update mechanism is required to eliminate all
2708  // the race conditions.
2709  if (IsDeleted || inTransit)
2710  return;
2711 
2712  // Even temporary objects take part in physics (e.g. temp-on-rez bullets)
2713  //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2714  // return;
2715 
2716  // If we somehow got here to updating the SOG and its root part is not scheduled for update,
2717  // check to see if the physical position or rotation warrant an update.
2718  if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
2719  {
2720  // rootpart SendScheduledUpdates will check if a update is needed
2721  m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2722  }
2723 
2724  if (IsAttachment)
2725  {
2726  ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
2727  if (sp != null)
2728  {
2729  sp.SendAttachmentScheduleUpdate(this);
2730  return;
2731  }
2732  }
2733 
2734  // while physics doesn't suports LookAt, we do it in RootPart
2735  if (!IsSelected)
2736  RootPart.UpdateLookAt();
2737 
2738  SceneObjectPart[] parts = m_parts.GetArray();
2739  for (int i = 0; i < parts.Length; i++)
2740  {
2741  SceneObjectPart part = parts[i];
2742  part.SendScheduledUpdates();
2743  }
2744  }
2745 
2755  {
2756 // if (IsAttachment)
2757 // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId);
2758 
2759  checkAtTargets();
2760  RootPart.ScheduleFullUpdate();
2761 
2762  SceneObjectPart[] parts = m_parts.GetArray();
2763  for (int i = 0; i < parts.Length; i++)
2764  {
2765  SceneObjectPart part = parts[i];
2766  if (part != RootPart)
2767  part.ScheduleFullUpdate();
2768  }
2769  }
2770 
2780  {
2781 // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID);
2782 
2783  SceneObjectPart[] parts = m_parts.GetArray();
2784  for (int i = 0; i < parts.Length; i++)
2785  parts[i].ScheduleTerseUpdate();
2786  }
2787 
2791  public void SendGroupFullUpdate()
2792  {
2793  if (IsDeleted)
2794  return;
2795 
2796 // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2797 
2798  if (IsAttachment)
2799  {
2800  ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
2801  if (sp != null)
2802  {
2803  sp.SendAttachmentUpdate(this,UpdateRequired.FULL);
2804  return;
2805  }
2806  }
2807 
2808  RootPart.SendFullUpdateToAllClientsInternal();
2809 
2810  SceneObjectPart[] parts = m_parts.GetArray();
2811  for (int i = 0; i < parts.Length; i++)
2812  {
2813  SceneObjectPart part = parts[i];
2814  if (part != RootPart)
2815  part.SendFullUpdateToAllClientsInternal();
2816  }
2817  }
2818 
2826  {
2827  if (IsDeleted || inTransit)
2828  return;
2829 
2830  RootPart.SendTerseUpdateToAllClients();
2831  }
2832 
2833  public void QueueForUpdateCheck()
2834  {
2835  if (m_scene == null) // Need to check here as it's null during object creation
2836  return;
2837 
2838  m_scene.SceneGraph.AddToUpdateList(this);
2839  }
2840 
2844  public void SendGroupTerseUpdate()
2845  {
2846  if (IsDeleted || inTransit)
2847  return;
2848 
2849  if (IsAttachment)
2850  {
2851  ScenePresence sp = m_scene.GetScenePresence(AttachedAvatar);
2852  if (sp != null)
2853  {
2854  sp.SendAttachmentUpdate(this, UpdateRequired.TERSE);
2855  return;
2856  }
2857  }
2858 
2859  SceneObjectPart[] parts = m_parts.GetArray();
2860  for (int i = 0; i < parts.Length; i++)
2861  parts[i].SendTerseUpdateToAllClientsInternal();
2862  }
2863 
2869  {
2870  m_rootPart.SendPropertiesToClient(client);
2871  }
2872 
2873  #region SceneGroupPart Methods
2874 
2880  public SceneObjectPart GetLinkNumPart(int linknum)
2881  {
2882  SceneObjectPart[] parts = m_parts.GetArray();
2883  for (int i = 0; i < parts.Length; i++)
2884  {
2885  if (parts[i].LinkNum == linknum)
2886  return parts[i];
2887  }
2888 
2889  return null;
2890  }
2891 
2897  public SceneObjectPart GetPart(UUID primID)
2898  {
2899  SceneObjectPart childPart;
2900  m_parts.TryGetValue(primID, out childPart);
2901  return childPart;
2902  }
2903 
2909  public SceneObjectPart GetPart(uint localID)
2910  {
2911  SceneObjectPart[] parts = m_parts.GetArray();
2912  for (int i = 0; i < parts.Length; i++)
2913  {
2914  if (parts[i].LocalId == localID)
2915  return parts[i];
2916  }
2917 
2918  return null;
2919  }
2920 
2921  #endregion
2922 
2923  #region Packet Handlers
2924 
2933  public void LinkToGroup(SceneObjectGroup objectGroup)
2934  {
2935  LinkToGroup(objectGroup, false);
2936  }
2937 
2938  // Link an existing group to this group.
2939  // The group being linked need not be a linkset -- it can have just one prim.
2940  public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2941  {
2942 // m_log.DebugFormat(
2943 // "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
2944 // objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
2945 
2946  // Linking to ourselves is not a valid operation.
2947  if (objectGroup == this)
2948  return;
2949 
2950  // If the configured linkset capacity is greater than zero,
2951  // and the new linkset would have a prim count higher than this
2952  // value, do not link it.
2953  if (m_scene.m_linksetCapacity > 0 &&
2954  (PrimCount + objectGroup.PrimCount) >
2955  m_scene.m_linksetCapacity)
2956  {
2957  m_log.DebugFormat(
2958  "[SCENE OBJECT GROUP]: Cannot link group with root" +
2959  " part {0}, {1} ({2} prims) to group with root part" +
2960  " {3}, {4} ({5} prims) because the new linkset" +
2961  " would exceed the configured maximum of {6}",
2962  objectGroup.RootPart.Name, objectGroup.RootPart.UUID,
2963  objectGroup.PrimCount, RootPart.Name, RootPart.UUID,
2964  PrimCount, m_scene.m_linksetCapacity);
2965 
2966  return;
2967  }
2968 
2969  // physical prims count limit
2970  // not very eficient :(
2971 
2972  if (UsesPhysics && m_scene.m_linksetPhysCapacity > 0 && (PrimCount + objectGroup.PrimCount) >
2973  m_scene.m_linksetPhysCapacity)
2974  {
2975  int cntr = 0;
2976  foreach (SceneObjectPart part in Parts)
2977  {
2978  if (part.PhysicsShapeType != (byte)PhysicsShapeType.None)
2979  cntr++;
2980  }
2981  foreach (SceneObjectPart part in objectGroup.Parts)
2982  {
2983  if (part.PhysicsShapeType != (byte)PhysicsShapeType.None)
2984  cntr++;
2985  }
2986 
2987  if (cntr > m_scene.m_linksetPhysCapacity)
2988  {
2989  // cancel physics
2990  RootPart.Flags &= ~PrimFlags.Physics;
2991  ApplyPhysics();
2992  }
2993  }
2994 
2995 
2996  // 'linkPart' == the root of the group being linked into this group
2997  SceneObjectPart linkPart = objectGroup.m_rootPart;
2998 
2999  if (m_rootPart.PhysActor != null)
3000  m_rootPart.PhysActor.Building = true;
3001  if (linkPart.PhysActor != null)
3002  linkPart.PhysActor.Building = true;
3003 
3004  // physics flags from group to be applied to linked parts
3005  bool grpusephys = UsesPhysics;
3006  bool grptemporary = IsTemporary;
3007 
3008  // Remember where the group being linked thought it was
3009  Vector3 oldGroupPosition = linkPart.GroupPosition;
3010  Quaternion oldRootRotation = linkPart.RotationOffset;
3011 
3012  // A linked SOP remembers its location and rotation relative to the root of a group.
3013  // Convert the root of the group being linked to be relative to the
3014  // root of the group being linked to.
3015  // Note: Some of the assignments have complex side effects.
3016 
3017  // First move the new group's root SOP's position to be relative to ours
3018  // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not,
3019  // this code can be reordered to have a more logical flow.)
3020  linkPart.setOffsetPosition(linkPart.GroupPosition - AbsolutePosition);
3021  // Assign the new parent to the root of the old group
3022  linkPart.ParentID = m_rootPart.LocalId;
3023  // Now that it's a child, it's group position is our root position
3024  linkPart.setGroupPosition(AbsolutePosition);
3025 
3026  // Rotate the linking root SOP's position to be relative to the new root prim
3027  Quaternion parentRot = m_rootPart.RotationOffset;
3028 
3029  // Make the linking root SOP's rotation relative to the new root prim
3030  Quaternion oldRot = linkPart.RotationOffset;
3031  Quaternion newRot = Quaternion.Conjugate(parentRot) * oldRot;
3032  linkPart.setRotationOffset(newRot);
3033 
3034  Vector3 axPos = linkPart.OffsetPosition;
3035  axPos *= Quaternion.Conjugate(parentRot);
3036  linkPart.OffsetPosition = axPos;
3037 
3038 
3039  // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
3040  // Now that we know this SOG has at least two SOPs in it, the new root
3041  // SOP becomes the first in the linkset.
3042  if (m_rootPart.LinkNum == 0)
3043  m_rootPart.LinkNum = 1;
3044 
3045  lock (m_parts.SyncRoot)
3046  {
3047  // Calculate the new link number for the old root SOP
3048  int linkNum;
3049  if (insert)
3050  {
3051  linkNum = 2;
3052  foreach (SceneObjectPart part in Parts)
3053  {
3054  if (part.LinkNum > 1)
3055  part.LinkNum++;
3056  }
3057  }
3058  else
3059  {
3060  linkNum = PrimCount + 1;
3061  }
3062 
3063  // Add the old root SOP as a part in our group's list
3064  m_parts.Add(linkPart.UUID, linkPart);
3065 
3066  linkPart.SetParent(this);
3067  m_scene.updateScenePartGroup(linkPart, this);
3068 
3069  linkPart.CreateSelected = true;
3070 
3071  // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
3072  linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive, true);
3073 
3074  // If the added SOP is physical, also tell the physics engine about the link relationship.
3075  if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
3076  {
3077  linkPart.PhysActor.link(m_rootPart.PhysActor);
3078  this.Scene.PhysicsScene.AddPhysicsActorTaint(linkPart.PhysActor);
3079  }
3080 
3081  linkPart.LinkNum = linkNum++;
3082  linkPart.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
3083 
3084  // Get a list of the SOP's in the old group in order of their linknum's.
3085  SceneObjectPart[] ogParts = objectGroup.Parts;
3086  Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
3087  {
3088  return a.LinkNum - b.LinkNum;
3089  });
3090 
3091  // Add each of the SOP's from the old linkset to our linkset
3092  for (int i = 0; i < ogParts.Length; i++)
3093  {
3094  SceneObjectPart part = ogParts[i];
3095  if (part.UUID != objectGroup.m_rootPart.UUID)
3096  {
3097  LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
3098 
3099  // Update the physics flags for the newly added SOP
3100  // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
3101  part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive, true);
3102 
3103  // If the added SOP is physical, also tell the physics engine about the link relationship.
3104  if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
3105  {
3106  part.PhysActor.link(m_rootPart.PhysActor);
3107  this.Scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
3108  }
3109  }
3110  part.ClearUndoState();
3111  }
3112  }
3113 
3114  // Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene.
3115  m_scene.UnlinkSceneObject(objectGroup, true);
3116  objectGroup.IsDeleted = true;
3117 
3118  objectGroup.m_parts.Clear();
3119 
3120  // Can't do this yet since backup still makes use of the root part without any synchronization
3121 // objectGroup.m_rootPart = null;
3122 
3123  // If linking prims with different permissions, fix them
3124  AdjustChildPrimPermissions(false);
3125 
3126  GroupContainsForeignPrims = true;
3127 
3128  AttachToBackup();
3129 
3130  // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
3131  // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
3132  // unmoved prims!
3133  ResetChildPrimPhysicsPositions();
3134 
3135  if (m_rootPart.PhysActor != null)
3136  m_rootPart.PhysActor.Building = false;
3137 
3138  //HasGroupChanged = true;
3139  //ScheduleGroupForFullUpdate();
3140  }
3141 
3153  public SceneObjectGroup DelinkFromGroup(uint partID)
3154  {
3155  return DelinkFromGroup(partID, true);
3156  }
3157 
3170  public SceneObjectGroup DelinkFromGroup(uint partID, bool sendEvents)
3171  {
3172  SceneObjectPart linkPart = GetPart(partID);
3173 
3174  if (linkPart != null)
3175  {
3176  return DelinkFromGroup(linkPart, sendEvents);
3177  }
3178  else
3179  {
3180  m_log.WarnFormat("[SCENE OBJECT GROUP]: " +
3181  "DelinkFromGroup(): Child prim {0} not found in object {1}, {2}",
3182  partID, LocalId, UUID);
3183 
3184  return null;
3185  }
3186  }
3187 
3200  public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents)
3201  {
3202 // m_log.DebugFormat(
3203 // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
3204 // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
3205 
3206  if (m_rootPart.PhysActor != null)
3207  m_rootPart.PhysActor.Building = true;
3208 
3209  linkPart.ClearUndoState();
3210 
3211  Vector3 worldPos = linkPart.GetWorldPosition();
3212  Quaternion worldRot = linkPart.GetWorldRotation();
3213 
3214  // Remove the part from this object
3215  lock (m_parts.SyncRoot)
3216  {
3217  m_parts.Remove(linkPart.UUID);
3218 
3219  SceneObjectPart[] parts = m_parts.GetArray();
3220 
3221  // Rejigger the linknum's of the remaining SOP's to fill any gap
3222  if (parts.Length == 1 && RootPart != null)
3223  {
3224  // Single prim left
3225  RootPart.LinkNum = 0;
3226  }
3227  else
3228  {
3229  for (int i = 0; i < parts.Length; i++)
3230  {
3231  SceneObjectPart part = parts[i];
3232  if (part.LinkNum > linkPart.LinkNum)
3233  part.LinkNum--;
3234  }
3235  }
3236  }
3237 
3238  linkPart.ParentID = 0;
3239  linkPart.LinkNum = 0;
3240 
3241  PhysicsActor linkPartPa = linkPart.PhysActor;
3242 
3243  // Remove the SOP from the physical scene.
3244  // If the new SOG is physical, it is re-created later.
3245  // (There is a problem here in that we have not yet told the physics
3246  // engine about the delink. Someday, linksets should be made first
3247  // class objects in the physics engine interface).
3248  if (linkPartPa != null)
3249  m_scene.PhysicsScene.RemovePrim(linkPartPa);
3250 
3251  // We need to reset the child part's position
3252  // ready for life as a separate object after being a part of another object
3253 
3254  /* This commented out code seems to recompute what GetWorldPosition already does.
3255  * Replace with a call to GetWorldPosition (before unlinking)
3256  Quaternion parentRot = m_rootPart.RotationOffset;
3257  Vector3 axPos = linkPart.OffsetPosition;
3258  axPos *= parentRot;
3259  linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
3260  linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
3261  linkPart.OffsetPosition = new Vector3(0, 0, 0);
3262  */
3263  linkPart.setGroupPosition(worldPos);
3264  linkPart.setOffsetPosition(Vector3.Zero);
3265  linkPart.setRotationOffset(worldRot);
3266 
3267  // Create a new SOG to go around this unlinked and unattached SOP
3269 
3270  m_scene.AddNewSceneObject(objectGroup, true);
3271 
3272  linkPart.Rezzed = RootPart.Rezzed;
3273 
3274  // When we delete a group, we currently have to force persist to the database if the object id has changed
3275  // (since delete works by deleting all rows which have a given object id)
3276 
3277  // this is as it seems to be in sl now
3278  if(linkPart.PhysicsShapeType == (byte)PhysShapeType.none)
3279  linkPart.PhysicsShapeType = linkPart.DefaultPhysicsShapeType(); // root prims can't have type none for now
3280 
3281  if (m_rootPart.PhysActor != null)
3282  m_rootPart.PhysActor.Building = false;
3283 
3284  objectGroup.HasGroupChangedDueToDelink = true;
3285 
3286  if (sendEvents)
3287  linkPart.TriggerScriptChangedEvent(Changed.LINK);
3288 
3289  return objectGroup;
3290  }
3291 
3296  public virtual void DetachFromBackup()
3297  {
3298  if (m_scene != null)
3299  m_scene.SceneGraph.FireDetachFromBackup(this);
3300  if (Backup && Scene != null)
3301  m_scene.EventManager.OnBackup -= ProcessBackup;
3302 
3303  Backup = false;
3304  }
3305 
3306  // This links an SOP from a previous linkset into my linkset.
3307  // The trick is that the SOP's position and rotation are relative to the old root SOP's
3308  // so we are passed in the position and rotation of the old linkset so this can
3309  // unjigger this SOP's position and rotation from the previous linkset and
3310  // then make them relative to my linkset root.
3311  private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum)
3312  {
3313  Quaternion parentRot = oldGroupRotation;
3314  Quaternion oldRot = part.RotationOffset;
3315 
3316  // Move our position in world
3317  Vector3 axPos = part.OffsetPosition;
3318  axPos *= parentRot;
3319  Vector3 newPos = oldGroupPosition + axPos;
3320  part.setGroupPosition(newPos);
3321  part.setOffsetPosition(Vector3.Zero);
3322 
3323  // Compution our rotation in world
3324  Quaternion worldRot = parentRot * oldRot;
3325  part.RotationOffset = worldRot;
3326 
3327  // Add this SOP to our linkset
3328  part.SetParent(this);
3329  part.ParentID = m_rootPart.LocalId;
3330  m_parts.Add(part.UUID, part);
3331 
3332  part.LinkNum = linkNum;
3333 
3334  m_scene.updateScenePartGroup(part, this);
3335 
3336  // Compute the new position of this SOP relative to the group position
3337  part.setOffsetPosition(newPos - AbsolutePosition);
3338 
3339  // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
3340  // It would have the affect of setting the physics engine position multiple
3341  // times. In theory, that is not necessary but I don't have a good linkset
3342  // test to know that cleaning up this code wouldn't break things.)
3343 
3344  // Compute the SOP's rotation relative to the rotation of the group.
3345  parentRot = m_rootPart.RotationOffset;
3346 
3347  oldRot = part.RotationOffset;
3348  Quaternion newRot = Quaternion.Conjugate(parentRot) * worldRot;
3349  part.setRotationOffset(newRot);
3350 
3351  Vector3 pos = part.OffsetPosition;
3352  pos *= Quaternion.Conjugate(parentRot);
3353 
3354  part.OffsetPosition = pos; // update position and orientation on physics also
3355 
3356  // Since this SOP's state has changed, push those changes into the physics engine
3357  // and the simulator.
3358  // done on caller
3359 // part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect, false);
3360  }
3361 
3370  public void GrabMovement(UUID partID, Vector3 offset, Vector3 pos, IClientAPI remoteClient)
3371  {
3372  if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
3373  {
3374  SceneObjectPart part = GetPart(partID);
3375 
3376  if (part == null)
3377  return;
3378 
3379  PhysicsActor pa = m_rootPart.PhysActor;
3380 
3381  if (pa != null)
3382  {
3383  if (pa.IsPhysical)
3384  {
3385  if (!BlockGrabOverride && !part.BlockGrab)
3386  {
3387 /* Vector3 llmoveforce = pos - AbsolutePosition;
3388  Vector3 grabforce = llmoveforce;
3389  grabforce = (grabforce / 10) * pa.Mass;
3390  */
3391  // empirically convert distance diference to a impulse
3392  Vector3 grabforce = pos - AbsolutePosition;
3393  grabforce = grabforce * (pa.Mass/ 10.0f);
3394  pa.AddForce(grabforce, false);
3395  m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
3396  }
3397  }
3398  else
3399  {
3400  NonPhysicalGrabMovement(pos);
3401  }
3402  }
3403  else
3404  {
3405  NonPhysicalGrabMovement(pos);
3406  }
3407  }
3408  }
3409 
3417  public void NonPhysicalGrabMovement(Vector3 pos)
3418  {
3419  if(!IsAttachment && ScriptCount() == 0)
3420  UpdateGroupPosition(pos);
3421  }
3422 
3428  public void SpinStart(IClientAPI remoteClient)
3429  {
3430  if (m_scene.EventManager.TriggerGroupSpinStart(UUID))
3431  {
3432  PhysicsActor pa = m_rootPart.PhysActor;
3433 
3434  if (pa != null)
3435  {
3436  if (pa.IsPhysical)
3437  {
3438  m_rootPart.IsWaitingForFirstSpinUpdatePacket = true;
3439  }
3440  }
3441  }
3442  }
3443 
3449  public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient)
3450  {
3451  // The incoming newOrientation, sent by the client, "seems" to be the
3452  // desired target orientation. This needs further verification; in particular,
3453  // one would expect that the initial incoming newOrientation should be
3454  // fairly close to the original prim's physical orientation,
3455  // m_rootPart.PhysActor.Orientation. This however does not seem to be the
3456  // case (might just be an issue with different quaternions representing the
3457  // same rotation, or it might be a coordinate system issue).
3458  //
3459  // Since it's not clear what the relationship is between the PhysActor.Orientation
3460  // and the incoming orientations sent by the client, we take an alternative approach
3461  // of calculating the delta rotation between the orientations being sent by the
3462  // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect
3463  // a steady stream of several new orientations coming in from the client.)
3464  // This ensures that the delta rotations are being calculated from self-consistent
3465  // pairs of old/new rotations. Given the delta rotation, we apply a torque around
3466  // the delta rotation axis, scaled by the object mass times an arbitrary scaling
3467  // factor (to ensure the resulting torque is not "too strong" or "too weak").
3468  //
3469  // Ideally we need to calculate (probably iteratively) the exact torque or series
3470  // of torques needed to arrive exactly at the destination orientation. However, since
3471  // it is not yet clear how to map the destination orientation (provided by the viewer)
3472  // into PhysActor orientations (needed by the physics engine), we omit this step.
3473  // This means that the resulting torque will at least be in the correct direction,
3474  // but it will result in over-shoot or under-shoot of the target orientation.
3475  // For the end user, this means that ctrl+shift+drag can be used for relative,
3476  // but not absolute, adjustments of orientation for physical prims.
3477  if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation))
3478  {
3479  PhysicsActor pa = m_rootPart.PhysActor;
3480 
3481  if (pa != null)
3482  {
3483  if (pa.IsPhysical)
3484  {
3485  if (m_rootPart.IsWaitingForFirstSpinUpdatePacket)
3486  {
3487  // first time initialization of "old" orientation for calculation of delta rotations
3488  m_rootPart.SpinOldOrientation = newOrientation;
3489  m_rootPart.IsWaitingForFirstSpinUpdatePacket = false;
3490  }
3491  else
3492  {
3493  // save and update old orientation
3494  Quaternion old = m_rootPart.SpinOldOrientation;
3495  m_rootPart.SpinOldOrientation = newOrientation;
3496  //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
3497  //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
3498 
3499  // compute difference between previous old rotation and new incoming rotation
3500  Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation;
3501 
3502  float rotationAngle;
3503  Vector3 rotationAxis;
3504  minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle);
3505  rotationAxis.Normalize();
3506 
3507  //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
3508  Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z);
3509  spinforce = (spinforce/8) * pa.Mass; // 8 is an arbitrary torque scaling factor
3510  pa.AddAngularForce(spinforce,true);
3511  m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
3512  }
3513  }
3514  else
3515  {
3516  NonPhysicalSpinMovement(newOrientation);
3517  }
3518  }
3519  else
3520  {
3521  NonPhysicalSpinMovement(newOrientation);
3522  }
3523  }
3524  }
3525 
3531  private void NonPhysicalSpinMovement(Quaternion newOrientation)
3532  {
3533  if(!IsAttachment && ScriptCount() == 0)
3534  UpdateGroupRotationR(newOrientation);
3535  }
3536 
3542  public void SetPartName(string name, uint localID)
3543  {
3544  SceneObjectPart part = GetPart(localID);
3545  if (part != null)
3546  {
3547  part.Name = name;
3548  }
3549  }
3550 
3551  public void SetPartDescription(string des, uint localID)
3552  {
3553  SceneObjectPart part = GetPart(localID);
3554  if (part != null)
3555  {
3556  part.Description = des;
3557  }
3558  }
3559 
3560  public void SetPartText(string text, uint localID)
3561  {
3562  SceneObjectPart part = GetPart(localID);
3563  if (part != null)
3564  {
3565  part.SetText(text);
3566  }
3567  }
3568 
3569  public void SetPartText(string text, UUID partID)
3570  {
3571  SceneObjectPart part = GetPart(partID);
3572  if (part != null)
3573  {
3574  part.SetText(text);
3575  }
3576  }
3577 
3578  public string GetPartName(uint localID)
3579  {
3580  SceneObjectPart part = GetPart(localID);
3581  if (part != null)
3582  {
3583  return part.Name;
3584  }
3585  return String.Empty;
3586  }
3587 
3588  public string GetPartDescription(uint localID)
3589  {
3590  SceneObjectPart part = GetPart(localID);
3591  if (part != null)
3592  {
3593  return part.Description;
3594  }
3595  return String.Empty;
3596  }
3597 
3606  public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
3607  {
3608  HasGroupChanged = true;
3609 
3610  SceneObjectPart selectionPart = GetPart(localID);
3611 
3612  if (Scene != null)
3613  {
3614  if (SetTemporary)
3615  {
3616  DetachFromBackup();
3617  // Remove from database and parcel prim count
3618  //
3619  m_scene.DeleteFromStorage(UUID);
3620  }
3621  else if (!Backup)
3622  {
3623  // Previously been temporary now switching back so make it
3624  // available for persisting again
3625  AttachToBackup();
3626  }
3627 
3628  m_scene.EventManager.TriggerParcelPrimCountTainted();
3629  }
3630 
3631  if (selectionPart != null)
3632  {
3633  SceneObjectPart[] parts = m_parts.GetArray();
3634 
3635  if (Scene != null && UsePhysics)
3636  {
3637  int maxprims = m_scene.m_linksetPhysCapacity;
3638  bool checkShape = (maxprims > 0 &&
3639  parts.Length > maxprims);
3640 
3641  for (int i = 0; i < parts.Length; i++)
3642  {
3643  SceneObjectPart part = parts[i];
3644  if (part.Scale.X > m_scene.m_maxPhys ||
3645  part.Scale.Y > m_scene.m_maxPhys ||
3646  part.Scale.Z > m_scene.m_maxPhys )
3647  {
3648  UsePhysics = false; // Reset physics
3649  break;
3650  }
3651 
3652  if (checkShape && part.PhysicsShapeType != (byte)PhysicsShapeType.None)
3653  {
3654  if (--maxprims < 0)
3655  {
3656  UsePhysics = false;
3657  break;
3658  }
3659  }
3660  }
3661  }
3662 
3663  if (parts.Length > 1)
3664  {
3665  m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3666 
3667  for (int i = 0; i < parts.Length; i++)
3668  {
3669 
3670  if (parts[i].UUID != m_rootPart.UUID)
3671  parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, true);
3672  }
3673 
3674  if (m_rootPart.PhysActor != null)
3675  m_rootPart.PhysActor.Building = false;
3676  }
3677  else
3678  m_rootPart.UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect, false);
3679  }
3680  }
3681 
3682  public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
3683  {
3684  SceneObjectPart part = GetPart(localID);
3685  if (part != null)
3686  {
3687  part.UpdateExtraParam(type, inUse, data);
3688  }
3689  }
3690 
3691 
3692 
3697  public int GetPartCount()
3698  {
3699  return Parts.Count();
3700  }
3701 
3707  public void UpdateTextureEntry(uint localID, byte[] textureEntry)
3708  {
3709  SceneObjectPart part = GetPart(localID);
3710  if (part != null)
3711  {
3712  part.UpdateTextureEntry(textureEntry);
3713  }
3714  }
3715 
3716  public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive)
3717  {
3718  uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits
3719  uint foldedPerms = RootPart.OwnerMask & 3;
3720 
3721  ForEachPart(part =>
3722  {
3723  newOwnerMask &= part.BaseMask;
3724  if (part != RootPart)
3725  part.ClonePermissions(RootPart);
3726  if (forceTaskInventoryPermissive)
3727  part.Inventory.ApplyGodPermissions(part.BaseMask);
3728  });
3729 
3730  uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify);
3731  uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify);
3732  RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
3733 
3734 // m_log.DebugFormat(
3735 // "[SCENE OBJECT GROUP]: RootPart.OwnerMask now {0} for {1} in {2}",
3736 // (OpenMetaverse.PermissionMask)RootPart.OwnerMask, Name, Scene.Name);
3737 
3738  RootPart.ScheduleFullUpdate();
3739  }
3740 
3741  public void UpdatePermissions(UUID AgentID, byte field, uint localID,
3742  uint mask, byte addRemTF)
3743  {
3744  RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
3745 
3746  bool god = Scene.Permissions.IsGod(AgentID);
3747 
3748  if (field == 1 && god)
3749  {
3750  ForEachPart(part =>
3751  {
3752  part.BaseMask = RootPart.BaseMask;
3753  });
3754  }
3755 
3756  AdjustChildPrimPermissions(false);
3757 
3758  if (field == 1 && god) // Base mask was set. Update all child part inventories
3759  {
3760  foreach (SceneObjectPart part in Parts)
3761  part.Inventory.ApplyGodPermissions(RootPart.BaseMask);
3762  }
3763 
3764  HasGroupChanged = true;
3765 
3766  // Send the group's properties to all clients once all parts are updated
3767  IClientAPI client;
3768  if (Scene.TryGetClient(AgentID, out client))
3769  SendPropertiesToClient(client);
3770  }
3771 
3772  #endregion
3773 
3774  #region Shape
3775 
3780  public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID)
3781  {
3782  SceneObjectPart part = GetPart(localID);
3783  if (part != null)
3784  {
3785  part.UpdateShape(shapeBlock);
3786 
3787  PhysicsActor pa = m_rootPart.PhysActor;
3788 
3789  if (pa != null)
3790  m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
3791  }
3792  }
3793 
3794  #endregion
3795 
3796  #region Resize
3797 
3802  public void GroupResize(Vector3 scale)
3803  {
3804 // m_log.DebugFormat(
3805 // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
3806 
3807  if (Scene == null)
3808  return;
3809 
3810  PhysicsActor pa = m_rootPart.PhysActor;
3811 
3812  float minsize = Scene.m_minNonphys;
3813  float maxsize = Scene.m_maxNonphys;
3814 
3815  if (pa != null && pa.IsPhysical)
3816  {
3817  minsize = Scene.m_minPhys;
3818  maxsize = Scene.m_maxPhys;
3819  }
3820 
3821  scale.X = Util.Clamp(scale.X, minsize, maxsize);
3822  scale.Y = Util.Clamp(scale.Y, minsize, maxsize);
3823  scale.Z = Util.Clamp(scale.Z, minsize, maxsize);
3824 
3825  // requested scaling factors
3826  float x = (scale.X / RootPart.Scale.X);
3827  float y = (scale.Y / RootPart.Scale.Y);
3828  float z = (scale.Z / RootPart.Scale.Z);
3829 
3830  SceneObjectPart[] parts = m_parts.GetArray();
3831 
3832  // fix scaling factors so parts don't violate dimensions
3833  for(int i = 0;i < parts.Length;i++)
3834  {
3835  SceneObjectPart obPart = parts[i];
3836  if(obPart.UUID != m_rootPart.UUID)
3837  {
3838  Vector3 oldSize = new Vector3(obPart.Scale);
3839 
3840  float f = 1.0f;
3841  float a = 1.0f;
3842 
3843  if(oldSize.X * x > maxsize)
3844  {
3845  f = maxsize / oldSize.X;
3846  a = f / x;
3847  x *= a;
3848  y *= a;
3849  z *= a;
3850  }
3851  else if(oldSize.X * x < minsize)
3852  {
3853  f = minsize / oldSize.X;
3854  a = f / x;
3855  x *= a;
3856  y *= a;
3857  z *= a;
3858  }
3859 
3860  if(oldSize.Y * y > maxsize)
3861  {
3862  f = maxsize / oldSize.Y;
3863  a = f / y;
3864  x *= a;
3865  y *= a;
3866  z *= a;
3867  }
3868  else if(oldSize.Y * y < minsize)
3869  {
3870  f = minsize / oldSize.Y;
3871  a = f / y;
3872  x *= a;
3873  y *= a;
3874  z *= a;
3875  }
3876 
3877  if(oldSize.Z * z > maxsize)
3878  {
3879  f = maxsize / oldSize.Z;
3880  a = f / z;
3881  x *= a;
3882  y *= a;
3883  z *= a;
3884  }
3885  else if(oldSize.Z * z < minsize)
3886  {
3887  f = minsize / oldSize.Z;
3888  a = f / z;
3889  x *= a;
3890  y *= a;
3891  z *= a;
3892  }
3893  }
3894  }
3895 
3896  Vector3 rootScale = RootPart.Scale;
3897  rootScale.X *= x;
3898  rootScale.Y *= y;
3899  rootScale.Z *= z;
3900 
3901  RootPart.Scale = rootScale;
3902 
3903  for (int i = 0; i < parts.Length; i++)
3904  {
3905  SceneObjectPart obPart = parts[i];
3906 
3907  if (obPart.UUID != m_rootPart.UUID)
3908  {
3909  Vector3 currentpos = new Vector3(obPart.OffsetPosition);
3910  currentpos.X *= x;
3911  currentpos.Y *= y;
3912  currentpos.Z *= z;
3913 
3914  Vector3 newSize = new Vector3(obPart.Scale);
3915  newSize.X *= x;
3916  newSize.Y *= y;
3917  newSize.Z *= z;
3918 
3919  obPart.Scale = newSize;
3920  obPart.UpdateOffSet(currentpos);
3921  }
3922 
3923  HasGroupChanged = true;
3924  m_rootPart.TriggerScriptChangedEvent(Changed.SCALE);
3925  ScheduleGroupForFullUpdate();
3926  }
3927  }
3928 
3929  #endregion
3930 
3931  #region Position
3932 
3937  public void UpdateGroupPosition(Vector3 pos)
3938  {
3939  if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
3940  {
3941  if (IsAttachment)
3942  {
3943  m_rootPart.AttachedPos = pos;
3944  }
3945 
3946  if (RootPart.GetStatusSandbox())
3947  {
3948  if (Util.GetDistanceTo(RootPart.StatusSandboxPos, pos) > 10)
3949  {
3950  RootPart.ScriptSetPhysicsStatus(false);
3951  pos = AbsolutePosition;
3952  Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
3953  ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
3954  }
3955  }
3956 
3957  AbsolutePosition = pos;
3958  HasGroupChanged = true;
3959  }
3960 
3961  //we need to do a terse update even if the move wasn't allowed
3962  // so that the position is reset in the client (the object snaps back)
3963  RootPart.ScheduleTerseUpdate();
3964  }
3965 
3972 
3973  public void UpdateSinglePosition(Vector3 pos, uint localID)
3974  {
3975  SceneObjectPart part = GetPart(localID);
3976 
3977  if (part != null)
3978  {
3979 // unlock parts position change
3980  if (m_rootPart.PhysActor != null)
3981  m_rootPart.PhysActor.Building = true;
3982 
3983  if (part.UUID == m_rootPart.UUID)
3984  {
3985  UpdateRootPosition(pos);
3986  }
3987  else
3988  {
3989  part.UpdateOffSet(pos);
3990  }
3991 
3992  if (m_rootPart.PhysActor != null)
3993  m_rootPart.PhysActor.Building = false;
3994 
3995  HasGroupChanged = true;
3996  }
3997  }
3998 
4003  public void UpdateRootPosition(Vector3 newPos)
4004  {
4005  // needs to be called with phys building true
4006  Vector3 oldPos;
4007 
4008  if (IsAttachment)
4009  oldPos = m_rootPart.AttachedPos + m_rootPart.OffsetPosition; // OffsetPosition should always be 0 in an attachments's root prim
4010  else
4011  oldPos = AbsolutePosition + m_rootPart.OffsetPosition;
4012 
4013  Vector3 diff = oldPos - newPos;
4014  Quaternion partRotation = m_rootPart.RotationOffset;
4015  diff *= Quaternion.Inverse(partRotation);
4016 
4017  SceneObjectPart[] parts = m_parts.GetArray();
4018  for (int i = 0; i < parts.Length; i++)
4019  {
4020  SceneObjectPart obPart = parts[i];
4021  if (obPart.UUID != m_rootPart.UUID)
4022  obPart.OffsetPosition = obPart.OffsetPosition + diff;
4023  }
4024 
4025  AbsolutePosition = newPos;
4026 
4027  if (IsAttachment)
4028  m_rootPart.AttachedPos = newPos;
4029 
4030  HasGroupChanged = true;
4031  if (m_rootPart.Undoing)
4032  {
4033  ScheduleGroupForFullUpdate();
4034  }
4035  else
4036  {
4037  ScheduleGroupForTerseUpdate();
4038  }
4039  }
4040 
4041  #endregion
4042 
4043  #region Rotation
4044 
4049  public void UpdateGroupRotationR(Quaternion rot)
4050  {
4051  m_rootPart.UpdateRotation(rot);
4052 
4053 /* this is done by rootpart RotationOffset set called by UpdateRotation
4054  PhysicsActor actor = m_rootPart.PhysActor;
4055  if (actor != null)
4056  {
4057  actor.Orientation = m_rootPart.RotationOffset;
4058  m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
4059  }
4060 */
4061  HasGroupChanged = true;
4062  ScheduleGroupForTerseUpdate();
4063  }
4064 
4070  public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
4071  {
4072  m_rootPart.UpdateRotation(rot);
4073 
4074  PhysicsActor actor = m_rootPart.PhysActor;
4075  if (actor != null)
4076  {
4077  actor.Orientation = m_rootPart.RotationOffset;
4078  m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
4079  }
4080 
4081  if (IsAttachment)
4082  {
4083  m_rootPart.AttachedPos = pos;
4084  }
4085 
4086  AbsolutePosition = pos;
4087 
4088  HasGroupChanged = true;
4089  ScheduleGroupForTerseUpdate();
4090  }
4091 
4097  public void UpdateSingleRotation(Quaternion rot, uint localID)
4098  {
4099  SceneObjectPart part = GetPart(localID);
4100 
4101  SceneObjectPart[] parts = m_parts.GetArray();
4102 
4103  if (part != null)
4104  {
4105  if (m_rootPart.PhysActor != null)
4106  m_rootPart.PhysActor.Building = true;
4107 
4108  if (part.UUID == m_rootPart.UUID)
4109  {
4110  UpdateRootRotation(rot);
4111  }
4112  else
4113  {
4114  part.UpdateRotation(rot);
4115  }
4116 
4117  if (m_rootPart.PhysActor != null)
4118  m_rootPart.PhysActor.Building = false;
4119  }
4120  }
4121 
4127  public void UpdateSingleRotation(Quaternion rot, Vector3 pos, uint localID)
4128  {
4129  SceneObjectPart part = GetPart(localID);
4130  if (part != null)
4131  {
4132  if (m_rootPart.PhysActor != null)
4133  m_rootPart.PhysActor.Building = true;
4134 
4135  if (part.UUID == m_rootPart.UUID)
4136  {
4137  UpdateRootRotation(rot);
4138  AbsolutePosition = pos;
4139  }
4140  else
4141  {
4142  part.UpdateRotation(rot);
4143  part.OffsetPosition = pos;
4144  }
4145 
4146  if (m_rootPart.PhysActor != null)
4147  m_rootPart.PhysActor.Building = false;
4148  }
4149  }
4150 
4155  public void UpdateRootRotation(Quaternion rot)
4156  {
4157  // needs to be called with phys building true
4158  Quaternion axRot = rot;
4159  Quaternion oldParentRot = m_rootPart.RotationOffset;
4160 
4161  //Don't use UpdateRotation because it schedules an update prematurely
4162  m_rootPart.RotationOffset = rot;
4163 
4164  PhysicsActor pa = m_rootPart.PhysActor;
4165 
4166  if (pa != null)
4167  {
4168  pa.Orientation = m_rootPart.RotationOffset;
4169  m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
4170  }
4171 
4172  SceneObjectPart[] parts = m_parts.GetArray();
4173  for (int i = 0; i < parts.Length; i++)
4174  {
4175  SceneObjectPart prim = parts[i];
4176  if (prim.UUID != m_rootPart.UUID)
4177  {
4178  Quaternion NewRot = oldParentRot * prim.RotationOffset;
4179  NewRot = Quaternion.Inverse(axRot) * NewRot;
4180  prim.RotationOffset = NewRot;
4181 
4182  Vector3 axPos = prim.OffsetPosition;
4183 
4184  axPos *= oldParentRot;
4185  axPos *= Quaternion.Inverse(axRot);
4186  prim.OffsetPosition = axPos;
4187  }
4188  }
4189 
4190  HasGroupChanged = true;
4191  ScheduleGroupForFullUpdate();
4192  }
4193 
4194  private enum updatetype :int
4195  {
4196  none = 0,
4197  partterse = 1,
4198  partfull = 2,
4199  groupterse = 3,
4200  groupfull = 4
4201  }
4202 
4204  {
4205  // TODO this still as excessive *.Schedule*Update()s
4206 
4207  if (part != null && part.ParentGroup != null)
4208  {
4209  ObjectChangeType change = data.change;
4210  bool togroup = ((change & ObjectChangeType.Group) != 0);
4211  // bool uniform = ((what & ObjectChangeType.UniformScale) != 0); not in use
4212 
4213  SceneObjectGroup group = part.ParentGroup;
4214  PhysicsActor pha = group.RootPart.PhysActor;
4215 
4216  updatetype updateType = updatetype.none;
4217 
4218  if (togroup)
4219  {
4220  // related to group
4221  if ((change & (ObjectChangeType.Rotation | ObjectChangeType.Position)) != 0)
4222  {
4223  if ((change & ObjectChangeType.Rotation) != 0)
4224  {
4225  group.RootPart.UpdateRotation(data.rotation);
4226  updateType = updatetype.none;
4227  }
4228  if ((change & ObjectChangeType.Position) != 0)
4229  {
4230  if (IsAttachment || m_scene.Permissions.CanObjectEntry(group.UUID, false, data.position))
4231  UpdateGroupPosition(data.position);
4232  updateType = updatetype.groupterse;
4233  }
4234  else
4235  // ugly rotation update of all parts
4236  {
4237  group.ResetChildPrimPhysicsPositions();
4238  }
4239 
4240  }
4241  if ((change & ObjectChangeType.Scale) != 0)
4242  {
4243  if (pha != null)
4244  pha.Building = true;
4245 
4246  group.GroupResize(data.scale);
4247  updateType = updatetype.none;
4248 
4249  if (pha != null)
4250  pha.Building = false;
4251  }
4252  }
4253  else
4254  {
4255  // related to single prim in a link-set ( ie group)
4256  if (pha != null)
4257  pha.Building = true;
4258 
4259  // root part is special
4260  // parts offset positions or rotations need to change also
4261 
4262  if (part == group.RootPart)
4263  {
4264  if ((change & ObjectChangeType.Rotation) != 0)
4265  group.UpdateRootRotation(data.rotation);
4266  if ((change & ObjectChangeType.Position) != 0)
4267  group.UpdateRootPosition(data.position);
4268  if ((change & ObjectChangeType.Scale) != 0)
4269  part.Resize(data.scale);
4270  }
4271  else
4272  {
4273  if ((change & ObjectChangeType.Position) != 0)
4274  {
4275  part.OffsetPosition = data.position;
4276  updateType = updatetype.partterse;
4277  }
4278  if ((change & ObjectChangeType.Rotation) != 0)
4279  {
4280  part.UpdateRotation(data.rotation);
4281  updateType = updatetype.none;
4282  }
4283  if ((change & ObjectChangeType.Scale) != 0)
4284  {
4285  part.Resize(data.scale);
4286  updateType = updatetype.none;
4287  }
4288  }
4289 
4290  if (pha != null)
4291  pha.Building = false;
4292  }
4293 
4294  if (updateType != updatetype.none)
4295  {
4296  group.HasGroupChanged = true;
4297 
4298  switch (updateType)
4299  {
4300  case updatetype.partterse:
4301  part.ScheduleTerseUpdate();
4302  break;
4303  case updatetype.partfull:
4304  part.ScheduleFullUpdate();
4305  break;
4306  case updatetype.groupterse:
4307  group.ScheduleGroupForTerseUpdate();
4308  break;
4309  case updatetype.groupfull:
4310  group.ScheduleGroupForFullUpdate();
4311  break;
4312  default:
4313  break;
4314  }
4315  }
4316  }
4317  }
4318 
4319  #endregion
4320 
4321  internal void SetAxisRotation(int axis, int rotate10)
4322  {
4323  bool setX = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) != 0);
4324  bool setY = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) != 0);
4325  bool setZ = ((axis & (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) != 0);
4326 
4327  if (setX || setY || setZ)
4328  {
4329  bool lockaxis = (rotate10 == 0); // zero means axis locked
4330 
4331  byte locks = RootPart.RotationAxisLocks;
4332 
4333  if (setX)
4334  {
4335  if(lockaxis)
4336  locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X;
4337  else
4338  locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_X;
4339  }
4340 
4341  if (setY)
4342  {
4343  if(lockaxis)
4344  locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y;
4345  else
4346  locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Y;
4347  }
4348 
4349  if (setZ)
4350  {
4351  if(lockaxis)
4352  locks |= (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z;
4353  else
4354  locks &= (byte)SceneObjectGroup.axisSelect.NOT_STATUS_ROTATE_Z;
4355  }
4356 
4357  RootPart.RotationAxisLocks = locks;
4358  RootPart.SetPhysicsAxisRotation();
4359  }
4360  }
4361 
4362  public int GetAxisRotation(int axis)
4363  {
4364  byte rotAxislocks = RootPart.RotationAxisLocks;
4365 
4366  // if multiple return the one with higher id
4367  if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z)
4368  return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Z) == 0 ? 1:0;
4369  if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y)
4370  return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_Y) == 0 ? 1:0;
4371  if (axis == (int)SceneObjectGroup.axisSelect.STATUS_ROTATE_X)
4372  return (rotAxislocks & (byte)SceneObjectGroup.axisSelect.STATUS_ROTATE_X) == 0 ? 1:0;
4373 
4374  return 0;
4375  }
4376 
4377  public int registerRotTargetWaypoint(Quaternion target, float tolerance)
4378  {
4379  scriptRotTarget waypoint = new scriptRotTarget();
4380  waypoint.targetRot = target;
4381  waypoint.tolerance = tolerance;
4382  uint handle = m_scene.AllocateLocalId();
4383  waypoint.handle = handle;
4384  lock (m_rotTargets)
4385  {
4386  if (m_rotTargets.Count >= 8)
4387  m_rotTargets.Remove(m_rotTargets.ElementAt(0).Key);
4388  m_rotTargets.Add(handle, waypoint);
4389  }
4390  m_scene.AddGroupTarget(this);
4391  return (int)handle;
4392  }
4393 
4394  public void unregisterRotTargetWaypoint(int handle)
4395  {
4396  lock (m_targets)
4397  {
4398  m_rotTargets.Remove((uint)handle);
4399  if (m_targets.Count == 0)
4400  m_scene.RemoveGroupTarget(this);
4401  }
4402  }
4403 
4404  public int registerTargetWaypoint(Vector3 target, float tolerance)
4405  {
4406  scriptPosTarget waypoint = new scriptPosTarget();
4407  waypoint.targetPos = target;
4408  waypoint.tolerance = tolerance;
4409  uint handle = m_scene.AllocateLocalId();
4410  waypoint.handle = handle;
4411  lock (m_targets)
4412  {
4413  if (m_targets.Count >= 8)
4414  m_targets.Remove(m_targets.ElementAt(0).Key);
4415  m_targets.Add(handle, waypoint);
4416  }
4417  m_scene.AddGroupTarget(this);
4418  return (int)handle;
4419  }
4420 
4421  public void unregisterTargetWaypoint(int handle)
4422  {
4423  lock (m_targets)
4424  {
4425  m_targets.Remove((uint)handle);
4426  if (m_targets.Count == 0)
4427  m_scene.RemoveGroupTarget(this);
4428  }
4429  }
4430 
4431  public void checkAtTargets()
4432  {
4433  if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
4434  {
4435  if (m_targets.Count > 0)
4436  {
4437  bool at_target = false;
4438  //Vector3 targetPos;
4439  //uint targetHandle;
4440  Dictionary<uint, scriptPosTarget> atTargets = new Dictionary<uint, scriptPosTarget>();
4441  lock (m_targets)
4442  {
4443  foreach (uint idx in m_targets.Keys)
4444  {
4445  scriptPosTarget target = m_targets[idx];
4446  if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
4447  {
4448  at_target = true;
4449 
4450  // trigger at_target
4451  if (m_scriptListens_atTarget)
4452  {
4453  scriptPosTarget att = new scriptPosTarget();
4454  att.targetPos = target.targetPos;
4455  att.tolerance = target.tolerance;
4456  att.handle = target.handle;
4457  atTargets.Add(idx, att);
4458  }
4459  }
4460  }
4461  }
4462 
4463  if (atTargets.Count > 0)
4464  {
4465  SceneObjectPart[] parts = m_parts.GetArray();
4466  uint[] localids = new uint[parts.Length];
4467  for (int i = 0; i < parts.Length; i++)
4468  localids[i] = parts[i].LocalId;
4469 
4470  for (int ctr = 0; ctr < localids.Length; ctr++)
4471  {
4472  foreach (uint target in atTargets.Keys)
4473  {
4474  scriptPosTarget att = atTargets[target];
4475  m_scene.EventManager.TriggerAtTargetEvent(
4476  localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition);
4477  }
4478  }
4479 
4480  return;
4481  }
4482 
4483  if (m_scriptListens_notAtTarget && !at_target)
4484  {
4485  //trigger not_at_target
4486  SceneObjectPart[] parts = m_parts.GetArray();
4487  uint[] localids = new uint[parts.Length];
4488  for (int i = 0; i < parts.Length; i++)
4489  localids[i] = parts[i].LocalId;
4490 
4491  for (int ctr = 0; ctr < localids.Length; ctr++)
4492  {
4493  m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
4494  }
4495  }
4496  }
4497  }
4498  if (m_scriptListens_atRotTarget || m_scriptListens_notAtRotTarget)
4499  {
4500  if (m_rotTargets.Count > 0)
4501  {
4502  bool at_Rottarget = false;
4503  Dictionary<uint, scriptRotTarget> atRotTargets = new Dictionary<uint, scriptRotTarget>();
4504  lock (m_rotTargets)
4505  {
4506  foreach (uint idx in m_rotTargets.Keys)
4507  {
4508  scriptRotTarget target = m_rotTargets[idx];
4509  double angle
4510  = Math.Acos(
4511  target.targetRot.X * m_rootPart.RotationOffset.X
4512  + target.targetRot.Y * m_rootPart.RotationOffset.Y
4513  + target.targetRot.Z * m_rootPart.RotationOffset.Z
4514  + target.targetRot.W * m_rootPart.RotationOffset.W)
4515  * 2;
4516  if (angle < 0) angle = -angle;
4517  if (angle > Math.PI) angle = (Math.PI * 2 - angle);
4518  if (angle <= target.tolerance)
4519  {
4520  // trigger at_rot_target
4521  if (m_scriptListens_atRotTarget)
4522  {
4523  at_Rottarget = true;
4524  scriptRotTarget att = new scriptRotTarget();
4525  att.targetRot = target.targetRot;
4526  att.tolerance = target.tolerance;
4527  att.handle = target.handle;
4528  atRotTargets.Add(idx, att);
4529  }
4530  }
4531  }
4532  }
4533 
4534  if (atRotTargets.Count > 0)
4535  {
4536  SceneObjectPart[] parts = m_parts.GetArray();
4537  uint[] localids = new uint[parts.Length];
4538  for (int i = 0; i < parts.Length; i++)
4539  localids[i] = parts[i].LocalId;
4540 
4541  for (int ctr = 0; ctr < localids.Length; ctr++)
4542  {
4543  foreach (uint target in atRotTargets.Keys)
4544  {
4545  scriptRotTarget att = atRotTargets[target];
4546  m_scene.EventManager.TriggerAtRotTargetEvent(
4547  localids[ctr], att.handle, att.targetRot, m_rootPart.RotationOffset);
4548  }
4549  }
4550 
4551  return;
4552  }
4553 
4554  if (m_scriptListens_notAtRotTarget && !at_Rottarget)
4555  {
4556  //trigger not_at_target
4557  SceneObjectPart[] parts = m_parts.GetArray();
4558  uint[] localids = new uint[parts.Length];
4559  for (int i = 0; i < parts.Length; i++)
4560  localids[i] = parts[i].LocalId;
4561 
4562  for (int ctr = 0; ctr < localids.Length; ctr++)
4563  {
4564  m_scene.EventManager.TriggerNotAtRotTargetEvent(localids[ctr]);
4565  }
4566  }
4567  }
4568  }
4569  }
4570 
4571  public Vector3 GetGeometricCenter()
4572  {
4573  // this is not real geometric center but a average of positions relative to root prim acording to
4574  // http://wiki.secondlife.com/wiki/llGetGeometricCenter
4575  // ignoring tortured prims details since sl also seems to ignore
4576  // so no real use in doing it on physics
4577 
4578  Vector3 gc = Vector3.Zero;
4579 
4580  int nparts = m_parts.Count;
4581  if (nparts <= 1)
4582  return gc;
4583 
4584  SceneObjectPart[] parts = m_parts.GetArray();
4585  nparts = parts.Length; // just in case it changed
4586  if (nparts <= 1)
4587  return gc;
4588 
4589  Quaternion parentRot = RootPart.RotationOffset;
4590  Vector3 pPos;
4591 
4592  // average all parts positions
4593  for (int i = 0; i < nparts; i++)
4594  {
4595  // do it directly
4596  // gc += parts[i].GetWorldPosition();
4597  if (parts[i] != RootPart)
4598  {
4599  pPos = parts[i].OffsetPosition;
4600  gc += pPos;
4601  }
4602 
4603  }
4604  gc /= nparts;
4605 
4606  // relative to root:
4607 // gc -= AbsolutePosition;
4608  return gc;
4609  }
4610 
4611  public float GetMass()
4612  {
4613  float retmass = 0f;
4614  SceneObjectPart[] parts = m_parts.GetArray();
4615  for (int i = 0; i < parts.Length; i++)
4616  retmass += parts[i].GetMass();
4617 
4618  return retmass;
4619  }
4620 
4621  // center of mass of full object
4622  public Vector3 GetCenterOfMass()
4623  {
4624  PhysicsActor pa = RootPart.PhysActor;
4625 
4626  if(((RootPart.Flags & PrimFlags.Physics) !=0) && pa !=null)
4627  {
4628  // physics knows better about center of mass of physical prims
4629  Vector3 tmp = pa.CenterOfMass;
4630  return tmp;
4631  }
4632 
4633  Vector3 Ptot = Vector3.Zero;
4634  float totmass = 0f;
4635  float m;
4636 
4637  SceneObjectPart[] parts = m_parts.GetArray();
4638  for (int i = 0; i < parts.Length; i++)
4639  {
4640  m = parts[i].GetMass();
4641  Ptot += parts[i].GetPartCenterOfMass() * m;
4642  totmass += m;
4643  }
4644 
4645  if (totmass == 0)
4646  totmass = 0;
4647  else
4648  totmass = 1 / totmass;
4649  Ptot *= totmass;
4650 
4651  return Ptot;
4652  }
4653 
4661 /*
4662  public void CheckSculptAndLoad()
4663  {
4664  if (IsDeleted)
4665  return;
4666 
4667  if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
4668  return;
4669 
4670 // m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
4671 
4672  SceneObjectPart[] parts = m_parts.GetArray();
4673 
4674  for (int i = 0; i < parts.Length; i++)
4675  parts[i].CheckSculptAndLoad();
4676  }
4677 */
4683  public void SetGroup(UUID GroupID, IClientAPI client)
4684  {
4685  SceneObjectPart[] parts = m_parts.GetArray();
4686  for (int i = 0; i < parts.Length; i++)
4687  {
4688  SceneObjectPart part = parts[i];
4689  part.SetGroup(GroupID, client);
4690  part.Inventory.ChangeInventoryGroup(GroupID);
4691  }
4692 
4693  HasGroupChanged = true;
4694 
4695  // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
4696  // for the same object with very different properties. The caller must schedule the update.
4697  //ScheduleGroupForFullUpdate();
4698  }
4699 
4701  {
4702  SceneObjectPart[] parts = m_parts.GetArray();
4703  for (int i = 0; i < parts.Length; i++)
4704  parts[i].TriggerScriptChangedEvent(val);
4705  }
4706 
4710  public int ScriptCount()
4711  {
4712  int count = 0;
4713  SceneObjectPart[] parts = m_parts.GetArray();
4714  for (int i = 0; i < parts.Length; i++)
4715  count += parts[i].Inventory.ScriptCount();
4716 
4717  return count;
4718  }
4719 
4723  public float ScriptExecutionTime()
4724  {
4725  IScriptModule[] engines = Scene.RequestModuleInterfaces<IScriptModule>();
4726 
4727  if (engines.Length == 0) // No engine at all
4728  return 0.0f;
4729 
4730  float time = 0.0f;
4731 
4732  // get all the scripts in all parts
4733  SceneObjectPart[] parts = m_parts.GetArray();
4734  List<TaskInventoryItem> scripts = new List<TaskInventoryItem>();
4735  for (int i = 0; i < parts.Length; i++)
4736  {
4737  scripts.AddRange(parts[i].Inventory.GetInventoryItems(InventoryType.LSL));
4738  }
4739  // extract the UUIDs
4740  List<UUID> ids = new List<UUID>(scripts.Count);
4741  foreach (TaskInventoryItem script in scripts)
4742  {
4743  if (!ids.Contains(script.ItemID))
4744  {
4745  ids.Add(script.ItemID);
4746  }
4747  }
4748  // Offer the list of script UUIDs to each engine found and accumulate the time
4749  foreach (IScriptModule e in engines)
4750  {
4751  if (e != null)
4752  {
4753  time += e.GetScriptExecutionTime(ids);
4754  }
4755  }
4756  return time;
4757  }
4758 
4762  public int RunningScriptCount()
4763  {
4764  int count = 0;
4765  SceneObjectPart[] parts = m_parts.GetArray();
4766  for (int i = 0; i < parts.Length; i++)
4767  count += parts[i].Inventory.RunningScriptCount();
4768 
4769  return count;
4770  }
4771 
4780  public List<ScenePresence> GetSittingAvatars()
4781  {
4782  lock (m_sittingAvatars)
4783  return new List<ScenePresence>(m_sittingAvatars);
4784  }
4785 
4792  {
4793  lock (m_sittingAvatars)
4794  return m_sittingAvatars.Count;
4795  }
4796 
4797  public override string ToString()
4798  {
4799  return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition);
4800  }
4801 
4802  #region ISceneObject
4803 
4805  {
4806  SceneObjectGroup sog = Copy(false);
4807  sog.IsDeleted = false;
4808  return sog;
4809  }
4810 
4811  public virtual string ToXml2()
4812  {
4813  return SceneObjectSerializer.ToXml2Format(this);
4814  }
4815 
4816  public virtual string ExtraToXmlString()
4817  {
4818  return "<ExtraFromItemID>" + FromItemID.ToString() + "</ExtraFromItemID>";
4819  }
4820 
4821  public virtual void ExtraFromXmlString(string xmlstr)
4822  {
4823  string id = xmlstr.Substring(xmlstr.IndexOf("<ExtraFromItemID>"));
4824  id = xmlstr.Replace("<ExtraFromItemID>", "");
4825  id = id.Replace("</ExtraFromItemID>", "");
4826 
4827  UUID uuid = UUID.Zero;
4828  UUID.TryParse(id, out uuid);
4829 
4830  FromItemID = uuid;
4831  }
4832 
4833  public void ResetOwnerChangeFlag()
4834  {
4835  ForEachPart(delegate(SceneObjectPart part)
4836  {
4837  part.ResetOwnerChangeFlag();
4838  });
4839  }
4840 
4841  // clear some references to easy cg
4842  public void Clear()
4843  {
4844  m_parts.Clear();
4845  m_sittingAvatars.Clear();
4846 // m_rootPart = null;
4847 
4848  m_PlaySoundMasterPrim = null;
4849  m_PlaySoundSlavePrims.Clear();
4850  m_LoopSoundMasterPrim = null;
4851  m_targets.Clear();
4852  }
4853 
4854  #endregion
4855  }
4856 
4857 }
virtual void OnGrabGroup(Vector3 offsetPos, IClientAPI remoteClient)
void SendGroupTerseUpdate()
Immediately send a terse update for this scene object.
SceneObjectGroup(SceneObjectPart part)
This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart. The original SceneO...
SceneObjectGroup CrossAsync(SceneObjectGroup sog, Vector3 val)
void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive)
void SetPartName(string name, uint localID)
Set the name of a prim
void SendGroupRootTerseUpdate()
Immediately send an update for this scene object's root prim only. This is for updates regarding the ...
abstract void AddAngularForce(Vector3 force, bool pushforce)
void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
const uint MaximumRegionSize
Definition: Constants.cs:39
SceneObjectGroup DelinkFromGroup(uint partID)
Delink the given prim from this group. The delinked prim is established as an independent SceneObject...
void NonPhysicalGrabMovement(Vector3 pos)
Apply possition for grabbing non-physical linksets (Ctrl+Drag) This MUST be blocked for linksets that...
void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
Set the owner of the root part.
SceneObjectPart GetLinkNumPart(int linknum)
Get the child part by LinkNum
SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
Make a copy of the given part.
void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID)
void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
Update prim flags for this group.
void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
Update the position and rotation of a group simultaneously.
void StartLookAt(Quaternion target, float strength, float damping)
void AddPart(SceneObjectPart part)
Add a new part to this scene object. The part must already be correctly configured.
SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents)
Delink the given prim from this group. The delinked prim is established as an independent SceneObject...
delegate void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient)
SceneObjectGroup(UUID ownerID, Vector3 pos, PrimitiveBaseShape shape)
Constructor.
void ObjectGrabHandler(uint localId, Vector3 offsetPos, IClientAPI remoteClient)
void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient)
If object is physical, apply torque to spin it around
float ScriptExecutionTime()
A float the value is a representative execution time in milliseconds of all scripts in the link set...
virtual void AttachToBackup()
Hooks this object up to the backup event so that it is persisted to the database when the update thre...
bool ContainsPart(uint localID)
Does this group contain the given part? should be able to remove these methods once we have a entity ...
void SendPropertiesToClient(IClientAPI client)
Send metadata about the root prim (name, description, sale price, permissions, etc.) to a client.
void GetResourcesCosts(SceneObjectPart apart, out float linksetResCost, out float linksetPhysCost, out float partCost, out float partPhysCost)
SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
Constructor. This object is added to the scene later via AttachToScene()
A scene object group is conceptually an object in the scene. The object is constituted of SceneObject...
void GroupResize(Vector3 scale)
Resize the entire group of prims.
void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
Gets a vector representing the size of the bounding box containing all the prims in the group Treats ...
PrimFlags Flags
Property flags. See OpenMetaverse.PrimFlags
void SetHoverHeight(float height, PIDHoverType hoverType, float tau)
Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds...
int registerTargetWaypoint(Vector3 target, float tolerance)
Represents an item in a task inventory
void AttachToScene(Scene scene)
Attach this object to a scene. It will also now appear to agents.
override void Update()
Performs any updates that need to be done at each frame, as opposed to immediately. These included scheduled updates and updates that occur due to physics processing.
void UpdateRootRotation(Quaternion rot)
Update the rotation of just the root prim of a linkset.
void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
int OtherCleanTime
Autoreturn number of minutes to return SceneObjectGroup that are owned by someone who doesn't own the...
Definition: LandData.cs:706
void Resize(Vector3 scale)
Set the scale of this part.
SceneObjectGroup Copy(bool userExposed)
Duplicates this object, including operations such as physics set up and attaching to the backup event...
Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
void UpdatePermissions(UUID AgentID, byte field, uint localID, uint mask, byte addRemTF)
int PrimCount
Number of prims in this group
SceneObjectPart GetPart(uint localID)
Get a part with a given local ID
void RotLookAt(Quaternion target, float strength, float damping)
void DeleteGroupFromScene(bool silent)
Delete this group from its scene.
void UpdateGroupRotationR(Quaternion rot)
Update the rotation of the group.
Vector3 Scale
Change the scale of this part.
bool IsAttachmentCheckFull()
Check both the attachment property and the relevant properties of the underlying root part...
EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
UUID GroupID
Unique ID of the Group that owns
Definition: LandData.cs:342
void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
void SetGroup(UUID GroupID, IClientAPI client)
If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape ...
void UpdateRootPosition(Vector3 newPos)
Update just the root prim position in a linkset
SceneObjectPart GetPart(UUID primID)
Get a part with a given UUID
delegate void PrimCountTaintedDelegate()
void UpdateSingleRotation(Quaternion rot, Vector3 pos, uint localID)
Update the position and rotation simultaneously of a single prim within the group.
void doChangeObject(SceneObjectPart part, ObjectChangeData data)
void SetPartDescription(string des, uint localID)
void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
void UpdateSinglePosition(Vector3 pos, uint localID)
Update the position of a single part of this scene object
PhysicsActor PhysActor
The representation of this part in the physics scene.
virtual void ProcessBackup(ISimulationDataService datastore, bool forcedBackup)
Processes backup.
void GrabMovement(UUID partID, Vector3 offset, Vector3 pos, IClientAPI remoteClient)
If object is physical, apply force to move it around If object is not physical, just put it at the re...
virtual void DetachFromBackup()
Stop this object from being persisted over server restarts.
void UpdateGroupPosition(Vector3 pos)
Move this scene object
void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
Copy the given part as the root part of this scene object.
void GetSelectedCosts(out float PhysCost, out float StreamCost, out float SimulCost)
int ScriptCount()
Returns a count of the number of scripts in this groups parts.
void SendFullUpdateToClient(IClientAPI remoteClient)
Send the parts of this SOG to a single client
void ScheduleGroupForTerseUpdate()
Schedule a terse update for this scene object to all interested viewers.
void ScheduleGroupForFullUpdate()
Schedule a full update for this scene object to all interested viewers.
void ApplyPhysics()
Apply physics to this group
void ForEachPart(Action< SceneObjectPart > whatToDo)
virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
uint ParentID
The parent ID of this part.
bool PositionIsInCurrentRegion(Vector3 pos)
Definition: Scene.cs:2903
void ResetIDs()
Reset the UUIDs for all the prims that make up this group.
bool IsInTransit
This signals whether the presence is in transit between neighbouring regions.
int GetSittingAvatarsCount()
Gets the number of sitting avatars.
void SendGroupFullUpdate()
Immediately send a full update for this scene object.
void UpdateTextureEntry(uint localID, byte[] textureEntry)
Update the texture entry for this part
int RunningScriptCount()
Returns a count of the number of running scripts in this groups parts.
int registerRotTargetWaypoint(Quaternion target, float tolerance)
void LinkToGroup(SceneObjectGroup objectGroup)
Link the prims in a given group to this group
void UpdateSingleRotation(Quaternion rot, uint localID)
Update the rotation of a single prim within the group.
SceneObjectGroup DelinkFromGroup(uint partID, bool sendEvents)
Delink the given prim from this group. The delinked prim is established as an independent SceneObject...
void SetText(string text, Vector3 color, double alpha)
void SetRootPart(SceneObjectPart part)
Set a part to act as the root part for this scene object
OpenSim.Framework.PermissionMask PermissionMask
void SaveScriptedState(XmlTextWriter writer, bool oldIDs)
bool TryGetClient(UUID avatarID, out IClientAPI client)
Definition: Scene.cs:5432
void SpinStart(IClientAPI remoteClient)
If object is physical, prepare for spinning torques (set flag to save old orientation) ...
This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph co...
Definition: SceneGraph.cs:54
List< ScenePresence > GetSittingAvatars()
Get a copy of the list of sitting avatars on all prims of this object.
uint ParentID
If the avatar is sitting, the local ID of the prim that it's sitting on. If not sitting then zero...
UUID OwnerID
Owner Avatar or Group of the parcel. Naturally, all land masses must be owned by someone ...
Definition: LandData.cs:551