2007-10-15 07:10:21 +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-10-15 07:10:21 +00:00
2007-09-19 00:30:55 +00:00
using System ;
2012-08-02 21:34:46 +00:00
using System.ComponentModel ;
2007-07-30 20:11:40 +00:00
using System.Collections.Generic ;
2007-12-27 21:41:48 +00:00
using System.Drawing ;
2007-09-19 00:30:55 +00:00
using System.IO ;
2010-09-15 20:41:42 +00:00
using System.Linq ;
2009-02-09 22:27:27 +00:00
using System.Threading ;
2007-08-13 13:36:42 +00:00
using System.Xml ;
2008-05-14 05:43:21 +00:00
using System.Xml.Serialization ;
2008-09-06 07:52:41 +00:00
using OpenMetaverse ;
using OpenMetaverse.Packets ;
2007-10-29 21:46:25 +00:00
using OpenSim.Framework ;
2009-02-06 16:55:34 +00:00
using OpenSim.Region.Framework.Interfaces ;
2007-09-19 00:30:55 +00:00
using OpenSim.Region.Physics.Manager ;
2009-08-06 23:41:24 +00:00
using OpenSim.Region.Framework.Scenes.Serialization ;
2013-03-26 03:40:06 +00:00
using PermissionMask = OpenSim . Framework . PermissionMask ;
2007-07-30 20:11:40 +00:00
2009-02-06 16:55:34 +00:00
namespace OpenSim.Region.Framework.Scenes
2007-07-30 20:11:40 +00:00
{
2008-04-20 04:19:44 +00:00
[Flags]
2008-04-21 14:11:36 +00:00
public enum scriptEvents
2008-04-20 04:19:44 +00:00
{
None = 0 ,
attach = 1 ,
2008-08-04 21:30:12 +00:00
collision = 16 ,
2008-04-20 04:19:44 +00:00
collision_end = 32 ,
collision_start = 64 ,
control = 128 ,
dataserver = 256 ,
email = 512 ,
http_response = 1024 ,
land_collision = 2048 ,
land_collision_end = 4096 ,
land_collision_start = 8192 ,
2010-01-11 02:04:05 +00:00
at_target = 16384 ,
2010-01-11 02:20:00 +00:00
at_rot_target = 16777216 ,
2008-04-20 04:19:44 +00:00
listen = 32768 ,
money = 65536 ,
moving_end = 131072 ,
moving_start = 262144 ,
not_at_rot_target = 524288 ,
not_at_target = 1048576 ,
remote_data = 8388608 ,
run_time_permissions = 268435456 ,
state_entry = 1073741824 ,
state_exit = 2 ,
timer = 4 ,
touch = 8 ,
touch_end = 536870912 ,
touch_start = 2097152 ,
object_rez = 4194304
}
2008-05-01 18:04:42 +00:00
struct scriptPosTarget
2008-04-25 01:00:55 +00:00
{
2008-09-06 07:52:41 +00:00
public Vector3 targetPos ;
2008-04-25 01:00:55 +00:00
public float tolerance ;
2009-03-07 10:37:15 +00:00
public uint handle ;
2010-01-11 02:04:05 +00:00
}
struct scriptRotTarget
{
public Quaternion targetRot ;
public float tolerance ;
public uint handle ;
2008-04-25 01:00:55 +00:00
}
2007-08-27 15:34:21 +00:00
public delegate void PrimCountTaintedDelegate ( ) ;
2007-07-30 20:11:40 +00:00
2008-05-26 02:17:03 +00:00
/// <summary>
/// A scene object group is conceptually an object in the scene. The object is constituted of SceneObjectParts
/// (often known as prims), one of which is considered the root part.
/// </summary>
2009-02-09 22:27:27 +00:00
public partial class SceneObjectGroup : EntityBase , ISceneObject
2007-07-30 20:11:40 +00:00
{
2012-12-18 22:59:41 +00:00
// Axis selection bitmask used by SetAxisRotation()
// Just happen to be the same bits used by llSetStatus() and defined in ScriptBaseClass.
public enum axisSelect : int
{
STATUS_ROTATE_X = 0x002 ,
STATUS_ROTATE_Y = 0x004 ,
STATUS_ROTATE_Z = 0x008 ,
}
2013-11-04 17:28:24 +00:00
// This flag has the same purpose as InventoryItemFlags.ObjectSlamPerm
public static readonly uint SLAM = 16 ;
2008-06-27 23:03:39 +00:00
// private PrimCountTaintedDelegate handlerPrimCountTainted = null;
2007-07-30 20:11:40 +00:00
2008-01-18 18:43:16 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
/// Signal whether the non-inventory attributes of any prims in the group have changed
2008-01-18 18:57:28 +00:00
/// since the group's last persistent backup
2008-01-18 18:43:16 +00:00
/// </summary>
2008-11-15 17:52:00 +00:00
private bool m_hasGroupChanged = false ;
private long timeFirstChanged ;
private long timeLastChanged ;
2012-07-03 22:19:11 +00:00
/// <summary>
/// This indicates whether the object has changed such that it needs to be repersisted to permenant storage
/// (the database).
/// </summary>
/// <remarks>
/// Ultimately, this should be managed such that region modules can change it at the end of a set of operations
/// so that either all changes are preserved or none at all. However, currently, a large amount of internal
/// code will set this anyway when some object properties are changed.
/// </remarks>
2008-11-15 17:52:00 +00:00
public bool HasGroupChanged
{
set
{
if ( value )
{
timeLastChanged = DateTime . Now . Ticks ;
if ( ! m_hasGroupChanged )
timeFirstChanged = DateTime . Now . Ticks ;
}
m_hasGroupChanged = value ;
2010-12-03 00:08:58 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: HasGroupChanged set to {0} for {1} {2}", m_hasGroupChanged, Name, LocalId);
2008-11-15 17:52:00 +00:00
}
get { return m_hasGroupChanged ; }
}
2013-10-24 08:18:15 +00:00
private bool m_groupContainsForeignPrims = false ;
2010-12-03 00:08:58 +00:00
/// <summary>
2013-10-24 08:18:15 +00:00
/// Whether the group contains prims that came from a different group. This happens when
/// linking or delinking groups. The implication is that until the group is persisted,
/// the prims in the database still use the old SceneGroupID. That's a problem if the group
/// is deleted, because we delete groups by searching for prims by their SceneGroupID.
2010-12-03 00:08:58 +00:00
/// </summary>
2013-10-24 08:18:15 +00:00
public bool GroupContainsForeignPrims
{
private set
{
m_groupContainsForeignPrims = value ;
if ( m_groupContainsForeignPrims )
HasGroupChanged = true ;
}
get { return m_groupContainsForeignPrims ; }
}
2008-11-15 17:52:00 +00:00
private bool isTimeToPersist ( )
{
if ( IsSelected | | IsDeleted | | IsAttachment )
return false ;
if ( ! m_hasGroupChanged )
return false ;
if ( m_scene . ShuttingDown )
return true ;
long currentTime = DateTime . Now . Ticks ;
if ( currentTime - timeLastChanged > m_scene . m_dontPersistBefore | | currentTime - timeFirstChanged > m_scene . m_persistAfter )
return true ;
return false ;
}
2011-08-26 23:15:21 +00:00
2011-08-26 21:02:23 +00:00
/// <summary>
2008-11-01 21:50:07 +00:00
/// Is this scene object acting as an attachment?
2011-08-26 21:02:23 +00:00
/// </summary>
2011-08-26 23:15:21 +00:00
public bool IsAttachment { get ; set ; }
2008-08-18 00:39:10 +00:00
2011-08-26 22:06:41 +00:00
/// <summary>
/// The avatar to which this scene object is attached.
/// </summary>
/// <remarks>
/// If we're not attached to an avatar then this is UUID.Zero
/// </remarks>
public UUID AttachedAvatar { get ; set ; }
2011-08-26 23:15:21 +00:00
/// <summary>
/// Attachment point of this scene object to an avatar.
/// </summary>
/// <remarks>
/// 0 if we're not attached to anything
/// </remarks>
2011-08-26 23:33:24 +00:00
public uint AttachmentPoint
{
get
{
return m_rootPart . Shape . State ;
}
set
{
IsAttachment = value ! = 0 ;
m_rootPart . Shape . State = ( byte ) value ;
}
}
2012-06-14 00:12:16 +00:00
/// <summary>
/// If this scene object has an attachment point then indicate whether there is a point where
/// attachments are perceivable by avatars other than the avatar to which this object is attached.
/// </summary>
/// <remarks>
/// HUDs are not perceivable by other avatars.
/// </remarks>
public bool HasPrivateAttachmentPoint
{
get
{
return AttachmentPoint > = ( uint ) OpenMetaverse . AttachmentPoint . HUDCenter2
& & AttachmentPoint < = ( uint ) OpenMetaverse . AttachmentPoint . HUDBottomRight ;
}
}
2011-08-26 23:33:24 +00:00
public void ClearPartAttachmentData ( )
{
AttachmentPoint = 0 ;
2011-09-02 21:28:27 +00:00
// Even though we don't use child part state parameters for attachments any more, we still need to set
// these to zero since having them non-zero in rezzed scene objects will crash some clients. Even if
// we store them correctly, scene objects that we receive from elsewhere might not.
foreach ( SceneObjectPart part in Parts )
part . Shape . State = 0 ;
2011-08-26 23:33:24 +00:00
}
2011-08-26 23:15:21 +00:00
2011-08-24 20:53:12 +00:00
/// <summary>
/// Is this scene object phantom?
/// </summary>
/// <remarks>
/// Updating must currently take place through UpdatePrimFlags()
/// </remarks>
public bool IsPhantom
{
get { return ( RootPart . Flags & PrimFlags . Phantom ) ! = 0 ; }
}
/// <summary>
/// Does this scene object use physics?
/// </summary>
/// <remarks>
/// Updating must currently take place through UpdatePrimFlags()
/// </remarks>
public bool UsesPhysics
{
2011-12-23 00:21:32 +00:00
get { return ( RootPart . Flags & PrimFlags . Physics ) ! = 0 ; }
2011-08-24 20:53:12 +00:00
}
/// <summary>
/// Is this scene object temporary?
/// </summary>
/// <remarks>
/// Updating must currently take place through UpdatePrimFlags()
/// </remarks>
public bool IsTemporary
{
get { return ( RootPart . Flags & PrimFlags . TemporaryOnRez ) ! = 0 ; }
}
public bool IsVolumeDetect
{
get { return RootPart . VolumeDetectActive ; }
}
2008-09-06 07:52:41 +00:00
private Vector3 lastPhysGroupPos ;
private Quaternion lastPhysGroupRot ;
2007-11-03 19:33:00 +00:00
2014-03-22 00:29:13 +00:00
/// <summary>
/// Is this entity set to be saved in persistent storage?
/// </summary>
public bool Backup { get ; private set ; }
2008-10-18 05:51:36 +00:00
2010-09-17 00:30:46 +00:00
protected MapAndArray < UUID , SceneObjectPart > m_parts = new MapAndArray < UUID , SceneObjectPart > ( ) ;
2008-04-21 14:11:36 +00:00
protected ulong m_regionHandle ;
protected SceneObjectPart m_rootPart ;
2008-09-06 07:52:41 +00:00
// private Dictionary<UUID, scriptEvents> m_scriptEvents = new Dictionary<UUID, scriptEvents>();
2008-04-21 14:11:36 +00:00
2010-01-11 02:04:05 +00:00
private Dictionary < uint , scriptPosTarget > m_targets = new Dictionary < uint , scriptPosTarget > ( ) ;
2010-01-11 02:20:00 +00:00
private Dictionary < uint , scriptRotTarget > m_rotTargets = new Dictionary < uint , scriptRotTarget > ( ) ;
2008-05-01 18:04:42 +00:00
2010-09-17 00:30:46 +00:00
private bool m_scriptListens_atTarget ;
private bool m_scriptListens_notAtTarget ;
2010-01-11 02:04:05 +00:00
2010-09-17 00:30:46 +00:00
private bool m_scriptListens_atRotTarget ;
private bool m_scriptListens_notAtRotTarget ;
2008-05-01 18:04:42 +00:00
2010-09-17 00:30:46 +00:00
internal Dictionary < UUID , string > m_savedScriptState ;
2009-04-22 18:09:55 +00:00
2007-08-13 13:36:42 +00:00
#region Properties
2008-08-18 00:39:10 +00:00
2008-06-21 18:11:45 +00:00
/// <summary>
/// The name of an object grouping is always the same as its root part
/// </summary>
public override string Name
{
2011-09-01 01:09:41 +00:00
get { return RootPart . Name ; }
2008-06-21 18:11:45 +00:00
set { RootPart . Name = value ; }
2008-08-18 00:39:10 +00:00
}
2007-09-19 00:30:55 +00:00
2012-01-31 23:03:39 +00:00
public string Description
{
get { return RootPart . Description ; }
set { RootPart . Description = value ; }
}
2008-04-21 14:11:36 +00:00
/// <summary>
/// Added because the Parcel code seems to use it
/// but not sure a object should have this
/// as what does it tell us? that some avatar has selected it (but not what Avatar/user)
/// think really there should be a list (or whatever) in each scenepresence
2008-05-16 01:22:11 +00:00
/// saying what prim(s) that user has selected.
2008-04-21 14:11:36 +00:00
/// </summary>
2008-05-01 18:04:42 +00:00
protected bool m_isSelected = false ;
2008-04-21 14:11:36 +00:00
2007-07-30 20:11:40 +00:00
/// <summary>
2008-06-21 23:45:22 +00:00
/// Number of prims in this group
2007-07-30 20:11:40 +00:00
/// </summary>
2007-08-01 16:50:20 +00:00
public int PrimCount
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
get { return m_parts . Count ; }
2007-07-30 20:11:40 +00:00
}
2009-10-01 23:47:01 +00:00
public Quaternion GroupRotation
2007-08-15 16:57:47 +00:00
{
get { return m_rootPart . RotationOffset ; }
}
2008-04-21 14:11:36 +00:00
2011-07-16 02:30:14 +00:00
public Vector3 GroupScale
{
get
{
2013-12-27 06:45:59 +00:00
Vector3 minScale = new Vector3 ( Constants . MaximumRegionSize , Constants . MaximumRegionSize , Constants . MaximumRegionSize ) ;
2011-07-16 02:30:14 +00:00
Vector3 maxScale = Vector3 . Zero ;
Vector3 finalScale = new Vector3 ( 0.5f , 0.5f , 0.5f ) ;
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
{
SceneObjectPart part = parts [ i ] ;
Vector3 partscale = part . Scale ;
Vector3 partoffset = part . OffsetPosition ;
minScale . X = ( partscale . X + partoffset . X < minScale . X ) ? partscale . X + partoffset . X : minScale . X ;
minScale . Y = ( partscale . Y + partoffset . Y < minScale . Y ) ? partscale . Y + partoffset . Y : minScale . Y ;
minScale . Z = ( partscale . Z + partoffset . Z < minScale . Z ) ? partscale . Z + partoffset . Z : minScale . Z ;
maxScale . X = ( partscale . X + partoffset . X > maxScale . X ) ? partscale . X + partoffset . X : maxScale . X ;
maxScale . Y = ( partscale . Y + partoffset . Y > maxScale . Y ) ? partscale . Y + partoffset . Y : maxScale . Y ;
maxScale . Z = ( partscale . Z + partoffset . Z > maxScale . Z ) ? partscale . Z + partoffset . Z : maxScale . Z ;
}
finalScale . X = ( minScale . X > maxScale . X ) ? minScale . X : maxScale . X ;
finalScale . Y = ( minScale . Y > maxScale . Y ) ? minScale . Y : maxScale . Y ;
finalScale . Z = ( minScale . Z > maxScale . Z ) ? minScale . Z : maxScale . Z ;
return finalScale ;
}
}
2008-09-06 07:52:41 +00:00
public UUID GroupID
2007-11-14 11:56:57 +00:00
{
get { return m_rootPart . GroupID ; }
set { m_rootPart . GroupID = value ; }
}
2008-04-21 14:11:36 +00:00
2010-09-17 00:30:46 +00:00
public SceneObjectPart [ ] Parts
{
get { return m_parts . GetArray ( ) ; }
}
public bool ContainsPart ( UUID partID )
2007-08-09 17:54:22 +00:00
{
2010-09-17 00:30:46 +00:00
return m_parts . ContainsKey ( partID ) ;
2007-08-09 17:54:22 +00:00
}
2012-03-31 00:45:37 +00:00
/// <summary>
/// Does this group contain the given part?
/// should be able to remove these methods once we have a entity index in scene
/// </summary>
/// <param name="localID"></param>
/// <returns></returns>
public bool ContainsPart ( uint localID )
{
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
{
if ( parts [ i ] . LocalId = = localID )
return true ;
}
return false ;
}
2008-11-10 20:04:55 +00:00
/// <value>
/// The root part of this scene object
/// </value>
2007-08-10 13:59:19 +00:00
public SceneObjectPart RootPart
{
2007-09-19 00:30:55 +00:00
get { return m_rootPart ; }
2007-08-10 13:59:19 +00:00
}
public ulong RegionHandle
{
get { return m_regionHandle ; }
set
{
m_regionHandle = value ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . RegionHandle = value ;
2007-08-10 13:59:19 +00:00
}
}
2010-02-08 19:10:54 +00:00
/// <summary>
/// Check both the attachment property and the relevant properties of the underlying root part.
/// </summary>
2011-08-26 23:15:21 +00:00
/// <remarks>
2010-02-08 19:10:54 +00:00
/// This is necessary in some cases, particularly when a scene object has just crossed into a region and doesn't
/// have the IsAttachment property yet checked.
///
/// FIXME: However, this should be fixed so that this property
/// propertly reflects the underlying status.
2011-08-26 23:15:21 +00:00
/// </remarks>
2010-02-08 19:10:54 +00:00
/// <returns></returns>
public bool IsAttachmentCheckFull ( )
2009-09-25 20:06:04 +00:00
{
2014-02-16 00:01:43 +00:00
return ( IsAttachment | | ( m_rootPart . Shape . PCode = = ( byte ) PCodeEnum . Primitive & & m_rootPart . Shape . State ! = 0 ) ) ;
2009-09-25 20:06:04 +00:00
}
2013-12-16 22:08:02 +00:00
private struct avtocrossInfo
{
public ScenePresence av ;
public uint ParentID ;
}
2008-09-12 00:37:59 +00:00
/// <summary>
/// The absolute position of this scene object in the scene
/// </summary>
2008-09-06 07:52:41 +00:00
public override Vector3 AbsolutePosition
2007-08-07 18:31:20 +00:00
{
2009-09-16 22:06:08 +00:00
get { return m_rootPart . GroupPosition ; }
2007-08-07 18:31:20 +00:00
set
{
2008-09-06 07:52:41 +00:00
Vector3 val = value ;
2009-09-02 08:39:00 +00:00
2011-04-14 16:33:55 +00:00
if ( Scene ! = null )
2009-09-30 16:00:09 +00:00
{
2012-12-17 05:12:01 +00:00
if (
2014-02-16 00:01:43 +00:00
! Scene . PositionIsInCurrentRegion ( val )
& & ! IsAttachmentCheckFull ( )
& & ( ! Scene . LoadingPrims )
)
2011-04-14 16:33:55 +00:00
{
2013-12-16 22:08:02 +00:00
IEntityTransferModule entityTransfer = m_scene . RequestModuleInterface < IEntityTransferModule > ( ) ;
string version = String . Empty ;
Vector3 newpos = Vector3 . Zero ;
2014-02-16 01:02:53 +00:00
string failureReason = String . Empty ;
2013-12-16 22:08:02 +00:00
OpenSim . Services . Interfaces . GridRegion destination = null ;
2013-06-06 02:03:05 +00:00
if ( m_rootPart . KeyframeMotion ! = null )
m_rootPart . KeyframeMotion . StartCrossingCheck ( ) ;
2013-12-16 22:08:02 +00:00
bool canCross = true ;
2014-04-03 00:14:39 +00:00
foreach ( ScenePresence av in GetSittingAvatars ( ) )
2013-12-16 22:08:02 +00:00
{
// We need to cross these agents. First, let's find
// out if any of them can't cross for some reason.
// We have to deny the crossing entirely if any
// of them are banned. Alternatively, we could
// unsit banned agents....
// We set the avatar position as being the object
// position to get the region to send to
2014-02-16 01:02:53 +00:00
if ( ( destination = entityTransfer . GetDestination ( m_scene , av . UUID , val , out version , out newpos , out failureReason ) ) = = null )
2013-12-16 22:08:02 +00:00
{
canCross = false ;
break ;
}
m_log . DebugFormat ( "[SCENE OBJECT]: Avatar {0} needs to be crossed to {1}" , av . Name , destination . RegionName ) ;
}
if ( canCross )
{
// We unparent the SP quietly so that it won't
// be made to stand up
List < avtocrossInfo > avsToCross = new List < avtocrossInfo > ( ) ;
2014-04-03 00:14:39 +00:00
foreach ( ScenePresence av in GetSittingAvatars ( ) )
2013-12-16 22:08:02 +00:00
{
avtocrossInfo avinfo = new avtocrossInfo ( ) ;
SceneObjectPart parentPart = m_scene . GetSceneObjectPart ( av . ParentID ) ;
if ( parentPart ! = null )
av . ParentUUID = parentPart . UUID ;
avinfo . av = av ;
avinfo . ParentID = av . ParentID ;
avsToCross . Add ( avinfo ) ;
av . PrevSitOffset = av . OffsetPosition ;
av . ParentID = 0 ;
}
m_scene . CrossPrimGroupIntoNewRegion ( val , this , true ) ;
// Normalize
2013-12-27 06:45:59 +00:00
if ( val . X > = m_scene . RegionInfo . RegionSizeX )
val . X - = m_scene . RegionInfo . RegionSizeX ;
if ( val . Y > = m_scene . RegionInfo . RegionSizeY )
val . Y - = m_scene . RegionInfo . RegionSizeY ;
2013-12-16 22:08:02 +00:00
if ( val . X < 0 )
2013-12-27 06:45:59 +00:00
val . X + = m_scene . RegionInfo . RegionSizeX ;
2013-12-16 22:08:02 +00:00
if ( val . Y < 0 )
2013-12-27 06:45:59 +00:00
val . Y + = m_scene . RegionInfo . RegionSizeY ;
2013-12-16 22:08:02 +00:00
// If it's deleted, crossing was successful
if ( IsDeleted )
{
foreach ( avtocrossInfo avinfo in avsToCross )
{
ScenePresence av = avinfo . av ;
if ( ! av . IsInTransit ) // just in case...
{
m_log . DebugFormat ( "[SCENE OBJECT]: Crossing avatar {0} to {1}" , av . Name , val ) ;
av . IsInTransit = true ;
2014-04-02 23:19:53 +00:00
// A temporary measure to allow regression tests to work.
// Quite possibly, all BeginInvoke() calls should be replaced by Util.FireAndForget
// or similar since BeginInvoke() always uses the system threadpool to launch
// threads rather than any replace threadpool that we might be using.
if ( Util . FireAndForgetMethod = = FireAndForgetMethod . RegressionTest )
{
entityTransfer . CrossAgentToNewRegionAsync ( av , val , destination , av . Flying , version ) ;
CrossAgentToNewRegionCompleted ( av ) ;
}
else
{
CrossAgentToNewRegionDelegate d = entityTransfer . CrossAgentToNewRegionAsync ;
d . BeginInvoke (
av , val , destination , av . Flying , version ,
ar = > CrossAgentToNewRegionCompleted ( d . EndInvoke ( ar ) ) , null ) ;
}
2013-12-16 22:08:02 +00:00
}
else
2014-04-02 23:19:53 +00:00
{
2014-07-10 13:02:38 +00:00
m_log . DebugFormat ( "[SCENE OBJECT]: Not crossing avatar {0} to {1} because it's already in transit" , av . Name , val ) ;
2014-04-02 23:19:53 +00:00
}
2013-12-16 22:08:02 +00:00
}
2014-04-02 23:19:53 +00:00
2013-12-16 22:08:02 +00:00
return ;
}
else // cross failed, put avas back ??
{
foreach ( avtocrossInfo avinfo in avsToCross )
{
ScenePresence av = avinfo . av ;
av . ParentUUID = UUID . Zero ;
av . ParentID = avinfo . ParentID ;
}
}
}
else
{
if ( m_rootPart . KeyframeMotion ! = null )
m_rootPart . KeyframeMotion . CrossingFailure ( ) ;
if ( RootPart . PhysActor ! = null )
{
RootPart . PhysActor . CrossingFailure ( ) ;
}
}
2014-04-02 23:26:55 +00:00
2013-12-16 22:08:02 +00:00
Vector3 oldp = AbsolutePosition ;
2013-12-27 06:45:59 +00:00
val . X = Util . Clamp < float > ( oldp . X , 0.5f , ( float ) m_scene . RegionInfo . RegionSizeX - 0.5f ) ;
val . Y = Util . Clamp < float > ( oldp . Y , 0.5f , ( float ) m_scene . RegionInfo . RegionSizeY - 0.5f ) ;
val . Z = Util . Clamp < float > ( oldp . Z , 0.5f , Constants . RegionHeight ) ;
2011-04-14 16:33:55 +00:00
}
2007-08-24 12:34:00 +00:00
}
2013-12-16 22:08:02 +00:00
2010-02-14 21:41:57 +00:00
if ( RootPart . GetStatusSandbox ( ) )
{
if ( Util . GetDistanceTo ( RootPart . StatusSandboxPos , value ) > 10 )
{
RootPart . ScriptSetPhysicsStatus ( false ) ;
2011-04-14 16:33:55 +00:00
if ( Scene ! = null )
Scene . SimChat ( Utils . StringToBytes ( "Hit Sandbox Limit" ) ,
ChatTypeEnum . DebugChannel , 0x7FFFFFFF , RootPart . AbsolutePosition , Name , UUID , false ) ;
2010-02-14 21:41:57 +00:00
return ;
}
}
2010-09-17 00:30:46 +00:00
2012-07-11 23:07:14 +00:00
// Restuff the new GroupPosition into each SOP of the linkset.
// This has the affect of resetting and tainting the physics actors.
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . GroupPosition = val ;
2008-05-16 01:22:11 +00:00
2008-01-14 18:29:04 +00:00
//if (m_rootPart.PhysActor != null)
//{
2008-04-21 14:11:36 +00:00
//m_rootPart.PhysActor.Position =
//new PhysicsVector(m_rootPart.GroupPosition.X, m_rootPart.GroupPosition.Y,
//m_rootPart.GroupPosition.Z);
//m_scene.PhysicsScene.AddPhysicsActorTaint(m_rootPart.PhysActor);
2008-01-14 18:29:04 +00:00
//}
2011-04-06 19:45:59 +00:00
2011-04-14 16:33:55 +00:00
if ( Scene ! = null )
Scene . EventManager . TriggerParcelPrimCountTainted ( ) ;
2007-08-13 14:39:12 +00:00
}
2007-08-07 18:31:20 +00:00
}
2008-05-16 01:22:11 +00:00
2013-12-16 22:08:02 +00:00
public override Vector3 Velocity
{
get { return RootPart . Velocity ; }
set { RootPart . Velocity = value ; }
}
2014-04-02 23:19:53 +00:00
private void CrossAgentToNewRegionCompleted ( ScenePresence agent )
2013-12-16 22:08:02 +00:00
{
//// If the cross was successful, this agent is a child agent
if ( agent . IsChildAgent )
{
if ( agent . ParentUUID ! = UUID . Zero )
{
agent . ParentPart = null ;
// agent.ParentPosition = Vector3.Zero;
// agent.ParentUUID = UUID.Zero;
}
}
agent . ParentUUID = UUID . Zero ;
// agent.Reset();
// else // Not successful
// agent.RestoreInCurrentScene();
// In any case
agent . IsInTransit = false ;
m_log . DebugFormat ( "[SCENE OBJECT]: Crossing agent {0} {1} completed." , agent . Firstname , agent . Lastname ) ;
}
2007-08-07 18:31:20 +00:00
public override uint LocalId
{
2009-09-16 22:06:08 +00:00
get { return m_rootPart . LocalId ; }
2008-03-05 18:57:13 +00:00
set { m_rootPart . LocalId = value ; }
2007-08-07 18:31:20 +00:00
}
2008-09-06 07:52:41 +00:00
public override UUID UUID
2007-08-07 18:31:20 +00:00
{
2009-09-16 22:06:08 +00:00
get { return m_rootPart . UUID ; }
2010-08-25 22:05:54 +00:00
set
2010-09-17 00:30:46 +00:00
{
2010-09-20 17:35:19 +00:00
lock ( m_parts . SyncRoot )
{
m_parts . Remove ( m_rootPart . UUID ) ;
m_rootPart . UUID = value ;
m_parts . Add ( value , m_rootPart ) ;
}
2010-08-25 22:05:54 +00:00
}
2007-08-07 18:31:20 +00:00
}
2012-01-28 02:21:41 +00:00
public UUID LastOwnerID
{
get { return m_rootPart . LastOwnerID ; }
set { m_rootPart . LastOwnerID = value ; }
}
2008-09-06 07:52:41 +00:00
public UUID OwnerID
2007-08-09 17:54:22 +00:00
{
2009-09-16 22:06:08 +00:00
get { return m_rootPart . OwnerID ; }
2007-11-14 11:56:57 +00:00
set { m_rootPart . OwnerID = value ; }
2007-08-09 17:54:22 +00:00
}
2009-07-15 00:10:01 +00:00
public float Damage
{
get { return m_rootPart . Damage ; }
set { m_rootPart . Damage = value ; }
}
2007-12-04 16:41:20 +00:00
public Color Color
2007-11-11 22:23:34 +00:00
{
get { return m_rootPart . Color ; }
set { m_rootPart . Color = value ; }
}
2007-08-16 16:31:32 +00:00
public string Text
{
2008-05-29 16:21:41 +00:00
get {
string returnstr = m_rootPart . Text ;
if ( returnstr . Length > 255 )
{
returnstr = returnstr . Substring ( 0 , 255 ) ;
}
return returnstr ;
}
2007-08-16 16:31:32 +00:00
set { m_rootPart . Text = value ; }
}
2008-05-25 23:27:38 +00:00
2014-03-22 01:36:21 +00:00
/// <summary>
/// If set to true then the scene object can be backed up in principle, though this will only actually occur
/// if Backup is set. If false then the scene object will never be backed up, Backup will always be false.
/// </summary>
protected virtual bool CanBeBackedUp
2007-09-13 05:25:26 +00:00
{
2007-09-19 00:30:55 +00:00
get { return true ; }
2008-05-25 23:27:38 +00:00
}
2009-12-31 17:41:07 +00:00
2007-08-09 17:54:22 +00:00
public bool IsSelected
{
2007-08-13 14:39:12 +00:00
get { return m_isSelected ; }
2008-04-21 14:11:36 +00:00
set
{
2008-01-29 15:10:18 +00:00
m_isSelected = value ;
// Tell physics engine that group is selected
2012-04-03 04:50:13 +00:00
PhysicsActor pa = m_rootPart . PhysActor ;
if ( pa ! = null )
2008-01-29 15:10:18 +00:00
{
2012-04-03 04:50:13 +00:00
pa . Selected = value ;
2008-02-23 11:42:55 +00:00
// Pass it on to the children.
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-02-23 11:42:55 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart child = parts [ i ] ;
2012-04-03 04:50:13 +00:00
PhysicsActor childPa = child . PhysActor ;
if ( childPa ! = null )
childPa . Selected = value ;
2008-02-23 11:42:55 +00:00
}
2008-01-29 15:10:18 +00:00
}
2013-06-06 02:03:05 +00:00
if ( RootPart . KeyframeMotion ! = null )
RootPart . KeyframeMotion . Selected = value ;
2008-01-29 15:10:18 +00:00
}
2007-08-09 17:54:22 +00:00
}
2010-02-14 21:41:57 +00:00
private SceneObjectPart m_PlaySoundMasterPrim = null ;
public SceneObjectPart PlaySoundMasterPrim
{
get { return m_PlaySoundMasterPrim ; }
set { m_PlaySoundMasterPrim = value ; }
}
private List < SceneObjectPart > m_PlaySoundSlavePrims = new List < SceneObjectPart > ( ) ;
public List < SceneObjectPart > PlaySoundSlavePrims
{
2010-03-03 23:40:32 +00:00
get { return m_PlaySoundSlavePrims ; }
set { m_PlaySoundSlavePrims = value ; }
2010-02-14 21:41:57 +00:00
}
private SceneObjectPart m_LoopSoundMasterPrim = null ;
public SceneObjectPart LoopSoundMasterPrim
{
get { return m_LoopSoundMasterPrim ; }
set { m_LoopSoundMasterPrim = value ; }
}
private List < SceneObjectPart > m_LoopSoundSlavePrims = new List < SceneObjectPart > ( ) ;
public List < SceneObjectPart > LoopSoundSlavePrims
{
get { return m_LoopSoundSlavePrims ; }
set { m_LoopSoundSlavePrims = value ; }
}
2012-04-06 23:33:02 +00:00
/// <summary>
/// The UUID for the region this object is in.
/// </summary>
2008-09-06 07:52:41 +00:00
public UUID RegionUUID
2007-08-20 16:07:37 +00:00
{
get
{
if ( m_scene ! = null )
2007-09-19 00:30:55 +00:00
{
2007-10-18 15:10:43 +00:00
return m_scene . RegionInfo . RegionID ;
2007-09-19 00:30:55 +00:00
}
2008-09-06 07:52:41 +00:00
return UUID . Zero ;
2007-08-20 16:07:37 +00:00
}
}
2007-09-19 00:30:55 +00:00
2012-04-06 23:40:55 +00:00
/// <summary>
/// The item ID that this object was rezzed from, if applicable.
/// </summary>
/// <remarks>
/// If not applicable will be UUID.Zero
/// </remarks>
public UUID FromItemID { get ; set ; }
2012-08-02 10:19:33 +00:00
/// <summary>
/// Refers to the SceneObjectPart.UUID property of the object that this object was rezzed from, if applicable.
/// </summary>
/// <remarks>
/// If not applicable will be UUID.Zero
/// </remarks>
2012-08-03 01:26:54 +00:00
public UUID FromPartID { get ; set ; }
2012-08-02 10:19:33 +00:00
2012-04-06 23:40:55 +00:00
/// <summary>
/// The folder ID that this object was rezzed from, if applicable.
/// </summary>
/// <remarks>
/// If not applicable will be UUID.Zero
/// </remarks>
public UUID FromFolderID { get ; set ; }
2012-04-06 23:33:02 +00:00
2014-08-29 22:40:21 +00:00
/// <summary>
/// If true then grabs are blocked no matter what the individual part BlockGrab setting.
/// </summary>
/// <value><c>true</c> if block grab override; otherwise, <c>false</c>.</value>
public bool BlockGrabOverride { get ; set ; }
2013-01-04 20:34:39 +00:00
/// <summary>
/// IDs of all avatars sat on this scene object.
/// </summary>
/// <remarks>
/// We need this so that we can maintain a linkset wide ordering of avatars sat on different parts.
/// This must be locked before it is read or written.
/// SceneObjectPart sitting avatar add/remove code also locks on this object to avoid race conditions.
/// No avatar should appear more than once in this list.
/// Do not manipulate this list directly - use the Add/Remove sitting avatar methods on SceneObjectPart.
/// </remarks>
2014-04-03 00:14:39 +00:00
protected internal List < ScenePresence > m_sittingAvatars = new List < ScenePresence > ( ) ;
2013-01-04 20:34:39 +00:00
2007-08-13 13:36:42 +00:00
# endregion
2011-06-10 19:40:14 +00:00
// ~SceneObjectGroup()
// {
2012-02-07 23:03:53 +00:00
// //m_log.DebugFormat("[SCENE OBJECT GROUP]: Destructor called for {0}, local id {1}", Name, LocalId);
// Console.WriteLine("Destructor called for {0}, local id {1}", Name, LocalId);
2011-06-10 19:40:14 +00:00
// }
2007-08-13 13:36:42 +00:00
#region Constructors
2007-09-19 00:30:55 +00:00
2009-09-30 16:51:02 +00:00
/// <summary>
/// Constructor
/// </summary>
public SceneObjectGroup ( )
{
}
2007-11-13 19:57:11 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
/// This constructor creates a SceneObjectGroup using a pre-existing SceneObjectPart.
/// The original SceneObjectPart will be used rather than a copy, preserving
2007-11-13 19:57:11 +00:00
/// its existing localID and UUID.
2008-05-16 01:22:11 +00:00
/// </summary>
2012-08-03 01:08:04 +00:00
/// <param name='part'>Root part for this scene object.</param>
2012-08-03 21:15:06 +00:00
public SceneObjectGroup ( SceneObjectPart part ) : this ( )
2007-12-04 16:41:20 +00:00
{
2008-11-10 19:47:13 +00:00
SetRootPart ( part ) ;
2007-11-13 19:57:11 +00:00
}
2009-01-02 17:22:24 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2008-11-06 22:21:25 +00:00
/// Constructor. This object is added to the scene later via AttachToScene()
2008-04-21 14:11:36 +00:00
/// </summary>
2012-08-03 01:08:04 +00:00
public SceneObjectGroup ( UUID ownerID , Vector3 pos , Quaternion rot , PrimitiveBaseShape shape )
: this ( new SceneObjectPart ( ownerID , shape , pos , rot , Vector3 . Zero ) )
2009-09-16 22:06:08 +00:00
{
2008-04-21 14:11:36 +00:00
}
2008-08-18 00:39:10 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2008-11-06 22:21:25 +00:00
/// Constructor.
2008-04-21 14:11:36 +00:00
/// </summary>
2008-11-07 21:07:14 +00:00
public SceneObjectGroup ( UUID ownerID , Vector3 pos , PrimitiveBaseShape shape )
: this ( ownerID , pos , Quaternion . Identity , shape )
2008-04-21 14:11:36 +00:00
{
}
2009-05-08 15:47:59 +00:00
public void LoadScriptState ( XmlDocument doc )
2009-04-22 18:09:55 +00:00
{
2009-04-23 14:38:55 +00:00
XmlNodeList nodes = doc . GetElementsByTagName ( "SavedScriptState" ) ;
if ( nodes . Count > 0 )
2009-04-22 18:09:55 +00:00
{
2010-11-16 21:01:56 +00:00
if ( m_savedScriptState = = null )
m_savedScriptState = new Dictionary < UUID , string > ( ) ;
2009-04-23 14:38:55 +00:00
foreach ( XmlNode node in nodes )
{
if ( node . Attributes [ "UUID" ] ! = null )
{
UUID itemid = new UUID ( node . Attributes [ "UUID" ] . Value ) ;
2010-11-16 21:01:56 +00:00
if ( itemid ! = UUID . Zero )
m_savedScriptState [ itemid ] = node . InnerXml ;
2009-04-23 14:38:55 +00:00
}
}
2009-04-22 18:09:55 +00:00
}
}
2014-08-29 18:08:23 +00:00
public void LoadScriptState ( XmlReader reader )
2014-08-28 17:15:33 +00:00
{
// m_log.DebugFormat("[SCENE OBJECT GROUP]: Looking for script state for {0} in {1}", Name);
while ( reader . ReadToFollowing ( "SavedScriptState" ) )
{
// m_log.DebugFormat("[SCENE OBJECT GROUP]: Loading script state for {0}", Name);
if ( m_savedScriptState = = null )
m_savedScriptState = new Dictionary < UUID , string > ( ) ;
string uuid = reader . GetAttribute ( "UUID" ) ;
if ( uuid ! = null )
{
// m_log.DebugFormat("[SCENE OBJECT GROUP]: Found state for item ID {0} in object {1}", uuid, Name);
UUID itemid = new UUID ( uuid ) ;
if ( itemid ! = UUID . Zero )
m_savedScriptState [ itemid ] = reader . ReadInnerXml ( ) ;
}
else
{
m_log . WarnFormat ( "[SCENE OBJECT GROUP]: SavedScriptState element had no UUID in object {0}" , Name ) ;
}
}
}
2008-04-01 17:06:33 +00:00
/// <summary>
/// Hooks this object up to the backup event so that it is persisted to the database when the update thread executes.
/// </summary>
2009-07-02 12:00:39 +00:00
public virtual void AttachToBackup ( )
2007-09-13 05:25:26 +00:00
{
2014-03-22 01:36:21 +00:00
if ( CanBeBackedUp )
2007-09-13 05:25:26 +00:00
{
2014-09-27 00:02:27 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Attaching object {0} {1} to scene presistence sweep", Name, UUID);
2008-05-25 23:27:38 +00:00
2014-03-22 00:29:13 +00:00
if ( ! Backup )
2008-10-18 05:51:36 +00:00
m_scene . EventManager . OnBackup + = ProcessBackup ;
2009-01-29 18:39:33 +00:00
2014-03-22 00:29:13 +00:00
Backup = true ;
2007-09-13 05:25:26 +00:00
}
}
2008-11-06 22:21:25 +00:00
/// <summary>
2008-11-07 19:30:20 +00:00
/// Attach this object to a scene. It will also now appear to agents.
2008-11-06 22:21:25 +00:00
/// </summary>
/// <param name="scene"></param>
public void AttachToScene ( Scene scene )
{
2009-09-30 16:00:09 +00:00
m_scene = scene ;
2008-11-07 18:46:11 +00:00
RegionHandle = m_scene . RegionInfo . RegionHandle ;
2008-11-20 00:13:15 +00:00
2008-11-29 01:33:10 +00:00
if ( m_rootPart . Shape . PCode ! = 9 | | m_rootPart . Shape . State = = 0 )
m_rootPart . ParentID = 0 ;
2010-02-16 14:36:08 +00:00
if ( m_rootPart . LocalId = = 0 )
2008-11-21 18:44:48 +00:00
m_rootPart . LocalId = m_scene . AllocateLocalId ( ) ;
2008-11-20 00:13:15 +00:00
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-11-07 18:46:11 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
2013-06-12 23:13:00 +00:00
if ( part . KeyframeMotion ! = null )
{
part . KeyframeMotion . UpdateSceneObject ( this ) ;
}
2010-09-17 00:30:46 +00:00
if ( Object . ReferenceEquals ( part , m_rootPart ) )
continue ;
if ( part . LocalId = = 0 )
part . LocalId = m_scene . AllocateLocalId ( ) ;
part . ParentID = m_rootPart . LocalId ;
//m_log.DebugFormat("[SCENE]: Given local id {0} to part {1}, linknum {2}, parent {3} {4}", part.LocalId, part.UUID, part.LinkNum, part.ParentID, part.ParentUUID);
2008-11-07 18:46:11 +00:00
}
2011-07-12 01:33:09 +00:00
2011-12-22 19:52:09 +00:00
ApplyPhysics ( ) ;
2010-03-03 22:14:06 +00:00
// Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
2010-03-10 04:15:36 +00:00
// for the same object with very different properties. The caller must schedule the update.
2010-03-03 22:14:06 +00:00
//ScheduleGroupForFullUpdate();
2008-11-06 22:21:25 +00:00
}
2008-05-25 23:27:38 +00:00
2008-05-01 15:17:49 +00:00
public EntityIntersection TestIntersection ( Ray hRay , bool frontFacesOnly , bool faceCenters )
2007-11-23 05:56:35 +00:00
{
2007-11-30 16:29:23 +00:00
// We got a request from the inner_scene to raytrace along the Ray hRay
// We're going to check all of the prim in this group for intersection with the ray
// If we get a result, we're going to find the closest result to the origin of the ray
// and send back the intersection information back to the innerscene.
2009-08-14 08:16:41 +00:00
EntityIntersection result = new EntityIntersection ( ) ;
2007-11-30 16:29:23 +00:00
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-11-23 05:56:35 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
2007-12-04 16:41:20 +00:00
2010-09-17 00:30:46 +00:00
// Temporary commented to stop compiler warning
//Vector3 partPosition =
// new Vector3(part.AbsolutePosition.X, part.AbsolutePosition.Y, part.AbsolutePosition.Z);
Quaternion parentrotation = GroupRotation ;
2008-03-23 06:24:59 +00:00
2010-09-17 00:30:46 +00:00
// Telling the prim to raytrace.
//EntityIntersection inter = part.TestIntersection(hRay, parentrotation);
2007-12-04 16:41:20 +00:00
2010-09-17 00:30:46 +00:00
EntityIntersection inter = part . TestIntersectionOBB ( hRay , parentrotation , frontFacesOnly , faceCenters ) ;
2007-11-23 05:56:35 +00:00
2010-09-17 00:30:46 +00:00
// This may need to be updated to the maximum draw distance possible..
// We might (and probably will) be checking for prim creation from other sims
// when the camera crosses the border.
float idist = Constants . RegionSize ;
if ( inter . HitTF )
{
// We need to find the closest prim to return to the testcaller along the ray
if ( inter . distance < idist )
2007-12-04 16:41:20 +00:00
{
2010-09-17 00:30:46 +00:00
result . HitTF = true ;
result . ipoint = inter . ipoint ;
result . obj = part ;
result . normal = inter . normal ;
result . distance = inter . distance ;
2007-11-23 05:56:35 +00:00
}
}
}
2010-09-17 00:30:46 +00:00
2009-08-14 08:16:41 +00:00
return result ;
2007-11-23 05:56:35 +00:00
}
2007-12-04 16:41:20 +00:00
2009-07-13 14:42:46 +00:00
/// <summary>
/// Gets a vector representing the size of the bounding box containing all the prims in the group
/// Treats all prims as rectangular, so no shape (cut etc) is taken into account
2009-07-15 19:46:32 +00:00
/// offsetHeight is the offset in the Z axis from the centre of the bounding box to the centre of the root prim
2009-07-13 14:42:46 +00:00
/// </summary>
/// <returns></returns>
2010-05-31 23:07:46 +00:00
public void GetAxisAlignedBoundingBoxRaw ( out float minX , out float maxX , out float minY , out float maxY , out float minZ , out float maxZ )
2009-07-13 14:42:46 +00:00
{
2010-05-31 23:07:46 +00:00
maxX = - 256f ;
maxY = - 256f ;
maxZ = - 256f ;
2013-11-05 06:09:52 +00:00
minX = 10000f ;
minY = 10000f ;
minZ = 10000f ;
2010-05-31 23:07:46 +00:00
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2009-07-13 14:42:46 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
2009-07-13 14:42:46 +00:00
2010-09-17 00:30:46 +00:00
Vector3 worldPos = part . GetWorldPosition ( ) ;
Vector3 offset = worldPos - AbsolutePosition ;
Quaternion worldRot ;
if ( part . ParentID = = 0 )
worldRot = part . RotationOffset ;
else
worldRot = part . GetWorldRotation ( ) ;
Vector3 frontTopLeft ;
Vector3 frontTopRight ;
Vector3 frontBottomLeft ;
Vector3 frontBottomRight ;
Vector3 backTopLeft ;
Vector3 backTopRight ;
Vector3 backBottomLeft ;
Vector3 backBottomRight ;
Vector3 orig = Vector3 . Zero ;
frontTopLeft . X = orig . X - ( part . Scale . X / 2 ) ;
frontTopLeft . Y = orig . Y - ( part . Scale . Y / 2 ) ;
frontTopLeft . Z = orig . Z + ( part . Scale . Z / 2 ) ;
frontTopRight . X = orig . X - ( part . Scale . X / 2 ) ;
frontTopRight . Y = orig . Y + ( part . Scale . Y / 2 ) ;
frontTopRight . Z = orig . Z + ( part . Scale . Z / 2 ) ;
frontBottomLeft . X = orig . X - ( part . Scale . X / 2 ) ;
frontBottomLeft . Y = orig . Y - ( part . Scale . Y / 2 ) ;
frontBottomLeft . Z = orig . Z - ( part . Scale . Z / 2 ) ;
frontBottomRight . X = orig . X - ( part . Scale . X / 2 ) ;
frontBottomRight . Y = orig . Y + ( part . Scale . Y / 2 ) ;
frontBottomRight . Z = orig . Z - ( part . Scale . Z / 2 ) ;
backTopLeft . X = orig . X + ( part . Scale . X / 2 ) ;
backTopLeft . Y = orig . Y - ( part . Scale . Y / 2 ) ;
backTopLeft . Z = orig . Z + ( part . Scale . Z / 2 ) ;
backTopRight . X = orig . X + ( part . Scale . X / 2 ) ;
backTopRight . Y = orig . Y + ( part . Scale . Y / 2 ) ;
backTopRight . Z = orig . Z + ( part . Scale . Z / 2 ) ;
backBottomLeft . X = orig . X + ( part . Scale . X / 2 ) ;
backBottomLeft . Y = orig . Y - ( part . Scale . Y / 2 ) ;
backBottomLeft . Z = orig . Z - ( part . Scale . Z / 2 ) ;
backBottomRight . X = orig . X + ( part . Scale . X / 2 ) ;
backBottomRight . Y = orig . Y + ( part . Scale . Y / 2 ) ;
backBottomRight . Z = orig . Z - ( part . Scale . Z / 2 ) ;
frontTopLeft = frontTopLeft * worldRot ;
frontTopRight = frontTopRight * worldRot ;
frontBottomLeft = frontBottomLeft * worldRot ;
frontBottomRight = frontBottomRight * worldRot ;
backBottomLeft = backBottomLeft * worldRot ;
backBottomRight = backBottomRight * worldRot ;
backTopLeft = backTopLeft * worldRot ;
backTopRight = backTopRight * worldRot ;
frontTopLeft + = offset ;
frontTopRight + = offset ;
frontBottomLeft + = offset ;
frontBottomRight + = offset ;
backBottomLeft + = offset ;
backBottomRight + = offset ;
backTopLeft + = offset ;
backTopRight + = offset ;
if ( frontTopRight . X > maxX )
maxX = frontTopRight . X ;
if ( frontTopLeft . X > maxX )
maxX = frontTopLeft . X ;
if ( frontBottomRight . X > maxX )
maxX = frontBottomRight . X ;
if ( frontBottomLeft . X > maxX )
maxX = frontBottomLeft . X ;
if ( backTopRight . X > maxX )
maxX = backTopRight . X ;
if ( backTopLeft . X > maxX )
maxX = backTopLeft . X ;
if ( backBottomRight . X > maxX )
maxX = backBottomRight . X ;
if ( backBottomLeft . X > maxX )
maxX = backBottomLeft . X ;
if ( frontTopRight . X < minX )
minX = frontTopRight . X ;
if ( frontTopLeft . X < minX )
minX = frontTopLeft . X ;
if ( frontBottomRight . X < minX )
minX = frontBottomRight . X ;
if ( frontBottomLeft . X < minX )
minX = frontBottomLeft . X ;
if ( backTopRight . X < minX )
minX = backTopRight . X ;
if ( backTopLeft . X < minX )
minX = backTopLeft . X ;
if ( backBottomRight . X < minX )
minX = backBottomRight . X ;
if ( backBottomLeft . X < minX )
minX = backBottomLeft . X ;
/ /
if ( frontTopRight . Y > maxY )
maxY = frontTopRight . Y ;
if ( frontTopLeft . Y > maxY )
maxY = frontTopLeft . Y ;
if ( frontBottomRight . Y > maxY )
maxY = frontBottomRight . Y ;
if ( frontBottomLeft . Y > maxY )
maxY = frontBottomLeft . Y ;
if ( backTopRight . Y > maxY )
maxY = backTopRight . Y ;
if ( backTopLeft . Y > maxY )
maxY = backTopLeft . Y ;
if ( backBottomRight . Y > maxY )
maxY = backBottomRight . Y ;
if ( backBottomLeft . Y > maxY )
maxY = backBottomLeft . Y ;
if ( frontTopRight . Y < minY )
minY = frontTopRight . Y ;
if ( frontTopLeft . Y < minY )
minY = frontTopLeft . Y ;
if ( frontBottomRight . Y < minY )
minY = frontBottomRight . Y ;
if ( frontBottomLeft . Y < minY )
minY = frontBottomLeft . Y ;
if ( backTopRight . Y < minY )
minY = backTopRight . Y ;
if ( backTopLeft . Y < minY )
minY = backTopLeft . Y ;
if ( backBottomRight . Y < minY )
minY = backBottomRight . Y ;
if ( backBottomLeft . Y < minY )
minY = backBottomLeft . Y ;
/ /
if ( frontTopRight . Z > maxZ )
maxZ = frontTopRight . Z ;
if ( frontTopLeft . Z > maxZ )
maxZ = frontTopLeft . Z ;
if ( frontBottomRight . Z > maxZ )
maxZ = frontBottomRight . Z ;
if ( frontBottomLeft . Z > maxZ )
maxZ = frontBottomLeft . Z ;
if ( backTopRight . Z > maxZ )
maxZ = backTopRight . Z ;
if ( backTopLeft . Z > maxZ )
maxZ = backTopLeft . Z ;
if ( backBottomRight . Z > maxZ )
maxZ = backBottomRight . Z ;
if ( backBottomLeft . Z > maxZ )
maxZ = backBottomLeft . Z ;
if ( frontTopRight . Z < minZ )
minZ = frontTopRight . Z ;
if ( frontTopLeft . Z < minZ )
minZ = frontTopLeft . Z ;
if ( frontBottomRight . Z < minZ )
minZ = frontBottomRight . Z ;
if ( frontBottomLeft . Z < minZ )
minZ = frontBottomLeft . Z ;
if ( backTopRight . Z < minZ )
minZ = backTopRight . Z ;
if ( backTopLeft . Z < minZ )
minZ = backTopLeft . Z ;
if ( backBottomRight . Z < minZ )
minZ = backBottomRight . Z ;
if ( backBottomLeft . Z < minZ )
minZ = backBottomLeft . Z ;
2009-07-13 14:42:46 +00:00
}
2010-05-31 23:07:46 +00:00
}
public Vector3 GetAxisAlignedBoundingBox ( out float offsetHeight )
{
float minX ;
float maxX ;
float minY ;
float maxY ;
float minZ ;
float maxZ ;
2009-07-13 14:42:46 +00:00
2010-05-31 23:07:46 +00:00
GetAxisAlignedBoundingBoxRaw ( out minX , out maxX , out minY , out maxY , out minZ , out maxZ ) ;
2009-07-13 14:42:46 +00:00
Vector3 boundingBox = new Vector3 ( maxX - minX , maxY - minY , maxZ - minZ ) ;
2009-07-15 19:46:32 +00:00
offsetHeight = 0 ;
float lower = ( minZ * - 1 ) ;
if ( lower > maxZ )
{
offsetHeight = lower - ( boundingBox . Z / 2 ) ;
2009-07-17 14:58:54 +00:00
2009-07-15 19:46:32 +00:00
}
else if ( maxZ > lower )
{
offsetHeight = maxZ - ( boundingBox . Z / 2 ) ;
offsetHeight * = - 1 ;
}
2009-07-17 14:58:54 +00:00
// m_log.InfoFormat("BoundingBox is {0} , {1} , {2} ", boundingBox.X, boundingBox.Y, boundingBox.Z);
2009-07-13 14:42:46 +00:00
return boundingBox ;
}
2009-08-14 08:16:41 +00:00
2007-08-13 13:36:42 +00:00
# endregion
2007-07-30 20:11:40 +00:00
2009-05-08 18:05:54 +00:00
public void SaveScriptedState ( XmlTextWriter writer )
2009-04-22 18:09:55 +00:00
{
XmlDocument doc = new XmlDocument ( ) ;
Dictionary < UUID , string > states = new Dictionary < UUID , string > ( ) ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2009-04-22 18:09:55 +00:00
{
2010-09-17 00:30:46 +00:00
Dictionary < UUID , string > pstates = parts [ i ] . Inventory . GetScriptStates ( ) ;
foreach ( KeyValuePair < UUID , string > kvp in pstates )
states . Add ( kvp . Key , kvp . Value ) ;
2009-04-22 18:09:55 +00:00
}
2009-04-23 14:38:55 +00:00
if ( states . Count > 0 )
2009-04-22 18:09:55 +00:00
{
2009-04-23 14:38:55 +00:00
// Now generate the necessary XML wrappings
writer . WriteStartElement ( String . Empty , "GroupScriptStates" , String . Empty ) ;
foreach ( UUID itemid in states . Keys )
{
doc . LoadXml ( states [ itemid ] ) ;
writer . WriteStartElement ( String . Empty , "SavedScriptState" , String . Empty ) ;
writer . WriteAttributeString ( String . Empty , "UUID" , String . Empty , itemid . ToString ( ) ) ;
writer . WriteRaw ( doc . DocumentElement . OuterXml ) ; // Writes ScriptState element
writer . WriteEndElement ( ) ; // End of SavedScriptState
}
writer . WriteEndElement ( ) ; // End of GroupScriptStates
2009-04-22 18:09:55 +00:00
}
2007-10-22 11:06:54 +00:00
}
2013-12-11 01:39:56 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
///
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="part"></param>
private void SetPartAsNonRoot ( SceneObjectPart part )
{
part . ParentID = m_rootPart . LocalId ;
2008-04-28 01:48:21 +00:00
part . ClearUndoState ( ) ;
2008-04-21 14:11:36 +00:00
}
2007-12-27 21:41:48 +00:00
2009-10-28 22:11:01 +00:00
public ushort GetTimeDilation ( )
2008-04-21 14:11:36 +00:00
{
2009-10-28 22:11:01 +00:00
return Utils . FloatToUInt16 ( m_scene . TimeDilation , 0.0f , 1.0f ) ;
2008-04-21 14:11:36 +00:00
}
2008-11-10 19:47:13 +00:00
/// <summary>
/// Set a part to act as the root part for this scene object
/// </summary>
/// <param name="part"></param>
2008-11-10 20:04:55 +00:00
public void SetRootPart ( SceneObjectPart part )
2009-09-16 22:06:08 +00:00
{
if ( part = = null )
throw new ArgumentNullException ( "Cannot give SceneObjectGroup a null root SceneObjectPart" ) ;
2008-11-10 19:47:13 +00:00
part . SetParent ( this ) ;
m_rootPart = part ;
2008-11-29 01:33:10 +00:00
if ( ! IsAttachment )
part . ParentID = 0 ;
2009-09-30 16:00:09 +00:00
part . LinkNum = 0 ;
2008-11-10 20:54:34 +00:00
2010-09-17 00:30:46 +00:00
m_parts . Add ( m_rootPart . UUID , m_rootPart ) ;
2009-09-30 16:00:09 +00:00
}
2007-08-03 14:47:38 +00:00
2007-08-04 18:15:48 +00:00
/// <summary>
2008-11-10 19:47:13 +00:00
/// Add a new part to this scene object. The part must already be correctly configured.
2007-08-04 18:15:48 +00:00
/// </summary>
/// <param name="part"></param>
2008-04-21 14:11:36 +00:00
public void AddPart ( SceneObjectPart part )
2007-08-03 14:47:38 +00:00
{
2010-09-17 00:30:46 +00:00
part . SetParent ( this ) ;
part . LinkNum = m_parts . Add ( part . UUID , part ) ;
2011-09-01 01:09:41 +00:00
if ( part . LinkNum = = 2 )
2010-09-17 00:30:46 +00:00
RootPart . LinkNum = 1 ;
2008-03-14 06:20:50 +00:00
}
2008-04-21 14:11:36 +00:00
/// <summary>
2008-07-12 21:43:35 +00:00
/// Make sure that every non root part has the proper parent root part local id
2008-04-21 14:11:36 +00:00
/// </summary>
2008-11-07 19:17:24 +00:00
private void UpdateParentIDs ( )
2008-03-14 06:20:50 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-03-14 06:20:50 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part . UUID ! = m_rootPart . UUID )
part . ParentID = m_rootPart . LocalId ;
2008-03-14 06:20:50 +00:00
}
}
2008-04-21 14:11:36 +00:00
public void RegenerateFullIDs ( )
2008-01-17 14:59:05 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . UUID = UUID . Random ( ) ;
2008-01-17 14:59:05 +00:00
}
2009-08-14 08:16:41 +00:00
2008-08-18 00:39:10 +00:00
// justincc: I don't believe this hack is needed any longer, especially since the physics
2008-07-25 17:48:58 +00:00
// parts of set AbsolutePosition were already commented out. By changing HasGroupChanged to false
// this method was preventing proper reload of scene objects.
2009-02-08 18:05:12 +00:00
2008-08-18 00:39:10 +00:00
// dahlia: I had to uncomment it, without it meshing was failing on some prims and objects
2008-07-26 01:58:13 +00:00
// at region startup
2009-02-08 18:05:12 +00:00
// teravus: After this was removed from the linking algorithm, Linked prims no longer collided
2009-02-09 20:06:06 +00:00
// properly when non-physical if they havn't been moved. This breaks ALL builds.
2009-02-08 18:05:12 +00:00
// see: http://opensimulator.org/mantis/view.php?id=3108
// Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
// position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
// unmoved prims! As soon as you move a Prim/group, it will collide properly because Absolute
// Position has been set!
2008-07-26 01:58:13 +00:00
public void ResetChildPrimPhysicsPositions ( )
{
2012-07-11 23:07:14 +00:00
// Setting this SOG's absolute position also loops through and sets the positions
// of the SOP's in this SOG's linkset. This has the side affect of making sure
// the physics world matches the simulated world.
2008-07-26 19:51:17 +00:00
AbsolutePosition = AbsolutePosition ; // could someone in the know please explain how this works?
2009-02-08 18:05:12 +00:00
// teravus: AbsolutePosition is NOT a normal property!
// the code in the getter of AbsolutePosition is significantly different then the code in the setter!
2010-09-17 00:30:46 +00:00
// jhurliman: Then why is it a property instead of two methods?
2008-07-26 01:58:13 +00:00
}
2008-03-25 03:36:31 +00:00
2008-09-06 07:52:41 +00:00
public UUID GetPartsFullID ( uint localID )
2007-12-04 16:41:20 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2007-12-05 06:44:32 +00:00
{
2008-04-21 14:11:36 +00:00
return part . UUID ;
2007-12-05 06:44:32 +00:00
}
2008-09-26 17:25:22 +00:00
return UUID . Zero ;
2007-11-14 11:56:57 +00:00
}
2007-08-03 14:47:38 +00:00
2008-09-06 07:52:41 +00:00
public void ObjectGrabHandler ( uint localId , Vector3 offsetPos , IClientAPI remoteClient )
2007-08-03 14:47:38 +00:00
{
2008-04-21 14:11:36 +00:00
if ( m_rootPart . LocalId = = localId )
2008-03-18 20:42:01 +00:00
{
2008-04-21 14:11:36 +00:00
OnGrabGroup ( offsetPos , remoteClient ) ;
2008-03-18 20:42:01 +00:00
}
2008-04-21 14:11:36 +00:00
else
2007-12-01 21:52:10 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localId ) ;
2008-04-21 14:11:36 +00:00
OnGrabPart ( part , offsetPos , remoteClient ) ;
2007-12-01 21:52:10 +00:00
}
}
2007-12-27 21:41:48 +00:00
2008-09-06 07:52:41 +00:00
public virtual void OnGrabPart ( SceneObjectPart part , Vector3 offsetPos , IClientAPI remoteClient )
2007-11-15 07:32:24 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Processing OnGrabPart for {0} on {1} {2}, offsetPos {3}",
// remoteClient.Name, part.Name, part.LocalId, offsetPos);
2008-04-28 01:48:21 +00:00
part . StoreUndoState ( ) ;
2008-04-21 14:11:36 +00:00
part . OnGrab ( offsetPos , remoteClient ) ;
2007-11-15 07:32:24 +00:00
}
2007-12-27 21:41:48 +00:00
2008-09-06 07:52:41 +00:00
public virtual void OnGrabGroup ( Vector3 offsetPos , IClientAPI remoteClient )
2007-11-14 11:56:57 +00:00
{
2008-04-21 14:11:36 +00:00
m_scene . EventManager . TriggerGroupGrab ( UUID , offsetPos , remoteClient . AgentId ) ;
2007-11-14 11:56:57 +00:00
}
2007-09-19 00:30:55 +00:00
2007-08-03 14:47:38 +00:00
/// <summary>
2010-09-12 17:43:49 +00:00
/// Delete this group from its scene.
2009-09-30 16:00:09 +00:00
/// </summary>
2013-05-09 17:02:19 +00:00
/// <remarks>
2010-09-06 23:34:06 +00:00
/// This only handles the in-world consequences of deletion (e.g. any avatars sitting on it are forcibly stood
/// up and all avatars receive notification of its removal. Removal of the scene object from database backup
/// must be handled by the caller.
2013-05-09 17:02:19 +00:00
/// </remarks>
2010-09-06 23:34:06 +00:00
/// <param name="silent">If true then deletion is not broadcast to clients</param>
2010-09-15 21:29:58 +00:00
public void DeleteGroupFromScene ( bool silent )
2007-08-03 14:47:38 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-11-03 19:33:00 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
2013-05-09 17:02:19 +00:00
Scene . ForEachScenePresence ( sp = >
2007-11-03 19:33:00 +00:00
{
2014-05-06 15:00:27 +00:00
if ( ! sp . IsChildAgent & & sp . ParentID = = part . LocalId )
2013-05-09 17:02:19 +00:00
sp . StandUp ( ) ;
2008-04-21 14:11:36 +00:00
2010-09-15 20:41:42 +00:00
if ( ! silent )
{
2011-11-02 21:59:00 +00:00
part . ClearUpdateSchedule ( ) ;
2010-09-15 20:41:42 +00:00
if ( part = = m_rootPart )
2011-09-24 22:51:43 +00:00
{
2012-06-20 22:25:07 +00:00
if ( ! IsAttachment
2013-05-09 17:02:19 +00:00
| | AttachedAvatar = = sp . UUID
2012-06-20 22:25:07 +00:00
| | ! HasPrivateAttachmentPoint )
2013-05-09 17:12:17 +00:00
sp . ControllingClient . SendKillObject ( new List < uint > { part . LocalId } ) ;
2011-09-24 22:51:43 +00:00
}
2010-09-15 20:41:42 +00:00
}
} ) ;
2007-08-03 14:47:38 +00:00
}
}
2008-08-18 00:39:10 +00:00
2008-04-21 14:11:36 +00:00
public void AddScriptLPS ( int count )
2007-09-06 14:15:16 +00:00
{
2012-03-16 00:34:30 +00:00
m_scene . SceneGraph . AddToScriptLPS ( count ) ;
2007-09-06 14:15:16 +00:00
}
2008-04-21 14:11:36 +00:00
public void AddActiveScriptCount ( int count )
2007-08-03 14:47:38 +00:00
{
2009-02-20 17:18:07 +00:00
SceneGraph d = m_scene . SceneGraph ;
2008-04-21 14:11:36 +00:00
d . AddActiveScripts ( count ) ;
2007-08-03 14:47:38 +00:00
}
2008-04-21 14:11:36 +00:00
public void aggregateScriptEvents ( )
2007-07-30 20:11:40 +00:00
{
2010-08-13 19:23:53 +00:00
PrimFlags objectflagupdate = ( PrimFlags ) RootPart . GetEffectiveObjectFlags ( ) ;
2007-07-30 20:11:40 +00:00
2010-08-13 19:23:53 +00:00
scriptEvents aggregateScriptEvents = 0 ;
2007-09-19 00:30:55 +00:00
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-12-17 02:30:03 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part = = null )
continue ;
if ( part ! = RootPart )
part . Flags = objectflagupdate ;
aggregateScriptEvents | = part . AggregateScriptEvents ;
2007-12-17 02:30:03 +00:00
}
2008-04-25 01:00:55 +00:00
2009-08-14 08:16:41 +00:00
m_scriptListens_atTarget = ( ( aggregateScriptEvents & scriptEvents . at_target ) ! = 0 ) ;
m_scriptListens_notAtTarget = ( ( aggregateScriptEvents & scriptEvents . not_at_target ) ! = 0 ) ;
2008-04-25 01:00:55 +00:00
2009-08-14 08:16:41 +00:00
if ( ! m_scriptListens_atTarget & & ! m_scriptListens_notAtTarget )
2008-04-25 01:00:55 +00:00
{
lock ( m_targets )
m_targets . Clear ( ) ;
2009-10-14 02:13:06 +00:00
m_scene . RemoveGroupTarget ( this ) ;
2010-01-11 02:04:05 +00:00
}
m_scriptListens_atRotTarget = ( ( aggregateScriptEvents & scriptEvents . at_rot_target ) ! = 0 ) ;
m_scriptListens_notAtRotTarget = ( ( aggregateScriptEvents & scriptEvents . not_at_rot_target ) ! = 0 ) ;
if ( ! m_scriptListens_atRotTarget & & ! m_scriptListens_notAtRotTarget )
{
lock ( m_rotTargets )
m_rotTargets . Clear ( ) ;
m_scene . RemoveGroupTarget ( this ) ;
2008-04-25 01:00:55 +00:00
}
2008-08-18 00:39:10 +00:00
2008-04-21 14:11:36 +00:00
ScheduleGroupForFullUpdate ( ) ;
2007-12-17 02:30:03 +00:00
}
2010-08-10 11:57:22 +00:00
public void SetText ( string text , Vector3 color , double alpha )
2007-07-30 20:11:40 +00:00
{
2008-04-21 14:11:36 +00:00
Color = Color . FromArgb ( 0xff - ( int ) ( alpha * 0xff ) ,
2008-09-06 07:52:41 +00:00
( int ) ( color . X * 0xff ) ,
( int ) ( color . Y * 0xff ) ,
( int ) ( color . Z * 0xff ) ) ;
2008-04-21 14:11:36 +00:00
Text = text ;
2008-06-27 16:36:19 +00:00
HasGroupChanged = true ;
2008-04-21 14:11:36 +00:00
m_rootPart . ScheduleFullUpdate ( ) ;
2007-07-30 20:11:40 +00:00
}
2008-06-17 17:23:00 +00:00
/// <summary>
/// Apply physics to this group
/// </summary>
2011-12-22 19:52:09 +00:00
public void ApplyPhysics ( )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
// Apply physics to the root prim
2011-10-15 01:47:27 +00:00
m_rootPart . ApplyPhysics ( m_rootPart . GetEffectiveObjectFlags ( ) , m_rootPart . VolumeDetectActive ) ;
2010-09-17 00:30:46 +00:00
// Apply physics to child prims
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
if ( parts . Length > 1 )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
2008-04-21 14:11:36 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part . LocalId ! = m_rootPart . LocalId )
2011-10-15 01:47:27 +00:00
part . ApplyPhysics ( m_rootPart . GetEffectiveObjectFlags ( ) , part . VolumeDetectActive ) ;
2008-04-21 14:11:36 +00:00
}
2010-09-17 00:30:46 +00:00
// Hack to get the physics scene geometries in the right spot
ResetChildPrimPhysicsPositions ( ) ;
2007-07-30 20:11:40 +00:00
}
}
2008-09-06 07:52:41 +00:00
public void SetOwnerId ( UUID userId )
2007-08-02 16:40:50 +00:00
{
2008-04-21 14:11:36 +00:00
ForEachPart ( delegate ( SceneObjectPart part ) { part . OwnerID = userId ; } ) ;
2007-08-02 16:40:50 +00:00
}
2008-04-21 14:11:36 +00:00
public void ForEachPart ( Action < SceneObjectPart > whatToDo )
2007-08-02 16:40:50 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
whatToDo ( parts [ i ] ) ;
2007-08-02 16:40:50 +00:00
}
2008-04-21 14:11:36 +00:00
#region Events
2007-09-19 00:30:55 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2008-09-16 17:30:30 +00:00
/// Processes backup.
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="datastore"></param>
2010-09-12 21:20:26 +00:00
public virtual void ProcessBackup ( ISimulationDataService datastore , bool forcedBackup )
2008-08-18 00:39:10 +00:00
{
2014-03-22 00:29:13 +00:00
if ( ! Backup )
2010-09-06 23:34:06 +00:00
{
// m_log.DebugFormat(
2010-09-12 17:43:49 +00:00
// "[WATER WARS]: Ignoring backup of {0} {1} since object is not marked to be backed up", Name, UUID);
2008-11-16 00:47:21 +00:00
return ;
2010-09-06 23:34:06 +00:00
}
2008-11-16 00:47:21 +00:00
2008-11-17 15:40:27 +00:00
if ( IsDeleted | | UUID = = UUID . Zero )
2010-09-06 23:34:06 +00:00
{
// m_log.DebugFormat(
// "[WATER WARS]: Ignoring backup of {0} {1} since object is marked as already deleted", Name, UUID);
2008-10-18 15:43:02 +00:00
return ;
2010-09-06 23:34:06 +00:00
}
2008-10-18 15:43:02 +00:00
2010-09-06 22:00:24 +00:00
// Since this is the top of the section of call stack for backing up a particular scene object, don't let
2010-09-12 17:43:49 +00:00
// any exception propogate upwards.
2008-09-16 17:30:30 +00:00
try
2008-03-18 20:42:01 +00:00
{
2008-11-15 17:52:00 +00:00
if ( ! m_scene . ShuttingDown ) // if shutting down then there will be nothing to handle the return so leave till next restart
2008-10-18 05:51:36 +00:00
{
2008-11-15 17:52:00 +00:00
ILandObject parcel = m_scene . LandChannel . GetLandObject (
m_rootPart . GroupPosition . X , m_rootPart . GroupPosition . Y ) ;
2009-10-02 09:10:52 +00:00
if ( parcel ! = null & & parcel . LandData ! = null & &
parcel . LandData . OtherCleanTime ! = 0 )
2008-10-18 05:51:36 +00:00
{
2009-10-02 09:10:52 +00:00
if ( parcel . LandData . OwnerID ! = OwnerID & &
( parcel . LandData . GroupID ! = GroupID | |
parcel . LandData . GroupID = = UUID . Zero ) )
2008-10-18 05:51:36 +00:00
{
2009-10-25 07:40:21 +00:00
if ( ( DateTime . UtcNow - RootPart . Rezzed ) . TotalMinutes >
2009-10-02 09:10:52 +00:00
parcel . LandData . OtherCleanTime )
2008-11-15 17:52:00 +00:00
{
2008-11-23 06:57:38 +00:00
DetachFromBackup ( ) ;
2011-04-05 21:25:00 +00:00
m_log . DebugFormat (
"[SCENE OBJECT GROUP]: Returning object {0} due to parcel autoreturn" ,
RootPart . UUID ) ;
2012-02-15 23:07:12 +00:00
m_scene . AddReturn ( OwnerID = = GroupID ? LastOwnerID : OwnerID , Name , AbsolutePosition , "parcel autoreturn" ) ;
2010-10-07 01:16:36 +00:00
m_scene . DeRezObjects ( null , new List < uint > ( ) { RootPart . LocalId } , UUID . Zero ,
DeRezAction . Return , UUID . Zero ) ;
2008-10-18 05:51:36 +00:00
2008-11-15 17:52:00 +00:00
return ;
}
2008-10-18 05:51:36 +00:00
}
}
}
2011-05-24 01:37:25 +00:00
if ( m_scene . UseBackup & & HasGroupChanged )
2008-05-25 19:21:21 +00:00
{
2008-09-16 17:30:30 +00:00
// don't backup while it's selected or you're asking for changes mid stream.
2010-09-06 23:34:06 +00:00
if ( isTimeToPersist ( ) | | forcedBackup )
2008-09-16 17:30:30 +00:00
{
2010-09-13 23:05:38 +00:00
// m_log.DebugFormat(
// "[SCENE]: Storing {0}, {1} in {2}",
// Name, UUID, m_scene.RegionInfo.RegionName);
2008-05-25 23:27:38 +00:00
2010-06-27 23:48:24 +00:00
SceneObjectGroup backup_group = Copy ( false ) ;
2008-09-16 17:30:30 +00:00
backup_group . RootPart . Velocity = RootPart . Velocity ;
backup_group . RootPart . Acceleration = RootPart . Acceleration ;
backup_group . RootPart . AngularVelocity = RootPart . AngularVelocity ;
backup_group . RootPart . ParticleSystem = RootPart . ParticleSystem ;
2008-11-15 17:52:00 +00:00
HasGroupChanged = false ;
2013-10-24 08:18:15 +00:00
GroupContainsForeignPrims = false ;
2008-05-25 23:27:38 +00:00
2010-07-26 19:36:28 +00:00
m_scene . EventManager . TriggerOnSceneObjectPreSave ( backup_group , this ) ;
2008-09-16 17:30:30 +00:00
datastore . StoreObject ( backup_group , m_scene . RegionInfo . RegionID ) ;
2008-05-25 01:09:14 +00:00
2009-01-29 18:39:33 +00:00
backup_group . ForEachPart ( delegate ( SceneObjectPart part )
{
part . Inventory . ProcessInventoryBackup ( datastore ) ;
} ) ;
2008-05-25 23:27:38 +00:00
2008-09-16 17:30:30 +00:00
backup_group = null ;
}
2010-09-06 23:34:06 +00:00
// else
// {
// m_log.DebugFormat(
// "[SCENE]: Did not update persistence of object {0} {1}, selected = {2}",
// Name, UUID, IsSelected);
// }
2008-05-25 19:21:21 +00:00
}
2008-09-16 17:30:30 +00:00
}
catch ( Exception e )
{
m_log . ErrorFormat (
2010-09-06 23:34:06 +00:00
"[SCENE]: Storing of {0}, {1} in {2} failed with exception {3}{4}" ,
Name , UUID , m_scene . RegionInfo . RegionName , e . Message , e . StackTrace ) ;
2008-03-18 20:42:01 +00:00
}
2008-04-21 14:11:36 +00:00
}
2007-11-20 04:38:08 +00:00
2008-04-21 14:11:36 +00:00
# endregion
2007-08-24 11:04:07 +00:00
2011-12-17 00:11:17 +00:00
/// <summary>
/// Send the parts of this SOG to a single client
/// </summary>
/// <remarks>
/// Used when the client initially connects and when client sends RequestPrim packet
/// </remarks>
/// <param name="remoteClient"></param>
2008-11-07 05:48:44 +00:00
public void SendFullUpdateToClient ( IClientAPI remoteClient )
2008-04-21 14:11:36 +00:00
{
2011-12-16 23:20:12 +00:00
RootPart . SendFullUpdate ( remoteClient ) ;
2008-11-07 05:48:44 +00:00
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-08-20 15:49:06 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part ! = RootPart )
2011-12-16 23:20:12 +00:00
part . SendFullUpdate ( remoteClient ) ;
2008-04-21 14:11:36 +00:00
}
}
2007-09-13 05:25:26 +00:00
2008-04-21 14:11:36 +00:00
#region Copying
2007-12-04 16:41:20 +00:00
2007-11-13 19:57:11 +00:00
/// <summary>
2008-04-21 14:11:36 +00:00
/// Duplicates this object, including operations such as physics set up and attaching to the backup event.
2007-11-13 19:57:11 +00:00
/// </summary>
2010-07-28 18:38:20 +00:00
/// <param name="userExposed">True if the duplicate will immediately be in the scene, false otherwise</param>
2008-04-21 14:11:36 +00:00
/// <returns></returns>
2010-06-27 23:48:24 +00:00
public SceneObjectGroup Copy ( bool userExposed )
2008-04-21 14:11:36 +00:00
{
2014-04-02 23:19:53 +00:00
// FIXME: This is dangerous since it's easy to forget to reset some references when necessary and end up
// with bugs that only occur in some circumstances (e.g. crossing between regions on the same simulator
// but not between regions on different simulators). Really, all copying should be done explicitly.
2009-02-03 17:50:25 +00:00
SceneObjectGroup dupe = ( SceneObjectGroup ) MemberwiseClone ( ) ;
2014-04-02 23:19:53 +00:00
2014-03-22 00:29:13 +00:00
dupe . Backup = false ;
2010-09-17 00:57:00 +00:00
dupe . m_parts = new MapAndArray < OpenMetaverse . UUID , SceneObjectPart > ( ) ;
2014-04-03 00:14:39 +00:00
dupe . m_sittingAvatars = new List < ScenePresence > ( ) ;
2008-05-21 21:22:56 +00:00
dupe . CopyRootPart ( m_rootPart , OwnerID , GroupID , userExposed ) ;
2008-11-26 07:34:38 +00:00
dupe . m_rootPart . LinkNum = m_rootPart . LinkNum ;
2008-05-21 21:22:56 +00:00
if ( userExposed )
dupe . m_rootPart . TrimPermissions ( ) ;
2008-01-15 04:27:02 +00:00
2010-09-17 00:30:46 +00:00
List < SceneObjectPart > partList = new List < SceneObjectPart > ( m_parts . GetArray ( ) ) ;
2009-02-03 18:06:24 +00:00
2008-11-26 07:34:38 +00:00
partList . Sort ( delegate ( SceneObjectPart p1 , SceneObjectPart p2 )
{
return p1 . LinkNum . CompareTo ( p2 . LinkNum ) ;
}
) ;
2008-04-21 14:11:36 +00:00
foreach ( SceneObjectPart part in partList )
2007-11-13 19:57:11 +00:00
{
2011-06-15 18:26:45 +00:00
SceneObjectPart newPart ;
2008-04-21 14:11:36 +00:00
if ( part . UUID ! = m_rootPart . UUID )
{
2011-06-15 18:26:45 +00:00
newPart = dupe . CopyPart ( part , OwnerID , GroupID , userExposed ) ;
2008-11-26 07:34:38 +00:00
newPart . LinkNum = part . LinkNum ;
2008-04-21 14:11:36 +00:00
}
2011-06-15 18:26:45 +00:00
else
{
newPart = dupe . m_rootPart ;
}
2007-08-13 13:36:42 +00:00
2010-09-12 17:43:49 +00:00
// Need to duplicate the physics actor as well
2012-04-03 04:50:13 +00:00
PhysicsActor originalPartPa = part . PhysActor ;
if ( originalPartPa ! = null & & userExposed )
2010-08-10 19:15:44 +00:00
{
2011-07-14 19:38:35 +00:00
PrimitiveBaseShape pbs = newPart . Shape ;
2010-08-10 19:15:44 +00:00
2011-06-15 18:26:45 +00:00
newPart . PhysActor
2010-08-10 19:15:44 +00:00
= m_scene . PhysicsScene . AddPrimShape (
2011-07-14 19:38:35 +00:00
string . Format ( "{0}/{1}" , newPart . Name , newPart . UUID ) ,
2010-08-10 19:15:44 +00:00
pbs ,
2011-07-14 19:38:35 +00:00
newPart . AbsolutePosition ,
newPart . Scale ,
newPart . RotationOffset ,
2012-04-03 04:50:13 +00:00
originalPartPa . IsPhysical ,
2011-07-15 19:07:59 +00:00
newPart . LocalId ) ;
2010-08-10 19:15:44 +00:00
2012-04-03 04:50:13 +00:00
newPart . DoPhysicsPropertyUpdate ( originalPartPa . IsPhysical , true ) ;
2010-09-12 17:43:49 +00:00
}
2013-06-06 02:03:05 +00:00
if ( part . KeyframeMotion ! = null )
newPart . KeyframeMotion = part . KeyframeMotion . Copy ( dupe ) ;
2010-08-10 19:15:44 +00:00
}
2008-05-21 21:22:56 +00:00
if ( userExposed )
{
dupe . UpdateParentIDs ( ) ;
2008-06-27 16:36:19 +00:00
dupe . HasGroupChanged = true ;
2008-05-21 21:22:56 +00:00
dupe . AttachToBackup ( ) ;
2008-08-18 00:39:10 +00:00
2008-05-21 21:22:56 +00:00
ScheduleGroupForFullUpdate ( ) ;
}
2008-04-21 14:11:36 +00:00
return dupe ;
2007-09-13 05:25:26 +00:00
}
2008-04-21 14:11:36 +00:00
/// <summary>
2010-08-25 23:08:53 +00:00
/// Copy the given part as the root part of this scene object.
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="part"></param>
/// <param name="cAgentID"></param>
/// <param name="cGroupID"></param>
2008-09-06 07:52:41 +00:00
public void CopyRootPart ( SceneObjectPart part , UUID cAgentID , UUID cGroupID , bool userExposed )
2007-08-20 15:49:06 +00:00
{
2010-08-25 23:15:26 +00:00
SetRootPart ( part . Copy ( m_scene . AllocateLocalId ( ) , OwnerID , GroupID , 0 , userExposed ) ) ;
2008-04-21 14:11:36 +00:00
}
2007-08-21 16:25:57 +00:00
2011-08-24 20:53:12 +00:00
public void ScriptSetPhysicsStatus ( bool usePhysics )
2008-04-21 14:11:36 +00:00
{
2013-06-06 02:03:05 +00:00
if ( usePhysics )
{
if ( RootPart . KeyframeMotion ! = null )
RootPart . KeyframeMotion . Stop ( ) ;
RootPart . KeyframeMotion = null ;
}
2011-08-24 20:53:12 +00:00
UpdatePrimFlags ( RootPart . LocalId , usePhysics , IsTemporary , IsPhantom , IsVolumeDetect ) ;
2008-11-07 22:57:32 +00:00
}
2007-08-21 16:25:57 +00:00
2011-08-24 20:53:12 +00:00
public void ScriptSetTemporaryStatus ( bool makeTemporary )
2008-11-07 22:57:32 +00:00
{
2011-08-24 20:53:12 +00:00
UpdatePrimFlags ( RootPart . LocalId , UsesPhysics , makeTemporary , IsPhantom , IsVolumeDetect ) ;
2007-08-20 15:49:06 +00:00
}
2011-08-24 20:53:12 +00:00
public void ScriptSetPhantomStatus ( bool makePhantom )
2007-07-30 20:11:40 +00:00
{
2011-08-24 20:53:12 +00:00
UpdatePrimFlags ( RootPart . LocalId , UsesPhysics , IsTemporary , makePhantom , IsVolumeDetect ) ;
2008-12-20 21:36:42 +00:00
}
2011-08-24 20:53:12 +00:00
public void ScriptSetVolumeDetect ( bool makeVolumeDetect )
2008-12-20 21:36:42 +00:00
{
2011-08-24 20:53:12 +00:00
UpdatePrimFlags ( RootPart . LocalId , UsesPhysics , IsTemporary , IsPhantom , makeVolumeDetect ) ;
2008-12-20 21:36:42 +00:00
/ *
ScriptSetPhantomStatus ( false ) ; // What ever it was before, now it's not phantom anymore
if ( PhysActor ! = null ) // Should always be the case now
{
PhysActor . SetVolumeDetect ( param ) ;
}
if ( param ! = 0 )
AddFlag ( PrimFlags . Phantom ) ;
ScheduleFullUpdate ( ) ;
* /
2007-07-30 20:11:40 +00:00
}
2009-10-26 06:16:12 +00:00
public void applyImpulse ( Vector3 impulse )
2007-07-30 20:11:40 +00:00
{
2011-09-01 01:09:41 +00:00
if ( IsAttachment )
2008-04-21 14:11:36 +00:00
{
2011-09-01 01:09:41 +00:00
ScenePresence avatar = m_scene . GetScenePresence ( AttachedAvatar ) ;
if ( avatar ! = null )
2008-04-21 14:11:36 +00:00
{
2011-09-01 01:09:41 +00:00
avatar . PushForce ( impulse ) ;
2009-03-21 11:42:31 +00:00
}
2011-09-01 01:09:41 +00:00
}
else
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = RootPart . PhysActor ;
if ( pa ! = null )
2009-03-21 11:42:31 +00:00
{
2012-04-03 04:50:13 +00:00
pa . AddForce ( impulse , true ) ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( pa ) ;
2008-04-21 14:11:36 +00:00
}
}
2007-07-30 20:11:40 +00:00
}
2009-10-26 06:16:12 +00:00
public void applyAngularImpulse ( Vector3 impulse )
2008-12-14 14:30:28 +00:00
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = RootPart . PhysActor ;
if ( pa ! = null )
2008-12-14 14:30:28 +00:00
{
2011-09-01 01:09:41 +00:00
if ( ! IsAttachment )
2008-12-14 14:30:28 +00:00
{
2012-04-03 04:50:13 +00:00
pa . AddAngularForce ( impulse , true ) ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( pa ) ;
2008-12-14 14:30:28 +00:00
}
}
}
2009-10-26 06:16:12 +00:00
public void setAngularImpulse ( Vector3 impulse )
2008-12-14 14:30:28 +00:00
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = RootPart . PhysActor ;
if ( pa ! = null )
2008-12-14 14:30:28 +00:00
{
2011-09-01 01:09:41 +00:00
if ( ! IsAttachment )
2008-12-14 14:30:28 +00:00
{
2012-04-03 04:50:13 +00:00
pa . Torque = impulse ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( pa ) ;
2008-12-14 14:30:28 +00:00
}
}
}
public Vector3 GetTorque ( )
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = RootPart . PhysActor ;
if ( pa ! = null )
2008-12-14 14:30:28 +00:00
{
2011-09-01 01:09:41 +00:00
if ( ! IsAttachment )
2008-12-14 14:30:28 +00:00
{
2012-04-03 04:50:13 +00:00
Vector3 torque = pa . Torque ;
2011-09-01 01:09:41 +00:00
return torque ;
2008-12-14 14:30:28 +00:00
}
}
2011-09-01 01:09:41 +00:00
2008-12-14 14:30:28 +00:00
return Vector3 . Zero ;
}
2008-09-06 07:52:41 +00:00
public void moveToTarget ( Vector3 target , float tau )
2007-08-09 17:54:22 +00:00
{
2011-09-01 01:09:41 +00:00
if ( IsAttachment )
2007-08-13 14:39:12 +00:00
{
2011-09-01 01:09:41 +00:00
ScenePresence avatar = m_scene . GetScenePresence ( AttachedAvatar ) ;
if ( avatar ! = null )
2009-04-22 14:44:19 +00:00
{
2011-09-21 23:16:05 +00:00
avatar . MoveToTarget ( target , false , false ) ;
2009-04-22 14:44:19 +00:00
}
2011-09-01 01:09:41 +00:00
}
else
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = RootPart . PhysActor ;
if ( pa ! = null )
2008-04-23 15:32:19 +00:00
{
2012-04-03 04:50:13 +00:00
pa . PIDTarget = target ;
pa . PIDTau = tau ;
pa . PIDActive = true ;
2008-04-23 15:32:19 +00:00
}
2007-08-13 14:39:12 +00:00
}
2007-08-09 17:54:22 +00:00
}
2008-04-21 14:11:36 +00:00
public void stopMoveToTarget ( )
2007-08-09 17:54:22 +00:00
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = RootPart . PhysActor ;
if ( pa ! = null )
pa . PIDActive = false ;
2007-08-09 17:54:22 +00:00
}
2009-12-22 00:26:12 +00:00
2009-03-06 23:01:35 +00:00
/// <summary>
/// Uses a PID to attempt to clamp the object on the Z axis at the given height over tau seconds.
/// </summary>
/// <param name="height">Height to hover. Height of zero disables hover.</param>
/// <param name="hoverType">Determines what the height is relative to </param>
/// <param name="tau">Number of seconds over which to reach target</param>
public void SetHoverHeight ( float height , PIDHoverType hoverType , float tau )
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = RootPart . PhysActor ;
if ( pa ! = null )
2009-03-06 23:01:35 +00:00
{
2011-09-01 01:09:41 +00:00
if ( height ! = 0f )
2009-03-06 23:01:35 +00:00
{
2012-04-03 04:50:13 +00:00
pa . PIDHoverHeight = height ;
pa . PIDHoverType = hoverType ;
pa . PIDTau = tau ;
pa . PIDHoverActive = true ;
2011-09-01 01:09:41 +00:00
}
else
{
2012-04-03 04:50:13 +00:00
pa . PIDHoverActive = false ;
2009-03-06 23:01:35 +00:00
}
2009-09-30 16:00:09 +00:00
}
2009-03-06 23:01:35 +00:00
}
2008-11-10 20:54:34 +00:00
/// <summary>
/// Set the owner of the root part.
/// </summary>
/// <param name="part"></param>
/// <param name="cAgentID"></param>
/// <param name="cGroupID"></param>
2008-09-06 07:52:41 +00:00
public void SetRootPartOwner ( SceneObjectPart part , UUID cAgentID , UUID cGroupID )
2007-08-13 14:39:12 +00:00
{
2008-04-21 14:11:36 +00:00
part . LastOwnerID = part . OwnerID ;
part . OwnerID = cAgentID ;
part . GroupID = cGroupID ;
if ( part . OwnerID ! = cAgentID )
2007-08-13 14:39:12 +00:00
{
2008-04-21 14:11:36 +00:00
// Apply Next Owner Permissions if we're not bypassing permissions
2008-11-21 22:14:57 +00:00
if ( ! m_scene . Permissions . BypassPermissions ( ) )
2008-05-15 19:28:10 +00:00
ApplyNextOwnerPermissions ( ) ;
2008-04-21 14:11:36 +00:00
}
part . ScheduleFullUpdate ( ) ;
2007-08-13 14:39:12 +00:00
}
2008-04-21 14:11:36 +00:00
/// <summary>
2008-07-13 00:18:29 +00:00
/// Make a copy of the given part.
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="part"></param>
/// <param name="cAgentID"></param>
/// <param name="cGroupID"></param>
2008-11-26 07:34:38 +00:00
public SceneObjectPart CopyPart ( SceneObjectPart part , UUID cAgentID , UUID cGroupID , bool userExposed )
2007-08-13 14:39:12 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart newPart = part . Copy ( m_scene . AllocateLocalId ( ) , OwnerID , GroupID , m_parts . Count , userExposed ) ;
AddPart ( newPart ) ;
2008-05-16 01:22:11 +00:00
2008-04-21 14:11:36 +00:00
SetPartAsNonRoot ( newPart ) ;
2008-11-26 07:34:38 +00:00
return newPart ;
2007-08-16 16:31:32 +00:00
}
2007-08-03 11:44:30 +00:00
/// <summary>
2008-09-06 07:52:41 +00:00
/// Reset the UUIDs for all the prims that make up this group.
2011-12-17 00:11:17 +00:00
/// </summary>
/// <remarks>
2008-04-21 14:11:36 +00:00
/// This is called by methods which want to add a new group to an existing scene, in order
/// to ensure that there are no clashes with groups already present.
2011-12-17 00:11:17 +00:00
/// </remarks>
2008-04-21 14:11:36 +00:00
public void ResetIDs ( )
2007-10-30 23:38:56 +00:00
{
2010-09-17 00:30:46 +00:00
lock ( m_parts . SyncRoot )
2007-10-30 23:38:56 +00:00
{
2010-09-17 00:30:46 +00:00
List < SceneObjectPart > partsList = new List < SceneObjectPart > ( m_parts . GetArray ( ) ) ;
2010-08-25 23:08:53 +00:00
m_parts . Clear ( ) ;
foreach ( SceneObjectPart part in partsList )
{
part . ResetIDs ( part . LinkNum ) ; // Don't change link nums
m_parts . Add ( part . UUID , part ) ;
}
2007-10-30 23:38:56 +00:00
}
}
2007-11-01 19:19:05 +00:00
2007-08-03 11:44:30 +00:00
/// <summary>
2008-05-16 01:22:11 +00:00
///
2007-08-03 11:44:30 +00:00
/// </summary>
2008-04-21 14:11:36 +00:00
/// <param name="part"></param>
2008-09-06 07:52:41 +00:00
public void ServiceObjectPropertiesFamilyRequest ( IClientAPI remoteClient , UUID AgentID , uint RequestFlags )
2007-08-03 11:44:30 +00:00
{
2011-04-12 19:36:36 +00:00
remoteClient . SendObjectPropertiesFamilyData ( RootPart , RequestFlags ) ;
// remoteClient.SendObjectPropertiesFamilyData(RequestFlags, RootPart.UUID, RootPart.OwnerID, RootPart.GroupID, RootPart.BaseMask,
// RootPart.OwnerMask, RootPart.GroupMask, RootPart.EveryoneMask, RootPart.NextOwnerMask,
// RootPart.OwnershipCost, RootPart.ObjectSaleType, RootPart.SalePrice, RootPart.Category,
// RootPart.CreatorID, RootPart.Name, RootPart.Description);
2007-08-03 11:44:30 +00:00
}
2007-09-19 00:30:55 +00:00
2008-09-06 07:52:41 +00:00
public void SetPartOwner ( SceneObjectPart part , UUID cAgentID , UUID cGroupID )
2007-12-05 06:44:32 +00:00
{
2008-04-21 14:11:36 +00:00
part . OwnerID = cAgentID ;
part . GroupID = cGroupID ;
2007-12-05 06:44:32 +00:00
}
2007-08-13 13:36:42 +00:00
# endregion
2007-08-03 11:44:30 +00:00
2008-04-21 14:11:36 +00:00
public override void Update ( )
2007-07-30 20:11:40 +00:00
{
2008-09-06 01:10:47 +00:00
// Check that the group was not deleted before the scheduled update
// FIXME: This is merely a temporary measure to reduce the incidence of failure when
// an object has been deleted from a scene before update was processed.
// A more fundamental overhaul of the update mechanism is required to eliminate all
// the race conditions.
2011-08-24 21:34:26 +00:00
if ( IsDeleted )
2008-09-06 01:10:47 +00:00
return ;
2008-05-16 01:22:11 +00:00
2009-05-05 19:44:19 +00:00
// Even temporary objects take part in physics (e.g. temp-on-rez bullets)
//if ((RootPart.Flags & PrimFlags.TemporaryOnRez) != 0)
// return;
2009-02-10 22:54:05 +00:00
2011-11-10 22:09:35 +00:00
// If we somehow got here to updating the SOG and its root part is not scheduled for update,
// check to see if the physical position or rotation warrant an update.
if ( m_rootPart . UpdateFlag = = UpdateRequired . NONE )
2010-08-27 23:40:33 +00:00
{
2011-11-10 22:09:35 +00:00
bool UsePhysics = ( ( RootPart . Flags & PrimFlags . Physics ) ! = 0 ) ;
2007-09-19 00:30:55 +00:00
2011-11-10 22:09:35 +00:00
if ( UsePhysics & & ! AbsolutePosition . ApproxEquals ( lastPhysGroupPos , 0.02f ) )
{
m_rootPart . UpdateFlag = UpdateRequired . TERSE ;
lastPhysGroupPos = AbsolutePosition ;
}
if ( UsePhysics & & ! GroupRotation . ApproxEquals ( lastPhysGroupRot , 0.1f ) )
{
m_rootPart . UpdateFlag = UpdateRequired . TERSE ;
lastPhysGroupRot = GroupRotation ;
}
2010-08-27 23:40:33 +00:00
}
2007-09-19 00:30:55 +00:00
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2010-08-27 23:40:33 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
2010-08-27 23:40:33 +00:00
if ( ! IsSelected )
part . UpdateLookAt ( ) ;
part . SendScheduledUpdates ( ) ;
2007-08-09 17:54:22 +00:00
}
}
2008-04-21 14:11:36 +00:00
2007-08-03 11:44:30 +00:00
/// <summary>
2012-07-03 22:19:11 +00:00
/// Schedule a full update for this scene object to all interested viewers.
2007-08-03 11:44:30 +00:00
/// </summary>
2012-07-03 22:19:11 +00:00
/// <remarks>
/// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations
/// so that either all changes are sent at once. However, currently, a large amount of internal
/// code will set this anyway when some object properties are changed.
/// </remarks>
2008-04-21 14:11:36 +00:00
public void ScheduleGroupForFullUpdate ( )
2007-07-30 20:11:40 +00:00
{
2010-08-07 21:28:42 +00:00
// if (IsAttachment)
// m_log.DebugFormat("[SOG]: Scheduling full update for {0} {1}", Name, LocalId);
2010-03-03 22:14:06 +00:00
2008-04-25 01:00:55 +00:00
checkAtTargets ( ) ;
2008-11-07 05:48:44 +00:00
RootPart . ScheduleFullUpdate ( ) ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part ! = RootPart )
part . ScheduleFullUpdate ( ) ;
2007-07-30 20:11:40 +00:00
}
}
2007-08-03 11:44:30 +00:00
/// <summary>
2012-07-03 22:19:11 +00:00
/// Schedule a terse update for this scene object to all interested viewers.
2007-08-03 11:44:30 +00:00
/// </summary>
2012-07-03 22:19:11 +00:00
/// <remarks>
/// Ultimately, this should be managed such that region modules can invoke it at the end of a set of operations
/// so that either all changes are sent at once. However, currently, a large amount of internal
/// code will set this anyway when some object properties are changed.
/// </remarks>
2008-04-21 14:11:36 +00:00
public void ScheduleGroupForTerseUpdate ( )
2008-09-09 01:26:48 +00:00
{
2010-03-03 22:14:06 +00:00
// m_log.DebugFormat("[SOG]: Scheduling terse update for {0} {1}", Name, UUID);
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . ScheduleTerseUpdate ( ) ;
2007-07-30 20:11:40 +00:00
}
2007-09-19 00:30:55 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2008-06-27 14:15:14 +00:00
/// Immediately send a full update for this scene object.
2008-04-21 14:11:36 +00:00
/// </summary>
public void SendGroupFullUpdate ( )
2010-03-10 04:15:36 +00:00
{
2008-11-17 16:33:41 +00:00
if ( IsDeleted )
return ;
2010-03-03 22:14:06 +00:00
2010-03-10 04:15:36 +00:00
// m_log.DebugFormat("[SOG]: Sending immediate full group update for {0} {1}", Name, UUID);
2008-11-17 16:33:41 +00:00
2008-11-07 05:48:44 +00:00
RootPart . SendFullUpdateToAllClients ( ) ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-04-21 14:11:36 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part ! = RootPart )
part . SendFullUpdateToAllClients ( ) ;
2008-04-21 14:11:36 +00:00
}
}
2009-01-30 23:23:02 +00:00
/// <summary>
/// Immediately send an update for this scene object's root prim only.
/// This is for updates regarding the object as a whole, and none of its parts in particular.
2010-03-03 22:14:06 +00:00
/// Note: this may not be used by opensim (it probably should) but it's used by
2009-01-30 23:23:02 +00:00
/// external modules.
/// </summary>
2009-11-14 22:14:08 +00:00
public void SendGroupRootTerseUpdate ( )
2009-01-30 23:23:02 +00:00
{
if ( IsDeleted )
return ;
2009-11-14 22:14:08 +00:00
RootPart . SendTerseUpdateToAllClients ( ) ;
2009-01-30 23:23:02 +00:00
}
2008-04-21 14:11:36 +00:00
public void QueueForUpdateCheck ( )
{
2008-11-18 17:21:33 +00:00
if ( m_scene = = null ) // Need to check here as it's null during object creation
return ;
2010-03-03 22:14:06 +00:00
2009-02-20 17:18:07 +00:00
m_scene . SceneGraph . AddToUpdateList ( this ) ;
2008-04-21 14:11:36 +00:00
}
/// <summary>
2008-06-27 14:15:14 +00:00
/// Immediately send a terse update for this scene object.
2008-04-21 14:11:36 +00:00
/// </summary>
public void SendGroupTerseUpdate ( )
{
2008-11-17 16:33:41 +00:00
if ( IsDeleted )
return ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . SendTerseUpdateToAllClients ( ) ;
2008-02-11 01:43:54 +00:00
}
2011-09-15 17:58:58 +00:00
/// <summary>
2011-11-10 23:20:21 +00:00
/// Send metadata about the root prim (name, description, sale price, permissions, etc.) to a client.
2011-09-15 17:58:58 +00:00
/// </summary>
/// <param name="client"></param>
public void SendPropertiesToClient ( IClientAPI client )
{
m_rootPart . SendPropertiesToClient ( client ) ;
}
2007-07-30 20:11:40 +00:00
2008-04-21 14:11:36 +00:00
#region SceneGroupPart Methods
2007-09-19 00:30:55 +00:00
2007-08-03 11:44:30 +00:00
/// <summary>
2008-04-21 14:11:36 +00:00
/// Get the child part by LinkNum
2007-08-03 11:44:30 +00:00
/// </summary>
2008-04-21 14:11:36 +00:00
/// <param name="linknum"></param>
/// <returns>null if no child part with that linknum or child part</returns>
public SceneObjectPart GetLinkNumPart ( int linknum )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-08-23 11:38:50 +00:00
{
2010-09-17 00:30:46 +00:00
if ( parts [ i ] . LinkNum = = linknum )
return parts [ i ] ;
2007-08-23 11:38:50 +00:00
}
2008-04-21 14:11:36 +00:00
return null ;
2007-07-30 20:11:40 +00:00
}
/// <summary>
2010-02-02 15:45:41 +00:00
/// Get a part with a given UUID
2007-07-30 20:11:40 +00:00
/// </summary>
2008-04-21 14:11:36 +00:00
/// <param name="primID"></param>
2012-03-31 00:52:06 +00:00
/// <returns>null if a part with the primID was not found</returns>
public SceneObjectPart GetPart ( UUID primID )
2007-07-30 20:11:40 +00:00
{
2010-09-10 19:41:36 +00:00
SceneObjectPart childPart ;
2010-09-17 00:30:46 +00:00
m_parts . TryGetValue ( primID , out childPart ) ;
2008-04-21 14:11:36 +00:00
return childPart ;
2007-07-30 20:11:40 +00:00
}
2007-08-03 11:44:30 +00:00
/// <summary>
2010-02-02 15:45:41 +00:00
/// Get a part with a given local ID
2007-08-03 11:44:30 +00:00
/// </summary>
/// <param name="localID"></param>
2012-03-31 00:52:06 +00:00
/// <returns>null if a part with the local ID was not found</returns>
public SceneObjectPart GetPart ( uint localID )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2007-07-30 20:11:40 +00:00
{
2010-09-17 00:30:46 +00:00
if ( parts [ i ] . LocalId = = localID )
return parts [ i ] ;
2007-07-30 20:11:40 +00:00
}
2008-04-21 14:11:36 +00:00
return null ;
2007-07-30 20:11:40 +00:00
}
2007-08-03 11:44:30 +00:00
2007-07-30 20:11:40 +00:00
# endregion
2007-09-19 00:30:55 +00:00
2008-04-21 14:11:36 +00:00
#region Packet Handlers
2007-07-30 20:11:40 +00:00
/// <summary>
2008-04-21 14:11:36 +00:00
/// Link the prims in a given group to this group
2007-07-30 20:11:40 +00:00
/// </summary>
2012-04-17 22:54:51 +00:00
/// <remarks>
/// Do not call this method directly - use Scene.LinkObjects() instead to avoid races between threads.
/// FIXME: There are places where scripts call these methods directly without locking. This is a potential race condition.
/// </remarks>
2008-04-21 14:11:36 +00:00
/// <param name="objectGroup">The group of prims which should be linked to this group</param>
public void LinkToGroup ( SceneObjectGroup objectGroup )
2007-07-30 20:11:40 +00:00
{
2012-04-25 18:09:22 +00:00
LinkToGroup ( objectGroup , false ) ;
}
2012-07-11 23:07:14 +00:00
// Link an existing group to this group.
// The group being linked need not be a linkset -- it can have just one prim.
2012-04-25 18:09:22 +00:00
public void LinkToGroup ( SceneObjectGroup objectGroup , bool insert )
{
2008-04-21 14:11:36 +00:00
// m_log.DebugFormat(
2008-05-16 01:22:11 +00:00
// "[SCENE OBJECT GROUP]: Linking group with root part {0}, {1} to group with root part {2}, {3}",
2008-04-21 14:11:36 +00:00
// objectGroup.RootPart.Name, objectGroup.RootPart.UUID, RootPart.Name, RootPart.UUID);
2012-02-08 21:58:59 +00:00
// Linking to ourselves is not a valid operation.
if ( objectGroup = = this )
return ;
2012-09-08 12:48:07 +00:00
// If the configured linkset capacity is greater than zero,
// and the new linkset would have a prim count higher than this
// value, do not link it.
if ( m_scene . m_linksetCapacity > 0 & &
( PrimCount + objectGroup . PrimCount ) >
m_scene . m_linksetCapacity )
{
m_log . DebugFormat (
2012-09-12 00:45:34 +00:00
"[SCENE OBJECT GROUP]: Cannot link group with root" +
" part {0}, {1} ({2} prims) to group with root part" +
" {3}, {4} ({5} prims) because the new linkset" +
" would exceed the configured maximum of {6}" ,
objectGroup . RootPart . Name , objectGroup . RootPart . UUID ,
objectGroup . PrimCount , RootPart . Name , RootPart . UUID ,
PrimCount , m_scene . m_linksetCapacity ) ;
2012-09-08 12:48:07 +00:00
return ;
}
2012-07-11 23:07:14 +00:00
// 'linkPart' == the root of the group being linked into this group
2008-04-21 14:11:36 +00:00
SceneObjectPart linkPart = objectGroup . m_rootPart ;
2012-04-25 18:09:22 +00:00
// physics flags from group to be applied to linked parts
bool grpusephys = UsesPhysics ;
bool grptemporary = IsTemporary ;
2012-07-11 23:07:14 +00:00
// Remember where the group being linked thought it was
2008-09-06 07:52:41 +00:00
Vector3 oldGroupPosition = linkPart . GroupPosition ;
Quaternion oldRootRotation = linkPart . RotationOffset ;
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
// A linked SOP remembers its location and rotation relative to the root of a group.
// Convert the root of the group being linked to be relative to the
// root of the group being linked to.
// Note: Some of the assignments have complex side effects.
// First move the new group's root SOP's position to be relative to ours
// (radams1: Not sure if the multiple setting of OffsetPosition is required. If not,
// this code can be reordered to have a more logical flow.)
2008-04-21 14:11:36 +00:00
linkPart . OffsetPosition = linkPart . GroupPosition - AbsolutePosition ;
2012-07-11 23:07:14 +00:00
// Assign the new parent to the root of the old group
2011-11-05 00:09:37 +00:00
linkPart . ParentID = m_rootPart . LocalId ;
2012-07-11 23:07:14 +00:00
// Now that it's a child, it's group position is our root position
2008-04-21 14:11:36 +00:00
linkPart . GroupPosition = AbsolutePosition ;
2012-07-11 23:07:14 +00:00
Vector3 axPos = linkPart . OffsetPosition ;
// Rotate the linking root SOP's position to be relative to the new root prim
2008-09-06 07:52:41 +00:00
Quaternion parentRot = m_rootPart . RotationOffset ;
axPos * = Quaternion . Inverse ( parentRot ) ;
linkPart . OffsetPosition = axPos ;
2012-07-11 23:07:14 +00:00
// Make the linking root SOP's rotation relative to the new root prim
2008-09-06 07:52:41 +00:00
Quaternion oldRot = linkPart . RotationOffset ;
2008-09-07 13:24:23 +00:00
Quaternion newRot = Quaternion . Inverse ( parentRot ) * oldRot ;
2008-09-06 07:52:41 +00:00
linkPart . RotationOffset = newRot ;
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
// If there is only one SOP in a SOG, the LinkNum is zero. I.e., not a linkset.
// Now that we know this SOG has at least two SOPs in it, the new root
// SOP becomes the first in the linkset.
2008-07-23 13:24:25 +00:00
if ( m_rootPart . LinkNum = = 0 )
2008-07-19 04:05:34 +00:00
m_rootPart . LinkNum = 1 ;
2008-04-21 14:11:36 +00:00
2010-09-17 00:30:46 +00:00
lock ( m_parts . SyncRoot )
2008-04-21 14:11:36 +00:00
{
2012-07-11 23:07:14 +00:00
// Calculate the new link number for the old root SOP
2012-04-25 18:09:22 +00:00
int linkNum ;
if ( insert )
{
linkNum = 2 ;
foreach ( SceneObjectPart part in Parts )
{
if ( part . LinkNum > 1 )
part . LinkNum + + ;
}
}
else
{
linkNum = PrimCount + 1 ;
}
2008-10-29 03:22:54 +00:00
2012-07-11 23:07:14 +00:00
// Add the old root SOP as a part in our group's list
2011-11-05 00:09:37 +00:00
m_parts . Add ( linkPart . UUID , linkPart ) ;
2008-10-29 03:22:54 +00:00
linkPart . SetParent ( this ) ;
2010-05-31 17:00:02 +00:00
linkPart . CreateSelected = true ;
2008-10-29 03:22:54 +00:00
2012-04-25 18:09:22 +00:00
// let physics know preserve part volume dtc messy since UpdatePrimFlags doesn't look to parent changes for now
linkPart . UpdatePrimFlags ( grpusephys , grptemporary , ( IsPhantom | | ( linkPart . Flags & PrimFlags . Phantom ) ! = 0 ) , linkPart . VolumeDetectActive ) ;
2012-07-11 23:07:14 +00:00
// If the added SOP is physical, also tell the physics engine about the link relationship.
2012-04-25 18:09:22 +00:00
if ( linkPart . PhysActor ! = null & & m_rootPart . PhysActor ! = null & & m_rootPart . PhysActor . IsPhysical )
{
linkPart . PhysActor . link ( m_rootPart . PhysActor ) ;
this . Scene . PhysicsScene . AddPhysicsActorTaint ( linkPart . PhysActor ) ;
}
2011-11-05 00:09:37 +00:00
linkPart . LinkNum = linkNum + + ;
2008-10-29 03:22:54 +00:00
2012-07-11 23:07:14 +00:00
// Get a list of the SOP's in the old group in order of their linknum's.
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] ogParts = objectGroup . Parts ;
2011-11-05 00:09:37 +00:00
Array . Sort ( ogParts , delegate ( SceneObjectPart a , SceneObjectPart b )
{
return a . LinkNum - b . LinkNum ;
} ) ;
2012-07-11 23:07:14 +00:00
// Add each of the SOP's from the old linkset to our linkset
2010-09-17 00:30:46 +00:00
for ( int i = 0 ; i < ogParts . Length ; i + + )
2008-10-29 03:22:54 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = ogParts [ i ] ;
2008-10-29 03:22:54 +00:00
if ( part . UUID ! = objectGroup . m_rootPart . UUID )
2012-04-25 18:09:22 +00:00
{
2008-10-29 03:22:54 +00:00
LinkNonRootPart ( part , oldGroupPosition , oldRootRotation , linkNum + + ) ;
2012-07-11 23:07:14 +00:00
// Update the physics flags for the newly added SOP
// (Is this necessary? LinkNonRootPart() has already called UpdatePrimFlags but with different flags!??)
2012-04-25 18:09:22 +00:00
part . UpdatePrimFlags ( grpusephys , grptemporary , ( IsPhantom | | ( part . Flags & PrimFlags . Phantom ) ! = 0 ) , part . VolumeDetectActive ) ;
2012-07-11 23:07:14 +00:00
// If the added SOP is physical, also tell the physics engine about the link relationship.
2012-04-25 18:09:22 +00:00
if ( part . PhysActor ! = null & & m_rootPart . PhysActor ! = null & & m_rootPart . PhysActor . IsPhysical )
{
part . PhysActor . link ( m_rootPart . PhysActor ) ;
this . Scene . PhysicsScene . AddPhysicsActorTaint ( part . PhysActor ) ;
}
}
2008-10-29 03:22:54 +00:00
part . ClearUndoState ( ) ;
}
}
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
// Now that we've aquired all of the old SOG's parts, remove the old SOG from the scene.
2010-09-06 23:34:06 +00:00
m_scene . UnlinkSceneObject ( objectGroup , true ) ;
2011-08-24 21:34:26 +00:00
objectGroup . IsDeleted = true ;
2010-09-17 00:30:46 +00:00
objectGroup . m_parts . Clear ( ) ;
2011-11-05 00:09:37 +00:00
2009-02-03 18:48:04 +00:00
// Can't do this yet since backup still makes use of the root part without any synchronization
2008-11-17 15:40:27 +00:00
// objectGroup.m_rootPart = null;
2008-04-21 14:11:36 +00:00
2012-08-23 23:15:30 +00:00
// If linking prims with different permissions, fix them
2014-04-24 21:11:42 +00:00
AdjustChildPrimPermissions ( false ) ;
2012-08-23 23:15:30 +00:00
2013-10-24 08:18:15 +00:00
GroupContainsForeignPrims = true ;
2009-02-09 20:06:06 +00:00
AttachToBackup ( ) ;
// Here's the deal, this is ABSOLUTELY CRITICAL so the physics scene gets the update about the
// position of linkset prims. IF YOU CHANGE THIS, YOU MUST TEST colliding with just linked and
// unmoved prims!
2009-02-08 18:05:12 +00:00
ResetChildPrimPhysicsPositions ( ) ;
2009-12-06 00:02:24 +00:00
//HasGroupChanged = true;
//ScheduleGroupForFullUpdate();
2007-07-30 20:11:40 +00:00
}
/// <summary>
2008-05-16 01:22:11 +00:00
/// Delink the given prim from this group. The delinked prim is established as
2008-04-21 14:11:36 +00:00
/// an independent SceneObjectGroup.
2007-07-30 20:11:40 +00:00
/// </summary>
2012-04-17 22:54:51 +00:00
/// <remarks>
/// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
/// condition. But currently there is no
/// alternative method that does take a lonk to delink a single prim.
/// </remarks>
2008-04-21 14:11:36 +00:00
/// <param name="partID"></param>
2010-02-16 14:36:08 +00:00
/// <returns>The object group of the newly delinked prim. Null if part could not be found</returns>
public SceneObjectGroup DelinkFromGroup ( uint partID )
2008-07-19 04:05:34 +00:00
{
2010-02-16 14:36:08 +00:00
return DelinkFromGroup ( partID , true ) ;
2008-07-19 04:05:34 +00:00
}
2008-11-07 21:07:14 +00:00
/// <summary>
/// Delink the given prim from this group. The delinked prim is established as
/// an independent SceneObjectGroup.
/// </summary>
2012-04-17 22:54:51 +00:00
/// <remarks>
/// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
/// condition. But currently there is no
/// alternative method that does take a lonk to delink a single prim.
/// </remarks>
2008-11-07 21:07:14 +00:00
/// <param name="partID"></param>
/// <param name="sendEvents"></param>
2010-02-16 14:36:08 +00:00
/// <returns>The object group of the newly delinked prim. Null if part could not be found</returns>
public SceneObjectGroup DelinkFromGroup ( uint partID , bool sendEvents )
2008-04-21 14:11:36 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart linkPart = GetPart ( partID ) ;
2008-05-16 01:22:11 +00:00
2009-04-29 15:54:16 +00:00
if ( linkPart ! = null )
2008-04-21 14:11:36 +00:00
{
2010-02-16 14:36:08 +00:00
return DelinkFromGroup ( linkPart , sendEvents ) ;
2009-04-29 15:54:16 +00:00
}
else
{
2010-02-16 14:36:08 +00:00
m_log . WarnFormat ( "[SCENE OBJECT GROUP]: " +
2009-04-29 15:54:16 +00:00
"DelinkFromGroup(): Child prim {0} not found in object {1}, {2}" ,
partID , LocalId , UUID ) ;
2010-02-16 14:36:08 +00:00
return null ;
2009-04-29 15:54:16 +00:00
}
}
2010-02-16 14:36:08 +00:00
/// <summary>
/// Delink the given prim from this group. The delinked prim is established as
/// an independent SceneObjectGroup.
/// </summary>
2012-04-17 22:54:51 +00:00
/// <remarks>
/// FIXME: This method should not be called directly since it bypasses update locking, allowing a potential race
/// condition. But currently there is no
2012-07-11 23:07:14 +00:00
/// alternative method that does take a lock to delink a single prim.
2012-04-17 22:54:51 +00:00
/// </remarks>
2010-02-16 14:36:08 +00:00
/// <param name="partID"></param>
/// <param name="sendEvents"></param>
2010-02-22 03:25:59 +00:00
/// <returns>The object group of the newly delinked prim.</returns>
2010-02-16 14:36:08 +00:00
public SceneObjectGroup DelinkFromGroup ( SceneObjectPart linkPart , bool sendEvents )
2009-04-29 15:54:16 +00:00
{
2008-04-21 14:11:36 +00:00
// m_log.DebugFormat(
2008-05-16 01:22:11 +00:00
// "[SCENE OBJECT GROUP]: Delinking part {0}, {1} from group with root part {2}, {3}",
2008-04-21 14:11:36 +00:00
// linkPart.Name, linkPart.UUID, RootPart.Name, RootPart.UUID);
2010-02-16 14:36:08 +00:00
linkPart . ClearUndoState ( ) ;
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
Vector3 worldPos = linkPart . GetWorldPosition ( ) ;
2009-04-29 15:54:16 +00:00
Quaternion worldRot = linkPart . GetWorldRotation ( ) ;
2008-04-21 14:11:36 +00:00
2009-04-29 15:54:16 +00:00
// Remove the part from this object
2010-09-17 00:30:46 +00:00
lock ( m_parts . SyncRoot )
2009-04-29 15:54:16 +00:00
{
m_parts . Remove ( linkPart . UUID ) ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
2012-07-11 23:07:14 +00:00
// Rejigger the linknum's of the remaining SOP's to fill any gap
2010-09-17 00:30:46 +00:00
if ( parts . Length = = 1 & & RootPart ! = null )
2008-07-19 04:05:34 +00:00
{
2010-09-17 00:30:46 +00:00
// Single prim left
2010-08-25 23:08:53 +00:00
RootPart . LinkNum = 0 ;
2008-07-19 04:05:34 +00:00
}
2010-08-25 23:08:53 +00:00
else
{
2010-09-17 00:30:46 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
2010-08-25 23:08:53 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
if ( part . LinkNum > linkPart . LinkNum )
part . LinkNum - - ;
2010-08-25 23:08:53 +00:00
}
2010-09-12 17:43:49 +00:00
}
2009-04-29 15:54:16 +00:00
}
2008-07-19 04:05:34 +00:00
2009-04-29 15:54:16 +00:00
linkPart . ParentID = 0 ;
linkPart . LinkNum = 0 ;
2008-04-21 14:11:36 +00:00
2012-04-03 04:50:13 +00:00
PhysicsActor linkPartPa = linkPart . PhysActor ;
2012-07-11 23:07:14 +00:00
// Remove the SOP from the physical scene.
// If the new SOG is physical, it is re-created later.
// (There is a problem here in that we have not yet told the physics
// engine about the delink. Someday, linksets should be made first
// class objects in the physics engine interface).
2012-04-03 04:50:13 +00:00
if ( linkPartPa ! = null )
m_scene . PhysicsScene . RemovePrim ( linkPartPa ) ;
2008-04-21 14:11:36 +00:00
2009-04-29 15:54:16 +00:00
// We need to reset the child part's position
// ready for life as a separate object after being a part of another object
2008-09-06 07:52:41 +00:00
2012-07-11 23:07:14 +00:00
/ * This commented out code seems to recompute what GetWorldPosition already does .
* Replace with a call to GetWorldPosition ( before unlinking )
Quaternion parentRot = m_rootPart . RotationOffset ;
2009-04-29 15:54:16 +00:00
Vector3 axPos = linkPart . OffsetPosition ;
axPos * = parentRot ;
linkPart . OffsetPosition = new Vector3 ( axPos . X , axPos . Y , axPos . Z ) ;
linkPart . GroupPosition = AbsolutePosition + linkPart . OffsetPosition ;
linkPart . OffsetPosition = new Vector3 ( 0 , 0 , 0 ) ;
2012-07-11 23:07:14 +00:00
* /
linkPart . GroupPosition = worldPos ;
linkPart . OffsetPosition = Vector3 . Zero ;
2009-04-29 15:54:16 +00:00
linkPart . RotationOffset = worldRot ;
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
// Create a new SOG to go around this unlinked and unattached SOP
2009-04-29 15:54:16 +00:00
SceneObjectGroup objectGroup = new SceneObjectGroup ( linkPart ) ;
2008-04-21 14:11:36 +00:00
2009-04-29 15:54:16 +00:00
m_scene . AddNewSceneObject ( objectGroup , true ) ;
2008-04-21 14:11:36 +00:00
2009-04-29 15:54:16 +00:00
if ( sendEvents )
linkPart . TriggerScriptChangedEvent ( Changed . LINK ) ;
2008-07-19 04:05:34 +00:00
2009-04-29 15:54:16 +00:00
linkPart . Rezzed = RootPart . Rezzed ;
2008-10-18 05:51:36 +00:00
2013-10-24 08:18:15 +00:00
// We must persist the delinked group to the database immediately, for safety. The problem
// is that although in memory the new group has a new SceneGroupID, in the database it
// still has the parent group's SceneGroupID (until the next backup). This means that if the
// parent group is deleted then the delinked group will also be deleted from the database.
// This problem will disappear if the region remains alive long enough for another backup,
// since at that time the delinked group's new SceneGroupID will be written to the database.
// But if the region crashes before that then the prims will be permanently gone, and this must
// not happen. (We can't use a just-in-time trick like GroupContainsForeignPrims in this case
// because the delinked group doesn't know when the source group is deleted.)
m_scene . ForceSceneObjectBackup ( objectGroup ) ;
2010-02-16 14:36:08 +00:00
return objectGroup ;
2008-04-21 14:11:36 +00:00
}
2008-06-12 17:49:08 +00:00
/// <summary>
/// Stop this object from being persisted over server restarts.
/// </summary>
/// <param name="objectGroup"></param>
2009-07-02 12:00:39 +00:00
public virtual void DetachFromBackup ( )
2007-07-30 20:11:40 +00:00
{
2014-03-22 00:29:13 +00:00
if ( Backup & & Scene ! = null )
2008-10-18 05:51:36 +00:00
m_scene . EventManager . OnBackup - = ProcessBackup ;
2008-11-07 21:07:14 +00:00
2014-03-22 00:29:13 +00:00
Backup = false ;
2008-04-21 14:11:36 +00:00
}
2012-07-11 23:07:14 +00:00
// This links an SOP from a previous linkset into my linkset.
// The trick is that the SOP's position and rotation are relative to the old root SOP's
// so we are passed in the position and rotation of the old linkset so this can
// unjigger this SOP's position and rotation from the previous linkset and
// then make them relative to my linkset root.
2008-10-28 11:26:23 +00:00
private void LinkNonRootPart ( SceneObjectPart part , Vector3 oldGroupPosition , Quaternion oldGroupRotation , int linkNum )
2008-04-21 14:11:36 +00:00
{
2008-12-21 14:50:58 +00:00
Quaternion parentRot = oldGroupRotation ;
Quaternion oldRot = part . RotationOffset ;
2012-07-11 23:07:14 +00:00
// Move our position to not be relative to the old parent
2008-12-21 14:50:58 +00:00
Vector3 axPos = part . OffsetPosition ;
axPos * = parentRot ;
part . OffsetPosition = axPos ;
part . GroupPosition = oldGroupPosition + part . OffsetPosition ;
part . OffsetPosition = Vector3 . Zero ;
2012-07-11 23:07:14 +00:00
// Compution our rotation to be not relative to the old parent
Quaternion worldRot = parentRot * oldRot ;
2008-12-21 14:50:58 +00:00
part . RotationOffset = worldRot ;
2012-07-11 23:07:14 +00:00
// Add this SOP to our linkset
2008-04-21 14:11:36 +00:00
part . SetParent ( this ) ;
2008-03-05 18:57:13 +00:00
part . ParentID = m_rootPart . LocalId ;
2008-10-29 03:22:54 +00:00
m_parts . Add ( part . UUID , part ) ;
2008-04-21 14:11:36 +00:00
2008-10-28 11:26:23 +00:00
part . LinkNum = linkNum ;
2008-07-19 04:05:34 +00:00
2012-07-11 23:07:14 +00:00
// Compute the new position of this SOP relative to the group position
2008-12-21 14:50:58 +00:00
part . OffsetPosition = part . GroupPosition - AbsolutePosition ;
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
// (radams1 20120711: I don't know why part.OffsetPosition is set multiple times.
// It would have the affect of setting the physics engine position multiple
// times. In theory, that is not necessary but I don't have a good linkset
// test to know that cleaning up this code wouldn't break things.)
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
// Rotate the relative position by the rotation of the group
Quaternion rootRotation = m_rootPart . RotationOffset ;
2008-09-06 07:52:41 +00:00
Vector3 pos = part . OffsetPosition ;
pos * = Quaternion . Inverse ( rootRotation ) ;
part . OffsetPosition = pos ;
2008-04-21 14:11:36 +00:00
2012-07-11 23:07:14 +00:00
// Compute the SOP's rotation relative to the rotation of the group.
2008-12-21 14:50:58 +00:00
parentRot = m_rootPart . RotationOffset ;
oldRot = part . RotationOffset ;
Quaternion newRot = Quaternion . Inverse ( parentRot ) * oldRot ;
part . RotationOffset = newRot ;
2012-04-21 00:43:09 +00:00
2012-07-11 23:07:14 +00:00
// Since this SOP's state has changed, push those changes into the physics engine
// and the simulator.
2012-04-21 00:43:09 +00:00
part . UpdatePrimFlags ( UsesPhysics , IsTemporary , IsPhantom , IsVolumeDetect ) ;
2007-07-30 20:11:40 +00:00
}
2007-08-03 12:00:24 +00:00
/// <summary>
2008-04-21 14:11:36 +00:00
/// If object is physical, apply force to move it around
/// If object is not physical, just put it at the resulting location
2007-08-03 12:00:24 +00:00
/// </summary>
2014-08-29 22:40:21 +00:00
/// <param name="partID">Part ID to check for grab</param>
2008-04-21 14:11:36 +00:00
/// <param name="offset">Always seems to be 0,0,0, so ignoring</param>
/// <param name="pos">New position. We do the math here to turn it into a force</param>
/// <param name="remoteClient"></param>
2014-08-29 22:40:21 +00:00
public void GrabMovement ( UUID partID , Vector3 offset , Vector3 pos , IClientAPI remoteClient )
2007-08-03 12:00:24 +00:00
{
2008-04-21 14:11:36 +00:00
if ( m_scene . EventManager . TriggerGroupMove ( UUID , pos ) )
{
2014-08-29 22:40:21 +00:00
SceneObjectPart part = GetPart ( partID ) ;
if ( part = = null )
return ;
2012-04-03 04:50:13 +00:00
PhysicsActor pa = m_rootPart . PhysActor ;
if ( pa ! = null )
2008-04-21 14:11:36 +00:00
{
2012-04-03 04:50:13 +00:00
if ( pa . IsPhysical )
2008-04-21 14:11:36 +00:00
{
2014-08-29 22:40:21 +00:00
if ( ! BlockGrabOverride & & ! part . BlockGrab )
2010-02-14 21:41:57 +00:00
{
Vector3 llmoveforce = pos - AbsolutePosition ;
Vector3 grabforce = llmoveforce ;
2012-04-03 04:50:13 +00:00
grabforce = ( grabforce / 10 ) * pa . Mass ;
pa . AddForce ( grabforce , true ) ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( pa ) ;
2010-02-14 21:41:57 +00:00
}
2008-04-21 14:11:36 +00:00
}
else
{
//NonPhysicalGrabMovement(pos);
}
}
else
{
//NonPhysicalGrabMovement(pos);
}
}
2007-08-03 12:00:24 +00:00
}
2007-08-07 17:25:21 +00:00
2008-09-06 07:52:41 +00:00
public void NonPhysicalGrabMovement ( Vector3 pos )
2008-04-21 14:11:36 +00:00
{
AbsolutePosition = pos ;
m_rootPart . SendTerseUpdateToAllClients ( ) ;
}
2007-09-19 00:30:55 +00:00
2009-04-10 06:39:52 +00:00
/// <summary>
/// If object is physical, prepare for spinning torques (set flag to save old orientation)
/// </summary>
/// <param name="rotation">Rotation. We do the math here to turn it into a torque</param>
/// <param name="remoteClient"></param>
public void SpinStart ( IClientAPI remoteClient )
{
if ( m_scene . EventManager . TriggerGroupSpinStart ( UUID ) )
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = m_rootPart . PhysActor ;
if ( pa ! = null )
2009-04-10 06:39:52 +00:00
{
2012-04-03 04:50:13 +00:00
if ( pa . IsPhysical )
2009-04-10 06:39:52 +00:00
{
m_rootPart . IsWaitingForFirstSpinUpdatePacket = true ;
}
}
}
}
/// <summary>
/// If object is physical, apply torque to spin it around
/// </summary>
/// <param name="rotation">Rotation. We do the math here to turn it into a torque</param>
/// <param name="remoteClient"></param>
public void SpinMovement ( Quaternion newOrientation , IClientAPI remoteClient )
{
// The incoming newOrientation, sent by the client, "seems" to be the
// desired target orientation. This needs further verification; in particular,
// one would expect that the initial incoming newOrientation should be
// fairly close to the original prim's physical orientation,
// m_rootPart.PhysActor.Orientation. This however does not seem to be the
// case (might just be an issue with different quaternions representing the
// same rotation, or it might be a coordinate system issue).
/ /
// Since it's not clear what the relationship is between the PhysActor.Orientation
// and the incoming orientations sent by the client, we take an alternative approach
// of calculating the delta rotation between the orientations being sent by the
// client. (Since a spin is invoked by ctrl+shift+drag in the client, we expect
// a steady stream of several new orientations coming in from the client.)
// This ensures that the delta rotations are being calculated from self-consistent
// pairs of old/new rotations. Given the delta rotation, we apply a torque around
// the delta rotation axis, scaled by the object mass times an arbitrary scaling
// factor (to ensure the resulting torque is not "too strong" or "too weak").
//
// Ideally we need to calculate (probably iteratively) the exact torque or series
// of torques needed to arrive exactly at the destination orientation. However, since
// it is not yet clear how to map the destination orientation (provided by the viewer)
// into PhysActor orientations (needed by the physics engine), we omit this step.
// This means that the resulting torque will at least be in the correct direction,
// but it will result in over-shoot or under-shoot of the target orientation.
// For the end user, this means that ctrl+shift+drag can be used for relative,
// but not absolute, adjustments of orientation for physical prims.
if ( m_scene . EventManager . TriggerGroupSpin ( UUID , newOrientation ) )
{
2012-04-03 04:50:13 +00:00
PhysicsActor pa = m_rootPart . PhysActor ;
if ( pa ! = null )
2009-04-10 06:39:52 +00:00
{
2012-04-03 04:50:13 +00:00
if ( pa . IsPhysical )
2009-04-10 06:39:52 +00:00
{
2009-04-14 11:38:33 +00:00
if ( m_rootPart . IsWaitingForFirstSpinUpdatePacket )
2009-04-10 06:39:52 +00:00
{
// first time initialization of "old" orientation for calculation of delta rotations
m_rootPart . SpinOldOrientation = newOrientation ;
m_rootPart . IsWaitingForFirstSpinUpdatePacket = false ;
}
else
{
// save and update old orientation
Quaternion old = m_rootPart . SpinOldOrientation ;
m_rootPart . SpinOldOrientation = newOrientation ;
//m_log.Error("[SCENE OBJECT GROUP]: Old orientation is " + old);
//m_log.Error("[SCENE OBJECT GROUP]: Incoming new orientation is " + newOrientation);
// compute difference between previous old rotation and new incoming rotation
Quaternion minimalRotationFromQ1ToQ2 = Quaternion . Inverse ( old ) * newOrientation ;
float rotationAngle ;
Vector3 rotationAxis ;
minimalRotationFromQ1ToQ2 . GetAxisAngle ( out rotationAxis , out rotationAngle ) ;
rotationAxis . Normalize ( ) ;
//m_log.Error("SCENE OBJECT GROUP]: rotation axis is " + rotationAxis);
2009-10-26 06:16:12 +00:00
Vector3 spinforce = new Vector3 ( rotationAxis . X , rotationAxis . Y , rotationAxis . Z ) ;
2012-04-03 04:50:13 +00:00
spinforce = ( spinforce / 8 ) * pa . Mass ; // 8 is an arbitrary torque scaling factor
pa . AddAngularForce ( spinforce , true ) ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( pa ) ;
2009-04-10 06:39:52 +00:00
}
}
else
{
//NonPhysicalSpinMovement(pos);
}
}
else
{
//NonPhysicalSpinMovement(pos);
}
}
}
2007-08-13 13:36:42 +00:00
/// <summary>
2008-04-21 14:11:36 +00:00
/// Set the name of a prim
2007-08-13 13:36:42 +00:00
/// </summary>
2008-04-21 14:11:36 +00:00
/// <param name="name"></param>
/// <param name="localID"></param>
public void SetPartName ( string name , uint localID )
2007-08-13 13:36:42 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2007-08-29 15:32:48 +00:00
{
2008-04-21 14:11:36 +00:00
part . Name = name ;
2007-08-29 15:32:48 +00:00
}
2007-08-13 13:36:42 +00:00
}
2007-09-19 00:30:55 +00:00
2008-04-21 14:11:36 +00:00
public void SetPartDescription ( string des , uint localID )
2007-08-10 13:59:19 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2007-08-10 13:59:19 +00:00
{
2008-04-21 14:11:36 +00:00
part . Description = des ;
2007-08-10 13:59:19 +00:00
}
}
2007-12-04 16:41:20 +00:00
2008-04-21 14:11:36 +00:00
public void SetPartText ( string text , uint localID )
2007-08-07 17:25:21 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2007-08-07 17:25:21 +00:00
{
2008-04-21 14:11:36 +00:00
part . SetText ( text ) ;
2007-08-07 17:25:21 +00:00
}
}
2007-08-07 18:31:20 +00:00
2008-09-06 07:52:41 +00:00
public void SetPartText ( string text , UUID partID )
2007-08-07 18:31:20 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( partID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2007-08-07 18:31:20 +00:00
{
2008-04-21 14:11:36 +00:00
part . SetText ( text ) ;
2007-08-07 18:31:20 +00:00
}
}
2007-09-19 00:30:55 +00:00
2008-04-21 14:11:36 +00:00
public string GetPartName ( uint localID )
2007-08-15 16:57:47 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2007-08-15 16:57:47 +00:00
{
2008-04-21 14:11:36 +00:00
return part . Name ;
2007-08-15 16:57:47 +00:00
}
2008-04-21 14:11:36 +00:00
return String . Empty ;
2007-08-13 13:36:42 +00:00
}
2008-04-21 14:11:36 +00:00
public string GetPartDescription ( uint localID )
2007-08-13 13:36:42 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2008-03-18 20:42:01 +00:00
{
2008-04-21 14:11:36 +00:00
return part . Description ;
2008-03-04 18:49:44 +00:00
}
2008-04-21 14:11:36 +00:00
return String . Empty ;
2007-08-13 13:36:42 +00:00
}
/// <summary>
2008-07-12 19:05:12 +00:00
/// Update prim flags for this group.
2007-08-13 13:36:42 +00:00
/// </summary>
2008-04-21 14:11:36 +00:00
/// <param name="localID"></param>
2011-07-11 01:18:19 +00:00
/// <param name="UsePhysics"></param>
/// <param name="SetTemporary"></param>
/// <param name="SetPhantom"></param>
/// <param name="SetVolumeDetect"></param>
public void UpdatePrimFlags ( uint localID , bool UsePhysics , bool SetTemporary , bool SetPhantom , bool SetVolumeDetect )
2007-08-13 13:36:42 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart selectionPart = GetPart ( localID ) ;
2008-08-18 00:39:10 +00:00
2014-03-22 00:29:13 +00:00
if ( Scene ! = null )
2008-10-03 16:18:38 +00:00
{
2014-03-22 00:29:13 +00:00
if ( SetTemporary )
{
DetachFromBackup ( ) ;
// Remove from database and parcel prim count
/ /
m_scene . DeleteFromStorage ( UUID ) ;
}
else if ( ! Backup )
{
// Previously been temporary now switching back so make it
// available for persisting again
AttachToBackup ( ) ;
}
2008-10-03 16:18:38 +00:00
m_scene . EventManager . TriggerParcelPrimCountTainted ( ) ;
}
2008-10-03 15:32:44 +00:00
2008-07-12 19:05:12 +00:00
if ( selectionPart ! = null )
2007-08-13 13:36:42 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
2011-08-05 22:42:05 +00:00
if ( Scene ! = null )
2007-08-13 13:36:42 +00:00
{
2011-08-05 22:42:05 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
2008-07-10 03:13:29 +00:00
{
2011-08-05 22:42:05 +00:00
SceneObjectPart part = parts [ i ] ;
2012-02-05 17:38:20 +00:00
if ( part . Scale . X > m_scene . m_maxPhys | |
part . Scale . Y > m_scene . m_maxPhys | |
part . Scale . Z > m_scene . m_maxPhys )
2011-08-05 22:42:05 +00:00
{
UsePhysics = false ; // Reset physics
break ;
}
2008-03-18 20:42:01 +00:00
}
2007-08-13 13:36:42 +00:00
}
2010-09-17 00:30:46 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
2011-07-11 01:18:19 +00:00
parts [ i ] . UpdatePrimFlags ( UsePhysics , SetTemporary , SetPhantom , SetVolumeDetect ) ;
2007-08-13 13:36:42 +00:00
}
}
2007-08-13 20:24:37 +00:00
2008-04-21 14:11:36 +00:00
public void UpdateExtraParam ( uint localID , ushort type , bool inUse , byte [ ] data )
2007-08-21 16:25:57 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2007-08-21 16:25:57 +00:00
{
2008-04-21 14:11:36 +00:00
part . UpdateExtraParam ( type , inUse , data ) ;
2007-08-21 16:25:57 +00:00
}
}
2008-04-21 14:11:36 +00:00
/// <summary>
2008-05-26 02:17:03 +00:00
/// Update the texture entry for this part
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="localID"></param>
/// <param name="textureEntry"></param>
public void UpdateTextureEntry ( uint localID , byte [ ] textureEntry )
2007-08-13 20:24:37 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2007-08-13 20:24:37 +00:00
if ( part ! = null )
{
2008-04-21 14:11:36 +00:00
part . UpdateTextureEntry ( textureEntry ) ;
2007-08-13 20:24:37 +00:00
}
}
2007-08-16 16:31:32 +00:00
2014-04-24 21:11:42 +00:00
public void AdjustChildPrimPermissions ( bool forceTaskInventoryPermissive )
2012-08-23 23:15:30 +00:00
{
2013-03-31 20:59:44 +00:00
uint newOwnerMask = ( uint ) ( PermissionMask . All | PermissionMask . Export ) & 0xfffffff8 ; // Mask folded bits
uint foldedPerms = RootPart . OwnerMask & 3 ;
2012-08-23 23:15:30 +00:00
ForEachPart ( part = >
{
2013-03-31 20:59:44 +00:00
newOwnerMask & = part . BaseMask ;
2012-08-23 23:15:30 +00:00
if ( part ! = RootPart )
part . ClonePermissions ( RootPart ) ;
2014-04-24 21:11:42 +00:00
if ( forceTaskInventoryPermissive )
part . Inventory . ApplyGodPermissions ( part . BaseMask ) ;
2012-08-23 23:15:30 +00:00
} ) ;
2013-03-31 20:59:44 +00:00
2013-06-22 23:14:07 +00:00
uint lockMask = ~ ( uint ) ( PermissionMask . Move | PermissionMask . Modify ) ;
uint lockBit = RootPart . OwnerMask & ( uint ) ( PermissionMask . Move | PermissionMask . Modify ) ;
2013-03-31 20:59:44 +00:00
RootPart . OwnerMask = ( RootPart . OwnerMask & lockBit ) | ( ( newOwnerMask | foldedPerms ) & lockMask ) ;
RootPart . ScheduleFullUpdate ( ) ;
2012-08-23 23:15:30 +00:00
}
2008-10-06 02:29:38 +00:00
public void UpdatePermissions ( UUID AgentID , byte field , uint localID ,
uint mask , byte addRemTF )
2007-08-15 21:24:25 +00:00
{
2012-08-23 23:15:30 +00:00
RootPart . UpdatePermissions ( AgentID , field , localID , mask , addRemTF ) ;
2014-04-24 21:11:42 +00:00
AdjustChildPrimPermissions ( Scene . Permissions . IsGod ( AgentID ) ) ;
2008-10-06 02:29:38 +00:00
2008-04-21 14:11:36 +00:00
HasGroupChanged = true ;
2011-11-10 23:20:21 +00:00
// Send the group's properties to all clients once all parts are updated
IClientAPI client ;
if ( Scene . TryGetClient ( AgentID , out client ) )
SendPropertiesToClient ( client ) ;
2007-08-15 21:24:25 +00:00
}
2008-04-21 14:11:36 +00:00
# endregion
2007-08-15 21:24:25 +00:00
2008-04-21 14:11:36 +00:00
#region Shape
/// <summary>
2008-05-16 01:22:11 +00:00
///
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="shapeBlock"></param>
public void UpdateShape ( ObjectShapePacket . ObjectDataBlock shapeBlock , uint localID )
2007-08-15 21:24:25 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
{
part . UpdateShape ( shapeBlock ) ;
2012-04-03 04:50:13 +00:00
PhysicsActor pa = m_rootPart . PhysActor ;
if ( pa ! = null )
m_scene . PhysicsScene . AddPhysicsActorTaint ( pa ) ;
2008-04-21 14:11:36 +00:00
}
2007-08-15 21:24:25 +00:00
}
2007-08-16 16:31:32 +00:00
2008-04-21 14:11:36 +00:00
# endregion
#region Resize
2011-07-16 01:53:36 +00:00
/// <summary>
/// Resize the entire group of prims.
/// </summary>
/// <param name="scale"></param>
public void GroupResize ( Vector3 scale )
2008-04-21 14:11:36 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Group resizing {0} {1} from {2} to {3}", Name, LocalId, RootPart.Scale, scale);
2011-07-16 00:36:27 +00:00
2012-04-03 04:50:13 +00:00
PhysicsActor pa = m_rootPart . PhysActor ;
2012-09-26 22:17:21 +00:00
RootPart . StoreUndoState ( true ) ;
if ( Scene ! = null )
2011-07-16 01:53:36 +00:00
{
2012-09-26 22:17:21 +00:00
scale . X = Math . Max ( Scene . m_minNonphys , Math . Min ( Scene . m_maxNonphys , scale . X ) ) ;
scale . Y = Math . Max ( Scene . m_minNonphys , Math . Min ( Scene . m_maxNonphys , scale . Y ) ) ;
scale . Z = Math . Max ( Scene . m_minNonphys , Math . Min ( Scene . m_maxNonphys , scale . Z ) ) ;
if ( pa ! = null & & pa . IsPhysical )
{
scale . X = Math . Max ( Scene . m_minPhys , Math . Min ( Scene . m_maxPhys , scale . X ) ) ;
scale . Y = Math . Max ( Scene . m_minPhys , Math . Min ( Scene . m_maxPhys , scale . Y ) ) ;
scale . Z = Math . Max ( Scene . m_minPhys , Math . Min ( Scene . m_maxPhys , scale . Z ) ) ;
}
2011-07-16 01:53:36 +00:00
}
2008-07-10 03:13:29 +00:00
2011-07-16 01:53:36 +00:00
float x = ( scale . X / RootPart . Scale . X ) ;
float y = ( scale . Y / RootPart . Scale . Y ) ;
float z = ( scale . Z / RootPart . Scale . Z ) ;
2012-09-26 22:17:21 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
if ( Scene ! = null & ( x > 1.0f | | y > 1.0f | | z > 1.0f ) )
2011-07-16 01:53:36 +00:00
{
for ( int i = 0 ; i < parts . Length ; i + + )
2008-07-10 03:13:29 +00:00
{
2011-07-16 01:53:36 +00:00
SceneObjectPart obPart = parts [ i ] ;
if ( obPart . UUID ! = m_rootPart . UUID )
2008-07-10 03:13:29 +00:00
{
2011-07-18 03:54:21 +00:00
// obPart.IgnoreUndoUpdate = true;
2011-07-16 01:53:36 +00:00
Vector3 oldSize = new Vector3 ( obPart . Scale ) ;
2008-07-10 03:13:29 +00:00
2011-07-16 01:53:36 +00:00
float f = 1.0f ;
float a = 1.0f ;
2008-07-10 03:13:29 +00:00
2012-04-03 04:50:13 +00:00
if ( pa ! = null & & pa . IsPhysical )
2011-07-16 01:53:36 +00:00
{
2012-09-26 22:17:21 +00:00
if ( oldSize . X * x > Scene . m_maxPhys )
2011-07-16 01:53:36 +00:00
{
f = m_scene . m_maxPhys / oldSize . X ;
a = f / x ;
x * = a ;
y * = a ;
z * = a ;
}
2012-09-26 22:17:21 +00:00
else if ( oldSize . X * x < Scene . m_minPhys )
2012-08-06 14:35:40 +00:00
{
f = m_scene . m_minPhys / oldSize . X ;
a = f / x ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-18 03:54:21 +00:00
2012-09-26 22:17:21 +00:00
if ( oldSize . Y * y > Scene . m_maxPhys )
2010-09-17 00:30:46 +00:00
{
2011-07-16 01:53:36 +00:00
f = m_scene . m_maxPhys / oldSize . Y ;
a = f / y ;
x * = a ;
y * = a ;
z * = a ;
2010-09-17 00:30:46 +00:00
}
2012-09-26 22:17:21 +00:00
else if ( oldSize . Y * y < Scene . m_minPhys )
2012-08-06 14:35:40 +00:00
{
f = m_scene . m_minPhys / oldSize . Y ;
a = f / y ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-18 03:54:21 +00:00
2012-09-26 22:17:21 +00:00
if ( oldSize . Z * z > Scene . m_maxPhys )
2010-09-17 00:30:46 +00:00
{
2011-07-16 01:53:36 +00:00
f = m_scene . m_maxPhys / oldSize . Z ;
a = f / z ;
x * = a ;
y * = a ;
z * = a ;
2008-07-10 03:13:29 +00:00
}
2012-09-26 22:17:21 +00:00
else if ( oldSize . Z * z < Scene . m_minPhys )
2012-08-06 14:35:40 +00:00
{
f = m_scene . m_minPhys / oldSize . Z ;
a = f / z ;
x * = a ;
y * = a ;
z * = a ;
}
2008-07-10 03:13:29 +00:00
}
2011-07-16 01:53:36 +00:00
else
{
2012-09-26 22:17:21 +00:00
if ( oldSize . X * x > Scene . m_maxNonphys )
2011-07-16 01:53:36 +00:00
{
f = m_scene . m_maxNonphys / oldSize . X ;
a = f / x ;
x * = a ;
y * = a ;
z * = a ;
}
2012-09-26 22:17:21 +00:00
else if ( oldSize . X * x < Scene . m_minNonphys )
2012-08-06 14:35:40 +00:00
{
f = m_scene . m_minNonphys / oldSize . X ;
a = f / x ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-18 03:54:21 +00:00
2012-09-26 22:17:21 +00:00
if ( oldSize . Y * y > Scene . m_maxNonphys )
2011-07-16 01:53:36 +00:00
{
f = m_scene . m_maxNonphys / oldSize . Y ;
a = f / y ;
x * = a ;
y * = a ;
z * = a ;
}
2012-09-26 22:17:21 +00:00
else if ( oldSize . Y * y < Scene . m_minNonphys )
2012-08-06 14:35:40 +00:00
{
f = m_scene . m_minNonphys / oldSize . Y ;
a = f / y ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-18 03:54:21 +00:00
2012-09-26 22:17:21 +00:00
if ( oldSize . Z * z > Scene . m_maxNonphys )
2011-07-16 01:53:36 +00:00
{
f = m_scene . m_maxNonphys / oldSize . Z ;
a = f / z ;
x * = a ;
y * = a ;
z * = a ;
}
2012-09-26 22:17:21 +00:00
else if ( oldSize . Z * z < Scene . m_minNonphys )
2012-08-06 14:35:40 +00:00
{
f = m_scene . m_minNonphys / oldSize . Z ;
a = f / z ;
x * = a ;
y * = a ;
z * = a ;
}
2011-07-16 01:53:36 +00:00
}
2011-07-16 03:49:21 +00:00
2011-07-18 03:54:21 +00:00
// obPart.IgnoreUndoUpdate = false;
2008-07-10 03:13:29 +00:00
}
}
2011-07-16 01:53:36 +00:00
}
2008-07-10 03:13:29 +00:00
2011-07-16 01:53:36 +00:00
Vector3 prevScale = RootPart . Scale ;
prevScale . X * = x ;
prevScale . Y * = y ;
prevScale . Z * = z ;
2011-07-19 02:01:54 +00:00
// RootPart.IgnoreUndoUpdate = true;
2011-07-16 01:53:36 +00:00
RootPart . Resize ( prevScale ) ;
2011-07-19 02:01:54 +00:00
// RootPart.IgnoreUndoUpdate = false;
2008-04-21 14:11:36 +00:00
2011-07-16 01:53:36 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
{
SceneObjectPart obPart = parts [ i ] ;
2011-07-16 03:49:21 +00:00
2011-07-16 01:53:36 +00:00
if ( obPart . UUID ! = m_rootPart . UUID )
2008-04-21 14:11:36 +00:00
{
2011-07-19 02:01:54 +00:00
obPart . IgnoreUndoUpdate = true ;
2011-07-16 01:53:36 +00:00
Vector3 currentpos = new Vector3 ( obPart . OffsetPosition ) ;
currentpos . X * = x ;
currentpos . Y * = y ;
currentpos . Z * = z ;
2011-07-16 03:49:21 +00:00
2011-07-16 01:53:36 +00:00
Vector3 newSize = new Vector3 ( obPart . Scale ) ;
newSize . X * = x ;
newSize . Y * = y ;
newSize . Z * = z ;
2011-07-18 03:54:21 +00:00
2011-07-19 02:01:54 +00:00
obPart . Resize ( newSize ) ;
2011-07-16 01:53:36 +00:00
obPart . UpdateOffSet ( currentpos ) ;
2011-07-19 02:01:54 +00:00
obPart . IgnoreUndoUpdate = false ;
2007-08-16 16:31:32 +00:00
}
2007-08-16 18:40:44 +00:00
2011-07-18 03:54:21 +00:00
// obPart.IgnoreUndoUpdate = false;
// obPart.StoreUndoState();
2011-07-16 01:53:36 +00:00
}
2011-07-16 00:42:56 +00:00
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Finished group resizing {0} {1} to {2}", Name, LocalId, RootPart.Scale);
2007-08-21 16:25:57 +00:00
}
2008-04-21 14:11:36 +00:00
# endregion
2008-02-06 08:03:22 +00:00
2008-04-21 14:11:36 +00:00
#region Position
2008-02-06 08:03:22 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2008-06-27 14:39:21 +00:00
/// Move this scene object
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="pos"></param>
2008-09-06 07:52:41 +00:00
public void UpdateGroupPosition ( Vector3 pos )
2008-04-20 04:19:44 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat("[SCENE OBJECT GROUP]: Updating group position on {0} {1} to {2}", Name, LocalId, pos);
2011-07-19 02:01:54 +00:00
RootPart . StoreUndoState ( true ) ;
// SceneObjectPart[] parts = m_parts.GetArray();
// for (int i = 0; i < parts.Length; i++)
// parts[i].StoreUndoState();
2010-09-17 00:30:46 +00:00
2008-04-21 14:11:36 +00:00
if ( m_scene . EventManager . TriggerGroupMove ( UUID , pos ) )
2008-04-20 04:19:44 +00:00
{
2008-11-01 22:04:35 +00:00
if ( IsAttachment )
2008-04-25 21:41:55 +00:00
{
2008-07-26 21:22:15 +00:00
m_rootPart . AttachedPos = pos ;
2008-04-25 21:41:55 +00:00
}
2012-04-06 23:33:02 +00:00
2010-02-14 21:41:57 +00:00
if ( RootPart . GetStatusSandbox ( ) )
{
if ( Util . GetDistanceTo ( RootPart . StatusSandboxPos , pos ) > 10 )
{
RootPart . ScriptSetPhysicsStatus ( false ) ;
pos = AbsolutePosition ;
Scene . SimChat ( Utils . StringToBytes ( "Hit Sandbox Limit" ) ,
ChatTypeEnum . DebugChannel , 0x7FFFFFFF , RootPart . AbsolutePosition , Name , UUID , false ) ;
}
}
2008-08-18 00:39:10 +00:00
2012-04-06 23:33:02 +00:00
AbsolutePosition = pos ;
2008-06-27 14:39:21 +00:00
HasGroupChanged = true ;
2008-04-20 04:19:44 +00:00
}
2008-08-18 00:39:10 +00:00
2008-04-21 14:11:36 +00:00
//we need to do a terse update even if the move wasn't allowed
// so that the position is reset in the client (the object snaps back)
2012-05-06 18:21:54 +00:00
RootPart . ScheduleTerseUpdate ( ) ;
2008-04-20 04:19:44 +00:00
}
2008-04-21 14:11:36 +00:00
/// <summary>
2008-06-27 14:39:21 +00:00
/// Update the position of a single part of this scene object
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="pos"></param>
/// <param name="localID"></param>
2008-09-06 07:52:41 +00:00
public void UpdateSinglePosition ( Vector3 pos , uint localID )
2008-04-20 04:19:44 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2010-09-17 00:30:46 +00:00
2011-07-19 02:27:16 +00:00
// SceneObjectPart[] parts = m_parts.GetArray();
// for (int i = 0; i < parts.Length; i++)
// parts[i].StoreUndoState();
2010-09-17 00:30:46 +00:00
2008-04-21 14:11:36 +00:00
if ( part ! = null )
2008-04-20 04:19:44 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating single position of {0} {1} to {2}", part.Name, part.LocalId, pos);
2011-07-19 02:27:16 +00:00
part . StoreUndoState ( false ) ;
2011-07-19 04:46:17 +00:00
part . IgnoreUndoUpdate = true ;
2011-07-19 02:27:16 +00:00
2008-04-21 14:11:36 +00:00
if ( part . UUID = = m_rootPart . UUID )
2008-04-20 04:19:44 +00:00
{
2008-04-21 14:11:36 +00:00
UpdateRootPosition ( pos ) ;
2008-04-20 04:19:44 +00:00
}
else
{
2008-04-21 14:11:36 +00:00
part . UpdateOffSet ( pos ) ;
2008-04-20 04:19:44 +00:00
}
2008-08-18 00:39:10 +00:00
2008-06-27 14:39:21 +00:00
HasGroupChanged = true ;
2011-07-19 04:46:17 +00:00
part . IgnoreUndoUpdate = false ;
2008-04-20 04:19:44 +00:00
}
}
2008-04-21 14:11:36 +00:00
/// <summary>
2011-07-19 04:20:04 +00:00
/// Update just the root prim position in a linkset
2008-04-21 14:11:36 +00:00
/// </summary>
2013-06-24 23:15:55 +00:00
/// <param name="newPos"></param>
public void UpdateRootPosition ( Vector3 newPos )
2008-04-20 04:19:44 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating root position of {0} {1} to {2}", Name, LocalId, pos);
2011-07-19 04:46:17 +00:00
// SceneObjectPart[] parts = m_parts.GetArray();
// for (int i = 0; i < parts.Length; i++)
// parts[i].StoreUndoState();
2010-09-17 00:30:46 +00:00
2013-06-24 23:41:46 +00:00
Vector3 oldPos ;
if ( IsAttachment )
2013-09-16 06:42:14 +00:00
oldPos = m_rootPart . AttachedPos + m_rootPart . OffsetPosition ; // OffsetPosition should always be 0 in an attachments's root prim
2013-06-24 23:41:46 +00:00
else
2013-09-16 06:42:14 +00:00
oldPos = AbsolutePosition + m_rootPart . OffsetPosition ;
2013-06-24 23:41:46 +00:00
2008-09-06 07:52:41 +00:00
Vector3 diff = oldPos - newPos ;
Quaternion partRotation = m_rootPart . RotationOffset ;
2013-06-24 23:15:55 +00:00
diff * = Quaternion . Inverse ( partRotation ) ;
2008-04-21 14:11:36 +00:00
2011-07-19 04:46:17 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
2010-09-17 00:30:46 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
2008-04-20 04:19:44 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart obPart = parts [ i ] ;
if ( obPart . UUID ! = m_rootPart . UUID )
obPart . OffsetPosition = obPart . OffsetPosition + diff ;
2008-04-20 04:19:44 +00:00
}
2008-04-21 14:11:36 +00:00
AbsolutePosition = newPos ;
2013-09-16 06:42:14 +00:00
if ( IsAttachment )
m_rootPart . AttachedPos = newPos ;
2008-08-18 00:39:10 +00:00
2008-06-27 15:04:35 +00:00
HasGroupChanged = true ;
2008-04-21 14:11:36 +00:00
ScheduleGroupForTerseUpdate ( ) ;
}
2008-04-20 04:19:44 +00:00
2008-04-21 14:11:36 +00:00
# endregion
#region Rotation
/// <summary>
2011-10-28 22:38:57 +00:00
/// Update the rotation of the group.
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="rot"></param>
2009-09-30 16:51:02 +00:00
public void UpdateGroupRotationR ( Quaternion rot )
2008-04-21 14:11:36 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating group rotation R of {0} {1} to {2}", Name, LocalId, rot);
2011-07-19 03:15:27 +00:00
// SceneObjectPart[] parts = m_parts.GetArray();
// for (int i = 0; i < parts.Length; i++)
// parts[i].StoreUndoState();
m_rootPart . StoreUndoState ( true ) ;
2010-09-17 00:30:46 +00:00
2008-04-21 14:11:36 +00:00
m_rootPart . UpdateRotation ( rot ) ;
2009-11-02 23:09:07 +00:00
PhysicsActor actor = m_rootPart . PhysActor ;
if ( actor ! = null )
2008-04-20 04:19:44 +00:00
{
2009-11-02 23:09:07 +00:00
actor . Orientation = m_rootPart . RotationOffset ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( actor ) ;
2008-04-20 04:19:44 +00:00
}
2008-08-18 00:39:10 +00:00
2008-06-27 15:04:35 +00:00
HasGroupChanged = true ;
2008-04-21 14:11:36 +00:00
ScheduleGroupForTerseUpdate ( ) ;
2008-04-20 04:19:44 +00:00
}
2008-04-21 14:11:36 +00:00
/// <summary>
2011-10-28 22:38:57 +00:00
/// Update the position and rotation of a group simultaneously.
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="pos"></param>
/// <param name="rot"></param>
2009-09-30 16:51:02 +00:00
public void UpdateGroupRotationPR ( Vector3 pos , Quaternion rot )
2007-08-16 18:40:44 +00:00
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating group rotation PR of {0} {1} to {2}", Name, LocalId, rot);
2011-07-19 03:15:27 +00:00
// SceneObjectPart[] parts = m_parts.GetArray();
// for (int i = 0; i < parts.Length; i++)
// parts[i].StoreUndoState();
RootPart . StoreUndoState ( true ) ;
RootPart . IgnoreUndoUpdate = true ;
2010-09-17 00:30:46 +00:00
2008-04-21 14:11:36 +00:00
m_rootPart . UpdateRotation ( rot ) ;
2009-11-02 23:09:07 +00:00
PhysicsActor actor = m_rootPart . PhysActor ;
if ( actor ! = null )
2008-04-21 14:11:36 +00:00
{
2009-11-02 23:09:07 +00:00
actor . Orientation = m_rootPart . RotationOffset ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( actor ) ;
2008-04-21 14:11:36 +00:00
}
2009-11-02 23:09:07 +00:00
2012-06-22 00:33:27 +00:00
if ( IsAttachment )
{
m_rootPart . AttachedPos = pos ;
}
2008-04-21 14:11:36 +00:00
AbsolutePosition = pos ;
2008-08-18 00:39:10 +00:00
2008-06-27 15:04:35 +00:00
HasGroupChanged = true ;
2008-04-21 14:11:36 +00:00
ScheduleGroupForTerseUpdate ( ) ;
2011-07-19 03:15:27 +00:00
RootPart . IgnoreUndoUpdate = false ;
2007-08-16 18:40:44 +00:00
}
2007-12-04 11:11:13 +00:00
2008-04-21 14:11:36 +00:00
/// <summary>
2011-10-28 22:38:57 +00:00
/// Update the rotation of a single prim within the group.
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="rot"></param>
/// <param name="localID"></param>
2008-09-06 07:52:41 +00:00
public void UpdateSingleRotation ( Quaternion rot , uint localID )
2007-12-04 11:11:13 +00:00
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . StoreUndoState ( ) ;
2008-04-21 14:11:36 +00:00
if ( part ! = null )
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating single rotation of {0} {1} to {2}", part.Name, part.LocalId, rot);
2008-04-21 14:11:36 +00:00
if ( part . UUID = = m_rootPart . UUID )
2008-01-14 18:29:04 +00:00
{
2008-04-21 14:11:36 +00:00
UpdateRootRotation ( rot ) ;
2008-01-14 18:29:04 +00:00
}
2008-03-18 20:42:01 +00:00
else
{
2008-04-21 14:11:36 +00:00
part . UpdateRotation ( rot ) ;
}
2008-01-14 18:29:04 +00:00
}
2007-12-04 11:11:13 +00:00
}
2008-01-17 09:32:02 +00:00
2009-07-17 14:58:54 +00:00
/// <summary>
2011-10-28 22:38:57 +00:00
/// Update the position and rotation simultaneously of a single prim within the group.
2009-07-17 14:58:54 +00:00
/// </summary>
/// <param name="rot"></param>
/// <param name="localID"></param>
public void UpdateSingleRotation ( Quaternion rot , Vector3 pos , uint localID )
{
2012-03-31 00:52:06 +00:00
SceneObjectPart part = GetPart ( localID ) ;
2009-07-17 14:58:54 +00:00
if ( part ! = null )
{
2011-07-18 03:54:21 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating single position and rotation of {0} {1} to {2}",
// part.Name, part.LocalId, rot);
2011-07-19 03:40:02 +00:00
part . StoreUndoState ( ) ;
part . IgnoreUndoUpdate = true ;
2009-07-17 14:58:54 +00:00
if ( part . UUID = = m_rootPart . UUID )
{
UpdateRootRotation ( rot ) ;
AbsolutePosition = pos ;
}
else
{
part . UpdateRotation ( rot ) ;
part . OffsetPosition = pos ;
}
2011-07-19 03:40:02 +00:00
part . IgnoreUndoUpdate = false ;
2009-07-17 14:58:54 +00:00
}
}
2008-04-21 14:11:36 +00:00
/// <summary>
2011-11-09 21:49:08 +00:00
/// Update the rotation of just the root prim of a linkset.
2008-04-21 14:11:36 +00:00
/// </summary>
/// <param name="rot"></param>
2011-07-19 04:05:50 +00:00
public void UpdateRootRotation ( Quaternion rot )
2008-01-17 09:32:02 +00:00
{
2011-07-19 04:14:58 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updating root rotation of {0} {1} to {2}",
// Name, LocalId, rot);
2011-07-18 03:54:21 +00:00
2008-09-06 07:52:41 +00:00
Quaternion axRot = rot ;
Quaternion oldParentRot = m_rootPart . RotationOffset ;
2008-04-21 14:11:36 +00:00
2010-02-14 21:41:57 +00:00
m_rootPart . StoreUndoState ( ) ;
2008-04-21 14:11:36 +00:00
m_rootPart . UpdateRotation ( rot ) ;
2012-04-03 04:50:13 +00:00
PhysicsActor pa = m_rootPart . PhysActor ;
if ( pa ! = null )
2008-04-21 14:11:36 +00:00
{
2012-04-03 04:50:13 +00:00
pa . Orientation = m_rootPart . RotationOffset ;
m_scene . PhysicsScene . AddPhysicsActorTaint ( pa ) ;
2008-04-21 14:11:36 +00:00
}
2008-01-17 09:32:02 +00:00
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-01-17 09:32:02 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart prim = parts [ i ] ;
if ( prim . UUID ! = m_rootPart . UUID )
2008-01-21 15:06:49 +00:00
{
2010-09-17 00:30:46 +00:00
prim . IgnoreUndoUpdate = true ;
Vector3 axPos = prim . OffsetPosition ;
axPos * = oldParentRot ;
axPos * = Quaternion . Inverse ( axRot ) ;
prim . OffsetPosition = axPos ;
Quaternion primsRot = prim . RotationOffset ;
2011-11-05 09:26:25 +00:00
Quaternion newRot = oldParentRot * primsRot ;
newRot = Quaternion . Inverse ( axRot ) * newRot ;
2010-09-17 00:30:46 +00:00
prim . RotationOffset = newRot ;
prim . ScheduleTerseUpdate ( ) ;
2011-07-19 04:05:50 +00:00
prim . IgnoreUndoUpdate = false ;
2008-01-21 15:06:49 +00:00
}
2008-01-17 09:32:02 +00:00
}
2010-09-17 00:30:46 +00:00
2011-07-19 04:14:58 +00:00
// for (int i = 0; i < parts.Length; i++)
// {
// SceneObjectPart childpart = parts[i];
// if (childpart != m_rootPart)
// {
//// childpart.IgnoreUndoUpdate = false;
//// childpart.StoreUndoState();
// }
// }
2010-09-17 00:30:46 +00:00
2008-04-21 14:11:36 +00:00
m_rootPart . ScheduleTerseUpdate ( ) ;
2011-07-19 04:05:50 +00:00
2011-07-19 04:14:58 +00:00
// m_log.DebugFormat(
// "[SCENE OBJECT GROUP]: Updated root rotation of {0} {1} to {2}",
// Name, LocalId, rot);
2008-01-17 09:32:02 +00:00
}
2008-03-25 03:36:31 +00:00
2008-04-21 14:11:36 +00:00
# endregion
2008-05-01 18:04:42 +00:00
internal void SetAxisRotation ( int axis , int rotate10 )
{
bool setX = false ;
bool setY = false ;
bool setZ = false ;
int xaxis = 2 ;
int yaxis = 4 ;
int zaxis = 8 ;
2011-09-01 01:09:41 +00:00
setX = ( ( axis & xaxis ) ! = 0 ) ? true : false ;
setY = ( ( axis & yaxis ) ! = 0 ) ? true : false ;
setZ = ( ( axis & zaxis ) ! = 0 ) ? true : false ;
2008-05-01 18:04:42 +00:00
2011-09-01 01:09:41 +00:00
float setval = ( rotate10 > 0 ) ? 1f : 0f ;
2009-09-30 16:51:02 +00:00
2011-09-01 01:09:41 +00:00
if ( setX )
RootPart . RotationAxis . X = setval ;
if ( setY )
RootPart . RotationAxis . Y = setval ;
if ( setZ )
RootPart . RotationAxis . Z = setval ;
2008-05-01 18:04:42 +00:00
2011-09-01 01:09:41 +00:00
if ( setX | | setY | | setZ )
RootPart . SetPhysicsAxisRotation ( ) ;
2010-01-11 02:04:05 +00:00
}
2011-09-01 01:09:41 +00:00
2010-01-11 02:04:05 +00:00
public int registerRotTargetWaypoint ( Quaternion target , float tolerance )
{
scriptRotTarget waypoint = new scriptRotTarget ( ) ;
waypoint . targetRot = target ;
waypoint . tolerance = tolerance ;
uint handle = m_scene . AllocateLocalId ( ) ;
waypoint . handle = handle ;
lock ( m_rotTargets )
{
m_rotTargets . Add ( handle , waypoint ) ;
}
m_scene . AddGroupTarget ( this ) ;
return ( int ) handle ;
}
public void unregisterRotTargetWaypoint ( int handle )
{
lock ( m_targets )
{
m_rotTargets . Remove ( ( uint ) handle ) ;
if ( m_targets . Count = = 0 )
m_scene . RemoveGroupTarget ( this ) ;
}
2008-05-01 18:04:42 +00:00
}
2008-09-06 07:52:41 +00:00
public int registerTargetWaypoint ( Vector3 target , float tolerance )
2008-05-01 18:04:42 +00:00
{
scriptPosTarget waypoint = new scriptPosTarget ( ) ;
waypoint . targetPos = target ;
waypoint . tolerance = tolerance ;
2008-11-07 22:49:36 +00:00
uint handle = m_scene . AllocateLocalId ( ) ;
2009-03-07 10:37:15 +00:00
waypoint . handle = handle ;
2008-05-01 18:04:42 +00:00
lock ( m_targets )
{
m_targets . Add ( handle , waypoint ) ;
}
2009-10-14 02:13:06 +00:00
m_scene . AddGroupTarget ( this ) ;
2008-05-01 18:04:42 +00:00
return ( int ) handle ;
}
2008-11-07 21:50:03 +00:00
2008-05-01 18:04:42 +00:00
public void unregisterTargetWaypoint ( int handle )
{
lock ( m_targets )
{
2009-10-14 02:13:06 +00:00
m_targets . Remove ( ( uint ) handle ) ;
if ( m_targets . Count = = 0 )
m_scene . RemoveGroupTarget ( this ) ;
2008-05-01 18:04:42 +00:00
}
}
2009-10-14 02:13:06 +00:00
public void checkAtTargets ( )
2008-05-01 18:04:42 +00:00
{
if ( m_scriptListens_atTarget | | m_scriptListens_notAtTarget )
{
if ( m_targets . Count > 0 )
{
bool at_target = false ;
2008-09-06 07:52:41 +00:00
//Vector3 targetPos;
2008-05-01 18:04:42 +00:00
//uint targetHandle;
Dictionary < uint , scriptPosTarget > atTargets = new Dictionary < uint , scriptPosTarget > ( ) ;
lock ( m_targets )
{
foreach ( uint idx in m_targets . Keys )
{
scriptPosTarget target = m_targets [ idx ] ;
if ( Util . GetDistanceTo ( target . targetPos , m_rootPart . GroupPosition ) < = target . tolerance )
{
// trigger at_target
if ( m_scriptListens_atTarget )
{
at_target = true ;
scriptPosTarget att = new scriptPosTarget ( ) ;
att . targetPos = target . targetPos ;
2009-03-07 10:37:15 +00:00
att . tolerance = target . tolerance ;
att . handle = target . handle ;
2008-05-01 18:04:42 +00:00
atTargets . Add ( idx , att ) ;
}
}
}
}
2009-03-27 20:41:35 +00:00
2008-05-01 18:04:42 +00:00
if ( atTargets . Count > 0 )
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
uint [ ] localids = new uint [ parts . Length ] ;
for ( int i = 0 ; i < parts . Length ; i + + )
localids [ i ] = parts [ i ] . LocalId ;
2009-03-27 20:41:35 +00:00
2008-05-01 18:04:42 +00:00
for ( int ctr = 0 ; ctr < localids . Length ; ctr + + )
{
foreach ( uint target in atTargets . Keys )
{
scriptPosTarget att = atTargets [ target ] ;
2009-03-27 20:41:35 +00:00
m_scene . EventManager . TriggerAtTargetEvent (
localids [ ctr ] , att . handle , att . targetPos , m_rootPart . GroupPosition ) ;
2008-05-01 18:04:42 +00:00
}
}
2009-03-27 20:41:35 +00:00
2008-05-01 18:04:42 +00:00
return ;
}
2009-03-27 20:41:35 +00:00
2008-05-01 18:04:42 +00:00
if ( m_scriptListens_notAtTarget & & ! at_target )
{
//trigger not_at_target
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
uint [ ] localids = new uint [ parts . Length ] ;
for ( int i = 0 ; i < parts . Length ; i + + )
localids [ i ] = parts [ i ] . LocalId ;
2009-03-27 20:41:35 +00:00
2008-05-01 18:04:42 +00:00
for ( int ctr = 0 ; ctr < localids . Length ; ctr + + )
{
2009-03-27 20:41:35 +00:00
m_scene . EventManager . TriggerNotAtTargetEvent ( localids [ ctr ] ) ;
2008-05-01 18:04:42 +00:00
}
}
}
2010-01-11 02:04:05 +00:00
}
if ( m_scriptListens_atRotTarget | | m_scriptListens_notAtRotTarget )
{
if ( m_rotTargets . Count > 0 )
{
bool at_Rottarget = false ;
Dictionary < uint , scriptRotTarget > atRotTargets = new Dictionary < uint , scriptRotTarget > ( ) ;
lock ( m_rotTargets )
{
foreach ( uint idx in m_rotTargets . Keys )
{
scriptRotTarget target = m_rotTargets [ idx ] ;
2011-09-01 01:09:41 +00:00
double angle
= Math . Acos (
target . targetRot . X * m_rootPart . RotationOffset . X
+ target . targetRot . Y * m_rootPart . RotationOffset . Y
+ target . targetRot . Z * m_rootPart . RotationOffset . Z
+ target . targetRot . W * m_rootPart . RotationOffset . W )
* 2 ;
2010-01-11 02:04:05 +00:00
if ( angle < 0 ) angle = - angle ;
if ( angle > Math . PI ) angle = ( Math . PI * 2 - angle ) ;
if ( angle < = target . tolerance )
{
// trigger at_rot_target
if ( m_scriptListens_atRotTarget )
{
at_Rottarget = true ;
scriptRotTarget att = new scriptRotTarget ( ) ;
att . targetRot = target . targetRot ;
att . tolerance = target . tolerance ;
att . handle = target . handle ;
atRotTargets . Add ( idx , att ) ;
}
}
}
}
if ( atRotTargets . Count > 0 )
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
uint [ ] localids = new uint [ parts . Length ] ;
for ( int i = 0 ; i < parts . Length ; i + + )
localids [ i ] = parts [ i ] . LocalId ;
2010-01-11 02:04:05 +00:00
for ( int ctr = 0 ; ctr < localids . Length ; ctr + + )
{
foreach ( uint target in atRotTargets . Keys )
{
scriptRotTarget att = atRotTargets [ target ] ;
m_scene . EventManager . TriggerAtRotTargetEvent (
localids [ ctr ] , att . handle , att . targetRot , m_rootPart . RotationOffset ) ;
}
}
return ;
}
if ( m_scriptListens_notAtRotTarget & & ! at_Rottarget )
{
//trigger not_at_target
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
uint [ ] localids = new uint [ parts . Length ] ;
for ( int i = 0 ; i < parts . Length ; i + + )
localids [ i ] = parts [ i ] . LocalId ;
2010-01-11 02:04:05 +00:00
for ( int ctr = 0 ; ctr < localids . Length ; ctr + + )
{
m_scene . EventManager . TriggerNotAtRotTargetEvent ( localids [ ctr ] ) ;
}
}
}
2008-05-01 18:04:42 +00:00
}
}
2008-11-17 15:40:27 +00:00
2008-05-05 00:03:30 +00:00
public float GetMass ( )
{
float retmass = 0f ;
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
retmass + = parts [ i ] . GetMass ( ) ;
2008-05-05 00:03:30 +00:00
return retmass ;
}
2011-07-11 02:35:29 +00:00
/// <summary>
/// If the object is a sculpt/mesh, retrieve the mesh data for each part and reinsert it into each shape so that
/// the physics engine can use it.
/// </summary>
/// <remarks>
/// When the physics engine has finished with it, the sculpt data is discarded to save memory.
/// </remarks>
2012-10-18 14:30:42 +00:00
/ *
2008-05-09 07:50:00 +00:00
public void CheckSculptAndLoad ( )
{
2010-09-17 00:30:46 +00:00
if ( IsDeleted )
return ;
2011-07-11 01:18:19 +00:00
2010-09-17 00:30:46 +00:00
if ( ( RootPart . GetEffectiveObjectFlags ( ) & ( uint ) PrimFlags . Phantom ) ! = 0 )
return ;
2011-07-11 02:13:59 +00:00
// m_log.Debug("Processing CheckSculptAndLoad for {0} {1}", Name, LocalId);
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
2011-07-11 02:13:59 +00:00
2012-10-18 14:30:42 +00:00
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . CheckSculptAndLoad ( ) ;
2008-05-09 07:50:00 +00:00
}
2012-10-18 14:30:42 +00:00
* /
2008-06-27 14:15:14 +00:00
/// <summary>
/// Set the user group to which this scene object belongs.
/// </summary>
/// <param name="GroupID"></param>
/// <param name="client"></param>
2008-09-06 07:52:41 +00:00
public void SetGroup ( UUID GroupID , IClientAPI client )
2008-05-18 03:21:22 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
2008-05-18 03:21:22 +00:00
{
2010-09-17 00:30:46 +00:00
SceneObjectPart part = parts [ i ] ;
part . SetGroup ( GroupID , client ) ;
part . Inventory . ChangeInventoryGroup ( GroupID ) ;
2008-05-18 03:21:22 +00:00
}
2008-08-18 00:39:10 +00:00
2011-12-17 02:23:24 +00:00
HasGroupChanged = true ;
2010-03-03 22:14:06 +00:00
// Don't trigger the update here - otherwise some client issues occur when multiple updates are scheduled
// for the same object with very different properties. The caller must schedule the update.
//ScheduleGroupForFullUpdate();
2008-05-18 03:21:22 +00:00
}
2008-07-19 04:05:34 +00:00
public void TriggerScriptChangedEvent ( Changed val )
{
2010-09-17 00:30:46 +00:00
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
parts [ i ] . TriggerScriptChangedEvent ( val ) ;
2008-07-19 04:05:34 +00:00
}
2012-04-09 18:58:07 +00:00
/// <summary>
/// Returns a count of the number of scripts in this groups parts.
/// </summary>
public int ScriptCount ( )
{
int count = 0 ;
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
count + = parts [ i ] . Inventory . ScriptCount ( ) ;
return count ;
}
2012-04-10 20:25:05 +00:00
/// <summary>
/// A float the value is a representative execution time in milliseconds of all scripts in the link set.
/// </summary>
public float ScriptExecutionTime ( )
{
IScriptModule [ ] engines = Scene . RequestModuleInterfaces < IScriptModule > ( ) ;
if ( engines . Length = = 0 ) // No engine at all
return 0.0f ;
float time = 0.0f ;
// get all the scripts in all parts
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
List < TaskInventoryItem > scripts = new List < TaskInventoryItem > ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
{
scripts . AddRange ( parts [ i ] . Inventory . GetInventoryItems ( InventoryType . LSL ) ) ;
}
// extract the UUIDs
List < UUID > ids = new List < UUID > ( scripts . Count ) ;
foreach ( TaskInventoryItem script in scripts )
{
if ( ! ids . Contains ( script . ItemID ) )
{
ids . Add ( script . ItemID ) ;
}
}
// Offer the list of script UUIDs to each engine found and accumulate the time
foreach ( IScriptModule e in engines )
{
if ( e ! = null )
{
time + = e . GetScriptExecutionTime ( ids ) ;
}
}
return time ;
}
2012-04-09 18:58:07 +00:00
/// <summary>
/// Returns a count of the number of running scripts in this groups parts.
/// </summary>
public int RunningScriptCount ( )
{
int count = 0 ;
SceneObjectPart [ ] parts = m_parts . GetArray ( ) ;
for ( int i = 0 ; i < parts . Length ; i + + )
count + = parts [ i ] . Inventory . RunningScriptCount ( ) ;
return count ;
}
2013-01-04 20:34:39 +00:00
/// <summary>
/// Get a copy of the list of sitting avatars on all prims of this object.
/// </summary>
/// <remarks>
/// This is sorted by the order in which avatars sat down. If an avatar stands up then all avatars that sat
/// down after it move one place down the list.
/// </remarks>
/// <returns>A list of the sitting avatars. Returns an empty list if there are no sitting avatars.</returns>
2014-04-03 00:14:39 +00:00
public List < ScenePresence > GetSittingAvatars ( )
2013-01-04 20:34:39 +00:00
{
lock ( m_sittingAvatars )
2014-04-03 00:14:39 +00:00
return new List < ScenePresence > ( m_sittingAvatars ) ;
2013-01-04 20:34:39 +00:00
}
2012-07-09 20:24:32 +00:00
/// <summary>
/// Gets the number of sitting avatars.
/// </summary>
/// <remarks>This applies to all sitting avatars whether there is a sit target set or not.</remarks>
/// <returns></returns>
public int GetSittingAvatarsCount ( )
{
2013-01-04 20:34:39 +00:00
lock ( m_sittingAvatars )
return m_sittingAvatars . Count ;
2012-07-09 20:24:32 +00:00
}
2008-09-12 00:37:59 +00:00
public override string ToString ( )
{
return String . Format ( "{0} {1} ({2})" , Name , UUID , AbsolutePosition ) ;
}
2008-10-03 21:44:33 +00:00
2009-02-09 22:27:27 +00:00
#region ISceneObject
2013-01-04 20:34:39 +00:00
2009-02-09 22:27:27 +00:00
public virtual ISceneObject CloneForNewScene ( )
{
2010-06-27 23:48:24 +00:00
SceneObjectGroup sog = Copy ( false ) ;
2011-08-24 21:34:26 +00:00
sog . IsDeleted = false ;
2009-02-09 22:27:27 +00:00
return sog ;
}
2009-08-06 23:41:24 +00:00
public virtual string ToXml2 ( )
{
return SceneObjectSerializer . ToXml2Format ( this ) ;
}
2009-02-09 22:27:27 +00:00
public virtual string ExtraToXmlString ( )
{
2012-04-06 23:33:02 +00:00
return "<ExtraFromItemID>" + FromItemID . ToString ( ) + "</ExtraFromItemID>" ;
2009-02-09 22:27:27 +00:00
}
public virtual void ExtraFromXmlString ( string xmlstr )
{
2009-08-15 16:36:45 +00:00
string id = xmlstr . Substring ( xmlstr . IndexOf ( "<ExtraFromItemID>" ) ) ;
id = xmlstr . Replace ( "<ExtraFromItemID>" , "" ) ;
id = id . Replace ( "</ExtraFromItemID>" , "" ) ;
2009-02-09 22:27:27 +00:00
UUID uuid = UUID . Zero ;
UUID . TryParse ( id , out uuid ) ;
2012-04-06 23:33:02 +00:00
FromItemID = uuid ;
2009-02-09 22:27:27 +00:00
}
2009-08-04 02:17:13 +00:00
2010-05-21 20:55:36 +00:00
# endregion
2007-07-30 20:11:40 +00:00
}
2008-05-01 18:04:42 +00:00
}