clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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.Linq;
34 using System.Threading;
35 using System.Xml;
36 using System.Xml.Serialization;
37 using OpenMetaverse;
38 using OpenMetaverse.Packets;
39 using OpenSim.Framework;
40 using OpenSim.Region.Framework.Interfaces;
41 using OpenSim.Region.Physics.Manager;
42 using OpenSim.Region.Framework.Scenes.Serialization;
43 using PermissionMask = OpenSim.Framework.PermissionMask;
44  
45 namespace OpenSim.Region.Framework.Scenes
46 {
47 [Flags]
48 public enum scriptEvents
49 {
50 None = 0,
51 attach = 1,
52 collision = 16,
53 collision_end = 32,
54 collision_start = 64,
55 control = 128,
56 dataserver = 256,
57 email = 512,
58 http_response = 1024,
59 land_collision = 2048,
60 land_collision_end = 4096,
61 land_collision_start = 8192,
62 at_target = 16384,
63 at_rot_target = 16777216,
64 listen = 32768,
65 money = 65536,
66 moving_end = 131072,
67 moving_start = 262144,
68 not_at_rot_target = 524288,
69 not_at_target = 1048576,
70 remote_data = 8388608,
71 run_time_permissions = 268435456,
72 state_entry = 1073741824,
73 state_exit = 2,
74 timer = 4,
75 touch = 8,
76 touch_end = 536870912,
77 touch_start = 2097152,
78 object_rez = 4194304
79 }
80  
81 struct scriptPosTarget
82 {
83 public Vector3 targetPos;
84 public float tolerance;
85 public uint handle;
86 }
87  
88 struct scriptRotTarget
89 {
90 public Quaternion targetRot;
91 public float tolerance;
92 public uint handle;
93 }
94  
95 public delegate void PrimCountTaintedDelegate();
96  
97 /// <summary>
98 /// A scene object group is conceptually an object in the scene. The object is constituted of SceneObjectParts
99 /// (often known as prims), one of which is considered the root part.
100 /// </summary>
101 public partial class SceneObjectGroup : EntityBase, ISceneObject
102 {
103 // Axis selection bitmask used by SetAxisRotation()
104 // Just happen to be the same bits used by llSetStatus() and defined in ScriptBaseClass.
105 public enum axisSelect : int
106 {
107 STATUS_ROTATE_X = 0x002,
108 STATUS_ROTATE_Y = 0x004,
109 STATUS_ROTATE_Z = 0x008,
110 }
111  
112 // This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm
113 public static readonly uint SLAM = 16;
114  
115 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
116  
117 /// <summary>
118 /// Signal whether the non-inventory attributes of any prims in the group have changed
119 /// since the group's last persistent backup
120 /// </summary>
121 private bool m_hasGroupChanged = false;
122 private long timeFirstChanged;
123 private long timeLastChanged;
124  
125 /// <summary>
126 /// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
127 /// (the database).
128 /// </summary>
129 /// <remarks>
130 /// Ultimately, this should be managed such that region modules can change it at the end of a set of operations
131 /// so that either all changes are preserved or none at all. However, currently, a large amount of internal
132 /// code will set this anyway when some object properties are changed.
133 /// </remarks>
134 public bool HasGroupChanged
135 {
136 set
137 {
138 if (value)
139 {
140 timeLastChanged = DateTime.Now.Ticks;
141 if (!m_hasGroupChanged)
142 timeFirstChanged = DateTime.Now.Ticks;
143 }
144 m_hasGroupChanged = value;
145  
146 // m_log.DebugFormat(
147 // "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId);
148 }
149  
150 get { return m_hasGroupChanged; }
151 }
152  
153 private bool m_groupContainsForeignPrims = false;
154  
155 /// <summary>
156 /// Whether the group contains prims that came from a different group. This happens when
157 /// linking or delinking groups. The implication is that until the group is persisted,
158 /// the prims in the database still use the old SceneGroupID. That's a problem if the group
159 /// is deleted, because we delete groups by searching for prims by their SceneGroupID.
160 /// </summary>
161 public bool GroupContainsForeignPrims
162 {
163 private set
164 {
165 m_groupContainsForeignPrims = value;
166 if (m_groupContainsForeignPrims)
167 HasGroupChanged = true;
168 }
169  
170 get { return m_groupContainsForeignPrims; }
171 }
172  
173  
174 private bool isTimeToPersist()
175 {
176 if (IsSelected || IsDeleted || IsAttachment)
177 return false;
178 if (!m_hasGroupChanged)
179 return false;
180 if (m_scene.ShuttingDown)
181 return true;
182 long currentTime = DateTime.Now.Ticks;
183 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter)
184 return true;
185 return false;
186 }
187  
188 /// <summary>
189 /// Is this scene object acting as an attachment?
190 /// </summary>
191 public bool IsAttachment { get; set; }
192  
193 /// <summary>
194 /// The avatar to which this scene object is attached.
195 /// </summary>
196 /// <remarks>
197 /// If we're not attached to an avatar then this is UUID.Zero
198 /// </remarks>
199 public UUID AttachedAvatar { get; set; }
200  
201 /// <summary>
202 /// Attachment point of this scene object to an avatar.
203 /// </summary>
204 /// <remarks>
205 /// 0 if we're not attached to anything
206 /// </remarks>
207 public uint AttachmentPoint
208 {
209 get
210 {
211 return m_rootPart.Shape.State;
212 }
213  
214 set
215 {
216 IsAttachment = value != 0;
217 m_rootPart.Shape.State = (byte)value;
218 }
219 }
220  
221 /// <summary>
222 /// If this scene object has an attachment point then indicate whether there is a point where
223 /// attachments are perceivable by avatars other than the avatar to which this object is attached.
224 /// </summary>
225 /// <remarks>
226 /// HUDs are not perceivable by other avatars.
227 /// </remarks>
228 public bool HasPrivateAttachmentPoint
229 {
230 get
231 {
232 return AttachmentPoint >= (uint)OpenMetaverse.AttachmentPoint.HUDCenter2
233 && AttachmentPoint <= (uint)OpenMetaverse.AttachmentPoint.HUDBottomRight;
234 }
235 }
236  
237 public void ClearPartAttachmentData()
238 {
239 AttachmentPoint = 0;
240  
241 // Even though we don't use child part state parameters for attachments any more, we still need to set
242 // these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
243 // we store them correctly, scene objects that we receive from elsewhere might not.
244 foreach (SceneObjectPart part in Parts)
245 part.Shape.State = 0;
246 }
247  
248 /// <summary>
249 /// Is this scene object phantom?
250 /// </summary>
251 /// <remarks>
252 /// Updating must currently take place through UpdatePrimFlags()
253 /// </remarks>
254 public bool IsPhantom
255 {
256 get { return (RootPart.Flags & PrimFlags.Phantom) != 0; }
257 }
258  
259 /// <summary>
260 /// Does this scene object use physics?
261 /// </summary>
262 /// <remarks>
263 /// Updating must currently take place through UpdatePrimFlags()
264 /// </remarks>
265 public bool UsesPhysics
266 {
267 get { return (RootPart.Flags & PrimFlags.Physics) != 0; }
268 }
269  
270 /// <summary>
271 /// Is this scene object temporary?
272 /// </summary>
273 /// <remarks>
274 /// Updating must currently take place through UpdatePrimFlags()
275 /// </remarks>
276 public bool IsTemporary
277 {
278 get { return (RootPart.Flags & PrimFlags.TemporaryOnRez) != 0; }
279 }
280  
281 public bool IsVolumeDetect
282 {
283 get { return RootPart.VolumeDetectActive; }
284 }
285  
286 private Vector3 lastPhysGroupPos;
287 private Quaternion lastPhysGroupRot;
288  
289 /// <summary>
290 /// Is this entity set to be saved in persistent storage?
291 /// </summary>
292 public bool Backup { get; private set; }
293  
294 protected MapAndArray<UUID, SceneObjectPart> m_parts = new MapAndArray<UUID, SceneObjectPart>();
295  
296 protected ulong m_regionHandle;
297 protected SceneObjectPart m_rootPart;
298 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
299  
300 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>();
301 private Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>();
302  
303 private bool m_scriptListens_atTarget;
304 private bool m_scriptListens_notAtTarget;
305  
306 private bool m_scriptListens_atRotTarget;
307 private bool m_scriptListens_notAtRotTarget;
308  
309 internal Dictionary<UUID, string> m_savedScriptState;
310  
311 #region Properties
312  
313 /// <summary>
314 /// The name of an object grouping is always the same as its root part
315 /// </summary>
316 public override string Name
317 {
318 get { return RootPart.Name; }
319 set { RootPart.Name = value; }
320 }
321  
322 public string Description
323 {
324 get { return RootPart.Description; }
325 set { RootPart.Description = value; }
326 }
327  
328 /// <summary>
329 /// Added because the Parcel code seems to use it
330 /// but not sure a object should have this
331 /// as what does it tell us? that some avatar has selected it (but not what Avatar/user)
332 /// think really there should be a list (or whatever) in each scenepresence
333 /// saying what prim(s) that user has selected.
334 /// </summary>
335 protected bool m_isSelected = false;
336  
337 /// <summary>
338 /// Number of prims in this group
339 /// </summary>
340 public int PrimCount
341 {
342 get { return m_parts.Count; }
343 }
344  
345 public Quaternion GroupRotation
346 {
347 get { return m_rootPart.RotationOffset; }
348 }
349  
350 public Vector3 GroupScale
351 {
352 get
353 {
354 Vector3 minScale = new Vector3(Constants.MaximumRegionSize, Constants.MaximumRegionSize, Constants.MaximumRegionSize);
355 Vector3 maxScale = Vector3.Zero;
356 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
357  
358 SceneObjectPart[] parts = m_parts.GetArray();
359 for (int i = 0; i < parts.Length; i++)
360 {
361 SceneObjectPart part = parts[i];
362 Vector3 partscale = part.Scale;
363 Vector3 partoffset = part.OffsetPosition;
364  
365 minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X;
366 minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.Y + partoffset.Y : minScale.Y;
367 minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.Z + partoffset.Z : minScale.Z;
368  
369 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
370 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
371 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
372 }
373  
374 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
375 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
376 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
377  
378 return finalScale;
379 }
380 }
381  
382 public UUID GroupID
383 {
384 get { return m_rootPart.GroupID; }
385 set { m_rootPart.GroupID = value; }
386 }
387  
388 public SceneObjectPart[] Parts
389 {
390 get { return m_parts.GetArray(); }
391 }
392  
393 public bool ContainsPart(UUID partID)
394 {
395 return m_parts.ContainsKey(partID);
396 }
397  
398 /// <summary>
399 /// Does this group contain the given part?
400 /// should be able to remove these methods once we have a entity index in scene
401 /// </summary>
402 /// <param name="localID"></param>
403 /// <returns></returns>
404 public bool ContainsPart(uint localID)
405 {
406 SceneObjectPart[] parts = m_parts.GetArray();
407 for (int i = 0; i < parts.Length; i++)
408 {
409 if (parts[i].LocalId == localID)
410 return true;
411 }
412  
413 return false;
414 }
415  
416 /// <value>
417 /// The root part of this scene object
418 /// </value>
419 public SceneObjectPart RootPart
420 {
421 get { return m_rootPart; }
422 }
423  
424 public ulong RegionHandle
425 {
426 get { return m_regionHandle; }
427 set
428 {
429 m_regionHandle = value;
430 SceneObjectPart[] parts = m_parts.GetArray();
431 for (int i = 0; i < parts.Length; i++)
432 parts[i].RegionHandle = value;
433 }
434 }
435  
436 /// <summary>
437 /// Check both the attachment property and the relevant properties of the underlying root part.
438 /// </summary>
439 /// <remarks>
440 /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't
441 /// have the IsAttachment property yet checked.
442 ///
443 /// FIXME: However, this should be fixed so that this property
444 /// propertly reflects the underlying status.
445 /// </remarks>
446 /// <returns></returns>
447 public bool IsAttachmentCheckFull()
448 {
449 return (IsAttachment || (m_rootPart.Shape.PCode == (byte)PCodeEnum.Primitive && m_rootPart.Shape.State != 0));
450 }
451  
452 private struct avtocrossInfo
453 {
454 public ScenePresence av;
455 public uint ParentID;
456 }
457  
458 /// <summary>
459 /// The absolute position of this scene object in the scene
460 /// </summary>
461 public override Vector3 AbsolutePosition
462 {
463 get { return m_rootPart.GroupPosition; }
464 set
465 {
466 Vector3 val = value;
467  
468 if (Scene != null)
469 {
470 if (
471 !Scene.PositionIsInCurrentRegion(val)
472 && !IsAttachmentCheckFull()
473 && (!Scene.LoadingPrims)
474 )
475 {
476 IEntityTransferModule entityTransfer = m_scene.RequestModuleInterface<IEntityTransferModule>();
477 string version = String.Empty;
478 Vector3 newpos = Vector3.Zero;
479 string failureReason = String.Empty;
480 OpenSim.Services.Interfaces.GridRegion destination = null;
481  
482 if (m_rootPart.KeyframeMotion != null)
483 m_rootPart.KeyframeMotion.StartCrossingCheck();
484  
485 bool canCross = true;
486 foreach (ScenePresence av in GetSittingAvatars())
487 {
488 // We need to cross these agents. First, let's find
489 // out if any of them can't cross for some reason.
490 // We have to deny the crossing entirely if any
491 // of them are banned. Alternatively, we could
492 // unsit banned agents....
493  
494  
495 // We set the avatar position as being the object
496 // position to get the region to send to
497 if ((destination = entityTransfer.GetDestination(m_scene, av.UUID, val, out version, out newpos, out failureReason)) == null)
498 {
499 canCross = false;
500 break;
501 }
502  
503 m_log.DebugFormat("[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}", av.Name, destination.RegionName);
504 }
505  
506 if (canCross)
507 {
508 // We unparent the SP quietly so that it won't
509 // be made to stand up
510  
511 List<avtocrossInfo> avsToCross = new List<avtocrossInfo>();
512  
513 foreach (ScenePresence av in GetSittingAvatars())
514 {
515 avtocrossInfo avinfo = new avtocrossInfo();
516 SceneObjectPart parentPart = m_scene.GetSceneObjectPart(av.ParentID);
517 if (parentPart != null)
518 av.ParentUUID = parentPart.UUID;
519  
520 avinfo.av = av;
521 avinfo.ParentID = av.ParentID;
522 avsToCross.Add(avinfo);
523  
524 av.PrevSitOffset = av.OffsetPosition;
525 av.ParentID = 0;
526 }
527  
528 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
529  
530 // Normalize
531 if (val.X >= m_scene.RegionInfo.RegionSizeX)
532 val.X -= m_scene.RegionInfo.RegionSizeX;
533 if (val.Y >= m_scene.RegionInfo.RegionSizeY)
534 val.Y -= m_scene.RegionInfo.RegionSizeY;
535 if (val.X < 0)
536 val.X += m_scene.RegionInfo.RegionSizeX;
537 if (val.Y < 0)
538 val.Y += m_scene.RegionInfo.RegionSizeY;
539  
540 // If it's deleted, crossing was successful
541 if (IsDeleted)
542 {
543 foreach (avtocrossInfo avinfo in avsToCross)
544 {
545 ScenePresence av = avinfo.av;
546 if (!av.IsInTransit) // just in case...
547 {
548 m_log.DebugFormat("[SCENE OBJECT]: Crossing avatar {0} to {1}", av.Name, val);
549  
550 av.IsInTransit = true;
551  
552 // A temporary measure to allow regression tests to work.
553 // Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget
554 // or similar since BeginInvoke() always uses the system threadpool to launch
555 // threads rather than any replace threadpool that we might be using.
556 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
557 {
558 entityTransfer.CrossAgentToNewRegionAsync(av, val, destination, av.Flying, version);
559 CrossAgentToNewRegionCompleted(av);
560 }
561 else
562 {
563 CrossAgentToNewRegionDelegate d = entityTransfer.CrossAgentToNewRegionAsync;
564 d.BeginInvoke(
565 av, val, destination, av.Flying, version,
566 ar => CrossAgentToNewRegionCompleted(d.EndInvoke(ar)), null);
567 }
568 }
569 else
570 {
571 m_log.DebugFormat("[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit", av.Name, val);
572 }
573 }
574  
575 return;
576 }
577 else // cross failed, put avas back ??
578 {
579 foreach (avtocrossInfo avinfo in avsToCross)
580 {
581 ScenePresence av = avinfo.av;
582 av.ParentUUID = UUID.Zero;
583 av.ParentID = avinfo.ParentID;
584 }
585 }
586 }
587 else
588 {
589 if (m_rootPart.KeyframeMotion != null)
590 m_rootPart.KeyframeMotion.CrossingFailure();
591  
592 if (RootPart.PhysActor != null)
593 {
594 RootPart.PhysActor.CrossingFailure();
595 }
596 }
597  
598 Vector3 oldp = AbsolutePosition;
599 val.X = Util.Clamp<float>(oldp.X, 0.5f, (float)m_scene.RegionInfo.RegionSizeX - 0.5f);
600 val.Y = Util.Clamp<float>(oldp.Y, 0.5f, (float)m_scene.RegionInfo.RegionSizeY - 0.5f);
601 val.Z = Util.Clamp<float>(oldp.Z, 0.5f, Constants.RegionHeight);
602 }
603 }
604  
605 if (RootPart.GetStatusSandbox())
606 {
607 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, value) > 10)
608 {
609 RootPart.ScriptSetPhysicsStatus(false);
610  
611 if (Scene != null)
612 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
613 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
614  
615 return;
616 }
617 }
618  
619 // Restuff the new GroupPosition into each SOP of the linkset.
620 // This has the affect of resetting and tainting the physics actors.
621 SceneObjectPart[] parts = m_parts.GetArray();
622 for (int i = 0; i < parts.Length; i++)
623 parts[i].GroupPosition = val;
624  
625 //if (m_rootPart.PhysActor != null)
626 //{
627 //m_rootPart.PhysActor.Position =
628 //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y,
629 //m_rootPart.GroupPosition.Z);
630 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
631 //}
632  
633 if (Scene != null)
634 Scene.EventManager.TriggerParcelPrimCountTainted();
635 }
636 }
637  
638 public override Vector3 Velocity
639 {
640 get { return RootPart.Velocity; }
641 set { RootPart.Velocity = value; }
642 }
643  
644 private void CrossAgentToNewRegionCompleted(ScenePresence agent)
645 {
646 //// If the cross was successful, this agent is a child agent
647 if (agent.IsChildAgent)
648 {
649 if (agent.ParentUUID != UUID.Zero)
650 {
651 agent.ParentPart = null;
652 // agent.ParentPosition = Vector3.Zero;
653 // agent.ParentUUID = UUID.Zero;
654 }
655 }
656  
657 agent.ParentUUID = UUID.Zero;
658 // agent.Reset();
659 // else // Not successful
660 // agent.RestoreInCurrentScene();
661  
662 // In any case
663 agent.IsInTransit = false;
664  
665 m_log.DebugFormat("[SCENE OBJECT]: Crossing agent {0} {1} completed.", agent.Firstname, agent.Lastname);
666 }
667  
668 public override uint LocalId
669 {
670 get { return m_rootPart.LocalId; }
671 set { m_rootPart.LocalId = value; }
672 }
673  
674 public override UUID UUID
675 {
676 get { return m_rootPart.UUID; }
677 set
678 {
679 lock (m_parts.SyncRoot)
680 {
681 m_parts.Remove(m_rootPart.UUID);
682 m_rootPart.UUID = value;
683 m_parts.Add(value, m_rootPart);
684 }
685 }
686 }
687  
688 public UUID LastOwnerID
689 {
690 get { return m_rootPart.LastOwnerID; }
691 set { m_rootPart.LastOwnerID = value; }
692 }
693  
694 public UUID OwnerID
695 {
696 get { return m_rootPart.OwnerID; }
697 set { m_rootPart.OwnerID = value; }
698 }
699  
700 public float Damage
701 {
702 get { return m_rootPart.Damage; }
703 set { m_rootPart.Damage = value; }
704 }
705  
706 public Color Color
707 {
708 get { return m_rootPart.Color; }
709 set { m_rootPart.Color = value; }
710 }
711  
712 public string Text
713 {
714 get {
715 string returnstr = m_rootPart.Text;
716 if (returnstr.Length > 255)
717 {
718 returnstr = returnstr.Substring(0, 255);
719 }
720 return returnstr;
721 }
722 set { m_rootPart.Text = value; }
723 }
724  
725 /// <summary>
726 /// If set to true then the scene object can be backed up in principle, though this will only actually occur
727 /// if Backup is set. If false then the scene object will never be backed up, Backup will always be false.
728 /// </summary>
729 protected virtual bool CanBeBackedUp
730 {
731 get { return true; }
732 }
733  
734 public bool IsSelected
735 {
736 get { return m_isSelected; }
737 set
738 {
739 m_isSelected = value;
740 // Tell physics engine that group is selected
741  
742 PhysicsActor pa = m_rootPart.PhysActor;
743 if (pa != null)
744 {
745 pa.Selected = value;
746  
747 // Pass it on to the children.
748 SceneObjectPart[] parts = m_parts.GetArray();
749 for (int i = 0; i < parts.Length; i++)
750 {
751 SceneObjectPart child = parts[i];
752  
753 PhysicsActor childPa = child.PhysActor;
754 if (childPa != null)
755 childPa.Selected = value;
756 }
757 }
758 if (RootPart.KeyframeMotion != null)
759 RootPart.KeyframeMotion.Selected = value;
760 }
761 }
762  
763 private SceneObjectPart m_PlaySoundMasterPrim = null;
764 public SceneObjectPart PlaySoundMasterPrim
765 {
766 get { return m_PlaySoundMasterPrim; }
767 set { m_PlaySoundMasterPrim = value; }
768 }
769  
770 private List<SceneObjectPart> m_PlaySoundSlavePrims = new List<SceneObjectPart>();
771 public List<SceneObjectPart> PlaySoundSlavePrims
772 {
773 get { return m_PlaySoundSlavePrims; }
774 set { m_PlaySoundSlavePrims = value; }
775 }
776  
777 private SceneObjectPart m_LoopSoundMasterPrim = null;
778 public SceneObjectPart LoopSoundMasterPrim
779 {
780 get { return m_LoopSoundMasterPrim; }
781 set { m_LoopSoundMasterPrim = value; }
782 }
783  
784 private List<SceneObjectPart> m_LoopSoundSlavePrims = new List<SceneObjectPart>();
785 public List<SceneObjectPart> LoopSoundSlavePrims
786 {
787 get { return m_LoopSoundSlavePrims; }
788 set { m_LoopSoundSlavePrims = value; }
789 }
790  
791 /// <summary>
792 /// The UUID for the region this object is in.
793 /// </summary>
794 public UUID RegionUUID
795 {
796 get
797 {
798 if (m_scene != null)
799 {
800 return m_scene.RegionInfo.RegionID;
801 }
802 return UUID.Zero;
803 }
804 }
805  
806 /// <summary>
807 /// The item ID that this object was rezzed from, if applicable.
808 /// </summary>
809 /// <remarks>
810 /// If not applicable will be UUID.Zero
811 /// </remarks>
812 public UUID FromItemID { get; set; }
813  
814 /// <summary>
815 /// Refers to the SceneObjectPart.UUID property of the object that this object was rezzed from, if applicable.
816 /// </summary>
817 /// <remarks>
818 /// If not applicable will be UUID.Zero
819 /// </remarks>
820 public UUID FromPartID { get; set; }
821  
822 /// <summary>
823 /// The folder ID that this object was rezzed from, if applicable.
824 /// </summary>
825 /// <remarks>
826 /// If not applicable will be UUID.Zero
827 /// </remarks>
828 public UUID FromFolderID { get; set; }
829  
830 /// <summary>
831 /// If true then grabs are blocked no matter what the individual part BlockGrab setting.
832 /// </summary>
833 /// <value><c>true</c> if block grab override; otherwise, <c>false</c>.</value>
834 public bool BlockGrabOverride { get; set; }
835  
836 /// <summary>
837 /// IDs of all avatars sat on this scene object.
838 /// </summary>
839 /// <remarks>
840 /// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts.
841 /// This must be locked before it is read or written.
842 /// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions.
843 /// No avatar should appear more than once in this list.
844 /// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
845 /// </remarks>
846 protected internal List<ScenePresence> m_sittingAvatars = new List<ScenePresence>();
847  
848 #endregion
849  
850 // ~SceneObjectGroup()
851 // {
852 // //m_log.DebugFormat("[SCENE OBJECT GROUP]: Destructor called for {0}, local id {1}", Name, LocalId);
853 // Console.WriteLine("Destructor called for {0}, local id {1}", Name, LocalId);
854 // }
855  
856 #region Constructors
857  
858 /// <summary>
859 /// Constructor
860 /// </summary>
861 public SceneObjectGroup()
862 {
863 }
864  
865 /// <summary>
866 /// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
867 /// The original SceneObjectPart will be used rather than a copy, preserving
868 /// its existing localID and UUID.
869 /// </summary>
870 /// <param name='part'>Root part for this scene object.</param>
871 public SceneObjectGroup(SceneObjectPart part) : this()
872 {
873 SetRootPart(part);
874 }
875  
876 /// <summary>
877 /// Constructor. This object is added to the scene later via AttachToScene()
878 /// </summary>
879 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
880 :this(new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero))
881 {
882 }
883  
884 /// <summary>
885 /// Constructor.
886 /// </summary>
887 public SceneObjectGroup(UUID ownerID, Vector3 pos, PrimitiveBaseShape shape)
888 : this(ownerID, pos, Quaternion.Identity, shape)
889 {
890 }
891  
892 public void LoadScriptState(XmlDocument doc)
893 {
894 XmlNodeList nodes = doc.GetElementsByTagName("SavedScriptState");
895 if (nodes.Count > 0)
896 {
897 if (m_savedScriptState == null)
898 m_savedScriptState = new Dictionary<UUID, string>();
899 foreach (XmlNode node in nodes)
900 {
901 if (node.Attributes["UUID"] != null)
902 {
903 UUID itemid = new UUID(node.Attributes["UUID"].Value);
904 if (itemid != UUID.Zero)
905 m_savedScriptState[itemid] = node.InnerXml;
906 }
907 }
908 }
909 }
910  
911 public void LoadScriptState(XmlReader reader)
912 {
913 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Looking for script state for {0} in {1}", Name);
914  
915 while (reader.ReadToFollowing("SavedScriptState"))
916 {
917 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Loading script state for {0}", Name);
918  
919 if (m_savedScriptState == null)
920 m_savedScriptState = new Dictionary<UUID, string>();
921  
922 string uuid = reader.GetAttribute("UUID");
923  
924 if (uuid != null)
925 {
926 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Found state for item ID {0} in object {1}", uuid, Name);
927  
928 UUID itemid = new UUID(uuid);
929 if (itemid != UUID.Zero)
930 m_savedScriptState[itemid] = reader.ReadInnerXml();
931 }
932 else
933 {
934 m_log.WarnFormat("[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}", Name);
935 }
936 }
937 }
938  
939 /// <summary>
940 /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes.
941 /// </summary>
942 public virtual void AttachToBackup()
943 {
944 if (CanBeBackedUp)
945 {
946 //m_log.DebugFormat(
947 // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
948  
949 if (!Backup)
950 m_scene.EventManager.OnBackup += ProcessBackup;
951  
952 Backup = true;
953 }
954 }
955  
956 /// <summary>
957 /// Attach this object to a scene. It will also now appear to agents.
958 /// </summary>
959 /// <param name="scene"></param>
960 public void AttachToScene(Scene scene)
961 {
962 m_scene = scene;
963 RegionHandle = m_scene.RegionInfo.RegionHandle;
964  
965 if (m_rootPart.Shape.PCode != 9 || m_rootPart.Shape.State == 0)
966 m_rootPart.ParentID = 0;
967 if (m_rootPart.LocalId == 0)
968 m_rootPart.LocalId = m_scene.AllocateLocalId();
969  
970 SceneObjectPart[] parts = m_parts.GetArray();
971 for (int i = 0; i < parts.Length; i++)
972 {
973 SceneObjectPart part = parts[i];
974 if (part.KeyframeMotion != null)
975 {
976 part.KeyframeMotion.UpdateSceneObject(this);
977 }
978  
979 if (Object.ReferenceEquals(part, m_rootPart))
980 continue;
981  
982 if (part.LocalId == 0)
983 part.LocalId = m_scene.AllocateLocalId();
984  
985 part.ParentID = m_rootPart.LocalId;
986 //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);
987 }
988  
989 ApplyPhysics();
990  
991 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
992 // for the same object with very different properties. The caller must schedule the update.
993 //ScheduleGroupForFullUpdate();
994 }
995  
996 public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
997 {
998 // We got a request from the inner_scene to raytrace along the Ray hRay
999 // We're going to check all of the prim in this group for intersection with the ray
1000 // If we get a result, we're going to find the closest result to the origin of the ray
1001 // and send back the intersection information back to the innerscene.
1002  
1003 EntityIntersection result = new EntityIntersection();
1004  
1005 SceneObjectPart[] parts = m_parts.GetArray();
1006 for (int i = 0; i < parts.Length; i++)
1007 {
1008 SceneObjectPart part = parts[i];
1009  
1010 // Temporary commented to stop compiler warning
1011 //Vector3 partPosition =
1012 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
1013 Quaternion parentrotation = GroupRotation;
1014  
1015 // Telling the prim to raytrace.
1016 //EntityIntersection inter = part.TestIntersection(hRay, parentrotation);
1017  
1018 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
1019  
1020 // This may need to be updated to the maximum draw distance possible..
1021 // We might (and probably will) be checking for prim creation from other sims
1022 // when the camera crosses the border.
1023 float idist = Constants.RegionSize;
1024  
1025 if (inter.HitTF)
1026 {
1027 // We need to find the closest prim to return to the testcaller along the ray
1028 if (inter.distance < idist)
1029 {
1030 result.HitTF = true;
1031 result.ipoint = inter.ipoint;
1032 result.obj = part;
1033 result.normal = inter.normal;
1034 result.distance = inter.distance;
1035 }
1036 }
1037 }
1038  
1039 return result;
1040 }
1041  
1042 /// <summary>
1043 /// Gets a vector representing the size of the bounding box containing all the prims in the group
1044 /// Treats all prims as rectangular, so no shape (cut etc) is taken into account
1045 /// offsetHeight is the offset in the Z axis from the centre of the bounding box to the centre of the root prim
1046 /// </summary>
1047 /// <returns></returns>
1048 public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY, out float minZ, out float maxZ)
1049 {
1050 maxX = -256f;
1051 maxY = -256f;
1052 maxZ = -256f;
1053 minX = 10000f;
1054 minY = 10000f;
1055 minZ = 10000f;
1056  
1057 SceneObjectPart[] parts = m_parts.GetArray();
1058 for (int i = 0; i < parts.Length; i++)
1059 {
1060 SceneObjectPart part = parts[i];
1061  
1062 Vector3 worldPos = part.GetWorldPosition();
1063 Vector3 offset = worldPos - AbsolutePosition;
1064 Quaternion worldRot;
1065 if (part.ParentID == 0)
1066 worldRot = part.RotationOffset;
1067 else
1068 worldRot = part.GetWorldRotation();
1069  
1070 Vector3 frontTopLeft;
1071 Vector3 frontTopRight;
1072 Vector3 frontBottomLeft;
1073 Vector3 frontBottomRight;
1074  
1075 Vector3 backTopLeft;
1076 Vector3 backTopRight;
1077 Vector3 backBottomLeft;
1078 Vector3 backBottomRight;
1079  
1080 Vector3 orig = Vector3.Zero;
1081  
1082 frontTopLeft.X = orig.X - (part.Scale.X / 2);
1083 frontTopLeft.Y = orig.Y - (part.Scale.Y / 2);
1084 frontTopLeft.Z = orig.Z + (part.Scale.Z / 2);
1085  
1086 frontTopRight.X = orig.X - (part.Scale.X / 2);
1087 frontTopRight.Y = orig.Y + (part.Scale.Y / 2);
1088 frontTopRight.Z = orig.Z + (part.Scale.Z / 2);
1089  
1090 frontBottomLeft.X = orig.X - (part.Scale.X / 2);
1091 frontBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
1092 frontBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
1093  
1094 frontBottomRight.X = orig.X - (part.Scale.X / 2);
1095 frontBottomRight.Y = orig.Y + (part.Scale.Y / 2);
1096 frontBottomRight.Z = orig.Z - (part.Scale.Z / 2);
1097  
1098 backTopLeft.X = orig.X + (part.Scale.X / 2);
1099 backTopLeft.Y = orig.Y - (part.Scale.Y / 2);
1100 backTopLeft.Z = orig.Z + (part.Scale.Z / 2);
1101  
1102 backTopRight.X = orig.X + (part.Scale.X / 2);
1103 backTopRight.Y = orig.Y + (part.Scale.Y / 2);
1104 backTopRight.Z = orig.Z + (part.Scale.Z / 2);
1105  
1106 backBottomLeft.X = orig.X + (part.Scale.X / 2);
1107 backBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
1108 backBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
1109  
1110 backBottomRight.X = orig.X + (part.Scale.X / 2);
1111 backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
1112 backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
1113  
1114 frontTopLeft = frontTopLeft * worldRot;
1115 frontTopRight = frontTopRight * worldRot;
1116 frontBottomLeft = frontBottomLeft * worldRot;
1117 frontBottomRight = frontBottomRight * worldRot;
1118  
1119 backBottomLeft = backBottomLeft * worldRot;
1120 backBottomRight = backBottomRight * worldRot;
1121 backTopLeft = backTopLeft * worldRot;
1122 backTopRight = backTopRight * worldRot;
1123  
1124  
1125 frontTopLeft += offset;
1126 frontTopRight += offset;
1127 frontBottomLeft += offset;
1128 frontBottomRight += offset;
1129  
1130 backBottomLeft += offset;
1131 backBottomRight += offset;
1132 backTopLeft += offset;
1133 backTopRight += offset;
1134  
1135 if (frontTopRight.X > maxX)
1136 maxX = frontTopRight.X;
1137 if (frontTopLeft.X > maxX)
1138 maxX = frontTopLeft.X;
1139 if (frontBottomRight.X > maxX)
1140 maxX = frontBottomRight.X;
1141 if (frontBottomLeft.X > maxX)
1142 maxX = frontBottomLeft.X;
1143  
1144 if (backTopRight.X > maxX)
1145 maxX = backTopRight.X;
1146 if (backTopLeft.X > maxX)
1147 maxX = backTopLeft.X;
1148 if (backBottomRight.X > maxX)
1149 maxX = backBottomRight.X;
1150 if (backBottomLeft.X > maxX)
1151 maxX = backBottomLeft.X;
1152  
1153 if (frontTopRight.X < minX)
1154 minX = frontTopRight.X;
1155 if (frontTopLeft.X < minX)
1156 minX = frontTopLeft.X;
1157 if (frontBottomRight.X < minX)
1158 minX = frontBottomRight.X;
1159 if (frontBottomLeft.X < minX)
1160 minX = frontBottomLeft.X;
1161  
1162 if (backTopRight.X < minX)
1163 minX = backTopRight.X;
1164 if (backTopLeft.X < minX)
1165 minX = backTopLeft.X;
1166 if (backBottomRight.X < minX)
1167 minX = backBottomRight.X;
1168 if (backBottomLeft.X < minX)
1169 minX = backBottomLeft.X;
1170  
1171 //
1172 if (frontTopRight.Y > maxY)
1173 maxY = frontTopRight.Y;
1174 if (frontTopLeft.Y > maxY)
1175 maxY = frontTopLeft.Y;
1176 if (frontBottomRight.Y > maxY)
1177 maxY = frontBottomRight.Y;
1178 if (frontBottomLeft.Y > maxY)
1179 maxY = frontBottomLeft.Y;
1180  
1181 if (backTopRight.Y > maxY)
1182 maxY = backTopRight.Y;
1183 if (backTopLeft.Y > maxY)
1184 maxY = backTopLeft.Y;
1185 if (backBottomRight.Y > maxY)
1186 maxY = backBottomRight.Y;
1187 if (backBottomLeft.Y > maxY)
1188 maxY = backBottomLeft.Y;
1189  
1190 if (frontTopRight.Y < minY)
1191 minY = frontTopRight.Y;
1192 if (frontTopLeft.Y < minY)
1193 minY = frontTopLeft.Y;
1194 if (frontBottomRight.Y < minY)
1195 minY = frontBottomRight.Y;
1196 if (frontBottomLeft.Y < minY)
1197 minY = frontBottomLeft.Y;
1198  
1199 if (backTopRight.Y < minY)
1200 minY = backTopRight.Y;
1201 if (backTopLeft.Y < minY)
1202 minY = backTopLeft.Y;
1203 if (backBottomRight.Y < minY)
1204 minY = backBottomRight.Y;
1205 if (backBottomLeft.Y < minY)
1206 minY = backBottomLeft.Y;
1207  
1208 //
1209 if (frontTopRight.Z > maxZ)
1210 maxZ = frontTopRight.Z;
1211 if (frontTopLeft.Z > maxZ)
1212 maxZ = frontTopLeft.Z;
1213 if (frontBottomRight.Z > maxZ)
1214 maxZ = frontBottomRight.Z;
1215 if (frontBottomLeft.Z > maxZ)
1216 maxZ = frontBottomLeft.Z;
1217  
1218 if (backTopRight.Z > maxZ)
1219 maxZ = backTopRight.Z;
1220 if (backTopLeft.Z > maxZ)
1221 maxZ = backTopLeft.Z;
1222 if (backBottomRight.Z > maxZ)
1223 maxZ = backBottomRight.Z;
1224 if (backBottomLeft.Z > maxZ)
1225 maxZ = backBottomLeft.Z;
1226  
1227 if (frontTopRight.Z < minZ)
1228 minZ = frontTopRight.Z;
1229 if (frontTopLeft.Z < minZ)
1230 minZ = frontTopLeft.Z;
1231 if (frontBottomRight.Z < minZ)
1232 minZ = frontBottomRight.Z;
1233 if (frontBottomLeft.Z < minZ)
1234 minZ = frontBottomLeft.Z;
1235  
1236 if (backTopRight.Z < minZ)
1237 minZ = backTopRight.Z;
1238 if (backTopLeft.Z < minZ)
1239 minZ = backTopLeft.Z;
1240 if (backBottomRight.Z < minZ)
1241 minZ = backBottomRight.Z;
1242 if (backBottomLeft.Z < minZ)
1243 minZ = backBottomLeft.Z;
1244 }
1245 }
1246  
1247 public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
1248 {
1249 float minX;
1250 float maxX;
1251 float minY;
1252 float maxY;
1253 float minZ;
1254 float maxZ;
1255  
1256 GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
1257 Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ);
1258  
1259 offsetHeight = 0;
1260 float lower = (minZ * -1);
1261 if (lower > maxZ)
1262 {
1263 offsetHeight = lower - (boundingBox.Z / 2);
1264  
1265 }
1266 else if (maxZ > lower)
1267 {
1268 offsetHeight = maxZ - (boundingBox.Z / 2);
1269 offsetHeight *= -1;
1270 }
1271  
1272 // m_log.InfoFormat("BoundingBox is {0} , {1} , {2} ", boundingBox.X, boundingBox.Y, boundingBox.Z);
1273 return boundingBox;
1274 }
1275  
1276 #endregion
1277  
1278 public void SaveScriptedState(XmlTextWriter writer)
1279 {
1280 XmlDocument doc = new XmlDocument();
1281 Dictionary<UUID,string> states = new Dictionary<UUID,string>();
1282  
1283 SceneObjectPart[] parts = m_parts.GetArray();
1284 for (int i = 0; i < parts.Length; i++)
1285 {
1286 Dictionary<UUID, string> pstates = parts[i].Inventory.GetScriptStates();
1287 foreach (KeyValuePair<UUID, string> kvp in pstates)
1288 states.Add(kvp.Key, kvp.Value);
1289 }
1290  
1291 if (states.Count > 0)
1292 {
1293 // Now generate the necessary XML wrappings
1294 writer.WriteStartElement(String.Empty, "GroupScriptStates", String.Empty);
1295 foreach (UUID itemid in states.Keys)
1296 {
1297 doc.LoadXml(states[itemid]);
1298 writer.WriteStartElement(String.Empty, "SavedScriptState", String.Empty);
1299 writer.WriteAttributeString(String.Empty, "UUID", String.Empty, itemid.ToString());
1300 writer.WriteRaw(doc.DocumentElement.OuterXml); // Writes ScriptState element
1301 writer.WriteEndElement(); // End of SavedScriptState
1302 }
1303 writer.WriteEndElement(); // End of GroupScriptStates
1304 }
1305 }
1306  
1307  
1308 /// <summary>
1309 ///
1310 /// </summary>
1311 /// <param name="part"></param>
1312 private void SetPartAsNonRoot(SceneObjectPart part)
1313 {
1314 part.ParentID = m_rootPart.LocalId;
1315 part.ClearUndoState();
1316 }
1317  
1318 public ushort GetTimeDilation()
1319 {
1320 return Utils.FloatToUInt16(m_scene.TimeDilation, 0.0f, 1.0f);
1321 }
1322  
1323 /// <summary>
1324 /// Set a part to act as the root part for this scene object
1325 /// </summary>
1326 /// <param name="part"></param>
1327 public void SetRootPart(SceneObjectPart part)
1328 {
1329 if (part == null)
1330 throw new ArgumentNullException("Cannot give SceneObjectGroup a null root SceneObjectPart");
1331  
1332 part.SetParent(this);
1333 m_rootPart = part;
1334 if (!IsAttachment)
1335 part.ParentID = 0;
1336 part.LinkNum = 0;
1337  
1338 m_parts.Add(m_rootPart.UUID, m_rootPart);
1339 }
1340  
1341 /// <summary>
1342 /// Add a new part to this scene object. The part must already be correctly configured.
1343 /// </summary>
1344 /// <param name="part"></param>
1345 public void AddPart(SceneObjectPart part)
1346 {
1347 part.SetParent(this);
1348 part.LinkNum = m_parts.Add(part.UUID, part);
1349 if (part.LinkNum == 2)
1350 RootPart.LinkNum = 1;
1351 }
1352  
1353 /// <summary>
1354 /// Make sure that every non root part has the proper parent root part local id
1355 /// </summary>
1356 private void UpdateParentIDs()
1357 {
1358 SceneObjectPart[] parts = m_parts.GetArray();
1359 for (int i = 0; i < parts.Length; i++)
1360 {
1361 SceneObjectPart part = parts[i];
1362 if (part.UUID != m_rootPart.UUID)
1363 part.ParentID = m_rootPart.LocalId;
1364 }
1365 }
1366  
1367 public void RegenerateFullIDs()
1368 {
1369 SceneObjectPart[] parts = m_parts.GetArray();
1370 for (int i = 0; i < parts.Length; i++)
1371 parts[i].UUID = UUID.Random();
1372 }
1373  
1374 // justincc: I don't believe this hack is needed any longer, especially since the physics
1375 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1376 // this method was preventing proper reload of scene objects.
1377  
1378 // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
1379 // at region startup
1380  
1381 // teravus: After this was removed from the linking algorithm, Linked prims no longer collided
1382 // properly when non-physical if they havn't been moved. This breaks ALL builds.
1383 // see: http://opensimulator.org/mantis/view.php?id=3108
1384  
1385 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
1386 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
1387 // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute
1388 // Position has been set!
1389  
1390 public void ResetChildPrimPhysicsPositions()
1391 {
1392 // Setting this SOG's absolute position also loops through and sets the positions
1393 // of the SOP's in this SOG's linkset. This has the side affect of making sure
1394 // the physics world matches the simulated world.
1395 AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
1396  
1397 // teravus: AbsolutePosition is NOT a normal property!
1398 // the code in the getter of AbsolutePosition is significantly different then the code in the setter!
1399 // jhurliman: Then why is it a property instead of two methods?
1400 }
1401  
1402 public UUID GetPartsFullID(uint localID)
1403 {
1404 SceneObjectPart part = GetPart(localID);
1405 if (part != null)
1406 {
1407 return part.UUID;
1408 }
1409 return UUID.Zero;
1410 }
1411  
1412 public void ObjectGrabHandler(uint localId, Vector3 offsetPos, IClientAPI remoteClient)
1413 {
1414 if (m_rootPart.LocalId == localId)
1415 {
1416 OnGrabGroup(offsetPos, remoteClient);
1417 }
1418 else
1419 {
1420 SceneObjectPart part = GetPart(localId);
1421 OnGrabPart(part, offsetPos, remoteClient);
1422 }
1423 }
1424  
1425 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1426 {
1427 // m_log.DebugFormat(
1428 // "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
1429 // remoteClient.Name, part.Name, part.LocalId, offsetPos);
1430  
1431 part.StoreUndoState();
1432 part.OnGrab(offsetPos, remoteClient);
1433 }
1434  
1435 public virtual void OnGrabGroup(Vector3 offsetPos, IClientAPI remoteClient)
1436 {
1437 m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId);
1438 }
1439  
1440 /// <summary>
1441 /// Delete this group from its scene.
1442 /// </summary>
1443 /// <remarks>
1444 /// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood
1445 /// up and all avatars receive notification of its removal. Removal of the scene object from database backup
1446 /// must be handled by the caller.
1447 /// </remarks>
1448 /// <param name="silent">If true then deletion is not broadcast to clients</param>
1449 public void DeleteGroupFromScene(bool silent)
1450 {
1451 SceneObjectPart[] parts = m_parts.GetArray();
1452 for (int i = 0; i < parts.Length; i++)
1453 {
1454 SceneObjectPart part = parts[i];
1455  
1456 Scene.ForEachScenePresence(sp =>
1457 {
1458 if (!sp.IsChildAgent && sp.ParentID == part.LocalId)
1459 sp.StandUp();
1460  
1461 if (!silent)
1462 {
1463 part.ClearUpdateSchedule();
1464 if (part == m_rootPart)
1465 {
1466 if (!IsAttachment
1467 || AttachedAvatar == sp.UUID
1468 || !HasPrivateAttachmentPoint)
1469 sp.ControllingClient.SendKillObject(new List<uint> { part.LocalId });
1470 }
1471 }
1472 });
1473 }
1474 }
1475  
1476 public void AddScriptLPS(int count)
1477 {
1478 m_scene.SceneGraph.AddToScriptLPS(count);
1479 }
1480  
1481 public void AddActiveScriptCount(int count)
1482 {
1483 SceneGraph d = m_scene.SceneGraph;
1484 d.AddActiveScripts(count);
1485 }
1486  
1487 public void aggregateScriptEvents()
1488 {
1489 PrimFlags objectflagupdate = (PrimFlags)RootPart.GetEffectiveObjectFlags();
1490  
1491 scriptEvents aggregateScriptEvents = 0;
1492  
1493 SceneObjectPart[] parts = m_parts.GetArray();
1494 for (int i = 0; i < parts.Length; i++)
1495 {
1496 SceneObjectPart part = parts[i];
1497 if (part == null)
1498 continue;
1499 if (part != RootPart)
1500 part.Flags = objectflagupdate;
1501 aggregateScriptEvents |= part.AggregateScriptEvents;
1502 }
1503  
1504 m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
1505 m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
1506  
1507 if (!m_scriptListens_atTarget && !m_scriptListens_notAtTarget)
1508 {
1509 lock (m_targets)
1510 m_targets.Clear();
1511 m_scene.RemoveGroupTarget(this);
1512 }
1513 m_scriptListens_atRotTarget = ((aggregateScriptEvents & scriptEvents.at_rot_target) != 0);
1514 m_scriptListens_notAtRotTarget = ((aggregateScriptEvents & scriptEvents.not_at_rot_target) != 0);
1515  
1516 if (!m_scriptListens_atRotTarget && !m_scriptListens_notAtRotTarget)
1517 {
1518 lock (m_rotTargets)
1519 m_rotTargets.Clear();
1520 m_scene.RemoveGroupTarget(this);
1521 }
1522  
1523 ScheduleGroupForFullUpdate();
1524 }
1525  
1526 public void SetText(string text, Vector3 color, double alpha)
1527 {
1528 Color = Color.FromArgb(0xff - (int) (alpha * 0xff),
1529 (int) (color.X * 0xff),
1530 (int) (color.Y * 0xff),
1531 (int) (color.Z * 0xff));
1532 Text = text;
1533  
1534 HasGroupChanged = true;
1535 m_rootPart.ScheduleFullUpdate();
1536 }
1537  
1538 /// <summary>
1539 /// Apply physics to this group
1540 /// </summary>
1541 public void ApplyPhysics()
1542 {
1543 // Apply physics to the root prim
1544 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive);
1545  
1546 // Apply physics to child prims
1547 SceneObjectPart[] parts = m_parts.GetArray();
1548 if (parts.Length > 1)
1549 {
1550 for (int i = 0; i < parts.Length; i++)
1551 {
1552 SceneObjectPart part = parts[i];
1553 if (part.LocalId != m_rootPart.LocalId)
1554 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive);
1555 }
1556  
1557 // Hack to get the physics scene geometries in the right spot
1558 ResetChildPrimPhysicsPositions();
1559 }
1560 }
1561  
1562 public void SetOwnerId(UUID userId)
1563 {
1564 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; });
1565 }
1566  
1567 public void ForEachPart(Action<SceneObjectPart> whatToDo)
1568 {
1569 SceneObjectPart[] parts = m_parts.GetArray();
1570 for (int i = 0; i < parts.Length; i++)
1571 whatToDo(parts[i]);
1572 }
1573  
1574 #region Events
1575  
1576 /// <summary>
1577 /// Processes backup.
1578 /// </summary>
1579 /// <param name="datastore"></param>
1580 public virtual void ProcessBackup(ISimulationDataService datastore, bool forcedBackup)
1581 {
1582 if (!Backup)
1583 {
1584 // m_log.DebugFormat(
1585 // "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID);
1586 return;
1587 }
1588  
1589 if (IsDeleted || UUID == UUID.Zero)
1590 {
1591 // m_log.DebugFormat(
1592 // "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID);
1593 return;
1594 }
1595  
1596 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1597 // any exception propogate upwards.
1598 try
1599 {
1600 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart
1601 {
1602 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1603 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
1604  
1605 if (parcel != null && parcel.LandData != null &&
1606 parcel.LandData.OtherCleanTime != 0)
1607 {
1608 if (parcel.LandData.OwnerID != OwnerID &&
1609 (parcel.LandData.GroupID != GroupID ||
1610 parcel.LandData.GroupID == UUID.Zero))
1611 {
1612 if ((DateTime.UtcNow - RootPart.Rezzed).TotalMinutes >
1613 parcel.LandData.OtherCleanTime)
1614 {
1615 DetachFromBackup();
1616 m_log.DebugFormat(
1617 "[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn",
1618 RootPart.UUID);
1619 m_scene.AddReturn(OwnerID == GroupID ? LastOwnerID : OwnerID, Name, AbsolutePosition, "parcel autoreturn");
1620 m_scene.DeRezObjects(null, new List<uint>() { RootPart.LocalId }, UUID.Zero,
1621 DeRezAction.Return, UUID.Zero);
1622  
1623 return;
1624 }
1625 }
1626 }
1627 }
1628  
1629 if (m_scene.UseBackup && HasGroupChanged)
1630 {
1631 // don't backup while it's selected or you're asking for changes mid stream.
1632 if (isTimeToPersist() || forcedBackup)
1633 {
1634 // m_log.DebugFormat(
1635 // "[SCENE]: Storing {0}, {1} in {2}",
1636 // Name, UUID, m_scene.RegionInfo.RegionName);
1637  
1638 SceneObjectGroup backup_group = Copy(false);
1639 backup_group.RootPart.Velocity = RootPart.Velocity;
1640 backup_group.RootPart.Acceleration = RootPart.Acceleration;
1641 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity;
1642 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem;
1643 HasGroupChanged = false;
1644 GroupContainsForeignPrims = false;
1645  
1646 m_scene.EventManager.TriggerOnSceneObjectPreSave(backup_group, this);
1647 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1648  
1649 backup_group.ForEachPart(delegate(SceneObjectPart part)
1650 {
1651 part.Inventory.ProcessInventoryBackup(datastore);
1652 });
1653  
1654 backup_group = null;
1655 }
1656 // else
1657 // {
1658 // m_log.DebugFormat(
1659 // "[SCENE]: Did not update persistence of object {0} {1}, selected = {2}",
1660 // Name, UUID, IsSelected);
1661 // }
1662 }
1663 }
1664 catch (Exception e)
1665 {
1666 m_log.ErrorFormat(
1667 "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}",
1668 Name, UUID, m_scene.RegionInfo.RegionName, e.Message, e.StackTrace);
1669 }
1670 }
1671  
1672 #endregion
1673  
1674 /// <summary>
1675 /// Send the parts of this SOG to a single client
1676 /// </summary>
1677 /// <remarks>
1678 /// Used when the client initially connects and when client sends RequestPrim packet
1679 /// </remarks>
1680 /// <param name="remoteClient"></param>
1681 public void SendFullUpdateToClient(IClientAPI remoteClient)
1682 {
1683 RootPart.SendFullUpdate(remoteClient);
1684  
1685 SceneObjectPart[] parts = m_parts.GetArray();
1686 for (int i = 0; i < parts.Length; i++)
1687 {
1688 SceneObjectPart part = parts[i];
1689 if (part != RootPart)
1690 part.SendFullUpdate(remoteClient);
1691 }
1692 }
1693  
1694 #region Copying
1695  
1696 /// <summary>
1697 /// Duplicates this object, including operations such as physics set up and attaching to the backup event.
1698 /// </summary>
1699 /// <param name="userExposed">True if the duplicate will immediately be in the scene, false otherwise</param>
1700 /// <returns></returns>
1701 public SceneObjectGroup Copy(bool userExposed)
1702 {
1703 // FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up
1704 // with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator
1705 // but not between regions on different simulators). Really, all copying should be done explicitly.
1706 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1707  
1708 dupe.Backup = false;
1709 dupe.m_parts = new MapAndArray<OpenMetaverse.UUID, SceneObjectPart>();
1710 dupe.m_sittingAvatars = new List<ScenePresence>();
1711 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1712 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1713  
1714 if (userExposed)
1715 dupe.m_rootPart.TrimPermissions();
1716  
1717 List<SceneObjectPart> partList = new List<SceneObjectPart>(m_parts.GetArray());
1718  
1719 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1720 {
1721 return p1.LinkNum.CompareTo(p2.LinkNum);
1722 }
1723 );
1724  
1725 foreach (SceneObjectPart part in partList)
1726 {
1727 SceneObjectPart newPart;
1728 if (part.UUID != m_rootPart.UUID)
1729 {
1730 newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1731 newPart.LinkNum = part.LinkNum;
1732 }
1733 else
1734 {
1735 newPart = dupe.m_rootPart;
1736 }
1737  
1738 // Need to duplicate the physics actor as well
1739 PhysicsActor originalPartPa = part.PhysActor;
1740 if (originalPartPa != null && userExposed)
1741 {
1742 PrimitiveBaseShape pbs = newPart.Shape;
1743  
1744 newPart.PhysActor
1745 = m_scene.PhysicsScene.AddPrimShape(
1746 string.Format("{0}/{1}", newPart.Name, newPart.UUID),
1747 pbs,
1748 newPart.AbsolutePosition,
1749 newPart.Scale,
1750 newPart.RotationOffset,
1751 originalPartPa.IsPhysical,
1752 newPart.LocalId);
1753  
1754 newPart.DoPhysicsPropertyUpdate(originalPartPa.IsPhysical, true);
1755 }
1756 if (part.KeyframeMotion != null)
1757 newPart.KeyframeMotion = part.KeyframeMotion.Copy(dupe);
1758 }
1759  
1760 if (userExposed)
1761 {
1762 dupe.UpdateParentIDs();
1763 dupe.HasGroupChanged = true;
1764 dupe.AttachToBackup();
1765  
1766 ScheduleGroupForFullUpdate();
1767 }
1768  
1769 return dupe;
1770 }
1771  
1772 /// <summary>
1773 /// Copy the given part as the root part of this scene object.
1774 /// </summary>
1775 /// <param name="part"></param>
1776 /// <param name="cAgentID"></param>
1777 /// <param name="cGroupID"></param>
1778 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1779 {
1780 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, 0, userExposed));
1781 }
1782  
1783 public void ScriptSetPhysicsStatus(bool usePhysics)
1784 {
1785 if (usePhysics)
1786 {
1787 if (RootPart.KeyframeMotion != null)
1788 RootPart.KeyframeMotion.Stop();
1789 RootPart.KeyframeMotion = null;
1790 }
1791 UpdatePrimFlags(RootPart.LocalId, usePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1792 }
1793  
1794 public void ScriptSetTemporaryStatus(bool makeTemporary)
1795 {
1796 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, makeTemporary, IsPhantom, IsVolumeDetect);
1797 }
1798  
1799 public void ScriptSetPhantomStatus(bool makePhantom)
1800 {
1801 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, makePhantom, IsVolumeDetect);
1802 }
1803  
1804 public void ScriptSetVolumeDetect(bool makeVolumeDetect)
1805 {
1806 UpdatePrimFlags(RootPart.LocalId, UsesPhysics, IsTemporary, IsPhantom, makeVolumeDetect);
1807  
1808 /*
1809 ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore
1810  
1811 if (PhysActor != null) // Should always be the case now
1812 {
1813 PhysActor.SetVolumeDetect(param);
1814 }
1815 if (param != 0)
1816 AddFlag(PrimFlags.Phantom);
1817  
1818 ScheduleFullUpdate();
1819 */
1820 }
1821  
1822 public void applyImpulse(Vector3 impulse)
1823 {
1824 if (IsAttachment)
1825 {
1826 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1827 if (avatar != null)
1828 {
1829 avatar.PushForce(impulse);
1830 }
1831 }
1832 else
1833 {
1834 PhysicsActor pa = RootPart.PhysActor;
1835  
1836 if (pa != null)
1837 {
1838 pa.AddForce(impulse, true);
1839 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1840 }
1841 }
1842 }
1843  
1844 public void applyAngularImpulse(Vector3 impulse)
1845 {
1846 PhysicsActor pa = RootPart.PhysActor;
1847  
1848 if (pa != null)
1849 {
1850 if (!IsAttachment)
1851 {
1852 pa.AddAngularForce(impulse, true);
1853 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1854 }
1855 }
1856 }
1857  
1858 public void setAngularImpulse(Vector3 impulse)
1859 {
1860 PhysicsActor pa = RootPart.PhysActor;
1861  
1862 if (pa != null)
1863 {
1864 if (!IsAttachment)
1865 {
1866 pa.Torque = impulse;
1867 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
1868 }
1869 }
1870 }
1871  
1872 public Vector3 GetTorque()
1873 {
1874 PhysicsActor pa = RootPart.PhysActor;
1875  
1876 if (pa != null)
1877 {
1878 if (!IsAttachment)
1879 {
1880 Vector3 torque = pa.Torque;
1881 return torque;
1882 }
1883 }
1884  
1885 return Vector3.Zero;
1886 }
1887  
1888 public void moveToTarget(Vector3 target, float tau)
1889 {
1890 if (IsAttachment)
1891 {
1892 ScenePresence avatar = m_scene.GetScenePresence(AttachedAvatar);
1893 if (avatar != null)
1894 {
1895 avatar.MoveToTarget(target, false, false);
1896 }
1897 }
1898 else
1899 {
1900 PhysicsActor pa = RootPart.PhysActor;
1901  
1902 if (pa != null)
1903 {
1904 pa.PIDTarget = target;
1905 pa.PIDTau = tau;
1906 pa.PIDActive = true;
1907 }
1908 }
1909 }
1910  
1911 public void stopMoveToTarget()
1912 {
1913 PhysicsActor pa = RootPart.PhysActor;
1914  
1915 if (pa != null)
1916 pa.PIDActive = false;
1917 }
1918  
1919 /// <summary>
1920 /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
1921 /// </summary>
1922 /// <param name="height">Height to hover. Height of zero disables hover.</param>
1923 /// <param name="hoverType">Determines what the height is relative to </param>
1924 /// <param name="tau">Number of seconds over which to reach target</param>
1925 public void SetHoverHeight(float height, PIDHoverType hoverType, float tau)
1926 {
1927 PhysicsActor pa = RootPart.PhysActor;
1928  
1929 if (pa != null)
1930 {
1931 if (height != 0f)
1932 {
1933 pa.PIDHoverHeight = height;
1934 pa.PIDHoverType = hoverType;
1935 pa.PIDTau = tau;
1936 pa.PIDHoverActive = true;
1937 }
1938 else
1939 {
1940 pa.PIDHoverActive = false;
1941 }
1942 }
1943 }
1944  
1945 /// <summary>
1946 /// Set the owner of the root part.
1947 /// </summary>
1948 /// <param name="part"></param>
1949 /// <param name="cAgentID"></param>
1950 /// <param name="cGroupID"></param>
1951 public void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
1952 {
1953 part.LastOwnerID = part.OwnerID;
1954 part.OwnerID = cAgentID;
1955 part.GroupID = cGroupID;
1956  
1957 if (part.OwnerID != cAgentID)
1958 {
1959 // Apply Next Owner Permissions if we're not bypassing permissions
1960 if (!m_scene.Permissions.BypassPermissions())
1961 ApplyNextOwnerPermissions();
1962 }
1963  
1964 part.ScheduleFullUpdate();
1965 }
1966  
1967 /// <summary>
1968 /// Make a copy of the given part.
1969 /// </summary>
1970 /// <param name="part"></param>
1971 /// <param name="cAgentID"></param>
1972 /// <param name="cGroupID"></param>
1973 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1974 {
1975 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1976 AddPart(newPart);
1977  
1978 SetPartAsNonRoot(newPart);
1979 return newPart;
1980 }
1981  
1982 /// <summary>
1983 /// Reset the UUIDs for all the prims that make up this group.
1984 /// </summary>
1985 /// <remarks>
1986 /// This is called by methods which want to add a new group to an existing scene, in order
1987 /// to ensure that there are no clashes with groups already present.
1988 /// </remarks>
1989 public void ResetIDs()
1990 {
1991 lock (m_parts.SyncRoot)
1992 {
1993 List<SceneObjectPart> partsList = new List<SceneObjectPart>(m_parts.GetArray());
1994 m_parts.Clear();
1995 foreach (SceneObjectPart part in partsList)
1996 {
1997 part.ResetIDs(part.LinkNum); // Don't change link nums
1998 m_parts.Add(part.UUID, part);
1999 }
2000 }
2001 }
2002  
2003 /// <summary>
2004 ///
2005 /// </summary>
2006 /// <param name="part"></param>
2007 public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
2008 {
2009 remoteClient.SendObjectPropertiesFamilyData(RootPart, RequestFlags);
2010  
2011 // remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
2012 // RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
2013 // RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
2014 // RootPart.CreatorID, RootPart.Name, RootPart.Description);
2015 }
2016  
2017 public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
2018 {
2019 part.OwnerID = cAgentID;
2020 part.GroupID = cGroupID;
2021 }
2022  
2023 #endregion
2024  
2025 public override void Update()
2026 {
2027 // Check that the group was not deleted before the scheduled update
2028 // FIXME: This is merely a temporary measure to reduce the incidence of failure when
2029 // an object has been deleted from a scene before update was processed.
2030 // A more fundamental overhaul of the update mechanism is required to eliminate all
2031 // the race conditions.
2032 if (IsDeleted)
2033 return;
2034  
2035 // Even temporary objects take part in physics (e.g. temp-on-rez bullets)
2036 //if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
2037 // return;
2038  
2039 // If we somehow got here to updating the SOG and its root part is not scheduled for update,
2040 // check to see if the physical position or rotation warrant an update.
2041 if (m_rootPart.UpdateFlag == UpdateRequired.NONE)
2042 {
2043 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
2044  
2045 if (UsePhysics && !AbsolutePosition.ApproxEquals(lastPhysGroupPos, 0.02f))
2046 {
2047 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2048 lastPhysGroupPos = AbsolutePosition;
2049 }
2050  
2051 if (UsePhysics && !GroupRotation.ApproxEquals(lastPhysGroupRot, 0.1f))
2052 {
2053 m_rootPart.UpdateFlag = UpdateRequired.TERSE;
2054 lastPhysGroupRot = GroupRotation;
2055 }
2056 }
2057  
2058 SceneObjectPart[] parts = m_parts.GetArray();
2059 for (int i = 0; i < parts.Length; i++)
2060 {
2061 SceneObjectPart part = parts[i];
2062 if (!IsSelected)
2063 part.UpdateLookAt();
2064 part.SendScheduledUpdates();
2065 }
2066 }
2067  
2068 /// <summary>
2069 /// Schedule a full update for this scene object to all interested viewers.
2070 /// </summary>
2071 /// <remarks>
2072 /// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations
2073 /// so that either all changes are sent at once. However, currently, a large amount of internal
2074 /// code will set this anyway when some object properties are changed.
2075 /// </remarks>
2076 public void ScheduleGroupForFullUpdate()
2077 {
2078 // if (IsAttachment)
2079 // m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId);
2080  
2081 checkAtTargets();
2082 RootPart.ScheduleFullUpdate();
2083  
2084 SceneObjectPart[] parts = m_parts.GetArray();
2085 for (int i = 0; i < parts.Length; i++)
2086 {
2087 SceneObjectPart part = parts[i];
2088 if (part != RootPart)
2089 part.ScheduleFullUpdate();
2090 }
2091 }
2092  
2093 /// <summary>
2094 /// Schedule a terse update for this scene object to all interested viewers.
2095 /// </summary>
2096 /// <remarks>
2097 /// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations
2098 /// so that either all changes are sent at once. However, currently, a large amount of internal
2099 /// code will set this anyway when some object properties are changed.
2100 /// </remarks>
2101 public void ScheduleGroupForTerseUpdate()
2102 {
2103 // m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID);
2104  
2105 SceneObjectPart[] parts = m_parts.GetArray();
2106 for (int i = 0; i < parts.Length; i++)
2107 parts[i].ScheduleTerseUpdate();
2108 }
2109  
2110 /// <summary>
2111 /// Immediately send a full update for this scene object.
2112 /// </summary>
2113 public void SendGroupFullUpdate()
2114 {
2115 if (IsDeleted)
2116 return;
2117  
2118 // m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2119  
2120 RootPart.SendFullUpdateToAllClients();
2121  
2122 SceneObjectPart[] parts = m_parts.GetArray();
2123 for (int i = 0; i < parts.Length; i++)
2124 {
2125 SceneObjectPart part = parts[i];
2126 if (part != RootPart)
2127 part.SendFullUpdateToAllClients();
2128 }
2129 }
2130  
2131 /// <summary>
2132 /// Immediately send an update for this scene object's root prim only.
2133 /// This is for updates regarding the object as a whole, and none of its parts in particular.
2134 /// Note: this may not be used by opensim (it probably should) but it's used by
2135 /// external modules.
2136 /// </summary>
2137 public void SendGroupRootTerseUpdate()
2138 {
2139 if (IsDeleted)
2140 return;
2141  
2142 RootPart.SendTerseUpdateToAllClients();
2143 }
2144  
2145 public void QueueForUpdateCheck()
2146 {
2147 if (m_scene == null) // Need to check here as it's null during object creation
2148 return;
2149  
2150 m_scene.SceneGraph.AddToUpdateList(this);
2151 }
2152  
2153 /// <summary>
2154 /// Immediately send a terse update for this scene object.
2155 /// </summary>
2156 public void SendGroupTerseUpdate()
2157 {
2158 if (IsDeleted)
2159 return;
2160  
2161 SceneObjectPart[] parts = m_parts.GetArray();
2162 for (int i = 0; i < parts.Length; i++)
2163 parts[i].SendTerseUpdateToAllClients();
2164 }
2165  
2166 /// <summary>
2167 /// Send metadata about the root prim (name, description, sale price, permissions, etc.) to a client.
2168 /// </summary>
2169 /// <param name="client"></param>
2170 public void SendPropertiesToClient(IClientAPI client)
2171 {
2172 m_rootPart.SendPropertiesToClient(client);
2173 }
2174  
2175 #region SceneGroupPart Methods
2176  
2177 /// <summary>
2178 /// Get the child part by LinkNum
2179 /// </summary>
2180 /// <param name="linknum"></param>
2181 /// <returns>null if no child part with that linknum or child part</returns>
2182 public SceneObjectPart GetLinkNumPart(int linknum)
2183 {
2184 SceneObjectPart[] parts = m_parts.GetArray();
2185 for (int i = 0; i < parts.Length; i++)
2186 {
2187 if (parts[i].LinkNum == linknum)
2188 return parts[i];
2189 }
2190  
2191 return null;
2192 }
2193  
2194 /// <summary>
2195 /// Get a part with a given UUID
2196 /// </summary>
2197 /// <param name="primID"></param>
2198 /// <returns>null if a part with the primID was not found</returns>
2199 public SceneObjectPart GetPart(UUID primID)
2200 {
2201 SceneObjectPart childPart;
2202 m_parts.TryGetValue(primID, out childPart);
2203 return childPart;
2204 }
2205  
2206 /// <summary>
2207 /// Get a part with a given local ID
2208 /// </summary>
2209 /// <param name="localID"></param>
2210 /// <returns>null if a part with the local ID was not found</returns>
2211 public SceneObjectPart GetPart(uint localID)
2212 {
2213 SceneObjectPart[] parts = m_parts.GetArray();
2214 for (int i = 0; i < parts.Length; i++)
2215 {
2216 if (parts[i].LocalId == localID)
2217 return parts[i];
2218 }
2219  
2220 return null;
2221 }
2222  
2223 #endregion
2224  
2225 #region Packet Handlers
2226  
2227 /// <summary>
2228 /// Link the prims in a given group to this group
2229 /// </summary>
2230 /// <remarks>
2231 /// Do not call this method directly - use Scene.LinkObjects() instead to avoid races between threads.
2232 /// FIXME: There are places where scripts call these methods directly without locking. This is a potential race condition.
2233 /// </remarks>
2234 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
2235 public void LinkToGroup(SceneObjectGroup objectGroup)
2236 {
2237 LinkToGroup(objectGroup, false);
2238 }
2239  
2240 // Link an existing group to this group.
2241 // The group being linked need not be a linkset -- it can have just one prim.
2242 public void LinkToGroup(SceneObjectGroup objectGroup, bool insert)
2243 {
2244 // m_log.DebugFormat(
2245 // "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
2246 // objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
2247  
2248 // Linking to ourselves is not a valid operation.
2249 if (objectGroup == this)
2250 return;
2251  
2252 // If the configured linkset capacity is greater than zero,
2253 // and the new linkset would have a prim count higher than this
2254 // value, do not link it.
2255 if (m_scene.m_linksetCapacity > 0 &&
2256 (PrimCount + objectGroup.PrimCount) >
2257 m_scene.m_linksetCapacity)
2258 {
2259 m_log.DebugFormat(
2260 "[SCENE OBJECT GROUP]: Cannot link group with root" +
2261 " part {0}, {1} ({2} prims) to group with root part" +
2262 " {3}, {4} ({5} prims) because the new linkset" +
2263 " would exceed the configured maximum of {6}",
2264 objectGroup.RootPart.Name, objectGroup.RootPart.UUID,
2265 objectGroup.PrimCount, RootPart.Name, RootPart.UUID,
2266 PrimCount, m_scene.m_linksetCapacity);
2267  
2268 return;
2269 }
2270  
2271 // 'linkPart' == the root of the group being linked into this group
2272 SceneObjectPart linkPart = objectGroup.m_rootPart;
2273  
2274 // physics flags from group to be applied to linked parts
2275 bool grpusephys = UsesPhysics;
2276 bool grptemporary = IsTemporary;
2277  
2278 // Remember where the group being linked thought it was
2279 Vector3 oldGroupPosition = linkPart.GroupPosition;
2280 Quaternion oldRootRotation = linkPart.RotationOffset;
2281  
2282 // A linked SOP remembers its location and rotation relative to the root of a group.
2283 // Convert the root of the group being linked to be relative to the
2284 // root of the group being linked to.
2285 // Note: Some of the assignments have complex side effects.
2286  
2287 // First move the new group's root SOP's position to be relative to ours
2288 // (radams1: Not sure if the multiple setting of OffsetPosition is required. If not,
2289 // this code can be reordered to have a more logical flow.)
2290 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
2291 // Assign the new parent to the root of the old group
2292 linkPart.ParentID = m_rootPart.LocalId;
2293 // Now that it's a child, it's group position is our root position
2294 linkPart.GroupPosition = AbsolutePosition;
2295  
2296 Vector3 axPos = linkPart.OffsetPosition;
2297 // Rotate the linking root SOP's position to be relative to the new root prim
2298 Quaternion parentRot = m_rootPart.RotationOffset;
2299 axPos *= Quaternion.Inverse(parentRot);
2300 linkPart.OffsetPosition = axPos;
2301  
2302 // Make the linking root SOP's rotation relative to the new root prim
2303 Quaternion oldRot = linkPart.RotationOffset;
2304 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
2305 linkPart.RotationOffset = newRot;
2306  
2307 // If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
2308 // Now that we know this SOG has at least two SOPs in it, the new root
2309 // SOP becomes the first in the linkset.
2310 if (m_rootPart.LinkNum == 0)
2311 m_rootPart.LinkNum = 1;
2312  
2313 lock (m_parts.SyncRoot)
2314 {
2315 // Calculate the new link number for the old root SOP
2316 int linkNum;
2317 if (insert)
2318 {
2319 linkNum = 2;
2320 foreach (SceneObjectPart part in Parts)
2321 {
2322 if (part.LinkNum > 1)
2323 part.LinkNum++;
2324 }
2325 }
2326 else
2327 {
2328 linkNum = PrimCount + 1;
2329 }
2330  
2331 // Add the old root SOP as a part in our group's list
2332 m_parts.Add(linkPart.UUID, linkPart);
2333  
2334 linkPart.SetParent(this);
2335 linkPart.CreateSelected = true;
2336  
2337 // let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
2338 linkPart.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (linkPart.Flags & PrimFlags.Phantom) != 0), linkPart.VolumeDetectActive);
2339  
2340 // If the added SOP is physical, also tell the physics engine about the link relationship.
2341 if (linkPart.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2342 {
2343 linkPart.PhysActor.link(m_rootPart.PhysActor);
2344 this.Scene.PhysicsScene.AddPhysicsActorTaint(linkPart.PhysActor);
2345 }
2346  
2347 linkPart.LinkNum = linkNum++;
2348  
2349 // Get a list of the SOP's in the old group in order of their linknum's.
2350 SceneObjectPart[] ogParts = objectGroup.Parts;
2351 Array.Sort(ogParts, delegate(SceneObjectPart a, SceneObjectPart b)
2352 {
2353 return a.LinkNum - b.LinkNum;
2354 });
2355  
2356 // Add each of the SOP's from the old linkset to our linkset
2357 for (int i = 0; i < ogParts.Length; i++)
2358 {
2359 SceneObjectPart part = ogParts[i];
2360 if (part.UUID != objectGroup.m_rootPart.UUID)
2361 {
2362 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2363  
2364 // Update the physics flags for the newly added SOP
2365 // (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2366 part.UpdatePrimFlags(grpusephys, grptemporary, (IsPhantom || (part.Flags & PrimFlags.Phantom) != 0), part.VolumeDetectActive);
2367  
2368 // If the added SOP is physical, also tell the physics engine about the link relationship.
2369 if (part.PhysActor != null && m_rootPart.PhysActor != null && m_rootPart.PhysActor.IsPhysical)
2370 {
2371 part.PhysActor.link(m_rootPart.PhysActor);
2372 this.Scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2373 }
2374 }
2375 part.ClearUndoState();
2376 }
2377 }
2378  
2379 // Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene.
2380 m_scene.UnlinkSceneObject(objectGroup, true);
2381 objectGroup.IsDeleted = true;
2382  
2383 objectGroup.m_parts.Clear();
2384  
2385 // Can't do this yet since backup still makes use of the root part without any synchronization
2386 // objectGroup.m_rootPart = null;
2387  
2388 // If linking prims with different permissions, fix them
2389 AdjustChildPrimPermissions(false);
2390  
2391 GroupContainsForeignPrims = true;
2392  
2393 AttachToBackup();
2394  
2395 // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
2396 // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
2397 // unmoved prims!
2398 ResetChildPrimPhysicsPositions();
2399  
2400 //HasGroupChanged = true;
2401 //ScheduleGroupForFullUpdate();
2402 }
2403  
2404 /// <summary>
2405 /// Delink the given prim from this group. The delinked prim is established as
2406 /// an independent SceneObjectGroup.
2407 /// </summary>
2408 /// <remarks>
2409 /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
2410 /// condition. But currently there is no
2411 /// alternative method that does take a lonk to delink a single prim.
2412 /// </remarks>
2413 /// <param name="partID"></param>
2414 /// <returns>The object group of the newly delinked prim. Null if part could not be found</returns>
2415 public SceneObjectGroup DelinkFromGroup(uint partID)
2416 {
2417 return DelinkFromGroup(partID, true);
2418 }
2419  
2420 /// <summary>
2421 /// Delink the given prim from this group. The delinked prim is established as
2422 /// an independent SceneObjectGroup.
2423 /// </summary>
2424 /// <remarks>
2425 /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
2426 /// condition. But currently there is no
2427 /// alternative method that does take a lonk to delink a single prim.
2428 /// </remarks>
2429 /// <param name="partID"></param>
2430 /// <param name="sendEvents"></param>
2431 /// <returns>The object group of the newly delinked prim. Null if part could not be found</returns>
2432 public SceneObjectGroup DelinkFromGroup(uint partID, bool sendEvents)
2433 {
2434 SceneObjectPart linkPart = GetPart(partID);
2435  
2436 if (linkPart != null)
2437 {
2438 return DelinkFromGroup(linkPart, sendEvents);
2439 }
2440 else
2441 {
2442 m_log.WarnFormat("[SCENE OBJECT GROUP]: " +
2443 "DelinkFromGroup(): Child prim {0} not found in object {1}, {2}",
2444 partID, LocalId, UUID);
2445  
2446 return null;
2447 }
2448 }
2449  
2450 /// <summary>
2451 /// Delink the given prim from this group. The delinked prim is established as
2452 /// an independent SceneObjectGroup.
2453 /// </summary>
2454 /// <remarks>
2455 /// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
2456 /// condition. But currently there is no
2457 /// alternative method that does take a lock to delink a single prim.
2458 /// </remarks>
2459 /// <param name="partID"></param>
2460 /// <param name="sendEvents"></param>
2461 /// <returns>The object group of the newly delinked prim.</returns>
2462 public SceneObjectGroup DelinkFromGroup(SceneObjectPart linkPart, bool sendEvents)
2463 {
2464 // m_log.DebugFormat(
2465 // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2466 // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2467  
2468 linkPart.ClearUndoState();
2469  
2470 Vector3 worldPos = linkPart.GetWorldPosition();
2471 Quaternion worldRot = linkPart.GetWorldRotation();
2472  
2473 // Remove the part from this object
2474 lock (m_parts.SyncRoot)
2475 {
2476 m_parts.Remove(linkPart.UUID);
2477  
2478 SceneObjectPart[] parts = m_parts.GetArray();
2479  
2480 // Rejigger the linknum's of the remaining SOP's to fill any gap
2481 if (parts.Length == 1 && RootPart != null)
2482 {
2483 // Single prim left
2484 RootPart.LinkNum = 0;
2485 }
2486 else
2487 {
2488 for (int i = 0; i < parts.Length; i++)
2489 {
2490 SceneObjectPart part = parts[i];
2491 if (part.LinkNum > linkPart.LinkNum)
2492 part.LinkNum--;
2493 }
2494 }
2495 }
2496  
2497 linkPart.ParentID = 0;
2498 linkPart.LinkNum = 0;
2499  
2500 PhysicsActor linkPartPa = linkPart.PhysActor;
2501  
2502 // Remove the SOP from the physical scene.
2503 // If the new SOG is physical, it is re-created later.
2504 // (There is a problem here in that we have not yet told the physics
2505 // engine about the delink. Someday, linksets should be made first
2506 // class objects in the physics engine interface).
2507 if (linkPartPa != null)
2508 m_scene.PhysicsScene.RemovePrim(linkPartPa);
2509  
2510 // We need to reset the child part's position
2511 // ready for life as a separate object after being a part of another object
2512  
2513 /* This commented out code seems to recompute what GetWorldPosition already does.
2514 * Replace with a call to GetWorldPosition (before unlinking)
2515 Quaternion parentRot = m_rootPart.RotationOffset;
2516 Vector3 axPos = linkPart.OffsetPosition;
2517 axPos *= parentRot;
2518 linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
2519 linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
2520 linkPart.OffsetPosition = new Vector3(0, 0, 0);
2521 */
2522 linkPart.GroupPosition = worldPos;
2523 linkPart.OffsetPosition = Vector3.Zero;
2524 linkPart.RotationOffset = worldRot;
2525  
2526 // Create a new SOG to go around this unlinked and unattached SOP
2527 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
2528  
2529 m_scene.AddNewSceneObject(objectGroup, true);
2530  
2531 if (sendEvents)
2532 linkPart.TriggerScriptChangedEvent(Changed.LINK);
2533  
2534 linkPart.Rezzed = RootPart.Rezzed;
2535  
2536 // We must persist the delinked group to the database immediately, for safety. The problem
2537 // is that although in memory the new group has a new SceneGroupID, in the database it
2538 // still has the parent group's SceneGroupID (until the next backup). This means that if the
2539 // parent group is deleted then the delinked group will also be deleted from the database.
2540 // This problem will disappear if the region remains alive long enough for another backup,
2541 // since at that time the delinked group's new SceneGroupID will be written to the database.
2542 // But if the region crashes before that then the prims will be permanently gone, and this must
2543 // not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case
2544 // because the delinked group doesn't know when the source group is deleted.)
2545 m_scene.ForceSceneObjectBackup(objectGroup);
2546  
2547 return objectGroup;
2548 }
2549  
2550 /// <summary>
2551 /// Stop this object from being persisted over server restarts.
2552 /// </summary>
2553 /// <param name="objectGroup"></param>
2554 public virtual void DetachFromBackup()
2555 {
2556 if (Backup && Scene != null)
2557 m_scene.EventManager.OnBackup -= ProcessBackup;
2558  
2559 Backup = false;
2560 }
2561  
2562 // This links an SOP from a previous linkset into my linkset.
2563 // The trick is that the SOP's position and rotation are relative to the old root SOP's
2564 // so we are passed in the position and rotation of the old linkset so this can
2565 // unjigger this SOP's position and rotation from the previous linkset and
2566 // then make them relative to my linkset root.
2567 private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum)
2568 {
2569 Quaternion parentRot = oldGroupRotation;
2570 Quaternion oldRot = part.RotationOffset;
2571  
2572 // Move our position to not be relative to the old parent
2573 Vector3 axPos = part.OffsetPosition;
2574 axPos *= parentRot;
2575 part.OffsetPosition = axPos;
2576 part.GroupPosition = oldGroupPosition + part.OffsetPosition;
2577 part.OffsetPosition = Vector3.Zero;
2578  
2579 // Compution our rotation to be not relative to the old parent
2580 Quaternion worldRot = parentRot * oldRot;
2581 part.RotationOffset = worldRot;
2582  
2583 // Add this SOP to our linkset
2584 part.SetParent(this);
2585 part.ParentID = m_rootPart.LocalId;
2586 m_parts.Add(part.UUID, part);
2587  
2588 part.LinkNum = linkNum;
2589  
2590 // Compute the new position of this SOP relative to the group position
2591 part.OffsetPosition = part.GroupPosition - AbsolutePosition;
2592  
2593 // (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
2594 // It would have the affect of setting the physics engine position multiple
2595 // times. In theory, that is not necessary but I don't have a good linkset
2596 // test to know that cleaning up this code wouldn't break things.)
2597  
2598 // Rotate the relative position by the rotation of the group
2599 Quaternion rootRotation = m_rootPart.RotationOffset;
2600 Vector3 pos = part.OffsetPosition;
2601 pos *= Quaternion.Inverse(rootRotation);
2602 part.OffsetPosition = pos;
2603  
2604 // Compute the SOP's rotation relative to the rotation of the group.
2605 parentRot = m_rootPart.RotationOffset;
2606 oldRot = part.RotationOffset;
2607 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
2608 part.RotationOffset = newRot;
2609  
2610 // Since this SOP's state has changed, push those changes into the physics engine
2611 // and the simulator.
2612 part.UpdatePrimFlags(UsesPhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2613 }
2614  
2615 /// <summary>
2616 /// If object is physical, apply force to move it around
2617 /// If object is not physical, just put it at the resulting location
2618 /// </summary>
2619 /// <param name="partID">Part ID to check for grab</param>
2620 /// <param name="offset">Always seems to be 0,0,0, so ignoring</param>
2621 /// <param name="pos">New position. We do the math here to turn it into a force</param>
2622 /// <param name="remoteClient"></param>
2623 public void GrabMovement(UUID partID, Vector3 offset, Vector3 pos, IClientAPI remoteClient)
2624 {
2625 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2626 {
2627 SceneObjectPart part = GetPart(partID);
2628  
2629 if (part == null)
2630 return;
2631  
2632 PhysicsActor pa = m_rootPart.PhysActor;
2633  
2634 if (pa != null)
2635 {
2636 if (pa.IsPhysical)
2637 {
2638 if (!BlockGrabOverride && !part.BlockGrab)
2639 {
2640 Vector3 llmoveforce = pos - AbsolutePosition;
2641 Vector3 grabforce = llmoveforce;
2642 grabforce = (grabforce / 10) * pa.Mass;
2643 pa.AddForce(grabforce, true);
2644 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2645 }
2646 }
2647 else
2648 {
2649 //NonPhysicalGrabMovement(pos);
2650 }
2651 }
2652 else
2653 {
2654 //NonPhysicalGrabMovement(pos);
2655 }
2656 }
2657 }
2658  
2659 public void NonPhysicalGrabMovement(Vector3 pos)
2660 {
2661 AbsolutePosition = pos;
2662 m_rootPart.SendTerseUpdateToAllClients();
2663 }
2664  
2665 /// <summary>
2666 /// If object is physical, prepare for spinning torques (set flag to save old orientation)
2667 /// </summary>
2668 /// <param name="rotation">Rotation. We do the math here to turn it into a torque</param>
2669 /// <param name="remoteClient"></param>
2670 public void SpinStart(IClientAPI remoteClient)
2671 {
2672 if (m_scene.EventManager.TriggerGroupSpinStart(UUID))
2673 {
2674 PhysicsActor pa = m_rootPart.PhysActor;
2675  
2676 if (pa != null)
2677 {
2678 if (pa.IsPhysical)
2679 {
2680 m_rootPart.IsWaitingForFirstSpinUpdatePacket = true;
2681 }
2682 }
2683 }
2684 }
2685  
2686 /// <summary>
2687 /// If object is physical, apply torque to spin it around
2688 /// </summary>
2689 /// <param name="rotation">Rotation. We do the math here to turn it into a torque</param>
2690 /// <param name="remoteClient"></param>
2691 public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient)
2692 {
2693 // The incoming newOrientation, sent by the client, "seems" to be the
2694 // desired target orientation. This needs further verification; in particular,
2695 // one would expect that the initial incoming newOrientation should be
2696 // fairly close to the original prim's physical orientation,
2697 // m_rootPart.PhysActor.Orientation. This however does not seem to be the
2698 // case (might just be an issue with different quaternions representing the
2699 // same rotation, or it might be a coordinate system issue).
2700 //
2701 // Since it's not clear what the relationship is between the PhysActor.Orientation
2702 // and the incoming orientations sent by the client, we take an alternative approach
2703 // of calculating the delta rotation between the orientations being sent by the
2704 // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect
2705 // a steady stream of several new orientations coming in from the client.)
2706 // This ensures that the delta rotations are being calculated from self-consistent
2707 // pairs of old/new rotations. Given the delta rotation, we apply a torque around
2708 // the delta rotation axis, scaled by the object mass times an arbitrary scaling
2709 // factor (to ensure the resulting torque is not "too strong" or "too weak").
2710 //
2711 // Ideally we need to calculate (probably iteratively) the exact torque or series
2712 // of torques needed to arrive exactly at the destination orientation. However, since
2713 // it is not yet clear how to map the destination orientation (provided by the viewer)
2714 // into PhysActor orientations (needed by the physics engine), we omit this step.
2715 // This means that the resulting torque will at least be in the correct direction,
2716 // but it will result in over-shoot or under-shoot of the target orientation.
2717 // For the end user, this means that ctrl+shift+drag can be used for relative,
2718 // but not absolute, adjustments of orientation for physical prims.
2719 if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation))
2720 {
2721 PhysicsActor pa = m_rootPart.PhysActor;
2722  
2723 if (pa != null)
2724 {
2725 if (pa.IsPhysical)
2726 {
2727 if (m_rootPart.IsWaitingForFirstSpinUpdatePacket)
2728 {
2729 // first time initialization of "old" orientation for calculation of delta rotations
2730 m_rootPart.SpinOldOrientation = newOrientation;
2731 m_rootPart.IsWaitingForFirstSpinUpdatePacket = false;
2732 }
2733 else
2734 {
2735 // save and update old orientation
2736 Quaternion old = m_rootPart.SpinOldOrientation;
2737 m_rootPart.SpinOldOrientation = newOrientation;
2738 //m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
2739 //m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
2740  
2741 // compute difference between previous old rotation and new incoming rotation
2742 Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old) * newOrientation;
2743  
2744 float rotationAngle;
2745 Vector3 rotationAxis;
2746 minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle);
2747 rotationAxis.Normalize();
2748  
2749 //m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
2750 Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z);
2751 spinforce = (spinforce/8) * pa.Mass; // 8 is an arbitrary torque scaling factor
2752 pa.AddAngularForce(spinforce,true);
2753 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2754 }
2755 }
2756 else
2757 {
2758 //NonPhysicalSpinMovement(pos);
2759 }
2760 }
2761 else
2762 {
2763 //NonPhysicalSpinMovement(pos);
2764 }
2765 }
2766 }
2767  
2768 /// <summary>
2769 /// Set the name of a prim
2770 /// </summary>
2771 /// <param name="name"></param>
2772 /// <param name="localID"></param>
2773 public void SetPartName(string name, uint localID)
2774 {
2775 SceneObjectPart part = GetPart(localID);
2776 if (part != null)
2777 {
2778 part.Name = name;
2779 }
2780 }
2781  
2782 public void SetPartDescription(string des, uint localID)
2783 {
2784 SceneObjectPart part = GetPart(localID);
2785 if (part != null)
2786 {
2787 part.Description = des;
2788 }
2789 }
2790  
2791 public void SetPartText(string text, uint localID)
2792 {
2793 SceneObjectPart part = GetPart(localID);
2794 if (part != null)
2795 {
2796 part.SetText(text);
2797 }
2798 }
2799  
2800 public void SetPartText(string text, UUID partID)
2801 {
2802 SceneObjectPart part = GetPart(partID);
2803 if (part != null)
2804 {
2805 part.SetText(text);
2806 }
2807 }
2808  
2809 public string GetPartName(uint localID)
2810 {
2811 SceneObjectPart part = GetPart(localID);
2812 if (part != null)
2813 {
2814 return part.Name;
2815 }
2816 return String.Empty;
2817 }
2818  
2819 public string GetPartDescription(uint localID)
2820 {
2821 SceneObjectPart part = GetPart(localID);
2822 if (part != null)
2823 {
2824 return part.Description;
2825 }
2826 return String.Empty;
2827 }
2828  
2829 /// <summary>
2830 /// Update prim flags for this group.
2831 /// </summary>
2832 /// <param name="localID"></param>
2833 /// <param name="UsePhysics"></param>
2834 /// <param name="SetTemporary"></param>
2835 /// <param name="SetPhantom"></param>
2836 /// <param name="SetVolumeDetect"></param>
2837 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, bool SetVolumeDetect)
2838 {
2839 SceneObjectPart selectionPart = GetPart(localID);
2840  
2841 if (Scene != null)
2842 {
2843 if (SetTemporary)
2844 {
2845 DetachFromBackup();
2846 // Remove from database and parcel prim count
2847 //
2848 m_scene.DeleteFromStorage(UUID);
2849 }
2850 else if (!Backup)
2851 {
2852 // Previously been temporary now switching back so make it
2853 // available for persisting again
2854 AttachToBackup();
2855 }
2856  
2857 m_scene.EventManager.TriggerParcelPrimCountTainted();
2858 }
2859  
2860 if (selectionPart != null)
2861 {
2862 SceneObjectPart[] parts = m_parts.GetArray();
2863  
2864 if (Scene != null)
2865 {
2866 for (int i = 0; i < parts.Length; i++)
2867 {
2868 SceneObjectPart part = parts[i];
2869 if (part.Scale.X > m_scene.m_maxPhys ||
2870 part.Scale.Y > m_scene.m_maxPhys ||
2871 part.Scale.Z > m_scene.m_maxPhys )
2872 {
2873 UsePhysics = false; // Reset physics
2874 break;
2875 }
2876 }
2877 }
2878  
2879 for (int i = 0; i < parts.Length; i++)
2880 parts[i].UpdatePrimFlags(UsePhysics, SetTemporary, SetPhantom, SetVolumeDetect);
2881 }
2882 }
2883  
2884 public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
2885 {
2886 SceneObjectPart part = GetPart(localID);
2887 if (part != null)
2888 {
2889 part.UpdateExtraParam(type, inUse, data);
2890 }
2891 }
2892  
2893 /// <summary>
2894 /// Update the texture entry for this part
2895 /// </summary>
2896 /// <param name="localID"></param>
2897 /// <param name="textureEntry"></param>
2898 public void UpdateTextureEntry(uint localID, byte[] textureEntry)
2899 {
2900 SceneObjectPart part = GetPart(localID);
2901 if (part != null)
2902 {
2903 part.UpdateTextureEntry(textureEntry);
2904 }
2905 }
2906  
2907 public void AdjustChildPrimPermissions(bool forceTaskInventoryPermissive)
2908 {
2909 uint newOwnerMask = (uint)(PermissionMask.All | PermissionMask.Export) & 0xfffffff8; // Mask folded bits
2910 uint foldedPerms = RootPart.OwnerMask & 3;
2911  
2912 ForEachPart(part =>
2913 {
2914 newOwnerMask &= part.BaseMask;
2915 if (part != RootPart)
2916 part.ClonePermissions(RootPart);
2917 if (forceTaskInventoryPermissive)
2918 part.Inventory.ApplyGodPermissions(part.BaseMask);
2919 });
2920  
2921 uint lockMask = ~(uint)(PermissionMask.Move | PermissionMask.Modify);
2922 uint lockBit = RootPart.OwnerMask & (uint)(PermissionMask.Move | PermissionMask.Modify);
2923 RootPart.OwnerMask = (RootPart.OwnerMask & lockBit) | ((newOwnerMask | foldedPerms) & lockMask);
2924 RootPart.ScheduleFullUpdate();
2925 }
2926  
2927 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
2928 uint mask, byte addRemTF)
2929 {
2930 RootPart.UpdatePermissions(AgentID, field, localID, mask, addRemTF);
2931  
2932 AdjustChildPrimPermissions(Scene.Permissions.IsGod(AgentID));
2933  
2934 HasGroupChanged = true;
2935  
2936 // Send the group's properties to all clients once all parts are updated
2937 IClientAPI client;
2938 if (Scene.TryGetClient(AgentID, out client))
2939 SendPropertiesToClient(client);
2940 }
2941  
2942 #endregion
2943  
2944 #region Shape
2945  
2946 /// <summary>
2947 ///
2948 /// </summary>
2949 /// <param name="shapeBlock"></param>
2950 public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID)
2951 {
2952 SceneObjectPart part = GetPart(localID);
2953 if (part != null)
2954 {
2955 part.UpdateShape(shapeBlock);
2956  
2957 PhysicsActor pa = m_rootPart.PhysActor;
2958  
2959 if (pa != null)
2960 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
2961 }
2962 }
2963  
2964 #endregion
2965  
2966 #region Resize
2967  
2968 /// <summary>
2969 /// Resize the entire group of prims.
2970 /// </summary>
2971 /// <param name="scale"></param>
2972 public void GroupResize(Vector3 scale)
2973 {
2974 // m_log.DebugFormat(
2975 // "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2976  
2977 PhysicsActor pa = m_rootPart.PhysActor;
2978  
2979 RootPart.StoreUndoState(true);
2980  
2981 if (Scene != null)
2982 {
2983 scale.X = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.X));
2984 scale.Y = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Y));
2985 scale.Z = Math.Max(Scene.m_minNonphys, Math.Min(Scene.m_maxNonphys, scale.Z));
2986  
2987 if (pa != null && pa.IsPhysical)
2988 {
2989 scale.X = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.X));
2990 scale.Y = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Y));
2991 scale.Z = Math.Max(Scene.m_minPhys, Math.Min(Scene.m_maxPhys, scale.Z));
2992 }
2993 }
2994  
2995 float x = (scale.X / RootPart.Scale.X);
2996 float y = (scale.Y / RootPart.Scale.Y);
2997 float z = (scale.Z / RootPart.Scale.Z);
2998  
2999 SceneObjectPart[] parts = m_parts.GetArray();
3000  
3001 if (Scene != null & (x > 1.0f || y > 1.0f || z > 1.0f))
3002 {
3003 for (int i = 0; i < parts.Length; i++)
3004 {
3005 SceneObjectPart obPart = parts[i];
3006 if (obPart.UUID != m_rootPart.UUID)
3007 {
3008 // obPart.IgnoreUndoUpdate = true;
3009 Vector3 oldSize = new Vector3(obPart.Scale);
3010  
3011 float f = 1.0f;
3012 float a = 1.0f;
3013  
3014 if (pa != null && pa.IsPhysical)
3015 {
3016 if (oldSize.X * x > Scene.m_maxPhys)
3017 {
3018 f = m_scene.m_maxPhys / oldSize.X;
3019 a = f / x;
3020 x *= a;
3021 y *= a;
3022 z *= a;
3023 }
3024 else if (oldSize.X * x < Scene.m_minPhys)
3025 {
3026 f = m_scene.m_minPhys / oldSize.X;
3027 a = f / x;
3028 x *= a;
3029 y *= a;
3030 z *= a;
3031 }
3032  
3033 if (oldSize.Y * y > Scene.m_maxPhys)
3034 {
3035 f = m_scene.m_maxPhys / oldSize.Y;
3036 a = f / y;
3037 x *= a;
3038 y *= a;
3039 z *= a;
3040 }
3041 else if (oldSize.Y * y < Scene.m_minPhys)
3042 {
3043 f = m_scene.m_minPhys / oldSize.Y;
3044 a = f / y;
3045 x *= a;
3046 y *= a;
3047 z *= a;
3048 }
3049  
3050 if (oldSize.Z * z > Scene.m_maxPhys)
3051 {
3052 f = m_scene.m_maxPhys / oldSize.Z;
3053 a = f / z;
3054 x *= a;
3055 y *= a;
3056 z *= a;
3057 }
3058 else if (oldSize.Z * z < Scene.m_minPhys)
3059 {
3060 f = m_scene.m_minPhys / oldSize.Z;
3061 a = f / z;
3062 x *= a;
3063 y *= a;
3064 z *= a;
3065 }
3066 }
3067 else
3068 {
3069 if (oldSize.X * x > Scene.m_maxNonphys)
3070 {
3071 f = m_scene.m_maxNonphys / oldSize.X;
3072 a = f / x;
3073 x *= a;
3074 y *= a;
3075 z *= a;
3076 }
3077 else if (oldSize.X * x < Scene.m_minNonphys)
3078 {
3079 f = m_scene.m_minNonphys / oldSize.X;
3080 a = f / x;
3081 x *= a;
3082 y *= a;
3083 z *= a;
3084 }
3085  
3086 if (oldSize.Y * y > Scene.m_maxNonphys)
3087 {
3088 f = m_scene.m_maxNonphys / oldSize.Y;
3089 a = f / y;
3090 x *= a;
3091 y *= a;
3092 z *= a;
3093 }
3094 else if (oldSize.Y * y < Scene.m_minNonphys)
3095 {
3096 f = m_scene.m_minNonphys / oldSize.Y;
3097 a = f / y;
3098 x *= a;
3099 y *= a;
3100 z *= a;
3101 }
3102  
3103 if (oldSize.Z * z > Scene.m_maxNonphys)
3104 {
3105 f = m_scene.m_maxNonphys / oldSize.Z;
3106 a = f / z;
3107 x *= a;
3108 y *= a;
3109 z *= a;
3110 }
3111 else if (oldSize.Z * z < Scene.m_minNonphys)
3112 {
3113 f = m_scene.m_minNonphys / oldSize.Z;
3114 a = f / z;
3115 x *= a;
3116 y *= a;
3117 z *= a;
3118 }
3119 }
3120  
3121 // obPart.IgnoreUndoUpdate = false;
3122 }
3123 }
3124 }
3125  
3126 Vector3 prevScale = RootPart.Scale;
3127 prevScale.X *= x;
3128 prevScale.Y *= y;
3129 prevScale.Z *= z;
3130  
3131 // RootPart.IgnoreUndoUpdate = true;
3132 RootPart.Resize(prevScale);
3133 // RootPart.IgnoreUndoUpdate = false;
3134  
3135 for (int i = 0; i < parts.Length; i++)
3136 {
3137 SceneObjectPart obPart = parts[i];
3138  
3139 if (obPart.UUID != m_rootPart.UUID)
3140 {
3141 obPart.IgnoreUndoUpdate = true;
3142  
3143 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
3144 currentpos.X *= x;
3145 currentpos.Y *= y;
3146 currentpos.Z *= z;
3147  
3148 Vector3 newSize = new Vector3(obPart.Scale);
3149 newSize.X *= x;
3150 newSize.Y *= y;
3151 newSize.Z *= z;
3152  
3153 obPart.Resize(newSize);
3154 obPart.UpdateOffSet(currentpos);
3155  
3156 obPart.IgnoreUndoUpdate = false;
3157 }
3158  
3159 // obPart.IgnoreUndoUpdate = false;
3160 // obPart.StoreUndoState();
3161 }
3162  
3163 // m_log.DebugFormat(
3164 // "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
3165 }
3166  
3167 #endregion
3168  
3169 #region Position
3170  
3171 /// <summary>
3172 /// Move this scene object
3173 /// </summary>
3174 /// <param name="pos"></param>
3175 public void UpdateGroupPosition(Vector3 pos)
3176 {
3177 // m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
3178  
3179 RootPart.StoreUndoState(true);
3180  
3181 // SceneObjectPart[] parts = m_parts.GetArray();
3182 // for (int i = 0; i < parts.Length; i++)
3183 // parts[i].StoreUndoState();
3184  
3185 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
3186 {
3187 if (IsAttachment)
3188 {
3189 m_rootPart.AttachedPos = pos;
3190 }
3191  
3192 if (RootPart.GetStatusSandbox())
3193 {
3194 if (Util.GetDistanceTo(RootPart.StatusSandboxPos, pos) > 10)
3195 {
3196 RootPart.ScriptSetPhysicsStatus(false);
3197 pos = AbsolutePosition;
3198 Scene.SimChat(Utils.StringToBytes("Hit Sandbox Limit"),
3199 ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name, UUID, false);
3200 }
3201 }
3202  
3203 AbsolutePosition = pos;
3204 HasGroupChanged = true;
3205 }
3206  
3207 //we need to do a terse update even if the move wasn't allowed
3208 // so that the position is reset in the client (the object snaps back)
3209 RootPart.ScheduleTerseUpdate();
3210 }
3211  
3212 /// <summary>
3213 /// Update the position of a single part of this scene object
3214 /// </summary>
3215 /// <param name="pos"></param>
3216 /// <param name="localID"></param>
3217 public void UpdateSinglePosition(Vector3 pos, uint localID)
3218 {
3219 SceneObjectPart part = GetPart(localID);
3220  
3221 // SceneObjectPart[] parts = m_parts.GetArray();
3222 // for (int i = 0; i < parts.Length; i++)
3223 // parts[i].StoreUndoState();
3224  
3225 if (part != null)
3226 {
3227 // m_log.DebugFormat(
3228 // "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos);
3229  
3230 part.StoreUndoState(false);
3231 part.IgnoreUndoUpdate = true;
3232  
3233 if (part.UUID == m_rootPart.UUID)
3234 {
3235 UpdateRootPosition(pos);
3236 }
3237 else
3238 {
3239 part.UpdateOffSet(pos);
3240 }
3241  
3242 HasGroupChanged = true;
3243 part.IgnoreUndoUpdate = false;
3244 }
3245 }
3246  
3247 /// <summary>
3248 /// Update just the root prim position in a linkset
3249 /// </summary>
3250 /// <param name="newPos"></param>
3251 public void UpdateRootPosition(Vector3 newPos)
3252 {
3253 // m_log.DebugFormat(
3254 // "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
3255  
3256 // SceneObjectPart[] parts = m_parts.GetArray();
3257 // for (int i = 0; i < parts.Length; i++)
3258 // parts[i].StoreUndoState();
3259  
3260 Vector3 oldPos;
3261  
3262 if (IsAttachment)
3263 oldPos = m_rootPart.AttachedPos + m_rootPart.OffsetPosition; // OffsetPosition should always be 0 in an attachments's root prim
3264 else
3265 oldPos = AbsolutePosition + m_rootPart.OffsetPosition;
3266  
3267 Vector3 diff = oldPos - newPos;
3268 Quaternion partRotation = m_rootPart.RotationOffset;
3269 diff *= Quaternion.Inverse(partRotation);
3270  
3271 SceneObjectPart[] parts = m_parts.GetArray();
3272 for (int i = 0; i < parts.Length; i++)
3273 {
3274 SceneObjectPart obPart = parts[i];
3275 if (obPart.UUID != m_rootPart.UUID)
3276 obPart.OffsetPosition = obPart.OffsetPosition + diff;
3277 }
3278  
3279 AbsolutePosition = newPos;
3280  
3281 if (IsAttachment)
3282 m_rootPart.AttachedPos = newPos;
3283  
3284 HasGroupChanged = true;
3285 ScheduleGroupForTerseUpdate();
3286 }
3287  
3288 #endregion
3289  
3290 #region Rotation
3291  
3292 /// <summary>
3293 /// Update the rotation of the group.
3294 /// </summary>
3295 /// <param name="rot"></param>
3296 public void UpdateGroupRotationR(Quaternion rot)
3297 {
3298 // m_log.DebugFormat(
3299 // "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
3300  
3301 // SceneObjectPart[] parts = m_parts.GetArray();
3302 // for (int i = 0; i < parts.Length; i++)
3303 // parts[i].StoreUndoState();
3304  
3305 m_rootPart.StoreUndoState(true);
3306  
3307 m_rootPart.UpdateRotation(rot);
3308  
3309 PhysicsActor actor = m_rootPart.PhysActor;
3310 if (actor != null)
3311 {
3312 actor.Orientation = m_rootPart.RotationOffset;
3313 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3314 }
3315  
3316 HasGroupChanged = true;
3317 ScheduleGroupForTerseUpdate();
3318 }
3319  
3320 /// <summary>
3321 /// Update the position and rotation of a group simultaneously.
3322 /// </summary>
3323 /// <param name="pos"></param>
3324 /// <param name="rot"></param>
3325 public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
3326 {
3327 // m_log.DebugFormat(
3328 // "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
3329  
3330 // SceneObjectPart[] parts = m_parts.GetArray();
3331 // for (int i = 0; i < parts.Length; i++)
3332 // parts[i].StoreUndoState();
3333  
3334 RootPart.StoreUndoState(true);
3335 RootPart.IgnoreUndoUpdate = true;
3336  
3337 m_rootPart.UpdateRotation(rot);
3338  
3339 PhysicsActor actor = m_rootPart.PhysActor;
3340 if (actor != null)
3341 {
3342 actor.Orientation = m_rootPart.RotationOffset;
3343 m_scene.PhysicsScene.AddPhysicsActorTaint(actor);
3344 }
3345  
3346 if (IsAttachment)
3347 {
3348 m_rootPart.AttachedPos = pos;
3349 }
3350  
3351 AbsolutePosition = pos;
3352  
3353 HasGroupChanged = true;
3354 ScheduleGroupForTerseUpdate();
3355  
3356 RootPart.IgnoreUndoUpdate = false;
3357 }
3358  
3359 /// <summary>
3360 /// Update the rotation of a single prim within the group.
3361 /// </summary>
3362 /// <param name="rot"></param>
3363 /// <param name="localID"></param>
3364 public void UpdateSingleRotation(Quaternion rot, uint localID)
3365 {
3366 SceneObjectPart part = GetPart(localID);
3367  
3368 SceneObjectPart[] parts = m_parts.GetArray();
3369 for (int i = 0; i < parts.Length; i++)
3370 parts[i].StoreUndoState();
3371  
3372 if (part != null)
3373 {
3374 // m_log.DebugFormat(
3375 // "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot);
3376  
3377 if (part.UUID == m_rootPart.UUID)
3378 {
3379 UpdateRootRotation(rot);
3380 }
3381 else
3382 {
3383 part.UpdateRotation(rot);
3384 }
3385 }
3386 }
3387  
3388 /// <summary>
3389 /// Update the position and rotation simultaneously of a single prim within the group.
3390 /// </summary>
3391 /// <param name="rot"></param>
3392 /// <param name="localID"></param>
3393 public void UpdateSingleRotation(Quaternion rot, Vector3 pos, uint localID)
3394 {
3395 SceneObjectPart part = GetPart(localID);
3396 if (part != null)
3397 {
3398 // m_log.DebugFormat(
3399 // "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}",
3400 // part.Name, part.LocalId, rot);
3401  
3402 part.StoreUndoState();
3403 part.IgnoreUndoUpdate = true;
3404  
3405 if (part.UUID == m_rootPart.UUID)
3406 {
3407 UpdateRootRotation(rot);
3408 AbsolutePosition = pos;
3409 }
3410 else
3411 {
3412 part.UpdateRotation(rot);
3413 part.OffsetPosition = pos;
3414 }
3415  
3416 part.IgnoreUndoUpdate = false;
3417 }
3418 }
3419  
3420 /// <summary>
3421 /// Update the rotation of just the root prim of a linkset.
3422 /// </summary>
3423 /// <param name="rot"></param>
3424 public void UpdateRootRotation(Quaternion rot)
3425 {
3426 // m_log.DebugFormat(
3427 // "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
3428 // Name, LocalId, rot);
3429  
3430 Quaternion axRot = rot;
3431 Quaternion oldParentRot = m_rootPart.RotationOffset;
3432  
3433 m_rootPart.StoreUndoState();
3434 m_rootPart.UpdateRotation(rot);
3435  
3436 PhysicsActor pa = m_rootPart.PhysActor;
3437  
3438 if (pa != null)
3439 {
3440 pa.Orientation = m_rootPart.RotationOffset;
3441 m_scene.PhysicsScene.AddPhysicsActorTaint(pa);
3442 }
3443  
3444 SceneObjectPart[] parts = m_parts.GetArray();
3445 for (int i = 0; i < parts.Length; i++)
3446 {
3447 SceneObjectPart prim = parts[i];
3448 if (prim.UUID != m_rootPart.UUID)
3449 {
3450 prim.IgnoreUndoUpdate = true;
3451 Vector3 axPos = prim.OffsetPosition;
3452 axPos *= oldParentRot;
3453 axPos *= Quaternion.Inverse(axRot);
3454 prim.OffsetPosition = axPos;
3455 Quaternion primsRot = prim.RotationOffset;
3456 Quaternion newRot = oldParentRot * primsRot;
3457 newRot = Quaternion.Inverse(axRot) * newRot;
3458 prim.RotationOffset = newRot;
3459 prim.ScheduleTerseUpdate();
3460 prim.IgnoreUndoUpdate = false;
3461 }
3462 }
3463  
3464 // for (int i = 0; i < parts.Length; i++)
3465 // {
3466 // SceneObjectPart childpart = parts[i];
3467 // if (childpart != m_rootPart)
3468 // {
3469 //// childpart.IgnoreUndoUpdate = false;
3470 //// childpart.StoreUndoState();
3471 // }
3472 // }
3473  
3474 m_rootPart.ScheduleTerseUpdate();
3475  
3476 // m_log.DebugFormat(
3477 // "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
3478 // Name, LocalId, rot);
3479 }
3480  
3481 #endregion
3482  
3483 internal void SetAxisRotation(int axis, int rotate10)
3484 {
3485 bool setX = false;
3486 bool setY = false;
3487 bool setZ = false;
3488  
3489 int xaxis = 2;
3490 int yaxis = 4;
3491 int zaxis = 8;
3492  
3493 setX = ((axis & xaxis) != 0) ? true : false;
3494 setY = ((axis & yaxis) != 0) ? true : false;
3495 setZ = ((axis & zaxis) != 0) ? true : false;
3496  
3497 float setval = (rotate10 > 0) ? 1f : 0f;
3498  
3499 if (setX)
3500 RootPart.RotationAxis.X = setval;
3501 if (setY)
3502 RootPart.RotationAxis.Y = setval;
3503 if (setZ)
3504 RootPart.RotationAxis.Z = setval;
3505  
3506 if (setX || setY || setZ)
3507 RootPart.SetPhysicsAxisRotation();
3508 }
3509  
3510 public int registerRotTargetWaypoint(Quaternion target, float tolerance)
3511 {
3512 scriptRotTarget waypoint = new scriptRotTarget();
3513 waypoint.targetRot = target;
3514 waypoint.tolerance = tolerance;
3515 uint handle = m_scene.AllocateLocalId();
3516 waypoint.handle = handle;
3517 lock (m_rotTargets)
3518 {
3519 m_rotTargets.Add(handle, waypoint);
3520 }
3521 m_scene.AddGroupTarget(this);
3522 return (int)handle;
3523 }
3524  
3525 public void unregisterRotTargetWaypoint(int handle)
3526 {
3527 lock (m_targets)
3528 {
3529 m_rotTargets.Remove((uint)handle);
3530 if (m_targets.Count == 0)
3531 m_scene.RemoveGroupTarget(this);
3532 }
3533 }
3534  
3535 public int registerTargetWaypoint(Vector3 target, float tolerance)
3536 {
3537 scriptPosTarget waypoint = new scriptPosTarget();
3538 waypoint.targetPos = target;
3539 waypoint.tolerance = tolerance;
3540 uint handle = m_scene.AllocateLocalId();
3541 waypoint.handle = handle;
3542 lock (m_targets)
3543 {
3544 m_targets.Add(handle, waypoint);
3545 }
3546 m_scene.AddGroupTarget(this);
3547 return (int)handle;
3548 }
3549  
3550 public void unregisterTargetWaypoint(int handle)
3551 {
3552 lock (m_targets)
3553 {
3554 m_targets.Remove((uint)handle);
3555 if (m_targets.Count == 0)
3556 m_scene.RemoveGroupTarget(this);
3557 }
3558 }
3559  
3560 public void checkAtTargets()
3561 {
3562 if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
3563 {
3564 if (m_targets.Count > 0)
3565 {
3566 bool at_target = false;
3567 //Vector3 targetPos;
3568 //uint targetHandle;
3569 Dictionary<uint, scriptPosTarget> atTargets = new Dictionary<uint, scriptPosTarget>();
3570 lock (m_targets)
3571 {
3572 foreach (uint idx in m_targets.Keys)
3573 {
3574 scriptPosTarget target = m_targets[idx];
3575 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
3576 {
3577 // trigger at_target
3578 if (m_scriptListens_atTarget)
3579 {
3580 at_target = true;
3581 scriptPosTarget att = new scriptPosTarget();
3582 att.targetPos = target.targetPos;
3583 att.tolerance = target.tolerance;
3584 att.handle = target.handle;
3585 atTargets.Add(idx, att);
3586 }
3587 }
3588 }
3589 }
3590  
3591 if (atTargets.Count > 0)
3592 {
3593 SceneObjectPart[] parts = m_parts.GetArray();
3594 uint[] localids = new uint[parts.Length];
3595 for (int i = 0; i < parts.Length; i++)
3596 localids[i] = parts[i].LocalId;
3597  
3598 for (int ctr = 0; ctr < localids.Length; ctr++)
3599 {
3600 foreach (uint target in atTargets.Keys)
3601 {
3602 scriptPosTarget att = atTargets[target];
3603 m_scene.EventManager.TriggerAtTargetEvent(
3604 localids[ctr], att.handle, att.targetPos, m_rootPart.GroupPosition);
3605 }
3606 }
3607  
3608 return;
3609 }
3610  
3611 if (m_scriptListens_notAtTarget && !at_target)
3612 {
3613 //trigger not_at_target
3614 SceneObjectPart[] parts = m_parts.GetArray();
3615 uint[] localids = new uint[parts.Length];
3616 for (int i = 0; i < parts.Length; i++)
3617 localids[i] = parts[i].LocalId;
3618  
3619 for (int ctr = 0; ctr < localids.Length; ctr++)
3620 {
3621 m_scene.EventManager.TriggerNotAtTargetEvent(localids[ctr]);
3622 }
3623 }
3624 }
3625 }
3626 if (m_scriptListens_atRotTarget || m_scriptListens_notAtRotTarget)
3627 {
3628 if (m_rotTargets.Count > 0)
3629 {
3630 bool at_Rottarget = false;
3631 Dictionary<uint, scriptRotTarget> atRotTargets = new Dictionary<uint, scriptRotTarget>();
3632 lock (m_rotTargets)
3633 {
3634 foreach (uint idx in m_rotTargets.Keys)
3635 {
3636 scriptRotTarget target = m_rotTargets[idx];
3637 double angle
3638 = Math.Acos(
3639 target.targetRot.X * m_rootPart.RotationOffset.X
3640 + target.targetRot.Y * m_rootPart.RotationOffset.Y
3641 + target.targetRot.Z * m_rootPart.RotationOffset.Z
3642 + target.targetRot.W * m_rootPart.RotationOffset.W)
3643 * 2;
3644 if (angle < 0) angle = -angle;
3645 if (angle > Math.PI) angle = (Math.PI * 2 - angle);
3646 if (angle <= target.tolerance)
3647 {
3648 // trigger at_rot_target
3649 if (m_scriptListens_atRotTarget)
3650 {
3651 at_Rottarget = true;
3652 scriptRotTarget att = new scriptRotTarget();
3653 att.targetRot = target.targetRot;
3654 att.tolerance = target.tolerance;
3655 att.handle = target.handle;
3656 atRotTargets.Add(idx, att);
3657 }
3658 }
3659 }
3660 }
3661  
3662 if (atRotTargets.Count > 0)
3663 {
3664 SceneObjectPart[] parts = m_parts.GetArray();
3665 uint[] localids = new uint[parts.Length];
3666 for (int i = 0; i < parts.Length; i++)
3667 localids[i] = parts[i].LocalId;
3668  
3669 for (int ctr = 0; ctr < localids.Length; ctr++)
3670 {
3671 foreach (uint target in atRotTargets.Keys)
3672 {
3673 scriptRotTarget att = atRotTargets[target];
3674 m_scene.EventManager.TriggerAtRotTargetEvent(
3675 localids[ctr], att.handle, att.targetRot, m_rootPart.RotationOffset);
3676 }
3677 }
3678  
3679 return;
3680 }
3681  
3682 if (m_scriptListens_notAtRotTarget && !at_Rottarget)
3683 {
3684 //trigger not_at_target
3685 SceneObjectPart[] parts = m_parts.GetArray();
3686 uint[] localids = new uint[parts.Length];
3687 for (int i = 0; i < parts.Length; i++)
3688 localids[i] = parts[i].LocalId;
3689  
3690 for (int ctr = 0; ctr < localids.Length; ctr++)
3691 {
3692 m_scene.EventManager.TriggerNotAtRotTargetEvent(localids[ctr]);
3693 }
3694 }
3695 }
3696 }
3697 }
3698  
3699 public float GetMass()
3700 {
3701 float retmass = 0f;
3702  
3703 SceneObjectPart[] parts = m_parts.GetArray();
3704 for (int i = 0; i < parts.Length; i++)
3705 retmass += parts[i].GetMass();
3706  
3707 return retmass;
3708 }
3709  
3710 /// <summary>
3711 /// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
3712 /// the physics engine can use it.
3713 /// </summary>
3714 /// <remarks>
3715 /// When the physics engine has finished with it, the sculpt data is discarded to save memory.
3716 /// </remarks>
3717 /*
3718 public void CheckSculptAndLoad()
3719 {
3720 if (IsDeleted)
3721 return;
3722  
3723 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) != 0)
3724 return;
3725  
3726 // m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
3727  
3728 SceneObjectPart[] parts = m_parts.GetArray();
3729  
3730 for (int i = 0; i < parts.Length; i++)
3731 parts[i].CheckSculptAndLoad();
3732 }
3733 */
3734 /// <summary>
3735 /// Set the user group to which this scene object belongs.
3736 /// </summary>
3737 /// <param name="GroupID"></param>
3738 /// <param name="client"></param>
3739 public void SetGroup(UUID GroupID, IClientAPI client)
3740 {
3741 SceneObjectPart[] parts = m_parts.GetArray();
3742 for (int i = 0; i < parts.Length; i++)
3743 {
3744 SceneObjectPart part = parts[i];
3745 part.SetGroup(GroupID, client);
3746 part.Inventory.ChangeInventoryGroup(GroupID);
3747 }
3748  
3749 HasGroupChanged = true;
3750  
3751 // Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
3752 // for the same object with very different properties. The caller must schedule the update.
3753 //ScheduleGroupForFullUpdate();
3754 }
3755  
3756 public void TriggerScriptChangedEvent(Changed val)
3757 {
3758 SceneObjectPart[] parts = m_parts.GetArray();
3759 for (int i = 0; i < parts.Length; i++)
3760 parts[i].TriggerScriptChangedEvent(val);
3761 }
3762  
3763 /// <summary>
3764 /// Returns a count of the number of scripts in this groups parts.
3765 /// </summary>
3766 public int ScriptCount()
3767 {
3768 int count = 0;
3769 SceneObjectPart[] parts = m_parts.GetArray();
3770 for (int i = 0; i < parts.Length; i++)
3771 count += parts[i].Inventory.ScriptCount();
3772  
3773 return count;
3774 }
3775  
3776 /// <summary>
3777 /// A float the value is a representative execution time in milliseconds of all scripts in the link set.
3778 /// </summary>
3779 public float ScriptExecutionTime()
3780 {
3781 IScriptModule[] engines = Scene.RequestModuleInterfaces<IScriptModule>();
3782  
3783 if (engines.Length == 0) // No engine at all
3784 return 0.0f;
3785  
3786 float time = 0.0f;
3787  
3788 // get all the scripts in all parts
3789 SceneObjectPart[] parts = m_parts.GetArray();
3790 List<TaskInventoryItem> scripts = new List<TaskInventoryItem>();
3791 for (int i = 0; i < parts.Length; i++)
3792 {
3793 scripts.AddRange(parts[i].Inventory.GetInventoryItems(InventoryType.LSL));
3794 }
3795 // extract the UUIDs
3796 List<UUID> ids = new List<UUID>(scripts.Count);
3797 foreach (TaskInventoryItem script in scripts)
3798 {
3799 if (!ids.Contains(script.ItemID))
3800 {
3801 ids.Add(script.ItemID);
3802 }
3803 }
3804 // Offer the list of script UUIDs to each engine found and accumulate the time
3805 foreach (IScriptModule e in engines)
3806 {
3807 if (e != null)
3808 {
3809 time += e.GetScriptExecutionTime(ids);
3810 }
3811 }
3812 return time;
3813 }
3814  
3815 /// <summary>
3816 /// Returns a count of the number of running scripts in this groups parts.
3817 /// </summary>
3818 public int RunningScriptCount()
3819 {
3820 int count = 0;
3821 SceneObjectPart[] parts = m_parts.GetArray();
3822 for (int i = 0; i < parts.Length; i++)
3823 count += parts[i].Inventory.RunningScriptCount();
3824  
3825 return count;
3826 }
3827  
3828 /// <summary>
3829 /// Get a copy of the list of sitting avatars on all prims of this object.
3830 /// </summary>
3831 /// <remarks>
3832 /// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat
3833 /// down after it move one place down the list.
3834 /// </remarks>
3835 /// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
3836 public List<ScenePresence> GetSittingAvatars()
3837 {
3838 lock (m_sittingAvatars)
3839 return new List<ScenePresence>(m_sittingAvatars);
3840 }
3841  
3842 /// <summary>
3843 /// Gets the number of sitting avatars.
3844 /// </summary>
3845 /// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
3846 /// <returns></returns>
3847 public int GetSittingAvatarsCount()
3848 {
3849 lock (m_sittingAvatars)
3850 return m_sittingAvatars.Count;
3851 }
3852  
3853 public override string ToString()
3854 {
3855 return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition);
3856 }
3857  
3858 #region ISceneObject
3859  
3860 public virtual ISceneObject CloneForNewScene()
3861 {
3862 SceneObjectGroup sog = Copy(false);
3863 sog.IsDeleted = false;
3864 return sog;
3865 }
3866  
3867 public virtual string ToXml2()
3868 {
3869 return SceneObjectSerializer.ToXml2Format(this);
3870 }
3871  
3872 public virtual string ExtraToXmlString()
3873 {
3874 return "<ExtraFromItemID>" + FromItemID.ToString() + "</ExtraFromItemID>";
3875 }
3876  
3877 public virtual void ExtraFromXmlString(string xmlstr)
3878 {
3879 string id = xmlstr.Substring(xmlstr.IndexOf("<ExtraFromItemID>"));
3880 id = xmlstr.Replace("<ExtraFromItemID>", "");
3881 id = id.Replace("</ExtraFromItemID>", "");
3882  
3883 UUID uuid = UUID.Zero;
3884 UUID.TryParse(id, out uuid);
3885  
3886 FromItemID = uuid;
3887 }
3888  
3889 #endregion
3890 }
3891 }