2007-12-27 21:41:48 +00:00
/ *
2008-03-18 05:16:43 +00:00
* Copyright ( c ) Contributors , http : //opensimulator.org/
* See CONTRIBUTORS . TXT for a full list of copyright holders .
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions are met :
* * Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* * Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
2009-06-01 06:37:14 +00:00
* * Neither the name of the OpenSimulator Project nor the
2008-03-18 05:16:43 +00:00
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission .
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ` ` AS IS ' ' AND ANY
* EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED . IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES
* ( INCLUDING , BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ;
* LOSS OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* /
2007-12-11 01:26:06 +00:00
using System ;
2009-12-06 00:25:04 +00:00
using System.Threading ;
2007-11-04 14:34:45 +00:00
using System.Collections.Generic ;
2018-12-28 13:52:59 +00:00
using System.Collections.Concurrent ;
2008-04-21 07:09:17 +00:00
using System.Reflection ;
2008-09-06 07:52:41 +00:00
using OpenMetaverse ;
using OpenMetaverse.Packets ;
2008-04-21 07:09:17 +00:00
using log4net ;
2007-11-04 14:34:45 +00:00
using OpenSim.Framework ;
2009-02-06 16:55:34 +00:00
using OpenSim.Region.Framework.Scenes.Types ;
2015-08-31 04:05:36 +00:00
using OpenSim.Region.PhysicsModules.SharedBase ;
2010-01-30 17:23:07 +00:00
using OpenSim.Region.Framework.Interfaces ;
2007-11-04 14:34:45 +00:00
2009-02-06 16:55:34 +00:00
namespace OpenSim.Region.Framework.Scenes
2007-11-04 14:34:45 +00:00
{
2007-11-28 06:18:07 +00:00
public delegate void PhysicsCrash ( ) ;
2010-06-25 21:25:39 +00:00
public delegate void AttachToBackupDelegate ( SceneObjectGroup sog ) ;
public delegate void DetachFromBackupDelegate ( SceneObjectGroup sog ) ;
2010-06-25 21:39:15 +00:00
public delegate void ChangedBackupDelegate ( SceneObjectGroup sog ) ;
2008-11-12 20:16:46 +00:00
/// <summary>
/// This class used to be called InnerScene and may not yet truly be a SceneGraph. The non scene graph components
/// should be migrated out over time.
/// </summary>
public class SceneGraph
2007-11-04 14:34:45 +00:00
{
2008-04-21 07:09:17 +00:00
private static readonly ILog m_log = LogManager . GetLogger ( MethodBase . GetCurrentMethod ( ) . DeclaringType ) ;
2008-02-05 19:44:27 +00:00
2007-11-28 06:18:07 +00:00
#region Events
2007-12-27 21:41:48 +00:00
2008-05-26 01:06:50 +00:00
protected internal event PhysicsCrash UnRecoverableError ;
2008-05-01 18:04:42 +00:00
private PhysicsCrash handlerPhysicsCrash = null ;
2010-06-25 21:25:39 +00:00
public event AttachToBackupDelegate OnAttachToBackup ;
public event DetachFromBackupDelegate OnDetachFromBackup ;
2010-06-25 21:39:15 +00:00
public event ChangedBackupDelegate OnChangeBackup ;
2009-01-06 15:14:15 +00:00
2007-11-28 06:18:07 +00:00
# endregion
2007-11-04 22:22:53 +00:00
#region Fields
2007-12-27 21:41:48 +00:00
2009-10-23 08:02:36 +00:00
2008-11-24 14:45:05 +00:00
protected internal EntityManager Entities = new EntityManager ( ) ;
2008-05-01 18:04:42 +00:00
2019-01-06 20:10:43 +00:00
private Dictionary < UUID , SceneObjectPart > m_scenePartsByID = new Dictionary < UUID , SceneObjectPart > ( 1024 ) ;
private Dictionary < uint , SceneObjectPart > m_scenePartsByLocalID = new Dictionary < uint , SceneObjectPart > ( 1024 ) ;
private SceneObjectPart [ ] m_scenePartsArray ;
private Dictionary < UUID , ScenePresence > m_scenePresenceMap = new Dictionary < UUID , ScenePresence > ( ) ;
private Dictionary < uint , ScenePresence > m_scenePresenceLocalIDMap = new Dictionary < uint , ScenePresence > ( ) ;
private Dictionary < UUID , SceneObjectGroup > m_updateList = new Dictionary < UUID , SceneObjectGroup > ( ) ;
private List < ScenePresence > m_scenePresenceList ;
2007-11-04 22:22:53 +00:00
2019-01-06 20:10:43 +00:00
private Scene m_parentScene ;
private PhysicsScene _PhyScene ;
2008-02-06 08:03:22 +00:00
2019-01-06 20:10:43 +00:00
private int m_numRootAgents = 0 ;
private int m_numTotalPrim = 0 ;
private int m_numPrim = 0 ;
private int m_numMesh = 0 ;
private int m_numChildAgents = 0 ;
private int m_physicalPrim = 0 ;
2017-01-05 19:07:37 +00:00
2019-01-06 20:10:43 +00:00
private int m_activeScripts = 0 ;
private int m_scriptLPS = 0 ;
2009-04-12 15:18:04 +00:00
2012-04-17 22:54:51 +00:00
/// <summary>
2012-05-08 20:31:35 +00:00
/// Lock to prevent object group update, linking, delinking and duplication operations from running concurrently.
2012-04-17 22:54:51 +00:00
/// </summary>
2012-05-08 20:31:35 +00:00
/// <remarks>
/// These operations rely on the parts composition of the object. If allowed to run concurrently then race
/// conditions can occur.
/// </remarks>
2009-12-06 00:25:04 +00:00
private Object m_updateLock = new Object ( ) ;
2019-01-25 03:19:48 +00:00
private Object m_linkLock = new Object ( ) ;
2019-01-06 20:10:43 +00:00
private System . Threading . ReaderWriterLockSlim m_scenePresencesLock ;
private System . Threading . ReaderWriterLockSlim m_scenePartsLock ;
2009-12-06 00:25:04 +00:00
2007-11-04 22:22:53 +00:00
# endregion
2007-11-04 14:34:45 +00:00
2011-09-12 21:51:56 +00:00
protected internal SceneGraph ( Scene parent )
2007-11-04 14:34:45 +00:00
{
2019-01-01 13:16:35 +00:00
m_scenePresencesLock = new System . Threading . ReaderWriterLockSlim ( ) ;
2019-01-06 20:10:43 +00:00
m_scenePartsLock = new System . Threading . ReaderWriterLockSlim ( ) ;
2007-11-04 14:34:45 +00:00
m_parentScene = parent ;
2019-01-06 20:10:43 +00:00
m_scenePresenceList = null ;
m_scenePartsArray = null ;
}
~ SceneGraph ( )
{
m_scenePartsLock . Dispose ( ) ;
m_scenePresencesLock . Dispose ( ) ;
2007-11-28 06:18:07 +00:00
}
2007-12-06 18:17:44 +00:00
2007-11-29 15:27:57 +00:00
public PhysicsScene PhysicsScene
2007-11-28 06:18:07 +00:00
{
2017-01-05 19:07:37 +00:00
get
2015-08-31 21:09:15 +00:00
{
if ( _PhyScene = = null )
_PhyScene = m_parentScene . RequestModuleInterface < PhysicsScene > ( ) ;
2017-01-05 19:07:37 +00:00
return _PhyScene ;
2015-08-31 21:09:15 +00:00
}
2007-11-28 06:18:07 +00:00
set
{
// If we're not doing the initial set
2008-05-16 01:22:11 +00:00
// Then we've got to remove the previous
2007-11-28 06:18:07 +00:00
// event handler
2008-08-18 00:39:10 +00:00
if ( _PhyScene ! = null )
2007-12-27 21:41:48 +00:00
_PhyScene . OnPhysicsCrash - = physicsBasedCrash ;
2007-11-28 06:18:07 +00:00
_PhyScene = value ;
2007-12-27 21:41:48 +00:00
2008-07-21 13:40:08 +00:00
if ( _PhyScene ! = null )
_PhyScene . OnPhysicsCrash + = physicsBasedCrash ;
2007-11-28 06:18:07 +00:00
}
2007-11-04 14:34:45 +00:00
}
2008-05-26 01:06:50 +00:00
protected internal void Close ( )
2007-11-04 14:34:45 +00:00
{
2019-01-06 01:44:37 +00:00
bool entered = false ;
2010-05-12 15:25:40 +00:00
try
2008-05-07 22:59:30 +00:00
{
2019-01-06 01:44:37 +00:00
try { }
finally
{
m_scenePresencesLock . EnterWriteLock ( ) ;
entered = true ;
}
2019-01-06 20:10:43 +00:00
m_scenePresenceMap = new Dictionary < UUID , ScenePresence > ( ) ;
m_scenePresenceLocalIDMap = new Dictionary < uint , ScenePresence > ( ) ;
m_scenePresenceList = null ;
2008-05-07 22:59:30 +00:00
}
2010-05-12 15:25:40 +00:00
finally
{
2019-01-06 20:10:43 +00:00
if ( entered )
2019-01-06 01:44:37 +00:00
m_scenePresencesLock . ExitWriteLock ( ) ;
2008-05-07 22:59:30 +00:00
}
2009-10-23 08:02:36 +00:00
2019-01-06 20:10:43 +00:00
entered = false ;
try
{
try { }
finally
{
m_scenePartsLock . EnterWriteLock ( ) ;
entered = true ;
}
2008-05-16 01:22:11 +00:00
2019-01-06 20:10:43 +00:00
Entities . Clear ( ) ;
m_scenePartsArray = null ;
m_scenePartsByID = new Dictionary < UUID , SceneObjectPart > ( ) ;
m_scenePartsByLocalID = new Dictionary < uint , SceneObjectPart > ( ) ;
if ( _PhyScene ! = null )
_PhyScene . OnPhysicsCrash - = physicsBasedCrash ;
_PhyScene = null ;
}
finally
{
if ( entered )
m_scenePartsLock . ExitWriteLock ( ) ;
}
2007-11-04 14:34:45 +00:00
}
2007-11-04 22:22:53 +00:00
#region Update Methods
2007-12-27 21:41:48 +00:00
2008-05-26 01:06:50 +00:00
protected internal void UpdatePreparePhysics ( )
2007-11-04 22:22:53 +00:00
{
}
2011-10-05 23:45:25 +00:00
/// <summary>
/// Update the position of all the scene presences.
/// </summary>
/// <remarks>
/// Called only from the main scene loop.
/// </remarks>
2008-05-26 01:06:50 +00:00
protected internal void UpdatePresences ( )
2008-02-20 00:08:04 +00:00
{
2010-03-17 13:40:00 +00:00
ForEachScenePresence ( delegate ( ScenePresence presence )
{
presence . Update ( ) ;
} ) ;
2008-02-20 00:08:04 +00:00
}
2018-12-28 13:52:59 +00:00
protected internal void UpdateScenePresenceMovement ( )
{
ForEachScenePresence ( delegate ( ScenePresence presence )
{
presence . UpdateMovement ( ) ;
} ) ;
}
2011-10-05 21:08:56 +00:00
/// <summary>
/// Perform a physics frame update.
/// </summary>
/// <param name="elapsed"></param>
/// <returns></returns>
2008-05-26 01:06:50 +00:00
protected internal float UpdatePhysics ( double elapsed )
2007-11-04 22:22:53 +00:00
{
2018-12-28 13:52:59 +00:00
if ( PhysicsScene ! = null )
return PhysicsScene . Simulate ( ( float ) elapsed ) ;
return 0 ;
2007-11-04 22:22:53 +00:00
}
2015-10-22 16:34:28 +00:00
protected internal void ProcessPhysicsPreSimulation ( )
{
if ( PhysicsScene ! = null )
PhysicsScene . ProcessPreSimulation ( ) ;
}
2010-06-08 23:30:51 +00:00
public void GetCoarseLocations ( out List < Vector3 > coarseLocations , out List < UUID > avatarUUIDs , uint maxLocations )
{
coarseLocations = new List < Vector3 > ( ) ;
avatarUUIDs = new List < UUID > ( ) ;
2016-07-03 14:47:20 +00:00
// coarse locations are sent as BYTE, so limited to the 255m max of normal regions
// try to work around that scale down X and Y acording to region size, so reducing the resolution
2017-01-05 19:07:37 +00:00
/ /
2016-07-03 14:47:20 +00:00
// viewers need to scale up
2016-11-09 22:12:27 +00:00
float scaleX = ( float ) m_parentScene . RegionInfo . RegionSizeX / ( float ) Constants . RegionSize ;
2016-07-03 14:47:20 +00:00
if ( scaleX = = 0 )
scaleX = 1.0f ;
scaleX = 1.0f / scaleX ;
2016-11-09 22:12:27 +00:00
float scaleY = ( float ) m_parentScene . RegionInfo . RegionSizeY / ( float ) Constants . RegionSize ;
2016-07-03 14:47:20 +00:00
if ( scaleY = = 0 )
scaleY = 1.0f ;
scaleY = 1.0f / scaleY ;
2010-06-08 23:30:51 +00:00
List < ScenePresence > presences = GetScenePresences ( ) ;
2019-01-06 20:10:43 +00:00
int len = presences . Count ;
if ( len > maxLocations )
len = ( int ) maxLocations ;
ScenePresence sp ;
for ( int i = 0 ; i < len ; + + i )
2010-06-08 23:30:51 +00:00
{
2019-01-06 20:10:43 +00:00
sp = presences [ i ] ;
2017-01-05 19:07:37 +00:00
2010-06-08 23:30:51 +00:00
// If this presence is a child agent, we don't want its coarse locations
if ( sp . IsChildAgent )
2011-02-24 22:33:54 +00:00
continue ;
2016-07-03 14:47:20 +00:00
Vector3 pos = sp . AbsolutePosition ;
pos . X * = scaleX ;
pos . Y * = scaleY ;
2010-06-08 23:30:51 +00:00
2016-07-03 14:47:20 +00:00
coarseLocations . Add ( pos ) ;
2012-03-09 02:38:11 +00:00
avatarUUIDs . Add ( sp . UUID ) ;
2010-06-08 23:30:51 +00:00
}
}
2007-11-04 22:22:53 +00:00
# endregion
#region Entity Methods
2007-12-27 21:41:48 +00:00
2008-05-24 22:10:14 +00:00
/// <summary>
/// Add an object into the scene that has come from storage
/// </summary>
/// <param name="sceneObject"></param>
2008-06-27 14:15:14 +00:00
/// <param name="attachToBackup">
/// If true, changes to the object will be reflected in its persisted data
/// If false, the persisted data will not be changed even if the object in the scene is changed
/// </param>
2008-07-13 00:18:29 +00:00
/// <param name="alreadyPersisted">
/// If true, we won't persist this object until it changes
/// If false, we'll persist this object immediately
/// </param>
2010-06-08 14:07:57 +00:00
/// <param name="sendClientUpdates">
/// If true, we send updates to the client to tell it about this object
/// If false, we leave it up to the caller to do this
/// </param>
2008-07-12 22:14:38 +00:00
/// <returns>
/// true if the object was added, false if an object with the same uuid was already in the scene
2008-08-18 00:39:10 +00:00
/// </returns>
2008-07-13 00:18:29 +00:00
protected internal bool AddRestoredSceneObject (
2010-06-08 14:07:57 +00:00
SceneObjectGroup sceneObject , bool attachToBackup , bool alreadyPersisted , bool sendClientUpdates )
2007-11-04 14:34:45 +00:00
{
2016-07-27 23:48:12 +00:00
// temporary checks to remove after varsize suport
float regionSizeX = m_parentScene . RegionInfo . RegionSizeX ;
float regionSizeY = m_parentScene . RegionInfo . RegionSizeY ;
// KF: Check for out-of-region, move inside and make static.
2019-01-06 20:10:43 +00:00
Vector3 npos = sceneObject . RootPart . GroupPosition ;
2016-07-27 23:48:12 +00:00
bool clampZ = m_parentScene . ClampNegativeZ ;
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 ) | |
npos . X > regionSizeX | |
npos . Y > regionSizeY ) )
2010-07-21 10:31:59 +00:00
{
2016-07-27 23:48:12 +00:00
if ( npos . X < 0.0 ) npos . X = 1.0f ;
if ( npos . Y < 0.0 ) npos . Y = 1.0f ;
if ( npos . Z < 0.0 & & clampZ ) npos . Z = 0.0f ;
if ( npos . X > regionSizeX ) npos . X = regionSizeX - 1.0f ;
if ( npos . Y > regionSizeY ) npos . Y = regionSizeY - 1.0f ;
SceneObjectPart rootpart = sceneObject . RootPart ;
rootpart . GroupPosition = npos ;
foreach ( SceneObjectPart part in sceneObject . Parts )
2009-12-25 00:19:44 +00:00
{
2016-07-27 23:48:12 +00:00
if ( part = = rootpart )
continue ;
part . GroupPosition = npos ;
2009-12-25 00:19:44 +00:00
}
2016-07-27 23:48:12 +00:00
rootpart . Velocity = Vector3 . Zero ;
rootpart . AngularVelocity = Vector3 . Zero ;
rootpart . Acceleration = Vector3 . Zero ;
2010-07-21 10:31:59 +00:00
}
2014-09-22 13:44:47 +00:00
bool ret = AddSceneObject ( sceneObject , attachToBackup , sendClientUpdates ) ;
2010-11-16 21:01:56 +00:00
if ( attachToBackup & & ( ! alreadyPersisted ) )
2008-07-13 00:18:29 +00:00
{
sceneObject . ForceInventoryPersistence ( ) ;
sceneObject . HasGroupChanged = true ;
}
2017-05-04 10:37:13 +00:00
sceneObject . InvalidateDeepEffectivePerms ( ) ;
2014-09-22 13:44:47 +00:00
return ret ;
2007-11-04 14:34:45 +00:00
}
2017-01-05 19:07:37 +00:00
2008-06-27 14:25:36 +00:00
/// <summary>
/// Add a newly created object to the scene. This will both update the scene, and send information about the
/// new object to all clients interested in the scene.
/// </summary>
/// <param name="sceneObject"></param>
/// <param name="attachToBackup">
/// If true, the object is made persistent into the scene.
/// If false, the object will not persist over server restarts
/// </param>
2008-07-12 22:14:38 +00:00
/// <returns>
/// true if the object was added, false if an object with the same uuid was already in the scene
2008-08-18 00:39:10 +00:00
/// </returns>
2010-03-03 22:14:06 +00:00
protected internal bool AddNewSceneObject ( SceneObjectGroup sceneObject , bool attachToBackup , bool sendClientUpdates )
2008-08-18 00:39:10 +00:00
{
2014-09-22 13:44:47 +00:00
bool ret = AddSceneObject ( sceneObject , attachToBackup , sendClientUpdates ) ;
// Ensure that we persist this new scene object if it's not an
2010-11-16 21:01:56 +00:00
// attachment
2014-09-22 13:44:47 +00:00
2010-11-16 21:01:56 +00:00
if ( attachToBackup )
sceneObject . HasGroupChanged = true ;
2008-08-18 00:39:10 +00:00
2014-09-22 13:44:47 +00:00
return ret ;
2008-06-27 14:25:36 +00:00
}
2017-01-05 19:07:37 +00:00
2010-08-24 22:25:19 +00:00
/// <summary>
/// Add a newly created object to the scene.
/// </summary>
2017-01-05 19:07:37 +00:00
///
2010-08-24 22:25:19 +00:00
/// This method does not send updates to the client - callers need to handle this themselves.
2012-01-19 10:53:21 +00:00
/// Caller should also trigger EventManager.TriggerObjectAddedToScene
2010-08-24 22:25:19 +00:00
/// <param name="sceneObject"></param>
/// <param name="attachToBackup"></param>
2011-05-20 23:02:53 +00:00
/// <param name="pos">Position of the object. If null then the position stored in the object is used.</param>
/// <param name="rot">Rotation of the object. If null then the rotation stored in the object is used.</param>
2010-08-24 22:25:19 +00:00
/// <param name="vel">Velocity of the object. This parameter only has an effect if the object is physical</param>
2010-09-12 17:43:49 +00:00
/// <returns></returns>
2010-08-24 22:25:19 +00:00
public bool AddNewSceneObject (
2011-05-20 23:02:53 +00:00
SceneObjectGroup sceneObject , bool attachToBackup , Vector3 ? pos , Quaternion ? rot , Vector3 vel )
2010-08-24 22:25:19 +00:00
{
2011-05-20 23:02:53 +00:00
if ( pos ! = null )
sceneObject . AbsolutePosition = ( Vector3 ) pos ;
2010-08-24 22:25:19 +00:00
2017-06-06 19:38:17 +00:00
if ( rot ! = null )
sceneObject . UpdateGroupRotationR ( ( Quaternion ) rot ) ;
AddNewSceneObject ( sceneObject , attachToBackup , false ) ;
2010-08-24 22:25:19 +00:00
if ( sceneObject . RootPart . Shape . PCode = = ( byte ) PCode . Prim )
{
sceneObject . ClearPartAttachmentData ( ) ;
}
2011-05-20 23:02:53 +00:00
2012-04-03 04:50:13 +00:00
PhysicsActor pa = sceneObject . RootPart . PhysActor ;
if ( pa ! = null & & pa . IsPhysical & & vel ! = Vector3 . Zero )
2010-08-24 22:25:19 +00:00
{
sceneObject . RootPart . ApplyImpulse ( ( vel * sceneObject . GetMass ( ) ) , false ) ;
}
2012-04-26 15:17:46 +00:00
2010-08-24 22:25:19 +00:00
return true ;
2010-09-12 17:43:49 +00:00
}
2007-11-04 14:34:45 +00:00
2008-05-24 22:10:14 +00:00
/// <summary>
2008-06-17 20:36:21 +00:00
/// Add an object to the scene. This will both update the scene, and send information about the
/// new object to all clients interested in the scene.
2008-05-24 22:10:14 +00:00
/// </summary>
2011-05-20 22:22:27 +00:00
/// <remarks>
/// The object's stored position, rotation and velocity are used.
/// </remarks>
2008-05-24 22:10:14 +00:00
/// <param name="sceneObject"></param>
2008-06-12 17:49:08 +00:00
/// <param name="attachToBackup">
2008-06-13 00:21:53 +00:00
/// If true, the object is made persistent into the scene.
2008-06-12 17:49:08 +00:00
/// If false, the object will not persist over server restarts
/// </param>
2010-03-03 22:14:06 +00:00
/// <param name="sendClientUpdates">
/// If true, updates for the new scene object are sent to all viewers in range.
/// If false, it is left to the caller to schedule the update
/// </param>
/// <returns>
/// true if the object was added, false if an object with the same uuid was already in the scene
2008-05-24 23:11:07 +00:00
/// </returns>
2010-03-03 22:14:06 +00:00
protected bool AddSceneObject ( SceneObjectGroup sceneObject , bool attachToBackup , bool sendClientUpdates )
2007-11-04 14:34:45 +00:00
{
2012-01-31 20:53:49 +00:00
if ( sceneObject = = null )
{
m_log . ErrorFormat ( "[SCENEGRAPH]: Tried to add null scene object" ) ;
return false ;
}
2012-01-31 20:30:30 +00:00
if ( sceneObject . UUID = = UUID . Zero )
{
m_log . ErrorFormat (
"[SCENEGRAPH]: Tried to add scene object {0} to {1} with illegal UUID of {2}" ,
sceneObject . Name , m_parentScene . RegionInfo . RegionName , UUID . Zero ) ;
2012-02-15 01:45:25 +00:00
2008-10-11 16:23:15 +00:00
return false ;
2012-01-31 20:30:30 +00:00
}
2010-03-03 22:14:06 +00:00
2010-09-10 19:04:12 +00:00
if ( Entities . ContainsKey ( sceneObject . UUID ) )
2012-01-31 19:56:37 +00:00
{
2012-07-06 23:02:45 +00:00
m_log . DebugFormat (
"[SCENEGRAPH]: Scene graph for {0} already contains object {1} in AddSceneObject()" ,
m_parentScene . RegionInfo . RegionName , sceneObject . UUID ) ;
2012-02-15 01:45:25 +00:00
2010-09-10 19:04:12 +00:00
return false ;
2012-01-31 19:56:37 +00:00
}
2012-02-15 01:45:25 +00:00
2011-03-26 02:24:32 +00:00
// m_log.DebugFormat(
2012-02-15 01:45:25 +00:00
// "[SCENEGRAPH]: Adding scene object {0} {1}, with {2} parts on {3}",
2011-03-26 02:24:32 +00:00
// sceneObject.Name, sceneObject.UUID, sceneObject.Parts.Length, m_parentScene.RegionInfo.RegionName);
2010-09-10 19:04:12 +00:00
2011-09-13 16:56:02 +00:00
SceneObjectPart [ ] parts = sceneObject . Parts ;
2019-01-06 20:10:43 +00:00
int partsLength = parts . Length ;
SceneObjectPart part ;
2010-09-10 19:41:36 +00:00
2015-04-20 18:55:00 +00:00
// Clamp the sizes (scales) of the child prims and add the child prims to the count of all primitives
// (meshes and geometric primitives) in the scene; add child prims to m_numTotalPrim count
2010-09-10 19:41:36 +00:00
if ( m_parentScene . m_clampPrimSize )
2010-09-10 19:04:12 +00:00
{
2019-01-06 20:10:43 +00:00
for ( int i = 0 ; i < partsLength ; + + i )
2010-05-21 20:57:56 +00:00
{
2019-01-06 20:10:43 +00:00
part = parts [ i ] ;
2010-09-10 19:41:36 +00:00
Vector3 scale = part . Shape . Scale ;
2010-09-10 19:04:12 +00:00
2014-10-25 22:00:41 +00:00
scale . X = Util . Clamp ( scale . X , m_parentScene . m_minNonphys , m_parentScene . m_maxNonphys ) ;
scale . Y = Util . Clamp ( scale . Y , m_parentScene . m_minNonphys , m_parentScene . m_maxNonphys ) ;
scale . Z = Util . Clamp ( scale . Z , m_parentScene . m_minNonphys , m_parentScene . m_maxNonphys ) ;
2010-09-10 19:04:12 +00:00
2010-09-10 19:41:36 +00:00
part . Shape . Scale = scale ;
2010-08-27 23:40:33 +00:00
}
2010-09-10 19:04:12 +00:00
}
2010-08-27 23:40:33 +00:00
2010-09-10 19:04:12 +00:00
sceneObject . AttachToScene ( m_parentScene ) ;
2010-08-27 23:40:33 +00:00
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
{
m_scenePartsLock . EnterWriteLock ( ) ;
entered = true ;
}
2010-09-10 19:04:12 +00:00
2019-01-06 20:10:43 +00:00
m_numTotalPrim + = partsLength ;
2012-02-15 01:45:25 +00:00
2019-01-06 20:10:43 +00:00
Entities . Add ( sceneObject ) ;
m_scenePartsArray = null ;
for ( int i = 0 ; i < partsLength ; + + i )
{
part = parts [ i ] ;
m_scenePartsByID [ part . UUID ] = part ;
m_scenePartsByLocalID [ part . LocalId ] = part ;
if ( part . GetPrimType ( ) = = PrimType . SCULPT )
+ + m_numMesh ;
else
+ + m_numPrim ;
}
}
finally
2010-09-10 19:04:12 +00:00
{
2019-01-06 20:10:43 +00:00
if ( entered )
m_scenePartsLock . ExitWriteLock ( ) ;
2007-11-04 14:34:45 +00:00
}
2008-11-24 15:09:25 +00:00
2014-09-22 13:32:56 +00:00
if ( sendClientUpdates )
2018-12-31 13:33:00 +00:00
sceneObject . ScheduleGroupForFullAnimUpdate ( ) ;
2014-09-22 13:32:56 +00:00
if ( attachToBackup )
sceneObject . AttachToBackup ( ) ;
2010-05-21 20:57:56 +00:00
return true ;
2007-11-04 14:34:45 +00:00
}
2008-05-28 03:44:49 +00:00
2008-05-24 23:11:07 +00:00
/// <summary>
/// Delete an object from the scene
/// </summary>
/// <returns>true if the object was deleted, false if there was no object to delete</returns>
2009-02-06 16:55:34 +00:00
public bool DeleteSceneObject ( UUID uuid , bool resultOfObjectLinked )
2008-05-24 23:11:07 +00:00
{
2011-09-13 19:25:32 +00:00
// m_log.DebugFormat(
// "[SCENE GRAPH]: Deleting scene object with uuid {0}, resultOfObjectLinked = {1}",
// uuid, resultOfObjectLinked);
2010-09-10 19:04:12 +00:00
EntityBase entity ;
2010-10-27 19:47:27 +00:00
if ( ! Entities . TryGetValue ( uuid , out entity ) | | ( ! ( entity is SceneObjectGroup ) ) )
2010-09-10 19:04:12 +00:00
return false ;
2010-08-25 21:11:00 +00:00
2010-09-10 19:04:12 +00:00
SceneObjectGroup grp = ( SceneObjectGroup ) entity ;
2019-01-06 20:10:43 +00:00
SceneObjectPart [ ] parts = grp . Parts ;
int partsLength = parts . Length ;
SceneObjectPart part ;
2010-10-27 19:47:27 +00:00
2010-09-10 19:04:12 +00:00
if ( ! resultOfObjectLinked )
{
2015-04-20 18:55:00 +00:00
// Decrement the total number of primitives (meshes and geometric primitives)
// that are part of the Scene Object being removed
m_numTotalPrim - = grp . PrimCount ;
2017-04-16 02:39:35 +00:00
bool isPh = ( grp . RootPart . Flags & PrimFlags . Physics ) = = PrimFlags . Physics ;
int nphysparts = 0 ;
2019-01-06 20:10:43 +00:00
2015-04-20 18:55:00 +00:00
// Go through all parts (primitives and meshes) of this Scene Object
2019-01-06 20:10:43 +00:00
for ( int i = 0 ; i < partsLength ; + + i )
2015-04-20 18:55:00 +00:00
{
2019-01-06 20:10:43 +00:00
part = parts [ i ] ;
2015-04-20 18:55:00 +00:00
// Keep track of the total number of meshes or geometric primitives left in the scene;
// determine which object this is based on its primitive type: sculpted (sculpt) prim refers to
// a mesh and all other prims (i.e. box, sphere, etc) are geometric primitives
if ( part . GetPrimType ( ) = = PrimType . SCULPT )
m_numMesh - - ;
else
m_numPrim - - ;
2017-04-16 02:39:35 +00:00
if ( isPh & & part . PhysicsShapeType ! = ( byte ) PhysShapeType . none )
nphysparts + + ;
2015-04-20 18:55:00 +00:00
}
2009-01-03 03:30:03 +00:00
2017-04-16 02:39:35 +00:00
if ( nphysparts > 0 )
RemovePhysicalPrim ( nphysparts ) ;
2010-09-10 19:04:12 +00:00
}
2014-10-25 22:00:41 +00:00
2019-01-06 20:10:43 +00:00
bool ret = false ;
bool entered = false ;
try
2010-09-10 19:04:12 +00:00
{
2019-01-06 20:10:43 +00:00
try { }
finally
{
m_scenePartsLock . EnterWriteLock ( ) ;
entered = true ;
}
2019-01-19 07:09:39 +00:00
if ( ! resultOfObjectLinked )
2019-01-06 20:10:43 +00:00
{
2019-01-19 07:09:39 +00:00
for ( int i = 0 ; i < parts . Length ; + + i )
{
part = parts [ i ] ;
m_scenePartsByID . Remove ( part . UUID ) ;
m_scenePartsByLocalID . Remove ( part . LocalId ) ;
}
m_scenePartsArray = null ;
2019-01-06 20:10:43 +00:00
}
ret = Entities . Remove ( uuid ) ;
}
finally
{
if ( entered )
m_scenePartsLock . ExitWriteLock ( ) ;
2008-05-24 23:11:07 +00:00
}
2014-10-25 22:00:41 +00:00
return ret ;
2008-05-24 23:11:07 +00:00
}
2007-12-27 21:41:48 +00:00
2008-03-13 00:22:38 +00:00
/// <summary>
2009-10-14 02:13:06 +00:00
/// Add an object to the list of prims to process on the next update
2008-03-13 00:22:38 +00:00
/// </summary>
/// <param name="obj">
2009-10-14 02:13:06 +00:00
/// A <see cref="SceneObjectGroup"/>
2008-03-13 00:22:38 +00:00
/// </param>
2009-10-14 02:13:06 +00:00
protected internal void AddToUpdateList ( SceneObjectGroup obj )
2008-02-20 00:08:04 +00:00
{
2019-01-06 20:10:43 +00:00
lock ( m_updateLock )
2009-04-12 15:18:04 +00:00
m_updateList [ obj . UUID ] = obj ;
2008-02-20 00:08:04 +00:00
}
2010-06-25 21:25:39 +00:00
public void FireAttachToBackup ( SceneObjectGroup obj )
{
if ( OnAttachToBackup ! = null )
{
OnAttachToBackup ( obj ) ;
}
}
public void FireDetachFromBackup ( SceneObjectGroup obj )
{
if ( OnDetachFromBackup ! = null )
{
OnDetachFromBackup ( obj ) ;
}
}
2010-06-25 21:39:15 +00:00
public void FireChangeBackup ( SceneObjectGroup obj )
{
if ( OnChangeBackup ! = null )
{
OnChangeBackup ( obj ) ;
}
}
2008-03-12 18:11:08 +00:00
/// <summary>
/// Process all pending updates
/// </summary>
2009-10-14 02:13:06 +00:00
protected internal void UpdateObjectGroups ( )
2008-02-20 00:08:04 +00:00
{
2019-01-25 03:19:48 +00:00
Dictionary < UUID , SceneObjectGroup > updates ;
// Get the current list of updates and clear the list before iterating
lock ( m_updateLock )
2009-04-12 15:18:04 +00:00
{
2019-01-31 11:46:18 +00:00
if ( m_updateList . Count = = 0 )
return ;
2019-01-25 03:19:48 +00:00
updates = m_updateList ;
m_updateList = new Dictionary < UUID , SceneObjectGroup > ( ) ;
}
// Go through all updates
foreach ( SceneObjectGroup sog in updates . Values )
{
if ( sog . IsDeleted )
continue ;
// Don't abort the whole update if one entity happens to give us an exception.
try
2008-02-20 00:08:04 +00:00
{
2019-01-25 03:19:48 +00:00
sog . Update ( ) ;
2009-04-12 15:18:04 +00:00
}
2019-01-25 03:19:48 +00:00
catch ( Exception e )
2009-04-12 15:18:04 +00:00
{
2019-01-25 03:19:48 +00:00
m_log . ErrorFormat (
"[INNER SCENE]: Failed to update {0}, {1} - {2}" , sog . Name , sog . UUID , e ) ;
2008-02-20 00:08:04 +00:00
}
2010-09-10 19:04:12 +00:00
}
2019-01-25 03:19:48 +00:00
updates = null ;
2008-02-20 00:08:04 +00:00
}
2008-05-26 01:06:50 +00:00
protected internal void AddPhysicalPrim ( int number )
2007-12-14 00:49:40 +00:00
{
2013-11-13 23:25:54 +00:00
m_physicalPrim + = number ;
2007-12-14 00:49:40 +00:00
}
2007-12-27 21:41:48 +00:00
2008-05-26 01:06:50 +00:00
protected internal void RemovePhysicalPrim ( int number )
2007-12-14 00:49:40 +00:00
{
2013-11-13 23:25:54 +00:00
m_physicalPrim - = number ;
2007-12-14 00:49:40 +00:00
}
2007-12-27 21:41:48 +00:00
2008-05-26 01:06:50 +00:00
protected internal void AddToScriptLPS ( int number )
2008-02-06 08:03:22 +00:00
{
m_scriptLPS + = number ;
}
2008-05-26 01:06:50 +00:00
protected internal void AddActiveScripts ( int number )
2008-02-06 08:03:22 +00:00
{
m_activeScripts + = number ;
}
2008-05-28 03:44:49 +00:00
2008-09-06 07:52:41 +00:00
protected internal void HandleUndo ( IClientAPI remoteClient , UUID primId )
2008-04-28 01:48:21 +00:00
{
2008-09-06 07:52:41 +00:00
if ( primId ! = UUID . Zero )
2008-04-28 01:48:21 +00:00
{
2008-05-01 18:04:42 +00:00
SceneObjectPart part = m_parentScene . GetSceneObjectPart ( primId ) ;
2008-04-28 01:48:21 +00:00
if ( part ! = null )
part . Undo ( ) ;
2008-05-28 03:44:49 +00:00
}
2008-04-28 01:48:21 +00:00
}
2011-07-18 03:54:21 +00:00
2010-02-14 21:41:57 +00:00
protected internal void HandleRedo ( IClientAPI remoteClient , UUID primId )
{
if ( primId ! = UUID . Zero )
{
SceneObjectPart part = m_parentScene . GetSceneObjectPart ( primId ) ;
2011-07-16 04:23:21 +00:00
2010-02-14 21:41:57 +00:00
if ( part ! = null )
part . Redo ( ) ;
}
}
2008-05-28 03:44:49 +00:00
2011-08-17 23:53:05 +00:00
protected internal ScenePresence CreateAndAddChildScenePresence (
2019-01-06 20:10:43 +00:00
IClientAPI client , AvatarAppearance appearance , PresenceType type )
2007-11-04 14:34:45 +00:00
{
2013-08-22 23:49:13 +00:00
ScenePresence presence = new ScenePresence ( client , m_parentScene , appearance , type ) ;
2008-03-04 05:31:54 +00:00
2019-01-01 13:16:35 +00:00
bool entered = false ;
2010-05-12 15:25:40 +00:00
try
2008-03-04 05:31:54 +00:00
{
2019-01-06 01:44:37 +00:00
try { }
finally
{
m_scenePresencesLock . EnterWriteLock ( ) ;
entered = true ;
2019-01-06 20:10:43 +00:00
}
2019-01-01 13:16:35 +00:00
2019-01-06 20:10:43 +00:00
UUID id = presence . UUID ;
Entities [ id ] = presence ;
// ScenePresence always defaults to child agent
+ + m_numChildAgents ;
2010-05-04 23:49:46 +00:00
2019-01-06 20:10:43 +00:00
uint localid = presence . LocalId ;
ScenePresence oldref ;
if ( m_scenePresenceMap . TryGetValue ( id , out oldref ) )
{
uint oldLocalID = oldref . LocalId ;
if ( localid ! = oldLocalID )
m_scenePresenceLocalIDMap . Remove ( oldLocalID ) ;
2019-01-06 01:44:37 +00:00
}
2019-01-31 11:46:18 +00:00
m_scenePresenceMap [ id ] = presence ;
m_scenePresenceLocalIDMap [ localid ] = presence ;
2019-01-06 20:10:43 +00:00
m_scenePresenceList = null ;
2008-03-04 05:31:54 +00:00
}
2010-05-12 15:25:40 +00:00
finally
{
2019-01-01 13:16:35 +00:00
if ( entered )
m_scenePresencesLock . ExitWriteLock ( ) ;
2010-05-12 15:25:40 +00:00
}
2013-08-22 23:49:13 +00:00
return presence ;
2008-03-14 15:28:34 +00:00
}
2008-05-28 03:44:49 +00:00
2008-05-26 00:38:04 +00:00
/// <summary>
/// Remove a presence from the scene
/// </summary>
2008-09-06 07:52:41 +00:00
protected internal void RemoveScenePresence ( UUID agentID )
2008-05-26 00:38:04 +00:00
{
2008-11-24 15:09:25 +00:00
if ( ! Entities . Remove ( agentID ) )
2008-05-26 00:38:04 +00:00
{
2008-11-24 15:09:25 +00:00
m_log . WarnFormat (
2011-09-13 21:13:58 +00:00
"[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene Entities list" ,
2008-11-24 15:09:25 +00:00
agentID ) ;
2008-05-26 00:38:04 +00:00
}
2008-05-28 03:44:49 +00:00
2019-01-01 13:16:35 +00:00
bool entered = false ;
2010-05-12 15:25:40 +00:00
try
2008-05-28 03:44:49 +00:00
{
2019-01-06 01:44:37 +00:00
try { }
finally
2008-05-26 00:38:04 +00:00
{
2019-01-06 01:44:37 +00:00
m_scenePresencesLock . EnterWriteLock ( ) ;
entered = true ;
2019-01-06 20:10:43 +00:00
}
// Remove the presence reference from the dictionary
ScenePresence oldref ;
if ( m_scenePresenceMap . TryGetValue ( agentID , out oldref ) )
{
m_scenePresenceMap . Remove ( agentID ) ;
// Find the index in the list where the old ref was stored and remove the reference
m_scenePresenceLocalIDMap . Remove ( oldref . LocalId ) ;
m_scenePresenceList = null ;
}
else
{
m_log . WarnFormat ( "[SCENE GRAPH]: Tried to remove non-existent scene presence with agent ID {0} from scene ScenePresences list" , agentID ) ;
2008-05-26 00:38:04 +00:00
}
2008-05-28 03:44:49 +00:00
}
2010-05-12 15:25:40 +00:00
finally
{
2019-01-01 13:16:35 +00:00
if ( entered )
m_scenePresencesLock . ExitWriteLock ( ) ;
2010-05-12 15:25:40 +00:00
}
2008-05-26 00:38:04 +00:00
}
2008-03-04 05:31:54 +00:00
2008-05-26 01:06:50 +00:00
protected internal void SwapRootChildAgent ( bool direction_RC_CR_T_F )
2007-12-12 06:58:55 +00:00
{
if ( direction_RC_CR_T_F )
{
m_numRootAgents - - ;
m_numChildAgents + + ;
}
else
{
m_numChildAgents - - ;
m_numRootAgents + + ;
}
}
2007-12-27 21:41:48 +00:00
2009-03-30 18:20:41 +00:00
public void removeUserCount ( bool TypeRCTF )
2007-12-12 06:58:55 +00:00
{
if ( TypeRCTF )
{
m_numRootAgents - - ;
}
2007-12-27 21:41:48 +00:00
else
2007-12-12 06:58:55 +00:00
{
m_numChildAgents - - ;
}
}
2007-12-27 21:41:48 +00:00
2009-01-06 00:07:24 +00:00
public void RecalculateStats ( )
{
int rootcount = 0 ;
int childcount = 0 ;
2010-03-17 13:40:00 +00:00
ForEachScenePresence ( delegate ( ScenePresence presence )
2009-01-06 00:07:24 +00:00
{
2010-03-17 13:40:00 +00:00
if ( presence . IsChildAgent )
2009-10-23 08:02:36 +00:00
+ + childcount ;
2009-01-06 00:07:24 +00:00
else
2009-10-23 08:02:36 +00:00
+ + rootcount ;
2010-03-17 13:40:00 +00:00
} ) ;
2009-10-23 08:02:36 +00:00
2009-01-06 00:07:24 +00:00
m_numRootAgents = rootcount ;
m_numChildAgents = childcount ;
}
2008-06-06 23:20:02 +00:00
public int GetChildAgentCount ( )
2007-12-12 06:58:55 +00:00
{
return m_numChildAgents ;
}
2008-06-06 23:20:02 +00:00
public int GetRootAgentCount ( )
2007-12-12 06:58:55 +00:00
{
return m_numRootAgents ;
}
2007-12-12 14:07:26 +00:00
2008-06-06 23:20:02 +00:00
public int GetTotalObjectsCount ( )
2015-04-20 18:55:00 +00:00
{
return m_numTotalPrim ;
}
public int GetTotalPrimObjectsCount ( )
2007-12-12 14:07:26 +00:00
{
return m_numPrim ;
}
2015-04-20 18:55:00 +00:00
public int GetTotalMeshObjectsCount ( )
{
return m_numMesh ;
}
2008-06-06 23:20:02 +00:00
public int GetActiveObjectsCount ( )
2007-12-14 00:49:40 +00:00
{
return m_physicalPrim ;
}
2008-06-06 23:20:02 +00:00
public int GetActiveScriptsCount ( )
2008-02-06 08:03:22 +00:00
{
return m_activeScripts ;
}
2008-06-06 23:20:02 +00:00
public int GetScriptLPS ( )
2008-02-06 08:03:22 +00:00
{
int returnval = m_scriptLPS ;
m_scriptLPS = 0 ;
return returnval ;
}
2008-05-28 03:44:49 +00:00
2007-11-04 22:22:53 +00:00
# endregion
#region Get Methods
2017-01-05 19:07:37 +00:00
2008-04-14 18:43:23 +00:00
/// <summary>
/// Get the controlling client for the given avatar, if there is one.
2008-05-16 01:22:11 +00:00
///
/// FIXME: The only user of the method right now is Caps.cs, in order to resolve a client API since it can't
2008-04-14 18:43:23 +00:00
/// use the ScenePresence. This could be better solved in a number of ways - we could establish an
2008-05-16 01:22:11 +00:00
/// OpenSim.Framework.IScenePresence, or move the caps code into a region package (which might be the more
2008-04-14 18:43:23 +00:00
/// suitable solution).
/// </summary>
/// <param name="agentId"></param>
2009-02-06 16:55:34 +00:00
/// <returns>null if either the avatar wasn't in the scene, or
/// they do not have a controlling client</returns>
/// <remarks>this used to be protected internal, but that
/// prevents CapabilitiesModule from accessing it</remarks>
public IClientAPI GetControllingClient ( UUID agentId )
2008-04-14 18:43:23 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
{
m_scenePresencesLock . EnterReadLock ( ) ;
entered = true ;
}
ScenePresence presence ;
if ( m_scenePresenceMap . TryGetValue ( agentId , out presence ) )
return presence . ControllingClient ;
return null ;
}
catch
2008-04-14 18:43:23 +00:00
{
2019-01-06 20:10:43 +00:00
return null ;
}
finally
{
if ( entered )
m_scenePresencesLock . ExitReadLock ( ) ;
2008-04-14 18:43:23 +00:00
}
}
2007-11-04 14:34:45 +00:00
2010-03-17 13:40:00 +00:00
/// <summary>
2010-05-04 23:49:46 +00:00
/// Get a reference to the scene presence list. Changes to the list will be done in a copy
2010-03-19 12:51:16 +00:00
/// There is no guarantee that presences will remain in the scene after the list is returned.
/// This list should remain private to SceneGraph. Callers wishing to iterate should instead
/// pass a delegate to ForEachScenePresence.
2010-03-17 13:40:00 +00:00
/// </summary>
/// <returns></returns>
2012-07-19 20:54:50 +00:00
protected internal List < ScenePresence > GetScenePresences ( )
2010-03-17 13:40:00 +00:00
{
2019-01-01 13:16:35 +00:00
bool entered = false ;
2018-12-28 13:52:59 +00:00
try
{
2019-01-06 01:44:37 +00:00
try { }
finally
2019-01-06 01:23:08 +00:00
{
2019-01-06 01:44:37 +00:00
m_scenePresencesLock . EnterWriteLock ( ) ;
entered = true ;
2019-01-06 01:23:08 +00:00
}
2019-01-06 20:10:43 +00:00
if ( m_scenePresenceList = = null )
m_scenePresenceList = new List < ScenePresence > ( m_scenePresenceMap . Values ) ;
return m_scenePresenceList ;
}
catch
{
return new List < ScenePresence > ( ) ;
2019-01-01 13:16:35 +00:00
}
2018-12-28 13:52:59 +00:00
finally
{
2019-01-01 13:16:35 +00:00
if ( entered )
2019-01-06 01:23:08 +00:00
m_scenePresencesLock . ExitWriteLock ( ) ;
2018-12-28 13:52:59 +00:00
}
2010-03-17 13:40:00 +00:00
}
/// <summary>
2010-03-19 12:51:16 +00:00
/// Request a scene presence by UUID. Fast, indexed lookup.
2010-03-17 13:40:00 +00:00
/// </summary>
2010-03-19 12:51:16 +00:00
/// <param name="agentID"></param>
/// <returns>null if the presence was not found</returns>
protected internal ScenePresence GetScenePresence ( UUID agentID )
2010-03-17 13:40:00 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
{
m_scenePresencesLock . EnterReadLock ( ) ;
entered = true ;
}
ScenePresence presence ;
m_scenePresenceMap . TryGetValue ( agentID , out presence ) ;
return presence ;
}
catch
{
return null ;
}
finally
{
if ( entered )
m_scenePresencesLock . ExitReadLock ( ) ;
}
2010-03-17 13:40:00 +00:00
}
2007-11-04 14:34:45 +00:00
/// <summary>
2010-03-19 12:51:16 +00:00
/// Request the scene presence by name.
2007-11-04 14:34:45 +00:00
/// </summary>
2010-03-19 12:51:16 +00:00
/// <param name="firstName"></param>
/// <param name="lastName"></param>
/// <returns>null if the presence was not found</returns>
protected internal ScenePresence GetScenePresence ( string firstName , string lastName )
2007-11-04 14:34:45 +00:00
{
2010-05-04 23:49:46 +00:00
List < ScenePresence > presences = GetScenePresences ( ) ;
foreach ( ScenePresence presence in presences )
2010-03-17 13:40:00 +00:00
{
2014-04-02 11:28:40 +00:00
if ( string . Equals ( presence . Firstname , firstName , StringComparison . CurrentCultureIgnoreCase )
& & string . Equals ( presence . Lastname , lastName , StringComparison . CurrentCultureIgnoreCase ) )
2010-03-19 12:51:16 +00:00
return presence ;
}
return null ;
2010-03-17 13:40:00 +00:00
}
2007-11-04 14:34:45 +00:00
2010-03-17 13:40:00 +00:00
/// <summary>
2010-03-19 12:51:16 +00:00
/// Request the scene presence by localID.
2010-03-17 13:40:00 +00:00
/// </summary>
2010-03-19 12:51:16 +00:00
/// <param name="localID"></param>
/// <returns>null if the presence was not found</returns>
protected internal ScenePresence GetScenePresence ( uint localID )
2010-03-17 13:40:00 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
{
m_scenePresencesLock . EnterReadLock ( ) ;
entered = true ;
}
ScenePresence sp ;
if ( m_scenePresenceLocalIDMap . TryGetValue ( localID , out sp ) )
return sp ;
}
finally
{
if ( entered )
m_scenePresencesLock . ExitReadLock ( ) ;
}
2010-03-19 12:51:16 +00:00
return null ;
2007-11-04 14:34:45 +00:00
}
2010-03-19 12:58:34 +00:00
protected internal bool TryGetScenePresence ( UUID agentID , out ScenePresence avatar )
2010-03-17 13:40:00 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
{
m_scenePresencesLock . EnterReadLock ( ) ;
entered = true ;
}
return m_scenePresenceMap . TryGetValue ( agentID , out avatar ) ;
}
catch
{
avatar = null ;
return false ;
}
finally
{
if ( entered )
m_scenePresencesLock . ExitReadLock ( ) ;
}
2007-11-04 14:34:45 +00:00
}
2010-03-19 12:51:16 +00:00
protected internal bool TryGetAvatarByName ( string name , out ScenePresence avatar )
2010-03-17 13:40:00 +00:00
{
2010-03-19 12:51:16 +00:00
avatar = null ;
2018-12-28 13:52:59 +00:00
List < ScenePresence > presences = GetScenePresences ( ) ;
foreach ( ScenePresence presence in presences )
2010-03-17 13:40:00 +00:00
{
2010-03-19 12:51:16 +00:00
if ( String . Compare ( name , presence . ControllingClient . Name , true ) = = 0 )
{
avatar = presence ;
break ;
}
}
return ( avatar ! = null ) ;
2010-03-17 13:40:00 +00:00
}
2008-07-12 21:43:35 +00:00
/// <summary>
/// Get a scene object group that contains the prim with the given local id
/// </summary>
/// <param name="localID"></param>
/// <returns>null if no scene object group containing that prim is found</returns>
2009-10-18 01:01:22 +00:00
public SceneObjectGroup GetGroupByPrim ( uint localID )
2007-11-04 14:34:45 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
2009-04-12 15:18:04 +00:00
{
2019-01-06 20:10:43 +00:00
try { }
finally
2011-09-13 19:25:32 +00:00
{
2019-01-06 20:10:43 +00:00
m_scenePartsLock . EnterReadLock ( ) ;
entered = true ;
2011-09-13 19:25:32 +00:00
}
2019-01-06 20:10:43 +00:00
SceneObjectPart sop ;
if ( m_scenePartsByLocalID . TryGetValue ( localID , out sop ) )
return sop . ParentGroup ;
return null ;
2009-04-12 15:18:04 +00:00
}
2019-01-06 20:10:43 +00:00
finally
2007-11-04 14:34:45 +00:00
{
2019-01-06 20:10:43 +00:00
if ( entered )
m_scenePartsLock . ExitReadLock ( ) ;
2007-11-04 14:34:45 +00:00
}
}
2008-07-12 21:43:35 +00:00
/// <summary>
/// Get a scene object group that contains the prim with the given uuid
/// </summary>
/// <param name="fullID"></param>
2008-08-18 00:39:10 +00:00
/// <returns>null if no scene object group containing that prim is found</returns>
2012-01-19 10:53:21 +00:00
public SceneObjectGroup GetGroupByPrim ( UUID fullID )
2007-11-04 14:34:45 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
2007-11-04 14:34:45 +00:00
{
2019-01-06 20:10:43 +00:00
try { }
finally
2007-11-04 14:34:45 +00:00
{
2019-01-06 20:10:43 +00:00
m_scenePartsLock . EnterReadLock ( ) ;
entered = true ;
2007-11-04 14:34:45 +00:00
}
2019-01-06 20:10:43 +00:00
SceneObjectPart sop ;
if ( m_scenePartsByID . TryGetValue ( fullID , out sop ) )
return sop . ParentGroup ;
return null ;
}
finally
{
if ( entered )
m_scenePartsLock . ExitReadLock ( ) ;
2007-11-04 14:34:45 +00:00
}
}
2008-05-26 01:06:50 +00:00
protected internal EntityIntersection GetClosestIntersectingPrim ( Ray hray , bool frontFacesOnly , bool faceCenters )
2007-11-23 05:56:35 +00:00
{
// Primitive Ray Tracing
float closestDistance = 280f ;
2009-08-14 08:16:41 +00:00
EntityIntersection result = new EntityIntersection ( ) ;
2010-09-10 19:04:12 +00:00
EntityBase [ ] EntityList = GetEntities ( ) ;
2008-06-25 12:21:51 +00:00
foreach ( EntityBase ent in EntityList )
2007-11-23 05:56:35 +00:00
{
if ( ent is SceneObjectGroup )
{
2008-05-01 18:04:42 +00:00
SceneObjectGroup reportingG = ( SceneObjectGroup ) ent ;
2009-08-14 08:16:41 +00:00
EntityIntersection inter = reportingG . TestIntersection ( hray , frontFacesOnly , faceCenters ) ;
if ( inter . HitTF & & inter . distance < closestDistance )
2007-11-23 05:56:35 +00:00
{
2009-08-14 08:16:41 +00:00
closestDistance = inter . distance ;
result = inter ;
2007-11-23 05:56:35 +00:00
}
}
}
2009-08-14 08:16:41 +00:00
return result ;
2008-02-16 13:01:42 +00:00
}
2007-11-23 05:56:35 +00:00
2012-07-06 22:07:50 +00:00
/// <summary>
/// Get all the scene object groups.
/// </summary>
/// <returns>
/// The scene object groups. If the scene is empty then an empty list is returned.
/// </returns>
protected internal List < SceneObjectGroup > GetSceneObjectGroups ( )
{
2019-01-06 20:10:43 +00:00
EntityBase [ ] entities = Entities . GetEntities ( ) ;
List < SceneObjectGroup > ret = new List < SceneObjectGroup > ( 256 ) ;
2019-01-31 11:46:18 +00:00
for ( int i = 0 ; i < entities . Length ; + + i )
2019-01-06 20:10:43 +00:00
{
if ( entities [ i ] is SceneObjectGroup )
ret . Add ( ( SceneObjectGroup ) entities [ i ] ) ;
}
return ret ;
2012-07-06 22:07:50 +00:00
}
2011-05-20 22:34:34 +00:00
/// <summary>
/// Get a group in the scene
/// </summary>
/// <param name="fullID">UUID of the group</param>
/// <returns>null if no such group was found</returns>
protected internal SceneObjectGroup GetSceneObjectGroup ( UUID fullID )
{
2019-01-06 20:10:43 +00:00
EntityBase entity ;
if ( Entities . TryGetValue ( fullID , out entity ) & & ( entity is SceneObjectGroup ) )
return ( SceneObjectGroup ) entity ;
2011-05-20 22:34:34 +00:00
return null ;
}
2012-10-24 03:10:22 +00:00
/// <summary>
/// Get a group in the scene
/// <param name="localID">Local id of the root part of the group</param>
/// <returns>null if no such group was found</returns>
protected internal SceneObjectGroup GetSceneObjectGroup ( uint localID )
{
2019-01-06 20:10:43 +00:00
EntityBase entity ;
if ( Entities . TryGetValue ( localID , out entity ) & & ( entity is SceneObjectGroup ) )
return ( SceneObjectGroup ) entity ;
2012-10-24 03:10:22 +00:00
return null ;
}
2011-05-20 22:41:14 +00:00
/// <summary>
/// Get a group by name from the scene (will return the first
/// found, if there are more than one prim with the same name)
/// </summary>
/// <param name="name"></param>
/// <returns>null if the part was not found</returns>
protected internal SceneObjectGroup GetSceneObjectGroup ( string name )
{
2019-01-06 20:10:43 +00:00
EntityBase entity = null ;
EntityBase [ ] entities = Entities . GetEntities ( ) ;
2019-01-31 11:46:18 +00:00
for ( int i = 0 ; i < entities . Length ; + + i )
2019-01-06 20:10:43 +00:00
{
entity = entities [ i ] ;
if ( entity is SceneObjectGroup & & entity . Name = = name )
return ( SceneObjectGroup ) entity ;
}
return null ;
2011-05-20 22:41:14 +00:00
}
2008-07-12 21:43:35 +00:00
/// <summary>
/// Get a part contained in this scene.
/// </summary>
/// <param name="localID"></param>
/// <returns>null if the part was not found</returns>
2008-05-26 01:06:50 +00:00
protected internal SceneObjectPart GetSceneObjectPart ( uint localID )
2007-11-07 02:42:18 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
{
m_scenePartsLock . EnterReadLock ( ) ;
entered = true ;
}
SceneObjectPart sop ;
if ( m_scenePartsByLocalID . TryGetValue ( localID , out sop ) )
{
if ( sop . ParentGroup = = null | | sop . ParentGroup . IsDeleted )
return null ;
return sop ;
}
2007-11-07 02:42:18 +00:00
return null ;
2019-01-06 20:10:43 +00:00
}
finally
{
if ( entered )
m_scenePartsLock . ExitReadLock ( ) ;
}
2007-11-07 02:42:18 +00:00
}
2008-10-01 06:39:36 +00:00
/// <summary>
2019-01-06 20:10:43 +00:00
/// Get a part contained in this scene.
2008-10-01 06:39:36 +00:00
/// </summary>
2019-01-06 20:10:43 +00:00
/// <param name="fullID"></param>
2008-10-01 06:39:36 +00:00
/// <returns>null if the part was not found</returns>
2019-01-06 20:10:43 +00:00
protected internal SceneObjectPart GetSceneObjectPart ( UUID fullID )
2008-10-01 06:39:36 +00:00
{
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
2008-10-01 06:39:36 +00:00
{
2019-01-06 20:10:43 +00:00
m_scenePartsLock . EnterReadLock ( ) ;
entered = true ;
2008-10-01 06:39:36 +00:00
}
2019-01-06 20:10:43 +00:00
SceneObjectPart sop ;
if ( m_scenePartsByID . TryGetValue ( fullID , out sop ) )
{
if ( sop . ParentGroup = = null | | sop . ParentGroup . IsDeleted )
return null ;
return sop ;
}
return null ;
}
finally
{
if ( entered )
m_scenePartsLock . ExitReadLock ( ) ;
}
2008-10-01 06:39:36 +00:00
}
2007-11-07 02:42:18 +00:00
2008-07-12 21:43:35 +00:00
/// <summary>
2019-01-06 20:10:43 +00:00
/// Get a prim by name from the scene (will return the first
/// found, if there are more than one prim with the same name)
2008-07-12 21:43:35 +00:00
/// </summary>
2019-01-06 20:10:43 +00:00
/// <param name="name"></param>
2008-08-18 00:39:10 +00:00
/// <returns>null if the part was not found</returns>
2019-01-06 20:10:43 +00:00
protected internal SceneObjectPart GetSceneObjectPart ( string name )
2007-11-07 02:42:18 +00:00
{
2019-01-06 20:10:43 +00:00
SceneObjectPart [ ] parts = GetPartsArray ( ) ;
SceneObjectPart sop ;
2019-01-31 11:46:18 +00:00
for ( int i = 0 ; i < parts . Length ; + + i )
2019-01-06 20:10:43 +00:00
{
sop = parts [ i ] ;
if ( sop . ParentGroup = = null | | sop . ParentGroup . IsDeleted )
continue ;
if ( sop . Name = = name )
return sop ;
}
return null ;
2007-11-07 02:42:18 +00:00
}
2019-01-06 20:10:43 +00:00
protected internal SceneObjectPart [ ] GetPartsArray ( )
{
bool entered = false ;
try
{
try { }
finally
{
m_scenePartsLock . EnterWriteLock ( ) ;
entered = true ;
}
if ( m_scenePartsArray = = null )
{
m_scenePartsArray = new SceneObjectPart [ m_scenePartsByID . Count ] ;
m_scenePartsByID . Values . CopyTo ( m_scenePartsArray , 0 ) ;
}
return m_scenePartsArray ;
}
finally
{
if ( entered )
m_scenePartsLock . ExitWriteLock ( ) ;
}
}
2008-05-24 21:57:00 +00:00
/// <summary>
2008-06-03 08:34:38 +00:00
/// Returns a list of the entities in the scene. This is a new list so no locking is required to iterate over
/// it
2008-05-24 21:57:00 +00:00
/// </summary>
/// <returns></returns>
2010-09-10 19:04:12 +00:00
protected internal EntityBase [ ] GetEntities ( )
2007-12-17 16:41:28 +00:00
{
2008-11-24 14:45:05 +00:00
return Entities . GetEntities ( ) ;
2007-12-17 16:41:28 +00:00
}
2007-11-04 22:22:53 +00:00
# endregion
#region Other Methods
2008-05-26 01:06:50 +00:00
protected internal void physicsBasedCrash ( )
2007-11-28 06:18:07 +00:00
{
2008-03-02 22:28:48 +00:00
handlerPhysicsCrash = UnRecoverableError ;
if ( handlerPhysicsCrash ! = null )
2007-11-28 06:18:07 +00:00
{
2008-03-02 22:28:48 +00:00
handlerPhysicsCrash ( ) ;
2007-11-28 06:18:07 +00:00
}
}
2010-03-19 12:51:16 +00:00
/// <summary>
2011-03-26 00:53:19 +00:00
/// Performs action once on all scene object groups.
2010-03-19 12:51:16 +00:00
/// </summary>
/// <param name="action"></param>
2009-09-29 14:54:56 +00:00
protected internal void ForEachSOG ( Action < SceneObjectGroup > action )
{
2019-01-06 20:10:43 +00:00
EntityBase [ ] entities = Entities . GetEntities ( ) ;
EntityBase entity ;
2019-01-31 11:46:18 +00:00
for ( int i = 0 ; i < entities . Length ; + + i )
2009-09-29 14:54:56 +00:00
{
2019-01-06 20:10:43 +00:00
entity = entities [ i ] ;
if ( entity is SceneObjectGroup )
2009-09-29 14:54:56 +00:00
{
2019-01-06 20:10:43 +00:00
try
{
action ( ( SceneObjectGroup ) entity ) ;
}
catch ( Exception e )
{
// Catch it and move on. This includes situations where objlist has inconsistent info
m_log . WarnFormat (
"[SCENEGRAPH]: Problem processing action in ForEachSOG: {0} {1}" , e . Message , e . StackTrace ) ;
}
2009-09-29 14:54:56 +00:00
}
}
}
2011-10-27 07:42:21 +00:00
/// <summary>
/// Performs action on all ROOT (not child) scene presences.
/// This is just a shortcut function since frequently actions only appy to root SPs
/// </summary>
/// <param name="action"></param>
2011-11-04 00:06:08 +00:00
public void ForEachAvatar ( Action < ScenePresence > action )
2011-10-27 07:42:21 +00:00
{
ForEachScenePresence ( delegate ( ScenePresence sp )
{
if ( ! sp . IsChildAgent )
action ( sp ) ;
} ) ;
}
2010-03-17 13:40:00 +00:00
/// <summary>
2010-03-19 12:51:16 +00:00
/// Performs action on all scene presences. This can ultimately run the actions in parallel but
/// any delegates passed in will need to implement their own locking on data they reference and
2017-01-05 19:07:37 +00:00
/// modify outside of the scope of the delegate.
2010-03-17 13:40:00 +00:00
/// </summary>
/// <param name="action"></param>
public void ForEachScenePresence ( Action < ScenePresence > action )
{
2010-05-04 23:49:46 +00:00
List < ScenePresence > presences = GetScenePresences ( ) ;
foreach ( ScenePresence sp in presences )
2010-03-17 13:40:00 +00:00
{
2010-03-19 12:51:16 +00:00
try
2010-03-17 13:40:00 +00:00
{
2010-03-19 12:51:16 +00:00
action ( sp ) ;
}
catch ( Exception e )
{
2011-03-22 23:47:36 +00:00
m_log . Error ( "[SCENEGRAPH]: Error in " + m_parentScene . RegionInfo . RegionName + ": " + e . ToString ( ) ) ;
2010-03-17 13:40:00 +00:00
}
}
}
2017-01-05 19:07:37 +00:00
2007-11-04 22:22:53 +00:00
# endregion
2007-11-04 14:34:45 +00:00
#region Client Event handlers
2007-12-27 21:41:48 +00:00
2012-03-10 20:32:19 +00:00
protected internal void ClientChangeObject ( uint localID , object odata , IClientAPI remoteClient )
{
SceneObjectPart part = GetSceneObjectPart ( localID ) ;
ObjectChangeData data = ( ObjectChangeData ) odata ;
if ( part ! = null )
{
SceneObjectGroup grp = part . ParentGroup ;
if ( grp ! = null )
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( grp , remoteClient ) )
2012-03-10 20:32:19 +00:00
{
2012-05-07 21:03:07 +00:00
// These two are exceptions SL makes in the interpretation
// of the change flags. Must check them here because otherwise
// the group flag (see below) would be lost
if ( data . change = = ObjectChangeType . groupS )
data . change = ObjectChangeType . primS ;
if ( data . change = = ObjectChangeType . groupPS )
data . change = ObjectChangeType . primPS ;
2012-03-13 12:08:32 +00:00
part . StoreUndoState ( data . change ) ; // lets test only saving what we changed
2012-03-10 20:32:19 +00:00
grp . doChangeObject ( part , ( ObjectChangeData ) data ) ;
}
2012-05-07 21:03:07 +00:00
else
{
// Is this any kind of group operation?
if ( ( data . change & ObjectChangeType . Group ) ! = 0 )
{
// Is a move and/or rotation requested?
if ( ( data . change & ( ObjectChangeType . Position | ObjectChangeType . Rotation ) ) ! = 0 )
{
// Are we allowed to move it?
2017-01-19 12:35:00 +00:00
if ( m_parentScene . Permissions . CanMoveObject ( grp , remoteClient ) )
2012-05-07 21:03:07 +00:00
{
// Strip all but move and rotation from request
data . change & = ( ObjectChangeType . Group | ObjectChangeType . Position | ObjectChangeType . Rotation ) ;
part . StoreUndoState ( data . change ) ;
grp . doChangeObject ( part , ( ObjectChangeData ) data ) ;
}
}
}
}
2012-03-10 20:32:19 +00:00
}
}
}
2007-11-04 14:34:45 +00:00
/// <summary>
2011-07-16 02:52:30 +00:00
/// Update the scale of an individual prim.
2007-11-04 14:34:45 +00:00
/// </summary>
/// <param name="localID"></param>
/// <param name="scale"></param>
/// <param name="remoteClient"></param>
2008-09-06 07:52:41 +00:00
protected internal void UpdatePrimScale ( uint localID , Vector3 scale , IClientAPI remoteClient )
2007-11-04 14:34:45 +00:00
{
2011-07-16 03:22:57 +00:00
SceneObjectPart part = GetSceneObjectPart ( localID ) ;
if ( part ! = null )
2007-12-07 07:42:03 +00:00
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( part . ParentGroup , remoteClient ) )
2007-12-07 07:42:03 +00:00
{
2012-03-10 20:32:19 +00:00
bool physbuild = false ;
if ( part . ParentGroup . RootPart . PhysActor ! = null )
{
part . ParentGroup . RootPart . PhysActor . Building = true ;
physbuild = true ;
}
2011-07-16 03:22:57 +00:00
part . Resize ( scale ) ;
2012-03-10 20:32:19 +00:00
if ( physbuild )
part . ParentGroup . RootPart . PhysActor . Building = false ;
2007-12-07 07:42:03 +00:00
}
}
2007-11-04 14:34:45 +00:00
}
2008-05-28 03:44:49 +00:00
2008-09-06 07:52:41 +00:00
protected internal void UpdatePrimGroupScale ( uint localID , Vector3 scale , IClientAPI remoteClient )
2008-04-19 21:01:26 +00:00
{
SceneObjectGroup group = GetGroupByPrim ( localID ) ;
if ( group ! = null )
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group , remoteClient ) )
2008-04-19 21:01:26 +00:00
{
2012-03-10 20:32:19 +00:00
bool physbuild = false ;
if ( group . RootPart . PhysActor ! = null )
{
group . RootPart . PhysActor . Building = true ;
physbuild = true ;
}
2011-07-16 01:53:36 +00:00
group . GroupResize ( scale ) ;
2012-03-10 20:32:19 +00:00
if ( physbuild )
group . RootPart . PhysActor . Building = false ;
2008-04-19 21:01:26 +00:00
}
}
}
2007-11-04 14:34:45 +00:00
2007-11-15 07:32:24 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
/// This handles the nifty little tool tip that you get when you drag your mouse over an object
2007-11-15 07:32:24 +00:00
/// Send to the Object Group to process. We don't know enough to service the request
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="AgentID"></param>
/// <param name="RequestFlags"></param>
/// <param name="ObjectID"></param>
2008-05-26 01:06:50 +00:00
protected internal void RequestObjectPropertiesFamily (
2008-09-06 07:52:41 +00:00
IClientAPI remoteClient , UUID AgentID , uint RequestFlags , UUID ObjectID )
2007-11-15 07:32:24 +00:00
{
SceneObjectGroup group = GetGroupByPrim ( ObjectID ) ;
if ( group ! = null )
2008-02-12 11:21:23 +00:00
{
2007-11-15 07:32:24 +00:00
group . ServiceObjectPropertiesFamilyRequest ( remoteClient , AgentID , RequestFlags ) ;
2008-02-12 11:21:23 +00:00
}
2007-11-15 07:32:24 +00:00
}
2007-11-04 14:34:45 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
///
2007-11-04 14:34:45 +00:00
/// </summary>
/// <param name="localID"></param>
/// <param name="rot"></param>
/// <param name="remoteClient"></param>
2008-09-06 07:52:41 +00:00
protected internal void UpdatePrimSingleRotation ( uint localID , Quaternion rot , IClientAPI remoteClient )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( localID ) ;
if ( group ! = null )
2007-12-07 07:42:03 +00:00
{
2017-01-19 12:35:00 +00:00
if ( m_parentScene . Permissions . CanMoveObject ( group , remoteClient ) )
2007-12-07 07:42:03 +00:00
{
group . UpdateSingleRotation ( rot , localID ) ;
}
}
2007-11-04 14:34:45 +00:00
}
2009-07-17 14:58:54 +00:00
/// <summary>
///
/// </summary>
/// <param name="localID"></param>
/// <param name="rot"></param>
/// <param name="remoteClient"></param>
protected internal void UpdatePrimSingleRotationPosition ( uint localID , Quaternion rot , Vector3 pos , IClientAPI remoteClient )
{
SceneObjectGroup group = GetGroupByPrim ( localID ) ;
if ( group ! = null )
{
2017-01-19 12:35:00 +00:00
if ( m_parentScene . Permissions . CanMoveObject ( group , remoteClient ) )
2009-07-17 14:58:54 +00:00
{
2011-07-19 02:27:16 +00:00
group . UpdateSingleRotation ( rot , pos , localID ) ;
2009-07-17 14:58:54 +00:00
}
}
}
2007-11-04 14:34:45 +00:00
/// <summary>
2011-07-19 02:44:49 +00:00
/// Update the rotation of a whole group.
2007-11-04 14:34:45 +00:00
/// </summary>
/// <param name="localID"></param>
/// <param name="rot"></param>
/// <param name="remoteClient"></param>
2011-07-19 02:44:49 +00:00
protected internal void UpdatePrimGroupRotation ( uint localID , Quaternion rot , IClientAPI remoteClient )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( localID ) ;
if ( group ! = null )
2007-12-07 07:42:03 +00:00
{
2017-01-19 12:35:00 +00:00
if ( m_parentScene . Permissions . CanMoveObject ( group , remoteClient ) )
2007-12-07 07:42:03 +00:00
{
2009-09-30 16:51:02 +00:00
group . UpdateGroupRotationR ( rot ) ;
2007-12-07 07:42:03 +00:00
}
}
2007-11-04 14:34:45 +00:00
}
/// <summary>
2008-05-16 01:22:11 +00:00
///
2007-11-04 14:34:45 +00:00
/// </summary>
/// <param name="localID"></param>
/// <param name="pos"></param>
/// <param name="rot"></param>
/// <param name="remoteClient"></param>
2011-07-19 02:44:49 +00:00
protected internal void UpdatePrimGroupRotation ( uint localID , Vector3 pos , Quaternion rot , IClientAPI remoteClient )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( localID ) ;
if ( group ! = null )
2007-12-07 07:42:03 +00:00
{
2017-01-19 12:35:00 +00:00
if ( m_parentScene . Permissions . CanMoveObject ( group , remoteClient ) )
2007-12-07 07:42:03 +00:00
{
2009-09-30 16:51:02 +00:00
group . UpdateGroupRotationPR ( pos , rot ) ;
2007-12-07 07:42:03 +00:00
}
}
2007-11-04 14:34:45 +00:00
}
2008-06-27 14:39:21 +00:00
/// <summary>
/// Update the position of the given part
/// </summary>
/// <param name="localID"></param>
/// <param name="pos"></param>
/// <param name="remoteClient"></param>
2008-09-06 07:52:41 +00:00
protected internal void UpdatePrimSinglePosition ( uint localID , Vector3 pos , IClientAPI remoteClient )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( localID ) ;
if ( group ! = null )
2007-12-07 07:42:03 +00:00
{
2017-01-19 12:35:00 +00:00
if ( m_parentScene . Permissions . CanMoveObject ( group , remoteClient ) | | group . IsAttachment )
2007-12-07 07:42:03 +00:00
{
group . UpdateSinglePosition ( pos , localID ) ;
}
}
2007-11-04 14:34:45 +00:00
}
/// <summary>
2011-07-19 04:20:04 +00:00
/// Update the position of the given group.
2007-11-04 14:34:45 +00:00
/// </summary>
2014-04-01 23:58:33 +00:00
/// <param name="localId"></param>
2007-11-04 14:34:45 +00:00
/// <param name="pos"></param>
/// <param name="remoteClient"></param>
2014-04-01 23:58:33 +00:00
public void UpdatePrimGroupPosition ( uint localId , Vector3 pos , IClientAPI remoteClient )
{
SceneObjectGroup group = GetGroupByPrim ( localId ) ;
2017-01-05 19:07:37 +00:00
2007-11-07 02:42:18 +00:00
if ( group ! = null )
2010-09-12 17:43:49 +00:00
{
2008-11-22 16:09:58 +00:00
if ( group . IsAttachment | | ( group . RootPart . Shape . PCode = = 9 & & group . RootPart . Shape . State ! = 0 ) )
2008-04-23 13:22:06 +00:00
{
2010-11-16 19:44:39 +00:00
// Set the new attachment point data in the object
2017-01-26 19:51:50 +00:00
byte attachmentPoint = ( byte ) group . AttachmentPoint ;
2010-11-16 19:44:39 +00:00
group . UpdateGroupPosition ( pos ) ;
2011-09-07 16:42:18 +00:00
group . IsAttachment = false ;
2010-11-16 19:44:39 +00:00
group . AbsolutePosition = group . RootPart . AttachedPos ;
2011-09-07 16:42:18 +00:00
group . AttachmentPoint = attachmentPoint ;
2010-11-16 19:44:39 +00:00
group . HasGroupChanged = true ;
2008-04-23 13:22:06 +00:00
}
2008-05-16 01:22:11 +00:00
else
2007-12-07 07:42:03 +00:00
{
2017-01-19 12:35:00 +00:00
if ( m_parentScene . Permissions . CanMoveObject ( group , remoteClient )
2017-01-20 14:26:24 +00:00
& & m_parentScene . Permissions . CanObjectEntry ( group , false , pos ) )
2008-04-24 11:32:41 +00:00
{
group . UpdateGroupPosition ( pos ) ;
}
2007-12-07 07:42:03 +00:00
}
}
2007-11-04 14:34:45 +00:00
}
/// <summary>
2010-08-26 20:50:19 +00:00
/// Update the texture entry of the given prim.
2007-11-04 14:34:45 +00:00
/// </summary>
2012-01-30 19:21:58 +00:00
/// <remarks>
2010-08-26 20:50:19 +00:00
/// A texture entry is an object that contains details of all the textures of the prim's face. In this case,
/// the texture is given in its byte serialized form.
2012-01-30 19:21:58 +00:00
/// </remarks>
2007-11-04 14:34:45 +00:00
/// <param name="localID"></param>
/// <param name="texture"></param>
/// <param name="remoteClient"></param>
2008-05-26 01:06:50 +00:00
protected internal void UpdatePrimTexture ( uint localID , byte [ ] texture , IClientAPI remoteClient )
2007-11-04 14:34:45 +00:00
{
2017-06-13 12:22:01 +00:00
SceneObjectPart part = GetSceneObjectPart ( localID ) ;
if ( part = = null )
return ;
2017-01-05 19:07:37 +00:00
2017-06-13 12:22:01 +00:00
SceneObjectGroup group = part . ParentGroup ;
if ( group ! = null & & ! group . IsDeleted )
2007-12-07 07:42:03 +00:00
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group , remoteClient ) )
2007-12-07 07:42:03 +00:00
{
2017-06-13 12:22:01 +00:00
part . UpdateTextureEntry ( texture ) ;
2007-12-07 07:42:03 +00:00
}
}
2007-11-04 14:34:45 +00:00
}
/// <summary>
2011-07-11 01:29:19 +00:00
/// Update the flags on a scene object. This covers properties such as phantom, physics and temporary.
2007-11-04 14:34:45 +00:00
/// </summary>
2011-07-11 01:29:19 +00:00
/// <remarks>
/// This is currently handling the incoming call from the client stack (e.g. LLClientView).
/// </remarks>
2007-11-04 14:34:45 +00:00
/// <param name="localID"></param>
2011-07-11 01:29:19 +00:00
/// <param name="UsePhysics"></param>
/// <param name="SetTemporary"></param>
/// <param name="SetPhantom"></param>
2007-11-04 14:34:45 +00:00
/// <param name="remoteClient"></param>
2011-07-11 01:29:19 +00:00
protected internal void UpdatePrimFlags (
2013-02-07 22:25:28 +00:00
uint localID , bool UsePhysics , bool SetTemporary , bool SetPhantom , ExtraPhysicsData PhysData , IClientAPI remoteClient )
2007-11-04 14:34:45 +00:00
{
2019-01-25 03:19:48 +00:00
SceneObjectPart part = GetSceneObjectPart ( localID ) ;
if ( part = = null )
return ;
SceneObjectGroup group = part . ParentGroup ;
if ( group = = null | | group . IsDeleted )
return ;
2013-02-07 22:25:28 +00:00
2019-01-25 03:19:48 +00:00
if ( ! m_parentScene . Permissions . CanEditObject ( group , remoteClient ) )
return ;
2013-02-07 22:25:28 +00:00
2019-01-25 03:19:48 +00:00
// VolumeDetect can't be set via UI and will always be off when a change is made there
// now only change volume dtc if phantom off
2014-09-08 22:58:49 +00:00
2019-01-25 03:19:48 +00:00
bool wantedPhys = UsePhysics ;
if ( PhysData . PhysShapeType = = PhysShapeType . invalid ) // check for extraPhysics data
{
bool vdtc ;
if ( SetPhantom ) // if phantom keep volumedtc
vdtc = group . RootPart . VolumeDetectActive ;
else // else turn it off
vdtc = false ;
group . UpdateFlags ( UsePhysics , SetTemporary , SetPhantom , vdtc ) ;
}
else
{
part . UpdateExtraPhysics ( PhysData ) ;
if ( remoteClient ! = null )
remoteClient . SendPartPhysicsProprieties ( part ) ;
}
if ( wantedPhys ! = group . UsesPhysics & & remoteClient ! = null )
{
if ( m_parentScene . m_linksetPhysCapacity ! = 0 )
remoteClient . SendAlertMessage ( "Object physics cancelled because it exceeds limits for physical prims, either size or number of primswith shape type not set to None" ) ;
else
remoteClient . SendAlertMessage ( "Object physics cancelled because it exceeds size limits for physical prims" ) ;
2017-06-11 21:32:56 +00:00
2019-01-25 03:19:48 +00:00
group . RootPart . ScheduleFullUpdate ( ) ;
2007-12-07 07:42:03 +00:00
}
2007-11-04 14:34:45 +00:00
}
2009-04-10 06:39:52 +00:00
2007-11-04 14:34:45 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
///
2007-11-04 14:34:45 +00:00
/// </summary>
/// <param name="primLocalID"></param>
/// <param name="description"></param>
2008-05-26 01:06:50 +00:00
protected internal void PrimName ( IClientAPI remoteClient , uint primLocalID , string name )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( primLocalID ) ;
if ( group ! = null )
2007-12-07 07:42:03 +00:00
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group , remoteClient ) )
2007-12-07 07:42:03 +00:00
{
2007-12-28 23:19:03 +00:00
group . SetPartName ( Util . CleanString ( name ) , primLocalID ) ;
2008-08-15 16:51:26 +00:00
group . HasGroupChanged = true ;
2007-12-07 07:42:03 +00:00
}
}
2007-11-04 14:34:45 +00:00
}
/// <summary>
2011-06-10 01:27:45 +00:00
/// Handle a prim description set request from a viewer.
2007-11-04 14:34:45 +00:00
/// </summary>
/// <param name="primLocalID"></param>
/// <param name="description"></param>
2008-05-26 01:06:50 +00:00
protected internal void PrimDescription ( IClientAPI remoteClient , uint primLocalID , string description )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( primLocalID ) ;
if ( group ! = null )
2007-12-07 07:42:03 +00:00
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group , remoteClient ) )
2007-12-07 07:42:03 +00:00
{
2007-12-28 23:19:03 +00:00
group . SetPartDescription ( Util . CleanString ( description ) , primLocalID ) ;
2008-08-15 16:51:26 +00:00
group . HasGroupChanged = true ;
2007-12-07 07:42:03 +00:00
}
}
2007-11-04 14:34:45 +00:00
}
2011-06-10 01:27:45 +00:00
/// <summary>
/// Set a click action for the prim.
/// </summary>
/// <param name="remoteClient"></param>
/// <param name="primLocalID"></param>
/// <param name="clickAction"></param>
2008-09-12 20:42:04 +00:00
protected internal void PrimClickAction ( IClientAPI remoteClient , uint primLocalID , string clickAction )
{
2011-06-10 01:27:45 +00:00
// m_log.DebugFormat(
// "[SCENEGRAPH]: User {0} set click action for {1} to {2}", remoteClient.Name, primLocalID, clickAction);
2008-09-12 20:42:04 +00:00
SceneObjectGroup group = GetGroupByPrim ( primLocalID ) ;
if ( group ! = null )
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group , remoteClient ) )
2008-09-12 20:42:04 +00:00
{
2019-01-31 11:46:18 +00:00
SceneObjectPart part = group . GetPart ( primLocalID ) ;
2011-08-27 03:16:46 +00:00
if ( part ! = null )
{
2017-01-05 19:07:37 +00:00
part . ClickAction = Convert . ToByte ( clickAction ) ;
group . HasGroupChanged = true ;
2011-08-27 03:16:46 +00:00
}
2008-09-12 20:42:04 +00:00
}
}
}
2008-10-03 12:00:13 +00:00
protected internal void PrimMaterial ( IClientAPI remoteClient , uint primLocalID , string material )
{
SceneObjectGroup group = GetGroupByPrim ( primLocalID ) ;
if ( group ! = null )
{
2017-01-19 13:10:04 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group , remoteClient ) )
2008-10-03 12:00:13 +00:00
{
2019-01-31 11:46:18 +00:00
SceneObjectPart part = group . GetPart ( primLocalID ) ;
2011-08-27 03:16:46 +00:00
if ( part ! = null )
{
part . Material = Convert . ToByte ( material ) ;
group . HasGroupChanged = true ;
2012-03-15 02:24:13 +00:00
remoteClient . SendPartPhysicsProprieties ( part ) ;
2011-08-27 03:16:46 +00:00
}
2008-10-03 12:00:13 +00:00
}
}
}
2008-09-12 20:42:04 +00:00
2008-09-06 07:52:41 +00:00
protected internal void UpdateExtraParam ( UUID agentID , uint primLocalID , ushort type , bool inUse , byte [ ] data )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( primLocalID ) ;
2007-12-27 21:41:48 +00:00
2007-12-07 07:42:03 +00:00
if ( group ! = null )
2007-11-29 15:24:31 +00:00
{
2012-02-18 01:15:43 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group . UUID , agentID ) )
2007-12-07 07:42:03 +00:00
{
2007-11-29 15:24:31 +00:00
group . UpdateExtraParam ( primLocalID , type , inUse , data ) ;
2007-12-07 07:42:03 +00:00
}
2007-11-29 15:24:31 +00:00
}
2007-11-04 14:34:45 +00:00
}
/// <summary>
2008-05-16 01:22:11 +00:00
///
2007-11-04 14:34:45 +00:00
/// </summary>
/// <param name="primLocalID"></param>
/// <param name="shapeBlock"></param>
2008-09-06 07:52:41 +00:00
protected internal void UpdatePrimShape ( UUID agentID , uint primLocalID , UpdateShapeArgs shapeBlock )
2007-11-04 14:34:45 +00:00
{
2007-11-07 02:42:18 +00:00
SceneObjectGroup group = GetGroupByPrim ( primLocalID ) ;
2007-12-07 07:42:03 +00:00
if ( group ! = null )
2007-11-29 15:24:31 +00:00
{
2012-02-18 01:15:43 +00:00
if ( m_parentScene . Permissions . CanEditObject ( group . UUID , agentID ) )
2007-12-07 07:42:03 +00:00
{
2008-05-07 20:31:48 +00:00
ObjectShapePacket . ObjectDataBlock shapeData = new ObjectShapePacket . ObjectDataBlock ( ) ;
shapeData . ObjectLocalID = shapeBlock . ObjectLocalID ;
shapeData . PathBegin = shapeBlock . PathBegin ;
shapeData . PathCurve = shapeBlock . PathCurve ;
shapeData . PathEnd = shapeBlock . PathEnd ;
shapeData . PathRadiusOffset = shapeBlock . PathRadiusOffset ;
shapeData . PathRevolutions = shapeBlock . PathRevolutions ;
shapeData . PathScaleX = shapeBlock . PathScaleX ;
shapeData . PathScaleY = shapeBlock . PathScaleY ;
shapeData . PathShearX = shapeBlock . PathShearX ;
shapeData . PathShearY = shapeBlock . PathShearY ;
shapeData . PathSkew = shapeBlock . PathSkew ;
shapeData . PathTaperX = shapeBlock . PathTaperX ;
shapeData . PathTaperY = shapeBlock . PathTaperY ;
shapeData . PathTwist = shapeBlock . PathTwist ;
shapeData . PathTwistBegin = shapeBlock . PathTwistBegin ;
shapeData . ProfileBegin = shapeBlock . ProfileBegin ;
shapeData . ProfileCurve = shapeBlock . ProfileCurve ;
shapeData . ProfileEnd = shapeBlock . ProfileEnd ;
shapeData . ProfileHollow = shapeBlock . ProfileHollow ;
group . UpdateShape ( shapeData , primLocalID ) ;
2007-12-07 07:42:03 +00:00
}
2007-11-29 15:24:31 +00:00
}
2007-11-04 14:34:45 +00:00
}
/// <summary>
2008-04-03 13:33:46 +00:00
/// Initial method invoked when we receive a link objects request from the client.
2007-11-04 14:34:45 +00:00
/// </summary>
2008-04-03 13:33:46 +00:00
/// <param name="client"></param>
2007-11-04 14:34:45 +00:00
/// <param name="parentPrim"></param>
/// <param name="childPrims"></param>
2010-04-30 10:46:50 +00:00
protected internal void LinkObjects ( SceneObjectPart root , List < SceneObjectPart > children )
2007-11-04 14:34:45 +00:00
{
2013-06-06 02:03:05 +00:00
if ( root . KeyframeMotion ! = null )
{
root . KeyframeMotion . Stop ( ) ;
root . KeyframeMotion = null ;
}
2011-11-11 00:28:12 +00:00
SceneObjectGroup parentGroup = root . ParentGroup ;
if ( parentGroup = = null ) return ;
// Cowardly refuse to link to a group owned root
if ( parentGroup . OwnerID = = parentGroup . GroupID )
return ;
2019-01-25 03:19:48 +00:00
Monitor . Enter ( m_linkLock ) ;
2010-05-29 09:10:34 +00:00
2009-12-06 01:20:39 +00:00
try
2007-11-04 14:34:45 +00:00
{
2009-12-06 00:25:04 +00:00
List < SceneObjectGroup > childGroups = new List < SceneObjectGroup > ( ) ;
2010-04-30 10:46:50 +00:00
2011-09-01 00:22:28 +00:00
// We do this in reverse to get the link order of the prims correct
2014-09-22 12:59:23 +00:00
for ( int i = 0 ; i < children . Count ; i + + )
2009-12-06 00:25:04 +00:00
{
2011-09-01 00:22:28 +00:00
SceneObjectGroup child = children [ i ] . ParentGroup ;
2012-02-08 21:58:59 +00:00
// Don't try and add a group to itself - this will only cause severe problems later on.
if ( child = = parentGroup )
continue ;
2011-09-01 00:22:28 +00:00
// Make sure no child prim is set for sale
// So that, on delink, no prims are unwittingly
// left for sale and sold off
2014-09-22 12:59:23 +00:00
2011-09-07 16:42:18 +00:00
if ( child ! = null )
{
child . RootPart . ObjectSaleType = 0 ;
child . RootPart . SalePrice = 10 ;
childGroups . Add ( child ) ;
2007-11-04 14:34:45 +00:00
}
2009-12-06 00:25:04 +00:00
}
2007-11-04 14:34:45 +00:00
2009-12-06 00:25:04 +00:00
foreach ( SceneObjectGroup child in childGroups )
{
2011-11-11 00:28:12 +00:00
if ( parentGroup . OwnerID = = child . OwnerID )
{
2012-07-23 18:53:26 +00:00
child . DetachFromBackup ( ) ;
2019-03-05 17:03:17 +00:00
parentGroup . LinkToGroup ( child ) ;
2012-07-23 18:53:26 +00:00
2011-11-11 00:28:12 +00:00
// this is here so physics gets updated!
// Don't remove! Bad juju! Stay away! or fix physics!
2016-09-24 17:16:30 +00:00
// already done in LinkToGroup
// child.AbsolutePosition = child.AbsolutePosition;
2011-11-11 00:28:12 +00:00
}
2009-12-06 00:25:04 +00:00
}
2008-05-16 01:22:11 +00:00
2009-12-06 00:25:04 +00:00
// We need to explicitly resend the newly link prim's object properties since no other actions
// occur on link to invoke this elsewhere (such as object selection)
2012-02-08 21:58:59 +00:00
if ( childGroups . Count > 0 )
{
parentGroup . RootPart . CreateSelected = true ;
parentGroup . TriggerScriptChangedEvent ( Changed . LINK ) ;
}
2008-07-19 04:05:34 +00:00
}
2009-12-06 01:20:39 +00:00
finally
{
2014-09-22 12:59:23 +00:00
/ *
2011-11-02 22:42:09 +00:00
lock ( SceneObjectGroupsByLocalPartID )
{
foreach ( SceneObjectPart part in parentGroup . Parts )
SceneObjectGroupsByLocalPartID [ part . LocalId ] = parentGroup ;
}
2014-09-22 12:59:23 +00:00
* /
2015-09-02 18:54:53 +00:00
parentGroup . AdjustChildPrimPermissions ( false ) ;
2010-05-29 09:10:34 +00:00
parentGroup . HasGroupChanged = true ;
2018-12-31 13:33:00 +00:00
parentGroup . ScheduleGroupForFullAnimUpdate ( ) ;
2019-01-25 03:19:48 +00:00
Monitor . Exit ( m_linkLock ) ;
2009-12-06 01:20:39 +00:00
}
2007-11-04 14:34:45 +00:00
}
2007-11-18 11:11:44 +00:00
2007-11-13 19:57:11 +00:00
/// <summary>
/// Delink a linkset
/// </summary>
2008-05-16 01:22:11 +00:00
/// <param name="prims"></param>
2010-04-30 10:46:50 +00:00
protected internal void DelinkObjects ( List < SceneObjectPart > prims )
2007-11-13 19:57:11 +00:00
{
2019-01-31 11:46:18 +00:00
List < SceneObjectPart > childParts = new List < SceneObjectPart > ( ) ;
List < SceneObjectPart > rootParts = new List < SceneObjectPart > ( ) ;
List < SceneObjectGroup > affectedGroups = new List < SceneObjectGroup > ( ) ;
// Look them all up in one go, since that is comparatively expensive
/ /
2019-01-25 03:19:48 +00:00
Monitor . Enter ( m_linkLock ) ;
2009-12-06 01:20:39 +00:00
try
2007-11-18 11:11:44 +00:00
{
2010-04-30 10:46:50 +00:00
foreach ( SceneObjectPart part in prims )
2007-11-13 19:57:11 +00:00
{
2016-09-24 21:21:51 +00:00
if ( part = = null )
continue ;
SceneObjectGroup parentSOG = part . ParentGroup ;
2019-01-31 11:46:18 +00:00
if ( parentSOG = = null | | parentSOG . IsDeleted | | parentSOG . inTransit | | parentSOG . PrimCount = = 1 )
2016-09-24 21:21:51 +00:00
continue ;
if ( ! affectedGroups . Contains ( parentSOG ) )
2009-12-06 00:25:04 +00:00
{
2016-09-24 21:21:51 +00:00
affectedGroups . Add ( parentSOG ) ;
if ( parentSOG . RootPart . PhysActor ! = null )
parentSOG . RootPart . PhysActor . Building = true ;
}
2009-12-06 02:00:32 +00:00
2016-09-24 21:21:51 +00:00
if ( part . KeyframeMotion ! = null )
{
part . KeyframeMotion . Stop ( ) ;
part . KeyframeMotion = null ;
}
if ( part . LinkNum < 2 ) // Root
{
rootParts . Add ( part ) ;
}
else
{
part . LastOwnerID = part . ParentGroup . RootPart . LastOwnerID ;
2016-12-04 06:10:13 +00:00
part . RezzerID = part . ParentGroup . RootPart . RezzerID ;
2016-09-24 21:21:51 +00:00
childParts . Add ( part ) ;
2009-12-06 00:25:04 +00:00
}
2009-04-29 15:54:16 +00:00
}
2009-12-06 00:25:04 +00:00
2010-05-29 09:10:34 +00:00
if ( childParts . Count > 0 )
2009-04-29 15:54:16 +00:00
{
2010-09-07 15:12:28 +00:00
foreach ( SceneObjectPart child in childParts )
2010-05-29 09:10:34 +00:00
{
2010-09-07 15:12:28 +00:00
// Unlink all child parts from their groups
child . ParentGroup . DelinkFromGroup ( child , true ) ;
2016-09-24 21:21:51 +00:00
//child.ParentGroup is now other
2010-09-07 15:12:28 +00:00
child . ParentGroup . HasGroupChanged = true ;
2018-12-31 13:33:00 +00:00
child . ParentGroup . ScheduleGroupForFullAnimUpdate ( ) ;
2010-05-29 09:10:34 +00:00
}
2007-11-18 11:11:44 +00:00
}
2007-11-13 19:57:11 +00:00
2009-12-06 00:25:04 +00:00
foreach ( SceneObjectPart root in rootParts )
2008-07-19 04:05:34 +00:00
{
2009-12-06 00:25:04 +00:00
// In most cases, this will run only one time, and the prim
// will be a solo prim
// However, editing linked parts and unlinking may be different
2008-07-19 04:05:34 +00:00
/ /
2009-12-06 00:25:04 +00:00
SceneObjectGroup group = root . ParentGroup ;
2017-01-05 19:07:37 +00:00
2010-09-17 00:30:46 +00:00
List < SceneObjectPart > newSet = new List < SceneObjectPart > ( group . Parts ) ;
2008-07-19 04:05:34 +00:00
2016-09-24 21:21:51 +00:00
newSet . Remove ( root ) ;
int numChildren = newSet . Count ;
if ( numChildren = = 0 )
2010-09-07 15:12:28 +00:00
break ;
foreach ( SceneObjectPart p in newSet )
2016-09-24 21:21:51 +00:00
group . DelinkFromGroup ( p , false ) ;
2008-07-19 04:05:34 +00:00
2016-09-24 21:21:51 +00:00
SceneObjectPart newRoot = newSet [ 0 ] ;
2017-01-05 19:07:37 +00:00
2010-09-07 15:12:28 +00:00
// If there is more than one prim remaining, we
// need to re-link
/ /
2016-09-24 21:21:51 +00:00
if ( numChildren > 1 )
2010-09-07 15:12:28 +00:00
{
// Determine new root
/ /
newSet . RemoveAt ( 0 ) ;
2016-09-24 21:21:51 +00:00
foreach ( SceneObjectPart newChild in newSet )
newChild . ClearUpdateSchedule ( ) ;
2008-07-19 04:05:34 +00:00
2010-09-07 15:12:28 +00:00
LinkObjects ( newRoot , newSet ) ;
2016-09-24 21:21:51 +00:00
}
else
{
newRoot . TriggerScriptChangedEvent ( Changed . LINK ) ;
newRoot . ParentGroup . HasGroupChanged = true ;
2017-04-04 18:27:45 +00:00
newRoot . ParentGroup . InvalidatePartsLinkMaps ( ) ;
2018-12-31 13:33:00 +00:00
newRoot . ParentGroup . ScheduleGroupForFullAnimUpdate ( ) ;
2008-07-19 04:05:34 +00:00
}
2007-11-18 11:11:44 +00:00
}
2008-07-19 04:05:34 +00:00
2016-09-24 21:21:51 +00:00
// trigger events in the roots
2009-12-06 00:25:04 +00:00
/ /
foreach ( SceneObjectGroup g in affectedGroups )
{
2016-09-24 21:21:51 +00:00
if ( g . RootPart . PhysActor ! = null )
g . RootPart . PhysActor . Building = false ;
g . AdjustChildPrimPermissions ( false ) ;
2010-11-04 20:09:59 +00:00
// Child prims that have been unlinked and deleted will
// return unless the root is deleted. This will remove them
// from the database. They will be rewritten immediately,
// minus the rows for the unlinked child prims.
m_parentScene . SimulationDataService . RemoveObject ( g . UUID , m_parentScene . RegionInfo . RegionID ) ;
2017-04-04 18:27:45 +00:00
g . InvalidatePartsLinkMaps ( ) ;
2009-12-06 00:25:04 +00:00
g . TriggerScriptChangedEvent ( Changed . LINK ) ;
g . HasGroupChanged = true ; // Persist
g . ScheduleGroupForFullUpdate ( ) ;
}
2007-11-13 19:57:11 +00:00
}
2009-12-06 01:20:39 +00:00
finally
{
2019-01-25 03:19:48 +00:00
Monitor . Exit ( m_linkLock ) ;
2009-12-06 01:20:39 +00:00
}
2007-11-13 19:57:11 +00:00
}
2007-11-04 14:34:45 +00:00
2008-05-26 01:06:50 +00:00
protected internal void MakeObjectSearchable ( IClientAPI remoteClient , bool IncludeInSearch , uint localID )
2008-04-16 03:55:21 +00:00
{
2017-01-19 12:35:00 +00:00
SceneObjectGroup sog = GetGroupByPrim ( localID ) ;
if ( sog = = null )
return ;
2008-05-16 01:22:11 +00:00
2008-04-16 03:55:21 +00:00
//Protip: In my day, we didn't call them searchable objects, we called them limited point-to-point joints
//aka ObjectFlags.JointWheel = IncludeInSearch
//Permissions model: Object can be REMOVED from search IFF:
// * User owns object
//use CanEditObject
//Object can be ADDED to search IFF:
// * User owns object
// * Asset/DRM permission bit "modify" is enabled
//use CanEditObjectPosition
2008-09-08 10:28:59 +00:00
// libomv will complain about PrimFlags.JointWheel being
// deprecated, so we
#pragma warning disable 0612
2017-01-19 13:10:04 +00:00
if ( IncludeInSearch & & m_parentScene . Permissions . CanEditObject ( sog , remoteClient ) )
2008-04-16 03:55:21 +00:00
{
2017-01-19 12:35:00 +00:00
sog . RootPart . AddFlag ( PrimFlags . JointWheel ) ;
sog . HasGroupChanged = true ;
2008-04-16 03:55:21 +00:00
}
2017-01-19 12:35:00 +00:00
else if ( ! IncludeInSearch & & m_parentScene . Permissions . CanMoveObject ( sog , remoteClient ) )
2008-04-16 03:55:21 +00:00
{
2017-01-19 12:35:00 +00:00
sog . RootPart . RemFlag ( PrimFlags . JointWheel ) ;
sog . HasGroupChanged = true ;
2008-04-16 03:55:21 +00:00
}
2008-09-08 10:28:59 +00:00
#pragma warning restore 0612
2008-04-16 03:55:21 +00:00
}
2008-06-10 00:18:00 +00:00
/// <summary>
/// Duplicate the given object.
/// </summary>
/// <param name="originalPrim"></param>
/// <param name="offset"></param>
/// <param name="flags"></param>
2010-08-06 23:45:04 +00:00
/// <param name="AgentID"></param>
/// <param name="GroupID"></param>
/// <param name="rot"></param>
2012-05-08 20:31:35 +00:00
/// <returns>null if duplication fails, otherwise the duplicated object</returns>
2012-05-08 23:43:33 +00:00
/// <summary>
2017-01-19 18:25:25 +00:00
public SceneObjectGroup DuplicateObject ( uint originalPrimID , Vector3 offset , UUID AgentID , UUID GroupID , Quaternion rot , bool createSelected )
2008-06-10 00:18:00 +00:00
{
2011-03-26 02:24:32 +00:00
// m_log.DebugFormat(
2017-01-05 19:07:37 +00:00
// "[SCENE]: Duplication of object {0} at offset {1} requested by agent {2}",
2011-03-26 02:24:32 +00:00
// originalPrimID, offset, AgentID);
2012-05-08 20:31:35 +00:00
2009-04-12 15:18:04 +00:00
SceneObjectGroup original = GetGroupByPrim ( originalPrimID ) ;
if ( original ! = null )
2007-11-04 14:34:45 +00:00
{
2017-01-19 19:01:56 +00:00
if ( m_parentScene . Permissions . CanDuplicateObject ( original , AgentID ) )
2007-11-18 11:11:44 +00:00
{
2010-06-27 23:48:24 +00:00
SceneObjectGroup copy = original . Copy ( true ) ;
2007-11-18 11:11:44 +00:00
copy . AbsolutePosition = copy . AbsolutePosition + offset ;
2008-02-16 13:01:42 +00:00
2017-01-17 00:41:30 +00:00
SceneObjectPart [ ] parts = copy . Parts ;
m_numTotalPrim + = parts . Length ;
2010-06-27 23:29:30 +00:00
if ( original . OwnerID ! = AgentID )
2010-06-27 19:04:30 +00:00
{
2017-01-16 20:27:39 +00:00
copy . SetOwner ( AgentID , GroupID ) ;
2010-06-27 19:04:30 +00:00
2010-06-27 19:04:30 +00:00
if ( m_parentScene . Permissions . PropagatePermissions ( ) )
{
2017-01-17 00:41:30 +00:00
foreach ( SceneObjectPart child in parts )
2010-06-27 19:04:30 +00:00
{
child . Inventory . ChangeInventoryOwner ( AgentID ) ;
child . TriggerScriptChangedEvent ( Changed . OWNER ) ;
child . ApplyNextOwnerPermissions ( ) ;
}
2017-05-04 11:08:10 +00:00
copy . InvalidateEffectivePerms ( ) ;
2010-06-27 19:04:30 +00:00
}
}
2010-06-27 19:04:30 +00:00
2019-01-06 20:10:43 +00:00
bool entered = false ;
try
{
try { }
finally
{
m_scenePartsLock . EnterWriteLock ( ) ;
entered = true ;
}
2010-06-27 19:04:30 +00:00
2019-01-06 20:10:43 +00:00
Entities . Add ( copy ) ;
m_scenePartsArray = null ;
foreach ( SceneObjectPart part in parts )
{
if ( part . GetPrimType ( ) = = PrimType . SCULPT )
m_numMesh + + ;
else
m_numPrim + + ;
2012-05-08 20:31:35 +00:00
2019-01-06 20:10:43 +00:00
m_scenePartsByID [ part . UUID ] = part ;
m_scenePartsByLocalID [ part . LocalId ] = part ;
}
}
finally
2008-06-10 00:18:00 +00:00
{
2019-01-06 20:10:43 +00:00
if ( entered )
m_scenePartsLock . ExitWriteLock ( ) ;
2008-06-10 00:18:00 +00:00
}
2017-01-19 18:33:00 +00:00
copy . IsSelected = createSelected ;
2008-05-25 19:21:21 +00:00
2008-09-06 07:52:41 +00:00
if ( rot ! = Quaternion . Identity )
2009-09-30 16:51:02 +00:00
copy . UpdateGroupRotationR ( rot ) ;
2017-01-17 00:41:30 +00:00
// required for physics to update it's position
copy . ResetChildPrimPhysicsPositions ( ) ;
2012-05-08 20:31:35 +00:00
2010-08-31 20:24:11 +00:00
copy . CreateScriptInstances ( 0 , false , m_parentScene . DefaultScriptEngine , 1 ) ;
2010-04-19 05:29:26 +00:00
copy . ResumeScripts ( ) ;
2012-05-08 20:31:35 +00:00
2017-01-17 00:41:30 +00:00
copy . HasGroupChanged = true ;
2018-12-31 13:33:00 +00:00
copy . ScheduleGroupForFullAnimUpdate ( ) ;
2008-06-10 00:18:00 +00:00
return copy ;
2007-11-18 11:11:44 +00:00
}
2007-11-04 14:34:45 +00:00
}
else
{
2008-02-10 01:57:59 +00:00
m_log . WarnFormat ( "[SCENE]: Attempted to duplicate nonexistant prim id {0}" , GroupID ) ;
2007-11-04 14:34:45 +00:00
}
2012-05-08 23:43:33 +00:00
2008-06-10 00:18:00 +00:00
return null ;
2007-11-18 11:11:44 +00:00
}
2012-05-08 23:43:33 +00:00
2007-11-04 14:34:45 +00:00
# endregion
2009-01-06 00:07:24 +00:00
2007-11-04 14:34:45 +00:00
}
2008-05-01 18:04:42 +00:00
}