opensim-development – Blame information for rev 1

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