SOPObject.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Security;
  30. using OpenMetaverse;
  31. using OpenMetaverse.Packets;
  32. using OpenSim.Framework;
  33. using OpenSim.Region.Framework.Scenes;
  34. using OpenSim.Region.OptionalModules.Scripting.Minimodule.Object;
  35. using OpenSim.Region.Physics.Manager;
  36. using PrimType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.PrimType;
  37. using SculptType=OpenSim.Region.OptionalModules.Scripting.Minimodule.Object.SculptType;
  38. namespace OpenSim.Region.OptionalModules.Scripting.Minimodule
  39. {
  40. class SOPObject : MarshalByRefObject, IObject, IObjectPhysics, IObjectShape, IObjectSound
  41. {
  42. private readonly Scene m_rootScene;
  43. private readonly uint m_localID;
  44. private readonly ISecurityCredential m_security;
  45. [Obsolete("Replace with 'credential' constructor [security]")]
  46. public SOPObject(Scene rootScene, uint localID)
  47. {
  48. m_rootScene = rootScene;
  49. m_localID = localID;
  50. }
  51. public SOPObject(Scene rootScene, uint localID, ISecurityCredential credential)
  52. {
  53. m_rootScene = rootScene;
  54. m_localID = localID;
  55. m_security = credential;
  56. }
  57. /// <summary>
  58. /// This needs to run very, very quickly.
  59. /// It is utilized in nearly every property and method.
  60. /// </summary>
  61. /// <returns></returns>
  62. private SceneObjectPart GetSOP()
  63. {
  64. return m_rootScene.GetSceneObjectPart(m_localID);
  65. }
  66. private bool CanEdit()
  67. {
  68. if (!m_security.CanEditObject(this))
  69. {
  70. throw new SecurityException("Insufficient Permission to edit object with UUID [" + GetSOP().UUID + "]");
  71. }
  72. return true;
  73. }
  74. #region OnTouch
  75. private event OnTouchDelegate _OnTouch;
  76. private bool _OnTouchActive = false;
  77. public event OnTouchDelegate OnTouch
  78. {
  79. add
  80. {
  81. if (CanEdit())
  82. {
  83. if (!_OnTouchActive)
  84. {
  85. GetSOP().Flags |= PrimFlags.Touch;
  86. _OnTouchActive = true;
  87. m_rootScene.EventManager.OnObjectGrab += EventManager_OnObjectGrab;
  88. }
  89. _OnTouch += value;
  90. }
  91. }
  92. remove
  93. {
  94. _OnTouch -= value;
  95. if (_OnTouch == null)
  96. {
  97. GetSOP().Flags &= ~PrimFlags.Touch;
  98. _OnTouchActive = false;
  99. m_rootScene.EventManager.OnObjectGrab -= EventManager_OnObjectGrab;
  100. }
  101. }
  102. }
  103. void EventManager_OnObjectGrab(uint localID, uint originalID, Vector3 offsetPos, IClientAPI remoteClient, SurfaceTouchEventArgs surfaceArgs)
  104. {
  105. if (_OnTouchActive && m_localID == localID)
  106. {
  107. TouchEventArgs e = new TouchEventArgs();
  108. e.Avatar = new SPAvatar(m_rootScene, remoteClient.AgentId, m_security);
  109. e.TouchBiNormal = surfaceArgs.Binormal;
  110. e.TouchMaterialIndex = surfaceArgs.FaceIndex;
  111. e.TouchNormal = surfaceArgs.Normal;
  112. e.TouchPosition = surfaceArgs.Position;
  113. e.TouchST = new Vector2(surfaceArgs.STCoord.X, surfaceArgs.STCoord.Y);
  114. e.TouchUV = new Vector2(surfaceArgs.UVCoord.X, surfaceArgs.UVCoord.Y);
  115. IObject sender = this;
  116. if (_OnTouch != null)
  117. _OnTouch(sender, e);
  118. }
  119. }
  120. #endregion
  121. public bool Exists
  122. {
  123. get { return GetSOP() != null; }
  124. }
  125. public uint LocalID
  126. {
  127. get { return m_localID; }
  128. }
  129. public UUID GlobalID
  130. {
  131. get { return GetSOP().UUID; }
  132. }
  133. public string Name
  134. {
  135. get { return GetSOP().Name; }
  136. set
  137. {
  138. if (CanEdit())
  139. GetSOP().Name = value;
  140. }
  141. }
  142. public string Description
  143. {
  144. get { return GetSOP().Description; }
  145. set
  146. {
  147. if (CanEdit())
  148. GetSOP().Description = value;
  149. }
  150. }
  151. public IObject[] Children
  152. {
  153. get
  154. {
  155. SceneObjectPart my = GetSOP();
  156. int total = my.ParentGroup.Children.Count;
  157. IObject[] rets = new IObject[total];
  158. int i = 0;
  159. foreach (KeyValuePair<UUID, SceneObjectPart> pair in my.ParentGroup.Children)
  160. {
  161. rets[i++] = new SOPObject(m_rootScene, pair.Value.LocalId, m_security);
  162. }
  163. return rets;
  164. }
  165. }
  166. public IObject Root
  167. {
  168. get { return new SOPObject(m_rootScene, GetSOP().ParentGroup.RootPart.LocalId, m_security); }
  169. }
  170. public IObjectMaterial[] Materials
  171. {
  172. get
  173. {
  174. SceneObjectPart sop = GetSOP();
  175. IObjectMaterial[] rets = new IObjectMaterial[getNumberOfSides(sop)];
  176. for (int i = 0; i < rets.Length; i++)
  177. {
  178. rets[i] = new SOPObjectMaterial(i, sop);
  179. }
  180. return rets;
  181. }
  182. }
  183. public Vector3 Scale
  184. {
  185. get { return GetSOP().Scale; }
  186. set
  187. {
  188. if (CanEdit())
  189. GetSOP().Scale = value;
  190. }
  191. }
  192. public Quaternion WorldRotation
  193. {
  194. get { throw new System.NotImplementedException(); }
  195. set { throw new System.NotImplementedException(); }
  196. }
  197. public Quaternion OffsetRotation
  198. {
  199. get { throw new System.NotImplementedException(); }
  200. set { throw new System.NotImplementedException(); }
  201. }
  202. public Vector3 WorldPosition
  203. {
  204. get { return GetSOP().AbsolutePosition; }
  205. set
  206. {
  207. if (CanEdit())
  208. {
  209. SceneObjectPart pos = GetSOP();
  210. pos.UpdateOffSet(value - pos.AbsolutePosition);
  211. }
  212. }
  213. }
  214. public Vector3 OffsetPosition
  215. {
  216. get { return GetSOP().OffsetPosition; }
  217. set
  218. {
  219. if (CanEdit())
  220. {
  221. GetSOP().OffsetPosition = value;
  222. }
  223. }
  224. }
  225. public Vector3 SitTarget
  226. {
  227. get { throw new System.NotImplementedException(); }
  228. set { throw new System.NotImplementedException(); }
  229. }
  230. public string SitTargetText
  231. {
  232. get { throw new System.NotImplementedException(); }
  233. set { throw new System.NotImplementedException(); }
  234. }
  235. public string TouchText
  236. {
  237. get { throw new System.NotImplementedException(); }
  238. set { throw new System.NotImplementedException(); }
  239. }
  240. public string Text
  241. {
  242. get { throw new System.NotImplementedException(); }
  243. set { throw new System.NotImplementedException(); }
  244. }
  245. public bool IsRotationLockedX
  246. {
  247. get { throw new System.NotImplementedException(); }
  248. set { throw new System.NotImplementedException(); }
  249. }
  250. public bool IsRotationLockedY
  251. {
  252. get { throw new System.NotImplementedException(); }
  253. set { throw new System.NotImplementedException(); }
  254. }
  255. public bool IsRotationLockedZ
  256. {
  257. get { throw new System.NotImplementedException(); }
  258. set { throw new System.NotImplementedException(); }
  259. }
  260. public bool IsSandboxed
  261. {
  262. get { throw new System.NotImplementedException(); }
  263. set { throw new System.NotImplementedException(); }
  264. }
  265. public bool IsImmotile
  266. {
  267. get { throw new System.NotImplementedException(); }
  268. set { throw new System.NotImplementedException(); }
  269. }
  270. public bool IsAlwaysReturned
  271. {
  272. get { throw new System.NotImplementedException(); }
  273. set { throw new System.NotImplementedException(); }
  274. }
  275. public bool IsTemporary
  276. {
  277. get { throw new System.NotImplementedException(); }
  278. set { throw new System.NotImplementedException(); }
  279. }
  280. public bool IsFlexible
  281. {
  282. get { throw new System.NotImplementedException(); }
  283. set { throw new System.NotImplementedException(); }
  284. }
  285. public PhysicsMaterial PhysicsMaterial
  286. {
  287. get { throw new System.NotImplementedException(); }
  288. set { throw new System.NotImplementedException(); }
  289. }
  290. public IObjectPhysics Physics
  291. {
  292. get { return this; }
  293. }
  294. public IObjectShape Shape
  295. {
  296. get { return this; }
  297. }
  298. public IObjectInventory Inventory
  299. {
  300. get { return new SOPObjectInventory(m_rootScene, GetSOP().TaskInventory); }
  301. }
  302. #region Public Functions
  303. public void Say(string msg)
  304. {
  305. if (!CanEdit())
  306. return;
  307. SceneObjectPart sop = GetSOP();
  308. m_rootScene.SimChat(msg, ChatTypeEnum.Say, sop.AbsolutePosition, sop.Name, sop.UUID, false);
  309. }
  310. #endregion
  311. #region Supporting Functions
  312. // Helper functions to understand if object has cut, hollow, dimple, and other affecting number of faces
  313. private static void hasCutHollowDimpleProfileCut(int primType, PrimitiveBaseShape shape, out bool hasCut, out bool hasHollow,
  314. out bool hasDimple, out bool hasProfileCut)
  315. {
  316. if (primType == (int)PrimType.Box
  317. ||
  318. primType == (int)PrimType.Cylinder
  319. ||
  320. primType == (int)PrimType.Prism)
  321. hasCut = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0);
  322. else
  323. hasCut = (shape.PathBegin > 0) || (shape.PathEnd > 0);
  324. hasHollow = shape.ProfileHollow > 0;
  325. hasDimple = (shape.ProfileBegin > 0) || (shape.ProfileEnd > 0); // taken from llSetPrimitiveParms
  326. hasProfileCut = hasDimple; // is it the same thing?
  327. }
  328. private static int getScriptPrimType(PrimitiveBaseShape primShape)
  329. {
  330. if (primShape.SculptEntry)
  331. return (int) PrimType.Sculpt;
  332. if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.Square)
  333. {
  334. if (primShape.PathCurve == (byte) Extrusion.Straight)
  335. return (int) PrimType.Box;
  336. if (primShape.PathCurve == (byte) Extrusion.Curve1)
  337. return (int) PrimType.Tube;
  338. }
  339. else if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.Circle)
  340. {
  341. if (primShape.PathCurve == (byte) Extrusion.Straight)
  342. return (int) PrimType.Cylinder;
  343. if (primShape.PathCurve == (byte) Extrusion.Curve1)
  344. return (int) PrimType.Torus;
  345. }
  346. else if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.HalfCircle)
  347. {
  348. if (primShape.PathCurve == (byte) Extrusion.Curve1 || primShape.PathCurve == (byte) Extrusion.Curve2)
  349. return (int) PrimType.Sphere;
  350. }
  351. else if ((primShape.ProfileCurve & 0x07) == (byte) ProfileShape.EquilateralTriangle)
  352. {
  353. if (primShape.PathCurve == (byte) Extrusion.Straight)
  354. return (int) PrimType.Prism;
  355. if (primShape.PathCurve == (byte) Extrusion.Curve1)
  356. return (int) PrimType.Ring;
  357. }
  358. return (int) PrimType.NotPrimitive;
  359. }
  360. private static int getNumberOfSides(SceneObjectPart part)
  361. {
  362. int ret;
  363. bool hasCut;
  364. bool hasHollow;
  365. bool hasDimple;
  366. bool hasProfileCut;
  367. int primType = getScriptPrimType(part.Shape);
  368. hasCutHollowDimpleProfileCut(primType, part.Shape, out hasCut, out hasHollow, out hasDimple, out hasProfileCut);
  369. switch (primType)
  370. {
  371. default:
  372. case (int) PrimType.Box:
  373. ret = 6;
  374. if (hasCut) ret += 2;
  375. if (hasHollow) ret += 1;
  376. break;
  377. case (int) PrimType.Cylinder:
  378. ret = 3;
  379. if (hasCut) ret += 2;
  380. if (hasHollow) ret += 1;
  381. break;
  382. case (int) PrimType.Prism:
  383. ret = 5;
  384. if (hasCut) ret += 2;
  385. if (hasHollow) ret += 1;
  386. break;
  387. case (int) PrimType.Sphere:
  388. ret = 1;
  389. if (hasCut) ret += 2;
  390. if (hasDimple) ret += 2;
  391. if (hasHollow)
  392. ret += 1; // GOTCHA: LSL shows 2 additional sides here.
  393. // This has been fixed, but may cause porting issues.
  394. break;
  395. case (int) PrimType.Torus:
  396. ret = 1;
  397. if (hasCut) ret += 2;
  398. if (hasProfileCut) ret += 2;
  399. if (hasHollow) ret += 1;
  400. break;
  401. case (int) PrimType.Tube:
  402. ret = 4;
  403. if (hasCut) ret += 2;
  404. if (hasProfileCut) ret += 2;
  405. if (hasHollow) ret += 1;
  406. break;
  407. case (int) PrimType.Ring:
  408. ret = 3;
  409. if (hasCut) ret += 2;
  410. if (hasProfileCut) ret += 2;
  411. if (hasHollow) ret += 1;
  412. break;
  413. case (int) PrimType.Sculpt:
  414. ret = 1;
  415. break;
  416. }
  417. return ret;
  418. }
  419. #endregion
  420. #region IObjectPhysics
  421. public bool Enabled
  422. {
  423. get { throw new System.NotImplementedException(); }
  424. set { throw new System.NotImplementedException(); }
  425. }
  426. public bool Phantom
  427. {
  428. get { throw new System.NotImplementedException(); }
  429. set { throw new System.NotImplementedException(); }
  430. }
  431. public bool PhantomCollisions
  432. {
  433. get { throw new System.NotImplementedException(); }
  434. set { throw new System.NotImplementedException(); }
  435. }
  436. public double Density
  437. {
  438. get { return (GetSOP().PhysActor.Mass/Scale.X*Scale.Y/Scale.Z); }
  439. set { throw new NotImplementedException(); }
  440. }
  441. public double Mass
  442. {
  443. get { return GetSOP().PhysActor.Mass; }
  444. set { throw new NotImplementedException(); }
  445. }
  446. public double Buoyancy
  447. {
  448. get { return GetSOP().PhysActor.Buoyancy; }
  449. set { GetSOP().PhysActor.Buoyancy = (float)value; }
  450. }
  451. public Vector3 GeometricCenter
  452. {
  453. get
  454. {
  455. PhysicsVector tmp = GetSOP().PhysActor.GeometricCenter;
  456. return new Vector3(tmp.X, tmp.Y, tmp.Z);
  457. }
  458. }
  459. public Vector3 CenterOfMass
  460. {
  461. get
  462. {
  463. PhysicsVector tmp = GetSOP().PhysActor.CenterOfMass;
  464. return new Vector3(tmp.X, tmp.Y, tmp.Z);
  465. }
  466. }
  467. public Vector3 RotationalVelocity
  468. {
  469. get
  470. {
  471. PhysicsVector tmp = GetSOP().PhysActor.RotationalVelocity;
  472. return new Vector3(tmp.X, tmp.Y, tmp.Z);
  473. }
  474. set
  475. {
  476. if (!CanEdit())
  477. return;
  478. GetSOP().PhysActor.RotationalVelocity = new PhysicsVector(value.X, value.Y, value.Z);
  479. }
  480. }
  481. public Vector3 Velocity
  482. {
  483. get
  484. {
  485. PhysicsVector tmp = GetSOP().PhysActor.Velocity;
  486. return new Vector3(tmp.X, tmp.Y, tmp.Z);
  487. }
  488. set
  489. {
  490. if (!CanEdit())
  491. return;
  492. GetSOP().PhysActor.Velocity = new PhysicsVector(value.X, value.Y, value.Z);
  493. }
  494. }
  495. public Vector3 Torque
  496. {
  497. get
  498. {
  499. PhysicsVector tmp = GetSOP().PhysActor.Torque;
  500. return new Vector3(tmp.X, tmp.Y, tmp.Z);
  501. }
  502. set
  503. {
  504. if (!CanEdit())
  505. return;
  506. GetSOP().PhysActor.Torque = new PhysicsVector(value.X, value.Y, value.Z);
  507. }
  508. }
  509. public Vector3 Acceleration
  510. {
  511. get
  512. {
  513. PhysicsVector tmp = GetSOP().PhysActor.Acceleration;
  514. return new Vector3(tmp.X, tmp.Y, tmp.Z);
  515. }
  516. }
  517. public Vector3 Force
  518. {
  519. get
  520. {
  521. PhysicsVector tmp = GetSOP().PhysActor.Force;
  522. return new Vector3(tmp.X, tmp.Y, tmp.Z);
  523. }
  524. set
  525. {
  526. if (!CanEdit())
  527. return;
  528. GetSOP().PhysActor.Force = new PhysicsVector(value.X, value.Y, value.Z);
  529. }
  530. }
  531. public bool FloatOnWater
  532. {
  533. set
  534. {
  535. if (!CanEdit())
  536. return;
  537. GetSOP().PhysActor.FloatOnWater = value;
  538. }
  539. }
  540. public void AddForce(Vector3 force, bool pushforce)
  541. {
  542. if (!CanEdit())
  543. return;
  544. GetSOP().PhysActor.AddForce(new PhysicsVector(force.X, force.Y, force.Z), pushforce);
  545. }
  546. public void AddAngularForce(Vector3 force, bool pushforce)
  547. {
  548. if (!CanEdit())
  549. return;
  550. GetSOP().PhysActor.AddAngularForce(new PhysicsVector(force.X, force.Y, force.Z), pushforce);
  551. }
  552. public void SetMomentum(Vector3 momentum)
  553. {
  554. if (!CanEdit())
  555. return;
  556. GetSOP().PhysActor.SetMomentum(new PhysicsVector(momentum.X, momentum.Y, momentum.Z));
  557. }
  558. #endregion
  559. #region Implementation of IObjectShape
  560. private UUID m_sculptMap = UUID.Zero;
  561. public UUID SculptMap
  562. {
  563. get { return m_sculptMap; }
  564. set
  565. {
  566. if (!CanEdit())
  567. return;
  568. m_sculptMap = value;
  569. SetPrimitiveSculpted(SculptMap, (byte) SculptType);
  570. }
  571. }
  572. private SculptType m_sculptType = Object.SculptType.Default;
  573. public SculptType SculptType
  574. {
  575. get { return m_sculptType; }
  576. set
  577. {
  578. if (!CanEdit())
  579. return;
  580. m_sculptType = value;
  581. SetPrimitiveSculpted(SculptMap, (byte) SculptType);
  582. }
  583. }
  584. public HoleShape HoleType
  585. {
  586. get { throw new System.NotImplementedException(); }
  587. set { throw new System.NotImplementedException(); }
  588. }
  589. public double HoleSize
  590. {
  591. get { throw new System.NotImplementedException(); }
  592. set { throw new System.NotImplementedException(); }
  593. }
  594. public PrimType PrimType
  595. {
  596. get { return (PrimType)getScriptPrimType(GetSOP().Shape); }
  597. set { throw new System.NotImplementedException(); }
  598. }
  599. private void SetPrimitiveSculpted(UUID map, byte type)
  600. {
  601. ObjectShapePacket.ObjectDataBlock shapeBlock = new ObjectShapePacket.ObjectDataBlock();
  602. SceneObjectPart part = GetSOP();
  603. UUID sculptId = map;
  604. shapeBlock.ObjectLocalID = part.LocalId;
  605. shapeBlock.PathScaleX = 100;
  606. shapeBlock.PathScaleY = 150;
  607. // retain pathcurve
  608. shapeBlock.PathCurve = part.Shape.PathCurve;
  609. part.Shape.SetSculptData((byte)type, sculptId);
  610. part.Shape.SculptEntry = true;
  611. part.UpdateShape(shapeBlock);
  612. }
  613. #endregion
  614. #region Implementation of IObjectSound
  615. public IObjectSound Sound
  616. {
  617. get { return this; }
  618. }
  619. public void Play(UUID asset, double volume)
  620. {
  621. if (!CanEdit())
  622. return;
  623. GetSOP().SendSound(asset.ToString(), volume, true, 0);
  624. }
  625. #endregion
  626. }
  627. }