PageRenderTime 68ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Aurora/Region/SceneObjectGroup.cs

https://bitbucket.org/VirtualReality/software-testing
C# | 4443 lines | 3090 code | 440 blank | 913 comment | 667 complexity | eb39fe50da51eea0a51eb78162e0ea63 MD5 | raw file
  1. /*
  2. * Copyright (c) Contributors, http://aurora-sim.org/, 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 Aurora-Sim 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. using Aurora.Framework;
  28. using Aurora.Framework.ClientInterfaces;
  29. using Aurora.Framework.ConsoleFramework;
  30. using Aurora.Framework.Modules;
  31. using Aurora.Framework.Physics;
  32. using Aurora.Framework.PresenceInfo;
  33. using Aurora.Framework.SceneInfo;
  34. using Aurora.Framework.SceneInfo.Entities;
  35. using Aurora.Framework.Serialization;
  36. using Aurora.Framework.Utilities;
  37. using OpenMetaverse;
  38. using OpenMetaverse.Packets;
  39. using OpenMetaverse.StructuredData;
  40. using ProtoBuf;
  41. using System;
  42. using System.Collections.Generic;
  43. using System.Drawing;
  44. using System.Linq;
  45. using System.Xml.Serialization;
  46. using GridRegion = Aurora.Framework.Services.GridRegion;
  47. namespace Aurora.Region
  48. {
  49. internal struct scriptPosTarget
  50. {
  51. public uint handle;
  52. public Vector3 targetPos;
  53. public float tolerance;
  54. }
  55. internal struct scriptRotTarget
  56. {
  57. public uint handle;
  58. public Quaternion targetRot;
  59. public float tolerance;
  60. }
  61. /// <summary>
  62. /// A scene object group is conceptually an object in the scene. The object is constituted of SceneObjectParts
  63. /// (often known as prims), one of which is considered the root part.
  64. /// </summary>
  65. [Serializable, ProtoContract()]
  66. public partial class SceneObjectGroup : ISceneEntity
  67. //(ISceneObject implements ISceneEntity and IEntity)
  68. {
  69. private readonly List<uint> m_lastColliders = new List<uint>();
  70. private readonly Dictionary<uint, scriptRotTarget> m_rotTargets = new Dictionary<uint, scriptRotTarget>();
  71. private readonly Dictionary<uint, scriptPosTarget> m_targets = new Dictionary<uint, scriptPosTarget>();
  72. [XmlIgnore] private bool m_ValidgrpOOB; // control recalcutation
  73. [XmlIgnore] private float m_grpBSphereRadiusSQ; // the square of the radius of a sphere containing the oob
  74. [XmlIgnore] private Vector3 m_grpOOBoffset; // the position center of the bounding box relative to it's Position
  75. [XmlIgnore] private Vector3 m_grpOOBsize;
  76. // the size of a bounding box oriented as prim, is future will consider cutted prims, meshs etc
  77. public bool IsInTransit { get; set; }
  78. private UUID m_lastParcelUUID = UUID.Zero;
  79. private Vector3 m_lastSignificantPosition = Vector3.Zero;
  80. protected Dictionary<UUID, SceneObjectPart> m_parts = new Dictionary<UUID, SceneObjectPart>();
  81. //Same as m_parts, but this is used for fast linear operations
  82. protected List<SceneObjectPart> m_partsList = new List<SceneObjectPart>();
  83. //This is the lock for m_parts and m_partsList
  84. protected object m_partsLock = new object();
  85. protected ulong m_regionHandle;
  86. protected SceneObjectPart m_rootPart;
  87. private bool m_scriptListens_atRotTarget;
  88. private bool m_scriptListens_atTarget;
  89. private bool m_scriptListens_notAtRotTarget;
  90. private bool m_scriptListens_notAtTarget;
  91. #region Properties
  92. private List<ISceneChildEntity> m_LoopSoundSlavePrims = new List<ISceneChildEntity>();
  93. private List<ISceneChildEntity> m_PlaySoundSlavePrims = new List<ISceneChildEntity>();
  94. /// <summary>
  95. /// Added because the Parcel code seems to use it
  96. /// but not sure a object should have this
  97. /// as what does it tell us? that some avatar has selected it (but not what Avatar/user)
  98. /// think really there should be a list (or whatever) in each scenepresence
  99. /// saying what prim(s) that user has selected.
  100. /// </summary>
  101. protected bool m_isSelected;
  102. protected Quaternion m_rotation = Quaternion.Identity;
  103. public SceneObjectPart[] Parts
  104. {
  105. get { return m_partsList.ToArray(); }
  106. }
  107. /// <value>
  108. /// The parts of this scene object group. You must lock this property before using it.
  109. /// </value>
  110. [ProtoMember(1)]
  111. public List<SceneObjectPart> ChildrenList
  112. {
  113. get { return m_partsList; }
  114. set { m_partsList = value; }
  115. }
  116. /// <value>
  117. /// The root part of this scene object
  118. /// </value>
  119. public SceneObjectPart RootPart
  120. {
  121. get { return m_rootPart; }
  122. }
  123. public Color Color
  124. {
  125. get { return m_rootPart.Color; }
  126. set
  127. {
  128. if (m_rootPart != null)
  129. m_rootPart.UpdateColor(value, true);
  130. }
  131. }
  132. public string Text
  133. {
  134. get
  135. {
  136. string returnstr = m_rootPart.Text;
  137. if (returnstr.Length > 255)
  138. {
  139. returnstr = returnstr.Substring(0, 255);
  140. }
  141. return returnstr;
  142. }
  143. set
  144. {
  145. if (m_rootPart != null && m_rootPart.Text != value)
  146. m_rootPart.Text = value;
  147. }
  148. }
  149. public ISceneChildEntity PlaySoundMasterPrim { get; set; }
  150. public List<ISceneChildEntity> PlaySoundSlavePrims
  151. {
  152. get { return m_PlaySoundSlavePrims; }
  153. set { m_PlaySoundSlavePrims = value; }
  154. }
  155. public UUID RegionUUID
  156. {
  157. get
  158. {
  159. if (m_scene != null)
  160. {
  161. return m_scene.RegionInfo.RegionID;
  162. }
  163. return UUID.Zero;
  164. }
  165. }
  166. /// <summary>
  167. /// The name of an object grouping is always the same as its root part
  168. /// </summary>
  169. public override string Name
  170. {
  171. get
  172. {
  173. if (RootPart == null)
  174. return String.Empty;
  175. return RootPart.Name;
  176. }
  177. set { RootPart.Name = value; }
  178. }
  179. /// <summary>
  180. /// Number of prims in this group
  181. /// </summary>
  182. public int PrimCount
  183. {
  184. get { return m_parts.Count; }
  185. }
  186. public override Quaternion Rotation
  187. {
  188. get { return m_rotation; }
  189. set
  190. {
  191. HasGroupChanged = true;
  192. m_rotation = value;
  193. }
  194. }
  195. public Quaternion GroupRotation
  196. {
  197. get { return m_rootPart.GetRotationOffset(); }
  198. }
  199. public UUID GroupID
  200. {
  201. get { return m_rootPart.GroupID; }
  202. set
  203. {
  204. HasGroupChanged = true;
  205. m_rootPart.GroupID = value;
  206. }
  207. }
  208. public List<ISceneChildEntity> ChildrenEntities()
  209. {
  210. return new List<SceneObjectPart>(m_partsList).Cast<ISceneChildEntity>().ToList();
  211. }
  212. public List<UUID> SitTargetAvatar
  213. {
  214. get
  215. {
  216. List<UUID> sittingAvatars = new List<UUID>();
  217. foreach (var prim in ChildrenEntities())
  218. sittingAvatars.AddRange(new List<UUID>(prim.SitTargetAvatar));
  219. return sittingAvatars;
  220. }
  221. }
  222. /// <summary>
  223. /// The absolute position of this scene object in the scene
  224. /// </summary>
  225. public override Vector3 AbsolutePosition
  226. {
  227. get { return m_rootPart.GroupPosition; }
  228. set { SetAbsolutePosition(true, value); }
  229. }
  230. public override uint LocalId
  231. {
  232. get { return m_rootPart.LocalId; }
  233. set { m_rootPart.LocalId = value; }
  234. }
  235. public override UUID UUID
  236. {
  237. get { return m_rootPart.UUID; }
  238. set { Scene.SceneGraph.UpdateEntity(this, value); }
  239. }
  240. public UUID OwnerID
  241. {
  242. get { return m_rootPart.OwnerID; }
  243. set
  244. {
  245. HasGroupChanged = true;
  246. m_rootPart.OwnerID = value;
  247. }
  248. }
  249. public float Damage
  250. {
  251. get { return m_rootPart.Damage; }
  252. set
  253. {
  254. HasGroupChanged = true;
  255. m_rootPart.Damage = value;
  256. }
  257. }
  258. public bool IsSelected
  259. {
  260. get { return m_isSelected; }
  261. set
  262. {
  263. m_isSelected = value;
  264. // Tell physics engine that group is selected
  265. if (m_rootPart.PhysActor != null)
  266. {
  267. m_rootPart.PhysActor.Selected = value;
  268. // Pass it on to the children.
  269. #if (!ISWIN)
  270. foreach (SceneObjectPart child in ChildrenList)
  271. {
  272. if (child.PhysActor != null)
  273. {
  274. child.PhysActor.Selected = value;
  275. }
  276. }
  277. #else
  278. foreach (SceneObjectPart child in ChildrenList.Where(child => child.PhysActor != null))
  279. {
  280. child.PhysActor.Selected = value;
  281. }
  282. #endif
  283. }
  284. }
  285. }
  286. public ISceneChildEntity LoopSoundMasterPrim { get; set; }
  287. public List<ISceneChildEntity> LoopSoundSlavePrims
  288. {
  289. get { return m_LoopSoundSlavePrims; }
  290. set { m_LoopSoundSlavePrims = value; }
  291. }
  292. public bool ContainsPart(UUID partID)
  293. {
  294. return m_parts.ContainsKey(partID);
  295. }
  296. /// <summary>
  297. /// Check both the attachment property and the relevant properties of the underlying root part.
  298. /// </summary>
  299. /// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't
  300. /// have the IsAttachment property yet checked.
  301. ///
  302. /// FIXME: However, this should be fixed so that this property
  303. /// propertly reflects the underlying status.
  304. /// <returns></returns>
  305. public bool IsAttachmentCheckFull()
  306. {
  307. return (IsAttachment || (m_rootPart.Shape.PCode == 9 && m_rootPart.Shape.State != 0));
  308. }
  309. // The UUID for the Region this Object is in.
  310. #endregion
  311. #region Constructors
  312. public SceneObjectGroup()
  313. {
  314. }
  315. /// <summary>
  316. /// THIS IS ONLY FOR SERIALIZATION AND AS A BASE CONSTRUCTOR
  317. /// </summary>
  318. public SceneObjectGroup(IScene scene)
  319. {
  320. m_scene = scene;
  321. }
  322. /// <summary>
  323. /// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
  324. /// The original SceneObjectPart will be used rather than a copy, preserving
  325. /// its existing localID and UUID.
  326. /// </summary>
  327. public SceneObjectGroup(SceneObjectPart part, IScene scene) : this(scene)
  328. {
  329. SetRootPart(part);
  330. part.Scale = part.Shape.Scale; // temporary hack to update oobb
  331. m_ValidgrpOOB = false;
  332. }
  333. public SceneObjectGroup(SceneObjectPart part, IScene scene, bool AddToScene)
  334. : this(scene)
  335. {
  336. if (!AddToScene)
  337. m_isDeleted = true;
  338. SetRootPart(part);
  339. part.Scale = part.Shape.Scale; // temporary hack to update oobb
  340. m_ValidgrpOOB = false;
  341. }
  342. /// <summary>
  343. /// Constructor. This object is added to the scene later via AttachToScene()
  344. /// </summary>
  345. public SceneObjectGroup(UUID ownerID, Vector3 pos, Quaternion rot, PrimitiveBaseShape shape, string name,
  346. IScene scene) : this(scene)
  347. {
  348. SceneObjectPart part = new SceneObjectPart(ownerID, shape, pos, rot, Vector3.Zero, name);
  349. SetRootPart(part);
  350. //This has to be set, otherwise it will break things like rezzing objects in an area where crossing is disabled, but rez isn't
  351. m_lastSignificantPosition = pos;
  352. m_ValidgrpOOB = false;
  353. }
  354. public void SetFromItemID(UUID itemID, UUID assetID)
  355. {
  356. foreach (SceneObjectPart part in m_partsList)
  357. {
  358. part.FromUserInventoryItemID = itemID;
  359. part.FromUserInventoryAssetID = assetID;
  360. }
  361. }
  362. /// <summary>
  363. /// Attach this object to a scene. It will also now apply to agents.
  364. /// </summary>
  365. /// <param name="scene"></param>
  366. public void AttachToScene(IScene scene)
  367. {
  368. m_scene = scene;
  369. if (m_rootPart.Shape == null)
  370. {
  371. MainConsole.Instance.Warn("[SceneObjectGroup]: Found null shape for prim " + UUID +
  372. ", creating default box shape");
  373. m_rootPart.Shape = new PrimitiveBaseShape();
  374. }
  375. IOpenRegionSettingsModule WSModule = Scene.RequestModuleInterface<IOpenRegionSettingsModule>();
  376. if (WSModule != null)
  377. {
  378. foreach (SceneObjectPart part in ChildrenList)
  379. {
  380. //It's being rezzed, add it to the scene if it doesn't already have a rez date
  381. if (part.Rezzed != Util.ToDateTime(Util.EnvironmentTickCount()))
  382. part.Rezzed = DateTime.UtcNow;
  383. if (part.Shape == null)
  384. continue;
  385. Vector3 scale = part.Shape.Scale;
  386. if (WSModule.MinimumPrimScale != -1)
  387. {
  388. if (scale.X < WSModule.MinimumPrimScale)
  389. scale.X = WSModule.MinimumPrimScale;
  390. if (scale.Y < WSModule.MinimumPrimScale)
  391. scale.Y = WSModule.MinimumPrimScale;
  392. if (scale.Z < WSModule.MinimumPrimScale)
  393. scale.Z = WSModule.MinimumPrimScale;
  394. }
  395. if (part.ParentGroup.RootPart.PhysActor != null && part.ParentGroup.RootPart.PhysActor.IsPhysical &&
  396. WSModule.MaximumPhysPrimScale != -1)
  397. {
  398. if (scale.X > WSModule.MaximumPhysPrimScale)
  399. scale.X = WSModule.MaximumPhysPrimScale;
  400. if (scale.Y > WSModule.MaximumPhysPrimScale)
  401. scale.Y = WSModule.MaximumPhysPrimScale;
  402. if (scale.Z > WSModule.MaximumPhysPrimScale)
  403. scale.Z = WSModule.MaximumPhysPrimScale;
  404. }
  405. if (WSModule.MaximumPrimScale != -1)
  406. {
  407. if (scale.X > WSModule.MaximumPrimScale)
  408. scale.X = WSModule.MaximumPrimScale;
  409. if (scale.Y > WSModule.MaximumPrimScale)
  410. scale.Y = WSModule.MaximumPrimScale;
  411. if (scale.Z > WSModule.MaximumPrimScale)
  412. scale.Z = WSModule.MaximumPrimScale;
  413. }
  414. part.Scale = scale;
  415. }
  416. }
  417. //Trigger our event
  418. Scene.EventManager.TriggerObjectBeingAddedToScene(this);
  419. RebuildPhysicalRepresentation(false);
  420. m_ValidgrpOOB = false;
  421. }
  422. public Vector3 GroupScale()
  423. {
  424. if (m_partsList.Count == 1)
  425. return RootPart.Scale;
  426. Vector3 minScale = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  427. Vector3 maxScale = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  428. Vector3 finalScale;
  429. foreach (SceneObjectPart part in m_partsList)
  430. {
  431. Vector3 partscale = part.Scale*0.5f;
  432. // not assuming root is at index 0
  433. if (part.ParentID == 0) // root is in local frame of reference, partscale.? are positive, no rotations
  434. {
  435. // if root is always at index 0 this can be just assigns
  436. if (partscale.X > maxScale.X)
  437. maxScale.X = partscale.X;
  438. if (partscale.Y > maxScale.Y)
  439. maxScale.Y = partscale.Y;
  440. if (partscale.Z > maxScale.Z)
  441. maxScale.Z = partscale.Z;
  442. partscale = -partscale;
  443. if (partscale.X < minScale.X)
  444. minScale.X = partscale.X;
  445. if (partscale.Y < minScale.Y)
  446. minScale.Y = partscale.Y;
  447. if (partscale.Z < minScale.Z)
  448. minScale.Z = partscale.Z;
  449. }
  450. else // prims are in their local frame of reference
  451. {
  452. Vector3 partoffset = part.OffsetPosition;
  453. Quaternion partrot = part.GetRotationOffset();
  454. // bring into this frame
  455. partscale *= partrot;
  456. partoffset *= partrot;
  457. partoffset += part.OffsetPosition;
  458. // now just 2 vertices in a diagonal
  459. Vector3 deltam = partoffset - partscale;
  460. Vector3 deltaM = partoffset + partscale;
  461. if (deltaM.X > deltam.X) // right vertices order for extrem X
  462. {
  463. if (deltam.X < minScale.X)
  464. minScale.X = deltam.X;
  465. if (deltaM.X > maxScale.X)
  466. maxScale.X = deltaM.X;
  467. }
  468. else // nopes inverse one
  469. {
  470. if (deltaM.X < minScale.X)
  471. minScale.X = deltaM.X;
  472. if (deltam.X > maxScale.X)
  473. maxScale.X = deltam.X;
  474. }
  475. if (deltaM.Y > deltam.Y)
  476. {
  477. if (deltam.Y < minScale.Y)
  478. minScale.Y = deltam.Y;
  479. if (deltaM.Y > maxScale.Y)
  480. maxScale.Y = deltaM.Y;
  481. }
  482. else
  483. {
  484. if (deltaM.Y < minScale.Y)
  485. minScale.Y = deltaM.Y;
  486. if (deltam.Y > maxScale.Y)
  487. maxScale.Y = deltam.Y;
  488. }
  489. if (deltaM.Z > deltam.Z)
  490. {
  491. if (deltam.Z < minScale.Z)
  492. minScale.Z = deltam.Z;
  493. if (deltaM.Z > maxScale.Z)
  494. maxScale.Z = deltaM.Z;
  495. }
  496. else
  497. {
  498. if (deltaM.Z < minScale.Z)
  499. minScale.Z = deltaM.Z;
  500. if (deltam.Z > maxScale.Z)
  501. maxScale.Z = deltam.Z;
  502. }
  503. }
  504. }
  505. finalScale.X = Math.Abs(maxScale.X - minScale.X);
  506. finalScale.Y = Math.Abs(maxScale.Y - minScale.Y);
  507. finalScale.Z = Math.Abs(maxScale.Z - minScale.Z);
  508. return finalScale;
  509. }
  510. public override int GetHashCode()
  511. {
  512. return UUID.GetHashCode();
  513. }
  514. public bool IsPhysical()
  515. {
  516. return ((RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics);
  517. }
  518. public void UpdateOOBfromOOBs()
  519. {
  520. if (m_partsList.Count == 1)
  521. {
  522. SceneObjectPart part = m_partsList.First();
  523. m_grpOOBsize = part.OOBsize;
  524. m_grpOOBoffset = part.OOBoffset;
  525. m_grpBSphereRadiusSQ = part.BSphereRadiusSQ;
  526. m_ValidgrpOOB = true;
  527. return;
  528. }
  529. Vector3 minScale = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  530. Vector3 maxScale = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  531. foreach (SceneObjectPart part in m_partsList)
  532. {
  533. Vector3 partscale = part.OOBsize; // (oobsize == vector with box vertice with all coords positive)
  534. Vector3 partoffset = part.OOBoffset;
  535. // not assuming root is at index 0
  536. Vector3 deltam;
  537. Vector3 deltaM;
  538. if (part.ParentID == 0) // root is in local frame of reference, partscale.? are positive, no rotations
  539. {
  540. //2 vertices in the right extrem sides:
  541. deltam = partoffset - partscale;
  542. deltaM = partoffset + partscale;
  543. // if root is always at index 0 this can be just assigns
  544. if (deltam.X < minScale.X)
  545. minScale.X = deltam.X;
  546. if (deltam.Y < minScale.Y)
  547. minScale.Y = deltam.Y;
  548. if (deltam.Z < minScale.Z)
  549. minScale.Z = deltam.Z;
  550. if (deltaM.X > maxScale.X)
  551. maxScale.X = deltaM.X;
  552. if (deltaM.Y > maxScale.Y)
  553. maxScale.Y = deltaM.Y;
  554. if (deltaM.Z > maxScale.Z)
  555. maxScale.Z = deltaM.Z;
  556. }
  557. else // prims are in their local frame of reference
  558. {
  559. // bring into this frame
  560. Quaternion partrot = part.GetRotationOffset();
  561. partscale *= partrot;
  562. partoffset *= partrot;
  563. partoffset += part.OffsetPosition;
  564. // now just 2 vertices in a diagonal
  565. deltam = partoffset - partscale;
  566. deltaM = partoffset + partscale;
  567. if (deltaM.X > deltam.X) // right vertices order for extrem X
  568. {
  569. if (deltam.X < minScale.X)
  570. minScale.X = deltam.X;
  571. if (deltaM.X > maxScale.X)
  572. maxScale.X = deltaM.X;
  573. }
  574. else // nopes inverse one
  575. {
  576. if (deltaM.X < minScale.X)
  577. minScale.X = deltaM.X;
  578. if (deltam.X > maxScale.X)
  579. maxScale.X = deltam.X;
  580. }
  581. if (deltaM.Y > deltam.Y)
  582. {
  583. if (deltam.Y < minScale.Y)
  584. minScale.Y = deltam.Y;
  585. if (deltaM.Y > maxScale.Y)
  586. maxScale.Y = deltaM.Y;
  587. }
  588. else
  589. {
  590. if (deltaM.Y < minScale.Y)
  591. minScale.Y = deltaM.Y;
  592. if (deltam.Y > maxScale.Y)
  593. maxScale.Y = deltam.Y;
  594. }
  595. if (deltaM.Z > deltam.Z)
  596. {
  597. if (deltam.Z < minScale.Z)
  598. minScale.Z = deltam.Z;
  599. if (deltaM.Z > maxScale.Z)
  600. maxScale.Z = deltaM.Z;
  601. }
  602. else
  603. {
  604. if (deltaM.Z < minScale.Z)
  605. minScale.Z = deltaM.Z;
  606. if (deltam.Z > maxScale.Z)
  607. maxScale.Z = deltam.Z;
  608. }
  609. }
  610. }
  611. // size == the vertice of box with all coords positive
  612. m_grpOOBsize.X = 0.5f*Math.Abs(maxScale.X - minScale.X);
  613. m_grpOOBsize.Y = 0.5f*Math.Abs(maxScale.Y - minScale.Y);
  614. m_grpOOBsize.Z = 0.5f*Math.Abs(maxScale.Z - minScale.Z);
  615. // centroid:
  616. m_grpOOBoffset.X = 0.5f*(maxScale.X + minScale.X);
  617. m_grpOOBoffset.Y = 0.5f*(maxScale.Y + minScale.Y);
  618. m_grpOOBoffset.Z = 0.5f*(maxScale.Z + minScale.Z);
  619. // containing sphere:
  620. m_grpBSphereRadiusSQ = m_grpOOBsize.LengthSquared();
  621. m_ValidgrpOOB = true;
  622. }
  623. public EntityIntersection TestIntersection(Ray hRay, bool frontFacesOnly, bool faceCenters)
  624. {
  625. // We got a request from the inner_scene to raytrace along the Ray hRay
  626. // We're going to check all of the prim in this group for intersection with the ray
  627. // If we get a result, we're going to find the closest result to the origin of the ray
  628. // and send back the intersection information back to the innerscene.
  629. EntityIntersection result = new EntityIntersection();
  630. foreach (SceneObjectPart part in m_partsList)
  631. {
  632. // Temporary commented to stop compiler warning
  633. //Vector3 partPosition =
  634. // new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
  635. Quaternion parentrotation = GroupRotation;
  636. // Telling the prim to raytrace.
  637. //EntityIntersection inter = part.TestIntersection(hRay, parentrotation);
  638. EntityIntersection inter = part.TestIntersectionOBB(hRay, parentrotation, frontFacesOnly, faceCenters);
  639. // This may need to be updated to the maximum draw distance possible..
  640. // We might (and probably will) be checking for prim creation from other sims
  641. // when the camera crosses the border.
  642. if (m_scene != null)
  643. {
  644. float idist = (m_scene.RegionInfo.RegionSizeX + m_scene.RegionInfo.RegionSizeY)/2;
  645. if (inter.HitTF)
  646. {
  647. // We need to find the closest prim to return to the testcaller along the ray
  648. if (inter.distance < idist)
  649. {
  650. result.HitTF = true;
  651. result.ipoint = inter.ipoint;
  652. result.obj = part;
  653. result.normal = inter.normal;
  654. result.distance = inter.distance;
  655. }
  656. }
  657. }
  658. }
  659. return result;
  660. }
  661. /// <summary>
  662. /// Gets a vector representing the size of the bounding box containing all the prims in the group
  663. /// Treats all prims as rectangular, so no shape (cut etc) is taken into account
  664. /// offsetHeight is the offset in the Z axis from the centre of the bounding box to the centre of the root prim
  665. /// </summary>
  666. /// <returns></returns>
  667. public void GetAxisAlignedBoundingBoxRaw(out float minX, out float maxX, out float minY, out float maxY,
  668. out float minZ, out float maxZ)
  669. {
  670. Vector3 pos = m_rootPart.AbsolutePosition;
  671. Quaternion rot = m_rootPart.GetRotationOffset();
  672. // Vector3 size = GroupScale();
  673. Vector3 minScale = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
  674. Vector3 maxScale = new Vector3(float.MinValue, float.MinValue, float.MinValue);
  675. //limits in group frame
  676. foreach (SceneObjectPart part in m_partsList)
  677. {
  678. Vector3 partscale = part.Scale*0.5f;
  679. Vector3 partoffset = part.OffsetPosition;
  680. if (part.ParentID != 0) // prims are rotated in group
  681. {
  682. partscale *= part.GetRotationOffset();
  683. partscale.X = Math.Abs(partscale.X);
  684. partscale.Y = Math.Abs(partscale.Y);
  685. partscale.Z = Math.Abs(partscale.Z);
  686. }
  687. Vector3 deltam = partoffset - partscale;
  688. Vector3 deltaM = partoffset + partscale;
  689. if (deltam.X < minScale.X)
  690. minScale.X = deltam.X;
  691. if (deltam.Y < minScale.Y)
  692. minScale.Y = deltam.Y;
  693. if (deltam.Z < minScale.Z)
  694. minScale.Z = deltam.Z;
  695. if (deltaM.X > maxScale.X)
  696. maxScale.X = deltaM.X;
  697. if (deltaM.Y > maxScale.Y)
  698. maxScale.Y = deltaM.Y;
  699. if (deltaM.Z > maxScale.Z)
  700. maxScale.Z = deltaM.Z;
  701. }
  702. Vector3 tmp;
  703. tmp.X = 0.5f*Math.Abs(maxScale.X - minScale.X);
  704. tmp.Y = 0.5f*Math.Abs(maxScale.Y - minScale.Y);
  705. tmp.Z = 0.5f*Math.Abs(maxScale.Z - minScale.Z);
  706. // tmp has half scale
  707. // group rotation
  708. tmp = tmp*rot;
  709. // scale is positive
  710. tmp.X = Math.Abs(tmp.X);
  711. tmp.Y = Math.Abs(tmp.Y);
  712. tmp.Z = Math.Abs(tmp.Z);
  713. // group position
  714. minX = pos.X - tmp.X;
  715. minY = pos.Y - tmp.Y;
  716. minZ = pos.Z - tmp.Z;
  717. maxX = pos.X + tmp.X;
  718. maxY = pos.Y + tmp.Y;
  719. maxZ = pos.Z + tmp.Z;
  720. /*
  721. maxX = -256f;
  722. maxY = -256f;
  723. maxZ = -256f;
  724. minX = 256f;
  725. minY = 256f;
  726. minZ = 8192f;
  727. foreach (SceneObjectPart part in m_partsList)
  728. {
  729. Vector3 worldPos = part.GetWorldPosition();
  730. Vector3 offset = worldPos - AbsolutePosition;
  731. Quaternion worldRot;
  732. if (part.ParentID == 0)
  733. worldRot = part.RotationOffset;
  734. else
  735. worldRot = part.GetWorldRotation();
  736. Vector3 frontTopLeft;
  737. Vector3 frontTopRight;
  738. Vector3 frontBottomLeft;
  739. Vector3 frontBottomRight;
  740. Vector3 backTopLeft;
  741. Vector3 backTopRight;
  742. Vector3 backBottomLeft;
  743. Vector3 backBottomRight;
  744. Vector3 orig = Vector3.Zero;
  745. frontTopLeft.X = orig.X - (part.Scale.X / 2);
  746. frontTopLeft.Y = orig.Y - (part.Scale.Y / 2);
  747. frontTopLeft.Z = orig.Z + (part.Scale.Z / 2);
  748. frontTopRight.X = orig.X - (part.Scale.X / 2);
  749. frontTopRight.Y = orig.Y + (part.Scale.Y / 2);
  750. frontTopRight.Z = orig.Z + (part.Scale.Z / 2);
  751. frontBottomLeft.X = orig.X - (part.Scale.X / 2);
  752. frontBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
  753. frontBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
  754. frontBottomRight.X = orig.X - (part.Scale.X / 2);
  755. frontBottomRight.Y = orig.Y + (part.Scale.Y / 2);
  756. frontBottomRight.Z = orig.Z - (part.Scale.Z / 2);
  757. backTopLeft.X = orig.X + (part.Scale.X / 2);
  758. backTopLeft.Y = orig.Y - (part.Scale.Y / 2);
  759. backTopLeft.Z = orig.Z + (part.Scale.Z / 2);
  760. backTopRight.X = orig.X + (part.Scale.X / 2);
  761. backTopRight.Y = orig.Y + (part.Scale.Y / 2);
  762. backTopRight.Z = orig.Z + (part.Scale.Z / 2);
  763. backBottomLeft.X = orig.X + (part.Scale.X / 2);
  764. backBottomLeft.Y = orig.Y - (part.Scale.Y / 2);
  765. backBottomLeft.Z = orig.Z - (part.Scale.Z / 2);
  766. backBottomRight.X = orig.X + (part.Scale.X / 2);
  767. backBottomRight.Y = orig.Y + (part.Scale.Y / 2);
  768. backBottomRight.Z = orig.Z - (part.Scale.Z / 2);
  769. frontTopLeft = frontTopLeft * worldRot;
  770. frontTopRight = frontTopRight * worldRot;
  771. frontBottomLeft = frontBottomLeft * worldRot;
  772. frontBottomRight = frontBottomRight * worldRot;
  773. backBottomLeft = backBottomLeft * worldRot;
  774. backBottomRight = backBottomRight * worldRot;
  775. backTopLeft = backTopLeft * worldRot;
  776. backTopRight = backTopRight * worldRot;
  777. frontTopLeft += offset;
  778. frontTopRight += offset;
  779. frontBottomLeft += offset;
  780. frontBottomRight += offset;
  781. backBottomLeft += offset;
  782. backBottomRight += offset;
  783. backTopLeft += offset;
  784. backTopRight += offset;
  785. if (frontTopRight.X > maxX)
  786. maxX = frontTopRight.X;
  787. if (frontTopLeft.X > maxX)
  788. maxX = frontTopLeft.X;
  789. if (frontBottomRight.X > maxX)
  790. maxX = frontBottomRight.X;
  791. if (frontBottomLeft.X > maxX)
  792. maxX = frontBottomLeft.X;
  793. if (backTopRight.X > maxX)
  794. maxX = backTopRight.X;
  795. if (backTopLeft.X > maxX)
  796. maxX = backTopLeft.X;
  797. if (backBottomRight.X > maxX)
  798. maxX = backBottomRight.X;
  799. if (backBottomLeft.X > maxX)
  800. maxX = backBottomLeft.X;
  801. if (frontTopRight.X < minX)
  802. minX = frontTopRight.X;
  803. if (frontTopLeft.X < minX)
  804. minX = frontTopLeft.X;
  805. if (frontBottomRight.X < minX)
  806. minX = frontBottomRight.X;
  807. if (frontBottomLeft.X < minX)
  808. minX = frontBottomLeft.X;
  809. if (backTopRight.X < minX)
  810. minX = backTopRight.X;
  811. if (backTopLeft.X < minX)
  812. minX = backTopLeft.X;
  813. if (backBottomRight.X < minX)
  814. minX = backBottomRight.X;
  815. if (backBottomLeft.X < minX)
  816. minX = backBottomLeft.X;
  817. if (frontTopRight.Y > maxY)
  818. maxY = frontTopRight.Y;
  819. if (frontTopLeft.Y > maxY)
  820. maxY = frontTopLeft.Y;
  821. if (frontBottomRight.Y > maxY)
  822. maxY = frontBottomRight.Y;
  823. if (frontBottomLeft.Y > maxY)
  824. maxY = frontBottomLeft.Y;
  825. if (backTopRight.Y > maxY)
  826. maxY = backTopRight.Y;
  827. if (backTopLeft.Y > maxY)
  828. maxY = backTopLeft.Y;
  829. if (backBottomRight.Y > maxY)
  830. maxY = backBottomRight.Y;
  831. if (backBottomLeft.Y > maxY)
  832. maxY = backBottomLeft.Y;
  833. if (backTopRight.Y < minY)
  834. minY = backTopRight.Y;
  835. if (backTopLeft.Y < minY)
  836. minY = backTopLeft.Y;
  837. if (backBottomRight.Y < minY)
  838. minY = backBottomRight.Y;
  839. if (backBottomLeft.Y < minY)
  840. minY = backBottomLeft.Y;
  841. if (backTopRight.Y < minY)
  842. minY = backTopRight.Y;
  843. if (backTopLeft.Y < minY)
  844. minY = backTopLeft.Y;
  845. if (backBottomRight.Y < minY)
  846. minY = backBottomRight.Y;
  847. if (backBottomLeft.Y < minY)
  848. minY = backBottomLeft.Y;
  849. if (frontTopRight.Z > maxZ)
  850. maxZ = frontTopRight.Z;
  851. if (frontTopLeft.Z > maxZ)
  852. maxZ = frontTopLeft.Z;
  853. if (frontBottomRight.Z > maxZ)
  854. maxZ = frontBottomRight.Z;
  855. if (frontBottomLeft.Z > maxZ)
  856. maxZ = frontBottomLeft.Z;
  857. if (backTopRight.Z > maxZ)
  858. maxZ = backTopRight.Z;
  859. if (backTopLeft.Z > maxZ)
  860. maxZ = backTopLeft.Z;
  861. if (backBottomRight.Z > maxZ)
  862. maxZ = backBottomRight.Z;
  863. if (backBottomLeft.Z > maxZ)
  864. maxZ = backBottomLeft.Z;
  865. if (frontTopRight.Z < minZ)
  866. minZ = frontTopRight.Z;
  867. if (frontTopLeft.Z < minZ)
  868. minZ = frontTopLeft.Z;
  869. if (frontBottomRight.Z < minZ)
  870. minZ = frontBottomRight.Z;
  871. if (frontBottomLeft.Z < minZ)
  872. minZ = frontBottomLeft.Z;
  873. if (backTopRight.Z < minZ)
  874. minZ = backTopRight.Z;
  875. if (backTopLeft.Z < minZ)
  876. minZ = backTopLeft.Z;
  877. if (backBottomRight.Z < minZ)
  878. minZ = backBottomRight.Z;
  879. if (backBottomLeft.Z < minZ)
  880. minZ = backBottomLeft.Z;
  881. }
  882. */
  883. }
  884. public Vector3 GetAxisAlignedBoundingBox(out float offsetHeight)
  885. {
  886. float minX;
  887. float maxX;
  888. float minY;
  889. float maxY;
  890. float minZ;
  891. float maxZ;
  892. GetAxisAlignedBoundingBoxRaw(out minX, out maxX, out minY, out maxY, out minZ, out maxZ);
  893. Vector3 boundingBox = new Vector3(maxX - minX, maxY - minY, maxZ - minZ);
  894. offsetHeight = 0.5f*(maxZ + minZ);
  895. offsetHeight -= m_rootPart.AbsolutePosition.Z;
  896. /*
  897. offsetHeight = 0;
  898. float lower = (minZ * -1);
  899. if (lower > maxZ)
  900. {
  901. offsetHeight = lower - (boundingBox.Z / 2);
  902. }
  903. else if (maxZ > lower)
  904. {
  905. offsetHeight = maxZ - (boundingBox.Z / 2);
  906. offsetHeight *= -1;
  907. }
  908. */
  909. // MainConsole.Instance.InfoFormat("BoundingBox is {0} , {1} , {2} ", boundingBox.X, boundingBox.Y, boundingBox.Z);
  910. return boundingBox;
  911. }
  912. #region Adding/Removing children from this group
  913. /// <summary>
  914. /// Clear all children from this group
  915. /// </summary>
  916. public void ClearChildren()
  917. {
  918. lock (m_partsLock)
  919. {
  920. m_parts.Clear();
  921. m_partsList.Clear();
  922. m_ValidgrpOOB = false;
  923. }
  924. }
  925. /// <summary>
  926. /// Add a child to the group, set the parent id's and then set the link number
  927. /// </summary>
  928. /// <param name="child"></param>
  929. /// <param name="linkNum"></param>
  930. /// <returns></returns>
  931. public bool AddChild(ISceneChildEntity child, int linkNum)
  932. {
  933. lock (m_partsLock)
  934. {
  935. if (child is SceneObjectPart)
  936. {
  937. SceneObjectPart part = (SceneObjectPart) child;
  938. //Root part is first
  939. if (m_partsList.Count == 0)
  940. {
  941. m_rootPart = part;
  942. }
  943. //Set the parent prim
  944. part.SetParent(this);
  945. if (m_rootPart.LocalId != 0 && !part.IsRoot)
  946. part.SetParentLocalId(m_rootPart.LocalId);
  947. else
  948. part.SetParentLocalId(0);
  949. //Fix the link num
  950. part.LinkNum = linkNum;
  951. if (!m_parts.ContainsKey(child.UUID))
  952. {
  953. m_parts.Add(child.UUID, part);
  954. m_partsList.Add(part);
  955. m_ValidgrpOOB = false;
  956. }
  957. return true;
  958. }
  959. }
  960. return false;
  961. }
  962. /// <summary>
  963. /// Add this child to the group and set the parent ID's,
  964. /// but do NOT set the link number,
  965. /// the caller wants to deal with it if they call this
  966. /// </summary>
  967. /// <param name="child"></param>
  968. /// <returns></returns>
  969. public bool LinkChild(ISceneChildEntity child)
  970. {
  971. lock (m_partsLock)
  972. {
  973. if (child is SceneObjectPart)
  974. {
  975. SceneObjectPart part = (SceneObjectPart) child;
  976. //Root part is first
  977. if (m_partsList.Count == 0)
  978. {
  979. m_rootPart = part;
  980. }
  981. //Set the parent prim
  982. part.SetParent(this);
  983. part.SetParentLocalId(m_rootPart.LocalId);
  984. if (!m_parts.ContainsKey(child.UUID))
  985. {
  986. m_parts.Add(child.UUID, part);
  987. m_partsList.Add(part);
  988. m_ValidgrpOOB = false;
  989. }
  990. m_partsList.Sort(m_scene.SceneGraph.LinkSetSorter);
  991. return true;
  992. }
  993. }
  994. return false;
  995. }
  996. /// <summary>
  997. /// Remove this child from the group and then update the link numbers so that there is not a hole
  998. /// </summary>
  999. /// <param name="child"></param>
  1000. /// <returns></returns>
  1001. public bool RemoveChild(ISceneChildEntity child)
  1002. {
  1003. lock (m_partsLock)
  1004. {
  1005. if (child is SceneObjectPart)
  1006. {
  1007. SceneObjectPart part = (SceneObjectPart) child;
  1008. m_parts.Remove(part.UUID);
  1009. m_partsList.Remove(part);
  1010. m_ValidgrpOOB = false;
  1011. //Fix the link numbers now
  1012. FixLinkNumbers();
  1013. return true;
  1014. }
  1015. }
  1016. return false;
  1017. }
  1018. /// <summary>
  1019. /// After a prim is removed, fix the link numbers so that they are correct
  1020. /// </summary>
  1021. private void FixLinkNumbers()
  1022. {
  1023. if (m_partsList.Count == 1)
  1024. {
  1025. m_partsList[0].LinkNum = 0;
  1026. return;
  1027. }
  1028. lock (m_partsLock)
  1029. {
  1030. // has prims so starts at 1
  1031. int lastSeenLinkNum = 1;
  1032. m_partsList.Sort(Scene.SceneGraph.LinkSetSorter);
  1033. foreach (SceneObjectPart t in m_partsList)
  1034. {
  1035. //If it isn't the same as the last seen +1, fix it
  1036. if (t != null && t.LinkNum != lastSeenLinkNum)
  1037. t.LinkNum = lastSeenLinkNum;
  1038. //Go onto the next prim
  1039. lastSeenLinkNum++;
  1040. }
  1041. }
  1042. }
  1043. #endregion
  1044. #endregion
  1045. /// <summary>
  1046. /// The position center of the bounding box relative to it's Position
  1047. /// </summary>
  1048. [XmlIgnore]
  1049. public Vector3 OOBoffset
  1050. {
  1051. get
  1052. {
  1053. if (!m_ValidgrpOOB)
  1054. UpdateOOBfromOOBs();
  1055. return m_grpOOBoffset;
  1056. }
  1057. }
  1058. public object ChildrenListLock
  1059. {
  1060. get { return m_partsLock; }
  1061. }
  1062. #region ISceneObject Members
  1063. public event BlankHandler OnFinishedPhysicalRepresentationBuilding;
  1064. public Vector3 LastSignificantPosition
  1065. {
  1066. get { return m_lastSignificantPosition; }
  1067. }
  1068. public UUID LastParcelUUID
  1069. {
  1070. get { return m_lastParcelUUID; }
  1071. set { m_lastParcelUUID = value; }
  1072. }
  1073. /// <summary>
  1074. /// The size of a bounding box oriented as prim, is future will consider cutted prims, meshs etc
  1075. /// </summary>
  1076. [XmlIgnore]
  1077. public Vector3 OOBsize
  1078. {
  1079. get
  1080. {
  1081. if (!m_ValidgrpOOB)
  1082. UpdateOOBfromOOBs();
  1083. return m_grpOOBsize;
  1084. }
  1085. }
  1086. /// <summary>
  1087. /// The square of the radius of a sphere containing the oob
  1088. /// </summary>
  1089. [XmlIgnore]
  1090. public float BSphereRadiusSQ
  1091. {
  1092. get
  1093. {
  1094. if (!m_ValidgrpOOB)
  1095. UpdateOOBfromOOBs();
  1096. return m_grpBSphereRadiusSQ;
  1097. }
  1098. }
  1099. public override bool HasGroupChanged
  1100. {
  1101. get { return m_hasGroupChanged; }
  1102. set
  1103. {
  1104. if (value)
  1105. {
  1106. if (m_scene != null)
  1107. {
  1108. IBackupModule backup = m_scene.RequestModuleInterface<IBackupModule>();
  1109. if (backup != null)
  1110. {
  1111. if (!backup.LoadingPrims) //Do NOT add to backup while still loading prims
  1112. backup.AddPrimBackupTaint(this);
  1113. }
  1114. }
  1115. }
  1116. m_hasGroupChanged = value;
  1117. }
  1118. }
  1119. /// <summary>
  1120. /// Force all prims in the scene object to persist
  1121. /// </summary>
  1122. public void ForcePersistence()
  1123. {
  1124. //Force normal backup
  1125. HasGroupChanged = true;
  1126. ForceInventoryPersistence();
  1127. }
  1128. /// <summary>
  1129. /// Clears all undo states from this group
  1130. /// </summary>
  1131. public void ClearUndoState()
  1132. {
  1133. foreach (SceneObjectPart child in ChildrenList)
  1134. {
  1135. child.ClearUndoState();
  1136. }
  1137. }
  1138. /// <value>
  1139. /// Is this scene object acting as an attachment?
  1140. /// We return false if the group has already been deleted.
  1141. /// TODO: At the moment set must be done on the part itself. There may be a case for doing it here since I
  1142. /// presume either all or no parts in a linkset can be part of an attachment (in which
  1143. /// case the value would get proprogated down into all the descendent parts).
  1144. /// </value>
  1145. public bool IsAttachment
  1146. {
  1147. get { return m_rootPart.IsAttachment; }
  1148. }
  1149. //private bool m_isBackedUp = false;
  1150. public byte GetAttachmentPoint()
  1151. {
  1152. return m_rootPart.Shape.State;
  1153. }
  1154. public Vector3 GetAttachmentPos()
  1155. {
  1156. return m_rootPart.SavedAttachedPos;
  1157. }
  1158. public byte GetSavedAttachmentPoint()
  1159. {
  1160. return (byte) m_rootPart.SavedAttachmentPoint;
  1161. }
  1162. public void FinishedSerializingGenericProperties()
  1163. {
  1164. foreach (ISceneChildEntity ent in ChildrenEntities())
  1165. ent.FinishedSerializingGenericProperties();
  1166. }
  1167. public void DetachToGround()
  1168. {
  1169. IScenePresence avatar = m_scene.GetScenePresence(m_rootPart.AttachedAvatar);
  1170. if (avatar == null)
  1171. return;
  1172. RootPart.FromUserInventoryItemID = UUID.Zero;
  1173. AbsolutePosition = avatar.AbsolutePosition;
  1174. m_rootPart.AttachedAvatar = UUID.Zero;
  1175. //Anakin Lohner bug #3839
  1176. foreach (SceneObjectPart p in m_partsList)
  1177. {
  1178. p.AttachedAvatar = UUID.Zero;
  1179. }
  1180. m_rootPart.SetParentLocalId(0);
  1181. SetAttachmentPoint(0);
  1182. RebuildPhysicalRepresentation(false);
  1183. HasGroupChanged = true;
  1184. m_ValidgrpOOB = false;
  1185. RootPart.Rezzed = DateTime.UtcNow;
  1186. RootPart.RemFlag(PrimFlags.TemporaryOnRez);
  1187. m_rootPart.ScheduleUpdate(PrimUpdateFlags.ForcedFullUpdate);
  1188. }
  1189. public void DetachToInventoryPrep()
  1190. {
  1191. m_rootPart.AttachedAvatar = UUID.Zero;
  1192. //Anakin Lohner bug #3839
  1193. foreach (SceneObjectPart p in m_partsList)
  1194. {
  1195. p.AttachedAvatar = UUID.Zero;
  1196. }
  1197. m_rootPart.SetParentLocalId(0);
  1198. //m_rootPart.SetAttachmentPoint((byte)0);
  1199. m_rootPart.IsAttachment = false;
  1200. AbsolutePosition = m_rootPart.AttachedPos;
  1201. m_ValidgrpOOB = false;
  1202. //m_rootPart.ApplyPhysics(m_rootPart.GetEffectiveObjectFlags(), m_scene.m_physicalPrim);
  1203. //AttachToBackup();
  1204. //m_rootPart.ScheduleFullUpdate();
  1205. }
  1206. // justincc: I don't believe this hack is needed any longer, especially since the physics
  1207. // parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
  1208. // this method was preventing proper reload of scene objects.
  1209. // dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
  1210. // at region startup
  1211. // teravus: After this was removed from the linking algorithm, Linked prims no longer collided
  1212. // properly when non-physical if they havn't been moved. This breaks ALL builds.
  1213. // see: http://opensimulator.org/mantis/view.php?id=3108
  1214. // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
  1215. // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
  1216. // unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute
  1217. // Position has been set!
  1218. public void ResetChildPrimPhysicsPositions()
  1219. {
  1220. AbsolutePosition = AbsolutePosition; // could someone in the know please explain how this works?
  1221. // teravus: AbsolutePosition is NOT a normal property!
  1222. // the code in the getter of AbsolutePosition is significantly different then the code in the setter!
  1223. // jhurliman: Then why is it a property instead of two methods?
  1224. }
  1225. public void SetOwnerId(UUID userId)
  1226. {
  1227. ForEachPart(delegate(SceneObjectPart part)
  1228. {
  1229. part.LastOwnerID = part.OwnerID;
  1230. part.OwnerID = userId;
  1231. });
  1232. }
  1233. public float GetMass()
  1234. {
  1235. return RootChild.GetMass();
  1236. }
  1237. /// <summary>
  1238. /// Set the user group to which this scene object belongs.
  1239. /// </summary>
  1240. /// <param name="GroupID2"></param>
  1241. /// <param name="attemptingUserID"></param>
  1242. /// <param name="needsUpdate"></param>
  1243. public void SetGroup(UUID GroupID2, UUID attemptingUserID, bool needsUpdate)
  1244. {
  1245. IGroupsModule module = Scene.RequestModuleInterface<IGroupsModule>();
  1246. if (module != null)
  1247. if (GroupID2 != UUID.Zero && !module.GroupPermissionCheck(attemptingUserID, GroupID2, GroupPowers.None))
  1248. return; // No settings to groups you arn't in
  1249. foreach (SceneObjectPart part in m_partsList)
  1250. {
  1251. part.SetGroup(GroupID2);
  1252. part.Inventory.ChangeInventoryGroup(GroupID2);
  1253. }
  1254. HasGroupChanged = true;
  1255. IScenePresence sp = Scene.GetScenePresence(attemptingUserID);
  1256. if (sp != null && needsUpdate)
  1257. GetProperties(sp.ControllingClient);
  1258. }
  1259. public void TriggerScriptChangedEvent(Changed val)
  1260. {
  1261. foreach (SceneObjectPart part in ChildrenList)
  1262. {
  1263. part.TriggerScriptChangedEvent(val);
  1264. }
  1265. }
  1266. public void SetAttachmentPoint(byte point)
  1267. {
  1268. foreach (SceneObjectPart part in m_partsList)
  1269. part.SetAttachmentPoint(point);
  1270. }
  1271. public void FireAttachmentCollisionEvents(EventArgs e)
  1272. {
  1273. CollisionEventUpdate a = (CollisionEventUpdate) e;
  1274. Dictionary<uint, ContactPoint> collissionswith = a.GetCollisionEvents();
  1275. List<uint> thisHitColliders = new List<uint>();
  1276. List<uint> startedColliders = new List<uint>();
  1277. // calculate things that started colliding this time
  1278. // and build up list of colliders this time
  1279. foreach (uint localid in collissionswith.Keys)
  1280. {
  1281. thisHitColliders.Add(localid);
  1282. if (!m_lastColliders.Contains(localid))
  1283. {
  1284. startedColliders.Add(localid);
  1285. }
  1286. //MainConsole.Instance.Debug("[OBJECT]: Collided with:" + localid.ToString() + " at depth of: " + collissionswith[localid].ToString());
  1287. }
  1288. // calculate things that ended colliding
  1289. #if (!ISWIN)
  1290. List<uint> endedColliders = new List<uint>();
  1291. foreach (uint localId in m_lastColliders)
  1292. {
  1293. if (!thisHitColliders.Contains(localId)) endedColliders.Add(localId);
  1294. }
  1295. #else
  1296. List<uint> endedColliders = m_lastColliders.Where(localID => !thisHitColliders.Contains(localID)).ToList();
  1297. #endif
  1298. //add the items that started colliding this time to the last colliders list.
  1299. foreach (uint localID in startedColliders)
  1300. {
  1301. m_lastColliders.Add(localID);
  1302. }
  1303. // remove things that ended colliding from the last colliders list
  1304. foreach (uint localID in endedColliders)
  1305. {
  1306. m_lastColliders.Remove(localID);
  1307. }
  1308. if (IsDeleted)
  1309. return;
  1310. // play the sound.
  1311. if (startedColliders.Count > 0 && RootPart.CollisionSound != UUID.Zero &&
  1312. RootPart.CollisionSoundVolume > 0.0f)
  1313. {
  1314. RootPart.SendSound(RootPart.CollisionSound.ToString(), RootPart.CollisionSoundVolume, true, 0, 0, false,
  1315. false);
  1316. }
  1317. if (RootPart.CollisionSprite != UUID.Zero && RootPart.CollisionSoundVolume > 0.0f)
  1318. // The collision volume isn't a mistake, its an SL feature/bug
  1319. {
  1320. // TODO: make a sprite!
  1321. }
  1322. if ((RootPart.ScriptEvents & scriptEvents.collision_start) != 0)
  1323. {
  1324. // do event notification
  1325. if (startedColliders.Count > 0)
  1326. {
  1327. ColliderArgs StartCollidingMessage = new ColliderArgs();
  1328. List<DetectedObject> colliding = new List<DetectedObject>();
  1329. foreach (uint localId in startedColliders)
  1330. {
  1331. if (localId != 0)
  1332. {
  1333. if (Scene == null)
  1334. return;
  1335. ISceneChildEntity obj = Scene.GetSceneObjectPart(localId);
  1336. string data = "";
  1337. if (obj != null)
  1338. {
  1339. if (RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) ||
  1340. RootPart.CollisionFilter.ContainsValue(obj.Name))
  1341. {
  1342. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1343. //If it is 1, it is to accept ONLY collisions from this object
  1344. if (found)
  1345. {
  1346. DetectedObject detobj = new DetectedObject
  1347. {
  1348. keyUUID = obj.UUID,
  1349. nameStr = obj.Name,
  1350. ownerUUID = obj.OwnerID,
  1351. posVector = obj.AbsolutePosition,
  1352. rotQuat = obj.GetWorldRotation(),
  1353. velVector = obj.Velocity,
  1354. colliderType = 0,
  1355. groupUUID = obj.GroupID
  1356. };
  1357. colliding.Add(detobj);
  1358. }
  1359. //If it is 0, it is to not accept collisions from this object
  1360. }
  1361. else
  1362. {
  1363. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1364. //If it is 1, it is to accept ONLY collisions from this object, so this other object will not work
  1365. if (!found)
  1366. {
  1367. DetectedObject detobj = new DetectedObject
  1368. {
  1369. keyUUID = obj.UUID,
  1370. nameStr = obj.Name,
  1371. ownerUUID = obj.OwnerID,
  1372. posVector = obj.AbsolutePosition,
  1373. rotQuat = obj.GetWorldRotation(),
  1374. velVector = obj.Velocity,
  1375. colliderType = 0,
  1376. groupUUID = obj.GroupID
  1377. };
  1378. colliding.Add(detobj);
  1379. }
  1380. }
  1381. }
  1382. else
  1383. {
  1384. IScenePresence av = Scene.GetScenePresence(localId);
  1385. if (av.LocalId == localId)
  1386. {
  1387. if (RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) ||
  1388. RootPart.CollisionFilter.ContainsValue(av.Name))
  1389. {
  1390. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1391. //If it is 1, it is to accept ONLY collisions from this avatar
  1392. if (found)
  1393. {
  1394. DetectedObject detobj = new DetectedObject
  1395. {
  1396. keyUUID = av.UUID,
  1397. nameStr = av.ControllingClient.Name,
  1398. ownerUUID = av.UUID,
  1399. posVector = av.AbsolutePosition,
  1400. rotQuat = av.Rotation,
  1401. velVector = av.Velocity,
  1402. colliderType = 0,
  1403. groupUUID =
  1404. av.ControllingClient.ActiveGroupId
  1405. };
  1406. colliding.Add(detobj);
  1407. }
  1408. //If it is 0, it is to not accept collisions from this avatar
  1409. }
  1410. else
  1411. {
  1412. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1413. //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
  1414. if (!found)
  1415. {
  1416. DetectedObject detobj = new DetectedObject
  1417. {
  1418. keyUUID = av.UUID,
  1419. nameStr = av.ControllingClient.Name,
  1420. ownerUUID = av.UUID,
  1421. posVector = av.AbsolutePosition,
  1422. rotQuat = av.Rotation,
  1423. velVector = av.Velocity,
  1424. colliderType = 0,
  1425. groupUUID =
  1426. av.ControllingClient.ActiveGroupId
  1427. };
  1428. colliding.Add(detobj);
  1429. }
  1430. }
  1431. }
  1432. }
  1433. }
  1434. }
  1435. if (colliding.Count > 0)
  1436. {
  1437. StartCollidingMessage.Colliders = colliding;
  1438. // always running this check because if the user deletes the object it would return a null reference.
  1439. if (Scene == null)
  1440. return;
  1441. Scene.EventManager.TriggerScriptCollidingStart(RootPart, StartCollidingMessage);
  1442. }
  1443. }
  1444. }
  1445. if ((RootPart.ScriptEvents & scriptEvents.collision) != 0)
  1446. {
  1447. if (m_lastColliders.Count > 0)
  1448. {
  1449. ColliderArgs CollidingMessage = new ColliderArgs();
  1450. List<DetectedObject> colliding = new List<DetectedObject>();
  1451. foreach (uint localId in m_lastColliders)
  1452. {
  1453. if (localId != 0)
  1454. {
  1455. if (Scene == null)
  1456. return;
  1457. ISceneChildEntity obj = Scene.GetSceneObjectPart(localId);
  1458. string data = "";
  1459. if (obj != null)
  1460. {
  1461. if (RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) ||
  1462. RootPart.CollisionFilter.ContainsValue(obj.Name))
  1463. {
  1464. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1465. //If it is 1, it is to accept ONLY collisions from this object
  1466. if (found)
  1467. {
  1468. DetectedObject detobj = new DetectedObject
  1469. {
  1470. keyUUID = obj.UUID,
  1471. nameStr = obj.Name,
  1472. ownerUUID = obj.OwnerID,
  1473. posVector = obj.AbsolutePosition,
  1474. rotQuat = obj.GetWorldRotation(),
  1475. velVector = obj.Velocity,
  1476. colliderType = 0,
  1477. groupUUID = obj.GroupID
  1478. };
  1479. colliding.Add(detobj);
  1480. }
  1481. //If it is 0, it is to not accept collisions from this object
  1482. }
  1483. else
  1484. {
  1485. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1486. //If it is 1, it is to accept ONLY collisions from this object, so this other object will not work
  1487. if (!found)
  1488. {
  1489. DetectedObject detobj = new DetectedObject
  1490. {
  1491. keyUUID = obj.UUID,
  1492. nameStr = obj.Name,
  1493. ownerUUID = obj.OwnerID,
  1494. posVector = obj.AbsolutePosition,
  1495. rotQuat = obj.GetWorldRotation(),
  1496. velVector = obj.Velocity,
  1497. colliderType = 0,
  1498. groupUUID = obj.GroupID
  1499. };
  1500. colliding.Add(detobj);
  1501. }
  1502. }
  1503. }
  1504. else
  1505. {
  1506. IScenePresence av = Scene.GetScenePresence(localId);
  1507. if (av != null && av.LocalId == localId)
  1508. {
  1509. if (RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) ||
  1510. RootPart.CollisionFilter.ContainsValue(av.Name))
  1511. {
  1512. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1513. //If it is 1, it is to accept ONLY collisions from this avatar
  1514. if (found)
  1515. {
  1516. DetectedObject detobj = new DetectedObject
  1517. {
  1518. keyUUID = av.UUID,
  1519. nameStr = av.ControllingClient.Name,
  1520. ownerUUID = av.UUID,
  1521. posVector = av.AbsolutePosition,
  1522. rotQuat = av.Rotation,
  1523. velVector = av.Velocity,
  1524. colliderType = 0,
  1525. groupUUID =
  1526. av.ControllingClient.ActiveGroupId
  1527. };
  1528. colliding.Add(detobj);
  1529. }
  1530. //If it is 0, it is to not accept collisions from this avatar
  1531. }
  1532. else
  1533. {
  1534. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1535. //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
  1536. if (!found)
  1537. {
  1538. DetectedObject detobj = new DetectedObject
  1539. {
  1540. keyUUID = av.UUID,
  1541. nameStr = av.ControllingClient.Name,
  1542. ownerUUID = av.UUID,
  1543. posVector = av.AbsolutePosition,
  1544. rotQuat = av.Rotation,
  1545. velVector = av.Velocity,
  1546. colliderType = 0,
  1547. groupUUID =
  1548. av.ControllingClient.ActiveGroupId
  1549. };
  1550. colliding.Add(detobj);
  1551. }
  1552. }
  1553. }
  1554. }
  1555. }
  1556. }
  1557. if (colliding.Count > 0)
  1558. {
  1559. CollidingMessage.Colliders = colliding;
  1560. if (Scene == null)
  1561. return;
  1562. Scene.EventManager.TriggerScriptColliding(RootPart, CollidingMessage);
  1563. }
  1564. }
  1565. }
  1566. if ((RootPart.ScriptEvents & scriptEvents.collision_end) != 0)
  1567. {
  1568. if (endedColliders.Count > 0)
  1569. {
  1570. ColliderArgs EndCollidingMessage = new ColliderArgs();
  1571. List<DetectedObject> colliding = new List<DetectedObject>();
  1572. foreach (uint localId in endedColliders)
  1573. {
  1574. if (localId != 0)
  1575. {
  1576. // always running this check because if the user deletes the object it would return a null reference.
  1577. if (Scene == null)
  1578. return;
  1579. ISceneChildEntity obj = Scene.GetSceneObjectPart(localId);
  1580. string data = "";
  1581. if (obj != null)
  1582. {
  1583. if (RootPart.CollisionFilter.ContainsValue(obj.UUID.ToString()) ||
  1584. RootPart.CollisionFilter.ContainsValue(obj.Name))
  1585. {
  1586. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1587. //If it is 1, it is to accept ONLY collisions from this object
  1588. if (found)
  1589. {
  1590. DetectedObject detobj = new DetectedObject
  1591. {
  1592. keyUUID = obj.UUID,
  1593. nameStr = obj.Name,
  1594. ownerUUID = obj.OwnerID,
  1595. posVector = obj.AbsolutePosition,
  1596. rotQuat = obj.GetWorldRotation(),
  1597. velVector = obj.Velocity,
  1598. colliderType = 0,
  1599. groupUUID = obj.GroupID
  1600. };
  1601. colliding.Add(detobj);
  1602. }
  1603. //If it is 0, it is to not accept collisions from this object
  1604. }
  1605. else
  1606. {
  1607. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1608. //If it is 1, it is to accept ONLY collisions from this object, so this other object will not work
  1609. if (!found)
  1610. {
  1611. DetectedObject detobj = new DetectedObject
  1612. {
  1613. keyUUID = obj.UUID,
  1614. nameStr = obj.Name,
  1615. ownerUUID = obj.OwnerID,
  1616. posVector = obj.AbsolutePosition,
  1617. rotQuat = obj.GetWorldRotation(),
  1618. velVector = obj.Velocity,
  1619. colliderType = 0,
  1620. groupUUID = obj.GroupID
  1621. };
  1622. colliding.Add(detobj);
  1623. }
  1624. }
  1625. }
  1626. else
  1627. {
  1628. IScenePresence av = Scene.GetScenePresence(localId);
  1629. if (av != null && av.LocalId == localId)
  1630. {
  1631. if (RootPart.CollisionFilter.ContainsValue(av.UUID.ToString()) ||
  1632. RootPart.CollisionFilter.ContainsValue(av.Name))
  1633. {
  1634. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1635. //If it is 1, it is to accept ONLY collisions from this avatar
  1636. if (found)
  1637. {
  1638. DetectedObject detobj = new DetectedObject
  1639. {
  1640. keyUUID = av.UUID,
  1641. nameStr = av.ControllingClient.Name,
  1642. ownerUUID = av.UUID,
  1643. posVector = av.AbsolutePosition,
  1644. rotQuat = av.Rotation,
  1645. velVector = av.Velocity,
  1646. colliderType = 0,
  1647. groupUUID =
  1648. av.ControllingClient.ActiveGroupId
  1649. };
  1650. colliding.Add(detobj);
  1651. }
  1652. //If it is 0, it is to not accept collisions from this avatar
  1653. }
  1654. else
  1655. {
  1656. bool found = RootPart.CollisionFilter.TryGetValue(1, out data);
  1657. //If it is 1, it is to accept ONLY collisions from this avatar, so this other avatar will not work
  1658. if (!found)
  1659. {
  1660. DetectedObject detobj = new DetectedObject
  1661. {
  1662. keyUUID = av.UUID,
  1663. nameStr = av.ControllingClient.Name,
  1664. ownerUUID = av.UUID,
  1665. posVector = av.AbsolutePosition,
  1666. rotQuat = av.Rotation,
  1667. velVector = av.Velocity,
  1668. colliderType = 0,
  1669. groupUUID =
  1670. av.ControllingClient.ActiveGroupId
  1671. };
  1672. colliding.Add(detobj);
  1673. }
  1674. }
  1675. }
  1676. }
  1677. }
  1678. }
  1679. if (colliding.Count > 0)
  1680. {
  1681. EndCollidingMessage.Colliders = colliding;
  1682. if (Scene == null)
  1683. return;
  1684. Scene.EventManager.TriggerScriptCollidingEnd(RootPart, EndCollidingMessage);
  1685. }
  1686. }
  1687. }
  1688. if ((RootPart.ScriptEvents & scriptEvents.land_collision_start) != 0)
  1689. {
  1690. if (startedColliders.Count > 0)
  1691. {
  1692. ColliderArgs LandStartCollidingMessage = new ColliderArgs();
  1693. List<DetectedObject> colliding = (from localId in startedColliders
  1694. where localId == 0
  1695. select new DetectedObject
  1696. {
  1697. keyUUID = UUID.Zero,
  1698. nameStr = "",
  1699. ownerUUID = UUID.Zero,
  1700. posVector = RootPart.AbsolutePosition,
  1701. rotQuat = Quaternion.Identity,
  1702. velVector = Vector3.Zero,
  1703. colliderType = 0,
  1704. groupUUID = UUID.Zero
  1705. }).ToList();
  1706. if (colliding.Count > 0)
  1707. {
  1708. LandStartCollidingMessage.Colliders = colliding;
  1709. if (Scene == null)
  1710. return;
  1711. Scene.EventManager.TriggerScriptLandCollidingStart(RootPart, LandStartCollidingMessage);
  1712. }
  1713. }
  1714. }
  1715. if ((RootPart.ScriptEvents & scriptEvents.land_collision) != 0)
  1716. {
  1717. if (m_lastColliders.Count > 0)
  1718. {
  1719. ColliderArgs LandCollidingMessage = new ColliderArgs();
  1720. List<DetectedObject> colliding = (from localId in startedColliders
  1721. where localId == 0
  1722. select new DetectedObject
  1723. {
  1724. keyUUID = UUID.Zero,
  1725. nameStr = "",
  1726. ownerUUID = UUID.Zero,
  1727. posVector = RootPart.AbsolutePosition,
  1728. rotQuat = Quaternion.Identity,
  1729. velVector = Vector3.Zero,
  1730. colliderType = 0,
  1731. groupUUID = UUID.Zero
  1732. }).ToList();
  1733. if (colliding.Count > 0)
  1734. {
  1735. LandCollidingMessage.Colliders = colliding;
  1736. if (Scene == null)
  1737. return;
  1738. Scene.EventManager.TriggerScriptLandColliding(RootPart, LandCollidingMessage);
  1739. }
  1740. }
  1741. }
  1742. if ((RootPart.ScriptEvents & scriptEvents.land_collision_end) != 0)
  1743. {
  1744. if (endedColliders.Count > 0)
  1745. {
  1746. ColliderArgs LandEndCollidingMessage = new ColliderArgs();
  1747. List<DetectedObject> colliding = (from localId in startedColliders
  1748. where localId == 0
  1749. select new DetectedObject
  1750. {
  1751. keyUUID = UUID.Zero,
  1752. nameStr = "",
  1753. ownerUUID = UUID.Zero,
  1754. posVector = RootPart.AbsolutePosition,
  1755. rotQuat = Quaternion.Identity,
  1756. velVector = Vector3.Zero,
  1757. colliderType = 0,
  1758. groupUUID = UUID.Zero
  1759. }).ToList();
  1760. if (colliding.Count > 0)
  1761. {
  1762. LandEndCollidingMessage.Colliders = colliding;
  1763. // always running this check because if the user deletes the object it would return a null reference.
  1764. if (Scene == null)
  1765. return;
  1766. Scene.EventManager.TriggerScriptLandCollidingEnd(RootPart, LandEndCollidingMessage);
  1767. }
  1768. }
  1769. }
  1770. }
  1771. public ISceneChildEntity RootChild
  1772. {
  1773. get { return m_rootPart; }
  1774. set { m_rootPart = (SceneObjectPart) value; }
  1775. }
  1776. #endregion
  1777. #region ISceneObject
  1778. public virtual string ToXml2()
  1779. {
  1780. return SceneEntitySerializer.SceneObjectSerializer.ToXml2Format(this);
  1781. }
  1782. public virtual byte[] ToBinaryXml2()
  1783. {
  1784. return SceneEntitySerializer.SceneObjectSerializer.ToBinaryXml2Format(this);
  1785. }
  1786. #endregion
  1787. public void ClearPartAttachmentData()
  1788. {
  1789. SetAttachmentPoint(0);
  1790. }
  1791. /// <summary>
  1792. /// Set a part to act as the root part for this scene object
  1793. /// </summary>
  1794. /// <param name="part"></param>
  1795. public void SetRootPart(SceneObjectPart part)
  1796. {
  1797. if (part == null)
  1798. throw new ArgumentNullException("part");
  1799. m_rootPart = part;
  1800. if (!IsAttachment)
  1801. part.SetParentLocalId(0);
  1802. AddChild(part, part.LinkNum);
  1803. }
  1804. public void ObjectGrabHandler(uint localId, Vector3 offsetPos, IClientAPI remoteClient)
  1805. {
  1806. if (m_rootPart.LocalId == localId)
  1807. {
  1808. OnGrabGroup(offsetPos, remoteClient);
  1809. }
  1810. else
  1811. {
  1812. SceneObjectPart part = (SceneObjectPart) GetChildPart(localId);
  1813. OnGrabPart(part, offsetPos, remoteClient);
  1814. }
  1815. }
  1816. public virtual void OnGrabPart(SceneObjectPart part, Vector3 offsetPos, IClientAPI remoteClient)
  1817. {
  1818. part.StoreUndoState();
  1819. part.OnGrab(offsetPos, remoteClient);
  1820. }
  1821. public virtual void OnGrabGroup(Vector3 offsetPos, IClientAPI remoteClient)
  1822. {
  1823. m_scene.EventManager.TriggerGroupGrab(UUID, offsetPos, remoteClient.AgentId);
  1824. }
  1825. public void aggregateScriptEvents()
  1826. {
  1827. PrimFlags objectflagupdate = (PrimFlags) RootPart.GetEffectiveObjectFlags();
  1828. scriptEvents aggregateScriptEvents = 0;
  1829. foreach (SceneObjectPart part in m_partsList.Where(part => part != null))
  1830. {
  1831. if (part != RootPart)
  1832. part.Flags = objectflagupdate;
  1833. aggregateScriptEvents |= part.AggregateScriptEvents;
  1834. }
  1835. m_scriptListens_atTarget = ((aggregateScriptEvents & scriptEvents.at_target) != 0);
  1836. m_scriptListens_notAtTarget = ((aggregateScriptEvents & scriptEvents.not_at_target) != 0);
  1837. if (!m_scriptListens_atTarget && !m_scriptListens_notAtTarget)
  1838. {
  1839. lock (m_targets)
  1840. m_targets.Clear();
  1841. RemoveGroupTarget(this);
  1842. }
  1843. m_scriptListens_atRotTarget = ((aggregateScriptEvents & scriptEvents.at_rot_target) != 0);
  1844. m_scriptListens_notAtRotTarget = ((aggregateScriptEvents & scriptEvents.not_at_rot_target) != 0);
  1845. if (!m_scriptListens_atRotTarget && !m_scriptListens_notAtRotTarget)
  1846. {
  1847. lock (m_rotTargets)
  1848. m_rotTargets.Clear();
  1849. RemoveGroupTarget(this);
  1850. }
  1851. ScheduleGroupUpdate(PrimUpdateFlags.PrimFlags);
  1852. }
  1853. public void SetText(string text, Vector3 color, double alpha)
  1854. {
  1855. Color = Color.FromArgb(0xff - (int) (alpha*0xff),
  1856. (int) (color.X*0xff),
  1857. (int) (color.Y*0xff),
  1858. (int) (color.Z*0xff));
  1859. Text = text;
  1860. m_rootPart.ScheduleUpdate(PrimUpdateFlags.Text);
  1861. }
  1862. public void ForEachPart(Action<SceneObjectPart> whatToDo)
  1863. {
  1864. lock (m_partsLock)
  1865. {
  1866. foreach (SceneObjectPart part in m_partsList)
  1867. {
  1868. whatToDo(part);
  1869. }
  1870. }
  1871. }
  1872. internal void SetAxisRotation(int axis, int rotate10)
  1873. {
  1874. const int xaxis = 2;
  1875. const int yaxis = 4;
  1876. const int zaxis = 8;
  1877. if (m_rootPart != null)
  1878. {
  1879. bool setX = ((axis & xaxis) != 0);
  1880. bool setY = ((axis & yaxis) != 0);
  1881. bool setZ = ((axis & zaxis) != 0);
  1882. float setval = (rotate10 > 0) ? 1f : 0f;
  1883. if (setX)
  1884. m_rootPart.RotationAxis.X = setval;
  1885. if (setY)
  1886. m_rootPart.RotationAxis.Y = setval;
  1887. if (setZ)
  1888. m_rootPart.RotationAxis.Z = setval;
  1889. if (setX || setY || setZ)
  1890. {
  1891. m_rootPart.SetPhysicsAxisRotation();
  1892. }
  1893. }
  1894. }
  1895. public int registerRotTargetWaypoint(Quaternion target, float tolerance)
  1896. {
  1897. scriptRotTarget waypoint = new scriptRotTarget {targetRot = target, tolerance = tolerance};
  1898. uint handle = m_scene.SceneGraph.AllocateLocalId();
  1899. waypoint.handle = handle;
  1900. lock (m_rotTargets)
  1901. {
  1902. m_rotTargets.Add(handle, waypoint);
  1903. }
  1904. AddGroupTarget(this);
  1905. return (int) handle;
  1906. }
  1907. public void unregisterRotTargetWaypoint(int handle)
  1908. {
  1909. lock (m_targets)
  1910. {
  1911. m_rotTargets.Remove((uint) handle);
  1912. if (m_targets.Count == 0)
  1913. RemoveGroupTarget(this);
  1914. }
  1915. }
  1916. public int registerTargetWaypoint(Vector3 target, float tolerance)
  1917. {
  1918. scriptPosTarget waypoint = new scriptPosTarget {targetPos = target, tolerance = tolerance};
  1919. uint handle = m_scene.SceneGraph.AllocateLocalId();
  1920. waypoint.handle = handle;
  1921. lock (m_targets)
  1922. {
  1923. m_targets.Add(handle, waypoint);
  1924. }
  1925. AddGroupTarget(this);
  1926. return (int) handle;
  1927. }
  1928. public void unregisterTargetWaypoint(int handle)
  1929. {
  1930. lock (m_targets)
  1931. {
  1932. m_targets.Remove((uint) handle);
  1933. if (m_targets.Count == 0)
  1934. RemoveGroupTarget(this);
  1935. }
  1936. }
  1937. public void AddGroupTarget(SceneObjectGroup grp)
  1938. {
  1939. m_scene.EventManager.OnFrame += checkAtTargets;
  1940. }
  1941. public void RemoveGroupTarget(SceneObjectGroup grp)
  1942. {
  1943. m_scene.EventManager.OnFrame -= checkAtTargets;
  1944. }
  1945. public void AddKeyframedMotion(KeyframeAnimation animation, KeyframeAnimation.Commands command)
  1946. {
  1947. if (command == KeyframeAnimation.Commands.Play)
  1948. {
  1949. m_rootPart.KeyframeAnimation = animation;
  1950. m_scene.EventManager.OnFrame += moveKeyframeMotion;
  1951. }
  1952. else
  1953. {
  1954. m_scene.EventManager.OnFrame -= moveKeyframeMotion;
  1955. if (command == KeyframeAnimation.Commands.Stop)
  1956. m_rootPart.KeyframeAnimation = null;
  1957. }
  1958. }
  1959. public void moveKeyframeMotion()
  1960. {
  1961. if (m_rootPart.KeyframeAnimation == null || m_rootPart.KeyframeAnimation.TimeList.Length == 0)
  1962. {
  1963. m_scene.EventManager.OnFrame -= moveKeyframeMotion;
  1964. return;
  1965. }
  1966. try
  1967. {
  1968. int currentTime =
  1969. m_rootPart.KeyframeAnimation.TimeList[m_rootPart.KeyframeAnimation.CurrentAnimationPosition];
  1970. float timeAmt = (1f/(float) currentTime);
  1971. Vector3 currentTarget = m_rootPart.KeyframeAnimation.PositionList.Length == 0
  1972. ? Vector3.Zero
  1973. : m_rootPart.KeyframeAnimation.PositionList[
  1974. m_rootPart.KeyframeAnimation.CurrentAnimationPosition];
  1975. Quaternion target = m_rootPart.KeyframeAnimation.RotationList.Length == 0
  1976. ? Quaternion.Identity
  1977. : m_rootPart.KeyframeAnimation.RotationList[
  1978. m_rootPart.KeyframeAnimation.CurrentAnimationPosition];
  1979. m_rootPart.KeyframeAnimation.CurrentFrame++;
  1980. //Add one to the current frame so that we know when to stops
  1981. bool AllDoneMoving = false;
  1982. bool MadeItToCheckpoint = false;
  1983. if (m_rootPart.KeyframeAnimation.CurrentFrame == currentTime)
  1984. {
  1985. if (m_rootPart.KeyframeAnimation.CurrentMode == KeyframeAnimation.Modes.Forward)
  1986. {
  1987. m_rootPart.KeyframeAnimation.CurrentAnimationPosition += 1;
  1988. if (m_rootPart.KeyframeAnimation.CurrentAnimationPosition ==
  1989. m_rootPart.KeyframeAnimation.TimeList.Length)
  1990. {
  1991. //All done moving...
  1992. AllDoneMoving = true;
  1993. m_scene.EventManager.OnFrame -= moveKeyframeMotion;
  1994. }
  1995. }
  1996. else if (m_rootPart.KeyframeAnimation.CurrentMode == KeyframeAnimation.Modes.Reverse)
  1997. {
  1998. m_rootPart.KeyframeAnimation.CurrentAnimationPosition -= 1;
  1999. if (m_rootPart.KeyframeAnimation.CurrentAnimationPosition < 0)
  2000. {
  2001. //All done moving...
  2002. AllDoneMoving = true;
  2003. m_scene.EventManager.OnFrame -= moveKeyframeMotion;
  2004. }
  2005. }
  2006. else if (m_rootPart.KeyframeAnimation.CurrentMode == KeyframeAnimation.Modes.Loop)
  2007. {
  2008. m_rootPart.KeyframeAnimation.CurrentAnimationPosition += 1;
  2009. if (m_rootPart.KeyframeAnimation.CurrentAnimationPosition ==
  2010. m_rootPart.KeyframeAnimation.TimeList.Length)
  2011. m_rootPart.KeyframeAnimation.CurrentAnimationPosition = 0;
  2012. }
  2013. else if (m_rootPart.KeyframeAnimation.CurrentMode == KeyframeAnimation.Modes.PingPong)
  2014. {
  2015. if (m_rootPart.KeyframeAnimation.PingPongForwardMotion)
  2016. {
  2017. m_rootPart.KeyframeAnimation.CurrentAnimationPosition += 1;
  2018. if (m_rootPart.KeyframeAnimation.CurrentAnimationPosition ==
  2019. m_rootPart.KeyframeAnimation.TimeList.Length)
  2020. {
  2021. m_rootPart.KeyframeAnimation.PingPongForwardMotion =
  2022. !m_rootPart.KeyframeAnimation.PingPongForwardMotion;
  2023. m_rootPart.KeyframeAnimation.CurrentAnimationPosition -= 2;
  2024. }
  2025. }
  2026. else
  2027. {
  2028. m_rootPart.KeyframeAnimation.CurrentAnimationPosition -= 1;
  2029. if (m_rootPart.KeyframeAnimation.CurrentAnimationPosition < 0)
  2030. {
  2031. m_rootPart.KeyframeAnimation.PingPongForwardMotion =
  2032. !m_rootPart.KeyframeAnimation.PingPongForwardMotion;
  2033. m_rootPart.KeyframeAnimation.CurrentAnimationPosition += 2;
  2034. }
  2035. }
  2036. }
  2037. m_rootPart.KeyframeAnimation.CurrentFrame = 0;
  2038. MadeItToCheckpoint = true;
  2039. }
  2040. if (m_rootPart.KeyframeAnimation.PositionList.Length != 0)
  2041. {
  2042. Vector3 _target_velocity =
  2043. new Vector3(
  2044. (currentTarget.X - m_rootPart.KeyframeAnimation.InitialPosition.X)*timeAmt,
  2045. (currentTarget.Y - m_rootPart.KeyframeAnimation.InitialPosition.Y)*timeAmt,
  2046. (currentTarget.Z - m_rootPart.KeyframeAnimation.InitialPosition.Z)*timeAmt
  2047. );
  2048. if (MadeItToCheckpoint)
  2049. {
  2050. if (AllDoneMoving)
  2051. Velocity = Vector3.Zero;
  2052. SetAbsolutePosition(true, currentTarget);
  2053. m_rootPart.KeyframeAnimation.InitialPosition = currentTarget;
  2054. }
  2055. else
  2056. {
  2057. SetAbsolutePosition(true, m_rootPart.AbsolutePosition + _target_velocity);
  2058. m_rootPart.Velocity = _target_velocity/45f;
  2059. }
  2060. }
  2061. if (m_rootPart.KeyframeAnimation.RotationList.Length != 0)
  2062. {
  2063. Quaternion source = m_rootPart.GetRotationOffset();
  2064. Quaternion newInterpolation = Quaternion.Slerp(source, target,
  2065. 1f/
  2066. ((float) currentTime -
  2067. (float) m_rootPart.KeyframeAnimation.CurrentFrame));
  2068. m_rootPart.UpdateRotation(newInterpolation);
  2069. if (MadeItToCheckpoint)
  2070. {
  2071. //Force set it to the right position, just to be sure
  2072. m_rootPart.UpdateRotation(target);
  2073. m_rootPart.KeyframeAnimation.InitialRotation = target;
  2074. }
  2075. }
  2076. }
  2077. catch
  2078. {
  2079. m_scene.EventManager.OnFrame -= moveKeyframeMotion;
  2080. }
  2081. ScheduleGroupTerseUpdate();
  2082. }
  2083. public void checkAtTargets()
  2084. {
  2085. if (m_scriptListens_atTarget || m_scriptListens_notAtTarget)
  2086. {
  2087. if (m_targets.Count > 0)
  2088. {
  2089. bool at_target = false;
  2090. //Vector3 targetPos;
  2091. //uint targetHandle;
  2092. Dictionary<uint, scriptPosTarget> atTargets = new Dictionary<uint, scriptPosTarget>();
  2093. lock (m_targets)
  2094. {
  2095. foreach (uint idx in m_targets.Keys)
  2096. {
  2097. scriptPosTarget target = m_targets[idx];
  2098. if (Util.GetDistanceTo(target.targetPos, m_rootPart.GroupPosition) <= target.tolerance)
  2099. {
  2100. // trigger at_target
  2101. if (m_scriptListens_atTarget)
  2102. {
  2103. at_target = true;
  2104. scriptPosTarget att = new scriptPosTarget
  2105. {
  2106. targetPos = target.targetPos,
  2107. tolerance = target.tolerance,
  2108. handle = target.handle
  2109. };
  2110. atTargets.Add(idx, att);
  2111. }
  2112. }
  2113. }
  2114. }
  2115. if (atTargets.Count > 0)
  2116. {
  2117. uint[] localids = new uint[0];
  2118. localids = new uint[m_parts.Count];
  2119. int cntr = 0;
  2120. foreach (SceneObjectPart part in m_partsList)
  2121. {
  2122. localids[cntr] = part.LocalId;
  2123. cntr++;
  2124. }
  2125. foreach (uint t in localids)
  2126. {
  2127. foreach (scriptPosTarget att in atTargets.Values)
  2128. {
  2129. m_scene.EventManager.TriggerAtTargetEvent(
  2130. t, att.handle, att.targetPos, m_rootPart.GroupPosition);
  2131. }
  2132. }
  2133. return;
  2134. }
  2135. if (m_scriptListens_notAtTarget && !at_target)
  2136. {
  2137. //trigger not_at_target
  2138. uint[] localids = new uint[0];
  2139. localids = new uint[m_parts.Count];
  2140. int cntr = 0;
  2141. foreach (SceneObjectPart part in m_partsList)
  2142. {
  2143. localids[cntr] = part.LocalId;
  2144. cntr++;
  2145. }
  2146. foreach (uint t in localids)
  2147. {
  2148. m_scene.EventManager.TriggerNotAtTargetEvent(t);
  2149. }
  2150. }
  2151. }
  2152. }
  2153. if (m_scriptListens_atRotTarget || m_scriptListens_notAtRotTarget)
  2154. {
  2155. if (m_rotTargets.Count > 0)
  2156. {
  2157. bool at_Rottarget = false;
  2158. Dictionary<uint, scriptRotTarget> atRotTargets = new Dictionary<uint, scriptRotTarget>();
  2159. lock (m_rotTargets)
  2160. {
  2161. foreach (uint idx in m_rotTargets.Keys)
  2162. {
  2163. scriptRotTarget target = m_rotTargets[idx];
  2164. double angle =
  2165. Math.Acos(target.targetRot.X*m_rootPart.GetRotationOffset().X +
  2166. target.targetRot.Y*m_rootPart.GetRotationOffset().Y +
  2167. target.targetRot.Z*m_rootPart.GetRotationOffset().Z +
  2168. target.targetRot.W*m_rootPart.GetRotationOffset().W)*2;
  2169. if (angle < 0) angle = -angle;
  2170. if (angle > Math.PI) angle = (Math.PI*2 - angle);
  2171. if (angle <= target.tolerance)
  2172. {
  2173. // trigger at_rot_target
  2174. if (m_scriptListens_atRotTarget)
  2175. {
  2176. at_Rottarget = true;
  2177. scriptRotTarget att = new scriptRotTarget
  2178. {
  2179. targetRot = target.targetRot,
  2180. tolerance = target.tolerance,
  2181. handle = target.handle
  2182. };
  2183. atRotTargets.Add(idx, att);
  2184. }
  2185. }
  2186. }
  2187. }
  2188. if (atRotTargets.Count > 0)
  2189. {
  2190. uint[] localids = new uint[0];
  2191. localids = new uint[m_parts.Count];
  2192. int cntr = 0;
  2193. foreach (SceneObjectPart part in m_partsList)
  2194. {
  2195. localids[cntr] = part.LocalId;
  2196. cntr++;
  2197. }
  2198. foreach (uint t in localids)
  2199. {
  2200. foreach (scriptRotTarget att in atRotTargets.Values)
  2201. {
  2202. m_scene.EventManager.TriggerAtRotTargetEvent(
  2203. t, att.handle, att.targetRot, m_rootPart.GetRotationOffset());
  2204. }
  2205. }
  2206. return;
  2207. }
  2208. if (m_scriptListens_notAtRotTarget && !at_Rottarget)
  2209. {
  2210. //trigger not_at_target
  2211. uint[] localids = new uint[0];
  2212. localids = new uint[m_parts.Count];
  2213. int cntr = 0;
  2214. foreach (SceneObjectPart part in m_partsList)
  2215. {
  2216. localids[cntr] = part.LocalId;
  2217. cntr++;
  2218. }
  2219. foreach (uint t in localids)
  2220. {
  2221. m_scene.EventManager.TriggerNotAtRotTargetEvent(t);
  2222. }
  2223. }
  2224. }
  2225. }
  2226. }
  2227. public void CheckSculptAndLoad()
  2228. {
  2229. foreach (SceneObjectPart part in m_partsList)
  2230. {
  2231. if (part.Shape == null)
  2232. continue;
  2233. if (!(RootPart.PhysicsType == (byte) PhysicsShapeType.None ||
  2234. part.PhysicsType == (byte) PhysicsShapeType.None ||
  2235. ((part.Flags & PrimFlags.Phantom) == PrimFlags.Phantom &&
  2236. !part.VolumeDetectActive) ||
  2237. ((RootPart.Flags & PrimFlags.Phantom) == PrimFlags.Phantom &&
  2238. !RootPart.VolumeDetectActive)))
  2239. {
  2240. if (part.Shape.SculptEntry && part.Shape.SculptTexture != UUID.Zero)
  2241. {
  2242. // If no sculpt data exists, we need to get the data
  2243. m_scene.AssetService.Get(part.Shape.SculptTexture.ToString(), true, part.AssetReceived);
  2244. //In the mean time...
  2245. //part.Shape.SculptEntry = false;
  2246. part.Shape.SculptData = new byte[0];
  2247. }
  2248. }
  2249. }
  2250. }
  2251. public void GeneratedMesh(ISceneChildEntity part, IMesh mesh)
  2252. {
  2253. //This destroys the mesh if it is added... this needs added in a way that won't corrupt the mesh
  2254. /*if (part.Shape.SculptType == (byte)SculptType.Mesh && !mesh.WasCached)//If it was cached, we don't want to resave it
  2255. {
  2256. //We can cache meshes into the mesh itself, saving time generating it next time around
  2257. OSDMap meshOsd = (OSDMap)OSDParser.DeserializeLLSDBinary(part.Shape.SculptData);
  2258. meshOsd["physics_cached"] = new OSDMap();
  2259. mesh.Serialize();
  2260. mesh.WasCached = true;
  2261. UUID newSculptTexture;
  2262. if (m_scene.AssetService.UpdateContent(part.Shape.SculptTexture,
  2263. OSDParser.SerializeLLSDBinary(meshOsd), out newSculptTexture))
  2264. {
  2265. part.Shape.SculptTexture = newSculptTexture;
  2266. HasGroupChanged = true;
  2267. }
  2268. }*/
  2269. }
  2270. public void TriggerScriptMovingStartEvent()
  2271. {
  2272. foreach (SceneObjectPart part in ChildrenList)
  2273. {
  2274. part.TriggerScriptMovingStartEvent();
  2275. }
  2276. }
  2277. public void TriggerScriptMovingEndEvent()
  2278. {
  2279. foreach (SceneObjectPart part in ChildrenList)
  2280. {
  2281. part.TriggerScriptMovingEndEvent();
  2282. }
  2283. }
  2284. public override string ToString()
  2285. {
  2286. return String.Format("{0} {1} ({2})", Name, UUID, AbsolutePosition);
  2287. }
  2288. #region Copying
  2289. /// <summary>
  2290. /// Make an exact copy of this group.
  2291. /// This does NOT reset any UUIDs, localIDs, or anything, as this is an EXACT copy.
  2292. /// </summary>
  2293. /// <returns></returns>
  2294. public ISceneEntity Copy(bool clonePhys)
  2295. {
  2296. SceneObjectGroup dupe = (SceneObjectGroup) MemberwiseClone();
  2297. dupe.m_parts = new Dictionary<UUID, SceneObjectPart>();
  2298. dupe.m_partsList = new List<SceneObjectPart>();
  2299. dupe.m_scene = Scene;
  2300. // Warning, The following code related to previousAttachmentStatus is needed so that clones of
  2301. // attachments do not bordercross while they're being duplicated. This is hacktastic!
  2302. // Normally, setting AbsolutePosition will bordercross a prim if it's outside the region!
  2303. // unless IsAttachment is true!, so to prevent border crossing, we save it's attachment state
  2304. // (which should be false anyway) set it as an Attachment and then set it's Absolute Position,
  2305. // then restore it's attachment state
  2306. // This is only necessary when userExposed is false!
  2307. dupe.ClearChildren();
  2308. dupe.AddChild(m_rootPart.Copy(dupe, clonePhys), m_rootPart.LinkNum);
  2309. bool previousAttachmentStatus = dupe.RootPart.IsAttachment;
  2310. dupe.RootPart.IsAttachment = true;
  2311. dupe.AbsolutePosition = AbsolutePosition;
  2312. dupe.RootPart.IsAttachment = previousAttachmentStatus;
  2313. dupe.m_rootPart.TrimPermissions();
  2314. List<SceneObjectPart> partList = new List<SceneObjectPart>();
  2315. lock (m_partsLock)
  2316. {
  2317. partList.AddRange(m_partsList);
  2318. }
  2319. //Sort the list by link number so that we get them in the right order
  2320. partList.Sort(Scene.SceneGraph.LinkSetSorter);
  2321. foreach (SceneObjectPart part in partList)
  2322. {
  2323. if (part.UUID != m_rootPart.UUID)
  2324. {
  2325. SceneObjectPart copy = part.Copy(dupe, clonePhys);
  2326. copy.LinkNum = part.LinkNum;
  2327. dupe.LinkChild(copy);
  2328. }
  2329. }
  2330. dupe.m_ValidgrpOOB = false;
  2331. return dupe;
  2332. }
  2333. /// <summary>
  2334. /// Rebuild the physical representation of all the prims.
  2335. /// This is used after copying the prim so that all of the object is readded to the physics scene.
  2336. /// </summary>
  2337. public void RebuildPhysicalRepresentation(bool keepSelectedStatuses)
  2338. {
  2339. // long lock or array copy? in this case lets try array
  2340. SceneObjectPart[] parts;
  2341. SceneObjectPart part;
  2342. int i;
  2343. lock (m_partsLock)
  2344. parts = m_partsList.ToArray();
  2345. if (RootPart.PhysActor != null)
  2346. RootPart.PhysActor.BlockPhysicalReconstruction = true;
  2347. for (i = 0; i < parts.Length; i++)
  2348. {
  2349. part = parts[i];
  2350. // PhysicsObject oldActor = part.PhysActor;
  2351. // PrimitiveBaseShape pbs = part.Shape;
  2352. if (part.PhysActor != null)
  2353. {
  2354. part.PhysActor.RotationalVelocity = Vector3.Zero;
  2355. part.m_hasSubscribedToCollisionEvent = false;
  2356. part.PhysActor.OnCollisionUpdate -= part.PhysicsCollision;
  2357. part.PhysActor.OnRequestTerseUpdate -= part.PhysicsRequestingTerseUpdate;
  2358. part.PhysActor.OnSignificantMovement -= part.ParentGroup.CheckForSignificantMovement;
  2359. part.PhysActor.OnOutOfBounds -= part.PhysicsOutOfBounds;
  2360. //part.PhysActor.delink ();
  2361. //Remove the old one so that we don't have more than we should,
  2362. // as when we copy, it readds it to the PhysicsScene somehow
  2363. //if (part.IsRoot)//The root removes all children
  2364. m_scene.PhysicsScene.RemovePrim(part.PhysActor);
  2365. part.FireOnRemovedPhysics();
  2366. part.PhysActor = null;
  2367. }
  2368. //Reset any old data that we have
  2369. part.Velocity = Vector3.Zero;
  2370. part.AngularVelocity = Vector3.Zero;
  2371. part.Acceleration = Vector3.Zero;
  2372. part.GenerateRotationalVelocityFromOmega();
  2373. }
  2374. //Check for meshes and stuff
  2375. CheckSculptAndLoad();
  2376. // check root part setting that make the entire object not having physics rep
  2377. if (RootPart.PhysicsType == (byte) PhysicsShapeType.None ||
  2378. ((RootPart.Flags & PrimFlags.Phantom) == PrimFlags.Phantom && !RootPart.VolumeDetectActive))
  2379. {
  2380. Scene.AuroraEventManager.FireGenericEventHandler("ObjectChangedPhysicalStatus", this);
  2381. if (OnFinishedPhysicalRepresentationBuilding != null)
  2382. OnFinishedPhysicalRepresentationBuilding();
  2383. OnFinishedPhysicalRepresentationBuilding = null;
  2384. return;
  2385. }
  2386. // create the root part
  2387. RootPart.PhysActor = m_scene.PhysicsScene.AddPrimShape(RootPart);
  2388. if (RootPart.PhysActor == null)
  2389. return;
  2390. // RootPart.PhysActor.BuildingRepresentation = true;
  2391. RootPart.PhysActor.BlockPhysicalReconstruction = true;
  2392. //Don't let it rebuild it until we have all the links done
  2393. //Fix the localID!
  2394. RootPart.PhysActor.LocalID = RootPart.LocalId;
  2395. RootPart.PhysActor.UUID = RootPart.UUID;
  2396. RootPart.PhysActor.VolumeDetect = RootPart.VolumeDetectActive;
  2397. //Force deselection here so that it isn't stuck forever
  2398. RootPart.PhysActor.Selected = keepSelectedStatuses && RootPart.IsSelected;
  2399. RootPart.PhysActor.SetMaterial(RootPart.Material, false);
  2400. // bool rootIsPhysical;
  2401. if ((RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics)
  2402. {
  2403. // rootIsPhysical = true;
  2404. RootPart.PhysActor.IsPhysical = true;
  2405. }
  2406. // else
  2407. // rootIsPhysical = false;
  2408. //Add collision updates
  2409. //part.PhysActor.OnCollisionUpdate += RootPart.PhysicsCollision;
  2410. RootPart.PhysActor.OnRequestTerseUpdate += RootPart.PhysicsRequestingTerseUpdate;
  2411. RootPart.PhysActor.OnSignificantMovement += RootPart.ParentGroup.CheckForSignificantMovement;
  2412. RootPart.PhysActor.OnOutOfBounds += RootPart.PhysicsOutOfBounds;
  2413. RootPart.FireOnAddedPhysics();
  2414. RootPart.aggregateScriptEvents();
  2415. for (i = 0; i < parts.Length; i++)
  2416. {
  2417. part = parts[i];
  2418. if (part == RootPart ||
  2419. part.PhysicsType == (byte) PhysicsShapeType.None ||
  2420. ((part.Flags & PrimFlags.Phantom) == PrimFlags.Phantom && !part.VolumeDetectActive))
  2421. {
  2422. continue; // ignore phantom prims
  2423. }
  2424. //Now read the physics actor to the physics scene
  2425. part.PhysActor = m_scene.PhysicsScene.AddPrimShape(part);
  2426. if (part.PhysActor == null)
  2427. continue;
  2428. // part.PhysActor.BuildingRepresentation = true;
  2429. // if(part.IsRoot)
  2430. part.PhysActor.BlockPhysicalReconstruction = true;
  2431. //Don't let it rebuild it until we have all the links done
  2432. //Fix the localID!
  2433. part.PhysActor.LocalID = part.LocalId;
  2434. part.PhysActor.UUID = part.UUID;
  2435. part.PhysActor.VolumeDetect = part.VolumeDetectActive;
  2436. //Force deselection here so that it isn't stuck forever
  2437. part.PhysActor.Selected = keepSelectedStatuses && part.IsSelected;
  2438. part.PhysActor.SetMaterial(part.Material, false);
  2439. if ((part.Flags & PrimFlags.Physics) == PrimFlags.Physics)
  2440. part.PhysActor.IsPhysical = true;
  2441. //Add collision updates
  2442. //part.PhysActor.OnCollisionUpdate += part.PhysicsCollision;
  2443. part.PhysActor.OnRequestTerseUpdate += part.PhysicsRequestingTerseUpdate;
  2444. part.PhysActor.OnSignificantMovement += part.ParentGroup.CheckForSignificantMovement;
  2445. part.PhysActor.OnOutOfBounds += part.PhysicsOutOfBounds;
  2446. part.FireOnAddedPhysics();
  2447. part.aggregateScriptEvents();
  2448. //Link the prim then
  2449. // if(rootIsPhysical)
  2450. part.PhysActor.link(RootPart.PhysActor);
  2451. }
  2452. Scene.AuroraEventManager.FireGenericEventHandler("ObjectChangedPhysicalStatus", this);
  2453. RootPart.PhysActor.BlockPhysicalReconstruction = false; // this sets children also (in AODE at least)
  2454. // RootPart.PhysActor.BuildingRepresentation = false;
  2455. FixVehicleParams(RootPart);
  2456. if (OnFinishedPhysicalRepresentationBuilding != null)
  2457. OnFinishedPhysicalRepresentationBuilding();
  2458. OnFinishedPhysicalRepresentationBuilding = null;
  2459. }
  2460. /*
  2461. lock (m_partsLock)
  2462. {
  2463. foreach (SceneObjectPart part in m_partsList)
  2464. {
  2465. PhysicsObject oldActor = part.PhysActor;
  2466. PrimitiveBaseShape pbs = part.Shape;
  2467. //Reset any old data that we have
  2468. part.Velocity = Vector3.Zero;
  2469. part.Acceleration = Vector3.Zero;
  2470. if (part.PhysActor != null)
  2471. {
  2472. part.PhysActor.RotationalVelocity = Vector3.Zero;
  2473. part.PhysActor.UnSubscribeEvents ();
  2474. part.m_hasSubscribedToCollisionEvent = false;
  2475. part.PhysActor.OnCollisionUpdate -= part.PhysicsCollision;
  2476. part.PhysActor.OnRequestTerseUpdate -= part.PhysicsRequestingTerseUpdate;
  2477. part.PhysActor.OnSignificantMovement -= part.ParentGroup.CheckForSignificantMovement;
  2478. part.PhysActor.OnOutOfBounds -= part.PhysicsOutOfBounds;
  2479. //part.PhysActor.delink ();
  2480. //Remove the old one so that we don't have more than we should,
  2481. // as when we copy, it readds it to the PhysicsScene somehow
  2482. //if (part.IsRoot)//The root removes all children
  2483. m_scene.PhysicsScene.RemovePrim (part.PhysActor);
  2484. part.FireOnRemovedPhysics ();
  2485. }
  2486. part.AngularVelocity = Vector3.Zero;
  2487. part.GenerateRotationalVelocityFromOmega ();
  2488. }
  2489. }
  2490. //Check for meshes and stuff
  2491. CheckSculptAndLoad ();
  2492. //This is a heavy operation... it is really bad to lock this, but if we don't, we could have multiple threads in here... which would be baaad
  2493. lock (m_partsLock)
  2494. {
  2495. foreach (SceneObjectPart part in m_partsList)
  2496. {
  2497. if (RootPart.PhysicsType == (byte)PhysicsShapeType.None ||
  2498. part.PhysicsType == (byte)PhysicsShapeType.None ||
  2499. ((part.Flags & PrimFlags.Phantom) == PrimFlags.Phantom &&
  2500. !part.VolumeDetectActive) ||
  2501. ((RootPart.Flags & PrimFlags.Phantom) == PrimFlags.Phantom &&
  2502. !RootPart.VolumeDetectActive))
  2503. {
  2504. part.PhysActor = null;
  2505. continue; //Don't rebuild! All phantom if the root is phantom
  2506. }
  2507. //Now readd the physics actor to the physics scene
  2508. part.PhysActor = m_scene.PhysicsScene.AddPrimShape (part);
  2509. // part.PhysActor.BuildingRepresentation = true;
  2510. // if(part.IsRoot)
  2511. // part.PhysActor.BlockPhysicalReconstruction = true;//Don't let it rebuild it until we have all the links done
  2512. //Fix the localID!
  2513. part.PhysActor.LocalID = part.LocalId;
  2514. part.PhysActor.UUID = part.UUID;
  2515. part.PhysActor.VolumeDetect = part.VolumeDetectActive;
  2516. //Force deselection here so that it isn't stuck forever
  2517. if (!keepSelectedStatuses)
  2518. part.PhysActor.Selected = false;
  2519. else
  2520. part.PhysActor.Selected = part.IsSelected;
  2521. part.PhysActor.SetMaterial (part.Material, false);
  2522. //Add collision updates
  2523. //part.PhysActor.OnCollisionUpdate += part.PhysicsCollision;
  2524. part.PhysActor.OnRequestTerseUpdate += part.PhysicsRequestingTerseUpdate;
  2525. part.PhysActor.OnSignificantMovement += part.ParentGroup.CheckForSignificantMovement;
  2526. part.PhysActor.OnOutOfBounds += part.PhysicsOutOfBounds;
  2527. part.FireOnAddedPhysics ();
  2528. part.aggregateScriptEvents ();
  2529. }
  2530. Scene.AuroraEventManager.FireGenericEventHandler ("ObjectChangedPhysicalStatus", this);
  2531. }
  2532. lock (m_partsLock)
  2533. {
  2534. foreach (SceneObjectPart part in m_partsList)
  2535. {
  2536. if (!part.IsRoot && RootPart.PhysActor != null && part.PhysActor != null)//Link the prim then
  2537. part.PhysActor.link (RootPart.PhysActor);
  2538. }
  2539. foreach (SceneObjectPart part in m_partsList)
  2540. {
  2541. if (part.PhysActor != null)
  2542. {
  2543. FixVehicleParams(part);
  2544. // *
  2545. if(part.IsRoot)
  2546. {
  2547. //All done linking, build the body
  2548. part.PhysActor.BlockPhysicalReconstruction = false;
  2549. }
  2550. part.PhysActor.BuildingRepresentation = false;
  2551. // *
  2552. }
  2553. }
  2554. if(OnFinishedPhysicalRepresentationBuilding != null)
  2555. OnFinishedPhysicalRepresentationBuilding();
  2556. }
  2557. }
  2558. */
  2559. /// <summary>
  2560. /// Fix all the vehicle params after rebuilding the representation
  2561. /// </summary>
  2562. /// <param name="part"></param>
  2563. private void FixVehicleParams(SceneObjectPart part)
  2564. {
  2565. part.PhysActor.VehicleType = part.VehicleType;
  2566. // OSD o = part.GetComponentState("VehicleParameters");
  2567. foreach (OSD param in part.VehicleFlags)
  2568. {
  2569. part.PhysActor.VehicleFlags(param.AsInteger(), false);
  2570. }
  2571. foreach (KeyValuePair<string, OSD> param in part.VehicleParameters)
  2572. {
  2573. if (param.Value.Type == OSDType.Real)
  2574. part.PhysActor.VehicleFloatParam(int.Parse(param.Key), (float) param.Value.AsReal());
  2575. else if (param.Value.Type == OSDType.Array)
  2576. {
  2577. OSDArray a = (OSDArray) param.Value;
  2578. if (a.Count == 3)
  2579. part.PhysActor.VehicleVectorParam(int.Parse(param.Key), param.Value.AsVector3());
  2580. else
  2581. part.PhysActor.VehicleRotationParam(int.Parse(param.Key), param.Value.AsQuaternion());
  2582. }
  2583. }
  2584. }
  2585. #endregion
  2586. #region Script methods
  2587. public Vector3 GetTorque()
  2588. {
  2589. // We check if rootpart is null here because scripts don't delete if you delete the host.
  2590. // This means that unfortunately, we can pass a null physics actor to Simulate!
  2591. // Make sure we don't do that!
  2592. SceneObjectPart rootpart = m_rootPart;
  2593. if (rootpart != null)
  2594. {
  2595. if (rootpart.PhysActor != null)
  2596. {
  2597. if (!IsAttachment)
  2598. {
  2599. Vector3 torque = rootpart.PhysActor.Torque;
  2600. return torque;
  2601. }
  2602. }
  2603. }
  2604. return Vector3.Zero;
  2605. }
  2606. /// <summary>
  2607. /// Set the owner of the root part.
  2608. /// </summary>
  2609. /// <param name="part"></param>
  2610. /// <param name="cAgentID"></param>
  2611. /// <param name="cGroupID"></param>
  2612. public void SetRootPartOwner(ISceneChildEntity part, UUID cAgentID, UUID cGroupID)
  2613. {
  2614. part.LastOwnerID = part.OwnerID;
  2615. part.OwnerID = cAgentID;
  2616. part.GroupID = cGroupID;
  2617. if (part.OwnerID != cAgentID)
  2618. {
  2619. // Apply Next Owner Permissions if we're not bypassing permissions
  2620. if (!m_scene.Permissions.BypassPermissions())
  2621. ApplyNextOwnerPermissions();
  2622. }
  2623. part.ScheduleUpdate(PrimUpdateFlags.ForcedFullUpdate);
  2624. }
  2625. public void ScriptSetPhysicsStatus(bool UsePhysics)
  2626. {
  2627. bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
  2628. bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
  2629. bool IsVolumeDetect = RootPart.VolumeDetectActive;
  2630. UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect, null);
  2631. }
  2632. public void ScriptSetTemporaryStatus(bool TemporaryStatus)
  2633. {
  2634. bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
  2635. bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
  2636. bool IsVolumeDetect = RootPart.VolumeDetectActive;
  2637. UpdatePrimFlags(RootPart.LocalId, UsePhysics, TemporaryStatus, IsPhantom, IsVolumeDetect, null);
  2638. }
  2639. public void ScriptSetPhantomStatus(bool PhantomStatus)
  2640. {
  2641. bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
  2642. bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
  2643. bool IsVolumeDetect = RootPart.VolumeDetectActive;
  2644. UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, PhantomStatus, IsVolumeDetect, null);
  2645. }
  2646. public void ScriptSetVolumeDetect(bool VDStatus)
  2647. {
  2648. bool UsePhysics = ((RootPart.Flags & PrimFlags.Physics) != 0);
  2649. bool IsTemporary = ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0);
  2650. bool IsPhantom = ((RootPart.Flags & PrimFlags.Phantom) != 0);
  2651. UpdatePrimFlags(RootPart.LocalId, UsePhysics, IsTemporary, IsPhantom, VDStatus, null);
  2652. }
  2653. public void applyImpulse(Vector3 impulse)
  2654. {
  2655. // We check if rootpart is null here because scripts don't delete if you delete the host.
  2656. // This means that unfortunately, we can pass a null physics actor to Simulate!
  2657. // Make sure we don't do that!
  2658. SceneObjectPart rootpart = m_rootPart;
  2659. if (rootpart != null)
  2660. {
  2661. if (IsAttachment)
  2662. {
  2663. IScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
  2664. if (avatar != null)
  2665. {
  2666. avatar.PushForce(impulse);
  2667. }
  2668. }
  2669. else
  2670. {
  2671. if (rootpart.PhysActor != null)
  2672. rootpart.PhysActor.AddForce(impulse, true);
  2673. }
  2674. }
  2675. }
  2676. public void applyAngularImpulse(Vector3 impulse)
  2677. {
  2678. // We check if rootpart is null here because scripts don't delete if you delete the host.
  2679. // This means that unfortunately, we can pass a null physics actor to Simulate!
  2680. // Make sure we don't do that!
  2681. SceneObjectPart rootpart = m_rootPart;
  2682. if (rootpart != null)
  2683. {
  2684. if (rootpart.PhysActor != null)
  2685. {
  2686. if (!IsAttachment)
  2687. rootpart.PhysActor.AddAngularForce(impulse, true);
  2688. }
  2689. }
  2690. }
  2691. public void setAngularImpulse(Vector3 impulse)
  2692. {
  2693. // We check if rootpart is null here because scripts don't delete if you delete the host.
  2694. // This means that unfortunately, we can pass a null physics actor to Simulate!
  2695. // Make sure we don't do that!
  2696. SceneObjectPart rootpart = m_rootPart;
  2697. if (rootpart != null)
  2698. {
  2699. if (rootpart.PhysActor != null)
  2700. {
  2701. if (!IsAttachment)
  2702. rootpart.PhysActor.Torque = impulse;
  2703. }
  2704. }
  2705. }
  2706. public void moveToTarget(Vector3 target, float tau)
  2707. {
  2708. SceneObjectPart rootpart = m_rootPart;
  2709. if (rootpart != null)
  2710. {
  2711. if (IsAttachment)
  2712. {
  2713. IScenePresence avatar = m_scene.GetScenePresence(rootpart.AttachedAvatar);
  2714. if (avatar != null)
  2715. {
  2716. List<string> coords = new List<string>();
  2717. uint regionX = 0;
  2718. uint regionY = 0;
  2719. Utils.LongToUInts(Scene.RegionInfo.RegionHandle, out regionX, out regionY);
  2720. target.X += regionX;
  2721. target.Y += regionY;
  2722. coords.Add(target.X.ToString());
  2723. coords.Add(target.Y.ToString());
  2724. coords.Add(target.Z.ToString());
  2725. avatar.DoMoveToPosition(avatar, "", coords);
  2726. }
  2727. }
  2728. else
  2729. {
  2730. rootpart.SetMoveToTarget(true, target, tau);
  2731. }
  2732. }
  2733. }
  2734. public void stopMoveToTarget()
  2735. {
  2736. SceneObjectPart rootpart = m_rootPart;
  2737. if (rootpart != null)
  2738. {
  2739. if (rootpart.PhysActor != null)
  2740. {
  2741. rootpart.SetMoveToTarget(false, Vector3.Zero, 0);
  2742. }
  2743. }
  2744. }
  2745. /// <summary>
  2746. /// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
  2747. /// </summary>
  2748. /// <param name="height">Height to hover. Height of zero disables hover.</param>
  2749. /// <param name="hoverType">Determines what the height is relative to </param>
  2750. /// <param name="tau">Number of seconds over which to reach target</param>
  2751. public void SetHoverHeight(float height, PIDHoverType hoverType, float tau)
  2752. {
  2753. SceneObjectPart rootpart = m_rootPart;
  2754. if (rootpart != null)
  2755. {
  2756. if (rootpart.PhysActor != null)
  2757. {
  2758. if (height != 0f)
  2759. {
  2760. rootpart.PIDHoverHeight = height;
  2761. rootpart.PIDHoverType = hoverType;
  2762. rootpart.PIDTau = tau;
  2763. rootpart.PIDHoverActive = true;
  2764. }
  2765. else
  2766. {
  2767. rootpart.PIDHoverActive = false;
  2768. }
  2769. }
  2770. }
  2771. }
  2772. public void SetPartOwner(SceneObjectPart part, UUID cAgentID, UUID cGroupID)
  2773. {
  2774. part.OwnerID = cAgentID;
  2775. part.GroupID = cGroupID;
  2776. }
  2777. #endregion
  2778. #region Scheduling
  2779. /// <summary>
  2780. /// Send an update to all prims in the group to a specific avatar
  2781. /// </summary>
  2782. /// <param name="presence"></param>
  2783. /// <param name="UpdateFlags"></param>
  2784. public void ScheduleGroupUpdateToAvatar(IScenePresence presence, PrimUpdateFlags UpdateFlags)
  2785. {
  2786. //We have to send the root part first as the client wants it that way
  2787. presence.AddUpdateToAvatar(RootPart, UpdateFlags);
  2788. #if (!ISWIN)
  2789. foreach (SceneObjectPart part in m_partsList)
  2790. {
  2791. if (part != RootPart)
  2792. {
  2793. presence.AddUpdateToAvatar(part, UpdateFlags);
  2794. }
  2795. }
  2796. #else
  2797. foreach (SceneObjectPart part in m_partsList.Where(part => part != RootPart))
  2798. {
  2799. presence.AddUpdateToAvatar(part, UpdateFlags);
  2800. }
  2801. #endif
  2802. }
  2803. /// <summary>
  2804. /// Send an update to all prims in the group
  2805. /// </summary>
  2806. /// <param name="UpdateFlags"></param>
  2807. public void ScheduleGroupUpdate(PrimUpdateFlags UpdateFlags)
  2808. {
  2809. //We have to send the root part first as the client wants it that way
  2810. RootPart.ScheduleUpdate(UpdateFlags);
  2811. foreach (SceneObjectPart part in m_partsList.Where(part => part != RootPart))
  2812. {
  2813. part.ScheduleUpdate(UpdateFlags);
  2814. }
  2815. }
  2816. /// <summary>
  2817. /// Schedule a terse update (position, rotation, velocity, and rotational velocity update) for this object to all clients
  2818. /// </summary>
  2819. public void ScheduleGroupTerseUpdate()
  2820. {
  2821. //We have to send the root part first as the client wants it that way
  2822. RootPart.ScheduleTerseUpdate();
  2823. foreach (SceneObjectPart part in m_partsList.Where(part => part != RootPart))
  2824. {
  2825. part.ScheduleTerseUpdate();
  2826. }
  2827. }
  2828. public void Update()
  2829. {
  2830. }
  2831. /// <summary>
  2832. /// </summary>
  2833. /// <param name="remoteClient"></param>
  2834. /// <param name="AgentID"></param>
  2835. /// <param name="RequestFlags"></param>
  2836. public void ServiceObjectPropertiesFamilyRequest(IClientAPI remoteClient, UUID AgentID, uint RequestFlags)
  2837. {
  2838. remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID,
  2839. RootPart.BaseMask,
  2840. RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask,
  2841. RootPart.NextOwnerMask,
  2842. RootPart.OwnershipCost, RootPart.ObjectSaleType,
  2843. RootPart.SalePrice, RootPart.Category,
  2844. RootPart.CreatorID, RootPart.Name, RootPart.Description);
  2845. }
  2846. /// <summary>
  2847. /// See if the object has moved enough to trigger the Significant Movement event
  2848. /// </summary>
  2849. protected internal void CheckForSignificantMovement()
  2850. {
  2851. m_scene.EventManager.TriggerSignificantObjectMovement(this);
  2852. //Do this second! This is important, otherwise
  2853. // if the object isn't allowed, we will not be able
  2854. // to reset its position to the last known good pos
  2855. m_lastSignificantPosition = AbsolutePosition;
  2856. }
  2857. #endregion
  2858. #region Get Children Methods
  2859. /// <summary>
  2860. /// Get the child part by LinkNum
  2861. /// </summary>
  2862. /// <param name="linknum"></param>
  2863. /// <returns>null if no child part with that linknum or child part</returns>
  2864. public IEntity GetLinkNumPart(int linknum)
  2865. {
  2866. if (linknum <= m_parts.Count)
  2867. {
  2868. if (m_parts.Count == 1)
  2869. return RootPart;
  2870. #if (!ISWIN)
  2871. foreach (SceneObjectPart part in m_partsList)
  2872. {
  2873. if (part.LinkNum == linknum)
  2874. {
  2875. return part;
  2876. }
  2877. }
  2878. #else
  2879. foreach (SceneObjectPart part in m_partsList.Where(part => part.LinkNum == linknum))
  2880. {
  2881. return part;
  2882. }
  2883. #endif
  2884. }
  2885. //Check sitting avatars
  2886. int count = m_parts.Count + 1;
  2887. foreach (UUID agentID in SitTargetAvatar)
  2888. {
  2889. if (count == linknum)
  2890. {
  2891. return m_scene.GetScenePresence(agentID);
  2892. }
  2893. count++;
  2894. }
  2895. return null;
  2896. }
  2897. /// <summary>
  2898. /// Get a child prim of this group by LocalID
  2899. /// </summary>
  2900. /// <param name="LocalID"></param>
  2901. /// <param name="entity"></param>
  2902. /// <returns></returns>
  2903. public bool GetChildPrim(uint LocalID, out ISceneChildEntity entity)
  2904. {
  2905. entity = GetChildPart(LocalID);
  2906. return entity != null;
  2907. }
  2908. /// <summary>
  2909. /// Get a child prim of this group by UUID
  2910. /// </summary>
  2911. /// <param name="UUID2"></param>
  2912. /// <param name="entity"></param>
  2913. /// <returns></returns>
  2914. public bool GetChildPrim(UUID UUID2, out ISceneChildEntity entity)
  2915. {
  2916. entity = GetChildPart(UUID2);
  2917. return entity != null;
  2918. }
  2919. /// <summary>
  2920. /// Get a part with a given UUID
  2921. /// </summary>
  2922. /// <param name="primID"></param>
  2923. /// <returns>null if a child part with the primID was not found</returns>
  2924. public ISceneChildEntity GetChildPart(UUID primID)
  2925. {
  2926. SceneObjectPart childPart = null;
  2927. m_parts.TryGetValue(primID, out childPart);
  2928. return childPart;
  2929. }
  2930. /// <summary>
  2931. /// Get a part with a given UUID
  2932. /// </summary>
  2933. /// <param name="primID"></param>
  2934. /// <returns>null if a child part with the primID was not found</returns>
  2935. public ISceneChildEntity GetChildPart(uint primID)
  2936. {
  2937. #if (!ISWIN)
  2938. foreach (ISceneChildEntity part in m_partsList)
  2939. {
  2940. if (part.LocalId == primID) return part;
  2941. }
  2942. return null;
  2943. #else
  2944. return m_partsList.Cast<ISceneChildEntity>().FirstOrDefault(part => part.LocalId == primID);
  2945. #endif
  2946. }
  2947. #endregion
  2948. #region Packet Handlers
  2949. #region Linking and Delinking
  2950. /// <summary>
  2951. /// Link the prims in a given group to this group
  2952. /// </summary>
  2953. /// <param name="grp">The group of prims which should be linked to this group</param>
  2954. public void LinkToGroup(ISceneEntity grp)
  2955. {
  2956. //MainConsole.Instance.DebugFormat(
  2957. // "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
  2958. // objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
  2959. if (!(grp is SceneObjectGroup))
  2960. return;
  2961. SceneObjectGroup objectGroup = (SceneObjectGroup) grp;
  2962. if (m_rootPart.PhysActor != null)
  2963. m_rootPart.PhysActor.BlockPhysicalReconstruction = true;
  2964. SceneObjectPart linkPart = objectGroup.m_rootPart;
  2965. Vector3 oldGroupPosition = linkPart.GroupPosition;
  2966. Quaternion oldRootRotation = linkPart.GetRotationOffset();
  2967. Quaternion parentRot = m_rootPart.GetRotationOffset();
  2968. linkPart.SetGroupPosition(AbsolutePosition); // just change it without doing anything else
  2969. Vector3 axPos = oldGroupPosition - AbsolutePosition;
  2970. axPos *= Quaternion.Inverse(parentRot);
  2971. linkPart.SetOffsetPosition(axPos);
  2972. Quaternion newRot = Quaternion.Inverse(parentRot)*oldRootRotation;
  2973. linkPart.SetRotationOffset(false, newRot, false);
  2974. //Fix the link number for the root
  2975. if (m_rootPart.LinkNum == 0)
  2976. m_rootPart.LinkNum = 1;
  2977. SceneObjectPart[] objectGroupChildren = new SceneObjectPart[objectGroup.ChildrenList.Count];
  2978. objectGroup.ChildrenList.CopyTo(objectGroupChildren, 0);
  2979. //Destroy the old group
  2980. m_scene.SceneGraph.DeleteEntity(objectGroup);
  2981. objectGroup.IsDeleted = true;
  2982. objectGroup.ClearChildren();
  2983. lock (m_partsLock)
  2984. {
  2985. int linkNum = 2;
  2986. //Add the root part to our group!
  2987. m_scene.SceneGraph.LinkPartToSOG(this, linkPart, linkNum++);
  2988. linkPart.CreateSelected = true;
  2989. linkPart.FixOffsetPosition(linkPart.OffsetPosition, true); // nasty let all know about where this is
  2990. // let physics link it
  2991. if (linkPart.PhysActor != null && m_rootPart.PhysActor != null)
  2992. {
  2993. if (linkPart.PhysicsType != (byte) PhysicsShapeType.None)
  2994. linkPart.PhysActor.link(m_rootPart.PhysActor);
  2995. }
  2996. //rest of parts
  2997. #if (!ISWIN)
  2998. foreach (SceneObjectPart part in objectGroupChildren)
  2999. {
  3000. if (part.UUID != objectGroup.m_rootPart.UUID)
  3001. {
  3002. LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
  3003. part.FixOffsetPosition(part.OffsetPosition, true);
  3004. if (part.PhysActor != null && m_rootPart.PhysActor != null)
  3005. part.PhysActor.link(m_rootPart.PhysActor);
  3006. }
  3007. }
  3008. #else
  3009. foreach (
  3010. SceneObjectPart part in objectGroupChildren.Where(part => part.UUID != objectGroup.m_rootPart.UUID))
  3011. {
  3012. LinkNonRootPart(part, oldGroupPosition, oldRootRotation, linkNum++);
  3013. part.FixOffsetPosition(part.OffsetPosition, true);
  3014. if (part.PhysActor != null && m_rootPart.PhysActor != null)
  3015. part.PhysActor.link(m_rootPart.PhysActor);
  3016. }
  3017. #endif
  3018. }
  3019. // Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
  3020. // position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
  3021. // unmoved prims!
  3022. m_ValidgrpOOB = false;
  3023. ResetChildPrimPhysicsPositions();
  3024. if (m_rootPart.PhysActor != null)
  3025. m_rootPart.PhysActor.BlockPhysicalReconstruction = false;
  3026. }
  3027. /// <summary>
  3028. /// Delink the given prim from this group. The delinked prim is established as
  3029. /// an independent SceneObjectGroup.
  3030. /// </summary>
  3031. /// <param name="part"></param>
  3032. /// <param name="sendEvents"></param>
  3033. /// <returns>The object group of the newly delinked prim.</returns>
  3034. public ISceneEntity DelinkFromGroup(ISceneChildEntity part, bool sendEvents)
  3035. {
  3036. if (!(part is SceneObjectPart))
  3037. return null;
  3038. SceneObjectPart linkPart = part as SceneObjectPart;
  3039. // MainConsole.Instance.DebugFormat(
  3040. // "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
  3041. // linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
  3042. Quaternion worldRot = linkPart.GetWorldRotation();
  3043. // Remove the part from this object
  3044. m_scene.SceneGraph.DeLinkPartFromEntity(this, linkPart);
  3045. linkPart.SetParentLocalId(0);
  3046. linkPart.LinkNum = 0;
  3047. if (linkPart.PhysActor != null)
  3048. {
  3049. m_scene.PhysicsScene.RemovePrim(linkPart.PhysActor);
  3050. }
  3051. // We need to reset the child part's position
  3052. // ready for life as a separate object after being a part of another object
  3053. Quaternion parentRot = m_rootPart.GetRotationOffset();
  3054. Vector3 axPos = linkPart.OffsetPosition;
  3055. axPos *= parentRot;
  3056. linkPart.SetOffsetPosition(axPos);
  3057. linkPart.FixGroupPosition(AbsolutePosition + linkPart.OffsetPosition, false);
  3058. linkPart.FixOffsetPosition(Vector3.Zero, false);
  3059. linkPart.SetRotationOffset(true, worldRot, true);
  3060. SceneObjectGroup objectGroup = new SceneObjectGroup(linkPart, Scene);
  3061. m_scene.SceneGraph.DelinkPartToScene(objectGroup);
  3062. if (sendEvents)
  3063. linkPart.TriggerScriptChangedEvent(Changed.LINK);
  3064. linkPart.Rezzed = RootPart.Rezzed;
  3065. //This is already set multiple places, no need to do it again
  3066. //HasGroupChanged = true;
  3067. //We need to send this so that we don't have issues with the client not realizing that the prims were unlinked
  3068. ScheduleGroupUpdate(PrimUpdateFlags.ForcedFullUpdate);
  3069. m_ValidgrpOOB = false;
  3070. return objectGroup;
  3071. }
  3072. private void LinkNonRootPart(SceneObjectPart part, Vector3 oldGroupPosition, Quaternion oldGroupRotation,
  3073. int linkNum)
  3074. {
  3075. Quaternion WorldRot = oldGroupRotation*part.GetRotationOffset();
  3076. // first fix from old local to world
  3077. // position
  3078. Vector3 axPos = part.OffsetPosition;
  3079. axPos *= oldGroupRotation;
  3080. part.SetGroupPosition(oldGroupPosition + axPos);
  3081. //offset
  3082. part.SetRotationOffset(false, WorldRot, false);
  3083. // have it in world coords lets fix other things
  3084. m_scene.SceneGraph.LinkPartToSOG(this, part, linkNum);
  3085. part.CreateSelected = true;
  3086. // now lets move to the new parent frame
  3087. Quaternion rootRotation = m_rootPart.GetRotationOffset();
  3088. Vector3 pos = part.GroupPosition - AbsolutePosition;
  3089. pos *= Quaternion.Inverse(rootRotation);
  3090. part.SetOffsetPosition(pos);
  3091. Quaternion newRot = Quaternion.Inverse(rootRotation)*WorldRot;
  3092. part.SetRotationOffset(false, newRot, false);
  3093. // caller will tell the rest about this position changes..
  3094. }
  3095. #endregion
  3096. /// <summary>
  3097. /// Return metadata about a prim (name, description, sale price, etc.)
  3098. /// </summary>
  3099. /// <param name="client"></param>
  3100. public void GetProperties(IClientAPI client)
  3101. {
  3102. m_rootPart.GetProperties(client);
  3103. }
  3104. public void UpdatePermissions(UUID AgentID, byte field, uint localID,
  3105. uint mask, byte addRemTF)
  3106. {
  3107. foreach (SceneObjectPart part in m_partsList)
  3108. part.UpdatePermissions(AgentID, field, localID, mask,
  3109. addRemTF);
  3110. HasGroupChanged = true;
  3111. }
  3112. /// <summary>
  3113. /// If object is physical, apply force to move it around
  3114. /// If object is not physical, just put it at the resulting location
  3115. /// </summary>
  3116. /// <param name="offset">Always seems to be 0,0,0, so ignoring</param>
  3117. /// <param name="pos">New position. We do the math here to turn it into a force</param>
  3118. /// <param name="remoteClient"></param>
  3119. public void GrabMovement(Vector3 offset, Vector3 pos, IClientAPI remoteClient)
  3120. {
  3121. if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
  3122. {
  3123. if (m_rootPart.PhysActor != null)
  3124. {
  3125. if (m_rootPart.PhysActor.IsPhysical)
  3126. {
  3127. if (!m_rootPart.BlockGrab && !m_rootPart.BlockGrabObject)
  3128. {
  3129. Vector3 grabforce = pos - AbsolutePosition;
  3130. grabforce = grabforce*m_rootPart.PhysActor.Mass;
  3131. m_rootPart.PhysActor.AddForce(grabforce, true);
  3132. // This is outside the above permissions condition
  3133. // so that if the object is locked the client moving the object
  3134. // get's it's position on the simulator even if it was the same as before
  3135. // This keeps the moving user's client in sync with the rest of the world.
  3136. ScheduleGroupTerseUpdate();
  3137. }
  3138. }
  3139. }
  3140. }
  3141. }
  3142. public void NonPhysicalGrabMovement(Vector3 pos)
  3143. {
  3144. AbsolutePosition = pos;
  3145. m_rootPart.ScheduleTerseUpdate();
  3146. }
  3147. /// <summary>
  3148. /// If object is physical, prepare for spinning torques (set flag to save old orientation)
  3149. /// </summary>
  3150. /// <param name="remoteClient"></param>
  3151. public void SpinStart(IClientAPI remoteClient)
  3152. {
  3153. if (m_scene.EventManager.TriggerGroupSpinStart(UUID))
  3154. {
  3155. if (m_rootPart.PhysActor != null)
  3156. {
  3157. if (m_rootPart.PhysActor.IsPhysical)
  3158. {
  3159. m_rootPart.IsWaitingForFirstSpinUpdatePacket = true;
  3160. }
  3161. }
  3162. }
  3163. }
  3164. /// <summary>
  3165. /// If object is physical, apply torque to spin it around
  3166. /// </summary>
  3167. /// <param name="newOrientation">Rotation. We do the math here to turn it into a torque</param>
  3168. /// <param name="remoteClient"></param>
  3169. public void SpinMovement(Quaternion newOrientation, IClientAPI remoteClient)
  3170. {
  3171. // The incoming newOrientation, sent by the client, "seems" to be the
  3172. // desired target orientation. This needs further verification; in particular,
  3173. // one would expect that the initial incoming newOrientation should be
  3174. // fairly close to the original prim's physical orientation,
  3175. // m_rootPart.PhysActor.Orientation. This however does not seem to be the
  3176. // case (might just be an issue with different quaternions representing the
  3177. // same rotation, or it might be a coordinate system issue).
  3178. //
  3179. // Since it's not clear what the relationship is between the PhysActor.Orientation
  3180. // and the incoming orientations sent by the client, we take an alternative approach
  3181. // of calculating the delta rotation between the orientations being sent by the
  3182. // client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect
  3183. // a steady stream of several new orientations coming in from the client.)
  3184. // This ensures that the delta rotations are being calculated from self-consistent
  3185. // pairs of old/new rotations. Given the delta rotation, we apply a torque around
  3186. // the delta rotation axis, scaled by the object mass times an arbitrary scaling
  3187. // factor (to ensure the resulting torque is not "too strong" or "too weak").
  3188. //
  3189. // Ideally we need to calculate (probably iteratively) the exact torque or series
  3190. // of torques needed to arrive exactly at the destination orientation. However, since
  3191. // it is not yet clear how to map the destination orientation (provided by the viewer)
  3192. // into PhysActor orientations (needed by the physics engine), we omit this step.
  3193. // This means that the resulting torque will at least be in the correct direction,
  3194. // but it will result in over-shoot or under-shoot of the target orientation.
  3195. // For the end user, this means that ctrl+shift+drag can be used for relative,
  3196. // but not absolute, adjustments of orientation for physical prims.
  3197. if (m_scene.EventManager.TriggerGroupSpin(UUID, newOrientation))
  3198. {
  3199. if (m_rootPart.PhysActor != null)
  3200. {
  3201. if (m_rootPart.PhysActor.IsPhysical)
  3202. {
  3203. if (m_rootPart.IsWaitingForFirstSpinUpdatePacket)
  3204. {
  3205. // first time initialization of "old" orientation for calculation of delta rotations
  3206. m_rootPart.SpinOldOrientation = newOrientation;
  3207. m_rootPart.IsWaitingForFirstSpinUpdatePacket = false;
  3208. }
  3209. else
  3210. {
  3211. // save and update old orientation
  3212. Quaternion old = m_rootPart.SpinOldOrientation;
  3213. m_rootPart.SpinOldOrientation = newOrientation;
  3214. //MainConsole.Instance.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
  3215. //MainConsole.Instance.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
  3216. // compute difference between previous old rotation and new incoming rotation
  3217. Quaternion minimalRotationFromQ1ToQ2 = Quaternion.Inverse(old)*newOrientation;
  3218. float rotationAngle;
  3219. Vector3 rotationAxis;
  3220. minimalRotationFromQ1ToQ2.GetAxisAngle(out rotationAxis, out rotationAngle);
  3221. rotationAxis.Normalize();
  3222. //MainConsole.Instance.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
  3223. Vector3 spinforce = new Vector3(rotationAxis.X, rotationAxis.Y, rotationAxis.Z);
  3224. spinforce = (spinforce/8)*m_rootPart.PhysActor.Mass;
  3225. // 8 is an arbitrary torque scaling factor
  3226. m_rootPart.PhysActor.AddAngularForce(spinforce, true);
  3227. }
  3228. }
  3229. }
  3230. }
  3231. }
  3232. /// <summary>
  3233. /// Set the name of a prim
  3234. /// </summary>
  3235. /// <param name="name"></param>
  3236. /// <param name="localID"></param>
  3237. public void SetPartName(string name, uint localID)
  3238. {
  3239. ISceneChildEntity part = GetChildPart(localID);
  3240. if (part != null)
  3241. {
  3242. part.Name = name;
  3243. }
  3244. }
  3245. public void SetPartDescription(string des, uint localID)
  3246. {
  3247. ISceneChildEntity part = GetChildPart(localID);
  3248. if (part != null)
  3249. {
  3250. part.Description = des;
  3251. }
  3252. }
  3253. public string GetPartName(uint localID)
  3254. {
  3255. ISceneChildEntity part = GetChildPart(localID);
  3256. if (part != null)
  3257. {
  3258. return part.Name;
  3259. }
  3260. return String.Empty;
  3261. }
  3262. public string GetPartDescription(uint localID)
  3263. {
  3264. ISceneChildEntity part = GetChildPart(localID);
  3265. if (part != null)
  3266. {
  3267. return part.Description;
  3268. }
  3269. return String.Empty;
  3270. }
  3271. /// <summary>
  3272. /// Update prim flags for this group.
  3273. /// </summary>
  3274. /// <param name="localID"></param>
  3275. /// <param name="UsePhysics"></param>
  3276. /// <param name="IsTemporary"></param>
  3277. /// <param name="IsPhantom"></param>
  3278. /// <param name="IsVolumeDetect"></param>
  3279. /// <param name="blocks"></param>
  3280. public void UpdatePrimFlags(uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVolumeDetect,
  3281. ObjectFlagUpdatePacket.ExtraPhysicsBlock[] blocks)
  3282. {
  3283. ISceneChildEntity selectionPart = GetChildPart(localID);
  3284. if (IsTemporary)
  3285. {
  3286. // Remove from database and parcel prim count
  3287. // Temporary objects arn't saved to the database ever, so we don't need to do anything
  3288. }
  3289. if (selectionPart != null)
  3290. {
  3291. foreach (SceneObjectPart part in m_partsList)
  3292. {
  3293. IOpenRegionSettingsModule WSModule = Scene.RequestModuleInterface<IOpenRegionSettingsModule>();
  3294. if (WSModule != null)
  3295. {
  3296. if (WSModule.MaximumPhysPrimScale == -1)
  3297. break;
  3298. if (part.Scale.X > WSModule.MaximumPhysPrimScale ||
  3299. part.Scale.Y > WSModule.MaximumPhysPrimScale ||
  3300. part.Scale.Z > WSModule.MaximumPhysPrimScale)
  3301. {
  3302. UsePhysics = false; // Reset physics
  3303. break;
  3304. }
  3305. }
  3306. }
  3307. bool needsPhysicalRebuild = ((SceneObjectPart) selectionPart).UpdatePrimFlags(UsePhysics, IsTemporary,
  3308. IsPhantom, IsVolumeDetect,
  3309. blocks);
  3310. #if (!ISWIN)
  3311. foreach (SceneObjectPart part in m_partsList)
  3312. {
  3313. if (selectionPart != part)
  3314. {
  3315. if (needsPhysicalRebuild)
  3316. part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect, null);
  3317. else
  3318. needsPhysicalRebuild = part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect, null);
  3319. }
  3320. }
  3321. #else
  3322. foreach (SceneObjectPart part in m_partsList.Where(part => selectionPart != part))
  3323. {
  3324. if (needsPhysicalRebuild)
  3325. part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom, IsVolumeDetect, null);
  3326. else
  3327. needsPhysicalRebuild = part.UpdatePrimFlags(UsePhysics, IsTemporary, IsPhantom,
  3328. IsVolumeDetect, null);
  3329. }
  3330. #endif
  3331. if (needsPhysicalRebuild)
  3332. RebuildPhysicalRepresentation(true);
  3333. }
  3334. }
  3335. public void UpdateExtraParam(uint localID, ushort type, bool inUse, byte[] data)
  3336. {
  3337. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3338. if (part != null)
  3339. {
  3340. part.UpdateExtraParam(type, inUse, data);
  3341. }
  3342. }
  3343. /// <summary>
  3344. /// Update the texture entry for this part
  3345. /// </summary>
  3346. /// <param name="localID"></param>
  3347. /// <param name="textureEntry"></param>
  3348. /// <param name="sendChangedEvent"></param>
  3349. public void UpdateTextureEntry(uint localID, byte[] textureEntry, bool sendChangedEvent)
  3350. {
  3351. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3352. if (part != null)
  3353. {
  3354. part.UpdateTextureEntry(textureEntry, sendChangedEvent);
  3355. }
  3356. }
  3357. #endregion
  3358. #region Shape
  3359. /// <summary>
  3360. /// </summary>
  3361. /// <param name="shapeBlock"></param>
  3362. /// <param name="localID"></param>
  3363. public void UpdateShape(ObjectShapePacket.ObjectDataBlock shapeBlock, uint localID)
  3364. {
  3365. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3366. if (part != null)
  3367. {
  3368. part.UpdateShape(shapeBlock);
  3369. m_ValidgrpOOB = false;
  3370. }
  3371. }
  3372. #endregion
  3373. #region Resize
  3374. /// <summary>
  3375. /// Resize the given part
  3376. /// </summary>
  3377. /// <param name="scale"></param>
  3378. /// <param name="localID"></param>
  3379. public void Resize(Vector3 scale, uint localID)
  3380. {
  3381. CheckSculptAndLoad();
  3382. //Grab the mesh again if it is a sculpty/mesh as we remove it after the first mesh is built
  3383. IOpenRegionSettingsModule WSModule = Scene.RequestModuleInterface<IOpenRegionSettingsModule>();
  3384. if (WSModule != null)
  3385. {
  3386. if (WSModule.MinimumPrimScale != -1)
  3387. {
  3388. if (scale.X < WSModule.MinimumPrimScale)
  3389. scale.X = WSModule.MinimumPrimScale;
  3390. if (scale.Y < WSModule.MinimumPrimScale)
  3391. scale.Y = WSModule.MinimumPrimScale;
  3392. if (scale.Z < WSModule.MinimumPrimScale)
  3393. scale.Z = WSModule.MinimumPrimScale;
  3394. }
  3395. if (RootPart.PhysActor != null && RootPart.PhysActor.IsPhysical &&
  3396. WSModule.MaximumPhysPrimScale != -1)
  3397. {
  3398. if (scale.X > WSModule.MaximumPhysPrimScale)
  3399. scale.X = WSModule.MaximumPhysPrimScale;
  3400. if (scale.Y > WSModule.MaximumPhysPrimScale)
  3401. scale.Y = WSModule.MaximumPhysPrimScale;
  3402. if (scale.Z > WSModule.MaximumPhysPrimScale)
  3403. scale.Z = WSModule.MaximumPhysPrimScale;
  3404. }
  3405. if (WSModule.MaximumPrimScale != -1)
  3406. {
  3407. if (scale.X > WSModule.MaximumPrimScale)
  3408. scale.X = WSModule.MaximumPrimScale;
  3409. if (scale.Y > WSModule.MaximumPrimScale)
  3410. scale.Y = WSModule.MaximumPrimScale;
  3411. if (scale.Z > WSModule.MaximumPrimScale)
  3412. scale.Z = WSModule.MaximumPrimScale;
  3413. }
  3414. }
  3415. m_ValidgrpOOB = false;
  3416. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3417. if (part != null)
  3418. {
  3419. part.Resize(scale);
  3420. if (part.PhysActor != null)
  3421. part.PhysActor.Size = scale;
  3422. //if (part.UUID != m_rootPart.UUID)
  3423. HasGroupChanged = true;
  3424. ScheduleGroupUpdate(PrimUpdateFlags.Shape);
  3425. //if (part.UUID == m_rootPart.UUID)
  3426. //{
  3427. //if (m_rootPart.PhysActor != null)
  3428. //{
  3429. //m_rootPart.PhysActor.Size =
  3430. //new PhysicsVector(m_rootPart.Scale.X, m_rootPart.Scale.Y, m_rootPart.Scale.Z);
  3431. //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
  3432. //}
  3433. //}
  3434. }
  3435. }
  3436. public void GroupResize(Vector3 scale, uint localID)
  3437. {
  3438. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3439. if (part != null)
  3440. {
  3441. CheckSculptAndLoad();
  3442. //Grab the mesh again if it is a sculpty/mesh as we remove it after the first mesh is built
  3443. part.IgnoreUndoUpdate = true;
  3444. IOpenRegionSettingsModule WSModule = Scene.RequestModuleInterface<IOpenRegionSettingsModule>();
  3445. if (WSModule != null)
  3446. {
  3447. if (WSModule.MinimumPrimScale != -1)
  3448. {
  3449. if (scale.X < WSModule.MinimumPrimScale)
  3450. scale.X = WSModule.MinimumPrimScale;
  3451. if (scale.Y < WSModule.MinimumPrimScale)
  3452. scale.Y = WSModule.MinimumPrimScale;
  3453. if (scale.Z < WSModule.MinimumPrimScale)
  3454. scale.Z = WSModule.MinimumPrimScale;
  3455. }
  3456. if (RootPart.PhysActor != null && RootPart.PhysActor.IsPhysical &&
  3457. WSModule.MaximumPhysPrimScale != -1)
  3458. {
  3459. if (scale.X > WSModule.MaximumPhysPrimScale)
  3460. scale.X = WSModule.MaximumPhysPrimScale;
  3461. if (scale.Y > WSModule.MaximumPhysPrimScale)
  3462. scale.Y = WSModule.MaximumPhysPrimScale;
  3463. if (scale.Z > WSModule.MaximumPhysPrimScale)
  3464. scale.Z = WSModule.MaximumPhysPrimScale;
  3465. }
  3466. if (WSModule.MaximumPrimScale != -1)
  3467. {
  3468. if (scale.X > WSModule.MaximumPrimScale)
  3469. scale.X = WSModule.MaximumPrimScale;
  3470. if (scale.Y > WSModule.MaximumPrimScale)
  3471. scale.Y = WSModule.MaximumPrimScale;
  3472. if (scale.Z > WSModule.MaximumPrimScale)
  3473. scale.Z = WSModule.MaximumPrimScale;
  3474. }
  3475. }
  3476. float x = (scale.X/part.Scale.X);
  3477. float y = (scale.Y/part.Scale.Y);
  3478. float z = (scale.Z/part.Scale.Z);
  3479. foreach (SceneObjectPart obPart in m_partsList)
  3480. {
  3481. obPart.StoreUndoState();
  3482. }
  3483. Vector3 prevScale = part.Scale;
  3484. prevScale.X *= x;
  3485. prevScale.Y *= y;
  3486. prevScale.Z *= z;
  3487. part.Resize(prevScale);
  3488. #if (!ISWIN)
  3489. foreach (SceneObjectPart obPart in m_partsList)
  3490. {
  3491. if (obPart.UUID != m_rootPart.UUID)
  3492. {
  3493. obPart.IgnoreUndoUpdate = true;
  3494. Vector3 currentpos = new Vector3(obPart.OffsetPosition);
  3495. currentpos.X *= x;
  3496. currentpos.Y *= y;
  3497. currentpos.Z *= z;
  3498. Vector3 newSize = new Vector3(obPart.Scale);
  3499. newSize.X *= x;
  3500. newSize.Y *= y;
  3501. newSize.Z *= z;
  3502. obPart.Resize(newSize);
  3503. obPart.UpdateOffSet(currentpos);
  3504. obPart.IgnoreUndoUpdate = false;
  3505. }
  3506. }
  3507. #else
  3508. foreach (SceneObjectPart obPart in m_partsList.Where(obPart => obPart.UUID != m_rootPart.UUID))
  3509. {
  3510. obPart.IgnoreUndoUpdate = true;
  3511. Vector3 currentpos = new Vector3(obPart.OffsetPosition);
  3512. currentpos.X *= x;
  3513. currentpos.Y *= y;
  3514. currentpos.Z *= z;
  3515. Vector3 newSize = new Vector3(obPart.Scale);
  3516. newSize.X *= x;
  3517. newSize.Y *= y;
  3518. newSize.Z *= z;
  3519. obPart.Resize(newSize);
  3520. obPart.UpdateOffSet(currentpos);
  3521. obPart.IgnoreUndoUpdate = false;
  3522. }
  3523. #endif
  3524. if (part.PhysActor != null)
  3525. part.PhysActor.Size = prevScale;
  3526. part.IgnoreUndoUpdate = false;
  3527. m_rootPart.IgnoreUndoUpdate = false;
  3528. HasGroupChanged = true;
  3529. ScheduleGroupTerseUpdate();
  3530. m_ValidgrpOOB = false;
  3531. }
  3532. }
  3533. #endregion
  3534. #region Position
  3535. private Vector3 m_lastSigInfiniteRegionPos = Vector3.Zero;
  3536. private List<GridRegion> m_nearbyInfiniteRegions = new List<GridRegion>();
  3537. /// <summary>
  3538. /// Move this scene object
  3539. /// </summary>
  3540. /// <param name="pos"></param>
  3541. /// <param name="SaveUpdate"></param>
  3542. public void UpdateGroupPosition(Vector3 pos, bool SaveUpdate)
  3543. {
  3544. if (SaveUpdate)
  3545. {
  3546. foreach (SceneObjectPart part in ChildrenList)
  3547. {
  3548. part.StoreUndoState();
  3549. }
  3550. }
  3551. if (m_scene.EventManager.TriggerGroupMove(UUID, pos))
  3552. {
  3553. if (IsAttachment)
  3554. {
  3555. m_rootPart.AttachedPos = pos;
  3556. }
  3557. if (RootPart.GetStatusSandbox())
  3558. {
  3559. if (Util.GetDistanceTo(RootPart.StatusSandboxPos, pos) > 10)
  3560. {
  3561. ScriptSetPhysicsStatus(false);
  3562. pos = AbsolutePosition;
  3563. IChatModule chatModule = Scene.RequestModuleInterface<IChatModule>();
  3564. if (chatModule != null)
  3565. chatModule.SimChat("Hit Sandbox Limit", ChatTypeEnum.DebugChannel, 0x7FFFFFFF,
  3566. RootPart.AbsolutePosition, Name, UUID, false, Scene);
  3567. }
  3568. }
  3569. AbsolutePosition = pos;
  3570. HasGroupChanged = true;
  3571. }
  3572. //we need to do a terse update even if the move wasn't allowed
  3573. // so that the position is reset in the client (the object snaps back)
  3574. ScheduleGroupTerseUpdate();
  3575. if (SitTargetAvatar.Count != 0)
  3576. {
  3577. foreach (UUID clientID in SitTargetAvatar)
  3578. {
  3579. //Send full updates to the avatar as well so that they move as well
  3580. IScenePresence SP;
  3581. if (m_scene.TryGetScenePresence(clientID, out SP))
  3582. {
  3583. SP.ParentPosition = AbsolutePosition;
  3584. SP.SendTerseUpdateToAllClients();
  3585. }
  3586. }
  3587. }
  3588. }
  3589. public void SetAbsolutePosition(bool UpdatePrimActor, Vector3 val)
  3590. {
  3591. if (!IsAttachment && RootPart != null && RootPart.Shape != null && Scene != null && Scene.RegionInfo != null &&
  3592. RootPart.Shape.State == 0 && !IsDeleted)
  3593. {
  3594. IBackupModule backup = Scene.RequestModuleInterface<IBackupModule>();
  3595. if ((val.X < 0f || val.Y < 0f || val.Z < 0f ||
  3596. val.X > Scene.RegionInfo.RegionSizeX || val.Y > Scene.RegionInfo.RegionSizeY)
  3597. && !IsAttachmentCheckFull() && (backup != null && !backup.LoadingPrims))
  3598. //Don't do it when backup is loading prims, otherwise it lags the region out
  3599. {
  3600. if (Scene.RegionInfo.InfiniteRegion && !IsInTransit)
  3601. {
  3602. IsInTransit = true;
  3603. double TargetX = Scene.RegionInfo.RegionLocX + (double) val.X;
  3604. double TargetY = Scene.RegionInfo.RegionLocY + (double) val.Y;
  3605. if (m_lastSigInfiniteRegionPos.X - AbsolutePosition.X > 256 ||
  3606. m_lastSigInfiniteRegionPos.X - AbsolutePosition.X < -256 ||
  3607. m_lastSigInfiniteRegionPos.Y - AbsolutePosition.Y > 256 ||
  3608. m_lastSigInfiniteRegionPos.Y - AbsolutePosition.Y < -256)
  3609. {
  3610. m_lastSigInfiniteRegionPos = AbsolutePosition;
  3611. m_nearbyInfiniteRegions = Scene.GridService.GetRegionRange(null,
  3612. (int)
  3613. (TargetX -
  3614. Scene.GridService
  3615. .GetMaxRegionSize()),
  3616. (int) (TargetX + 256),
  3617. (int)
  3618. (TargetY -
  3619. Scene.GridService
  3620. .GetMaxRegionSize()),
  3621. (int) (TargetY + 256));
  3622. }
  3623. #if (!ISWIN)
  3624. GridRegion neighborRegion = null;
  3625. foreach (GridRegion region in m_nearbyInfiniteRegions)
  3626. {
  3627. if (TargetX >= region.RegionLocX && TargetY >= region.RegionLocY && TargetX < (region.RegionLocX + region.RegionSizeX) && TargetY < (region.RegionLocY + region.RegionSizeY))
  3628. {
  3629. neighborRegion = region;
  3630. break;
  3631. }
  3632. }
  3633. #else
  3634. GridRegion neighborRegion =
  3635. m_nearbyInfiniteRegions.FirstOrDefault(
  3636. region =>
  3637. TargetX >= region.RegionLocX && TargetY >= region.RegionLocY &&
  3638. TargetX < (region.RegionLocX + region.RegionSizeX) &&
  3639. TargetY < (region.RegionLocY + region.RegionSizeY));
  3640. #endif
  3641. if (neighborRegion != null)
  3642. {
  3643. //Fix the location that the prim will land
  3644. if (val.X < 0)
  3645. val.X += neighborRegion.RegionSizeX;
  3646. if (val.X > Scene.RegionInfo.RegionSizeX)
  3647. val.X -= Scene.RegionInfo.RegionSizeX;
  3648. if (val.Y < 0)
  3649. val.Y += neighborRegion.RegionSizeY;
  3650. if (val.Y > Scene.RegionInfo.RegionSizeY)
  3651. val.Y -= Scene.RegionInfo.RegionSizeY;
  3652. IEntityTransferModule transferModule = Scene.RequestModuleInterface<IEntityTransferModule>();
  3653. if (transferModule != null)
  3654. {
  3655. if (transferModule.CrossGroupToNewRegion(this, val, neighborRegion))
  3656. {
  3657. IsInTransit = false;
  3658. return;
  3659. }
  3660. }
  3661. }
  3662. IsInTransit = false;
  3663. return;
  3664. }
  3665. //If we are headed out of the region, make sure we have a region there
  3666. IGridRegisterModule neighborService = Scene.RequestModuleInterface<IGridRegisterModule>();
  3667. if (neighborService != null && !IsInTransit)
  3668. {
  3669. IsInTransit = true;
  3670. List<GridRegion> neighbors = neighborService.GetNeighbors(Scene);
  3671. int RegionCrossX = Scene.RegionInfo.RegionLocX;
  3672. int RegionCrossY = Scene.RegionInfo.RegionLocY;
  3673. if (val.X < 0f)
  3674. RegionCrossX -= Constants.RegionSize;
  3675. if (val.Y < 0f)
  3676. RegionCrossY -= Constants.RegionSize;
  3677. if (val.X > Scene.RegionInfo.RegionSizeX)
  3678. RegionCrossX += Scene.RegionInfo.RegionSizeX;
  3679. if (val.Y > Scene.RegionInfo.RegionSizeY)
  3680. RegionCrossY += Scene.RegionInfo.RegionSizeY;
  3681. GridRegion neighborRegion =
  3682. neighbors.FirstOrDefault(
  3683. region => region.RegionLocX == RegionCrossX && region.RegionLocY == RegionCrossY);
  3684. if (neighborRegion != null)
  3685. {
  3686. //Fix the location that the prim will land
  3687. if (val.X < 0)
  3688. val.X += neighborRegion.RegionSizeX;
  3689. if (val.X > Scene.RegionInfo.RegionSizeX)
  3690. val.X -= Scene.RegionInfo.RegionSizeX;
  3691. if (val.Y < 0)
  3692. val.Y += neighborRegion.RegionSizeY;
  3693. if (val.Y > Scene.RegionInfo.RegionSizeY)
  3694. val.Y -= Scene.RegionInfo.RegionSizeY;
  3695. IEntityTransferModule transferModule =
  3696. Scene.RequestModuleInterface<IEntityTransferModule>();
  3697. if (transferModule != null)
  3698. {
  3699. if (transferModule.CrossGroupToNewRegion(this, val, neighborRegion))
  3700. {
  3701. IsInTransit = false;
  3702. return;
  3703. }
  3704. }
  3705. }
  3706. IsInTransit = false;
  3707. //The group should have crossed a region, but no region was found so return it instead
  3708. MainConsole.Instance.Info("[SceneObjectGroup]: Returning prim " + Name + " @ " +
  3709. AbsolutePosition +
  3710. " because it has gone out of bounds.");
  3711. ILLClientInventory inventoryModule = Scene.RequestModuleInterface<ILLClientInventory>();
  3712. if (inventoryModule != null)
  3713. inventoryModule.ReturnObjects(new ISceneEntity[] {this}, UUID.Zero);
  3714. return;
  3715. }
  3716. }
  3717. }
  3718. if (RootPart != null && RootPart.GetStatusSandbox())
  3719. {
  3720. if (Util.GetDistanceTo(RootPart.StatusSandboxPos, val) > 10)
  3721. {
  3722. ScriptSetPhysicsStatus(false);
  3723. if (Scene != null)
  3724. {
  3725. IChatModule chatModule = Scene.RequestModuleInterface<IChatModule>();
  3726. if (chatModule != null)
  3727. chatModule.SimChat("Hit Sandbox Limit",
  3728. ChatTypeEnum.DebugChannel, 0x7FFFFFFF, RootPart.AbsolutePosition, Name,
  3729. UUID,
  3730. false, Scene);
  3731. }
  3732. return;
  3733. }
  3734. }
  3735. foreach (SceneObjectPart part in m_partsList)
  3736. {
  3737. part.FixGroupPositionComum(UpdatePrimActor, val, false);
  3738. }
  3739. //if (m_rootPart.PhysActor != null)
  3740. //{
  3741. //m_rootPart.PhysActor.Position =
  3742. //new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y,
  3743. //m_rootPart.GroupPosition.Z);
  3744. //m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
  3745. //}
  3746. }
  3747. /// <summary>
  3748. /// Update the position of a single part of this scene object
  3749. /// </summary>
  3750. /// <param name="pos"></param>
  3751. /// <param name="localID"></param>
  3752. /// <param name="SaveUpdate"></param>
  3753. public void UpdateSinglePosition(Vector3 pos, uint localID, bool SaveUpdate)
  3754. {
  3755. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3756. if (part != null)
  3757. {
  3758. if (!SaveUpdate)
  3759. part.IgnoreUndoUpdate = true;
  3760. if (part.UUID == m_rootPart.UUID)
  3761. {
  3762. UpdateRootPosition(pos);
  3763. }
  3764. else
  3765. {
  3766. part.UpdateOffSet(pos);
  3767. }
  3768. if (!SaveUpdate)
  3769. part.IgnoreUndoUpdate = false;
  3770. HasGroupChanged = true;
  3771. }
  3772. }
  3773. /// <summary>
  3774. /// </summary>
  3775. /// <param name="pos"></param>
  3776. public void UpdateRootPosition(Vector3 pos)
  3777. {
  3778. foreach (SceneObjectPart part in ChildrenList)
  3779. {
  3780. part.StoreUndoState();
  3781. }
  3782. Vector3 newPos = new Vector3(pos.X, pos.Y, pos.Z);
  3783. Vector3 oldPos =
  3784. IsAttachment
  3785. ? new Vector3(m_rootPart.OffsetPosition.X, m_rootPart.OffsetPosition.Y,
  3786. m_rootPart.OffsetPosition.Z)
  3787. : new Vector3(AbsolutePosition.X + m_rootPart.OffsetPosition.X,
  3788. AbsolutePosition.Y + m_rootPart.OffsetPosition.Y,
  3789. AbsolutePosition.Z + m_rootPart.OffsetPosition.Z);
  3790. Vector3 diff = oldPos - newPos;
  3791. Vector3 axDiff = new Vector3(diff.X, diff.Y, diff.Z);
  3792. Quaternion partRotation = m_rootPart.GetRotationOffset();
  3793. axDiff *= Quaternion.Inverse(partRotation);
  3794. diff = axDiff;
  3795. if (IsAttachment)
  3796. {
  3797. m_rootPart.FixOffsetPosition((newPos), false);
  3798. foreach (SceneObjectPart obPart in m_partsList)
  3799. {
  3800. if (obPart.UUID != m_rootPart.UUID)
  3801. {
  3802. obPart.OffsetPosition += diff;
  3803. obPart.SetGroupPosition(AbsolutePosition);
  3804. }
  3805. }
  3806. }
  3807. else
  3808. {
  3809. foreach (SceneObjectPart obPart in m_partsList)
  3810. {
  3811. if (obPart.UUID != m_rootPart.UUID)
  3812. obPart.FixOffsetPosition((obPart.OffsetPosition + diff), false);
  3813. }
  3814. AbsolutePosition = newPos;
  3815. }
  3816. HasGroupChanged = true;
  3817. ScheduleGroupTerseUpdate();
  3818. }
  3819. public void OffsetForNewRegion(Vector3 offset)
  3820. {
  3821. m_rootPart.FixGroupPosition(offset, false);
  3822. }
  3823. #endregion
  3824. #region Rotation
  3825. /// <summary>
  3826. /// </summary>
  3827. /// <param name="rot"></param>
  3828. public void UpdateGroupRotationR(Quaternion rot)
  3829. {
  3830. foreach (SceneObjectPart parts in ChildrenList)
  3831. {
  3832. parts.StoreUndoState();
  3833. }
  3834. m_rootPart.UpdateRotation(rot);
  3835. PhysicsObject actor = m_rootPart.PhysActor;
  3836. if (actor != null)
  3837. actor.Orientation = m_rootPart.GetRotationOffset();
  3838. HasGroupChanged = true;
  3839. ScheduleGroupTerseUpdate();
  3840. }
  3841. /// <summary>
  3842. /// </summary>
  3843. /// <param name="pos"></param>
  3844. /// <param name="rot"></param>
  3845. public void UpdateGroupRotationPR(Vector3 pos, Quaternion rot)
  3846. {
  3847. foreach (SceneObjectPart part in ChildrenList)
  3848. {
  3849. part.StoreUndoState();
  3850. }
  3851. m_rootPart.UpdateRotation(rot);
  3852. PhysicsObject actor = m_rootPart.PhysActor;
  3853. if (actor != null)
  3854. actor.Orientation = m_rootPart.GetRotationOffset();
  3855. AbsolutePosition = pos;
  3856. HasGroupChanged = true;
  3857. ScheduleGroupTerseUpdate();
  3858. }
  3859. /// <summary>
  3860. /// </summary>
  3861. /// <param name="rot"></param>
  3862. /// <param name="localID"></param>
  3863. public void UpdateSingleRotation(Quaternion rot, uint localID)
  3864. {
  3865. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3866. foreach (SceneObjectPart parts in ChildrenList)
  3867. {
  3868. parts.StoreUndoState();
  3869. }
  3870. if (part != null)
  3871. {
  3872. if (part.UUID == m_rootPart.UUID)
  3873. {
  3874. UpdateRootRotation(rot);
  3875. }
  3876. else
  3877. {
  3878. part.UpdateRotation(rot);
  3879. }
  3880. }
  3881. }
  3882. /// <summary>
  3883. /// </summary>
  3884. /// <param name="rot"></param>
  3885. /// <param name="pos"></param>
  3886. /// <param name="localID"></param>
  3887. public void UpdateSingleRotation(Quaternion rot, Vector3 pos, uint localID)
  3888. {
  3889. SceneObjectPart part = (SceneObjectPart) GetChildPart(localID);
  3890. if (part != null)
  3891. {
  3892. if (part.UUID == m_rootPart.UUID)
  3893. {
  3894. UpdateRootRotation(rot);
  3895. AbsolutePosition = pos;
  3896. }
  3897. else
  3898. {
  3899. part.StoreUndoState();
  3900. part.IgnoreUndoUpdate = true;
  3901. part.UpdateRotation(rot);
  3902. part.FixOffsetPosition(pos, true);
  3903. part.IgnoreUndoUpdate = false;
  3904. }
  3905. }
  3906. }
  3907. /// <summary>
  3908. /// </summary>
  3909. /// <param name="rot"></param>
  3910. private void UpdateRootRotation(Quaternion rot)
  3911. {
  3912. Quaternion new_global_group_rot = rot;
  3913. Quaternion old_global_group_rot = m_rootPart.GetRotationOffset();
  3914. m_rootPart.UpdateRotation(rot);
  3915. if (m_rootPart.PhysActor != null)
  3916. m_rootPart.PhysActor.Orientation = m_rootPart.GetRotationOffset();
  3917. #if (!ISWIN)
  3918. foreach (SceneObjectPart childPrim in m_partsList)
  3919. {
  3920. if (childPrim.UUID != m_rootPart.UUID)
  3921. {
  3922. childPrim.StoreUndoState();
  3923. childPrim.IgnoreUndoUpdate = true;
  3924. // fix rotation
  3925. // get in world coords
  3926. Quaternion primsRot = old_global_group_rot*childPrim.RotationOffset;
  3927. // set new offset as inverse of the one on root
  3928. // so world is right
  3929. primsRot = Quaternion.Inverse(new_global_group_rot)*primsRot;
  3930. // just store it
  3931. childPrim.SetRotationOffset(false, primsRot, false);
  3932. // fix position offset
  3933. Vector3 axPos = childPrim.OffsetPosition;
  3934. axPos *= old_global_group_rot;
  3935. axPos *= Quaternion.Inverse(new_global_group_rot);
  3936. // store it and let physics know about both changes
  3937. childPrim.FixOffsetPosition(axPos, true);
  3938. childPrim.ScheduleTerseUpdate();
  3939. childPrim.IgnoreUndoUpdate = false;
  3940. }
  3941. }
  3942. #else
  3943. foreach (SceneObjectPart childPrim in m_partsList.Where(childPrim => childPrim.UUID != m_rootPart.UUID))
  3944. {
  3945. childPrim.StoreUndoState();
  3946. childPrim.IgnoreUndoUpdate = true;
  3947. // fix rotation
  3948. // get in world coords
  3949. Quaternion primsRot = old_global_group_rot*childPrim.GetRotationOffset();
  3950. // set new offset as inverse of the one on root
  3951. // so world is right
  3952. primsRot = Quaternion.Inverse(new_global_group_rot)*primsRot;
  3953. // just store it
  3954. childPrim.SetRotationOffset(false, primsRot, false);
  3955. // fix position offset
  3956. Vector3 axPos = childPrim.OffsetPosition;
  3957. axPos *= old_global_group_rot;
  3958. axPos *= Quaternion.Inverse(new_global_group_rot);
  3959. // store it and let physics know about both changes
  3960. childPrim.FixOffsetPosition(axPos, true);
  3961. childPrim.ScheduleTerseUpdate();
  3962. childPrim.IgnoreUndoUpdate = false;
  3963. }
  3964. #endif
  3965. m_rootPart.ScheduleTerseUpdate();
  3966. }
  3967. #endregion
  3968. }
  3969. }