aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
diff options
context:
space:
mode:
authorDr Scofield2009-02-06 16:55:34 +0000
committerDr Scofield2009-02-06 16:55:34 +0000
commit9b66108081a8c8cf79faaa6c541554091c40850e (patch)
tree095a232ae5a9de3a9244bcd34da08294f61eeea5 /OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
parent* removed superfluous constants class (diff)
downloadopensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.zip
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.gz
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.bz2
opensim-SC_OLD-9b66108081a8c8cf79faaa6c541554091c40850e.tar.xz
This changeset is the step 1 of 2 in refactoring
OpenSim.Region.Environment into a "framework" part and a modules only part. This first changeset refactors OpenSim.Region.Environment.Scenes, OpenSim.Region.Environment.Interfaces, and OpenSim.Region.Interfaces into OpenSim.Region.Framework.{Interfaces,Scenes} leaving only region modules in OpenSim.Region.Environment. The next step will be to move region modules up from OpenSim.Region.Environment.Modules to OpenSim.Region.CoreModules and then sort out which modules are really core modules and which should move out to forge. I've been very careful to NOT BREAK anything. i hope i've succeeded. as this is the work of a whole week i hope i managed to keep track with the applied patches of the last week --- could any of you that did check in stuff have a look at whether it survived? thx!
Diffstat (limited to 'OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs')
-rw-r--r--OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs3012
1 files changed, 0 insertions, 3012 deletions
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
deleted file mode 100644
index 5ae95ee..0000000
--- a/OpenSim/Region/Environment/Scenes/SceneObjectGroup.cs
+++ /dev/null
@@ -1,3012 +0,0 @@
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 OpenSim 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
28using System;
29using System.Collections.Generic;
30using System.Drawing;
31using System.IO;
32using System.Xml;
33using System.Xml.Serialization;
34using OpenMetaverse;
35using OpenMetaverse.Packets;
36using OpenSim.Framework;
37using OpenSim.Region.Environment.Interfaces;
38using OpenSim.Region.Physics.Manager;
39
40namespace OpenSim.Region.Environment.Scenes
41{
42 [Flags]
43 public enum scriptEvents
44 {
45 None = 0,
46 attach = 1,
47 collision = 16,
48 collision_end = 32,
49 collision_start = 64,
50 control = 128,
51 dataserver = 256,
52 email = 512,
53 http_response = 1024,
54 land_collision = 2048,
55 land_collision_end = 4096,
56 land_collision_start = 8192,
57 at_target = 16384,
58 listen = 32768,
59 money = 65536,
60 moving_end = 131072,
61 moving_start = 262144,
62 not_at_rot_target = 524288,
63 not_at_target = 1048576,
64 remote_data = 8388608,
65 run_time_permissions = 268435456,
66 state_entry = 1073741824,
67 state_exit = 2,
68 timer = 4,
69 touch = 8,
70 touch_end = 536870912,
71 touch_start = 2097152,
72 object_rez = 4194304
73 }
74
75 struct scriptPosTarget
76 {
77 public Vector3 targetPos;
78 public float tolerance;
79 }
80
81 public delegate void PrimCountTaintedDelegate();
82
83 /// <summary>
84 /// A scene object group is conceptually an object in the scene. The object is constituted of SceneObjectParts
85 /// (often known as prims), one of which is considered the root part.
86 /// </summary>
87 public partial class SceneObjectGroup : EntityBase
88 {
89 // private PrimCountTaintedDelegate handlerPrimCountTainted = null;
90
91 /// <summary>
92 /// Signal whether the non-inventory attributes of any prims in the group have changed
93 /// since the group's last persistent backup
94 /// </summary>
95 private bool m_hasGroupChanged = false;
96 private long timeFirstChanged;
97 private long timeLastChanged;
98
99 public bool HasGroupChanged
100 {
101 set
102 {
103 if (value)
104 {
105 timeLastChanged = DateTime.Now.Ticks;
106 if (!m_hasGroupChanged)
107 timeFirstChanged = DateTime.Now.Ticks;
108 }
109 m_hasGroupChanged = value;
110 }
111
112 get { return m_hasGroupChanged; }
113 }
114
115 private bool isTimeToPersist()
116 {
117 if (IsSelected || IsDeleted || IsAttachment)
118 return false;
119 if (!m_hasGroupChanged)
120 return false;
121 if (m_scene.ShuttingDown)
122 return true;
123 long currentTime = DateTime.Now.Ticks;
124 if (currentTime - timeLastChanged > m_scene.m_dontPersistBefore || currentTime - timeFirstChanged > m_scene.m_persistAfter)
125 return true;
126 return false;
127 }
128
129 /// <value>
130 /// Is this scene object acting as an attachment?
131 ///
132 /// We return false if the group has already been deleted.
133 ///
134 /// TODO: At the moment set must be done on the part itself. There may be a case for doing it here since I
135 /// presume either all or no parts in a linkset can be part of an attachment (in which
136 /// case the value would get proprogated down into all the descendent parts).
137 /// </value>
138 public bool IsAttachment
139 {
140 get
141 {
142 if (!IsDeleted)
143 return m_rootPart.IsAttachment;
144
145 return false;
146 }
147 }
148
149 public float scriptScore = 0f;
150
151 private Vector3 lastPhysGroupPos;
152 private Quaternion lastPhysGroupRot;
153
154 private bool m_isBackedUp = false;
155
156 /// <summary>
157 /// The constituent parts of this group
158 /// </summary>
159 protected Dictionary<UUID, SceneObjectPart> m_parts = new Dictionary<UUID, SceneObjectPart>();
160
161 protected ulong m_regionHandle;
162 protected SceneObjectPart m_rootPart;
163 // private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
164
165 private Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>();
166
167 private bool m_scriptListens_atTarget = false;
168 private bool m_scriptListens_notAtTarget = false;
169
170 #region Properties
171
172 /// <summary>
173 /// The name of an object grouping is always the same as its root part
174 /// </summary>
175 public override string Name
176 {
177 get {
178 if (RootPart == null)
179 return "";
180 return RootPart.Name;
181 }
182 set { RootPart.Name = value; }
183 }
184
185 /// <summary>
186 /// Added because the Parcel code seems to use it
187 /// but not sure a object should have this
188 /// as what does it tell us? that some avatar has selected it (but not what Avatar/user)
189 /// think really there should be a list (or whatever) in each scenepresence
190 /// saying what prim(s) that user has selected.
191 /// </summary>
192 protected bool m_isSelected = false;
193
194 /// <summary>
195 /// Number of prims in this group
196 /// </summary>
197 public int PrimCount
198 {
199 get { return m_parts.Count; }
200 }
201
202 public Quaternion GroupRotation
203 {
204 get { return m_rootPart.RotationOffset; }
205 }
206
207 public UUID GroupID
208 {
209 get { return m_rootPart.GroupID; }
210 set { m_rootPart.GroupID = value; }
211 }
212
213 public Dictionary<UUID, SceneObjectPart> Children
214 {
215 get { return m_parts; }
216 set { m_parts = value; }
217 }
218
219 /// <value>
220 /// The root part of this scene object
221 /// </value>
222 public SceneObjectPart RootPart
223 {
224 get { return m_rootPart; }
225 }
226
227 public ulong RegionHandle
228 {
229 get { return m_regionHandle; }
230 set
231 {
232 m_regionHandle = value;
233 lock (m_parts)
234 {
235 foreach (SceneObjectPart part in m_parts.Values)
236 {
237 part.RegionHandle = m_regionHandle;
238 }
239 }
240 }
241 }
242
243 /// <summary>
244 /// The absolute position of this scene object in the scene
245 /// </summary>
246 public override Vector3 AbsolutePosition
247 {
248 get
249 {
250 if (m_rootPart == null)
251 {
252 throw new NullReferenceException(
253 string.Format("[SCENE OBJECT GROUP]: Object {0} has no root part.", m_uuid));
254 }
255
256 return m_rootPart.GroupPosition;
257 }
258 set
259 {
260 Vector3 val = value;
261
262 if ((val.X > 257f || val.X < -1f || val.Y > 257f || val.Y < -1f) && !IsAttachment)
263 {
264 m_scene.CrossPrimGroupIntoNewRegion(val, this, true);
265 }
266
267 lock (m_parts)
268 {
269 foreach (SceneObjectPart part in m_parts.Values)
270 {
271 part.GroupPosition = val;
272 }
273 }
274
275 //if (m_rootPart.PhysActor != null)
276 //{
277 //m_rootPart.PhysActor.Position =
278 //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y,
279 //m_rootPart.GroupPosition.Z);
280 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
281 //}
282 }
283 }
284
285 public override uint LocalId
286 {
287 get
288 {
289 if (m_rootPart == null)
290 {
291 m_log.Error("[SCENE OBJECT GROUP]: Unable to find the rootpart for a LocalId Request!");
292 return 0;
293 }
294
295 return m_rootPart.LocalId;
296 }
297 set { m_rootPart.LocalId = value; }
298 }
299
300 public override UUID UUID
301 {
302 get {
303 if (m_rootPart == null)
304 {
305 m_log.Error("Got a null rootpart while requesting UUID. Called from: ", new Exception());
306 return UUID.Zero;
307 }
308 else return m_rootPart.UUID;
309 }
310 set { m_rootPart.UUID = value; }
311 }
312
313 public UUID OwnerID
314 {
315 get
316 {
317 if (m_rootPart == null)
318 return UUID.Zero;
319
320 return m_rootPart.OwnerID;
321 }
322 set { m_rootPart.OwnerID = value; }
323 }
324
325 public Color Color
326 {
327 get { return m_rootPart.Color; }
328 set { m_rootPart.Color = value; }
329 }
330
331 public string Text
332 {
333 get {
334 string returnstr = m_rootPart.Text;
335 if (returnstr.Length > 255)
336 {
337 returnstr = returnstr.Substring(0, 255);
338 }
339 return returnstr;
340 }
341 set { m_rootPart.Text = value; }
342 }
343
344 protected virtual bool InSceneBackup
345 {
346 get { return true; }
347 }
348
349 public bool IsSelected
350 {
351 get { return m_isSelected; }
352 set
353 {
354 m_isSelected = value;
355 // Tell physics engine that group is selected
356 if (m_rootPart != null && m_rootPart.PhysActor != null)
357 {
358 m_rootPart.PhysActor.Selected = value;
359 // Pass it on to the children.
360 foreach (SceneObjectPart child in Children.Values)
361 {
362 if (child.PhysActor != null)
363 {
364 child.PhysActor.Selected = value;
365 }
366 }
367 }
368 }
369 }
370
371 // The UUID for the Region this Object is in.
372 public UUID RegionUUID
373 {
374 get
375 {
376 if (m_scene != null)
377 {
378 return m_scene.RegionInfo.RegionID;
379 }
380 return UUID.Zero;
381 }
382 }
383
384 #endregion
385
386 #region Constructors
387
388 /// <summary>
389 /// Constructor
390 /// </summary>
391 public SceneObjectGroup()
392 {
393 }
394
395 /// <summary>
396 /// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
397 /// The original SceneObjectPart will be used rather than a copy, preserving
398 /// its existing localID and UUID.
399 /// </summary>
400 public SceneObjectGroup(SceneObjectPart part)
401 {
402 SetRootPart(part);
403 }
404
405 public SceneObjectGroup(string xmlData, bool isOriginalXmlFormat)
406 : this(UUID.Zero, xmlData, isOriginalXmlFormat)
407 {
408 }
409
410 /// <summary>
411 /// Create an object using serialized data in OpenSim's original xml format.
412 /// </summary>
413 /// <param name="fromUserInventoryItemID">
414 /// If applicable, the user inventory item id from which this object was rezzed. If not applicable then this
415 /// should be UUID.Zero
416 /// </param>
417 /// <param name="xmlData"></param>
418 /// <param name="isOriginalXmlFormat">
419 /// This parameter only exists to separate the two different xml constructors. In the future, versions should
420 /// be specified within the xml itself.
421 /// </param>
422 public SceneObjectGroup(UUID fromUserInventoryItemID, string xmlData, bool isOriginalXmlFormat)
423 {
424 if (!isOriginalXmlFormat)
425 throw new Exception("This constructor must specify the xml is in OpenSim's original format");
426
427 //m_log.DebugFormat("[SOG]: Starting deserialization of SOG");
428 int time = System.Environment.TickCount;
429
430 // libomv.types changes UUID to Guid
431 xmlData = xmlData.Replace("<UUID>", "<Guid>");
432 xmlData = xmlData.Replace("</UUID>", "</Guid>");
433
434 // Handle Nested <UUID><UUID> property
435 xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>");
436 xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>");
437 StringReader sr = new StringReader(xmlData);
438 XmlTextReader reader = new XmlTextReader(sr);
439
440 try
441 {
442 reader.Read();
443 reader.ReadStartElement("SceneObjectGroup");
444 reader.ReadStartElement("RootPart");
445 SetRootPart(SceneObjectPart.FromXml(fromUserInventoryItemID, reader));
446
447 reader.ReadEndElement();
448
449 while (reader.Read())
450 {
451 switch (reader.NodeType)
452 {
453 case XmlNodeType.Element:
454 if (reader.Name == "Part")
455 {
456 reader.Read();
457 SceneObjectPart part = SceneObjectPart.FromXml(reader);
458
459 // We reset the link number in order to make sure that the persisted linkset order is
460 int linkNum = part.LinkNum;
461 AddPart(part);
462 part.LinkNum = linkNum;
463
464 part.TrimPermissions();
465 part.StoreUndoState();
466 }
467 break;
468
469 case XmlNodeType.EndElement:
470 break;
471 }
472 }
473 }
474 catch (XmlException e)
475 {
476 m_log.ErrorFormat("[SCENE]: Deserialization of xml failed with {0}. xml was {1}", e, xmlData);
477 }
478
479 reader.Close();
480 sr.Close();
481 m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
482 }
483
484 /// <summary>
485 /// Create an object using serialized data in OpenSim's xml2 format.
486 /// </summary>
487 public SceneObjectGroup(string xmlData)
488 {
489 SetFromXml(xmlData);
490 }
491
492 protected void SetFromXml(string xmlData)
493 {
494 //m_log.DebugFormat("[SOG]: Starting deserialization of SOG");
495 //int time = System.Environment.TickCount;
496
497 // libomv.types changes UUID to Guid
498 xmlData = xmlData.Replace("<UUID>", "<Guid>");
499 xmlData = xmlData.Replace("</UUID>", "</Guid>");
500
501 // Handle Nested <UUID><UUID> property
502 xmlData = xmlData.Replace("<Guid><Guid>", "<UUID><Guid>");
503 xmlData = xmlData.Replace("</Guid></Guid>", "</Guid></UUID>");
504
505 StringReader sr = new StringReader(xmlData);
506 XmlTextReader reader = new XmlTextReader(sr);
507 reader.Read();
508
509 reader.ReadStartElement("SceneObjectGroup");
510 SetRootPart(CreatePartFromXml(reader));
511
512 reader.Read();
513 bool more = true;
514
515 while (more)
516 {
517 switch (reader.NodeType)
518 {
519 case XmlNodeType.Element:
520 if (reader.Name == "SceneObjectPart")
521 {
522 SceneObjectPart part = CreatePartFromXml(reader);
523 AddPart(part);
524 part.StoreUndoState();
525 }
526 else
527 {
528 Console.WriteLine("found unexpected element: " + reader.Name);
529 reader.Read();
530 }
531 break;
532 case XmlNodeType.EndElement:
533 reader.Read();
534 break;
535 }
536 more = !reader.EOF;
537 }
538
539 reader.Close();
540 sr.Close();
541
542 //m_log.DebugFormat("[SOG]: Finished deserialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
543 }
544
545 protected virtual SceneObjectPart CreatePartFromXml(XmlTextReader reader)
546 {
547 SceneObjectPart part = SceneObjectPart.FromXml(reader);
548 return part;
549 }
550
551 /// <summary>
552 /// Constructor. This object is added to the scene later via AttachToScene()
553 /// </summary>
554 public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape)
555 {
556 Vector3 rootOffset = new Vector3(0, 0, 0);
557 SetRootPart(new SceneObjectPart(ownerID, shape, pos, rot, rootOffset));
558 }
559
560 /// <summary>
561 /// Constructor.
562 /// </summary>
563 public SceneObjectGroup(UUID ownerID, Vector3 pos, PrimitiveBaseShape shape)
564 : this(ownerID, pos, Quaternion.Identity, shape)
565 {
566 }
567
568 public void SetFromAssetID(UUID AssetId)
569 {
570 lock (m_parts)
571 {
572 foreach (SceneObjectPart part in m_parts.Values)
573 {
574 part.FromAssetID = AssetId;
575 }
576 }
577 }
578
579 public UUID GetFromAssetID()
580 {
581 if (m_rootPart != null)
582 {
583 return m_rootPart.FromAssetID;
584 }
585 return UUID.Zero;
586 }
587
588 /// <summary>
589 /// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes.
590 /// </summary>
591 public void AttachToBackup()
592 {
593 if (InSceneBackup)
594 {
595 //m_log.DebugFormat(
596 // "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
597
598 if (!m_isBackedUp)
599 m_scene.EventManager.OnBackup += ProcessBackup;
600
601 m_isBackedUp = true;
602 }
603 }
604
605 /// <summary>
606 /// Attach this object to a scene. It will also now appear to agents.
607 /// </summary>
608 /// <param name="scene"></param>
609 public void AttachToScene(Scene scene)
610 {
611 m_scene = scene;
612 RegionHandle = m_scene.RegionInfo.RegionHandle;
613
614 if (m_rootPart.Shape.PCode != 9 || m_rootPart.Shape.State == 0)
615 m_rootPart.ParentID = 0;
616 if (m_rootPart.LocalId==0)
617 m_rootPart.LocalId = m_scene.AllocateLocalId();
618
619 // No need to lock here since the object isn't yet in a scene
620 foreach (SceneObjectPart part in m_parts.Values)
621 {
622 if (Object.ReferenceEquals(part, m_rootPart))
623 continue;
624 if (part.LocalId==0)
625 part.LocalId = m_scene.AllocateLocalId();
626 part.ParentID = m_rootPart.LocalId;
627 //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);
628 }
629
630 ApplyPhysics(m_scene.m_physicalPrim);
631
632 ScheduleGroupForFullUpdate();
633 }
634
635 public Vector3 GroupScale()
636 {
637 Vector3 minScale = new Vector3(Constants.RegionSize,Constants.RegionSize,Constants.RegionSize);
638 Vector3 maxScale = new Vector3(0f,0f,0f);
639 Vector3 finalScale = new Vector3(0.5f, 0.5f, 0.5f);
640
641 lock (m_parts)
642 {
643 foreach (SceneObjectPart part in m_parts.Values)
644 {
645 Vector3 partscale = part.Scale;
646 Vector3 partoffset = part.OffsetPosition;
647
648 minScale.X = (partscale.X + partoffset.X < minScale.X) ? partscale.X + partoffset.X : minScale.X;
649 minScale.Y = (partscale.Y + partoffset.Y < minScale.Y) ? partscale.X + partoffset.Y : minScale.Y;
650 minScale.Z = (partscale.Z + partoffset.Z < minScale.Z) ? partscale.X + partoffset.Z : minScale.Z;
651
652 maxScale.X = (partscale.X + partoffset.X > maxScale.X) ? partscale.X + partoffset.X : maxScale.X;
653 maxScale.Y = (partscale.Y + partoffset.Y > maxScale.Y) ? partscale.Y + partoffset.Y : maxScale.Y;
654 maxScale.Z = (partscale.Z + partoffset.Z > maxScale.Z) ? partscale.Z + partoffset.Z : maxScale.Z;
655 }
656 }
657 finalScale.X = (minScale.X > maxScale.X) ? minScale.X : maxScale.X;
658 finalScale.Y = (minScale.Y > maxScale.Y) ? minScale.Y : maxScale.Y;
659 finalScale.Z = (minScale.Z > maxScale.Z) ? minScale.Z : maxScale.Z;
660 return finalScale;
661
662 }
663 public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
664 {
665 // We got a request from the inner_scene to raytrace along the Ray hRay
666 // We're going to check all of the prim in this group for intersection with the ray
667 // If we get a result, we're going to find the closest result to the origin of the ray
668 // and send back the intersection information back to the innerscene.
669
670 EntityIntersection returnresult = new EntityIntersection();
671
672 lock (m_parts)
673 {
674 foreach (SceneObjectPart part in m_parts.Values)
675 {
676 // Temporary commented to stop compiler warning
677 //Vector3 partPosition =
678 // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
679 Quaternion parentrotation = GroupRotation;
680
681 // Telling the prim to raytrace.
682 //EntityIntersection inter = part.TestIntersection(hRay, parentrotation);
683
684 EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation,frontFacesOnly, faceCenters);
685
686 // This may need to be updated to the maximum draw distance possible..
687 // We might (and probably will) be checking for prim creation from other sims
688 // when the camera crosses the border.
689 float idist = Constants.RegionSize;
690
691
692 if (inter.HitTF)
693 {
694 // We need to find the closest prim to return to the testcaller along the ray
695 if (inter.distance < idist)
696 {
697 returnresult.HitTF = true;
698 returnresult.ipoint = inter.ipoint;
699 returnresult.obj = part;
700 returnresult.normal = inter.normal;
701 returnresult.distance = inter.distance;
702 }
703 }
704 }
705 }
706 return returnresult;
707 }
708
709 #endregion
710
711
712 public string ToXmlString()
713 {
714 using (StringWriter sw = new StringWriter())
715 {
716 using (XmlTextWriter writer = new XmlTextWriter(sw))
717 {
718 ToXml(writer);
719 }
720
721 return sw.ToString();
722 }
723 }
724
725 public void ToXml(XmlTextWriter writer)
726 {
727 m_log.DebugFormat("[SOG]: Starting serialization of {0}", Name);
728 int time = System.Environment.TickCount;
729
730 writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
731 writer.WriteStartElement(String.Empty, "RootPart", String.Empty);
732 m_rootPart.ToXml(writer);
733 writer.WriteEndElement();
734 writer.WriteStartElement(String.Empty, "OtherParts", String.Empty);
735
736 lock (m_parts)
737 {
738 foreach (SceneObjectPart part in m_parts.Values)
739 {
740 if (part.UUID != m_rootPart.UUID)
741 {
742 writer.WriteStartElement(String.Empty, "Part", String.Empty);
743 part.ToXml(writer);
744 writer.WriteEndElement();
745 }
746 }
747 }
748
749 writer.WriteEndElement();
750 writer.WriteEndElement();
751
752 m_log.DebugFormat("[SOG]: Finished serialization of SOG {0}, {1}ms", Name, System.Environment.TickCount - time);
753
754 }
755
756 public string ToXmlString2()
757 {
758 using (StringWriter sw = new StringWriter())
759 {
760 using (XmlTextWriter writer = new XmlTextWriter(sw))
761 {
762 ToXml2(writer);
763 }
764
765 return sw.ToString();
766 }
767 }
768
769 public void ToXml2(XmlTextWriter writer)
770 {
771 m_log.DebugFormat("[SOG]: Starting serialization of SOG {0} to XML2", Name);
772 int time = System.Environment.TickCount;
773
774 writer.WriteStartElement(String.Empty, "SceneObjectGroup", String.Empty);
775 m_rootPart.ToXml(writer);
776 writer.WriteStartElement(String.Empty, "OtherParts", String.Empty);
777
778 lock (m_parts)
779 {
780 foreach (SceneObjectPart part in m_parts.Values)
781 {
782 if (part.UUID != m_rootPart.UUID)
783 {
784 part.ToXml(writer);
785 }
786 }
787 }
788
789 writer.WriteEndElement();
790 writer.WriteEndElement();
791 m_log.DebugFormat("[SOG]: Finished serialization of SOG {0} to XML2, {1}ms", Name, System.Environment.TickCount - time);
792 }
793
794 /// <summary>
795 /// Attach this scene object to the given avatar.
796 /// </summary>
797 /// <param name="agentID"></param>
798 /// <param name="attachmentpoint"></param>
799 /// <param name="AttachOffset"></param>
800 public void AttachToAgent(UUID agentID, uint attachmentpoint, Vector3 AttachOffset, bool silent)
801 {
802 ScenePresence avatar = m_scene.GetScenePresence(agentID);
803 if (avatar != null)
804 {
805 // don't attach attachments to child agents
806 if (avatar.IsChildAgent) return;
807
808 DetachFromBackup();
809
810 // Remove from database and parcel prim count
811 //
812 m_scene.DeleteFromStorage(UUID);
813 m_scene.EventManager.TriggerParcelPrimCountTainted();
814
815 m_rootPart.AttachedAvatar = agentID;
816
817 if (m_rootPart.PhysActor != null)
818 {
819 m_scene.PhysicsScene.RemovePrim(m_rootPart.PhysActor);
820 m_rootPart.PhysActor = null;
821 }
822
823 AbsolutePosition = AttachOffset;
824 m_rootPart.AttachedPos = AttachOffset;
825 m_rootPart.IsAttachment = true;
826
827 m_rootPart.SetParentLocalId(avatar.LocalId);
828 SetAttachmentPoint(Convert.ToByte(attachmentpoint));
829
830 avatar.AddAttachment(this);
831
832 if (!silent)
833 {
834 // Killing it here will cause the client to deselect it
835 // It then reappears on the avatar, deselected
836 // through the full update below
837 //
838 if (IsSelected)
839 {
840 m_scene.SendKillObject(m_rootPart.LocalId);
841 }
842
843 IsSelected = false; // fudge....
844 ScheduleGroupForFullUpdate();
845 }
846 }
847 }
848
849 public byte GetAttachmentPoint()
850 {
851 if (m_rootPart != null)
852 {
853 return m_rootPart.Shape.State;
854 }
855 return (byte)0;
856 }
857
858 public void ClearPartAttachmentData()
859 {
860 SetAttachmentPoint((Byte)0);
861 }
862
863 public void DetachToGround()
864 {
865 ScenePresence avatar = m_scene.GetScenePresence(m_rootPart.AttachedAvatar);
866 if (avatar == null)
867 return;
868
869 avatar.RemoveAttachment(this);
870
871 Vector3 detachedpos = new Vector3(127f,127f,127f);
872 if (avatar == null)
873 return;
874
875 detachedpos = avatar.AbsolutePosition;
876
877 AbsolutePosition = detachedpos;
878 m_rootPart.AttachedAvatar = UUID.Zero;
879 m_rootPart.SetParentLocalId(0);
880 SetAttachmentPoint((byte)0);
881 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_scene.m_physicalPrim);
882 HasGroupChanged = true;
883 RootPart.Rezzed = DateTime.Now;
884 RootPart.RemFlag(PrimFlags.TemporaryOnRez);
885 AttachToBackup();
886 m_scene.EventManager.TriggerParcelPrimCountTainted();
887 m_rootPart.ScheduleFullUpdate();
888 m_rootPart.ClearUndoState();
889 }
890
891 public void DetachToInventoryPrep()
892 {
893 ScenePresence avatar = m_scene.GetScenePresence(m_rootPart.AttachedAvatar);
894 //Vector3 detachedpos = new Vector3(127f, 127f, 127f);
895 if (avatar != null)
896 {
897 //detachedpos = avatar.AbsolutePosition;
898 avatar.RemoveAttachment(this);
899 }
900
901 m_rootPart.AttachedAvatar = UUID.Zero;
902 m_rootPart.SetParentLocalId(0);
903 //m_rootPart.SetAttachmentPoint((byte)0);
904 m_rootPart.IsAttachment = false;
905 AbsolutePosition = m_rootPart.AttachedPos;
906 //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
907 //AttachToBackup();
908 //m_rootPart.ScheduleFullUpdate();
909
910 }
911 /// <summary>
912 ///
913 /// </summary>
914 /// <param name="part"></param>
915 private void SetPartAsNonRoot(SceneObjectPart part)
916 {
917 part.ParentID = m_rootPart.LocalId;
918 part.ClearUndoState();
919 }
920
921 public override void UpdateMovement()
922 {
923 lock (m_parts)
924 {
925 foreach (SceneObjectPart part in m_parts.Values)
926 {
927 part.UpdateMovement();
928 }
929 }
930 }
931
932 public float GetTimeDilation()
933 {
934 return m_scene.TimeDilation;
935 }
936
937 /// <summary>
938 /// Added as a way for the storage provider to reset the scene,
939 /// most likely a better way to do this sort of thing but for now...
940 /// </summary>
941 /// <param name="scene"></param>
942 public void SetScene(Scene scene)
943 {
944 m_scene = scene;
945 }
946
947 /// <summary>
948 /// Set a part to act as the root part for this scene object
949 /// </summary>
950 /// <param name="part"></param>
951 public void SetRootPart(SceneObjectPart part)
952 {
953 part.SetParent(this);
954 m_rootPart = part;
955 if (!IsAttachment)
956 part.ParentID = 0;
957 part.LinkNum = 0;
958
959 // No locking required since the SOG should not be in the scene yet - one can't change root parts after
960 // the scene object has been attached to the scene
961 m_parts.Add(m_rootPart.UUID, m_rootPart);
962 }
963
964 /// <summary>
965 /// Add a new part to this scene object. The part must already be correctly configured.
966 /// </summary>
967 /// <param name="part"></param>
968 public void AddPart(SceneObjectPart part)
969 {
970 lock (m_parts)
971 {
972 part.SetParent(this);
973 m_parts.Add(part.UUID, part);
974
975 part.LinkNum = m_parts.Count;
976
977 if (part.LinkNum == 2 && RootPart != null)
978 RootPart.LinkNum = 1;
979 }
980 }
981
982 /// <summary>
983 /// Make sure that every non root part has the proper parent root part local id
984 /// </summary>
985 private void UpdateParentIDs()
986 {
987 lock (m_parts)
988 {
989 foreach (SceneObjectPart part in m_parts.Values)
990 {
991 if (part.UUID != m_rootPart.UUID)
992 {
993 part.ParentID = m_rootPart.LocalId;
994 }
995 }
996 }
997 }
998
999 public void RegenerateFullIDs()
1000 {
1001 lock (m_parts)
1002 {
1003 foreach (SceneObjectPart part in m_parts.Values)
1004 {
1005 part.UUID = UUID.Random();
1006
1007 }
1008 }
1009 }
1010 // helper provided for parts.
1011 public int GetSceneMaxUndo()
1012 {
1013 if (m_scene != null)
1014 return m_scene.MaxUndoCount;
1015 return 5;
1016 }
1017
1018 // justincc: I don't believe this hack is needed any longer, especially since the physics
1019 // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
1020 // this method was preventing proper reload of scene objects.
1021 // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
1022 // at region startup
1023 public void ResetChildPrimPhysicsPositions()
1024 {
1025 AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
1026 }
1027
1028 public UUID GetPartsFullID(uint localID)
1029 {
1030 SceneObjectPart part = GetChildPart(localID);
1031 if (part != null)
1032 {
1033 return part.UUID;
1034 }
1035 return UUID.Zero;
1036 }
1037
1038 public void ObjectGrabHandler(uint localId, Vector3 offsetPos, IClientAPI remoteClient)
1039 {
1040 if (m_rootPart.LocalId == localId)
1041 {
1042 OnGrabGroup(offsetPos, remoteClient);
1043 }
1044 else
1045 {
1046 SceneObjectPart part = GetChildPart(localId);
1047 OnGrabPart(part, offsetPos, remoteClient);
1048
1049 }
1050 }
1051
1052 public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
1053 {
1054 part.StoreUndoState();
1055 part.OnGrab(offsetPos, remoteClient);
1056 }
1057
1058 public virtual void OnGrabGroup(Vector3 offsetPos, IClientAPI remoteClient)
1059 {
1060 m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId);
1061 }
1062
1063 /// <summary>
1064 /// Delete this group from its scene and tell all the scene presences about that deletion.
1065 /// </summary>
1066 /// <param name="silent">Broadcast deletions to all clients.</param>
1067 public void DeleteGroup(bool silent)
1068 {
1069 // We need to keep track of this state in case this group is still queued for backup.
1070 m_isDeleted = true;
1071
1072 DetachFromBackup();
1073
1074 lock (m_parts)
1075 {
1076 foreach (SceneObjectPart part in m_parts.Values)
1077 {
1078// part.Inventory.RemoveScriptInstances();
1079
1080 List<ScenePresence> avatars = Scene.GetScenePresences();
1081 for (int i = 0; i < avatars.Count; i++)
1082 {
1083 if (avatars[i].ParentID == LocalId)
1084 {
1085 avatars[i].StandUp();
1086 }
1087
1088 if (!silent)
1089 {
1090 if (m_rootPart != null && part == m_rootPart)
1091 avatars[i].ControllingClient.SendKillObject(m_regionHandle, part.LocalId);
1092 }
1093 }
1094 }
1095 }
1096 }
1097
1098 public void AddScriptLPS(int count)
1099 {
1100 if (scriptScore + count >= float.MaxValue - count)
1101 scriptScore = 0;
1102
1103 scriptScore += (float)count;
1104 SceneGraph d = m_scene.m_sceneGraph;
1105 d.AddToScriptLPS(count);
1106 }
1107
1108 public void AddActiveScriptCount(int count)
1109 {
1110 SceneGraph d = m_scene.m_sceneGraph;
1111 d.AddActiveScripts(count);
1112 }
1113
1114 public void aggregateScriptEvents()
1115 {
1116 uint objectflagupdate=(uint)RootPart.GetEffectiveObjectFlags();
1117
1118 scriptEvents aggregateScriptEvents=0;
1119
1120 lock (m_parts)
1121 {
1122 foreach (SceneObjectPart part in m_parts.Values)
1123 {
1124 if (part == null)
1125 continue;
1126 if (part != RootPart)
1127 part.ObjectFlags = objectflagupdate;
1128 aggregateScriptEvents |= part.AggregateScriptEvents;
1129 }
1130 }
1131
1132 if ((aggregateScriptEvents & scriptEvents.at_target) != 0)
1133 {
1134 m_scriptListens_atTarget = true;
1135 }
1136 else
1137 {
1138 m_scriptListens_atTarget = false;
1139 }
1140
1141 if ((aggregateScriptEvents & scriptEvents.not_at_target) != 0)
1142 {
1143 m_scriptListens_notAtTarget = true;
1144 }
1145 else
1146 {
1147 m_scriptListens_notAtTarget = false;
1148 }
1149
1150 if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
1151 {
1152 }
1153 else
1154 {
1155 lock (m_targets)
1156 m_targets.Clear();
1157 }
1158
1159 ScheduleGroupForFullUpdate();
1160 }
1161
1162 public override void SetText(string text, Vector3 color, double alpha)
1163 {
1164 Color = Color.FromArgb(0xff - (int) (alpha * 0xff),
1165 (int) (color.X * 0xff),
1166 (int) (color.Y * 0xff),
1167 (int) (color.Z * 0xff));
1168 Text = text;
1169
1170 HasGroupChanged = true;
1171 m_rootPart.ScheduleFullUpdate();
1172 }
1173
1174 /// <summary>
1175 /// Apply physics to this group
1176 /// </summary>
1177 /// <param name="m_physicalPrim"></param>
1178 public void ApplyPhysics(bool m_physicalPrim)
1179 {
1180 lock (m_parts)
1181 {
1182 if (m_parts.Count > 1)
1183 {
1184 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1185 foreach (SceneObjectPart part in m_parts.Values)
1186 {
1187 if (part.LocalId != m_rootPart.LocalId)
1188 {
1189 part.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), part.VolumeDetectActive, m_physicalPrim);
1190 }
1191 }
1192
1193 // Hack to get the physics scene geometries in the right spot
1194 ResetChildPrimPhysicsPositions();
1195 }
1196 else
1197 {
1198 m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_rootPart.VolumeDetectActive, m_physicalPrim);
1199 }
1200 }
1201 }
1202
1203 public void SetOwnerId(UUID userId)
1204 {
1205 ForEachPart(delegate(SceneObjectPart part) { part.OwnerID = userId; });
1206 }
1207
1208 public void ForEachPart(Action<SceneObjectPart> whatToDo)
1209 {
1210 lock (m_parts)
1211 {
1212 foreach (SceneObjectPart part in m_parts.Values)
1213 {
1214 whatToDo(part);
1215 }
1216 }
1217 }
1218
1219 #region Events
1220
1221 /// <summary>
1222 /// Processes backup.
1223 /// </summary>
1224 /// <param name="datastore"></param>
1225 public void ProcessBackup(IRegionDataStore datastore, bool forcedBackup)
1226 {
1227 if (!m_isBackedUp)
1228 return;
1229
1230 // Since this is the top of the section of call stack for backing up a particular scene object, don't let
1231 // any exception propogate upwards.
1232
1233 if (IsDeleted || UUID == UUID.Zero)
1234 return;
1235
1236 try
1237 {
1238 if (!m_scene.ShuttingDown) // if shutting down then there will be nothing to handle the return so leave till next restart
1239 {
1240 ILandObject parcel = m_scene.LandChannel.GetLandObject(
1241 m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y);
1242
1243 if (parcel != null && parcel.landData != null &&
1244 parcel.landData.OtherCleanTime != 0)
1245 {
1246 if (parcel.landData.OwnerID != OwnerID &&
1247 (parcel.landData.GroupID != GroupID ||
1248 parcel.landData.GroupID == UUID.Zero))
1249 {
1250 if ((DateTime.Now - RootPart.Rezzed).TotalMinutes >
1251 parcel.landData.OtherCleanTime)
1252 {
1253 DetachFromBackup();
1254 m_log.InfoFormat("[SCENE]: Returning object {0} due to parcel auto return", RootPart.UUID.ToString());
1255 m_scene.AddReturn(OwnerID, Name, AbsolutePosition, "parcel auto return");
1256 m_scene.DeRezObject(null, RootPart.LocalId,
1257 RootPart.GroupID, DeRezAction.Return, UUID.Zero);
1258
1259 return;
1260 }
1261 }
1262 }
1263 }
1264
1265 if (HasGroupChanged)
1266 {
1267 // don't backup while it's selected or you're asking for changes mid stream.
1268 if ((isTimeToPersist()) || (forcedBackup))
1269 {
1270 m_log.DebugFormat(
1271 "[SCENE]: Storing {0}, {1} in {2}",
1272 Name, UUID, m_scene.RegionInfo.RegionName);
1273
1274 SceneObjectGroup backup_group = Copy(OwnerID, GroupID, false);
1275 backup_group.RootPart.Velocity = RootPart.Velocity;
1276 backup_group.RootPart.Acceleration = RootPart.Acceleration;
1277 backup_group.RootPart.AngularVelocity = RootPart.AngularVelocity;
1278 backup_group.RootPart.ParticleSystem = RootPart.ParticleSystem;
1279 HasGroupChanged = false;
1280
1281 datastore.StoreObject(backup_group, m_scene.RegionInfo.RegionID);
1282
1283 backup_group.ForEachPart(delegate(SceneObjectPart part)
1284 {
1285 part.Inventory.ProcessInventoryBackup(datastore);
1286 });
1287
1288 backup_group = null;
1289 }
1290 // else
1291 // {
1292 // m_log.DebugFormat(
1293 // "[SCENE]: Did not update persistence of object {0} {1}, selected = {2}",
1294 // Name, UUID, IsSelected);
1295 // }
1296 }
1297 }
1298 catch (Exception e)
1299 {
1300 m_log.ErrorFormat(
1301 "[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}\n\t{4}",
1302 Name, UUID, m_scene.RegionInfo.RegionName, e, e.StackTrace);
1303 }
1304 }
1305
1306 #endregion
1307
1308 #region Client Updating
1309
1310 public void SendFullUpdateToClient(IClientAPI remoteClient)
1311 {
1312 SendPartFullUpdate(remoteClient, RootPart, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, RootPart.UUID));
1313
1314 lock (m_parts)
1315 {
1316 foreach (SceneObjectPart part in m_parts.Values)
1317 {
1318 if (part != RootPart)
1319 SendPartFullUpdate(remoteClient, part, m_scene.Permissions.GenerateClientFlags(remoteClient.AgentId, part.UUID));
1320 }
1321 }
1322 }
1323
1324 /// <summary>
1325 /// Send a full update to the client for the given part
1326 /// </summary>
1327 /// <param name="remoteClient"></param>
1328 /// <param name="part"></param>
1329 internal void SendPartFullUpdate(IClientAPI remoteClient, SceneObjectPart part, uint clientFlags)
1330 {
1331 if (m_rootPart != null && m_rootPart.UUID == part.UUID)
1332 {
1333 if (IsAttachment)
1334 {
1335 part.SendFullUpdateToClient(remoteClient, m_rootPart.AttachedPos, clientFlags);
1336 }
1337 else
1338 {
1339 part.SendFullUpdateToClient(remoteClient, AbsolutePosition, clientFlags);
1340 }
1341 }
1342 else
1343 {
1344 part.SendFullUpdateToClient(remoteClient, clientFlags);
1345 }
1346 }
1347
1348 #endregion
1349
1350 #region Copying
1351
1352 /// <summary>
1353 /// Duplicates this object, including operations such as physics set up and attaching to the backup event.
1354 /// </summary>
1355 /// <returns></returns>
1356 public SceneObjectGroup Copy(UUID cAgentID, UUID cGroupID, bool userExposed)
1357 {
1358 SceneObjectGroup dupe = (SceneObjectGroup)MemberwiseClone();
1359 dupe.m_isBackedUp = false;
1360 dupe.m_parts = new Dictionary<UUID, SceneObjectPart>();
1361 dupe.AbsolutePosition = new Vector3(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z);
1362
1363 dupe.CopyRootPart(m_rootPart, OwnerID, GroupID, userExposed);
1364 dupe.m_rootPart.LinkNum = m_rootPart.LinkNum;
1365
1366 if (userExposed)
1367 dupe.m_rootPart.TrimPermissions();
1368
1369 /// may need to create a new Physics actor.
1370 if (dupe.RootPart.PhysActor != null && userExposed)
1371 {
1372 PrimitiveBaseShape pbs = dupe.RootPart.Shape;
1373
1374 dupe.RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(
1375 dupe.RootPart.Name,
1376 pbs,
1377 new PhysicsVector(dupe.RootPart.AbsolutePosition.X, dupe.RootPart.AbsolutePosition.Y, dupe.RootPart.AbsolutePosition.Z),
1378 new PhysicsVector(dupe.RootPart.Scale.X, dupe.RootPart.Scale.Y, dupe.RootPart.Scale.Z),
1379 dupe.RootPart.RotationOffset,
1380 dupe.RootPart.PhysActor.IsPhysical);
1381
1382 dupe.RootPart.PhysActor.LocalID = dupe.RootPart.LocalId;
1383 dupe.RootPart.DoPhysicsPropertyUpdate(dupe.RootPart.PhysActor.IsPhysical, true);
1384 }
1385
1386 // Now we've made a copy that replaces this one, we need to
1387 // switch the owner to the person who did the copying
1388 // Second Life copies an object and duplicates the first one in it's place
1389 // So, we have to make a copy of this one, set it in it's place then set the owner on this one
1390 if (userExposed)
1391 {
1392 SetRootPartOwner(m_rootPart, cAgentID, cGroupID);
1393 m_rootPart.ScheduleFullUpdate();
1394 }
1395
1396 List<SceneObjectPart> partList;
1397
1398 lock (m_parts)
1399 {
1400 partList = new List<SceneObjectPart>(m_parts.Values);
1401 }
1402
1403 partList.Sort(delegate(SceneObjectPart p1, SceneObjectPart p2)
1404 {
1405 return p1.LinkNum.CompareTo(p2.LinkNum);
1406 }
1407 );
1408
1409 foreach (SceneObjectPart part in partList)
1410 {
1411 if (part.UUID != m_rootPart.UUID)
1412 {
1413 SceneObjectPart newPart = dupe.CopyPart(part, OwnerID, GroupID, userExposed);
1414
1415 newPart.LinkNum = part.LinkNum;
1416
1417 if (userExposed)
1418 {
1419 SetPartOwner(newPart, cAgentID, cGroupID);
1420 newPart.ScheduleFullUpdate();
1421 }
1422 }
1423 }
1424
1425 if (userExposed)
1426 {
1427 dupe.UpdateParentIDs();
1428 dupe.HasGroupChanged = true;
1429 dupe.AttachToBackup();
1430
1431 ScheduleGroupForFullUpdate();
1432 }
1433
1434 return dupe;
1435 }
1436
1437 /// <summary>
1438 ///
1439 /// </summary>
1440 /// <param name="part"></param>
1441 /// <param name="cAgentID"></param>
1442 /// <param name="cGroupID"></param>
1443 public void CopyRootPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1444 {
1445 SetRootPart(part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed));
1446 }
1447
1448 public void ScriptSetPhysicsStatus(bool UsePhysics)
1449 {
1450 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1451 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1452 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1453 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
1454 }
1455
1456 public void ScriptSetTemporaryStatus(bool TemporaryStatus)
1457 {
1458 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1459 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1460 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1461 UpdatePrimFlags(RootPart.LocalId, UsePhysics, TemporaryStatus, IsPhantom, IsVolumeDetect);
1462 }
1463
1464 public void ScriptSetPhantomStatus(bool PhantomStatus)
1465 {
1466 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1467 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1468 bool IsVolumeDetect = RootPart.VolumeDetectActive;
1469 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, PhantomStatus, IsVolumeDetect);
1470 }
1471
1472 public void ScriptSetVolumeDetect(bool VDStatus)
1473 {
1474 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1475 bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
1476 bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
1477 UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, VDStatus);
1478
1479 /*
1480 ScriptSetPhantomStatus(false); // What ever it was before, now it's not phantom anymore
1481
1482 if (PhysActor != null) // Should always be the case now
1483 {
1484 PhysActor.SetVolumeDetect(param);
1485 }
1486 if (param != 0)
1487 AddFlag(PrimFlags.Phantom);
1488
1489 ScheduleFullUpdate();
1490 */
1491 }
1492
1493 public void applyImpulse(PhysicsVector impulse)
1494 {
1495 // We check if rootpart is null here because scripts don't delete if you delete the host.
1496 // This means that unfortunately, we can pass a null physics actor to Simulate!
1497 // Make sure we don't do that!
1498 SceneObjectPart rootpart = m_rootPart;
1499 if (rootpart != null)
1500 {
1501 if (rootpart.PhysActor != null)
1502 {
1503 if (IsAttachment)
1504 {
1505 ScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
1506 if (avatar != null)
1507 {
1508 avatar.PushForce(impulse);
1509 }
1510 }
1511 else
1512 {
1513 rootpart.PhysActor.AddForce(impulse,true);
1514 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1515 }
1516 }
1517 }
1518 }
1519
1520 public void applyAngularImpulse(PhysicsVector impulse)
1521 {
1522 // We check if rootpart is null here because scripts don't delete if you delete the host.
1523 // This means that unfortunately, we can pass a null physics actor to Simulate!
1524 // Make sure we don't do that!
1525 SceneObjectPart rootpart = m_rootPart;
1526 if (rootpart != null)
1527 {
1528 if (rootpart.PhysActor != null)
1529 {
1530 if (!IsAttachment)
1531 {
1532 rootpart.PhysActor.AddAngularForce(impulse, true);
1533 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1534 }
1535 }
1536 }
1537 }
1538
1539 public void setAngularImpulse(PhysicsVector impulse)
1540 {
1541 // We check if rootpart is null here because scripts don't delete if you delete the host.
1542 // This means that unfortunately, we can pass a null physics actor to Simulate!
1543 // Make sure we don't do that!
1544 SceneObjectPart rootpart = m_rootPart;
1545 if (rootpart != null)
1546 {
1547 if (rootpart.PhysActor != null)
1548 {
1549 if (!IsAttachment)
1550 {
1551 rootpart.PhysActor.Torque = impulse;
1552 m_scene.PhysicsScene.AddPhysicsActorTaint(rootpart.PhysActor);
1553 }
1554 }
1555 }
1556 }
1557
1558 public Vector3 GetTorque()
1559 {
1560 // We check if rootpart is null here because scripts don't delete if you delete the host.
1561 // This means that unfortunately, we can pass a null physics actor to Simulate!
1562 // Make sure we don't do that!
1563 SceneObjectPart rootpart = m_rootPart;
1564 if (rootpart != null)
1565 {
1566 if (rootpart.PhysActor != null)
1567 {
1568 if (!IsAttachment)
1569 {
1570 PhysicsVector torque = rootpart.PhysActor.Torque;
1571 return new Vector3(torque.X, torque.Y, torque.Z);
1572 }
1573 }
1574 }
1575 return Vector3.Zero;
1576 }
1577
1578 public void moveToTarget(Vector3 target, float tau)
1579 {
1580 SceneObjectPart rootpart = m_rootPart;
1581 if (rootpart != null)
1582 {
1583 if (rootpart.PhysActor != null)
1584 {
1585 rootpart.PhysActor.PIDTarget = new PhysicsVector(target.X, target.Y, target.Z);
1586 rootpart.PhysActor.PIDTau = tau;
1587 rootpart.PhysActor.PIDActive = true;
1588 }
1589 }
1590 }
1591
1592 public void stopMoveToTarget()
1593 {
1594 SceneObjectPart rootpart = m_rootPart;
1595 if (rootpart != null)
1596 {
1597 if (rootpart.PhysActor != null)
1598 {
1599 rootpart.PhysActor.PIDActive = false;
1600 }
1601 }
1602 }
1603
1604 /// <summary>
1605 /// Set the owner of the root part.
1606 /// </summary>
1607 /// <param name="part"></param>
1608 /// <param name="cAgentID"></param>
1609 /// <param name="cGroupID"></param>
1610 public void SetRootPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
1611 {
1612 part.LastOwnerID = part.OwnerID;
1613 part.OwnerID = cAgentID;
1614 part.GroupID = cGroupID;
1615
1616 if (part.OwnerID != cAgentID)
1617 {
1618 // Apply Next Owner Permissions if we're not bypassing permissions
1619 if (!m_scene.Permissions.BypassPermissions())
1620 ApplyNextOwnerPermissions();
1621 }
1622
1623 part.ScheduleFullUpdate();
1624 }
1625
1626 /// <summary>
1627 /// Make a copy of the given part.
1628 /// </summary>
1629 /// <param name="part"></param>
1630 /// <param name="cAgentID"></param>
1631 /// <param name="cGroupID"></param>
1632 public SceneObjectPart CopyPart(SceneObjectPart part, UUID cAgentID, UUID cGroupID, bool userExposed)
1633 {
1634 SceneObjectPart newPart = part.Copy(m_scene.AllocateLocalId(), OwnerID, GroupID, m_parts.Count, userExposed);
1635 newPart.SetParent(this);
1636
1637 lock (m_parts)
1638 {
1639 m_parts.Add(newPart.UUID, newPart);
1640 }
1641
1642 SetPartAsNonRoot(newPart);
1643
1644 return newPart;
1645 }
1646
1647 /// <summary>
1648 /// Reset the UUIDs for all the prims that make up this group.
1649 ///
1650 /// This is called by methods which want to add a new group to an existing scene, in order
1651 /// to ensure that there are no clashes with groups already present.
1652 /// </summary>
1653 public void ResetIDs()
1654 {
1655 // As this is only ever called for prims which are not currently part of the scene (and hence
1656 // not accessible by clients), there should be no need to lock
1657 List<SceneObjectPart> partsList = new List<SceneObjectPart>(m_parts.Values);
1658 m_parts.Clear();
1659 foreach (SceneObjectPart part in partsList)
1660 {
1661 part.ResetIDs(part.LinkNum); // Don't change link nums
1662 m_parts.Add(part.UUID, part);
1663 }
1664 }
1665
1666 /// <summary>
1667 ///
1668 /// </summary>
1669 /// <param name="part"></param>
1670 public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
1671 {
1672
1673 remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.ObjectOwner, RootPart.GroupID, RootPart.BaseMask,
1674 RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
1675 RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
1676 RootPart.CreatorID, RootPart.Name, RootPart.Description);
1677 }
1678
1679 public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
1680 {
1681 part.OwnerID = cAgentID;
1682 part.GroupID = cGroupID;
1683 }
1684
1685 #endregion
1686
1687 #region Scheduling
1688
1689 public override void Update()
1690 {
1691 // Check that the group was not deleted before the scheduled update
1692 // FIXME: This is merely a temporary measure to reduce the incidence of failure when
1693 // an object has been deleted from a scene before update was processed.
1694 // A more fundamental overhaul of the update mechanism is required to eliminate all
1695 // the race conditions.
1696 if (m_isDeleted)
1697 return;
1698
1699 // This is what happens when an orphanced link set child prim's
1700 // group was queued when it was linked
1701 //
1702 if (m_rootPart == null)
1703 return;
1704
1705 lock (m_parts)
1706 {
1707 bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
1708
1709 //if (IsAttachment)
1710 //{
1711 //foreach (SceneObjectPart part in m_parts.Values)
1712 //{
1713 //part.SendScheduledUpdates();
1714 //}
1715 //return;
1716 //}
1717
1718 if ((Util.GetDistanceTo(lastPhysGroupPos, AbsolutePosition) > 0.02) && UsePhysics)
1719 {
1720 m_rootPart.UpdateFlag = 1;
1721 lastPhysGroupPos = AbsolutePosition;
1722 }
1723 //foreach (SceneObjectPart part in m_parts.Values)
1724 //{
1725 //if (part.UpdateFlag == 0) part.UpdateFlag = 1;
1726 //}
1727
1728 checkAtTargets();
1729
1730 if (((Math.Abs(lastPhysGroupRot.W - GroupRotation.W) > 0.1)
1731 || (Math.Abs(lastPhysGroupRot.X - GroupRotation.X) > 0.1)
1732 || (Math.Abs(lastPhysGroupRot.Y - GroupRotation.Y) > 0.1)
1733 || (Math.Abs(lastPhysGroupRot.Z - GroupRotation.Z) > 0.1))
1734 && UsePhysics)
1735 {
1736 m_rootPart.UpdateFlag = 1;
1737
1738 lastPhysGroupRot = GroupRotation;
1739 }
1740
1741 foreach (SceneObjectPart part in m_parts.Values)
1742 {
1743 part.SendScheduledUpdates();
1744 }
1745 }
1746 }
1747
1748 public void ScheduleFullUpdateToAvatar(ScenePresence presence)
1749 {
1750 RootPart.AddFullUpdateToAvatar(presence);
1751
1752 lock (m_parts)
1753 {
1754 foreach (SceneObjectPart part in m_parts.Values)
1755 {
1756 if (part != RootPart)
1757 part.AddFullUpdateToAvatar(presence);
1758 }
1759 }
1760 }
1761
1762 public void ScheduleTerseUpdateToAvatar(ScenePresence presence)
1763 {
1764 lock (m_parts)
1765 {
1766 foreach (SceneObjectPart part in m_parts.Values)
1767 {
1768 part.AddTerseUpdateToAvatar(presence);
1769 }
1770 }
1771 }
1772
1773 /// <summary>
1774 /// Schedule a full update for this scene object
1775 /// </summary>
1776 public void ScheduleGroupForFullUpdate()
1777 {
1778 checkAtTargets();
1779 RootPart.ScheduleFullUpdate();
1780
1781 lock (m_parts)
1782 {
1783 foreach (SceneObjectPart part in m_parts.Values)
1784 {
1785 if (part != RootPart)
1786 part.ScheduleFullUpdate();
1787 }
1788 }
1789 }
1790
1791 /// <summary>
1792 /// Schedule a terse update for this scene object
1793 /// </summary>
1794 public void ScheduleGroupForTerseUpdate()
1795 {
1796 lock (m_parts)
1797 {
1798 foreach (SceneObjectPart part in m_parts.Values)
1799 {
1800 part.ScheduleTerseUpdate();
1801 }
1802 }
1803 }
1804
1805 /// <summary>
1806 /// Immediately send a full update for this scene object.
1807 /// </summary>
1808 public void SendGroupFullUpdate()
1809 {
1810 if (IsDeleted)
1811 return;
1812
1813 RootPart.SendFullUpdateToAllClients();
1814
1815 lock (m_parts)
1816 {
1817 foreach (SceneObjectPart part in m_parts.Values)
1818 {
1819 if (part != RootPart)
1820 part.SendFullUpdateToAllClients();
1821 }
1822 }
1823 }
1824
1825 /// <summary>
1826 /// Immediately send an update for this scene object's root prim only.
1827 /// This is for updates regarding the object as a whole, and none of its parts in particular.
1828 /// Note: this may not be cused by opensim (it probably should) but it's used by
1829 /// external modules.
1830 /// </summary>
1831 public void SendGroupRootUpdate()
1832 {
1833 if (IsDeleted)
1834 return;
1835
1836 RootPart.SendFullUpdateToAllClients();
1837 }
1838
1839 public void QueueForUpdateCheck()
1840 {
1841 if (m_scene == null) // Need to check here as it's null during object creation
1842 return;
1843 m_scene.m_sceneGraph.AddToUpdateList(this);
1844 }
1845
1846 /// <summary>
1847 /// Immediately send a terse update for this scene object.
1848 /// </summary>
1849 public void SendGroupTerseUpdate()
1850 {
1851 if (IsDeleted)
1852 return;
1853
1854 lock (m_parts)
1855 {
1856 foreach (SceneObjectPart part in m_parts.Values)
1857 {
1858 part.SendTerseUpdateToAllClients();
1859 }
1860 }
1861 }
1862
1863 #endregion
1864
1865 #region SceneGroupPart Methods
1866
1867 /// <summary>
1868 /// Get the child part by LinkNum
1869 /// </summary>
1870 /// <param name="linknum"></param>
1871 /// <returns>null if no child part with that linknum or child part</returns>
1872 public SceneObjectPart GetLinkNumPart(int linknum)
1873 {
1874 lock (m_parts)
1875 {
1876 foreach (SceneObjectPart part in m_parts.Values)
1877 {
1878 if (part.LinkNum == linknum)
1879 {
1880 return part;
1881 }
1882 }
1883 }
1884
1885 return null;
1886 }
1887
1888 /// <summary>
1889 /// Get a child part with a given UUID
1890 /// </summary>
1891 /// <param name="primID"></param>
1892 /// <returns>null if a child part with the primID was not found</returns>
1893 public SceneObjectPart GetChildPart(UUID primID)
1894 {
1895 SceneObjectPart childPart = null;
1896 if (m_parts.ContainsKey(primID))
1897 {
1898 childPart = m_parts[primID];
1899 }
1900 return childPart;
1901 }
1902
1903 /// <summary>
1904 /// Get a child part with a given local ID
1905 /// </summary>
1906 /// <param name="localID"></param>
1907 /// <returns>null if a child part with the local ID was not found</returns>
1908 public SceneObjectPart GetChildPart(uint localID)
1909 {
1910 //m_log.DebugFormat("Entered looking for {0}", localID);
1911 lock (m_parts)
1912 {
1913 foreach (SceneObjectPart part in m_parts.Values)
1914 {
1915 //m_log.DebugFormat("Found {0}", part.LocalId);
1916 if (part.LocalId == localID)
1917 {
1918 return part;
1919 }
1920 }
1921 }
1922
1923 return null;
1924 }
1925
1926 /// <summary>
1927 /// Does this group contain the child prim
1928 /// should be able to remove these methods once we have a entity index in scene
1929 /// </summary>
1930 /// <param name="primID"></param>
1931 /// <returns></returns>
1932 public bool HasChildPrim(UUID primID)
1933 {
1934 if (m_parts.ContainsKey(primID))
1935 {
1936 return true;
1937 }
1938
1939 return false;
1940 }
1941
1942 /// <summary>
1943 /// Does this group contain the child prim
1944 /// should be able to remove these methods once we have a entity index in scene
1945 /// </summary>
1946 /// <param name="localID"></param>
1947 /// <returns></returns>
1948 public bool HasChildPrim(uint localID)
1949 {
1950 //m_log.DebugFormat("Entered HasChildPrim looking for {0}", localID);
1951 lock (m_parts)
1952 {
1953 foreach (SceneObjectPart part in m_parts.Values)
1954 {
1955 //m_log.DebugFormat("Found {0}", part.LocalId);
1956 if (part.LocalId == localID)
1957 {
1958 return true;
1959 }
1960 }
1961 }
1962
1963 return false;
1964 }
1965
1966 #endregion
1967
1968 #region Packet Handlers
1969
1970 /// <summary>
1971 /// Link the prims in a given group to this group
1972 /// </summary>
1973 /// <param name="objectGroup">The group of prims which should be linked to this group</param>
1974 public void LinkToGroup(SceneObjectGroup objectGroup)
1975 {
1976 if (objectGroup.RootPart.UpdateFlag > 0)
1977 {
1978 // I've never actually seen this happen, though I think it's theoretically possible
1979 m_log.WarnFormat(
1980 "[SCENE OBJECT GROUP]: Aborted linking {0}, {1} to {2}, {3} as it has yet to finish delinking",
1981 objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
1982
1983 return;
1984 }
1985
1986// m_log.DebugFormat(
1987// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
1988// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
1989
1990 SceneObjectPart linkPart = objectGroup.m_rootPart;
1991
1992 Vector3 oldGroupPosition = linkPart.GroupPosition;
1993 Quaternion oldRootRotation = linkPart.RotationOffset;
1994
1995 linkPart.OffsetPosition = linkPart.GroupPosition - AbsolutePosition;
1996 linkPart.GroupPosition = AbsolutePosition;
1997 Vector3 axPos = linkPart.OffsetPosition;
1998
1999 Quaternion parentRot = m_rootPart.RotationOffset;
2000 axPos *= Quaternion.Inverse(parentRot);
2001
2002 linkPart.OffsetPosition = axPos;
2003 Quaternion oldRot = linkPart.RotationOffset;
2004 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
2005 linkPart.RotationOffset = newRot;
2006
2007 linkPart.ParentID = m_rootPart.LocalId;
2008 if (m_rootPart.LinkNum == 0)
2009 m_rootPart.LinkNum = 1;
2010
2011 lock (m_parts)
2012 {
2013 m_parts.Add(linkPart.UUID, linkPart);
2014
2015 // Insert in terms of link numbers, the new links
2016 // before the current ones (with the exception of
2017 // the root prim. Shuffle the old ones up
2018 foreach (KeyValuePair<UUID, SceneObjectPart> kvp in m_parts)
2019 {
2020 if (kvp.Value.LinkNum != 1)
2021 {
2022 // Don't update root prim link number
2023 kvp.Value.LinkNum += objectGroup.PrimCount;
2024 }
2025 }
2026
2027 linkPart.LinkNum = 2;
2028
2029 linkPart.SetParent(this);
2030 linkPart.AddFlag(PrimFlags.CreateSelected);
2031
2032 //if (linkPart.PhysActor != null)
2033 //{
2034 // m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2035
2036 //linkPart.PhysActor = null;
2037 //}
2038
2039 //TODO: rest of parts
2040 int linkNum = 3;
2041 foreach (SceneObjectPart part in objectGroup.Children.Values)
2042 {
2043 if (part.UUID != objectGroup.m_rootPart.UUID)
2044 {
2045 LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
2046 }
2047 part.ClearUndoState();
2048 }
2049 }
2050
2051 m_scene.UnlinkSceneObject(objectGroup.UUID, true);
2052 objectGroup.m_isDeleted = true;
2053
2054 lock (objectGroup.m_parts)
2055 {
2056 objectGroup.m_parts.Clear();
2057 }
2058
2059 // Can't do this yet since backup still makes use of the root part without any synchronization
2060// objectGroup.m_rootPart = null;
2061
2062 AttachToBackup();
2063 HasGroupChanged = true;
2064 ScheduleGroupForFullUpdate();
2065 }
2066
2067 /// <summary>
2068 /// Delink the given prim from this group. The delinked prim is established as
2069 /// an independent SceneObjectGroup.
2070 /// </summary>
2071 /// <param name="partID"></param>
2072 public void DelinkFromGroup(uint partID)
2073 {
2074 DelinkFromGroup(partID, true);
2075 }
2076
2077 /// <summary>
2078 /// Delink the given prim from this group. The delinked prim is established as
2079 /// an independent SceneObjectGroup.
2080 /// </summary>
2081 /// <param name="partID"></param>
2082 /// <param name="sendEvents"></param>
2083 public void DelinkFromGroup(uint partID, bool sendEvents)
2084 {
2085 SceneObjectPart linkPart = GetChildPart(partID);
2086
2087 if (null != linkPart)
2088 {
2089 linkPart.ClearUndoState();
2090// m_log.DebugFormat(
2091// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2092// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2093
2094 Quaternion worldRot = linkPart.GetWorldRotation();
2095
2096 // Remove the part from this object
2097 lock (m_parts)
2098 {
2099 m_parts.Remove(linkPart.UUID);
2100 }
2101
2102 if (m_parts.Count == 1 && RootPart != null) //Single prim is left
2103 RootPart.LinkNum = 0;
2104 else
2105 {
2106 foreach (SceneObjectPart p in m_parts.Values)
2107 {
2108 if (p.LinkNum > linkPart.LinkNum)
2109 p.LinkNum--;
2110 }
2111 }
2112
2113 linkPart.ParentID = 0;
2114 linkPart.LinkNum = 0;
2115
2116 if (linkPart.PhysActor != null)
2117 {
2118 m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
2119 }
2120
2121 // We need to reset the child part's position
2122 // ready for life as a separate object after being a part of another object
2123 Quaternion parentRot = m_rootPart.RotationOffset;
2124
2125 Vector3 axPos = linkPart.OffsetPosition;
2126
2127 axPos *= parentRot;
2128 linkPart.OffsetPosition = new Vector3(axPos.X, axPos.Y, axPos.Z);
2129 linkPart.GroupPosition = AbsolutePosition + linkPart.OffsetPosition;
2130 linkPart.OffsetPosition = new Vector3(0, 0, 0);
2131
2132 linkPart.RotationOffset = worldRot;
2133
2134 SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart);
2135
2136 m_scene.AddNewSceneObject(objectGroup, true);
2137
2138 if (sendEvents)
2139 linkPart.TriggerScriptChangedEvent(Changed.LINK);
2140
2141 linkPart.Rezzed = RootPart.Rezzed;
2142
2143 HasGroupChanged = true;
2144 ScheduleGroupForFullUpdate();
2145 }
2146 else
2147 {
2148 m_log.InfoFormat("[SCENE OBJECT GROUP]: " +
2149 "DelinkFromGroup(): Child prim {0} not found in object {1}, {2}",
2150 partID, LocalId, UUID);
2151 }
2152 }
2153
2154 /// <summary>
2155 /// Stop this object from being persisted over server restarts.
2156 /// </summary>
2157 /// <param name="objectGroup"></param>
2158 public void DetachFromBackup()
2159 {
2160 if (m_isBackedUp)
2161 m_scene.EventManager.OnBackup -= ProcessBackup;
2162
2163 m_isBackedUp = false;
2164 }
2165
2166 private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation, int linkNum)
2167 {
2168
2169 Quaternion parentRot = oldGroupRotation;
2170 Quaternion oldRot = part.RotationOffset;
2171 Quaternion worldRot = parentRot * oldRot;
2172
2173 parentRot = oldGroupRotation;
2174
2175 Vector3 axPos = part.OffsetPosition;
2176
2177 axPos *= parentRot;
2178 part.OffsetPosition = axPos;
2179 part.GroupPosition = oldGroupPosition + part.OffsetPosition;
2180 part.OffsetPosition = Vector3.Zero;
2181 part.RotationOffset = worldRot;
2182
2183 part.SetParent(this);
2184 part.ParentID = m_rootPart.LocalId;
2185
2186 // Caller locks m_parts for us
2187 m_parts.Add(part.UUID, part);
2188
2189 part.LinkNum = linkNum;
2190
2191
2192 part.OffsetPosition = part.GroupPosition - AbsolutePosition;
2193
2194 Quaternion rootRotation = m_rootPart.RotationOffset;
2195
2196 Vector3 pos = part.OffsetPosition;
2197 pos *= Quaternion.Inverse(rootRotation);
2198 part.OffsetPosition = pos;
2199
2200 parentRot = m_rootPart.RotationOffset;
2201 oldRot = part.RotationOffset;
2202 Quaternion newRot = Quaternion.Inverse(parentRot) * oldRot;
2203 part.RotationOffset = newRot;
2204 }
2205
2206 /// <summary>
2207 /// If object is physical, apply force to move it around
2208 /// If object is not physical, just put it at the resulting location
2209 /// </summary>
2210 /// <param name="offset">Always seems to be 0,0,0, so ignoring</param>
2211 /// <param name="pos">New position. We do the math here to turn it into a force</param>
2212 /// <param name="remoteClient"></param>
2213 public void GrabMovement(Vector3 offset, Vector3 pos, IClientAPI remoteClient)
2214 {
2215 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2216 {
2217 if (m_rootPart.PhysActor != null)
2218 {
2219 if (m_rootPart.PhysActor.IsPhysical)
2220 {
2221 Vector3 llmoveforce = pos - AbsolutePosition;
2222 PhysicsVector grabforce = new PhysicsVector(llmoveforce.X, llmoveforce.Y, llmoveforce.Z);
2223 grabforce = (grabforce / 10) * m_rootPart.PhysActor.Mass;
2224 m_rootPart.PhysActor.AddForce(grabforce,true);
2225 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2226 }
2227 else
2228 {
2229 //NonPhysicalGrabMovement(pos);
2230 }
2231 }
2232 else
2233 {
2234 //NonPhysicalGrabMovement(pos);
2235 }
2236 }
2237 }
2238
2239 public void NonPhysicalGrabMovement(Vector3 pos)
2240 {
2241 AbsolutePosition = pos;
2242 m_rootPart.SendTerseUpdateToAllClients();
2243 }
2244
2245 /// <summary>
2246 /// Return metadata about a prim (name, description, sale price, etc.)
2247 /// </summary>
2248 /// <param name="client"></param>
2249 public void GetProperties(IClientAPI client)
2250 {
2251 m_rootPart.GetProperties(client);
2252 }
2253
2254 /// <summary>
2255 /// Set the name of a prim
2256 /// </summary>
2257 /// <param name="name"></param>
2258 /// <param name="localID"></param>
2259 public void SetPartName(string name, uint localID)
2260 {
2261 SceneObjectPart part = GetChildPart(localID);
2262 if (part != null)
2263 {
2264 part.Name = name;
2265 }
2266 }
2267
2268 public void SetPartDescription(string des, uint localID)
2269 {
2270 SceneObjectPart part = GetChildPart(localID);
2271 if (part != null)
2272 {
2273 part.Description = des;
2274 }
2275 }
2276
2277 public void SetPartText(string text, uint localID)
2278 {
2279 SceneObjectPart part = GetChildPart(localID);
2280 if (part != null)
2281 {
2282 part.SetText(text);
2283 }
2284 }
2285
2286 public void SetPartText(string text, UUID partID)
2287 {
2288 SceneObjectPart part = GetChildPart(partID);
2289 if (part != null)
2290 {
2291 part.SetText(text);
2292 }
2293 }
2294
2295 public string GetPartName(uint localID)
2296 {
2297 SceneObjectPart part = GetChildPart(localID);
2298 if (part != null)
2299 {
2300 return part.Name;
2301 }
2302 return String.Empty;
2303 }
2304
2305 public string GetPartDescription(uint localID)
2306 {
2307 SceneObjectPart part = GetChildPart(localID);
2308 if (part != null)
2309 {
2310 return part.Description;
2311 }
2312 return String.Empty;
2313 }
2314
2315 /// <summary>
2316 /// Update prim flags for this group.
2317 /// </summary>
2318 /// <param name="localID"></param>
2319 /// <param name="type"></param>
2320 /// <param name="inUse"></param>
2321 /// <param name="data"></param>
2322 public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVolumeDetect)
2323 {
2324 SceneObjectPart selectionPart = GetChildPart(localID);
2325
2326 if (IsTemporary)
2327 {
2328 DetachFromBackup();
2329 // Remove from database and parcel prim count
2330 //
2331 m_scene.DeleteFromStorage(UUID);
2332 m_scene.EventManager.TriggerParcelPrimCountTainted();
2333 }
2334
2335 if (selectionPart != null)
2336 {
2337 lock (m_parts)
2338 {
2339 foreach (SceneObjectPart part in m_parts.Values)
2340 {
2341 if (part.Scale.X > 10.0 || part.Scale.Y > 10.0 || part.Scale.Z > 10.0)
2342 {
2343 UsePhysics = false; // Reset physics
2344 break;
2345 }
2346 }
2347
2348 foreach (SceneObjectPart part in m_parts.Values)
2349 {
2350 part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect);
2351 }
2352 }
2353 }
2354 }
2355
2356 public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
2357 {
2358 SceneObjectPart part = GetChildPart(localID);
2359 if (part != null)
2360 {
2361 part.UpdateExtraParam(type, inUse, data);
2362 }
2363 }
2364
2365 /// <summary>
2366 /// Get the parts of this scene object
2367 /// </summary>
2368 /// <returns></returns>
2369 public SceneObjectPart[] GetParts()
2370 {
2371 int numParts = Children.Count;
2372 SceneObjectPart[] partArray = new SceneObjectPart[numParts];
2373 Children.Values.CopyTo(partArray, 0);
2374 return partArray;
2375 }
2376
2377 /// <summary>
2378 /// Update the texture entry for this part
2379 /// </summary>
2380 /// <param name="localID"></param>
2381 /// <param name="textureEntry"></param>
2382 public void UpdateTextureEntry(uint localID, byte[] textureEntry)
2383 {
2384 SceneObjectPart part = GetChildPart(localID);
2385 if (part != null)
2386 {
2387 part.UpdateTextureEntry(textureEntry);
2388 }
2389 }
2390
2391 public void UpdatePermissions(UUID AgentID, byte field, uint localID,
2392 uint mask, byte addRemTF)
2393 {
2394 foreach (SceneObjectPart part in m_parts.Values)
2395 part.UpdatePermissions(AgentID, field, localID, mask,
2396 addRemTF);
2397
2398 HasGroupChanged = true;
2399 }
2400
2401 #endregion
2402
2403 #region Shape
2404
2405 /// <summary>
2406 ///
2407 /// </summary>
2408 /// <param name="shapeBlock"></param>
2409 public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID)
2410 {
2411 SceneObjectPart part = GetChildPart(localID);
2412 if (part != null)
2413 {
2414 part.UpdateShape(shapeBlock);
2415
2416 if (part.PhysActor != null)
2417 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2418 }
2419 }
2420
2421 #endregion
2422
2423 #region Resize
2424
2425 /// <summary>
2426 /// Resize the given part
2427 /// </summary>
2428 /// <param name="scale"></param>
2429 /// <param name="localID"></param>
2430 public void Resize(Vector3 scale, uint localID)
2431 {
2432 if (scale.X > m_scene.m_maxNonphys)
2433 scale.X = m_scene.m_maxNonphys;
2434 if (scale.Y > m_scene.m_maxNonphys)
2435 scale.Y = m_scene.m_maxNonphys;
2436 if (scale.Z > m_scene.m_maxNonphys)
2437 scale.Z = m_scene.m_maxNonphys;
2438
2439 SceneObjectPart part = GetChildPart(localID);
2440 if (part != null)
2441 {
2442 part.Resize(scale);
2443 if (part.PhysActor != null)
2444 {
2445 if (part.PhysActor.IsPhysical)
2446 {
2447 if (scale.X > m_scene.m_maxPhys)
2448 scale.X = m_scene.m_maxPhys;
2449 if (scale.Y > m_scene.m_maxPhys)
2450 scale.Y = m_scene.m_maxPhys;
2451 if (scale.Z > m_scene.m_maxPhys)
2452 scale.Z = m_scene.m_maxPhys;
2453 }
2454 part.PhysActor.Size =
2455 new PhysicsVector(scale.X, scale.Y, scale.Z);
2456 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2457 }
2458 //if (part.UUID != m_rootPart.UUID)
2459
2460 HasGroupChanged = true;
2461 ScheduleGroupForFullUpdate();
2462
2463 //if (part.UUID == m_rootPart.UUID)
2464 //{
2465 //if (m_rootPart.PhysActor != null)
2466 //{
2467 //m_rootPart.PhysActor.Size =
2468 //new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z);
2469 //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2470 //}
2471 //}
2472 }
2473 }
2474
2475 public void GroupResize(Vector3 scale, uint localID)
2476 {
2477 SceneObjectPart part = GetChildPart(localID);
2478 if (part != null)
2479 {
2480 if (scale.X > m_scene.m_maxNonphys)
2481 scale.X = m_scene.m_maxNonphys;
2482 if (scale.Y > m_scene.m_maxNonphys)
2483 scale.Y = m_scene.m_maxNonphys;
2484 if (scale.Z > m_scene.m_maxNonphys)
2485 scale.Z = m_scene.m_maxNonphys;
2486 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2487 {
2488 if (scale.X > m_scene.m_maxPhys)
2489 scale.X = m_scene.m_maxPhys;
2490 if (scale.Y > m_scene.m_maxPhys)
2491 scale.Y = m_scene.m_maxPhys;
2492 if (scale.Z > m_scene.m_maxPhys)
2493 scale.Z = m_scene.m_maxPhys;
2494 }
2495 float x = (scale.X / part.Scale.X);
2496 float y = (scale.Y / part.Scale.Y);
2497 float z = (scale.Z / part.Scale.Z);
2498
2499 lock (m_parts)
2500 {
2501 if (x > 1.0f || y > 1.0f || z > 1.0f)
2502 {
2503 foreach (SceneObjectPart obPart in m_parts.Values)
2504 {
2505 if (obPart.UUID != m_rootPart.UUID)
2506 {
2507 Vector3 oldSize = new Vector3(obPart.Scale);
2508
2509 float f = 1.0f;
2510 float a = 1.0f;
2511
2512 if (part.PhysActor != null && part.PhysActor.IsPhysical)
2513 {
2514 if (oldSize.X*x > m_scene.m_maxPhys)
2515 {
2516 f = m_scene.m_maxPhys / oldSize.X;
2517 a = f / x;
2518 x *= a;
2519 y *= a;
2520 z *= a;
2521 }
2522 if (oldSize.Y*y > m_scene.m_maxPhys)
2523 {
2524 f = m_scene.m_maxPhys / oldSize.Y;
2525 a = f / y;
2526 x *= a;
2527 y *= a;
2528 z *= a;
2529 }
2530 if (oldSize.Z*z > m_scene.m_maxPhys)
2531 {
2532 f = m_scene.m_maxPhys / oldSize.Z;
2533 a = f / z;
2534 x *= a;
2535 y *= a;
2536 z *= a;
2537 }
2538 }
2539 else
2540 {
2541 if (oldSize.X*x > m_scene.m_maxNonphys)
2542 {
2543 f = m_scene.m_maxNonphys / oldSize.X;
2544 a = f / x;
2545 x *= a;
2546 y *= a;
2547 z *= a;
2548 }
2549 if (oldSize.Y*y > m_scene.m_maxNonphys)
2550 {
2551 f = m_scene.m_maxNonphys / oldSize.Y;
2552 a = f / y;
2553 x *= a;
2554 y *= a;
2555 z *= a;
2556 }
2557 if (oldSize.Z*z > m_scene.m_maxNonphys)
2558 {
2559 f = m_scene.m_maxNonphys / oldSize.Z;
2560 a = f / z;
2561 x *= a;
2562 y *= a;
2563 z *= a;
2564 }
2565 }
2566 }
2567 }
2568 }
2569 }
2570
2571 Vector3 prevScale = part.Scale;
2572 prevScale.X *= x;
2573 prevScale.Y *= y;
2574 prevScale.Z *= z;
2575 part.Resize(prevScale);
2576
2577 lock (m_parts)
2578 {
2579 foreach (SceneObjectPart obPart in m_parts.Values)
2580 {
2581 if (obPart.UUID != m_rootPart.UUID)
2582 {
2583 Vector3 currentpos = new Vector3(obPart.OffsetPosition);
2584 currentpos.X *= x;
2585 currentpos.Y *= y;
2586 currentpos.Z *= z;
2587 Vector3 newSize = new Vector3(obPart.Scale);
2588 newSize.X *= x;
2589 newSize.Y *= y;
2590 newSize.Z *= z;
2591 obPart.Resize(newSize);
2592 obPart.UpdateOffSet(currentpos);
2593 }
2594 }
2595 }
2596
2597 if (part.PhysActor != null)
2598 {
2599 part.PhysActor.Size =
2600 new PhysicsVector(prevScale.X, prevScale.Y, prevScale.Z);
2601 m_scene.PhysicsScene.AddPhysicsActorTaint(part.PhysActor);
2602 }
2603
2604 HasGroupChanged = true;
2605 ScheduleGroupForTerseUpdate();
2606 }
2607 }
2608
2609 #endregion
2610
2611 #region Position
2612
2613 /// <summary>
2614 /// Move this scene object
2615 /// </summary>
2616 /// <param name="pos"></param>
2617 public void UpdateGroupPosition(Vector3 pos)
2618 {
2619 if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
2620 {
2621 if (IsAttachment)
2622 {
2623 m_rootPart.AttachedPos = pos;
2624 }
2625
2626 AbsolutePosition = pos;
2627
2628 HasGroupChanged = true;
2629 }
2630
2631 //we need to do a terse update even if the move wasn't allowed
2632 // so that the position is reset in the client (the object snaps back)
2633 ScheduleGroupForTerseUpdate();
2634 }
2635
2636 /// <summary>
2637 /// Update the position of a single part of this scene object
2638 /// </summary>
2639 /// <param name="pos"></param>
2640 /// <param name="localID"></param>
2641 public void UpdateSinglePosition(Vector3 pos, uint localID)
2642 {
2643 SceneObjectPart part = GetChildPart(localID);
2644
2645 if (part != null)
2646 {
2647 if (part.UUID == m_rootPart.UUID)
2648 {
2649 UpdateRootPosition(pos);
2650 }
2651 else
2652 {
2653 part.UpdateOffSet(pos);
2654 }
2655
2656 HasGroupChanged = true;
2657 }
2658 }
2659
2660 /// <summary>
2661 ///
2662 /// </summary>
2663 /// <param name="pos"></param>
2664 private void UpdateRootPosition(Vector3 pos)
2665 {
2666 Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
2667 Vector3 oldPos =
2668 new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
2669 AbsolutePosition.Y + m_rootPart.OffsetPosition.Y,
2670 AbsolutePosition.Z + m_rootPart.OffsetPosition.Z);
2671 Vector3 diff = oldPos - newPos;
2672 Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z);
2673 Quaternion partRotation = m_rootPart.RotationOffset;
2674 axDiff *= Quaternion.Inverse(partRotation);
2675 diff = axDiff;
2676
2677 lock (m_parts)
2678 {
2679 foreach (SceneObjectPart obPart in m_parts.Values)
2680 {
2681 if (obPart.UUID != m_rootPart.UUID)
2682 {
2683 obPart.OffsetPosition = obPart.OffsetPosition + diff;
2684 }
2685 }
2686 }
2687
2688 AbsolutePosition = newPos;
2689
2690 HasGroupChanged = true;
2691 ScheduleGroupForTerseUpdate();
2692 }
2693
2694 public void OffsetForNewRegion(Vector3 offset)
2695 {
2696 m_rootPart.GroupPosition = offset;
2697 }
2698
2699 #endregion
2700
2701 #region Rotation
2702
2703 /// <summary>
2704 ///
2705 /// </summary>
2706 /// <param name="rot"></param>
2707 public void UpdateGroupRotation(Quaternion rot)
2708 {
2709 m_rootPart.UpdateRotation(rot);
2710 if (m_rootPart.PhysActor != null)
2711 {
2712 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
2713 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2714 }
2715
2716 HasGroupChanged = true;
2717 ScheduleGroupForTerseUpdate();
2718 }
2719
2720 /// <summary>
2721 ///
2722 /// </summary>
2723 /// <param name="pos"></param>
2724 /// <param name="rot"></param>
2725 public void UpdateGroupRotation(Vector3 pos, Quaternion rot)
2726 {
2727 m_rootPart.UpdateRotation(rot);
2728 if (m_rootPart.PhysActor != null)
2729 {
2730 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
2731 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2732 }
2733 AbsolutePosition = pos;
2734
2735 HasGroupChanged = true;
2736 ScheduleGroupForTerseUpdate();
2737 }
2738
2739 /// <summary>
2740 ///
2741 /// </summary>
2742 /// <param name="rot"></param>
2743 /// <param name="localID"></param>
2744 public void UpdateSingleRotation(Quaternion rot, uint localID)
2745 {
2746 SceneObjectPart part = GetChildPart(localID);
2747 if (part != null)
2748 {
2749 if (part.UUID == m_rootPart.UUID)
2750 {
2751 UpdateRootRotation(rot);
2752 }
2753 else
2754 {
2755 part.UpdateRotation(rot);
2756 }
2757 }
2758 }
2759
2760 /// <summary>
2761 ///
2762 /// </summary>
2763 /// <param name="rot"></param>
2764 private void UpdateRootRotation(Quaternion rot)
2765 {
2766 Quaternion axRot = rot;
2767 Quaternion oldParentRot = m_rootPart.RotationOffset;
2768
2769 m_rootPart.UpdateRotation(rot);
2770 if (m_rootPart.PhysActor != null)
2771 {
2772 m_rootPart.PhysActor.Orientation = m_rootPart.RotationOffset;
2773 m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2774 }
2775
2776 lock (m_parts)
2777 {
2778 foreach (SceneObjectPart prim in m_parts.Values)
2779 {
2780 if (prim.UUID != m_rootPart.UUID)
2781 {
2782 Vector3 axPos = prim.OffsetPosition;
2783 axPos *= oldParentRot;
2784 axPos *= Quaternion.Inverse(axRot);
2785 prim.OffsetPosition = axPos;
2786 Quaternion primsRot = prim.RotationOffset;
2787 Quaternion newRot = primsRot * oldParentRot;
2788 newRot *= Quaternion.Inverse(axRot);
2789 prim.RotationOffset = newRot;
2790 prim.ScheduleTerseUpdate();
2791 }
2792 }
2793 }
2794
2795 m_rootPart.ScheduleTerseUpdate();
2796 }
2797
2798 #endregion
2799
2800 internal void SetAxisRotation(int axis, int rotate10)
2801 {
2802 bool setX = false;
2803 bool setY = false;
2804 bool setZ = false;
2805
2806 int xaxis = 2;
2807 int yaxis = 4;
2808 int zaxis = 8;
2809
2810 if (m_rootPart != null)
2811 {
2812 setX = ((axis & xaxis) != 0) ? true : false;
2813 setY = ((axis & yaxis) != 0) ? true : false;
2814 setZ = ((axis & zaxis) != 0) ? true : false;
2815
2816 float setval = (rotate10 > 0) ? 1f : 0f;
2817
2818 if (setX)
2819 m_rootPart.RotationAxis.X = setval;
2820 if (setY)
2821 m_rootPart.RotationAxis.Y = setval;
2822 if (setZ)
2823 m_rootPart.RotationAxis.Z = setval;
2824
2825 if (setX || setY || setZ)
2826 {
2827 m_rootPart.SetPhysicsAxisRotation();
2828 }
2829
2830 }
2831 }
2832
2833 public int registerTargetWaypoint(Vector3 target, float tolerance)
2834 {
2835 scriptPosTarget waypoint = new scriptPosTarget();
2836 waypoint.targetPos = target;
2837 waypoint.tolerance = tolerance;
2838 uint handle = m_scene.AllocateLocalId();
2839 lock (m_targets)
2840 {
2841 m_targets.Add(handle, waypoint);
2842 }
2843 return (int)handle;
2844 }
2845
2846 public void unregisterTargetWaypoint(int handle)
2847 {
2848 lock (m_targets)
2849 {
2850 if (m_targets.ContainsKey((uint)handle))
2851 m_targets.Remove((uint)handle);
2852 }
2853 }
2854
2855 private void checkAtTargets()
2856 {
2857 if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
2858 {
2859 if (m_targets.Count > 0)
2860 {
2861 bool at_target = false;
2862 //Vector3 targetPos;
2863 //uint targetHandle;
2864 Dictionary<uint, scriptPosTarget> atTargets = new Dictionary<uint, scriptPosTarget>();
2865 lock (m_targets)
2866 {
2867 foreach (uint idx in m_targets.Keys)
2868 {
2869 scriptPosTarget target = m_targets[idx];
2870 if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
2871 {
2872 // trigger at_target
2873 if (m_scriptListens_atTarget)
2874 {
2875 // Reusing att.tolerance to hold the index of the target in the targets dictionary
2876 // to avoid deadlocking the sim.
2877 at_target = true;
2878 scriptPosTarget att = new scriptPosTarget();
2879 att.targetPos = target.targetPos;
2880 att.tolerance = (float)idx;
2881 atTargets.Add(idx, att);
2882 }
2883 }
2884 }
2885 }
2886 if (atTargets.Count > 0)
2887 {
2888 uint[] localids = new uint[0];
2889 lock (m_parts)
2890 {
2891 localids = new uint[m_parts.Count];
2892 int cntr = 0;
2893 foreach (SceneObjectPart part in m_parts.Values)
2894 {
2895 localids[cntr] = part.LocalId;
2896 cntr++;
2897 }
2898 }
2899 for (int ctr = 0; ctr < localids.Length; ctr++)
2900 {
2901 foreach (uint target in atTargets.Keys)
2902 {
2903 scriptPosTarget att = atTargets[target];
2904 // Reusing att.tolerance to hold the index of the target in the targets dictionary
2905 // to avoid deadlocking the sim.
2906 m_scene.TriggerAtTargetEvent(localids[ctr], (uint)att.tolerance, att.targetPos, m_rootPart.GroupPosition);
2907
2908
2909 }
2910 }
2911 return;
2912 }
2913 if (m_scriptListens_notAtTarget && !at_target)
2914 {
2915 //trigger not_at_target
2916 uint[] localids = new uint[0];
2917 lock (m_parts)
2918 {
2919 localids = new uint[m_parts.Count];
2920 int cntr = 0;
2921 foreach (SceneObjectPart part in m_parts.Values)
2922 {
2923 localids[cntr] = part.LocalId;
2924 cntr++;
2925 }
2926 }
2927 for (int ctr = 0; ctr < localids.Length; ctr++)
2928 {
2929 m_scene.TriggerNotAtTargetEvent(localids[ctr]);
2930 }
2931 }
2932 }
2933 }
2934 }
2935
2936 public float GetMass()
2937 {
2938 float retmass = 0f;
2939 lock (m_parts)
2940 {
2941 foreach (SceneObjectPart part in m_parts.Values)
2942 {
2943 retmass += part.GetMass();
2944 }
2945 }
2946 return retmass;
2947 }
2948
2949 public void CheckSculptAndLoad()
2950 {
2951 lock (m_parts)
2952 {
2953 if (!IsDeleted)
2954 {
2955 if ((RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Phantom) == 0)
2956 {
2957 foreach (SceneObjectPart part in m_parts.Values)
2958 {
2959 if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero)
2960 {
2961 m_scene.AssetCache.GetAsset(part.Shape.SculptTexture, part.SculptTextureCallback, true);
2962 }
2963 }
2964 }
2965 }
2966 }
2967 }
2968
2969 /// <summary>
2970 /// Set the user group to which this scene object belongs.
2971 /// </summary>
2972 /// <param name="GroupID"></param>
2973 /// <param name="client"></param>
2974 public void SetGroup(UUID GroupID, IClientAPI client)
2975 {
2976 lock (m_parts)
2977 {
2978 foreach (SceneObjectPart part in m_parts.Values)
2979 {
2980 part.SetGroup(GroupID, client);
2981 part.Inventory.ChangeInventoryGroup(GroupID);
2982 }
2983
2984 HasGroupChanged = true;
2985 }
2986
2987 ScheduleGroupForFullUpdate();
2988 }
2989
2990 public void TriggerScriptChangedEvent(Changed val)
2991 {
2992 foreach (SceneObjectPart part in Children.Values)
2993 {
2994 part.TriggerScriptChangedEvent(val);
2995 }
2996 }
2997
2998 public override string ToString()
2999 {
3000 return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition);
3001 }
3002
3003 public void SetAttachmentPoint(byte point)
3004 {
3005 lock (m_parts)
3006 {
3007 foreach (SceneObjectPart part in m_parts.Values)
3008 part.SetAttachmentPoint(point);
3009 }
3010 }
3011 }
3012}