1
0

SceneGraph.cs 82 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254
  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.Threading;
  29. using System.Collections.Generic;
  30. using System.Reflection;
  31. using System.Runtime.CompilerServices;
  32. using OpenMetaverse;
  33. using OpenMetaverse.Packets;
  34. using log4net;
  35. using OpenSim.Framework;
  36. using OpenSim.Region.PhysicsModules.SharedBase;
  37. using System.Runtime.InteropServices;
  38. namespace OpenSim.Region.Framework.Scenes
  39. {
  40. public delegate void PhysicsCrash();
  41. public delegate void AttachToBackupDelegate(SceneObjectGroup sog);
  42. public delegate void DetachFromBackupDelegate(SceneObjectGroup sog);
  43. public delegate void ChangedBackupDelegate(SceneObjectGroup sog);
  44. /// <summary>
  45. /// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
  46. /// should be migrated out over time.
  47. /// </summary>
  48. public class SceneGraph
  49. {
  50. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  51. #region Events
  52. protected internal event PhysicsCrash UnRecoverableError;
  53. public event AttachToBackupDelegate OnAttachToBackup;
  54. public event DetachFromBackupDelegate OnDetachFromBackup;
  55. public event ChangedBackupDelegate OnChangeBackup;
  56. #endregion
  57. #region Fields
  58. protected internal EntityManager Entities = new();
  59. private Dictionary<UUID, SceneObjectPart> m_scenePartsByID = new(1024);
  60. private Dictionary<uint, SceneObjectPart> m_scenePartsByLocalID = new(1024);
  61. private SceneObjectPart[] m_scenePartsArray;
  62. private Dictionary<UUID, ScenePresence> m_scenePresenceMap = new();
  63. private Dictionary<uint, ScenePresence> m_scenePresenceLocalIDMap = new();
  64. private Dictionary<UUID, SceneObjectGroup> m_updateList = new();
  65. private List<ScenePresence> m_scenePresenceList;
  66. private readonly Scene m_parentScene;
  67. private PhysicsScene _PhyScene;
  68. private int m_numRootAgents = 0;
  69. private int m_numChildAgents = 0;
  70. private int m_numRootNPC = 0;
  71. private int m_numPrim = 0;
  72. private int m_numMesh = 0;
  73. private int m_physicalPrim = 0;
  74. private int m_activeScripts = 0;
  75. //private int m_scriptLPS = 0;
  76. /// <summary>
  77. /// Lock to prevent object group update, linking, delinking and duplication operations from running concurrently.
  78. /// </summary>
  79. /// <remarks>
  80. /// These operations rely on the parts composition of the object. If allowed to run concurrently then race
  81. /// conditions can occur.
  82. /// </remarks>
  83. private readonly Object m_updateLock = new();
  84. private readonly Object m_linkLock = new();
  85. private readonly ReaderWriterLockSlim m_scenePresencesLock;
  86. private readonly ReaderWriterLockSlim m_scenePartsLock;
  87. #endregion
  88. protected internal SceneGraph(Scene parent)
  89. {
  90. m_scenePresencesLock = new ReaderWriterLockSlim();
  91. m_scenePartsLock = new ReaderWriterLockSlim();
  92. m_parentScene = parent;
  93. m_scenePresenceList = null;
  94. m_scenePartsArray = null;
  95. }
  96. ~SceneGraph()
  97. {
  98. m_scenePartsLock.Dispose();
  99. m_scenePresencesLock.Dispose();
  100. }
  101. public PhysicsScene PhysicsScene
  102. {
  103. get
  104. {
  105. _PhyScene ??= m_parentScene.RequestModuleInterface<PhysicsScene>();
  106. return _PhyScene;
  107. }
  108. set
  109. {
  110. // If we're not doing the initial set
  111. // Then we've got to remove the previous
  112. // event handler
  113. if (_PhyScene is not null)
  114. _PhyScene.OnPhysicsCrash -= physicsBasedCrash;
  115. _PhyScene = value;
  116. if (_PhyScene is not null)
  117. _PhyScene.OnPhysicsCrash += physicsBasedCrash;
  118. }
  119. }
  120. protected internal void Close()
  121. {
  122. bool entered = false;
  123. try
  124. {
  125. try { }
  126. finally
  127. {
  128. m_scenePresencesLock.EnterWriteLock();
  129. entered = true;
  130. }
  131. m_scenePresenceMap = new Dictionary<UUID, ScenePresence>();
  132. m_scenePresenceLocalIDMap = new Dictionary<uint, ScenePresence>();
  133. m_scenePresenceList = null;
  134. }
  135. finally
  136. {
  137. if (entered)
  138. m_scenePresencesLock.ExitWriteLock();
  139. }
  140. entered = false;
  141. try
  142. {
  143. try { }
  144. finally
  145. {
  146. m_scenePartsLock.EnterWriteLock();
  147. entered = true;
  148. }
  149. Entities.Clear();
  150. m_scenePartsArray = null;
  151. m_scenePartsByID = new Dictionary<UUID, SceneObjectPart>();
  152. m_scenePartsByLocalID = new Dictionary<uint, SceneObjectPart>();
  153. if (_PhyScene is not null)
  154. _PhyScene.OnPhysicsCrash -= physicsBasedCrash;
  155. _PhyScene = null;
  156. }
  157. finally
  158. {
  159. if (entered)
  160. m_scenePartsLock.ExitWriteLock();
  161. }
  162. }
  163. #region Update Methods
  164. protected internal void UpdatePreparePhysics()
  165. {
  166. }
  167. /// <summary>
  168. /// Update the position of all the scene presences.
  169. /// </summary>
  170. /// <remarks>
  171. /// Called only from the main scene loop.
  172. /// </remarks>
  173. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  174. protected internal void UpdatePresences()
  175. {
  176. ForEachScenePresence(delegate(ScenePresence presence)
  177. {
  178. presence.Update();
  179. });
  180. }
  181. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  182. protected internal void UpdateScenePresenceMovement()
  183. {
  184. ForEachScenePresence(delegate (ScenePresence presence)
  185. {
  186. presence.UpdateMovement();
  187. });
  188. }
  189. /// <summary>
  190. /// Perform a physics frame update.
  191. /// </summary>
  192. /// <param name="elapsed"></param>
  193. /// <returns></returns>
  194. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  195. protected internal float UpdatePhysics(double elapsed)
  196. {
  197. return PhysicsScene is null ? 0 : PhysicsScene.Simulate((float)elapsed);
  198. }
  199. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  200. protected internal void ProcessPhysicsPreSimulation()
  201. {
  202. PhysicsScene?.ProcessPreSimulation();
  203. }
  204. public void GetCoarseLocations(out List<Vector3> coarseLocations, out List<UUID> avatarUUIDs, int maxLocations)
  205. {
  206. coarseLocations = new List<Vector3>();
  207. avatarUUIDs = new List<UUID>();
  208. // coarse locations are sent as BYTE, so limited to the 255m max of normal regions
  209. // try to work around that scale down X and Y acording to region size, so reducing the resolution
  210. //
  211. // viewers need to scale up
  212. float scaleX = (float)m_parentScene.RegionInfo.RegionSizeX / (float)Constants.RegionSize;
  213. if (scaleX == 0)
  214. scaleX = 1.0f;
  215. else
  216. scaleX = 1.0f / scaleX;
  217. float scaleY = (float)m_parentScene.RegionInfo.RegionSizeY / (float)Constants.RegionSize;
  218. if (scaleY == 0)
  219. scaleY = 1.0f;
  220. else
  221. scaleY = 1.0f / scaleY;
  222. List<ScenePresence> presences = GetScenePresences();
  223. foreach (ScenePresence sp in CollectionsMarshal.AsSpan(presences))
  224. {
  225. // If this presence is a child agent, we don't want its coarse locations
  226. if (sp.IsChildAgent)
  227. continue;
  228. Vector3 pos = sp.AbsolutePosition;
  229. pos.X *= scaleX;
  230. pos.Y *= scaleY;
  231. coarseLocations.Add(pos);
  232. avatarUUIDs.Add(sp.UUID);
  233. if (--maxLocations <= 0)
  234. break;
  235. }
  236. }
  237. #endregion
  238. #region Entity Methods
  239. /// <summary>
  240. /// Add an object into the scene that has come from storage
  241. /// </summary>
  242. /// <param name="sceneObject"></param>
  243. /// <param name="attachToBackup">
  244. /// If true, changes to the object will be reflected in its persisted data
  245. /// If false, the persisted data will not be changed even if the object in the scene is changed
  246. /// </param>
  247. /// <param name="alreadyPersisted">
  248. /// If true, we won't persist this object until it changes
  249. /// If false, we'll persist this object immediately
  250. /// </param>
  251. /// <param name="sendClientUpdates">
  252. /// If true, we send updates to the client to tell it about this object
  253. /// If false, we leave it up to the caller to do this
  254. /// </param>
  255. /// <returns>
  256. /// true if the object was added, false if an object with the same uuid was already in the scene
  257. /// </returns>
  258. protected internal bool AddRestoredSceneObject(
  259. SceneObjectGroup sceneObject, bool attachToBackup, bool alreadyPersisted, bool sendClientUpdates)
  260. {
  261. // temporary checks to remove after varsize suport
  262. float regionSizeX = m_parentScene.RegionInfo.RegionSizeX;
  263. float regionSizeY = m_parentScene.RegionInfo.RegionSizeY;
  264. // KF: Check for out-of-region, move inside and make static.
  265. Vector3 npos = sceneObject.RootPart.GroupPosition;
  266. bool clampZ = m_parentScene.ClampNegativeZ;
  267. if (!((sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim) && (sceneObject.RootPart.Shape.State != 0)) && (npos.X < 0.0 || npos.Y < 0.0 || (npos.Z < 0.0 && clampZ) ||
  268. npos.X > regionSizeX || npos.Y > regionSizeY))
  269. {
  270. if (npos.X < 0.0) npos.X = 1.0f;
  271. if (npos.Y < 0.0) npos.Y = 1.0f;
  272. if (npos.Z < 0.0 && clampZ) npos.Z = 0.0f;
  273. if (npos.X > regionSizeX) npos.X = regionSizeX - 1.0f;
  274. if (npos.Y > regionSizeY) npos.Y = regionSizeY - 1.0f;
  275. SceneObjectPart rootpart = sceneObject.RootPart;
  276. rootpart.GroupPosition = npos;
  277. foreach (SceneObjectPart part in sceneObject.Parts)
  278. {
  279. if (part == rootpart)
  280. continue;
  281. part.GroupPosition = npos;
  282. }
  283. rootpart.Velocity = Vector3.Zero;
  284. rootpart.AngularVelocity = Vector3.Zero;
  285. rootpart.Acceleration = Vector3.Zero;
  286. }
  287. bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
  288. if (attachToBackup && (!alreadyPersisted))
  289. {
  290. sceneObject.ForceInventoryPersistence();
  291. sceneObject.HasGroupChanged = true;
  292. }
  293. sceneObject.InvalidateDeepEffectivePerms();
  294. return ret;
  295. }
  296. /// <summary>
  297. /// Add a newly created object to the scene. This will both update the scene, and send information about the
  298. /// new object to all clients interested in the scene.
  299. /// </summary>
  300. /// <param name="sceneObject"></param>
  301. /// <param name="attachToBackup">
  302. /// If true, the object is made persistent into the scene.
  303. /// If false, the object will not persist over server restarts
  304. /// </param>
  305. /// <returns>
  306. /// true if the object was added, false if an object with the same uuid was already in the scene
  307. /// </returns>
  308. protected internal bool AddNewSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
  309. {
  310. bool ret = AddSceneObject(sceneObject, attachToBackup, sendClientUpdates);
  311. // Ensure that we persist this new scene object if it's not an
  312. // attachment
  313. if (attachToBackup)
  314. sceneObject.HasGroupChanged = true;
  315. return ret;
  316. }
  317. /// <summary>
  318. /// Add a newly created object to the scene.
  319. /// </summary>
  320. ///
  321. /// This method does not send updates to the client - callers need to handle this themselves.
  322. /// Caller should also trigger EventManager.TriggerObjectAddedToScene
  323. /// <param name="sceneObject"></param>
  324. /// <param name="attachToBackup"></param>
  325. /// <param name="pos">Position of the object. If null then the position stored in the object is used.</param>
  326. /// <param name="rot">Rotation of the object. If null then the rotation stored in the object is used.</param>
  327. /// <param name="vel">Velocity of the object. This parameter only has an effect if the object is physical</param>
  328. /// <returns></returns>
  329. public bool AddNewSceneObject(
  330. SceneObjectGroup sceneObject, bool attachToBackup, Vector3? pos, Quaternion? rot, Vector3 vel)
  331. {
  332. if (pos is not null)
  333. sceneObject.AbsolutePosition = (Vector3)pos;
  334. if (rot is not null)
  335. sceneObject.UpdateGroupRotationR((Quaternion)rot);
  336. AddNewSceneObject(sceneObject, attachToBackup, false);
  337. if (sceneObject.RootPart.Shape.PCode == (byte)PCode.Prim)
  338. {
  339. sceneObject.ClearPartAttachmentData();
  340. }
  341. PhysicsActor pa = sceneObject.RootPart.PhysActor;
  342. if (pa is not null && pa.IsPhysical && vel.IsNotZero())
  343. {
  344. sceneObject.RootPart.ApplyImpulse(vel * sceneObject.GetMass(), false);
  345. }
  346. return true;
  347. }
  348. /// <summary>
  349. /// Add an object to the scene. This will both update the scene, and send information about the
  350. /// new object to all clients interested in the scene.
  351. /// </summary>
  352. /// <remarks>
  353. /// The object's stored position, rotation and velocity are used.
  354. /// </remarks>
  355. /// <param name="sceneObject"></param>
  356. /// <param name="attachToBackup">
  357. /// If true, the object is made persistent into the scene.
  358. /// If false, the object will not persist over server restarts
  359. /// </param>
  360. /// <param name="sendClientUpdates">
  361. /// If true, updates for the new scene object are sent to all viewers in range.
  362. /// If false, it is left to the caller to schedule the update
  363. /// </param>
  364. /// <returns>
  365. /// true if the object was added, false if an object with the same uuid was already in the scene
  366. /// </returns>
  367. protected bool AddSceneObject(SceneObjectGroup sceneObject, bool attachToBackup, bool sendClientUpdates)
  368. {
  369. if (sceneObject is null)
  370. {
  371. m_log.Error("[SCENEGRAPH]: Tried to add null scene object");
  372. return false;
  373. }
  374. if (sceneObject.UUID.IsZero())
  375. {
  376. m_log.Error(
  377. $"[SCENEGRAPH]: Tried to add scene object {sceneObject.Name} to {m_parentScene.RegionInfo.RegionName} with Zero UUID");
  378. return false;
  379. }
  380. if (Entities.ContainsKey(sceneObject.UUID))
  381. {
  382. m_log.Debug(
  383. $"[SCENEGRAPH]: Scene graph for {m_parentScene.RegionInfo.RegionName} already contains object {sceneObject.UUID} in AddSceneObject()");
  384. return false;
  385. }
  386. //m_log.DebugFormat(
  387. // "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}",
  388. // sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName);
  389. ReadOnlySpan<SceneObjectPart> parts = sceneObject.Parts.AsSpan();
  390. SceneObjectPart part;
  391. // Clamp the sizes (scales) of the child prims and add the child prims to the count of all primitives
  392. // (meshes and geometric primitives) in the scene; add child prims to m_numTotalPrim count
  393. if (m_parentScene.m_clampPrimSize)
  394. {
  395. for (int i = 0; i < parts.Length; ++i)
  396. {
  397. part = parts[i];
  398. Vector3 scale = part.Shape.Scale;
  399. scale.X = Utils.Clamp(scale.X, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys);
  400. scale.Y = Utils.Clamp(scale.Y, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys);
  401. scale.Z = Utils.Clamp(scale.Z, m_parentScene.m_minNonphys, m_parentScene.m_maxNonphys);
  402. part.Shape.Scale = scale;
  403. }
  404. }
  405. sceneObject.AttachToScene(m_parentScene);
  406. bool entered = false;
  407. try
  408. {
  409. try { }
  410. finally
  411. {
  412. m_scenePartsLock.EnterWriteLock();
  413. entered = true;
  414. }
  415. Entities.Add(sceneObject);
  416. m_scenePartsArray = null;
  417. for (int i = 0; i < parts.Length; ++i)
  418. {
  419. part = parts[i];
  420. if (!m_scenePartsByID.ContainsKey(part.UUID))
  421. {
  422. m_scenePartsByID[part.UUID] = part;
  423. m_scenePartsByLocalID[part.LocalId] = part;
  424. if (part.GetPrimType() == PrimType.SCULPT)
  425. ++m_numMesh;
  426. else
  427. ++m_numPrim;
  428. }
  429. }
  430. }
  431. finally
  432. {
  433. if(entered)
  434. m_scenePartsLock.ExitWriteLock();
  435. }
  436. if (sendClientUpdates)
  437. sceneObject.ScheduleGroupForUpdate(PrimUpdateFlags.FullUpdatewithAnimMatOvr);
  438. if (attachToBackup)
  439. sceneObject.AttachToBackup();
  440. return true;
  441. }
  442. /// <summary>
  443. /// Delete an object from the scene
  444. /// </summary>
  445. /// <returns>true if the object was deleted, false if there was no object to delete</returns>
  446. public bool DeleteSceneObject(UUID uuid, bool resultOfObjectLinked)
  447. {
  448. // m_log.DebugFormat(
  449. // "[SCENE GRAPH]: Deleting scene object with uuid {0}, resultOfObjectLinked = {1}",
  450. // uuid, resultOfObjectLinked);
  451. if (!Entities.TryGetValue(uuid, out EntityBase entity) || (entity is not SceneObjectGroup grp))
  452. return false;
  453. SceneObjectPart[] parts = grp.Parts;
  454. int partsLength = parts.Length;
  455. SceneObjectPart part;
  456. if (!resultOfObjectLinked)
  457. {
  458. bool isPh = (grp.RootPart.Flags & PrimFlags.Physics) == PrimFlags.Physics;
  459. int nphysparts = 0;
  460. // Go through all parts (primitives and meshes) of this Scene Object
  461. for (int i= 0; i < partsLength; ++i)
  462. {
  463. part = parts[i];
  464. // Keep track of the total number of meshes or geometric primitives left in the scene;
  465. // determine which object this is based on its primitive type: sculpted (sculpt) prim refers to
  466. // a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives
  467. if (part.GetPrimType() == PrimType.SCULPT)
  468. m_numMesh--;
  469. else
  470. m_numPrim--;
  471. if(isPh && part.PhysicsShapeType != (byte)PhysShapeType.none)
  472. nphysparts++;
  473. }
  474. if (nphysparts > 0 )
  475. RemovePhysicalPrim(nphysparts);
  476. }
  477. bool ret = false;
  478. bool entered = false;
  479. try
  480. {
  481. try { }
  482. finally
  483. {
  484. m_scenePartsLock.EnterWriteLock();
  485. entered = true;
  486. }
  487. if (!resultOfObjectLinked)
  488. {
  489. for (int i = 0; i < parts.Length; ++i)
  490. {
  491. part = parts[i];
  492. m_scenePartsByID.Remove(part.UUID);
  493. m_scenePartsByLocalID.Remove(part.LocalId);
  494. }
  495. m_scenePartsArray = null;
  496. }
  497. ret = Entities.Remove(uuid);
  498. }
  499. finally
  500. {
  501. if(entered)
  502. m_scenePartsLock.ExitWriteLock();
  503. }
  504. return ret;
  505. }
  506. /// <summary>
  507. /// Add an object to the list of prims to process on the next update
  508. /// </summary>
  509. /// <param name="obj">
  510. /// A <see cref="SceneObjectGroup"/>
  511. /// </param>
  512. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  513. protected internal void AddToUpdateList(SceneObjectGroup obj)
  514. {
  515. lock(m_updateLock)
  516. m_updateList[obj.UUID] = obj;
  517. }
  518. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  519. public void FireAttachToBackup(SceneObjectGroup obj)
  520. {
  521. OnAttachToBackup?.Invoke(obj);
  522. }
  523. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  524. public void FireDetachFromBackup(SceneObjectGroup obj)
  525. {
  526. OnDetachFromBackup?.Invoke(obj);
  527. }
  528. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  529. public void FireChangeBackup(SceneObjectGroup obj)
  530. {
  531. OnChangeBackup?.Invoke(obj);
  532. }
  533. /// <summary>
  534. /// Process all pending updates
  535. /// </summary>
  536. protected internal void UpdateObjectGroups()
  537. {
  538. Dictionary<UUID, SceneObjectGroup> updates;
  539. // Get the current list of updates and clear the list before iterating
  540. lock (m_updateLock)
  541. {
  542. if(m_updateList.Count == 0)
  543. return;
  544. updates = m_updateList;
  545. m_updateList = new Dictionary<UUID, SceneObjectGroup>();
  546. }
  547. // Go through all updates
  548. foreach (SceneObjectGroup sog in updates.Values)
  549. {
  550. if (sog.IsDeleted)
  551. continue;
  552. // Don't abort the whole update if one entity happens to give us an exception.
  553. try
  554. {
  555. sog.Update();
  556. }
  557. catch (Exception e)
  558. {
  559. m_log.Error($"[INNER SCENE]: Failed to update {sog.Name}, {sog.UUID} - {e.Message}");
  560. }
  561. }
  562. }
  563. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  564. protected internal void AddPhysicalPrim(int number)
  565. {
  566. Interlocked.Add(ref m_physicalPrim, number);
  567. }
  568. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  569. protected internal void RemovePhysicalPrim(int number)
  570. {
  571. Interlocked.Add(ref m_physicalPrim, -number);
  572. }
  573. protected internal void AddToScriptLPS(int number)
  574. {
  575. //m_scriptLPS += number;
  576. }
  577. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  578. protected internal void AddActiveScripts(int number)
  579. {
  580. Interlocked.Add(ref m_activeScripts, number);
  581. }
  582. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  583. protected internal void HandleUndo(IClientAPI remoteClient, UUID primId)
  584. {
  585. if (primId.IsNotZero())
  586. {
  587. SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
  588. part?.Undo();
  589. }
  590. }
  591. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  592. protected internal void HandleRedo(IClientAPI remoteClient, UUID primId)
  593. {
  594. if (primId.IsNotZero())
  595. {
  596. SceneObjectPart part = m_parentScene.GetSceneObjectPart(primId);
  597. part?.Redo();
  598. }
  599. }
  600. protected internal ScenePresence CreateAndAddChildScenePresence(
  601. IClientAPI client, AvatarAppearance appearance, PresenceType type)
  602. {
  603. ScenePresence presence = new(client, m_parentScene, appearance, type);
  604. bool entered = false;
  605. try
  606. {
  607. try{ }
  608. finally
  609. {
  610. m_scenePresencesLock.EnterWriteLock();
  611. entered = true;
  612. }
  613. UUID id = presence.UUID;
  614. Entities[id] = presence;
  615. // ScenePresence always defaults to child agent
  616. ++m_numChildAgents;
  617. uint localid = presence.LocalId;
  618. if (m_scenePresenceMap.TryGetValue(id, out ScenePresence oldref))
  619. {
  620. uint oldLocalID = oldref.LocalId;
  621. if (localid != oldLocalID)
  622. m_scenePresenceLocalIDMap.Remove(oldLocalID);
  623. }
  624. m_scenePresenceMap[id] = presence;
  625. m_scenePresenceLocalIDMap[localid] = presence;
  626. m_scenePresenceList = null;
  627. }
  628. finally
  629. {
  630. if(entered)
  631. m_scenePresencesLock.ExitWriteLock();
  632. }
  633. return presence;
  634. }
  635. /// <summary>
  636. /// Remove a presence from the scene
  637. /// </summary>
  638. protected internal void RemoveScenePresence(UUID agentID)
  639. {
  640. if (!Entities.Remove(agentID))
  641. {
  642. m_log.Warn($"[SCENE GRAPH]: Tried to remove non-existent scene presence with ID {agentID}");
  643. }
  644. bool entered = false;
  645. try
  646. {
  647. try { }
  648. finally
  649. {
  650. m_scenePresencesLock.EnterWriteLock();
  651. entered = true;
  652. }
  653. // Remove the presence reference from the dictionary
  654. if(m_scenePresenceMap.TryGetValue(agentID, out ScenePresence oldref))
  655. {
  656. m_scenePresenceMap.Remove(agentID);
  657. // Find the index in the list where the old ref was stored and remove the reference
  658. m_scenePresenceLocalIDMap.Remove(oldref.LocalId);
  659. m_scenePresenceList = null;
  660. if(oldref.IsChildAgent)
  661. --m_numChildAgents;
  662. else
  663. {
  664. --m_numRootAgents;
  665. if(oldref.IsNPC)
  666. --m_numRootNPC;
  667. }
  668. }
  669. else
  670. {
  671. m_log.Warn($"[SCENE GRAPH]: Tried to remove non-existent scene presence with ID {agentID}");
  672. }
  673. }
  674. finally
  675. {
  676. if(entered)
  677. m_scenePresencesLock.ExitWriteLock();
  678. }
  679. }
  680. protected internal void SwapRootChildAgent(bool direction_RootToChild, bool isnpc = false)
  681. {
  682. if (direction_RootToChild)
  683. {
  684. --m_numRootAgents;
  685. if(isnpc)
  686. --m_numRootNPC;
  687. m_numChildAgents++;
  688. }
  689. else
  690. {
  691. --m_numChildAgents;
  692. ++m_numRootAgents;
  693. if (isnpc)
  694. ++m_numRootNPC;
  695. }
  696. }
  697. public void removeUserCount(bool TypeRCTF)
  698. {
  699. if (TypeRCTF)
  700. {
  701. m_numRootAgents--;
  702. }
  703. else
  704. {
  705. m_numChildAgents--;
  706. }
  707. }
  708. public void RecalculateStats()
  709. {
  710. int rootcount = 0;
  711. int childcount = 0;
  712. int rootnpccount = 0;
  713. List<ScenePresence> presences = GetScenePresences();
  714. foreach(ScenePresence sp in CollectionsMarshal.AsSpan(presences))
  715. {
  716. if (sp.IsChildAgent)
  717. ++childcount;
  718. else
  719. {
  720. ++rootcount;
  721. if(sp.IsNPC)
  722. ++rootnpccount;
  723. }
  724. }
  725. m_numRootAgents = rootcount;
  726. m_numChildAgents = childcount;
  727. m_numRootNPC = rootnpccount;
  728. }
  729. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  730. public int GetChildAgentCount()
  731. {
  732. return m_numChildAgents;
  733. }
  734. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  735. public int GetRootAgentCount()
  736. {
  737. return m_numRootAgents;
  738. }
  739. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  740. public int GetRootNPCCount()
  741. {
  742. return m_numRootNPC;
  743. }
  744. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  745. public int GetTotalObjectsCount()
  746. {
  747. return m_scenePartsByID.Count;
  748. }
  749. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  750. public int GetTotalPrimObjectsCount()
  751. {
  752. return m_numPrim;
  753. }
  754. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  755. public int GetTotalMeshObjectsCount()
  756. {
  757. return m_numMesh;
  758. }
  759. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  760. public int GetActiveObjectsCount()
  761. {
  762. return m_physicalPrim;
  763. }
  764. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  765. public int GetActiveScriptsCount()
  766. {
  767. return m_activeScripts;
  768. }
  769. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  770. public int GetScriptLPS()
  771. {
  772. //int returnval = m_scriptLPS;
  773. //m_scriptLPS = 0;
  774. //return returnval;
  775. return 0;
  776. }
  777. #endregion
  778. #region Get Methods
  779. /// <summary>
  780. /// Get the controlling client for the given avatar, if there is one.
  781. ///
  782. /// FIXME: The only user of the method right now is Caps.cs, in order to resolve a client API since it can't
  783. /// use the ScenePresence. This could be better solved in a number of ways - we could establish an
  784. /// OpenSim.Framework.IScenePresence, or move the caps code into a region package (which might be the more
  785. /// suitable solution).
  786. /// </summary>
  787. /// <param name="agentId"></param>
  788. /// <returns>null if either the avatar wasn't in the scene, or
  789. /// they do not have a controlling client</returns>
  790. /// <remarks>this used to be protected internal, but that
  791. /// prevents CapabilitiesModule from accessing it</remarks>
  792. public IClientAPI GetControllingClient(UUID agentId)
  793. {
  794. bool entered = false;
  795. try
  796. {
  797. try { }
  798. finally
  799. {
  800. m_scenePresencesLock.EnterReadLock();
  801. entered = true;
  802. }
  803. if (m_scenePresenceMap.TryGetValue(agentId, out ScenePresence presence))
  804. return presence.ControllingClient;
  805. return null;
  806. }
  807. catch
  808. {
  809. return null;
  810. }
  811. finally
  812. {
  813. if (entered)
  814. m_scenePresencesLock.ExitReadLock();
  815. }
  816. }
  817. /// <summary>
  818. /// Get a reference to the scene presence list. Changes to the list will be done in a copy
  819. /// There is no guarantee that presences will remain in the scene after the list is returned.
  820. /// This list should remain private to SceneGraph. Callers wishing to iterate should instead
  821. /// pass a delegate to ForEachScenePresence.
  822. /// </summary>
  823. /// <returns></returns>
  824. protected internal List<ScenePresence> GetScenePresences()
  825. {
  826. bool entered = false;
  827. try
  828. {
  829. try{ }
  830. finally
  831. {
  832. m_scenePresencesLock.EnterWriteLock();
  833. entered = true;
  834. }
  835. m_scenePresenceList ??= new List<ScenePresence>(m_scenePresenceMap.Values);
  836. return m_scenePresenceList;
  837. }
  838. catch
  839. {
  840. return new List<ScenePresence>();
  841. }
  842. finally
  843. {
  844. if(entered)
  845. m_scenePresencesLock.ExitWriteLock();
  846. }
  847. }
  848. /// <summary>
  849. /// Request a scene presence by UUID. Fast, indexed lookup.
  850. /// </summary>
  851. /// <param name="agentID"></param>
  852. /// <returns>null if the presence was not found</returns>
  853. protected internal ScenePresence GetScenePresence(UUID agentID)
  854. {
  855. bool entered = false;
  856. try
  857. {
  858. try { }
  859. finally
  860. {
  861. m_scenePresencesLock.EnterReadLock();
  862. entered = true;
  863. }
  864. if(m_scenePresenceMap.TryGetValue(agentID, out ScenePresence presence))
  865. return presence;
  866. return null;
  867. }
  868. catch
  869. {
  870. return null;
  871. }
  872. finally
  873. {
  874. if (entered)
  875. m_scenePresencesLock.ExitReadLock();
  876. }
  877. }
  878. /// <summary>
  879. /// Request the scene presence by name.
  880. /// </summary>
  881. /// <param name="firstName"></param>
  882. /// <param name="lastName"></param>
  883. /// <returns>null if the presence was not found</returns>
  884. protected internal ScenePresence GetScenePresence(string firstName, string lastName)
  885. {
  886. List<ScenePresence> presences = GetScenePresences();
  887. foreach (ScenePresence presence in CollectionsMarshal.AsSpan(presences))
  888. {
  889. if (string.Equals(presence.Firstname, firstName, StringComparison.CurrentCultureIgnoreCase)
  890. && string.Equals(presence.Lastname, lastName, StringComparison.CurrentCultureIgnoreCase))
  891. return presence;
  892. }
  893. return null;
  894. }
  895. /// <summary>
  896. /// Request the scene presence by localID.
  897. /// </summary>
  898. /// <param name="localID"></param>
  899. /// <returns>null if the presence was not found</returns>
  900. protected internal ScenePresence GetScenePresence(uint localID)
  901. {
  902. bool entered = false;
  903. try
  904. {
  905. try { }
  906. finally
  907. {
  908. m_scenePresencesLock.EnterReadLock();
  909. entered = true;
  910. }
  911. if (m_scenePresenceLocalIDMap.TryGetValue(localID, out ScenePresence sp))
  912. return sp;
  913. }
  914. finally
  915. {
  916. if (entered)
  917. m_scenePresencesLock.ExitReadLock();
  918. }
  919. return null;
  920. }
  921. protected internal bool TryGetScenePresence(UUID agentID, out ScenePresence avatar)
  922. {
  923. bool entered = false;
  924. try
  925. {
  926. try { }
  927. finally
  928. {
  929. m_scenePresencesLock.EnterReadLock();
  930. entered = true;
  931. }
  932. return m_scenePresenceMap.TryGetValue(agentID, out avatar);
  933. }
  934. catch
  935. {
  936. avatar = null;
  937. return false;
  938. }
  939. finally
  940. {
  941. if (entered)
  942. m_scenePresencesLock.ExitReadLock();
  943. }
  944. }
  945. protected internal bool TryGetSceneRootPresence(UUID agentID, out ScenePresence avatar)
  946. {
  947. bool entered = false;
  948. try
  949. {
  950. try { }
  951. finally
  952. {
  953. m_scenePresencesLock.EnterReadLock();
  954. entered = true;
  955. }
  956. return m_scenePresenceMap.TryGetValue(agentID, out avatar) && !avatar.IsChildAgent;
  957. }
  958. catch
  959. {
  960. avatar = null;
  961. return false;
  962. }
  963. finally
  964. {
  965. if (entered)
  966. m_scenePresencesLock.ExitReadLock();
  967. }
  968. }
  969. protected internal bool TryGetAvatarByName(string name, out ScenePresence avatar)
  970. {
  971. List<ScenePresence> presences = GetScenePresences();
  972. foreach (ScenePresence presence in CollectionsMarshal.AsSpan(presences))
  973. {
  974. if (string.Equals(name, presence.ControllingClient.Name, StringComparison.CurrentCultureIgnoreCase))
  975. {
  976. avatar = presence;
  977. return true;
  978. }
  979. }
  980. avatar = null;
  981. return false;
  982. }
  983. /// <summary>
  984. /// Get a scene object group that contains the prim with the given local id
  985. /// </summary>
  986. /// <param name="localID"></param>
  987. /// <returns>null if no scene object group containing that prim is found</returns>
  988. public SceneObjectGroup GetGroupByPrim(uint localID)
  989. {
  990. bool entered = false;
  991. try
  992. {
  993. try { }
  994. finally
  995. {
  996. m_scenePartsLock.EnterReadLock();
  997. entered = true;
  998. }
  999. return m_scenePartsByLocalID.TryGetValue(localID, out SceneObjectPart sop) ? sop.ParentGroup : null;
  1000. }
  1001. finally
  1002. {
  1003. if (entered)
  1004. m_scenePartsLock.ExitReadLock();
  1005. }
  1006. }
  1007. /// <summary>
  1008. /// Get a scene object group that contains the prim with the given uuid
  1009. /// </summary>
  1010. /// <param name="fullID"></param>
  1011. /// <returns>null if no scene object group containing that prim is found</returns>
  1012. public SceneObjectGroup GetGroupByPrim(UUID fullID)
  1013. {
  1014. bool entered = false;
  1015. try
  1016. {
  1017. try { }
  1018. finally
  1019. {
  1020. m_scenePartsLock.EnterReadLock();
  1021. entered = true;
  1022. }
  1023. return m_scenePartsByID.TryGetValue(fullID, out SceneObjectPart sop) ? sop.ParentGroup : null;
  1024. }
  1025. finally
  1026. {
  1027. if (entered)
  1028. m_scenePartsLock.ExitReadLock();
  1029. }
  1030. }
  1031. protected internal EntityIntersection GetClosestIntersectingPrim(Ray hray, bool frontFacesOnly, bool faceCenters)
  1032. {
  1033. // Primitive Ray Tracing
  1034. float closestDistance = 280f;
  1035. EntityIntersection result = new();
  1036. EntityBase[] EntityList = GetEntities();
  1037. foreach (EntityBase ent in EntityList.AsSpan())
  1038. {
  1039. if (ent is SceneObjectGroup reportingG)
  1040. {
  1041. EntityIntersection inter = reportingG.TestIntersection(hray, frontFacesOnly, faceCenters);
  1042. if (inter.HitTF && inter.distance < closestDistance)
  1043. {
  1044. closestDistance = inter.distance;
  1045. result = inter;
  1046. }
  1047. }
  1048. }
  1049. return result;
  1050. }
  1051. /// <summary>
  1052. /// Get all the scene object groups.
  1053. /// </summary>
  1054. /// <returns>
  1055. /// The scene object groups. If the scene is empty then an empty list is returned.
  1056. /// </returns>
  1057. protected internal List<SceneObjectGroup> GetSceneObjectGroups()
  1058. {
  1059. EntityBase[] entities = Entities.GetEntities();
  1060. List<SceneObjectGroup> ret = new(entities.Length);
  1061. foreach(EntityBase et in entities.AsSpan())
  1062. {
  1063. if(et is SceneObjectGroup sog)
  1064. ret.Add(sog);
  1065. }
  1066. return ret;
  1067. }
  1068. /// <summary>
  1069. /// Get a group in the scene
  1070. /// </summary>
  1071. /// <param name="fullID">UUID of the group</param>
  1072. /// <returns>null if no such group was found</returns>
  1073. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1074. protected internal SceneObjectGroup GetSceneObjectGroup(UUID fullID)
  1075. {
  1076. if (Entities.TryGetValue(fullID, out EntityBase entity) && (entity is SceneObjectGroup sog))
  1077. return sog;
  1078. return null;
  1079. }
  1080. /// <summary>
  1081. /// Get a group in the scene
  1082. /// <param name="localID">Local id of the root part of the group</param>
  1083. /// <returns>null if no such group was found</retu
  1084. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1085. protected internal SceneObjectGroup GetSceneObjectGroup(uint localID)
  1086. {
  1087. if (Entities.TryGetValue(localID, out EntityBase entity) && (entity is SceneObjectGroup sog))
  1088. return sog;
  1089. return null;
  1090. }
  1091. /// <summary>
  1092. /// Get a group by name from the scene (will return the first
  1093. /// found, if there are more than one prim with the same name)
  1094. /// </summary>
  1095. /// <param name="name"></param>
  1096. /// <returns>null if the part was not found</returns>
  1097. protected internal SceneObjectGroup GetSceneObjectGroup(string name)
  1098. {
  1099. foreach(EntityBase entity in Entities.GetEntities().AsSpan())
  1100. {
  1101. if (entity is SceneObjectGroup sog && sog.Name.Equals(name))
  1102. return sog;
  1103. }
  1104. return null;
  1105. }
  1106. /// <summary>
  1107. /// Get a part contained in this scene.
  1108. /// </summary>
  1109. /// <param name="localID"></param>
  1110. /// <returns>null if the part was not found</returns>
  1111. protected internal SceneObjectPart GetSceneObjectPart(uint localID)
  1112. {
  1113. bool entered = false;
  1114. try
  1115. {
  1116. try { }
  1117. finally
  1118. {
  1119. m_scenePartsLock.EnterReadLock();
  1120. entered = true;
  1121. }
  1122. return m_scenePartsByLocalID.TryGetValue(localID, out SceneObjectPart sop) &&
  1123. sop.ParentGroup is not null && !sop.ParentGroup.IsDeleted ? sop : null;
  1124. }
  1125. finally
  1126. {
  1127. if (entered)
  1128. m_scenePartsLock.ExitReadLock();
  1129. }
  1130. }
  1131. protected internal bool TryGetSceneObjectPart(uint localID, out SceneObjectPart sop)
  1132. {
  1133. bool entered = false;
  1134. try
  1135. {
  1136. try { }
  1137. finally
  1138. {
  1139. m_scenePartsLock.EnterReadLock();
  1140. entered = true;
  1141. }
  1142. return m_scenePartsByLocalID.TryGetValue(localID, out sop) &&
  1143. sop.ParentGroup is not null &&
  1144. !sop.ParentGroup.IsDeleted;
  1145. }
  1146. finally
  1147. {
  1148. if (entered)
  1149. m_scenePartsLock.ExitReadLock();
  1150. }
  1151. }
  1152. /// <summary>
  1153. /// Get a part contained in this scene.
  1154. /// </summary>
  1155. /// <param name="fullID"></param>
  1156. /// <returns>null if the part was not found</returns>
  1157. protected internal SceneObjectPart GetSceneObjectPart(UUID fullID)
  1158. {
  1159. bool entered = false;
  1160. try
  1161. {
  1162. try { }
  1163. finally
  1164. {
  1165. m_scenePartsLock.EnterReadLock();
  1166. entered = true;
  1167. }
  1168. return m_scenePartsByID.TryGetValue(fullID, out SceneObjectPart sop) &&
  1169. sop.ParentGroup is not null && !sop.ParentGroup.IsDeleted ? sop : null;
  1170. }
  1171. finally
  1172. {
  1173. if (entered)
  1174. m_scenePartsLock.ExitReadLock();
  1175. }
  1176. }
  1177. protected internal bool TryGetSceneObjectPart(UUID fullID, out SceneObjectPart sop)
  1178. {
  1179. bool entered = false;
  1180. try
  1181. {
  1182. try { }
  1183. finally
  1184. {
  1185. m_scenePartsLock.EnterReadLock();
  1186. entered = true;
  1187. }
  1188. return m_scenePartsByID.TryGetValue(fullID, out sop) && sop.ParentGroup is not null && !sop.ParentGroup.IsDeleted;
  1189. }
  1190. finally
  1191. {
  1192. if (entered)
  1193. m_scenePartsLock.ExitReadLock();
  1194. }
  1195. }
  1196. /// <summary>
  1197. /// Get a prim by name from the scene (will return the first
  1198. /// found, if there are more than one prim with the same name)
  1199. /// </summary>
  1200. /// <param name="name"></param>
  1201. /// <returns>null if the part was not found</returns>
  1202. protected internal SceneObjectPart GetSceneObjectPart(string name)
  1203. {
  1204. SceneObjectPart[] parts = GetPartsArray();
  1205. foreach (SceneObjectPart sop in parts)
  1206. {
  1207. if (sop.ParentGroup is null || sop.ParentGroup.IsDeleted)
  1208. continue;
  1209. if (sop.Name.Equals(name))
  1210. return sop;
  1211. }
  1212. return null;
  1213. }
  1214. protected internal SceneObjectPart[] GetPartsArray()
  1215. {
  1216. bool entered = false;
  1217. try
  1218. {
  1219. try { }
  1220. finally
  1221. {
  1222. m_scenePartsLock.EnterWriteLock();
  1223. entered = true;
  1224. }
  1225. if(m_scenePartsArray is null)
  1226. {
  1227. m_scenePartsArray = new SceneObjectPart[m_scenePartsByID.Count];
  1228. m_scenePartsByID.Values.CopyTo(m_scenePartsArray, 0);
  1229. }
  1230. return m_scenePartsArray;
  1231. }
  1232. finally
  1233. {
  1234. if(entered)
  1235. m_scenePartsLock.ExitWriteLock();
  1236. }
  1237. }
  1238. /// <summary>
  1239. /// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over
  1240. /// it
  1241. /// </summary>
  1242. /// <returns></returns>
  1243. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1244. protected internal EntityBase[] GetEntities()
  1245. {
  1246. return Entities.GetEntities();
  1247. }
  1248. #endregion
  1249. #region Other Methods
  1250. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1251. protected internal void physicsBasedCrash()
  1252. {
  1253. UnRecoverableError?.Invoke();
  1254. }
  1255. /// <summary>
  1256. /// Performs action once on all scene object groups.
  1257. /// </summary>
  1258. /// <param name="action"></param>
  1259. protected internal void ForEachSOG(Action<SceneObjectGroup> action)
  1260. {
  1261. EntityBase[] entities = Entities.GetEntities();
  1262. foreach (EntityBase entity in entities.AsSpan())
  1263. {
  1264. if (entity is SceneObjectGroup sog)
  1265. {
  1266. try
  1267. {
  1268. action(sog);
  1269. }
  1270. catch (Exception e)
  1271. {
  1272. m_log.Warn($"[SCENEGRAPH]: Problem processing action in ForEachSOG: {e.Message}");
  1273. }
  1274. }
  1275. }
  1276. }
  1277. /// <summary>
  1278. /// Performs action on all ROOT (not child) scene presences.
  1279. /// This is just a shortcut function since frequently actions only appy to root SPs
  1280. /// </summary>
  1281. /// <param name="action"></param>
  1282. public void ForEachRootScenePresence(Action<ScenePresence> action)
  1283. {
  1284. List<ScenePresence> presences = GetScenePresences();
  1285. foreach (ScenePresence sp in CollectionsMarshal.AsSpan(presences))
  1286. {
  1287. if(sp.IsChildAgent || sp.IsDeleted)
  1288. continue;
  1289. try
  1290. {
  1291. action(sp);
  1292. }
  1293. catch (Exception e)
  1294. {
  1295. m_log.Error($"[SCENEGRAPH]: Error in {m_parentScene.RegionInfo.RegionName}: {e.Message}");
  1296. }
  1297. };
  1298. }
  1299. /// <summary>
  1300. /// Performs action on all scene presences
  1301. /// </summary>
  1302. /// <param name="action"></param>
  1303. public void ForEachScenePresence(Action<ScenePresence> action)
  1304. {
  1305. List<ScenePresence> presences = GetScenePresences();
  1306. foreach (ScenePresence sp in CollectionsMarshal.AsSpan(presences))
  1307. {
  1308. if (sp.IsDeleted)
  1309. continue;
  1310. try
  1311. {
  1312. action(sp);
  1313. }
  1314. catch (Exception e)
  1315. {
  1316. m_log.Error($"[SCENEGRAPH]: Error in {m_parentScene.RegionInfo.RegionName}: {e.Message}");
  1317. }
  1318. }
  1319. }
  1320. #endregion
  1321. #region Client Event handlers
  1322. protected internal void ClientChangeObject(uint localID, object odata, IClientAPI remoteClient)
  1323. {
  1324. SceneObjectPart part = GetSceneObjectPart(localID);
  1325. if(part is null)
  1326. return;
  1327. SceneObjectGroup grp = part.ParentGroup;
  1328. if (grp is null)
  1329. return;
  1330. ObjectChangeData data = (ObjectChangeData)odata;
  1331. if (m_parentScene.Permissions.CanEditObject(grp, remoteClient))
  1332. {
  1333. // These two are exceptions SL makes in the interpretation
  1334. // of the change flags. Must check them here because otherwise
  1335. // the group flag (see below) would be lost
  1336. if (data.change == ObjectChangeType.groupS)
  1337. data.change = ObjectChangeType.primS;
  1338. if (data.change == ObjectChangeType.groupPS)
  1339. data.change = ObjectChangeType.primPS;
  1340. part.StoreUndoState(data.change); // lets test only saving what we changed
  1341. grp.doChangeObject(part, data);
  1342. }
  1343. else
  1344. {
  1345. // Is this any kind of group operation?
  1346. if ((data.change & ObjectChangeType.Group) != 0)
  1347. {
  1348. // Is a move and/or rotation requested?
  1349. if ((data.change & (ObjectChangeType.Position | ObjectChangeType.Rotation)) != 0)
  1350. {
  1351. // Are we allowed to move it?
  1352. if (m_parentScene.Permissions.CanMoveObject(grp, remoteClient))
  1353. {
  1354. // Strip all but move and rotation from request
  1355. data.change &= (ObjectChangeType.Group | ObjectChangeType.Position | ObjectChangeType.Rotation);
  1356. part.StoreUndoState(data.change);
  1357. grp.doChangeObject(part, data);
  1358. }
  1359. }
  1360. }
  1361. }
  1362. }
  1363. /// <summary>
  1364. /// Update the scale of an individual prim.
  1365. /// </summary>
  1366. /// <param name="localID"></param>
  1367. /// <param name="scale"></param>
  1368. /// <param name="remoteClient"></param>
  1369. protected internal void UpdatePrimScale(uint localID, in Vector3 scale, IClientAPI remoteClient)
  1370. {
  1371. if(TryGetSceneObjectPart(localID, out SceneObjectPart part))
  1372. {
  1373. if (m_parentScene.Permissions.CanEditObject(part.ParentGroup, remoteClient))
  1374. {
  1375. bool physbuild = false;
  1376. if (part.ParentGroup.RootPart.PhysActor is not null)
  1377. {
  1378. part.ParentGroup.RootPart.PhysActor.Building = true;
  1379. physbuild = true;
  1380. }
  1381. part.Resize(scale);
  1382. if (physbuild)
  1383. part.ParentGroup.RootPart.PhysActor.Building = false;
  1384. }
  1385. }
  1386. }
  1387. protected internal void UpdatePrimGroupScale(uint localID, in Vector3 scale, IClientAPI remoteClient)
  1388. {
  1389. SceneObjectGroup group = GetGroupByPrim(localID);
  1390. if (group is not null)
  1391. {
  1392. if (m_parentScene.Permissions.CanEditObject(group, remoteClient))
  1393. {
  1394. bool physbuild = false;
  1395. if (group.RootPart.PhysActor is not null)
  1396. {
  1397. group.RootPart.PhysActor.Building = true;
  1398. physbuild = true;
  1399. }
  1400. group.GroupResize(scale);
  1401. if (physbuild)
  1402. group.RootPart.PhysActor.Building = false;
  1403. }
  1404. }
  1405. }
  1406. /// <summary>
  1407. /// This handles the nifty little tool tip that you get when you drag your mouse over an object
  1408. /// Send to the Object Group to process. We don't know enough to service the request
  1409. /// </summary>
  1410. /// <param name="remoteClient"></param>
  1411. /// <param name="AgentID"></param>
  1412. /// <param name="RequestFlags"></param>
  1413. /// <param name="ObjectID"></param>
  1414. protected internal void RequestObjectPropertiesFamily(
  1415. IClientAPI remoteClient, UUID AgentID, uint RequestFlags, UUID ObjectID)
  1416. {
  1417. SceneObjectGroup group = GetGroupByPrim(ObjectID);
  1418. group?.ServiceObjectPropertiesFamilyRequest(remoteClient, AgentID, RequestFlags);
  1419. }
  1420. /// <summary>
  1421. ///
  1422. /// </summary>
  1423. /// <param name="localID"></param>
  1424. /// <param name="rot"></param>
  1425. /// <param name="remoteClient"></param>
  1426. protected internal void UpdatePrimSingleRotation(uint localID, in Quaternion rot, IClientAPI remoteClient)
  1427. {
  1428. SceneObjectGroup group = GetGroupByPrim(localID);
  1429. if (group is not null)
  1430. {
  1431. if (m_parentScene.Permissions.CanMoveObject(group, remoteClient))
  1432. {
  1433. group.UpdateSingleRotation(rot, localID);
  1434. }
  1435. }
  1436. }
  1437. /// <summary>
  1438. ///
  1439. /// </summary>
  1440. /// <param name="localID"></param>
  1441. /// <param name="rot"></param>
  1442. /// <param name="remoteClient"></param>
  1443. protected internal void UpdatePrimSingleRotationPosition(uint localID, in Quaternion rot, in Vector3 pos, IClientAPI remoteClient)
  1444. {
  1445. SceneObjectGroup group = GetGroupByPrim(localID);
  1446. if (group is not null)
  1447. {
  1448. if (m_parentScene.Permissions.CanMoveObject(group, remoteClient))
  1449. {
  1450. group.UpdateSingleRotation(rot, pos, localID);
  1451. }
  1452. }
  1453. }
  1454. /// <summary>
  1455. /// Update the rotation of a whole group.
  1456. /// </summary>
  1457. /// <param name="localID"></param>
  1458. /// <param name="rot"></param>
  1459. /// <param name="remoteClient"></param>
  1460. protected internal void UpdatePrimGroupRotation(uint localID, in Quaternion rot, IClientAPI remoteClient)
  1461. {
  1462. SceneObjectGroup group = GetGroupByPrim(localID);
  1463. if (group is not null)
  1464. {
  1465. if (m_parentScene.Permissions.CanMoveObject(group, remoteClient))
  1466. {
  1467. group.UpdateGroupRotationR(rot);
  1468. }
  1469. }
  1470. }
  1471. /// <summary>
  1472. ///
  1473. /// </summary>
  1474. /// <param name="localID"></param>
  1475. /// <param name="pos"></param>
  1476. /// <param name="rot"></param>
  1477. /// <param name="remoteClient"></param>
  1478. protected internal void UpdatePrimGroupRotation(uint localID, in Vector3 pos, in Quaternion rot, IClientAPI remoteClient)
  1479. {
  1480. SceneObjectGroup group = GetGroupByPrim(localID);
  1481. if (group is not null)
  1482. {
  1483. if (m_parentScene.Permissions.CanMoveObject(group, remoteClient))
  1484. {
  1485. group.UpdateGroupRotationPR(pos, rot);
  1486. }
  1487. }
  1488. }
  1489. /// <summary>
  1490. /// Update the position of the given part
  1491. /// </summary>
  1492. /// <param name="localID"></param>
  1493. /// <param name="pos"></param>
  1494. /// <param name="remoteClient"></param>
  1495. protected internal void UpdatePrimSinglePosition(uint localID, in Vector3 pos, IClientAPI remoteClient)
  1496. {
  1497. SceneObjectGroup group = GetGroupByPrim(localID);
  1498. if (group is not null)
  1499. {
  1500. if (m_parentScene.Permissions.CanMoveObject(group, remoteClient) || group.IsAttachment)
  1501. {
  1502. group.UpdateSinglePosition(pos, localID);
  1503. }
  1504. }
  1505. }
  1506. /// <summary>
  1507. /// Update the position of the given group.
  1508. /// </summary>
  1509. /// <param name="localId"></param>
  1510. /// <param name="pos"></param>
  1511. /// <param name="remoteClient"></param>
  1512. public void UpdatePrimGroupPosition(uint localId, in Vector3 pos, IClientAPI remoteClient)
  1513. {
  1514. SceneObjectGroup group = GetGroupByPrim(localId);
  1515. if (group is not null)
  1516. {
  1517. if (group.IsAttachment || (group.RootPart.Shape.PCode == 9 && group.RootPart.Shape.State != 0))
  1518. {
  1519. // Set the new attachment point data in the object
  1520. byte attachmentPoint = (byte)group.AttachmentPoint;
  1521. group.UpdateGroupPosition(pos);
  1522. group.IsAttachment = false;
  1523. group.AbsolutePosition = group.RootPart.AttachedPos;
  1524. group.AttachmentPoint = attachmentPoint;
  1525. group.HasGroupChanged = true;
  1526. }
  1527. else
  1528. {
  1529. if (m_parentScene.Permissions.CanMoveObject(group, remoteClient)
  1530. && m_parentScene.Permissions.CanObjectEntry(group, false, pos))
  1531. {
  1532. group.UpdateGroupPosition(pos);
  1533. }
  1534. }
  1535. }
  1536. }
  1537. /// <summary>
  1538. /// Update the texture entry of the given prim.
  1539. /// </summary>
  1540. /// <remarks>
  1541. /// A texture entry is an object that contains details of all the textures of the prim's face. In this case,
  1542. /// the texture is given in its byte serialized form.
  1543. /// </remarks>
  1544. /// <param name="localID"></param>
  1545. /// <param name="texture"></param>
  1546. /// <param name="remoteClient"></param>
  1547. protected internal void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient)
  1548. {
  1549. SceneObjectPart part = GetSceneObjectPart(localID);
  1550. if(part is null)
  1551. return;
  1552. SceneObjectGroup group = part.ParentGroup;
  1553. if (m_parentScene.Permissions.CanEditObject(group, remoteClient))
  1554. {
  1555. part.UpdateTextureEntry(texture);
  1556. }
  1557. }
  1558. /// <summary>
  1559. /// Update the flags on a scene object. This covers properties such as phantom, physics and temporary.
  1560. /// </summary>
  1561. /// <remarks>
  1562. /// This is currently handling the incoming call from the client stack (e.g. LLClientView).
  1563. /// </remarks>
  1564. /// <param name="localID"></param>
  1565. /// <param name="UsePhysics"></param>
  1566. /// <param name="SetTemporary"></param>
  1567. /// <param name="SetPhantom"></param>
  1568. /// <param name="remoteClient"></param>
  1569. protected internal void UpdatePrimFlags(
  1570. uint localID, bool UsePhysics, bool SetTemporary, bool SetPhantom, in ExtraPhysicsData PhysData, IClientAPI remoteClient)
  1571. {
  1572. SceneObjectPart part = GetSceneObjectPart(localID);
  1573. if(part is null)
  1574. return;
  1575. SceneObjectGroup group = part.ParentGroup;
  1576. if (!m_parentScene.Permissions.CanEditObject(group, remoteClient))
  1577. return;
  1578. // VolumeDetect can't be set via UI and will always be off when a change is made there
  1579. // now only change volume dtc if phantom off
  1580. bool wantedPhys = UsePhysics;
  1581. if (PhysData.PhysShapeType == PhysShapeType.invalid) // check for extraPhysics data
  1582. {
  1583. bool vdtc;
  1584. if (SetPhantom) // if phantom keep volumedtc
  1585. vdtc = group.RootPart.VolumeDetectActive;
  1586. else // else turn it off
  1587. vdtc = false;
  1588. group.UpdateFlags(UsePhysics, SetTemporary, SetPhantom, vdtc);
  1589. }
  1590. else
  1591. {
  1592. part.UpdateExtraPhysics(PhysData);
  1593. remoteClient?.SendPartPhysicsProprieties(part);
  1594. }
  1595. if (wantedPhys != group.UsesPhysics && remoteClient is not null)
  1596. {
  1597. if(m_parentScene.m_linksetPhysCapacity != 0)
  1598. remoteClient.SendAlertMessage("Object physics cancelled because it exceeds limits for physical prims, either size or number of primswith shape type not set to None");
  1599. else
  1600. remoteClient.SendAlertMessage("Object physics cancelled because it exceeds size limits for physical prims");
  1601. group.RootPart.ScheduleFullUpdate();
  1602. }
  1603. }
  1604. /// <summary>
  1605. ///
  1606. /// </summary>
  1607. /// <param name="primLocalID"></param>
  1608. /// <param name="description"></param>
  1609. protected internal void PrimName(IClientAPI remoteClient, uint primLocalID, string name)
  1610. {
  1611. SceneObjectGroup group = GetGroupByPrim(primLocalID);
  1612. if (group is not null)
  1613. {
  1614. if (m_parentScene.Permissions.CanEditObject(group, remoteClient))
  1615. {
  1616. group.SetPartName(Util.CleanString(name), primLocalID);
  1617. group.HasGroupChanged = true;
  1618. }
  1619. }
  1620. }
  1621. /// <summary>
  1622. /// Handle a prim description set request from a viewer.
  1623. /// </summary>
  1624. /// <param name="primLocalID"></param>
  1625. /// <param name="description"></param>
  1626. protected internal void PrimDescription(IClientAPI remoteClient, uint primLocalID, string description)
  1627. {
  1628. SceneObjectGroup group = GetGroupByPrim(primLocalID);
  1629. if (group is not null)
  1630. {
  1631. if (m_parentScene.Permissions.CanEditObject(group, remoteClient))
  1632. {
  1633. group.SetPartDescription(Util.CleanString(description), primLocalID);
  1634. group.HasGroupChanged = true;
  1635. }
  1636. }
  1637. }
  1638. /// <summary>
  1639. /// Set a click action for the prim.
  1640. /// </summary>
  1641. /// <param name="remoteClient"></param>
  1642. /// <param name="primLocalID"></param>
  1643. /// <param name="clickAction"></param>
  1644. protected internal void PrimClickAction(IClientAPI remoteClient, uint primLocalID, string clickAction)
  1645. {
  1646. //m_log.DebugFormat(
  1647. // "[SCENEGRAPH]: User {0} set click action for {1} to {2}", remoteClient.Name, primLocalID, clickAction);
  1648. SceneObjectGroup group = GetGroupByPrim(primLocalID);
  1649. if (group is not null)
  1650. {
  1651. if (m_parentScene.Permissions.CanEditObject(group, remoteClient))
  1652. {
  1653. SceneObjectPart part = group.GetPart(primLocalID);
  1654. if (part is not null)
  1655. {
  1656. part.ClickAction = Convert.ToByte(clickAction);
  1657. group.HasGroupChanged = true;
  1658. }
  1659. }
  1660. }
  1661. }
  1662. protected internal void PrimMaterial(IClientAPI remoteClient, uint primLocalID, string material)
  1663. {
  1664. SceneObjectGroup group = GetGroupByPrim(primLocalID);
  1665. if (group is not null)
  1666. {
  1667. if (m_parentScene.Permissions.CanEditObject(group, remoteClient))
  1668. {
  1669. SceneObjectPart part = group.GetPart(primLocalID);
  1670. if (part is not null)
  1671. {
  1672. part.Material = Convert.ToByte(material);
  1673. group.HasGroupChanged = true;
  1674. remoteClient.SendPartPhysicsProprieties(part);
  1675. }
  1676. }
  1677. }
  1678. }
  1679. protected internal void UpdateExtraParam(UUID agentID, uint primLocalID, ushort type, bool inUse, byte[] data)
  1680. {
  1681. SceneObjectGroup group = GetGroupByPrim(primLocalID);
  1682. if (group is not null)
  1683. {
  1684. if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
  1685. {
  1686. group.UpdateExtraParam(primLocalID, type, inUse, data);
  1687. }
  1688. }
  1689. }
  1690. /// <summary>
  1691. ///
  1692. /// </summary>
  1693. /// <param name="primLocalID"></param>
  1694. /// <param name="shapeBlock"></param>
  1695. protected internal void UpdatePrimShape(UUID agentID, uint primLocalID, UpdateShapeArgs shapeBlock)
  1696. {
  1697. SceneObjectGroup group = GetGroupByPrim(primLocalID);
  1698. if (group is not null)
  1699. {
  1700. if (m_parentScene.Permissions.CanEditObject(group.UUID, agentID))
  1701. {
  1702. ObjectShapePacket.ObjectDataBlock shapeData = new()
  1703. {
  1704. ObjectLocalID = shapeBlock.ObjectLocalID,
  1705. PathBegin = shapeBlock.PathBegin,
  1706. PathCurve = shapeBlock.PathCurve,
  1707. PathEnd = shapeBlock.PathEnd,
  1708. PathRadiusOffset = shapeBlock.PathRadiusOffset,
  1709. PathRevolutions = shapeBlock.PathRevolutions,
  1710. PathScaleX = shapeBlock.PathScaleX,
  1711. PathScaleY = shapeBlock.PathScaleY,
  1712. PathShearX = shapeBlock.PathShearX,
  1713. PathShearY = shapeBlock.PathShearY,
  1714. PathSkew = shapeBlock.PathSkew,
  1715. PathTaperX = shapeBlock.PathTaperX,
  1716. PathTaperY = shapeBlock.PathTaperY,
  1717. PathTwist = shapeBlock.PathTwist,
  1718. PathTwistBegin = shapeBlock.PathTwistBegin,
  1719. ProfileBegin = shapeBlock.ProfileBegin,
  1720. ProfileCurve = shapeBlock.ProfileCurve,
  1721. ProfileEnd = shapeBlock.ProfileEnd,
  1722. ProfileHollow = shapeBlock.ProfileHollow
  1723. };
  1724. group.UpdateShape(shapeData, primLocalID);
  1725. }
  1726. }
  1727. }
  1728. /// <summary>
  1729. /// Initial method invoked when we receive a link objects request from the client.
  1730. /// </summary>
  1731. /// <param name="client"></param>
  1732. /// <param name="parentPrim"></param>
  1733. /// <param name="childPrims"></param>
  1734. protected internal void LinkObjects(SceneObjectPart root, List<SceneObjectPart> children)
  1735. {
  1736. if (root.KeyframeMotion is not null)
  1737. {
  1738. root.KeyframeMotion.Stop();
  1739. root.KeyframeMotion = null;
  1740. }
  1741. SceneObjectGroup parentGroup = root.ParentGroup;
  1742. if (parentGroup is null) return;
  1743. // Cowardly refuse to link to a group owned root
  1744. if (parentGroup.OwnerID == parentGroup.GroupID)
  1745. return;
  1746. Monitor.Enter(m_linkLock);
  1747. try
  1748. {
  1749. List<SceneObjectGroup> childGroups = new();
  1750. // We do this in reverse to get the link order of the prims correct
  1751. foreach (SceneObjectPart childpart in CollectionsMarshal.AsSpan(children))
  1752. {
  1753. SceneObjectGroup child = childpart.ParentGroup;
  1754. // Don't try and add a group to itself - this will only cause severe problems later on.
  1755. if (child == parentGroup)
  1756. continue;
  1757. // Make sure no child prim is set for sale
  1758. // So that, on delink, no prims are unwittingly
  1759. // left for sale and sold off
  1760. if (child is not null)
  1761. {
  1762. child.RootPart.ObjectSaleType = 0;
  1763. child.RootPart.SalePrice = 10;
  1764. childGroups.Add(child);
  1765. }
  1766. }
  1767. foreach (SceneObjectGroup child in CollectionsMarshal.AsSpan(childGroups))
  1768. {
  1769. if (parentGroup.OwnerID == child.OwnerID)
  1770. {
  1771. child.DetachFromBackup();
  1772. parentGroup.LinkToGroup(child);
  1773. // this is here so physics gets updated!
  1774. // Don't remove! Bad juju! Stay away! or fix physics!
  1775. // already done in LinkToGroup
  1776. // child.AbsolutePosition = child.AbsolutePosition;
  1777. }
  1778. }
  1779. // We need to explicitly resend the newly link prim's object properties since no other actions
  1780. // occur on link to invoke this elsewhere (such as object selection)
  1781. if (childGroups.Count > 0)
  1782. {
  1783. //parentGroup.RootPart.CreateSelected = true;
  1784. parentGroup.TriggerScriptChangedEvent(Changed.LINK);
  1785. }
  1786. }
  1787. finally
  1788. {
  1789. /*
  1790. lock (SceneObjectGroupsByLocalPartID)
  1791. {
  1792. foreach (SceneObjectPart part in parentGroup.Parts)
  1793. SceneObjectGroupsByLocalPartID[part.LocalId] = parentGroup;
  1794. }
  1795. */
  1796. parentGroup.AdjustChildPrimPermissions(false);
  1797. parentGroup.HasGroupChanged = true;
  1798. parentGroup.ScheduleGroupForFullAnimUpdate();
  1799. Monitor.Exit(m_linkLock);
  1800. }
  1801. }
  1802. /// <summary>
  1803. /// Delink a linkset
  1804. /// </summary>
  1805. /// <param name="prims"></param>
  1806. protected internal void DelinkObjects(List<SceneObjectPart> prims)
  1807. {
  1808. List<SceneObjectPart> childParts = new();
  1809. List<SceneObjectPart> rootParts = new();
  1810. List<SceneObjectGroup> affectedGroups = new();
  1811. // Look them all up in one go, since that is comparatively expensive
  1812. //
  1813. Monitor.Enter(m_linkLock);
  1814. try
  1815. {
  1816. foreach (SceneObjectPart part in CollectionsMarshal.AsSpan(prims))
  1817. {
  1818. if(part is null)
  1819. continue;
  1820. SceneObjectGroup parentSOG = part.ParentGroup;
  1821. if(parentSOG is null || parentSOG.IsDeleted || parentSOG.inTransit || parentSOG.PrimCount == 1)
  1822. continue;
  1823. if (!affectedGroups.Contains(parentSOG))
  1824. {
  1825. affectedGroups.Add(parentSOG);
  1826. if(parentSOG.RootPart.PhysActor is not null)
  1827. parentSOG.RootPart.PhysActor.Building = true;
  1828. }
  1829. if (part.KeyframeMotion is not null)
  1830. {
  1831. part.KeyframeMotion.Stop();
  1832. part.KeyframeMotion = null;
  1833. }
  1834. if (part.LinkNum < 2) // Root
  1835. {
  1836. rootParts.Add(part);
  1837. }
  1838. else
  1839. {
  1840. part.LastOwnerID = part.ParentGroup.RootPart.LastOwnerID;
  1841. part.RezzerID = part.ParentGroup.RootPart.RezzerID;
  1842. childParts.Add(part);
  1843. }
  1844. }
  1845. if (childParts.Count > 0)
  1846. {
  1847. foreach (SceneObjectPart child in CollectionsMarshal.AsSpan(childParts))
  1848. {
  1849. // Unlink all child parts from their groups
  1850. child.ParentGroup.DelinkFromGroup(child, true);
  1851. //child.ParentGroup is now other
  1852. child.ParentGroup.HasGroupChanged = true;
  1853. child.ParentGroup.ScheduleGroupForFullAnimUpdate();
  1854. }
  1855. }
  1856. foreach (SceneObjectPart root in CollectionsMarshal.AsSpan(rootParts))
  1857. {
  1858. // In most cases, this will run only one time, and the prim
  1859. // will be a solo prim
  1860. // However, editing linked parts and unlinking may be different
  1861. //
  1862. SceneObjectGroup group = root.ParentGroup;
  1863. List<SceneObjectPart> newSet = new(group.Parts);
  1864. newSet.Remove(root);
  1865. int numChildren = newSet.Count;
  1866. if(numChildren == 0)
  1867. break;
  1868. foreach (SceneObjectPart p in newSet)
  1869. group.DelinkFromGroup(p, false);
  1870. SceneObjectPart newRoot = newSet[0];
  1871. // If there is more than one prim remaining, we
  1872. // need to re-link
  1873. //
  1874. if (numChildren > 1)
  1875. {
  1876. // Determine new root
  1877. //
  1878. newSet.RemoveAt(0);
  1879. foreach (SceneObjectPart newChild in CollectionsMarshal.AsSpan(newSet))
  1880. newChild.ClearUpdateSchedule();
  1881. LinkObjects(newRoot, newSet);
  1882. }
  1883. else
  1884. {
  1885. newRoot.TriggerScriptChangedEvent(Changed.LINK);
  1886. newRoot.ParentGroup.HasGroupChanged = true;
  1887. newRoot.ParentGroup.InvalidatePartsLinkMaps();
  1888. newRoot.ParentGroup.ScheduleGroupForFullAnimUpdate();
  1889. }
  1890. }
  1891. // trigger events in the roots
  1892. //
  1893. foreach (SceneObjectGroup g in CollectionsMarshal.AsSpan(affectedGroups))
  1894. {
  1895. if(g.RootPart.PhysActor is not null)
  1896. g.RootPart.PhysActor.Building = false;
  1897. g.AdjustChildPrimPermissions(false);
  1898. // Child prims that have been unlinked and deleted will
  1899. // return unless the root is deleted. This will remove them
  1900. // from the database. They will be rewritten immediately,
  1901. // minus the rows for the unlinked child prims.
  1902. m_parentScene.SimulationDataService.RemoveObject(g.UUID, m_parentScene.RegionInfo.RegionID);
  1903. g.InvalidatePartsLinkMaps();
  1904. g.TriggerScriptChangedEvent(Changed.LINK);
  1905. g.HasGroupChanged = true; // Persist
  1906. g.ScheduleGroupForFullUpdate();
  1907. }
  1908. }
  1909. finally
  1910. {
  1911. Monitor.Exit(m_linkLock);
  1912. }
  1913. }
  1914. protected internal void MakeObjectSearchable(IClientAPI remoteClient, bool IncludeInSearch, uint localID)
  1915. {
  1916. SceneObjectGroup sog = GetGroupByPrim(localID);
  1917. if(sog is null)
  1918. return;
  1919. //Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
  1920. //aka ObjectFlags.JointWheel = IncludeInSearch
  1921. //Permissions model: Object can be REMOVED from search IFF:
  1922. // * User owns object
  1923. //use CanEditObject
  1924. //Object can be ADDED to search IFF:
  1925. // * User owns object
  1926. // * Asset/DRM permission bit "modify" is enabled
  1927. //use CanEditObjectPosition
  1928. // libomv will complain about PrimFlags.JointWheel being
  1929. // deprecated, so we
  1930. if (IncludeInSearch && m_parentScene.Permissions.CanEditObject(sog, remoteClient))
  1931. {
  1932. sog.RootPart.AddFlag(PrimFlags.JointWheel);
  1933. sog.HasGroupChanged = true;
  1934. }
  1935. else if (!IncludeInSearch && m_parentScene.Permissions.CanMoveObject(sog, remoteClient))
  1936. {
  1937. sog.RootPart.RemFlag(PrimFlags.JointWheel);
  1938. sog.HasGroupChanged = true;
  1939. }
  1940. }
  1941. /// <summary>
  1942. /// Duplicate the given object.
  1943. /// </summary>
  1944. /// <param name="originalPrim"></param>
  1945. /// <param name="offset"></param>
  1946. /// <param name="flags"></param>
  1947. /// <param name="AgentID"></param>
  1948. /// <param name="GroupID"></param>
  1949. /// <param name="rot"></param>
  1950. /// <returns>null if duplication fails, otherwise the duplicated object</returns>
  1951. /// <summary>
  1952. public SceneObjectGroup DuplicateObject(uint originalPrimID, Vector3 offset, UUID AgentID, UUID GroupID, Quaternion rot, bool createSelected)
  1953. {
  1954. // m_log.DebugFormat(
  1955. // "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
  1956. // originalPrimID, offset, AgentID);
  1957. SceneObjectGroup original = GetGroupByPrim(originalPrimID);
  1958. if (original is not null)
  1959. {
  1960. if (m_parentScene.Permissions.CanDuplicateObject(original, AgentID))
  1961. {
  1962. SceneObjectGroup copy = original.Copy(true);
  1963. copy.AbsolutePosition += offset;
  1964. copy.RootPart.Rezzed = DateTime.UtcNow;
  1965. copy.RootPart.RezzerID = AgentID;
  1966. ReadOnlySpan<SceneObjectPart> parts = copy.Parts.AsSpan();
  1967. if (original.OwnerID.NotEqual(AgentID))
  1968. {
  1969. copy.SetOwner(AgentID, GroupID);
  1970. if (m_parentScene.Permissions.PropagatePermissions())
  1971. {
  1972. foreach (SceneObjectPart child in parts)
  1973. {
  1974. child.Inventory.ChangeInventoryOwner(AgentID);
  1975. child.TriggerScriptChangedEvent(Changed.OWNER);
  1976. child.ApplyNextOwnerPermissions();
  1977. }
  1978. copy.InvalidateEffectivePerms();
  1979. }
  1980. }
  1981. bool entered = false;
  1982. try
  1983. {
  1984. try { }
  1985. finally
  1986. {
  1987. m_scenePartsLock.EnterWriteLock();
  1988. entered = true;
  1989. }
  1990. Entities.Add(copy);
  1991. m_scenePartsArray = null;
  1992. foreach (SceneObjectPart part in parts)
  1993. {
  1994. if (!m_scenePartsByID.ContainsKey(part.UUID))
  1995. {
  1996. if (part.GetPrimType() == PrimType.SCULPT)
  1997. m_numMesh++;
  1998. else
  1999. m_numPrim++;
  2000. m_scenePartsByID[part.UUID] = part;
  2001. m_scenePartsByLocalID[part.LocalId] = part;
  2002. }
  2003. }
  2004. }
  2005. finally
  2006. {
  2007. if(entered)
  2008. m_scenePartsLock.ExitWriteLock();
  2009. }
  2010. copy.IsSelected = createSelected;
  2011. if (rot != Quaternion.Identity)
  2012. copy.UpdateGroupRotationR(rot);
  2013. // required for physics to update it's position
  2014. copy.ResetChildPrimPhysicsPositions();
  2015. copy.CreateScriptInstances(0, false, m_parentScene.DefaultScriptEngine, 1);
  2016. copy.ResumeScripts();
  2017. copy.HasGroupChanged = true;
  2018. copy.ScheduleGroupForUpdate(PrimUpdateFlags.FullUpdatewithAnimMatOvr);
  2019. return copy;
  2020. }
  2021. }
  2022. else
  2023. {
  2024. m_log.Warn($"[SCENE]: Attempted to duplicate nonexistant prim id {GroupID}");
  2025. }
  2026. return null;
  2027. }
  2028. #endregion
  2029. }
  2030. }